@@ -74,6 +74,8 @@ type TestInfo struct {
74
74
75
75
// TimeTaken is a description of the time taken to run the test case.
76
76
TimeTaken string
77
+
78
+ logs []string
77
79
}
78
80
79
81
// PackageTests contains information about the tests that have been executed for
@@ -92,6 +94,7 @@ type PackageTests struct {
92
94
type testResults struct {
93
95
result string
94
96
timeTaken string
97
+ logs []string
95
98
}
96
99
97
100
type colouredRow struct {
@@ -271,6 +274,8 @@ func findTestFiles(packs []string) ([]PackageInfo, error) {
271
274
}
272
275
273
276
func dumpErrorOutput (errorOutput * bytes.Buffer ) {
277
+ fmt .Fprintln (os .Stderr , "Output from stderr" )
278
+ fmt .Fprintln (os .Stderr , "------------------" )
274
279
scanner := bufio .NewScanner (errorOutput )
275
280
for scanner .Scan () {
276
281
line := scanner .Text ()
@@ -279,6 +284,8 @@ func dumpErrorOutput(errorOutput *bytes.Buffer) {
279
284
}
280
285
281
286
func dumpColourErrorOutput (errorOutput * bytes.Buffer ) {
287
+ fmt .Fprintln (os .Stderr , "Output from stderr" )
288
+ fmt .Fprintln (os .Stderr , "------------------" )
282
289
scanner := bufio .NewScanner (errorOutput )
283
290
for scanner .Scan () {
284
291
line := scanner .Text ()
@@ -288,9 +295,48 @@ func dumpColourErrorOutput(errorOutput *bytes.Buffer) {
288
295
fmt .Fprintf (os .Stderr , "%c[%dm\n " , 0x1b , 0 )
289
296
}
290
297
298
+ func parseTestOutput (output bytes.Buffer , results map [string ]* testResults ) string {
299
+ var coverage string
300
+
301
+ scanner := bufio .NewScanner (& output )
302
+ key := ""
303
+ for scanner .Scan () {
304
+ line := scanner .Text ()
305
+
306
+ stripped := strings .TrimSpace (line )
307
+ if strings .HasPrefix (stripped , "PASS" ) || strings .HasPrefix (stripped , "FAIL" ) ||
308
+ strings .HasPrefix (stripped , "=== RUN" ) {
309
+ key = ""
310
+ continue
311
+ }
312
+
313
+ matches := resultRegexp .FindStringSubmatch (line )
314
+ if matches != nil && len (matches ) == 4 {
315
+ key = matches [2 ]
316
+ results [key ] = & testResults {
317
+ result : matches [1 ],
318
+ timeTaken : matches [3 ],
319
+ logs : make ([]string , 0 , 16 )}
320
+ continue
321
+ }
322
+
323
+ if key != "" {
324
+ results [key ].logs = append (results [key ].logs , line )
325
+ }
326
+
327
+ if coverage == "" {
328
+ matches := coverageRegexp .FindStringSubmatch (line )
329
+ if matches == nil || len (matches ) != 2 {
330
+ continue
331
+ }
332
+ coverage = matches [1 ]
333
+ }
334
+ }
335
+ return coverage
336
+ }
337
+
291
338
func runPackageTests (p * PackageTests , coverFile string , errorOutput * bytes.Buffer ) (int , error ) {
292
339
var output bytes.Buffer
293
- var coverage string
294
340
295
341
exitCode := 0
296
342
results := make (map [string ]* testResults )
@@ -309,23 +355,7 @@ func runPackageTests(p *PackageTests, coverFile string, errorOutput *bytes.Buffe
309
355
cmd .Stderr = errorOutput
310
356
err := cmd .Run ()
311
357
312
- scanner := bufio .NewScanner (& output )
313
- for scanner .Scan () {
314
- line := scanner .Text ()
315
- matches := resultRegexp .FindStringSubmatch (line )
316
- if matches != nil && len (matches ) == 4 {
317
- results [matches [2 ]] = & testResults {matches [1 ], matches [3 ]}
318
- continue
319
- }
320
-
321
- if coverage == "" {
322
- matches := coverageRegexp .FindStringSubmatch (line )
323
- if matches == nil || len (matches ) != 2 {
324
- continue
325
- }
326
- coverage = matches [1 ]
327
- }
328
- }
358
+ coverage := parseTestOutput (output , results )
329
359
330
360
for _ , t := range p .Tests {
331
361
res := results [t .Name ]
@@ -340,6 +370,7 @@ func runPackageTests(p *PackageTests, coverFile string, errorOutput *bytes.Buffe
340
370
exitCode = 1
341
371
}
342
372
t .TimeTaken = res .timeTaken
373
+ t .logs = res .logs
343
374
}
344
375
}
345
376
@@ -393,30 +424,53 @@ func generateHTMLReport(tests []*PackageTests) error {
393
424
}
394
425
395
426
func findCommonPrefix (tests []* PackageTests ) string {
396
- if len (tests ) == 0 {
397
- return ""
398
- }
399
-
400
- pkgName := tests [0 ].Name
401
- OUTER:
402
- for {
427
+ for j := range tests {
428
+ pkgName := tests [j ].Name
403
429
index := strings .LastIndex (pkgName , "/" )
404
430
if index == - 1 {
405
431
return ""
406
432
}
407
- pkgName := pkgName [:index + 1 ]
433
+ pkgRoot := pkgName [:index + 1 ]
408
434
409
435
var i int
410
- for i = 1 ; i < len (tests ); i ++ {
411
- if ! strings .HasPrefix (tests [i ].Name , pkgName ) {
412
- continue OUTER
436
+ for i = 0 ; i < len (tests ); i ++ {
437
+ if i == j {
438
+ continue
439
+ }
440
+ if ! strings .HasPrefix (tests [i ].Name , pkgRoot ) {
441
+ break
442
+ }
443
+ }
444
+
445
+ if i == len (tests ) {
446
+ return pkgRoot
447
+ }
448
+ }
449
+
450
+ return ""
451
+ }
452
+
453
+ func dumpFailedTestOutput (prefix string , tests []* PackageTests , colourOn , colourOff string ) {
454
+ fmt .Fprintln (os .Stderr , "" )
455
+ fmt .Fprintln (os .Stderr , "Logs for failed tests" )
456
+ fmt .Fprintln (os .Stderr , "---------------------" )
457
+ for _ , p := range tests {
458
+ for _ , t := range p .Tests {
459
+ if ! t .Pass && len (t .logs ) > 0 {
460
+ fmt .Fprintf (os .Stderr , "%s" , colourOff )
461
+ pkgName := p .Name [len (prefix ):]
462
+ fmt .Fprintf (os .Stderr , "Logs for %s.%s\n " , pkgName , t .Name )
463
+ for _ , s := range t .logs {
464
+ fmt .Fprintf (os .Stderr , "%s%s\n " , colourOn , s )
465
+ }
413
466
}
414
467
}
415
- return pkgName
416
468
}
417
469
}
418
470
419
- func generateColourTextReport (tests []* PackageTests ) {
471
+ func generateColourTextReport (tests []* PackageTests , exitCode int ) {
472
+ colourOn := fmt .Sprintf ("%c[%dm" , 0x1b , 31 )
473
+ colourOff := fmt .Sprintf ("%c[%dm" , 0x1b , 0 )
420
474
prefix := findCommonPrefix (tests )
421
475
table := make ([]colouredRow , 0 , 128 )
422
476
table = append (table , colouredRow {
@@ -434,11 +488,11 @@ func generateColourTextReport(tests []*PackageTests) {
434
488
for _ , t := range p .Tests {
435
489
row := colouredRow {}
436
490
if ! t .Pass {
437
- row .ansiSeq = fmt . Sprintf ( "%c[%dm" , 0x1b , 31 )
491
+ row .ansiSeq = colourOn
438
492
coloured = true
439
493
} else if t .Pass && coloured {
440
494
coloured = false
441
- row .ansiSeq = fmt . Sprintf ( "%c[%dm" , 0x1b , 0 )
495
+ row .ansiSeq = colourOff
442
496
}
443
497
row .columns = []string {pkgName , t .Name , t .TimeTaken , t .Result }
444
498
for i := range colWidth {
@@ -463,9 +517,14 @@ func generateColourTextReport(tests []*PackageTests) {
463
517
if coloured {
464
518
fmt .Printf ("%c[%dm\n " , 0x1b , 0 )
465
519
}
520
+
521
+ if exitCode != 0 {
522
+ dumpFailedTestOutput (prefix , tests , colourOn , colourOff )
523
+ fmt .Println (colourOff )
524
+ }
466
525
}
467
526
468
- func generateTextReport (tests []* PackageTests ) {
527
+ func generateTextReport (tests []* PackageTests , exitCode int ) {
469
528
prefix := findCommonPrefix (tests )
470
529
w := new (tabwriter.Writer )
471
530
w .Init (os .Stdout , 0 , 8 , 1 , ' ' , 0 )
@@ -478,7 +537,10 @@ func generateTextReport(tests []*PackageTests) {
478
537
}
479
538
}
480
539
_ = w .Flush ()
481
- fmt .Println ()
540
+ if exitCode != 0 {
541
+ dumpFailedTestOutput (prefix , tests , "" , "" )
542
+ fmt .Println ()
543
+ }
482
544
}
483
545
484
546
func createCoverFile () (* os.File , error ) {
@@ -585,9 +647,9 @@ func main() {
585
647
586
648
if textOutput {
587
649
if colour {
588
- generateColourTextReport (tests )
650
+ generateColourTextReport (tests , exitCode )
589
651
} else {
590
- generateTextReport (tests )
652
+ generateTextReport (tests , exitCode )
591
653
}
592
654
} else {
593
655
err = generateHTMLReport (tests )
0 commit comments