Repository: gotestyourself/gotestsum
Pull request #35 (2018-12-02 06:40:25)

Add flag value for noSummary flag


Patch:
diff --git a/flags.go b/flags.go
new file mode 100644
index 0000000..2f4e09b
--- /dev/null
+++ b/flags.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+	"encoding/csv"
+	"strings"
+
+	"github.com/pkg/errors"
+	"gotest.tools/gotestsum/testjson"
+)
+
+type noSummaryValue struct {
+	value testjson.Summary
+}
+
+func newNoSummaryValue() *noSummaryValue {
+	return &noSummaryValue{value: testjson.SummarizeAll}
+}
+
+func readAsCSV(val string) ([]string, error) {
+	if val == "" {
+		return nil, nil
+	}
+	return csv.NewReader(strings.NewReader(val)).Read()
+}
+
+func (s *noSummaryValue) Set(val string) error {
+	v, err := readAsCSV(val)
+	if err != nil {
+		return err
+	}
+	for _, item := range v {
+		summary, ok := testjson.NewSummary(item)
+		if !ok {
+			return errors.Errorf("value must be one or more of: %s",
+				testjson.SummarizeAll.String())
+		}
+		s.value -= summary
+	}
+	return nil
+}
+
+func (s *noSummaryValue) Type() string {
+	return "summary"
+}
+
+func (s *noSummaryValue) String() string {
+	// flip all the bits, since the flag value is the negative of what is stored
+	return (testjson.SummarizeAll ^ s.value).String()
+}
diff --git a/main.go b/main.go
index 546cf42..45ac15c 100644
--- a/main.go
+++ b/main.go
@@ -42,7 +42,7 @@ func main() {
 }
 
 func setupFlags(name string) (*pflag.FlagSet, *options) {
-	opts := &options{}
+	opts := &options{noSummary: newNoSummaryValue()}
 	flags := pflag.NewFlagSet(name, pflag.ContinueOnError)
 	flags.SetInterspersed(false)
 	flags.Usage = func() {
@@ -74,8 +74,8 @@ Formats:
 		lookEnvWithDefault("GOTESTSUM_JUNITFILE", ""),
 		"write a JUnit XML file")
 	flags.BoolVar(&opts.noColor, "no-color", false, "disable color output")
-	flags.StringSliceVar(&opts.noSummary, "no-summary", nil,
-		"do not print summary of: failed, skipped, errors, output")
+	flags.Var(opts.noSummary, "no-summary",
+		fmt.Sprintf("do not print summary of: %s", testjson.SummarizeAll.String()))
 	return flags, opts
 }
 
@@ -94,7 +94,7 @@ type options struct {
 	jsonFile   string
 	junitFile  string
 	noColor    bool
-	noSummary  []string
+	noSummary  *noSummaryValue
 }
 
 func setupLogging(opts *options) {
@@ -131,7 +131,7 @@ func run(opts *options) error {
 	if err != nil {
 		return err
 	}
-	if err := summarizer(opts)(out, exec); err != nil {
+	if err := testjson.PrintSummary(out, exec, opts.noSummary.value); err != nil {
 		return err
 	}
 	if err := writeJUnitFile(opts.junitFile, exec); err != nil {
@@ -203,23 +203,3 @@ func startGoTest(ctx context.Context, args []string) (proc, error) {
 	}
 	return p, err
 }
-
-func summarizer(opts *options) func(io.Writer, *testjson.Execution) error {
-	summary := testjson.SummarizeAll
-	// TODO: do this in a pflag.Value to validate the string
-	for _, item := range opts.noSummary {
-		switch item {
-		case "failed":
-			summary -= testjson.SummarizeFailed
-		case "skipped":
-			summary -= testjson.SummarizeSkipped
-		case "errors":
-			summary -= testjson.SummarizeErrors
-		case "output":
-			summary -= testjson.SummarizeOutput
-		}
-	}
-	return func(out io.Writer, exec *testjson.Execution) error {
-		return testjson.PrintSummary(out, exec, summary)
-	}
-}


Test patch:
diff --git a/flags_test.go b/flags_test.go
new file mode 100644
index 0000000..488b037
--- /dev/null
+++ b/flags_test.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+)
+
+func TestNoSummaryValue_SetAndString(t *testing.T) {
+	t.Run("none", func(t *testing.T) {
+		assert.Equal(t, newNoSummaryValue().String(), "")
+	})
+	t.Run("one", func(t *testing.T) {
+		value := newNoSummaryValue()
+		assert.NilError(t, value.Set("output"))
+		assert.Equal(t, value.String(), "output")
+
+	})
+	t.Run("some", func(t *testing.T) {
+		value := newNoSummaryValue()
+		assert.NilError(t, value.Set("errors,failed"))
+		assert.Equal(t, value.String(), "failed,errors")
+	})
+	t.Run("bad value", func(t *testing.T) {
+		value := newNoSummaryValue()
+		assert.ErrorContains(t, value.Set("bogus"), "must be one or more of")
+	})
+}
diff --git a/testjson/summary.go b/testjson/summary.go
index ebf0353..ef7131e 100644
--- a/testjson/summary.go
+++ b/testjson/summary.go
@@ -24,19 +24,60 @@ const (
 	SummarizeAll = SummarizeSkipped | SummarizeFailed | SummarizeErrors | SummarizeOutput
 )
 
+var summaryValues = map[Summary]string{
+	SummarizeSkipped: "skipped",
+	SummarizeFailed:  "failed",
+	SummarizeErrors:  "errors",
+	SummarizeOutput:  "output",
+}
+
+var summaryFromValue = map[string]Summary{
+	"none":    SummarizeNone,
+	"skipped": SummarizeSkipped,
+	"failed":  SummarizeFailed,
+	"errors":  SummarizeErrors,
+	"output":  SummarizeOutput,
+	"all":     SummarizeAll,
+}
+
+func (s Summary) String() string {
+	if s == SummarizeNone {
+		return "none"
+	}
+	var result []string
+	for v := SummarizeNone; v <= s; v = v << 1 {
+		if s.Includes(v) {
+			result = append(result, summaryValues[v])
+		}
+	}
+	return strings.Join(result, ",")
+}
+
+// Includes returns true if Summary includes all the values set by other.
+func (s Summary) Includes(other Summary) bool {
+	return s&other == other
+}
+
+// NewSummary returns a new Summary from a string value. If the string does not
+// match any known values returns false for the second value.
+func NewSummary(value string) (Summary, bool) {
+	s, ok := summaryFromValue[value]
+	return s, ok
+}
+
 // PrintSummary of a test Execution. Prints a section for each summary type
 // followed by a DONE line.
 func PrintSummary(out io.Writer, execution *Execution, opts Summary) error {
 	execSummary := newExecSummary(execution, opts)
-	if opts&SummarizeSkipped != 0 {
+	if opts.Includes(SummarizeSkipped) {
 		writeTestCaseSummary(out, execSummary, formatSkipped())
 	}
-	if opts&SummarizeFailed != 0 {
+	if opts.Includes(SummarizeFailed) {
 		writeTestCaseSummary(out, execSummary, formatFailed())
 	}
 
 	errors := execution.Errors()
-	if opts&SummarizeErrors != 0 {
+	if opts.Includes(SummarizeErrors) {
 		writeErrorSummary(out, errors)
 	}
 
@@ -105,7 +146,7 @@ func (s *noOutputSummary) OutputLines(_, _ string) []string {
 }
 
 func newExecSummary(execution *Execution, opts Summary) executionSummary {
-	if opts&SummarizeOutput != 0 {
+	if opts.Includes(SummarizeOutput) {
 		return execution
 	}
 	return &noOutputSummary{Execution: *execution}
diff --git a/testjson/summary_test.go b/testjson/summary_test.go
index 660b8a9..d009999 100644
--- a/testjson/summary_test.go
+++ b/testjson/summary_test.go
@@ -10,6 +10,40 @@ import (
 	"gotest.tools/assert"
 )
 
+func TestSummary_String(t *testing.T) {
+	var testcases = []struct {
+		name     string
+		summary  Summary
+		expected string
+	}{
+		{
+			name:     "none",
+			summary:  SummarizeNone,
+			expected: "none",
+		},
+		{
+			name:     "all",
+			summary:  SummarizeAll,
+			expected: "skipped,failed,errors,output",
+		},
+		{
+			name:     "one value",
+			summary:  SummarizeErrors,
+			expected: "errors",
+		},
+		{
+			name:     "a few values",
+			summary:  SummarizeOutput | SummarizeSkipped | SummarizeErrors,
+			expected: "skipped,errors,output",
+		},
+	}
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.summary.String(), tc.expected)
+		})
+	}
+}
+
 func TestPrintSummary_NoFailures(t *testing.T) {
 	fake, reset := patchClock()
 	defer reset()