@@ -320,7 +320,6 @@ var (
320
320
cpuListStr * string
321
321
parallel * int
322
322
testlog * string
323
- printer * testPrinter
324
323
325
324
haveExamples bool // are there examples?
326
325
@@ -330,55 +329,45 @@ var (
330
329
numFailed uint32 // number of test failures
331
330
)
332
331
333
- type testPrinter struct {
334
- chatty bool
335
-
332
+ type chattyPrinter struct {
333
+ w io.Writer
336
334
lastNameMu sync.Mutex // guards lastName
337
335
lastName string // last printed test name in chatty mode
338
336
}
339
337
340
- func newTestPrinter (chatty bool ) * testPrinter {
341
- return & testPrinter {
342
- chatty : chatty ,
343
- }
338
+ func newChattyPrinter (w io.Writer ) * chattyPrinter {
339
+ return & chattyPrinter {w : w }
344
340
}
345
341
346
- func (p * testPrinter ) Print (testName , out string ) {
347
- p .Fprint (os .Stdout , testName , out )
342
+ // Updatef prints a message about the status of the named test to w.
343
+ //
344
+ // The formatted message must include the test name itself.
345
+ func (p * chattyPrinter ) Updatef (testName , format string , args ... interface {}) {
346
+ p .lastNameMu .Lock ()
347
+ defer p .lastNameMu .Unlock ()
348
+
349
+ // Since the message already implies an association with a specific new test,
350
+ // we don't need to check what the old test name was or log an extra CONT line
351
+ // for it. (We're updating it anyway, and the current message already includes
352
+ // the test name.)
353
+ p .lastName = testName
354
+ fmt .Fprintf (p .w , format , args ... )
348
355
}
349
356
350
- func (p * testPrinter ) Fprint (w io.Writer , testName , out string ) {
357
+ // Printf prints a message, generated by the named test, that does not
358
+ // necessarily mention that tests's name itself.
359
+ func (p * chattyPrinter ) Printf (testName , format string , args ... interface {}) {
351
360
p .lastNameMu .Lock ()
352
361
defer p .lastNameMu .Unlock ()
353
362
354
- if ! p .chatty ||
355
- strings .HasPrefix (out , "--- PASS: " ) ||
356
- strings .HasPrefix (out , "--- FAIL: " ) ||
357
- strings .HasPrefix (out , "--- SKIP: " ) ||
358
- strings .HasPrefix (out , "=== RUN " ) ||
359
- strings .HasPrefix (out , "=== CONT " ) ||
360
- strings .HasPrefix (out , "=== PAUSE " ) {
361
- // If we're buffering test output (!p.chatty), we don't really care which
362
- // test is emitting which line so long as they are serialized.
363
- //
364
- // If the message already implies an association with a specific new test,
365
- // we don't need to check what the old test name was or log an extra CONT
366
- // line for it. (We're updating it anyway, and the current message already
367
- // includes the test name.)
368
- p .lastName = testName
369
- fmt .Fprint (w , out )
370
- return
371
- }
372
-
373
363
if p .lastName == "" {
374
364
p .lastName = testName
375
365
} else if p .lastName != testName {
376
- // Always printed as-is, with 0 decoration or indentation. So, we skip
377
- // printing to w.
378
- fmt .Printf ("=== CONT %s\n " , testName )
366
+ fmt .Fprintf (p .w , "=== CONT %s\n " , testName )
379
367
p .lastName = testName
380
368
}
381
- fmt .Fprint (w , out )
369
+
370
+ fmt .Fprintf (p .w , format , args ... )
382
371
}
383
372
384
373
// The maximum number of stack frames to go through when skipping helper functions for
@@ -398,12 +387,12 @@ type common struct {
398
387
helpers map [string ]struct {} // functions to be skipped when writing file/line info
399
388
cleanup func () // optional function to be called at the end of the test
400
389
401
- chatty bool // A copy of the chatty flag.
402
- bench bool // Whether the current test is a benchmark.
403
- finished bool // Test function has completed.
404
- hasSub int32 // Written atomically.
405
- raceErrors int // Number of races detected during test.
406
- runner string // Function name of tRunner running the test.
390
+ chatty * chattyPrinter // A copy of chattyPrinter, if the chatty flag is set .
391
+ bench bool // Whether the current test is a benchmark.
392
+ finished bool // Test function has completed.
393
+ hasSub int32 // Written atomically.
394
+ raceErrors int // Number of races detected during test.
395
+ runner string // Function name of tRunner running the test.
407
396
408
397
parent * common
409
398
level int // Nesting depth of test or benchmark.
@@ -556,12 +545,31 @@ func (c *common) flushToParent(testName, format string, args ...interface{}) {
556
545
p .mu .Lock ()
557
546
defer p .mu .Unlock ()
558
547
559
- printer .Fprint (p .w , testName , fmt .Sprintf (format , args ... ))
560
-
561
548
c .mu .Lock ()
562
549
defer c .mu .Unlock ()
563
- io .Copy (p .w , bytes .NewReader (c .output ))
564
- c .output = c .output [:0 ]
550
+
551
+ if len (c .output ) > 0 {
552
+ format += "%s"
553
+ args = append (args [:len (args ):len (args )], c .output )
554
+ c .output = c .output [:0 ] // but why?
555
+ }
556
+
557
+ if c .chatty != nil && p .w == c .chatty .w {
558
+ // We're flushing to the actual output, so track that this output is
559
+ // associated with a specific test (and, specifically, that the next output
560
+ // is *not* associated with that test).
561
+ //
562
+ // Moreover, if c.output is non-empty it is important that this write be
563
+ // atomic with respect to the output of other tests, so that we don't end up
564
+ // with confusing '=== CONT' lines in the middle of our '--- PASS' block.
565
+ // Neither humans nor cmd/test2json can parse those easily.
566
+ // (See https://golang.org/issue/40771.)
567
+ c .chatty .Updatef (testName , format , args ... )
568
+ } else {
569
+ // We're flushing to the output buffer of the parent test, which will
570
+ // itself follow a test-name header when it is finally flushed to stdout.
571
+ fmt .Fprintf (p .w , format , args ... )
572
+ }
565
573
}
566
574
567
575
type indenter struct {
@@ -729,13 +737,13 @@ func (c *common) logDepth(s string, depth int) {
729
737
}
730
738
panic ("Log in goroutine after " + c .name + " has completed" )
731
739
} else {
732
- if c .chatty {
740
+ if c .chatty != nil {
733
741
if c .bench {
734
742
// Benchmarks don't print === CONT, so we should skip the test
735
743
// printer and just print straight to stdout.
736
744
fmt .Print (c .decorate (s , depth + 1 ))
737
745
} else {
738
- printer . Print (c .name , c .decorate (s , depth + 1 ))
746
+ c . chatty . Printf (c .name , "%s" , c .decorate (s , depth + 1 ))
739
747
}
740
748
741
749
return
@@ -910,34 +918,22 @@ func (t *T) Parallel() {
910
918
t .parent .sub = append (t .parent .sub , t )
911
919
t .raceErrors += race .Errors ()
912
920
913
- if t .chatty {
914
- // Print directly to root's io.Writer so there is no delay.
915
- root := t .parent
916
- for ; root .parent != nil ; root = root .parent {
917
- }
918
- root .mu .Lock ()
921
+ if t .chatty != nil {
919
922
// Unfortunately, even though PAUSE indicates that the named test is *no
920
923
// longer* running, cmd/test2json interprets it as changing the active test
921
924
// for the purpose of log parsing. We could fix cmd/test2json, but that
922
925
// won't fix existing deployments of third-party tools that already shell
923
926
// out to older builds of cmd/test2json — so merely fixing cmd/test2json
924
927
// isn't enough for now.
925
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== PAUSE %s\n " , t .name ))
926
- root .mu .Unlock ()
928
+ t .chatty .Updatef (t .name , "=== PAUSE %s\n " , t .name )
927
929
}
928
930
929
931
t .signal <- true // Release calling test.
930
932
<- t .parent .barrier // Wait for the parent test to complete.
931
933
t .context .waitParallel ()
932
934
933
- if t .chatty {
934
- // Print directly to root's io.Writer so there is no delay.
935
- root := t .parent
936
- for ; root .parent != nil ; root = root .parent {
937
- }
938
- root .mu .Lock ()
939
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== CONT %s\n " , t .name ))
940
- root .mu .Unlock ()
935
+ if t .chatty != nil {
936
+ t .chatty .Updatef (t .name , "=== CONT %s\n " , t .name )
941
937
}
942
938
943
939
t .start = time .Now ()
@@ -1088,14 +1084,8 @@ func (t *T) Run(name string, f func(t *T)) bool {
1088
1084
}
1089
1085
t .w = indenter {& t .common }
1090
1086
1091
- if t .chatty {
1092
- // Print directly to root's io.Writer so there is no delay.
1093
- root := t .parent
1094
- for ; root .parent != nil ; root = root .parent {
1095
- }
1096
- root .mu .Lock ()
1097
- printer .Fprint (root .w , t .name , fmt .Sprintf ("=== RUN %s\n " , t .name ))
1098
- root .mu .Unlock ()
1087
+ if t .chatty != nil {
1088
+ t .chatty .Updatef (t .name , "=== RUN %s\n " , t .name )
1099
1089
}
1100
1090
// Instead of reducing the running count of this test before calling the
1101
1091
// tRunner and increasing it afterwards, we rely on tRunner keeping the
@@ -1242,8 +1232,6 @@ func (m *M) Run() int {
1242
1232
flag .Parse ()
1243
1233
}
1244
1234
1245
- printer = newTestPrinter (Verbose ())
1246
-
1247
1235
if * parallel < 1 {
1248
1236
fmt .Fprintln (os .Stderr , "testing: -parallel can only be given a positive integer" )
1249
1237
flag .Usage ()
@@ -1284,7 +1272,7 @@ func (t *T) report() {
1284
1272
format := "--- %s: %s (%s)\n "
1285
1273
if t .Failed () {
1286
1274
t .flushToParent (t .name , format , "FAIL" , t .name , dstr )
1287
- } else if t .chatty {
1275
+ } else if t .chatty != nil {
1288
1276
if t .Skipped () {
1289
1277
t .flushToParent (t .name , format , "SKIP" , t .name , dstr )
1290
1278
} else {
@@ -1340,10 +1328,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
1340
1328
signal : make (chan bool ),
1341
1329
barrier : make (chan bool ),
1342
1330
w : os .Stdout ,
1343
- chatty : * chatty ,
1344
1331
},
1345
1332
context : ctx ,
1346
1333
}
1334
+ if Verbose () {
1335
+ t .chatty = newChattyPrinter (t .w )
1336
+ }
1347
1337
tRunner (t , func (t * T ) {
1348
1338
for _ , test := range tests {
1349
1339
t .Run (test .Name , test .F )
0 commit comments