@@ -325,7 +325,6 @@ var (
325
325
cpuListStr * string
326
326
parallel * int
327
327
testlog * string
328
- printer * testPrinter
329
328
330
329
haveExamples bool // are there examples?
331
330
@@ -335,55 +334,45 @@ var (
335
334
numFailed uint32 // number of test failures
336
335
)
337
336
338
- type testPrinter struct {
339
- chatty bool
340
-
337
+ type chattyPrinter struct {
338
+ w io.Writer
341
339
lastNameMu sync.Mutex // guards lastName
342
340
lastName string // last printed test name in chatty mode
343
341
}
344
342
345
- func newTestPrinter (chatty bool ) * testPrinter {
346
- return & testPrinter {
347
- chatty : chatty ,
348
- }
343
+ func newChattyPrinter (w io.Writer ) * chattyPrinter {
344
+ return & chattyPrinter {w : w }
349
345
}
350
346
351
- func (p * testPrinter ) Print (testName , out string ) {
352
- p .Fprint (os .Stdout , testName , out )
347
+ // Updatef prints a message about the status of the named test to w.
348
+ //
349
+ // The formatted message must include the test name itself.
350
+ func (p * chattyPrinter ) Updatef (testName , format string , args ... interface {}) {
351
+ p .lastNameMu .Lock ()
352
+ defer p .lastNameMu .Unlock ()
353
+
354
+ // Since the message already implies an association with a specific new test,
355
+ // we don't need to check what the old test name was or log an extra CONT line
356
+ // for it. (We're updating it anyway, and the current message already includes
357
+ // the test name.)
358
+ p .lastName = testName
359
+ fmt .Fprintf (p .w , format , args ... )
353
360
}
354
361
355
- func (p * testPrinter ) Fprint (w io.Writer , testName , out string ) {
362
+ // Printf prints a message, generated by the named test, that does not
363
+ // necessarily mention that tests's name itself.
364
+ func (p * chattyPrinter ) Printf (testName , format string , args ... interface {}) {
356
365
p .lastNameMu .Lock ()
357
366
defer p .lastNameMu .Unlock ()
358
367
359
- if ! p .chatty ||
360
- strings .HasPrefix (out , "--- PASS: " ) ||
361
- strings .HasPrefix (out , "--- FAIL: " ) ||
362
- strings .HasPrefix (out , "--- SKIP: " ) ||
363
- strings .HasPrefix (out , "=== RUN " ) ||
364
- strings .HasPrefix (out , "=== CONT " ) ||
365
- strings .HasPrefix (out , "=== PAUSE " ) {
366
- // If we're buffering test output (!p.chatty), we don't really care which
367
- // test is emitting which line so long as they are serialized.
368
- //
369
- // If the message already implies an association with a specific new test,
370
- // we don't need to check what the old test name was or log an extra CONT
371
- // line for it. (We're updating it anyway, and the current message already
372
- // includes the test name.)
373
- p .lastName = testName
374
- fmt .Fprint (w , out )
375
- return
376
- }
377
-
378
368
if p .lastName == "" {
379
369
p .lastName = testName
380
370
} else if p .lastName != testName {
381
- // Always printed as-is, with 0 decoration or indentation. So, we skip
382
- // printing to w.
383
- fmt .Printf ("=== CONT %s\n " , testName )
371
+ fmt .Fprintf (p .w , "=== CONT %s\n " , testName )
384
372
p .lastName = testName
385
373
}
386
- fmt .Fprint (w , out )
374
+
375
+ fmt .Fprintf (p .w , format , args ... )
387
376
}
388
377
389
378
// The maximum number of stack frames to go through when skipping helper functions for
@@ -405,12 +394,12 @@ type common struct {
405
394
cleanupName string // Name of the cleanup function.
406
395
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
407
396
408
- chatty bool // A copy of the chatty flag.
409
- bench bool // Whether the current test is a benchmark.
410
- finished bool // Test function has completed.
411
- hasSub int32 // Written atomically.
412
- raceErrors int // Number of races detected during test.
413
- runner string // Function name of tRunner running the test.
397
+ chatty * chattyPrinter // A copy of chattyPrinter, if the chatty flag is set .
398
+ bench bool // Whether the current test is a benchmark.
399
+ finished bool // Test function has completed.
400
+ hasSub int32 // Written atomically.
401
+ raceErrors int // Number of races detected during test.
402
+ runner string // Function name of tRunner running the test.
414
403
415
404
parent * common
416
405
level int // Nesting depth of test or benchmark.
@@ -572,12 +561,31 @@ func (c *common) flushToParent(testName, format string, args ...interface{}) {
572
561
p .mu .Lock ()
573
562
defer p .mu .Unlock ()
574
563
575
- printer .Fprint (p .w , testName , fmt .Sprintf (format , args ... ))
576
-
577
564
c .mu .Lock ()
578
565
defer c .mu .Unlock ()
579
- io .Copy (p .w , bytes .NewReader (c .output ))
580
- c .output = c .output [:0 ]
566
+
567
+ if len (c .output ) > 0 {
568
+ format += "%s"
569
+ args = append (args [:len (args ):len (args )], c .output )
570
+ c .output = c .output [:0 ] // but why?
571
+ }
572
+
573
+ if c .chatty != nil && p .w == c .chatty .w {
574
+ // We're flushing to the actual output, so track that this output is
575
+ // associated with a specific test (and, specifically, that the next output
576
+ // is *not* associated with that test).
577
+ //
578
+ // Moreover, if c.output is non-empty it is important that this write be
579
+ // atomic with respect to the output of other tests, so that we don't end up
580
+ // with confusing '=== CONT' lines in the middle of our '--- PASS' block.
581
+ // Neither humans nor cmd/test2json can parse those easily.
582
+ // (See https://golang.org/issue/40771.)
583
+ c .chatty .Updatef (testName , format , args ... )
584
+ } else {
585
+ // We're flushing to the output buffer of the parent test, which will
586
+ // itself follow a test-name header when it is finally flushed to stdout.
587
+ fmt .Fprintf (p .w , format , args ... )
588
+ }
581
589
}
582
590
583
591
type indenter struct {
@@ -746,13 +754,13 @@ func (c *common) logDepth(s string, depth int) {
746
754
}
747
755
panic ("Log in goroutine after " + c .name + " has completed" )
748
756
} else {
749
- if c .chatty {
757
+ if c .chatty != nil {
750
758
if c .bench {
751
759
// Benchmarks don't print === CONT, so we should skip the test
752
760
// printer and just print straight to stdout.
753
761
fmt .Print (c .decorate (s , depth + 1 ))
754
762
} else {
755
- printer . Print (c .name , c .decorate (s , depth + 1 ))
763
+ c . chatty . Printf (c .name , "%s" , c .decorate (s , depth + 1 ))
756
764
}
757
765
758
766
return
@@ -983,34 +991,22 @@ func (t *T) Parallel() {
983
991
t .parent .sub = append (t .parent .sub , t )
984
992
t .raceErrors += race .Errors ()
985
993
986
- if t .chatty {
987
- // Print directly to root's io.Writer so there is no delay.
988
- root := t .parent
989
- for ; root .parent != nil ; root = root .parent {
990
- }
991
- root .mu .Lock ()
994
+ if t .chatty != nil {
992
995
// Unfortunately, even though PAUSE indicates that the named test is *no
993
996
// longer* running, cmd/test2json interprets it as changing the active test
994
997
// for the purpose of log parsing. We could fix cmd/test2json, but that
995
998
// won't fix existing deployments of third-party tools that already shell
996
999
// out to older builds of cmd/test2json — so merely fixing cmd/test2json
997
1000
// isn't enough for now.
998
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== PAUSE %s\n " , t .name ))
999
- root .mu .Unlock ()
1001
+ t .chatty .Updatef (t .name , "=== PAUSE %s\n " , t .name )
1000
1002
}
1001
1003
1002
1004
t .signal <- true // Release calling test.
1003
1005
<- t .parent .barrier // Wait for the parent test to complete.
1004
1006
t .context .waitParallel ()
1005
1007
1006
- if t .chatty {
1007
- // Print directly to root's io.Writer so there is no delay.
1008
- root := t .parent
1009
- for ; root .parent != nil ; root = root .parent {
1010
- }
1011
- root .mu .Lock ()
1012
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== CONT %s\n " , t .name ))
1013
- root .mu .Unlock ()
1008
+ if t .chatty != nil {
1009
+ t .chatty .Updatef (t .name , "=== CONT %s\n " , t .name )
1014
1010
}
1015
1011
1016
1012
t .start = time .Now ()
@@ -1161,14 +1157,8 @@ func (t *T) Run(name string, f func(t *T)) bool {
1161
1157
}
1162
1158
t .w = indenter {& t .common }
1163
1159
1164
- if t .chatty {
1165
- // Print directly to root's io.Writer so there is no delay.
1166
- root := t .parent
1167
- for ; root .parent != nil ; root = root .parent {
1168
- }
1169
- root .mu .Lock ()
1170
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== RUN %s\n " , t .name ))
1171
- root .mu .Unlock ()
1160
+ if t .chatty != nil {
1161
+ t .chatty .Updatef (t .name , "=== RUN %s\n " , t .name )
1172
1162
}
1173
1163
// Instead of reducing the running count of this test before calling the
1174
1164
// tRunner and increasing it afterwards, we rely on tRunner keeping the
@@ -1333,8 +1323,6 @@ func (m *M) Run() (code int) {
1333
1323
flag .Parse ()
1334
1324
}
1335
1325
1336
- printer = newTestPrinter (Verbose ())
1337
-
1338
1326
if * parallel < 1 {
1339
1327
fmt .Fprintln (os .Stderr , "testing: -parallel can only be given a positive integer" )
1340
1328
flag .Usage ()
@@ -1379,7 +1367,7 @@ func (t *T) report() {
1379
1367
format := "--- %s: %s (%s)\n "
1380
1368
if t .Failed () {
1381
1369
t .flushToParent (t .name , format , "FAIL" , t .name , dstr )
1382
- } else if t .chatty {
1370
+ } else if t .chatty != nil {
1383
1371
if t .Skipped () {
1384
1372
t .flushToParent (t .name , format , "SKIP" , t .name , dstr )
1385
1373
} else {
@@ -1440,10 +1428,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
1440
1428
signal : make (chan bool ),
1441
1429
barrier : make (chan bool ),
1442
1430
w : os .Stdout ,
1443
- chatty : * chatty ,
1444
1431
},
1445
1432
context : ctx ,
1446
1433
}
1434
+ if Verbose () {
1435
+ t .chatty = newChattyPrinter (t .w )
1436
+ }
1447
1437
tRunner (t , func (t * T ) {
1448
1438
for _ , test := range tests {
1449
1439
t .Run (test .Name , test .F )
0 commit comments