@@ -327,7 +327,6 @@ var (
327
327
cpuListStr * string
328
328
parallel * int
329
329
testlog * string
330
- printer * testPrinter
331
330
332
331
haveExamples bool // are there examples?
333
332
@@ -337,55 +336,45 @@ var (
337
336
numFailed uint32 // number of test failures
338
337
)
339
338
340
- type testPrinter struct {
341
- chatty bool
342
-
339
+ type chattyPrinter struct {
340
+ w io.Writer
343
341
lastNameMu sync.Mutex // guards lastName
344
342
lastName string // last printed test name in chatty mode
345
343
}
346
344
347
- func newTestPrinter (chatty bool ) * testPrinter {
348
- return & testPrinter {
349
- chatty : chatty ,
350
- }
345
+ func newChattyPrinter (w io.Writer ) * chattyPrinter {
346
+ return & chattyPrinter {w : w }
351
347
}
352
348
353
- func (p * testPrinter ) Print (testName , out string ) {
354
- p .Fprint (os .Stdout , testName , out )
349
+ // Updatef prints a message about the status of the named test to w.
350
+ //
351
+ // The formatted message must include the test name itself.
352
+ func (p * chattyPrinter ) Updatef (testName , format string , args ... interface {}) {
353
+ p .lastNameMu .Lock ()
354
+ defer p .lastNameMu .Unlock ()
355
+
356
+ // Since the message already implies an association with a specific new test,
357
+ // we don't need to check what the old test name was or log an extra CONT line
358
+ // for it. (We're updating it anyway, and the current message already includes
359
+ // the test name.)
360
+ p .lastName = testName
361
+ fmt .Fprintf (p .w , format , args ... )
355
362
}
356
363
357
- func (p * testPrinter ) Fprint (w io.Writer , testName , out string ) {
364
+ // Printf prints a message, generated by the named test, that does not
365
+ // necessarily mention that tests's name itself.
366
+ func (p * chattyPrinter ) Printf (testName , format string , args ... interface {}) {
358
367
p .lastNameMu .Lock ()
359
368
defer p .lastNameMu .Unlock ()
360
369
361
- if ! p .chatty ||
362
- strings .HasPrefix (out , "--- PASS: " ) ||
363
- strings .HasPrefix (out , "--- FAIL: " ) ||
364
- strings .HasPrefix (out , "--- SKIP: " ) ||
365
- strings .HasPrefix (out , "=== RUN " ) ||
366
- strings .HasPrefix (out , "=== CONT " ) ||
367
- strings .HasPrefix (out , "=== PAUSE " ) {
368
- // If we're buffering test output (!p.chatty), we don't really care which
369
- // test is emitting which line so long as they are serialized.
370
- //
371
- // If the message already implies an association with a specific new test,
372
- // we don't need to check what the old test name was or log an extra CONT
373
- // line for it. (We're updating it anyway, and the current message already
374
- // includes the test name.)
375
- p .lastName = testName
376
- fmt .Fprint (w , out )
377
- return
378
- }
379
-
380
370
if p .lastName == "" {
381
371
p .lastName = testName
382
372
} else if p .lastName != testName {
383
- // Always printed as-is, with 0 decoration or indentation. So, we skip
384
- // printing to w.
385
- fmt .Printf ("=== CONT %s\n " , testName )
373
+ fmt .Fprintf (p .w , "=== CONT %s\n " , testName )
386
374
p .lastName = testName
387
375
}
388
- fmt .Fprint (w , out )
376
+
377
+ fmt .Fprintf (p .w , format , args ... )
389
378
}
390
379
391
380
// The maximum number of stack frames to go through when skipping helper functions for
@@ -407,12 +396,12 @@ type common struct {
407
396
cleanupName string // Name of the cleanup function.
408
397
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
409
398
410
- chatty bool // A copy of the chatty flag.
411
- bench bool // Whether the current test is a benchmark.
412
- finished bool // Test function has completed.
413
- hasSub int32 // Written atomically.
414
- raceErrors int // Number of races detected during test.
415
- runner string // Function name of tRunner running the test.
399
+ chatty * chattyPrinter // A copy of chattyPrinter, if the chatty flag is set .
400
+ bench bool // Whether the current test is a benchmark.
401
+ finished bool // Test function has completed.
402
+ hasSub int32 // Written atomically.
403
+ raceErrors int // Number of races detected during test.
404
+ runner string // Function name of tRunner running the test.
416
405
417
406
parent * common
418
407
level int // Nesting depth of test or benchmark.
@@ -574,12 +563,31 @@ func (c *common) flushToParent(testName, format string, args ...interface{}) {
574
563
p .mu .Lock ()
575
564
defer p .mu .Unlock ()
576
565
577
- printer .Fprint (p .w , testName , fmt .Sprintf (format , args ... ))
578
-
579
566
c .mu .Lock ()
580
567
defer c .mu .Unlock ()
581
- io .Copy (p .w , bytes .NewReader (c .output ))
582
- c .output = c .output [:0 ]
568
+
569
+ if len (c .output ) > 0 {
570
+ format += "%s"
571
+ args = append (args [:len (args ):len (args )], c .output )
572
+ c .output = c .output [:0 ] // but why?
573
+ }
574
+
575
+ if c .chatty != nil && p .w == c .chatty .w {
576
+ // We're flushing to the actual output, so track that this output is
577
+ // associated with a specific test (and, specifically, that the next output
578
+ // is *not* associated with that test).
579
+ //
580
+ // Moreover, if c.output is non-empty it is important that this write be
581
+ // atomic with respect to the output of other tests, so that we don't end up
582
+ // with confusing '=== CONT' lines in the middle of our '--- PASS' block.
583
+ // Neither humans nor cmd/test2json can parse those easily.
584
+ // (See https://golang.org/issue/40771.)
585
+ c .chatty .Updatef (testName , format , args ... )
586
+ } else {
587
+ // We're flushing to the output buffer of the parent test, which will
588
+ // itself follow a test-name header when it is finally flushed to stdout.
589
+ fmt .Fprintf (p .w , format , args ... )
590
+ }
583
591
}
584
592
585
593
type indenter struct {
@@ -748,13 +756,13 @@ func (c *common) logDepth(s string, depth int) {
748
756
}
749
757
panic ("Log in goroutine after " + c .name + " has completed" )
750
758
} else {
751
- if c .chatty {
759
+ if c .chatty != nil {
752
760
if c .bench {
753
761
// Benchmarks don't print === CONT, so we should skip the test
754
762
// printer and just print straight to stdout.
755
763
fmt .Print (c .decorate (s , depth + 1 ))
756
764
} else {
757
- printer . Print (c .name , c .decorate (s , depth + 1 ))
765
+ c . chatty . Printf (c .name , "%s" , c .decorate (s , depth + 1 ))
758
766
}
759
767
760
768
return
@@ -1003,34 +1011,22 @@ func (t *T) Parallel() {
1003
1011
t .parent .sub = append (t .parent .sub , t )
1004
1012
t .raceErrors += race .Errors ()
1005
1013
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 ()
1014
+ if t .chatty != nil {
1012
1015
// Unfortunately, even though PAUSE indicates that the named test is *no
1013
1016
// longer* running, cmd/test2json interprets it as changing the active test
1014
1017
// for the purpose of log parsing. We could fix cmd/test2json, but that
1015
1018
// won't fix existing deployments of third-party tools that already shell
1016
1019
// out to older builds of cmd/test2json — so merely fixing cmd/test2json
1017
1020
// isn't enough for now.
1018
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== PAUSE %s\n " , t .name ))
1019
- root .mu .Unlock ()
1021
+ t .chatty .Updatef (t .name , "=== PAUSE %s\n " , t .name )
1020
1022
}
1021
1023
1022
1024
t .signal <- true // Release calling test.
1023
1025
<- t .parent .barrier // Wait for the parent test to complete.
1024
1026
t .context .waitParallel ()
1025
1027
1026
- if t .chatty {
1027
- // Print directly to root's io.Writer so there is no delay.
1028
- root := t .parent
1029
- for ; root .parent != nil ; root = root .parent {
1030
- }
1031
- root .mu .Lock ()
1032
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== CONT %s\n " , t .name ))
1033
- root .mu .Unlock ()
1028
+ if t .chatty != nil {
1029
+ t .chatty .Updatef (t .name , "=== CONT %s\n " , t .name )
1034
1030
}
1035
1031
1036
1032
t .start = time .Now ()
@@ -1181,14 +1177,8 @@ func (t *T) Run(name string, f func(t *T)) bool {
1181
1177
}
1182
1178
t .w = indenter {& t .common }
1183
1179
1184
- if t .chatty {
1185
- // Print directly to root's io.Writer so there is no delay.
1186
- root := t .parent
1187
- for ; root .parent != nil ; root = root .parent {
1188
- }
1189
- root .mu .Lock ()
1190
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== RUN %s\n " , t .name ))
1191
- root .mu .Unlock ()
1180
+ if t .chatty != nil {
1181
+ t .chatty .Updatef (t .name , "=== RUN %s\n " , t .name )
1192
1182
}
1193
1183
// Instead of reducing the running count of this test before calling the
1194
1184
// tRunner and increasing it afterwards, we rely on tRunner keeping the
@@ -1355,8 +1345,6 @@ func (m *M) Run() (code int) {
1355
1345
flag .Parse ()
1356
1346
}
1357
1347
1358
- printer = newTestPrinter (Verbose ())
1359
-
1360
1348
if * parallel < 1 {
1361
1349
fmt .Fprintln (os .Stderr , "testing: -parallel can only be given a positive integer" )
1362
1350
flag .Usage ()
@@ -1401,7 +1389,7 @@ func (t *T) report() {
1401
1389
format := "--- %s: %s (%s)\n "
1402
1390
if t .Failed () {
1403
1391
t .flushToParent (t .name , format , "FAIL" , t .name , dstr )
1404
- } else if t .chatty {
1392
+ } else if t .chatty != nil {
1405
1393
if t .Skipped () {
1406
1394
t .flushToParent (t .name , format , "SKIP" , t .name , dstr )
1407
1395
} else {
@@ -1462,10 +1450,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
1462
1450
signal : make (chan bool ),
1463
1451
barrier : make (chan bool ),
1464
1452
w : os .Stdout ,
1465
- chatty : * chatty ,
1466
1453
},
1467
1454
context : ctx ,
1468
1455
}
1456
+ if Verbose () {
1457
+ t .chatty = newChattyPrinter (t .w )
1458
+ }
1469
1459
tRunner (t , func (t * T ) {
1470
1460
for _ , test := range tests {
1471
1461
t .Run (test .Name , test .F )
0 commit comments