ipld-eth-server/vendor/github.com/aristanetworks/goarista/cmd/json2test/main.go
2019-07-23 15:26:18 -05:00

143 lines
3.2 KiB
Go

// Copyright (c) 2018 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
// json2test reformats 'go test -json' output as text as if the -json
// flag were not passed to go test. It is useful if you want to
// analyze go test -json output, but still want a human readable test
// log.
//
// Usage:
//
// go test -json > out.txt; <analysis program> out.txt; cat out.txt | json2test
//
package main
import (
"bufio"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"log"
"os"
"time"
)
var errTestFailure = errors.New("testfailure")
func main() {
verbose := flag.Bool("v", false, "Verbose output. "+
"By default only failed tests emit verbose output in test result summary.")
flag.Parse()
err := writeTestOutput(os.Stdin, os.Stdout, *verbose)
if err == errTestFailure {
os.Exit(1)
} else if err != nil {
log.Fatal(err)
}
}
type testEvent struct {
Time time.Time // encodes as an RFC3339-format string
Action string
Package string
Test string
Elapsed float64 // seconds
Output string
}
type test struct {
pkg string
test string
}
type outputBuffer struct {
output []string
}
func (o *outputBuffer) push(s string) {
o.output = append(o.output, s)
}
type testFailure struct {
t test
o outputBuffer
}
func writeTestOutput(in io.Reader, out io.Writer, verbose bool) error {
testOutputBuffer := map[test]*outputBuffer{}
var failures []testFailure
d := json.NewDecoder(in)
buf := bufio.NewWriter(out)
defer buf.Flush()
for {
var e testEvent
if err := d.Decode(&e); err != nil {
break
}
switch e.Action {
default:
continue
case "run":
testOutputBuffer[test{pkg: e.Package, test: e.Test}] = new(outputBuffer)
case "pass":
if !verbose && e.Test == "" {
// Match go test output:
// ok foo/bar 2.109s
fmt.Fprintf(buf, "ok \t%s\t%.3fs\n", e.Package, e.Elapsed)
}
// Don't hold onto text for passing
delete(testOutputBuffer, test{pkg: e.Package, test: e.Test})
case "fail":
if !verbose {
if e.Test != "" {
// Match go test output:
// --- FAIL: TestFooBar (0.00s)
fmt.Fprintf(buf, "--- FAIL: %s (%.3f)\n", e.Test, e.Elapsed)
} else {
// Match go test output:
// FAIL foo/bar 1.444s
fmt.Fprintf(buf, "FAIL\t%s\t%.3fs\n", e.Package, e.Elapsed)
}
}
// fail may be for a package, which won't have an entry in
// testOutputBuffer because packages don't have a "run"
// action.
t := test{pkg: e.Package, test: e.Test}
if o, ok := testOutputBuffer[t]; ok {
f := testFailure{t: t, o: *o}
delete(testOutputBuffer, t)
failures = append(failures, f)
}
case "output":
if verbose {
buf.WriteString(e.Output)
}
// output may be for a package, which won't have an entry
// in testOutputBuffer because packages don't have a "run"
// action.
if o, ok := testOutputBuffer[test{pkg: e.Package, test: e.Test}]; ok {
o.push(e.Output)
}
}
}
if len(failures) == 0 {
return nil
}
buf.WriteString("\nTest failures:\n")
for i, f := range failures {
fmt.Fprintf(buf, "[%d] %s.%s\n", i+1, f.t.pkg, f.t.test)
for _, s := range f.o.output {
buf.WriteString(s)
}
if i < len(failures)-1 {
buf.WriteByte('\n')
}
}
return errTestFailure
}