From 6087bd544c10d54abca0359049fe631d8b85e785 Mon Sep 17 00:00:00 2001 From: Jeff Grafton Date: Mon, 29 Jun 2015 17:36:33 -0700 Subject: [PATCH 1/2] Extract and report coverage information. When `go test` is run on multiple packages and with coverage collection enabled, it appends coverage information to the final result line for each package. With this change, properly handle this additional information and add it into the JUnit XML report as a property of the test suite. --- go-junit-report_test.go | 70 ++++++++++++++++++++++++++++++++++ junit-formatter.go | 3 ++ parser.go | 38 ++++++++++++------ tests/09-coverage.txt | 7 ++++ tests/09-report.xml | 11 ++++++ tests/10-multipkg-coverage.txt | 12 ++++++ tests/10-report.xml | 18 +++++++++ 7 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 tests/09-coverage.txt create mode 100644 tests/09-report.xml create mode 100644 tests/10-multipkg-coverage.txt create mode 100644 tests/10-report.xml diff --git a/go-junit-report_test.go b/go-junit-report_test.go index daa3cd8..6b62447 100644 --- a/go-junit-report_test.go +++ b/go-junit-report_test.go @@ -260,6 +260,73 @@ var testCases = []TestCase{ }, }, }, + { + name: "09-coverage.txt", + reportName: "09-report.xml", + report: &Report{ + Packages: []Package{ + { + Name: "package/name", + Time: 160, + Tests: []*Test{ + { + Name: "TestZ", + Time: 60, + Result: PASS, + Output: []string{}, + }, + { + Name: "TestA", + Time: 100, + Result: PASS, + Output: []string{}, + }, + }, + CoveragePct: "13.37", + }, + }, + }, + }, + { + name: "10-multipkg-coverage.txt", + reportName: "10-report.xml", + report: &Report{ + Packages: []Package{ + { + Name: "package1/foo", + Time: 400, + Tests: []*Test{ + { + Name: "TestA", + Time: 100, + Result: PASS, + Output: []string{}, + }, + { + Name: "TestB", + Time: 300, + Result: PASS, + Output: []string{}, + }, + }, + CoveragePct: "10.0", + }, + { + Name: "package2/bar", + Time: 4200, + Tests: []*Test{ + { + Name: "TestC", + Time: 4200, + Result: PASS, + Output: []string{}, + }, + }, + CoveragePct: "99.8", + }, + }, + }, + }, } func TestParser(t *testing.T) { @@ -321,6 +388,9 @@ func TestParser(t *testing.T) { t.Errorf("Test.Output ==\n%s\n, want\n%s", testOutput, expTestOutput) } } + if pkg.CoveragePct != expPkg.CoveragePct { + t.Errorf("Package.CoveragePct == %s, want %s", pkg.CoveragePct, expPkg.CoveragePct) + } } } } diff --git a/junit-formatter.go b/junit-formatter.go index e247612..932f5aa 100644 --- a/junit-formatter.go +++ b/junit-formatter.go @@ -78,6 +78,9 @@ func JUnitReportXML(report *Report, noXMLHeader bool, w io.Writer) error { // properties ts.Properties = append(ts.Properties, JUnitProperty{"go.version", runtime.Version()}) + if pkg.CoveragePct != "" { + ts.Properties = append(ts.Properties, JUnitProperty{"coverage.statements.pct", pkg.CoveragePct}) + } // individual test cases for _, test := range pkg.Tests { diff --git a/parser.go b/parser.go index 978abe9..535be35 100644 --- a/parser.go +++ b/parser.go @@ -25,9 +25,10 @@ type Report struct { // Package contains the test results of a single package. type Package struct { - Name string - Time int - Tests []*Test + Name string + Time int + Tests []*Test + CoveragePct string } // Test contains the results of a single test. @@ -39,8 +40,9 @@ type Test struct { } var ( - regexStatus = regexp.MustCompile(`^--- (PASS|FAIL|SKIP): (.+) \((\d+\.\d+)(?: seconds|s)\)$`) - regexResult = regexp.MustCompile(`^(ok|FAIL)\s+(.+)\s(\d+\.\d+)s$`) + regexStatus = regexp.MustCompile(`^--- (PASS|FAIL|SKIP): (.+) \((\d+\.\d+)(?: seconds|s)\)$`) + regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+\.\d+)%\s+of\s+statements$`) + regexResult = regexp.MustCompile(`^(ok|FAIL)\s+(.+)\s(\d+\.\d+)s(?:\s+coverage:\s+(\d+\.\d+)%\s+of\s+statements)?$`) ) // Parse parses go test output from reader r and returns a report with the @@ -60,6 +62,9 @@ func Parse(r io.Reader, pkgName string) (*Report, error) { // current test var cur string + // coverage percentage report for current package + var coveragePct string + // parse lines for { l, _, err := reader.ReadLine() @@ -79,15 +84,21 @@ func Parse(r io.Reader, pkgName string) (*Report, error) { Result: FAIL, Output: make([]string, 0), }) - } else if matches := regexResult.FindStringSubmatch(line); len(matches) == 4 { + } else if matches := regexResult.FindStringSubmatch(line); len(matches) == 5 { + if matches[4] != "" { + coveragePct = matches[4] + } + // all tests in this package are finished report.Packages = append(report.Packages, Package{ - Name: matches[2], - Time: parseTime(matches[3]), - Tests: tests, + Name: matches[2], + Time: parseTime(matches[3]), + Tests: tests, + CoveragePct: coveragePct, }) tests = make([]*Test, 0) + coveragePct = "" cur = "" testsTime = 0 } else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 4 { @@ -110,6 +121,8 @@ func Parse(r io.Reader, pkgName string) (*Report, error) { testTime := parseTime(matches[3]) * 10 test.Time = testTime testsTime += testTime + } else if matches := regexCoverage.FindStringSubmatch(line); len(matches) == 2 { + coveragePct = matches[1] } else if strings.HasPrefix(line, "\t") { // test output test := findTest(tests, cur) @@ -123,9 +136,10 @@ func Parse(r io.Reader, pkgName string) (*Report, error) { if len(tests) > 0 { // no result line found report.Packages = append(report.Packages, Package{ - Name: pkgName, - Time: testsTime, - Tests: tests, + Name: pkgName, + Time: testsTime, + Tests: tests, + CoveragePct: coveragePct, }) } diff --git a/tests/09-coverage.txt b/tests/09-coverage.txt new file mode 100644 index 0000000..ee362d8 --- /dev/null +++ b/tests/09-coverage.txt @@ -0,0 +1,7 @@ +=== RUN TestZ +--- PASS: TestZ (0.06 seconds) +=== RUN TestA +--- PASS: TestA (0.10 seconds) +PASS +coverage: 13.37% of statements +ok package/name 0.160s diff --git a/tests/09-report.xml b/tests/09-report.xml new file mode 100644 index 0000000..9bbc3c2 --- /dev/null +++ b/tests/09-report.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/10-multipkg-coverage.txt b/tests/10-multipkg-coverage.txt new file mode 100644 index 0000000..3c4f213 --- /dev/null +++ b/tests/10-multipkg-coverage.txt @@ -0,0 +1,12 @@ +=== RUN TestA +--- PASS: TestA (0.10 seconds) +=== RUN TestB +--- PASS: TestB (0.30 seconds) +PASS +coverage: 10% of statements +ok package1/foo 0.400s coverage: 10.0% of statements +=== RUN TestC +--- PASS: TestC (4.20 seconds) +PASS +coverage: 99.8% of statements +ok package2/bar 4.200s coverage: 99.8% of statements diff --git a/tests/10-report.xml b/tests/10-report.xml new file mode 100644 index 0000000..ceb97fb --- /dev/null +++ b/tests/10-report.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From ba0125f1ef43e62caf429f42d451ef699a5b5f40 Mon Sep 17 00:00:00 2001 From: Jeff Grafton Date: Mon, 29 Jun 2015 18:16:46 -0700 Subject: [PATCH 2/2] Fix multipkg test case to work for all versions of go. --- tests/10-report.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/10-report.xml b/tests/10-report.xml index ceb97fb..a78497c 100644 --- a/tests/10-report.xml +++ b/tests/10-report.xml @@ -2,7 +2,7 @@ - + @@ -10,7 +10,7 @@ - +