From c78e04707fc81493756c96945e3d2e76936e7a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Stemmer?= Date: Mon, 14 Mar 2022 23:17:57 +0000 Subject: [PATCH] gtr,parser/gotest: move Event and building a report to parser/gotest The Parse method now directly returns a report, rather than a list of events that then need to be converted into a report. As part of this change, the Event struct has also been moved to the gotest package. It's now the responsibility of the parser to construct a gtr.Report. --- go-junit-report.go | 11 +- go-junit-report_test.go | 9 +- pkg/gtr/builder.go | 7 +- pkg/gtr/event.go | 53 ---------- pkg/gtr/gtr.go | 59 +++++------ pkg/gtr/gtr_test.go | 112 ++++---------------- pkg/parser/gotest/event.go | 25 +++++ pkg/parser/gotest/gotest.go | 72 ++++++++++--- pkg/parser/gotest/gotest_test.go | 176 +++++++++++++++++++++++-------- 9 files changed, 272 insertions(+), 252 deletions(-) delete mode 100644 pkg/gtr/event.go create mode 100644 pkg/parser/gotest/event.go diff --git a/go-junit-report.go b/go-junit-report.go index bf7405b..10bb660 100644 --- a/go-junit-report.go +++ b/go-junit-report.go @@ -9,7 +9,6 @@ import ( "strings" "time" - "github.com/jstemmer/go-junit-report/v2/pkg/gtr" "github.com/jstemmer/go-junit-report/v2/pkg/junit" "github.com/jstemmer/go-junit-report/v2/pkg/parser/gotest" ) @@ -76,18 +75,18 @@ func main() { in = io.TeeReader(in, os.Stdout) } - parser := gotest.New() - events, err := parser.Parse(in) + parser := gotest.New(gotest.PackageName(*packageName)) + + report, err := parser.Parse(in) if err != nil { - exitf("error reading input: %s\n", err) + exitf("error parsing input: %s\n", err) } if *printEvents { - for i, ev := range events { + for i, ev := range parser.Events() { fmt.Printf("%02d: %#v\n", i, ev) } } - report := gtr.FromEvents(events, *packageName) for i := range report.Packages { for k, v := range properties { report.Packages[i].SetProperty(k, v) diff --git a/go-junit-report_test.go b/go-junit-report_test.go index 848643f..137f745 100644 --- a/go-junit-report_test.go +++ b/go-junit-report_test.go @@ -13,7 +13,6 @@ import ( "testing" "time" - "github.com/jstemmer/go-junit-report/v2/pkg/gtr" "github.com/jstemmer/go-junit-report/v2/pkg/junit" "github.com/jstemmer/go-junit-report/v2/pkg/parser/gotest" @@ -192,20 +191,20 @@ func testReport(input, reportFile, packageName string, t *testing.T) { } defer file.Close() - parser := gotest.New() - events, err := parser.Parse(file) + parser := gotest.New(gotest.PackageName(packageName)) + + report, err := parser.Parse(file) if err != nil { t.Fatal(err) } if *printEvents { - for _, event := range events { + for _, event := range parser.Events() { t.Logf("Event: %+v", event) } } testTime := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC) - report := gtr.FromEvents(events, packageName) actual := junit.CreateFromReport(report, "hostname", testTime) expectedXML, err := loadTestReport(reportFile, "") diff --git a/pkg/gtr/builder.go b/pkg/gtr/builder.go index 66a1448..6034c2f 100644 --- a/pkg/gtr/builder.go +++ b/pkg/gtr/builder.go @@ -26,18 +26,17 @@ type ReportBuilder struct { coverage float64 // coverage percentage // default values - packageName string + PackageName string } // NewReportBuilder creates a new ReportBuilder. -func NewReportBuilder(packageName string) *ReportBuilder { +func NewReportBuilder() *ReportBuilder { return &ReportBuilder{ tests: make(map[int]Test), benchmarks: make(map[int]Benchmark), buildErrors: make(map[int]Error), runErrors: make(map[int]Error), nextId: 1, - packageName: packageName, } } @@ -54,7 +53,7 @@ func (b *ReportBuilder) newId() int { // benchmark did not end with a summary. func (b *ReportBuilder) flush() { if len(b.tests) > 0 || len(b.benchmarks) > 0 { - b.CreatePackage(b.packageName, "", 0, "") + b.CreatePackage(b.PackageName, "", 0, "") } } diff --git a/pkg/gtr/event.go b/pkg/gtr/event.go deleted file mode 100644 index 6717ba8..0000000 --- a/pkg/gtr/event.go +++ /dev/null @@ -1,53 +0,0 @@ -package gtr - -import "time" - -type Result int - -const ( - Unknown Result = iota - Pass - Fail - Skip -) - -func (r Result) String() string { - switch r { - case Unknown: - return "UNKNOWN" - case Pass: - return "PASS" - case Fail: - return "FAIL" - case Skip: - return "SKIP" - default: - panic("invalid Result") - } -} - -// TODO: provide some common types, or have a custom type (e.g. -// identifier:type, where identifier is a unique identifier for a particular -// parser.) - -// Event is a single event in a test or benchmark. -type Event struct { - Type string - - Name string - Result string - Duration time.Duration - Data string - Indent int - - // Code coverage - CovPct float64 - CovPackages []string - - // Benchmarks - Iterations int64 - NsPerOp float64 - MBPerSec float64 - BytesPerOp int64 - AllocsPerOp int64 -} diff --git a/pkg/gtr/gtr.go b/pkg/gtr/gtr.go index 3c071d3..2709399 100644 --- a/pkg/gtr/gtr.go +++ b/pkg/gtr/gtr.go @@ -3,11 +3,35 @@ package gtr import ( - "fmt" "strings" "time" ) +// Result is the result of a test or benchmark. +type Result int + +const ( + Unknown Result = iota + Pass + Fail + Skip +) + +func (r Result) String() string { + switch r { + case Unknown: + return "UNKNOWN" + case Pass: + return "PASS" + case Fail: + return "FAIL" + case Skip: + return "SKIP" + default: + panic("invalid Result") + } +} + // Report contains the build, test and/or benchmark results of a collection of // packages. type Report struct { @@ -84,39 +108,6 @@ type Error struct { Output []string } -// FromEvents creates a Report from the given list of events. -// TODO: make packageName optional option -func FromEvents(events []Event, packageName string) Report { - report := NewReportBuilder(packageName) - for _, ev := range events { - switch ev.Type { - case "run_test": - report.CreateTest(ev.Name) - case "pause_test": - report.PauseTest(ev.Name) - case "cont_test": - report.ContinueTest(ev.Name) - case "end_test": - report.EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent) - case "benchmark": - report.Benchmark(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp) - case "status": - report.End() - case "summary": - report.CreatePackage(ev.Name, ev.Result, ev.Duration, ev.Data) - case "coverage": - report.Coverage(ev.CovPct, ev.CovPackages) - case "build_output": - report.CreateBuildError(ev.Name) - case "output": - report.AppendOutput(ev.Data) - default: - fmt.Printf("unhandled event type: %v\n", ev.Type) - } - } - return report.Build() -} - // TrimPrefixSpaces trims the leading whitespace of the given line using the // indentation level of the test. Printing logs in a Go test is typically // prepended by blocks of 4 spaces to align it with the rest of the test diff --git a/pkg/gtr/gtr_test.go b/pkg/gtr/gtr_test.go index 1338ecf..06cf3ae 100644 --- a/pkg/gtr/gtr_test.go +++ b/pkg/gtr/gtr_test.go @@ -1,100 +1,26 @@ package gtr -import ( - "testing" - "time" +import "testing" - "github.com/google/go-cmp/cmp" -) - -func TestFromEvents(t *testing.T) { - events := []Event{ - {Type: "run_test", Name: "TestOne"}, - {Type: "output", Data: "\tHello"}, - {Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 1 * time.Millisecond}, - {Type: "status", Result: "PASS"}, - {Type: "run_test", Name: "TestSkip"}, - {Type: "end_test", Name: "TestSkip", Result: "SKIP", Duration: 1 * time.Millisecond}, - {Type: "summary", Result: "ok", Name: "package/name", Duration: 1 * time.Millisecond}, - {Type: "run_test", Name: "TestOne"}, - {Type: "output", Data: "\tfile_test.go:10: error"}, - {Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 1 * time.Millisecond}, - {Type: "status", Result: "FAIL"}, - {Type: "summary", Result: "FAIL", Name: "package/name2", Duration: 1 * time.Millisecond}, - {Type: "output", Data: "goarch: amd64"}, - {Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 100}, - {Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 300}, - {Type: "status", Result: "PASS"}, - {Type: "summary", Result: "ok", Name: "package/name3", Duration: 1234 * time.Millisecond}, - {Type: "build_output", Name: "package/failing1"}, - {Type: "output", Data: "error message"}, - {Type: "summary", Result: "FAIL", Name: "package/failing1", Data: "[build failed]"}, - } - expected := Report{ - Packages: []Package{ - { - Name: "package/name", - Duration: 1 * time.Millisecond, - Tests: []Test{ - { - Name: "TestOne", - Duration: 1 * time.Millisecond, - Result: Pass, - Output: []string{ - "\tHello", // TODO: strip tabs? - }, - }, - { - Name: "TestSkip", - Duration: 1 * time.Millisecond, - Result: Skip, - }, - }, - }, - { - Name: "package/name2", - Duration: 1 * time.Millisecond, - Tests: []Test{ - { - Name: "TestOne", - Duration: 1 * time.Millisecond, - Result: Fail, - Output: []string{ - "\tfile_test.go:10: error", - }, - }, - }, - }, - { - Name: "package/name3", - Duration: 1234 * time.Millisecond, - Benchmarks: []Benchmark{ - { - Name: "BenchmarkOne", - Result: Pass, - NsPerOp: 100, - }, - { - Name: "BenchmarkOne", - Result: Pass, - NsPerOp: 300, - }, - }, - Output: []string{"goarch: amd64"}, - }, - { - Name: "package/failing1", - BuildError: Error{ - Name: "package/failing1", - Cause: "[build failed]", - Output: []string{"error message"}, - }, - }, - }, +func TestTrimPrefixSpaces(t *testing.T) { + tests := []struct { + input string + indent int + want string + }{ + {"", 0, ""}, + {"\ttest", 0, "test"}, // prefixed tabs are always trimmed + {" test", 0, "test"}, + {" test", 0, " test"}, + {" test", 2, "test"}, + {" test", 1, " test"}, // prefix is not a multiple of 4 + {" \t test", 3, " test"}, } - actual := FromEvents(events, "") - if diff := cmp.Diff(actual, expected); diff != "" { - t.Errorf("FromEvents report incorrect, diff (-got, +want):\n%v", diff) + for _, test := range tests { + got := TrimPrefixSpaces(test.input, test.indent) + if got != test.want { + t.Errorf("TrimPrefixSpaces(%q, %d) incorrect, got %q, want %q", test.input, test.indent, got, test.want) + } } } diff --git a/pkg/parser/gotest/event.go b/pkg/parser/gotest/event.go new file mode 100644 index 0000000..2fdf021 --- /dev/null +++ b/pkg/parser/gotest/event.go @@ -0,0 +1,25 @@ +package gotest + +import "time" + +// Event is a single event in a test or benchmark. +type Event struct { + Type string + + Name string + Result string + Duration time.Duration + Data string + Indent int + + // Code coverage + CovPct float64 + CovPackages []string + + // Benchmarks + Iterations int64 + NsPerOp float64 + MBPerSec float64 + BytesPerOp int64 + AllocsPerOp int64 +} diff --git a/pkg/parser/gotest/gotest.go b/pkg/parser/gotest/gotest.go index 3f2e3dc..44efbbe 100644 --- a/pkg/parser/gotest/gotest.go +++ b/pkg/parser/gotest/gotest.go @@ -59,16 +59,58 @@ func New(options ...Option) *Parser { type Parser struct { packageName string - events []gtr.Event + events []Event } -// Parse parses Go test output from the given io.Reader r. -func (p *Parser) Parse(r io.Reader) ([]gtr.Event, error) { +// Parse parses Go test output from the given io.Reader r and returns +// gtr.Report. +func (p *Parser) Parse(r io.Reader) (gtr.Report, error) { + p.events = nil s := bufio.NewScanner(r) for s.Scan() { p.parseLine(s.Text()) } - return p.events, s.Err() + return p.report(p.events), s.Err() +} + +// report generates a gtr.Report from the given list of events. +func (p *Parser) report(events []Event) gtr.Report { + rb := gtr.NewReportBuilder() + rb.PackageName = p.packageName + for _, ev := range events { + switch ev.Type { + case "run_test": + rb.CreateTest(ev.Name) + case "pause_test": + rb.PauseTest(ev.Name) + case "cont_test": + rb.ContinueTest(ev.Name) + case "end_test": + rb.EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent) + case "benchmark": + rb.Benchmark(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp) + case "status": + rb.End() + case "summary": + rb.CreatePackage(ev.Name, ev.Result, ev.Duration, ev.Data) + case "coverage": + rb.Coverage(ev.CovPct, ev.CovPackages) + case "build_output": + rb.CreateBuildError(ev.Name) + case "output": + rb.AppendOutput(ev.Data) + default: + fmt.Printf("unhandled event type: %v\n", ev.Type) + } + } + return rb.Build() +} + +// Events returns the events created by the parser. +func (p *Parser) Events() []Event { + events := make([]Event, len(p.events)) + copy(events, p.events) + return events } func (p *Parser) parseLine(line string) { @@ -101,20 +143,20 @@ func (p *Parser) parseLine(line string) { } } -func (p *Parser) add(event gtr.Event) { +func (p *Parser) add(event Event) { p.events = append(p.events, event) } func (p *Parser) runTest(name string) { - p.add(gtr.Event{Type: "run_test", Name: name}) + p.add(Event{Type: "run_test", Name: name}) } func (p *Parser) pauseTest(name string) { - p.add(gtr.Event{Type: "pause_test", Name: name}) + p.add(Event{Type: "pause_test", Name: name}) } func (p *Parser) contTest(name string) { - p.add(gtr.Event{Type: "cont_test", Name: name}) + p.add(Event{Type: "cont_test", Name: name}) } func (p *Parser) endTest(line, indent, result, name, duration string) { @@ -122,7 +164,7 @@ func (p *Parser) endTest(line, indent, result, name, duration string) { p.output(line[:idx]) } _, n := stripIndent(indent) - p.add(gtr.Event{ + p.add(Event{ Type: "end_test", Name: name, Result: result, @@ -132,11 +174,11 @@ func (p *Parser) endTest(line, indent, result, name, duration string) { } func (p *Parser) status(result string) { - p.add(gtr.Event{Type: "status", Result: result}) + p.add(Event{Type: "status", Result: result}) } func (p *Parser) summary(result, name, duration, cached, status, covpct, packages string) { - p.add(gtr.Event{ + p.add(Event{ Type: "summary", Result: result, Name: name, @@ -148,7 +190,7 @@ func (p *Parser) summary(result, name, duration, cached, status, covpct, package } func (p *Parser) coverage(percent, packages string) { - p.add(gtr.Event{ + p.add(Event{ Type: "coverage", CovPct: parseFloat(percent), CovPackages: parsePackages(packages), @@ -156,7 +198,7 @@ func (p *Parser) coverage(percent, packages string) { } func (p *Parser) benchmark(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp string) { - p.add(gtr.Event{ + p.add(Event{ Type: "benchmark", Name: name, Iterations: parseInt(iterations), @@ -168,14 +210,14 @@ func (p *Parser) benchmark(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allo } func (p *Parser) buildOutput(packageName string) { - p.add(gtr.Event{ + p.add(Event{ Type: "build_output", Name: packageName, }) } func (p *Parser) output(line string) { - p.add(gtr.Event{Type: "output", Data: line}) + p.add(Event{Type: "output", Data: line}) } func parseSeconds(s string) time.Duration { diff --git a/pkg/parser/gotest/gotest_test.go b/pkg/parser/gotest/gotest_test.go index e7297d7..56ef314 100644 --- a/pkg/parser/gotest/gotest_test.go +++ b/pkg/parser/gotest/gotest_test.go @@ -6,9 +6,8 @@ import ( "testing" "time" - "github.com/jstemmer/go-junit-report/v2/pkg/gtr" - "github.com/google/go-cmp/cmp" + "github.com/jstemmer/go-junit-report/v2/pkg/gtr" ) type parseLineTest struct { @@ -19,160 +18,160 @@ type parseLineTest struct { var parseLineTests = []parseLineTest{ { "=== RUN TestOne", - gtr.Event{Type: "run_test", Name: "TestOne"}, + Event{Type: "run_test", Name: "TestOne"}, }, { "=== RUN TestTwo/Subtest", - gtr.Event{Type: "run_test", Name: "TestTwo/Subtest"}, + Event{Type: "run_test", Name: "TestTwo/Subtest"}, }, { "=== PAUSE TestOne", - gtr.Event{Type: "pause_test", Name: "TestOne"}, + Event{Type: "pause_test", Name: "TestOne"}, }, { "=== CONT TestOne", - gtr.Event{Type: "cont_test", Name: "TestOne"}, + Event{Type: "cont_test", Name: "TestOne"}, }, { "--- PASS: TestOne (12.34 seconds)", - gtr.Event{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 12_340 * time.Millisecond}, + Event{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 12_340 * time.Millisecond}, }, { " --- SKIP: TestOne/Subtest (0.00s)", - gtr.Event{Type: "end_test", Name: "TestOne/Subtest", Result: "SKIP", Indent: 1}, + Event{Type: "end_test", Name: "TestOne/Subtest", Result: "SKIP", Indent: 1}, }, { " --- FAIL: TestOne/Subtest/#01 (0.35s)", - gtr.Event{Type: "end_test", Name: "TestOne/Subtest/#01", Result: "FAIL", Duration: 350 * time.Millisecond, Indent: 2}, + Event{Type: "end_test", Name: "TestOne/Subtest/#01", Result: "FAIL", Duration: 350 * time.Millisecond, Indent: 2}, }, { "some text--- PASS: TestTwo (0.06 seconds)", - []gtr.Event{ + []Event{ {Type: "output", Data: "some text"}, {Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 60 * time.Millisecond}, }, }, { "PASS", - gtr.Event{Type: "status", Result: "PASS"}, + Event{Type: "status", Result: "PASS"}, }, { "FAIL", - gtr.Event{Type: "status", Result: "FAIL"}, + Event{Type: "status", Result: "FAIL"}, }, { "SKIP", - gtr.Event{Type: "status", Result: "SKIP"}, + Event{Type: "status", Result: "SKIP"}, }, { "ok package/name/ok 0.100s", - gtr.Event{Type: "summary", Name: "package/name/ok", Result: "ok", Duration: 100 * time.Millisecond}, + Event{Type: "summary", Name: "package/name/ok", Result: "ok", Duration: 100 * time.Millisecond}, }, { "FAIL package/name/failing [build failed]", - gtr.Event{Type: "summary", Name: "package/name/failing", Result: "FAIL", Data: "[build failed]"}, + Event{Type: "summary", Name: "package/name/failing", Result: "FAIL", Data: "[build failed]"}, }, { "FAIL package/other/failing [setup failed]", - gtr.Event{Type: "summary", Name: "package/other/failing", Result: "FAIL", Data: "[setup failed]"}, + Event{Type: "summary", Name: "package/other/failing", Result: "FAIL", Data: "[setup failed]"}, }, { "ok package/other (cached)", - gtr.Event{Type: "summary", Name: "package/other", Result: "ok", Data: "(cached)"}, + Event{Type: "summary", Name: "package/other", Result: "ok", Data: "(cached)"}, }, { "ok package/name 0.400s coverage: 10.0% of statements", - gtr.Event{Type: "summary", Name: "package/name", Result: "ok", Duration: 400 * time.Millisecond, CovPct: 10}, + Event{Type: "summary", Name: "package/name", Result: "ok", Duration: 400 * time.Millisecond, CovPct: 10}, }, { "ok package/name 4.200s coverage: 99.8% of statements in fmt, encoding/xml", - gtr.Event{Type: "summary", Name: "package/name", Result: "ok", Duration: 4200 * time.Millisecond, CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}}, + Event{Type: "summary", Name: "package/name", Result: "ok", Duration: 4200 * time.Millisecond, CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}}, }, { "? package/name [no test files]", - gtr.Event{Type: "summary", Name: "package/name", Result: "?", Data: "[no test files]"}, + Event{Type: "summary", Name: "package/name", Result: "?", Data: "[no test files]"}, }, { "ok package/name 0.001s [no tests to run]", - gtr.Event{Type: "summary", Name: "package/name", Result: "ok", Duration: 1 * time.Millisecond, Data: "[no tests to run]"}, + Event{Type: "summary", Name: "package/name", Result: "ok", Duration: 1 * time.Millisecond, Data: "[no tests to run]"}, }, { "ok package/name (cached) [no tests to run]", - gtr.Event{Type: "summary", Name: "package/name", Result: "ok", Data: "(cached) [no tests to run]"}, + Event{Type: "summary", Name: "package/name", Result: "ok", Data: "(cached) [no tests to run]"}, }, { "coverage: 10% of statements", - gtr.Event{Type: "coverage", CovPct: 10}, + Event{Type: "coverage", CovPct: 10}, }, { "coverage: 10% of statements in fmt, encoding/xml", - gtr.Event{Type: "coverage", CovPct: 10, CovPackages: []string{"fmt", "encoding/xml"}}, + Event{Type: "coverage", CovPct: 10, CovPackages: []string{"fmt", "encoding/xml"}}, }, { "coverage: 13.37% of statements", - gtr.Event{Type: "coverage", CovPct: 13.37}, + Event{Type: "coverage", CovPct: 13.37}, }, { "coverage: 99.8% of statements in fmt, encoding/xml", - gtr.Event{Type: "coverage", CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}}, + Event{Type: "coverage", CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}}, }, { "BenchmarkOne-8 2000000 604 ns/op", - gtr.Event{Type: "benchmark", Name: "BenchmarkOne", Iterations: 2_000_000, NsPerOp: 604}, + Event{Type: "benchmark", Name: "BenchmarkOne", Iterations: 2_000_000, NsPerOp: 604}, }, { "BenchmarkTwo-16 30000 52568 ns/op 24879 B/op 494 allocs/op", - gtr.Event{Type: "benchmark", Name: "BenchmarkTwo", Iterations: 30_000, NsPerOp: 52_568, BytesPerOp: 24_879, AllocsPerOp: 494}, + Event{Type: "benchmark", Name: "BenchmarkTwo", Iterations: 30_000, NsPerOp: 52_568, BytesPerOp: 24_879, AllocsPerOp: 494}, }, { "BenchmarkThree 2000000000 0.26 ns/op", - gtr.Event{Type: "benchmark", Name: "BenchmarkThree", Iterations: 2_000_000_000, NsPerOp: 0.26}, + Event{Type: "benchmark", Name: "BenchmarkThree", Iterations: 2_000_000_000, NsPerOp: 0.26}, }, { "BenchmarkFour-8 10000 104427 ns/op 95.76 MB/s 40629 B/op 5 allocs/op", - gtr.Event{Type: "benchmark", Name: "BenchmarkFour", Iterations: 10_000, NsPerOp: 104_427, MBPerSec: 95.76, BytesPerOp: 40_629, AllocsPerOp: 5}, + Event{Type: "benchmark", Name: "BenchmarkFour", Iterations: 10_000, NsPerOp: 104_427, MBPerSec: 95.76, BytesPerOp: 40_629, AllocsPerOp: 5}, }, { "# package/name/failing1", - gtr.Event{Type: "build_output", Name: "package/name/failing1"}, + Event{Type: "build_output", Name: "package/name/failing1"}, }, { "# package/name/failing2 [package/name/failing2.test]", - gtr.Event{Type: "build_output", Name: "package/name/failing2"}, + Event{Type: "build_output", Name: "package/name/failing2"}, }, { "single line stdout", - gtr.Event{Type: "output", Data: "single line stdout"}, + Event{Type: "output", Data: "single line stdout"}, }, { "# some more output", - gtr.Event{Type: "output", Data: "# some more output"}, + Event{Type: "output", Data: "# some more output"}, }, { "\tfile_test.go:11: Error message", - gtr.Event{Type: "output", Data: "\tfile_test.go:11: Error message"}, + Event{Type: "output", Data: "\tfile_test.go:11: Error message"}, }, { "\tfile_test.go:12: Longer", - gtr.Event{Type: "output", Data: "\tfile_test.go:12: Longer"}, + Event{Type: "output", Data: "\tfile_test.go:12: Longer"}, }, { "\t\terror", - gtr.Event{Type: "output", Data: "\t\terror"}, + Event{Type: "output", Data: "\t\terror"}, }, { "\t\tmessage.", - gtr.Event{Type: "output", Data: "\t\tmessage."}, + Event{Type: "output", Data: "\t\tmessage."}, }, } func TestParseLine(t *testing.T) { for i, test := range parseLineTests { - var want []gtr.Event + var want []Event switch e := test.events.(type) { - case gtr.Event: - want = []gtr.Event{e} - case []gtr.Event: + case Event: + want = []Event{e} + case []Event: want = e default: panic("invalid events type") @@ -194,3 +193,96 @@ func TestParseLine(t *testing.T) { }) } } + +func TestReport(t *testing.T) { + events := []Event{ + {Type: "run_test", Name: "TestOne"}, + {Type: "output", Data: "\tHello"}, + {Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 1 * time.Millisecond}, + {Type: "status", Result: "PASS"}, + {Type: "run_test", Name: "TestSkip"}, + {Type: "end_test", Name: "TestSkip", Result: "SKIP", Duration: 1 * time.Millisecond}, + {Type: "summary", Result: "ok", Name: "package/name", Duration: 1 * time.Millisecond}, + {Type: "run_test", Name: "TestOne"}, + {Type: "output", Data: "\tfile_test.go:10: error"}, + {Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 1 * time.Millisecond}, + {Type: "status", Result: "FAIL"}, + {Type: "summary", Result: "FAIL", Name: "package/name2", Duration: 1 * time.Millisecond}, + {Type: "output", Data: "goarch: amd64"}, + {Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 100}, + {Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 300}, + {Type: "status", Result: "PASS"}, + {Type: "summary", Result: "ok", Name: "package/name3", Duration: 1234 * time.Millisecond}, + {Type: "build_output", Name: "package/failing1"}, + {Type: "output", Data: "error message"}, + {Type: "summary", Result: "FAIL", Name: "package/failing1", Data: "[build failed]"}, + } + expected := gtr.Report{ + Packages: []gtr.Package{ + { + Name: "package/name", + Duration: 1 * time.Millisecond, + Tests: []gtr.Test{ + { + Name: "TestOne", + Duration: 1 * time.Millisecond, + Result: gtr.Pass, + Output: []string{ + "\tHello", // TODO: strip tabs? + }, + }, + { + Name: "TestSkip", + Duration: 1 * time.Millisecond, + Result: gtr.Skip, + }, + }, + }, + { + Name: "package/name2", + Duration: 1 * time.Millisecond, + Tests: []gtr.Test{ + { + Name: "TestOne", + Duration: 1 * time.Millisecond, + Result: gtr.Fail, + Output: []string{ + "\tfile_test.go:10: error", + }, + }, + }, + }, + { + Name: "package/name3", + Duration: 1234 * time.Millisecond, + Benchmarks: []gtr.Benchmark{ + { + Name: "BenchmarkOne", + Result: gtr.Pass, + NsPerOp: 100, + }, + { + Name: "BenchmarkOne", + Result: gtr.Pass, + NsPerOp: 300, + }, + }, + Output: []string{"goarch: amd64"}, + }, + { + Name: "package/failing1", + BuildError: gtr.Error{ + Name: "package/failing1", + Cause: "[build failed]", + Output: []string{"error message"}, + }, + }, + }, + } + + parser := &Parser{} + actual := parser.report(events) + if diff := cmp.Diff(actual, expected); diff != "" { + t.Errorf("FromEvents report incorrect, diff (-got, +want):\n%v", diff) + } +}