mirror of
https://github.com/jstemmer/go-junit-report.git
synced 2025-07-05 05:22:53 -05:00
Merge branch 'subpackage'
This commit is contained in:
179
parser/parser.go
Normal file
179
parser/parser.go
Normal file
@ -0,0 +1,179 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Result represents a test result.
|
||||
type Result int
|
||||
|
||||
// Test result constants
|
||||
const (
|
||||
PASS Result = iota
|
||||
FAIL
|
||||
SKIP
|
||||
)
|
||||
|
||||
// Report is a collection of package tests.
|
||||
type Report struct {
|
||||
Packages []Package
|
||||
}
|
||||
|
||||
// Package contains the test results of a single package.
|
||||
type Package struct {
|
||||
Name string
|
||||
Time int
|
||||
Tests []*Test
|
||||
CoveragePct string
|
||||
}
|
||||
|
||||
// Test contains the results of a single test.
|
||||
type Test struct {
|
||||
Name string
|
||||
Time int
|
||||
Result Result
|
||||
Output []string
|
||||
}
|
||||
|
||||
var (
|
||||
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
|
||||
// results. An optional pkgName can be given, which is used in case a package
|
||||
// result line is missing.
|
||||
func Parse(r io.Reader, pkgName string) (*Report, error) {
|
||||
reader := bufio.NewReader(r)
|
||||
|
||||
report := &Report{make([]Package, 0)}
|
||||
|
||||
// keep track of tests we find
|
||||
var tests []*Test
|
||||
|
||||
// sum of tests' time, use this if current test has no result line (when it is compiled test)
|
||||
testsTime := 0
|
||||
|
||||
// current test
|
||||
var cur string
|
||||
|
||||
// coverage percentage report for current package
|
||||
var coveragePct string
|
||||
|
||||
// parse lines
|
||||
for {
|
||||
l, _, err := reader.ReadLine()
|
||||
if err != nil && err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
line := string(l)
|
||||
|
||||
if strings.HasPrefix(line, "=== RUN ") {
|
||||
// new test
|
||||
cur = line[8:]
|
||||
tests = append(tests, &Test{
|
||||
Name: line[8:],
|
||||
Result: FAIL,
|
||||
Output: make([]string, 0),
|
||||
})
|
||||
} 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,
|
||||
CoveragePct: coveragePct,
|
||||
})
|
||||
|
||||
tests = make([]*Test, 0)
|
||||
coveragePct = ""
|
||||
cur = ""
|
||||
testsTime = 0
|
||||
} else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 4 {
|
||||
cur = matches[2]
|
||||
test := findTest(tests, cur)
|
||||
if test == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// test status
|
||||
if matches[1] == "PASS" {
|
||||
test.Result = PASS
|
||||
} else if matches[1] == "SKIP" {
|
||||
test.Result = SKIP
|
||||
} else {
|
||||
test.Result = FAIL
|
||||
}
|
||||
|
||||
test.Name = matches[2]
|
||||
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)
|
||||
if test == nil {
|
||||
continue
|
||||
}
|
||||
test.Output = append(test.Output, line[1:])
|
||||
}
|
||||
}
|
||||
|
||||
if len(tests) > 0 {
|
||||
// no result line found
|
||||
report.Packages = append(report.Packages, Package{
|
||||
Name: pkgName,
|
||||
Time: testsTime,
|
||||
Tests: tests,
|
||||
CoveragePct: coveragePct,
|
||||
})
|
||||
}
|
||||
|
||||
return report, nil
|
||||
}
|
||||
|
||||
func parseTime(time string) int {
|
||||
t, err := strconv.Atoi(strings.Replace(time, ".", "", -1))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func findTest(tests []*Test, name string) *Test {
|
||||
for i := 0; i < len(tests); i++ {
|
||||
if tests[i].Name == name {
|
||||
return tests[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Failures counts the number of failed tests in this report
|
||||
func (r *Report) Failures() int {
|
||||
count := 0
|
||||
|
||||
for _, p := range r.Packages {
|
||||
for _, t := range p.Tests {
|
||||
if t.Result == FAIL {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
Reference in New Issue
Block a user