From 832cc9703795e2f3bcff43bc790ec633ba7f6d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Stemmer?= Date: Mon, 14 Mar 2022 23:12:20 +0000 Subject: [PATCH] parser/gotest: refactor parser so Parse is no longer a top level func Making Parse a method on a Parser struct makes it possible to later define an common parser interface. --- go-junit-report.go | 3 +- go-junit-report_test.go | 3 +- pkg/parser/gotest/gotest.go | 59 ++++++++++++++++++++++---------- pkg/parser/gotest/gotest_test.go | 15 ++++---- 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/go-junit-report.go b/go-junit-report.go index ea6cfae..bf7405b 100644 --- a/go-junit-report.go +++ b/go-junit-report.go @@ -76,7 +76,8 @@ func main() { in = io.TeeReader(in, os.Stdout) } - events, err := gotest.Parse(in) + parser := gotest.New() + events, err := parser.Parse(in) if err != nil { exitf("error reading input: %s\n", err) } diff --git a/go-junit-report_test.go b/go-junit-report_test.go index 960cc14..848643f 100644 --- a/go-junit-report_test.go +++ b/go-junit-report_test.go @@ -192,7 +192,8 @@ func testReport(input, reportFile, packageName string, t *testing.T) { } defer file.Close() - events, err := gotest.Parse(file) + parser := gotest.New() + events, err := parser.Parse(file) if err != nil { t.Fatal(err) } diff --git a/pkg/parser/gotest/gotest.go b/pkg/parser/gotest/gotest.go index 95b323f..3f2e3dc 100644 --- a/pkg/parser/gotest/gotest.go +++ b/pkg/parser/gotest/gotest.go @@ -35,10 +35,35 @@ var ( `(?:\s+coverage:\s+(\d+\.\d+)%\sof\sstatements(?:\sin\s(.+))?)?$`) ) -// Parse parses Go test output from the given io.Reader r. -func Parse(r io.Reader) ([]gtr.Event, error) { - p := &parser{} +// Option defines options that can be passed to gotest.New. +type Option func(*Parser) +// PackageName sets the default package name to use when it cannot be +// determined from the test output. +func PackageName(name string) Option { + return func(p *Parser) { + p.packageName = name + } +} + +// New returns a new Go test output parser. +func New(options ...Option) *Parser { + p := &Parser{} + for _, option := range options { + option(p) + } + return p +} + +// Parser is a Go test output Parser. +type Parser struct { + packageName string + + events []gtr.Event +} + +// Parse parses Go test output from the given io.Reader r. +func (p *Parser) Parse(r io.Reader) ([]gtr.Event, error) { s := bufio.NewScanner(r) for s.Scan() { p.parseLine(s.Text()) @@ -46,11 +71,7 @@ func Parse(r io.Reader) ([]gtr.Event, error) { return p.events, s.Err() } -type parser struct { - events []gtr.Event -} - -func (p *parser) parseLine(line string) { +func (p *Parser) parseLine(line string) { if strings.HasPrefix(line, "=== RUN ") { p.runTest(strings.TrimSpace(line[8:])) } else if strings.HasPrefix(line, "=== PAUSE ") { @@ -80,23 +101,23 @@ func (p *parser) parseLine(line string) { } } -func (p *parser) add(event gtr.Event) { +func (p *Parser) add(event gtr.Event) { p.events = append(p.events, event) } -func (p *parser) runTest(name string) { +func (p *Parser) runTest(name string) { p.add(gtr.Event{Type: "run_test", Name: name}) } -func (p *parser) pauseTest(name string) { +func (p *Parser) pauseTest(name string) { p.add(gtr.Event{Type: "pause_test", Name: name}) } -func (p *parser) contTest(name string) { +func (p *Parser) contTest(name string) { p.add(gtr.Event{Type: "cont_test", Name: name}) } -func (p *parser) endTest(line, indent, result, name, duration string) { +func (p *Parser) endTest(line, indent, result, name, duration string) { if idx := strings.Index(line, fmt.Sprintf("%s--- %s:", indent, result)); idx > 0 { p.output(line[:idx]) } @@ -110,11 +131,11 @@ func (p *parser) endTest(line, indent, result, name, duration string) { }) } -func (p *parser) status(result string) { +func (p *Parser) status(result string) { p.add(gtr.Event{Type: "status", Result: result}) } -func (p *parser) summary(result, name, duration, cached, status, covpct, packages string) { +func (p *Parser) summary(result, name, duration, cached, status, covpct, packages string) { p.add(gtr.Event{ Type: "summary", Result: result, @@ -126,7 +147,7 @@ func (p *parser) summary(result, name, duration, cached, status, covpct, package }) } -func (p *parser) coverage(percent, packages string) { +func (p *Parser) coverage(percent, packages string) { p.add(gtr.Event{ Type: "coverage", CovPct: parseFloat(percent), @@ -134,7 +155,7 @@ func (p *parser) coverage(percent, packages string) { }) } -func (p *parser) benchmark(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp string) { +func (p *Parser) benchmark(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp string) { p.add(gtr.Event{ Type: "benchmark", Name: name, @@ -146,14 +167,14 @@ func (p *parser) benchmark(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allo }) } -func (p *parser) buildOutput(packageName string) { +func (p *Parser) buildOutput(packageName string) { p.add(gtr.Event{ Type: "build_output", Name: packageName, }) } -func (p *parser) output(line string) { +func (p *Parser) output(line string) { p.add(gtr.Event{Type: "output", Data: line}) } diff --git a/pkg/parser/gotest/gotest_test.go b/pkg/parser/gotest/gotest_test.go index 0ccf432..e7297d7 100644 --- a/pkg/parser/gotest/gotest_test.go +++ b/pkg/parser/gotest/gotest_test.go @@ -185,15 +185,12 @@ func TestParseLine(t *testing.T) { name := fmt.Sprintf("%d %s", i+1, strings.Join(types, ",")) t.Run(name, func(t *testing.T) { - testParseLine(t, &parser{}, test.input, want) + parser := New() + parser.parseLine(test.input) + got := parser.events + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("parseLine(%q) returned unexpected events, diff (-got, +want):\n%v", test.input, diff) + } }) } } - -func testParseLine(t *testing.T, parser *parser, input string, want []gtr.Event) { - parser.parseLine(input) - got := parser.events - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf("parseLine(%q) returned unexpected events, diff (-got, +want):\n%v", input, diff) - } -}