diff options
Diffstat (limited to 'libgo/go/testing')
-rw-r--r-- | libgo/go/testing/benchmark.go | 3 | ||||
-rw-r--r-- | libgo/go/testing/sub_test.go | 126 | ||||
-rw-r--r-- | libgo/go/testing/testing.go | 80 |
3 files changed, 132 insertions, 77 deletions
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go index 88ba0f0..5276600 100644 --- a/libgo/go/testing/benchmark.go +++ b/libgo/go/testing/benchmark.go @@ -526,6 +526,7 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e name: "Main", w: os.Stdout, chatty: *chatty, + bench: true, }, importPath: importPath, benchFunc: func(b *B) { @@ -559,6 +560,7 @@ func (ctx *benchContext) processBench(b *B) { name: b.name, w: b.w, chatty: b.chatty, + bench: true, }, benchFunc: b.benchFunc, benchTime: b.benchTime, @@ -624,6 +626,7 @@ func (b *B) Run(name string, f func(b *B)) bool { creator: pc[:n], w: b.w, chatty: b.chatty, + bench: true, }, importPath: b.importPath, benchFunc: f, diff --git a/libgo/go/testing/sub_test.go b/libgo/go/testing/sub_test.go index 95f8220..8eb0084 100644 --- a/libgo/go/testing/sub_test.go +++ b/libgo/go/testing/sub_test.go @@ -438,8 +438,6 @@ func TestTRun(t *T) { }, { // A chatty test should always log with fmt.Print, even if the // parent test has completed. - // TODO(deklerk) Capture the log of fmt.Print and assert that the - // subtest message is not lost. desc: "log in finished sub test with chatty", ok: false, chatty: true, @@ -477,35 +475,37 @@ func TestTRun(t *T) { }, }} for _, tc := range testCases { - ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", "")) - buf := &bytes.Buffer{} - root := &T{ - common: common{ - signal: make(chan bool), - name: "Test", - w: buf, - chatty: tc.chatty, - }, - context: ctx, - } - ok := root.Run(tc.desc, tc.f) - ctx.release() + t.Run(tc.desc, func(t *T) { + ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", "")) + buf := &bytes.Buffer{} + root := &T{ + common: common{ + signal: make(chan bool), + name: "Test", + w: buf, + chatty: tc.chatty, + }, + context: ctx, + } + ok := root.Run(tc.desc, tc.f) + ctx.release() - if ok != tc.ok { - t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok) - } - if ok != !root.Failed() { - t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) - } - if ctx.running != 0 || ctx.numWaiting != 0 { - t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting) - } - got := strings.TrimSpace(buf.String()) - want := strings.TrimSpace(tc.output) - re := makeRegexp(want) - if ok, err := regexp.MatchString(re, got); !ok || err != nil { - t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) - } + if ok != tc.ok { + t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok) + } + if ok != !root.Failed() { + t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) + } + if ctx.running != 0 || ctx.numWaiting != 0 { + t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting) + } + got := strings.TrimSpace(buf.String()) + want := strings.TrimSpace(tc.output) + re := makeRegexp(want) + if ok, err := regexp.MatchString(re, got); !ok || err != nil { + t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) + } + }) } } @@ -655,43 +655,45 @@ func TestBRun(t *T) { }, }} for _, tc := range testCases { - var ok bool - buf := &bytes.Buffer{} - // This is almost like the Benchmark function, except that we override - // the benchtime and catch the failure result of the subbenchmark. - root := &B{ - common: common{ - signal: make(chan bool), - name: "root", - w: buf, - chatty: tc.chatty, - }, - benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure. - benchTime: benchTimeFlag{d: 1 * time.Microsecond}, - } - root.runN(1) - if ok != !tc.failed { - t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed) - } - if !ok != root.Failed() { - t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) - } - // All tests are run as subtests - if root.result.N != 1 { - t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N) - } - got := strings.TrimSpace(buf.String()) - want := strings.TrimSpace(tc.output) - re := makeRegexp(want) - if ok, err := regexp.MatchString(re, got); !ok || err != nil { - t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) - } + t.Run(tc.desc, func(t *T) { + var ok bool + buf := &bytes.Buffer{} + // This is almost like the Benchmark function, except that we override + // the benchtime and catch the failure result of the subbenchmark. + root := &B{ + common: common{ + signal: make(chan bool), + name: "root", + w: buf, + chatty: tc.chatty, + }, + benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure. + benchTime: benchTimeFlag{d: 1 * time.Microsecond}, + } + root.runN(1) + if ok != !tc.failed { + t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed) + } + if !ok != root.Failed() { + t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) + } + // All tests are run as subtests + if root.result.N != 1 { + t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N) + } + got := strings.TrimSpace(buf.String()) + want := strings.TrimSpace(tc.output) + re := makeRegexp(want) + if ok, err := regexp.MatchString(re, got); !ok || err != nil { + t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) + } + }) } } func makeRegexp(s string) string { s = regexp.QuoteMeta(s) - s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d:`) + s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d\d?:`) s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`) return s } diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index 758af74..9f47eb8 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -320,6 +320,7 @@ var ( cpuListStr *string parallel *int testlog *string + printer *testPrinter haveExamples bool // are there examples? @@ -329,6 +330,48 @@ var ( numFailed uint32 // number of test failures ) +type testPrinter struct { + chatty bool + + lastNameMu sync.Mutex // guards lastName + lastName string // last printed test name in chatty mode +} + +func newTestPrinter(chatty bool) *testPrinter { + return &testPrinter{ + chatty: chatty, + } +} + +func (p *testPrinter) Print(testName, out string) { + p.Fprint(os.Stdout, testName, out) +} + +func (p *testPrinter) Fprint(w io.Writer, testName, out string) { + p.lastNameMu.Lock() + defer p.lastNameMu.Unlock() + + if !p.chatty || + strings.HasPrefix(out, "--- PASS") || + strings.HasPrefix(out, "--- FAIL") || + strings.HasPrefix(out, "=== CONT") || + strings.HasPrefix(out, "=== RUN") { + p.lastName = testName + fmt.Fprint(w, out) + return + } + + if p.lastName == "" { + p.lastName = testName + } else if p.lastName != testName { + // Always printed as-is, with 0 decoration or indentation. So, we skip + // printing to w. + fmt.Printf("=== CONT %s\n", testName) + p.lastName = testName + } + fmt.Fprint(w, out) +} + // The maximum number of stack frames to go through when skipping helper functions for // the purpose of decorating log messages. const maxStackLen = 50 @@ -347,10 +390,11 @@ type common struct { cleanup func() // optional function to be called at the end of the test chatty bool // A copy of the chatty flag. + bench bool // Whether the current test is a benchmark. finished bool // Test function has completed. - hasSub int32 // written atomically - raceErrors int // number of races detected during test - runner string // function name of tRunner running the test + hasSub int32 // Written atomically. + raceErrors int // Number of races detected during test. + runner string // Function name of tRunner running the test. parent *common level int // Nesting depth of test or benchmark. @@ -480,9 +524,6 @@ func (c *common) decorate(s string, skip int) string { buf := new(strings.Builder) // Every line is indented at least 4 spaces. buf.WriteString(" ") - if c.chatty { - fmt.Fprintf(buf, "%s: ", c.name) - } fmt.Fprintf(buf, "%s:%d: ", file, line) lines := strings.Split(s, "\n") if l := len(lines); l > 1 && lines[l-1] == "" { @@ -501,12 +542,12 @@ func (c *common) decorate(s string, skip int) string { // flushToParent writes c.output to the parent after first writing the header // with the given format and arguments. -func (c *common) flushToParent(format string, args ...interface{}) { +func (c *common) flushToParent(testName, format string, args ...interface{}) { p := c.parent p.mu.Lock() defer p.mu.Unlock() - fmt.Fprintf(p.w, format, args...) + printer.Fprint(p.w, testName, fmt.Sprintf(format, args...)) c.mu.Lock() defer c.mu.Unlock() @@ -680,7 +721,14 @@ func (c *common) logDepth(s string, depth int) { panic("Log in goroutine after " + c.name + " has completed") } else { if c.chatty { - fmt.Print(c.decorate(s, depth+1)) + if c.bench { + // Benchmarks don't print === CONT, so we should skip the test + // printer and just print straight to stdout. + fmt.Print(c.decorate(s, depth+1)) + } else { + printer.Print(c.name, c.decorate(s, depth+1)) + } + return } c.output = append(c.output, c.decorate(s, depth+1)...) @@ -909,7 +957,7 @@ func (t *T) Parallel() { for ; root.parent != nil; root = root.parent { } root.mu.Lock() - fmt.Fprintf(root.w, "=== CONT %s\n", t.name) + printer.Fprint(root.w, t.name, fmt.Sprintf("=== CONT %s\n", t.name)) root.mu.Unlock() } @@ -968,7 +1016,7 @@ func tRunner(t *T, fn func(t *T)) { root.duration += time.Since(root.start) d := root.duration root.mu.Unlock() - root.flushToParent("--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) + root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil { fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r) } @@ -1067,7 +1115,7 @@ func (t *T) Run(name string, f func(t *T)) bool { for ; root.parent != nil; root = root.parent { } root.mu.Lock() - fmt.Fprintf(root.w, "=== RUN %s\n", t.name) + printer.Fprint(root.w, t.name, fmt.Sprintf("=== RUN %s\n", t.name)) root.mu.Unlock() } // Instead of reducing the running count of this test before calling the @@ -1215,6 +1263,8 @@ func (m *M) Run() int { flag.Parse() } + printer = newTestPrinter(Verbose()) + if *parallel < 1 { fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer") flag.Usage() @@ -1254,12 +1304,12 @@ func (t *T) report() { dstr := fmtDuration(t.duration) format := "--- %s: %s (%s)\n" if t.Failed() { - t.flushToParent(format, "FAIL", t.name, dstr) + t.flushToParent(t.name, format, "FAIL", t.name, dstr) } else if t.chatty { if t.Skipped() { - t.flushToParent(format, "SKIP", t.name, dstr) + t.flushToParent(t.name, format, "SKIP", t.name, dstr) } else { - t.flushToParent(format, "PASS", t.name, dstr) + t.flushToParent(t.name, format, "PASS", t.name, dstr) } } } |