mirror of
https://github.com/jstemmer/go-junit-report.git
synced 2025-04-05 05:00:15 -05:00
Merge pull request #83 from liggitt/test-output
Include test output and stdout in test failures
This commit is contained in:
commit
55f6716122
@ -1212,6 +1212,219 @@ var testCases = []TestCase{
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// generated by running go test on https://gist.github.com/liggitt/09a021ccec988b19917e0c2d60a18ee9
|
||||
name: "30-stdout.txt",
|
||||
reportName: "30-report.xml",
|
||||
report: &parser.Report{
|
||||
Packages: []parser.Package{
|
||||
{
|
||||
Name: "package/name1",
|
||||
Duration: 4567 * time.Millisecond,
|
||||
Time: 4567,
|
||||
Tests: []*parser.Test{
|
||||
{
|
||||
Name: "TestFailWithStdoutAndTestOutput",
|
||||
Duration: 100 * time.Millisecond,
|
||||
Time: 100,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{
|
||||
`multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`single-line stdout`,
|
||||
`example_test.go:13: single-line error`,
|
||||
`example_test.go:14: multi`,
|
||||
` line`,
|
||||
` error`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestFailWithStdoutAndNoTestOutput",
|
||||
Duration: 150 * time.Millisecond,
|
||||
Time: 150,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{
|
||||
`multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`single-line stdout`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestFailWithTestOutput",
|
||||
Duration: 200 * time.Millisecond,
|
||||
Time: 200,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{
|
||||
`example_test.go:26: single-line error`,
|
||||
`example_test.go:27: multi`,
|
||||
` line`,
|
||||
` error`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestFailWithNoTestOutput",
|
||||
Duration: 250 * time.Millisecond,
|
||||
Time: 250,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "TestPassWithStdoutAndTestOutput",
|
||||
Duration: 300 * time.Millisecond,
|
||||
Time: 300,
|
||||
Result: parser.PASS,
|
||||
Output: []string{
|
||||
`multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`single-line stdout`,
|
||||
`example_test.go:39: single-line info`,
|
||||
`example_test.go:40: multi`,
|
||||
` line`,
|
||||
` info`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestPassWithStdoutAndNoTestOutput",
|
||||
Duration: 350 * time.Millisecond,
|
||||
Time: 350,
|
||||
Result: parser.PASS,
|
||||
Output: []string{
|
||||
`multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`single-line stdout`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestPassWithTestOutput",
|
||||
Duration: 400 * time.Millisecond,
|
||||
Time: 400,
|
||||
Result: parser.PASS,
|
||||
Output: []string{
|
||||
`example_test.go:51: single-line info`,
|
||||
`example_test.go:52: multi`,
|
||||
` line`,
|
||||
` info`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestPassWithNoTestOutput",
|
||||
Duration: 500 * time.Millisecond,
|
||||
Time: 500,
|
||||
Result: parser.PASS,
|
||||
Output: []string{},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "TestSubtests",
|
||||
Duration: 2270 * time.Millisecond,
|
||||
Time: 2270,
|
||||
Result: parser.FAIL,
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestFailWithStdoutAndTestOutput",
|
||||
Duration: 100 * time.Millisecond,
|
||||
Time: 100,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{
|
||||
`1 multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`1 single-line stdout`,
|
||||
`example_test.go:65: 1 single-line error`,
|
||||
`example_test.go:66: 1 multi`,
|
||||
` line`,
|
||||
` error`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestFailWithStdoutAndNoTestOutput",
|
||||
Duration: 150 * time.Millisecond,
|
||||
Time: 150,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{
|
||||
`2 multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`2 single-line stdout`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestFailWithTestOutput",
|
||||
Duration: 200 * time.Millisecond,
|
||||
Time: 200,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{
|
||||
`example_test.go:78: 3 single-line error`,
|
||||
`example_test.go:79: 3 multi`,
|
||||
` line`,
|
||||
` error`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestFailWithNoTestOutput",
|
||||
Duration: 250 * time.Millisecond,
|
||||
Time: 250,
|
||||
Result: parser.FAIL,
|
||||
Output: []string{},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "TestSubtests/TestPassWithStdoutAndTestOutput",
|
||||
Duration: 300 * time.Millisecond,
|
||||
Time: 300,
|
||||
Result: parser.PASS,
|
||||
Output: []string{
|
||||
`4 multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`4 single-line stdout`,
|
||||
`example_test.go:91: 4 single-line info`,
|
||||
`example_test.go:92: 4 multi`,
|
||||
` line`,
|
||||
` info`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestPassWithStdoutAndNoTestOutput",
|
||||
Duration: 350 * time.Millisecond,
|
||||
Time: 350,
|
||||
Result: parser.PASS,
|
||||
Output: []string{
|
||||
`5 multi`,
|
||||
`line`,
|
||||
`stdout`,
|
||||
`5 single-line stdout`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestPassWithTestOutput",
|
||||
Duration: 400 * time.Millisecond,
|
||||
Time: 400,
|
||||
Result: parser.PASS,
|
||||
Output: []string{
|
||||
`example_test.go:103: 6 single-line info`,
|
||||
`example_test.go:104: 6 multi`,
|
||||
` line`,
|
||||
` info`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSubtests/TestPassWithNoTestOutput",
|
||||
Duration: 500 * time.Millisecond,
|
||||
Time: 500,
|
||||
Result: parser.PASS,
|
||||
Output: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
|
@ -43,6 +43,8 @@ type Test struct {
|
||||
Result Result
|
||||
Output []string
|
||||
|
||||
SubtestIndent string
|
||||
|
||||
// Time is deprecated, use Duration instead.
|
||||
Time int // in milliseconds
|
||||
}
|
||||
@ -59,6 +61,7 @@ type Benchmark struct {
|
||||
|
||||
var (
|
||||
regexStatus = regexp.MustCompile(`--- (PASS|FAIL|SKIP): (.+) \((\d+\.\d+)(?: seconds|s)\)`)
|
||||
regexIndent = regexp.MustCompile(`^([ \t]+)---`)
|
||||
regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+\.\d+)%\s+of\s+statements(?:\sin\s.+)?$`)
|
||||
regexResult = regexp.MustCompile(`^(ok|FAIL)\s+([^ ]+)\s+(?:(\d+\.\d+)s|\(cached\)|(\[\w+ failed]))(?:\s+coverage:\s+(\d+\.\d+)%\sof\sstatements(?:\sin\s.+)?)?$`)
|
||||
// regexBenchmark captures 3-5 groups: benchmark name, number of times ran, ns/op (with or without decimal), B/op (optional), and allocs/op (optional).
|
||||
@ -195,6 +198,11 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
|
||||
} else {
|
||||
test.Result = FAIL
|
||||
}
|
||||
|
||||
if matches := regexIndent.FindStringSubmatch(line); len(matches) == 2 {
|
||||
test.SubtestIndent = matches[1]
|
||||
}
|
||||
|
||||
test.Output = buffers[cur]
|
||||
|
||||
test.Name = matches[2]
|
||||
@ -225,6 +233,14 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
|
||||
} else if !seenSummary {
|
||||
// buffer anything else that we didn't recognize
|
||||
buffers[cur] = append(buffers[cur], line)
|
||||
|
||||
// if we have a current test, also append to its output
|
||||
test := findTest(tests, cur)
|
||||
if test != nil {
|
||||
if strings.HasPrefix(line, test.SubtestIndent+" ") {
|
||||
test.Output = append(test.Output, strings.TrimPrefix(line, test.SubtestIndent+" "))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
43
testdata/30-report.xml
vendored
Normal file
43
testdata/30-report.xml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite tests="17" failures="9" time="4.567" name="package/name1">
|
||||
<properties>
|
||||
<property name="go.version" value="1.0"></property>
|
||||
</properties>
|
||||
<testcase classname="name1" name="TestFailWithStdoutAndTestOutput" time="0.100">
|
||||
<failure message="Failed" type="">multi
line
stdout
single-line stdout
example_test.go:13: single-line error
example_test.go:14: multi
 line
 error</failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestFailWithStdoutAndNoTestOutput" time="0.150">
|
||||
<failure message="Failed" type="">multi
line
stdout
single-line stdout</failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestFailWithTestOutput" time="0.200">
|
||||
<failure message="Failed" type="">example_test.go:26: single-line error
example_test.go:27: multi
 line
 error</failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestFailWithNoTestOutput" time="0.250">
|
||||
<failure message="Failed" type=""></failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestPassWithStdoutAndTestOutput" time="0.300"></testcase>
|
||||
<testcase classname="name1" name="TestPassWithStdoutAndNoTestOutput" time="0.350"></testcase>
|
||||
<testcase classname="name1" name="TestPassWithTestOutput" time="0.400"></testcase>
|
||||
<testcase classname="name1" name="TestPassWithNoTestOutput" time="0.500"></testcase>
|
||||
<testcase classname="name1" name="TestSubtests" time="2.270">
|
||||
<failure message="Failed" type=""></failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestFailWithStdoutAndTestOutput" time="0.100">
|
||||
<failure message="Failed" type="">1 multi
line
stdout
1 single-line stdout
example_test.go:65: 1 single-line error
example_test.go:66: 1 multi
 line
 error</failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestFailWithStdoutAndNoTestOutput" time="0.150">
|
||||
<failure message="Failed" type="">2 multi
line
stdout
2 single-line stdout</failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestFailWithTestOutput" time="0.200">
|
||||
<failure message="Failed" type="">example_test.go:78: 3 single-line error
example_test.go:79: 3 multi
 line
 error</failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestFailWithNoTestOutput" time="0.250">
|
||||
<failure message="Failed" type=""></failure>
|
||||
</testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestPassWithStdoutAndTestOutput" time="0.300"></testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestPassWithStdoutAndNoTestOutput" time="0.350"></testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestPassWithTestOutput" time="0.400"></testcase>
|
||||
<testcase classname="name1" name="TestSubtests/TestPassWithNoTestOutput" time="0.500"></testcase>
|
||||
</testsuite>
|
||||
</testsuites>
|
100
testdata/30-stdout.txt
vendored
Normal file
100
testdata/30-stdout.txt
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
=== RUN TestFailWithStdoutAndTestOutput
|
||||
multi
|
||||
line
|
||||
stdout
|
||||
single-line stdout
|
||||
--- FAIL: TestFailWithStdoutAndTestOutput (0.10s)
|
||||
example_test.go:13: single-line error
|
||||
example_test.go:14: multi
|
||||
line
|
||||
error
|
||||
=== RUN TestFailWithStdoutAndNoTestOutput
|
||||
multi
|
||||
line
|
||||
stdout
|
||||
single-line stdout
|
||||
--- FAIL: TestFailWithStdoutAndNoTestOutput (0.15s)
|
||||
=== RUN TestFailWithTestOutput
|
||||
--- FAIL: TestFailWithTestOutput (0.20s)
|
||||
example_test.go:26: single-line error
|
||||
example_test.go:27: multi
|
||||
line
|
||||
error
|
||||
=== RUN TestFailWithNoTestOutput
|
||||
--- FAIL: TestFailWithNoTestOutput (0.25s)
|
||||
=== RUN TestPassWithStdoutAndTestOutput
|
||||
multi
|
||||
line
|
||||
stdout
|
||||
single-line stdout
|
||||
--- PASS: TestPassWithStdoutAndTestOutput (0.30s)
|
||||
example_test.go:39: single-line info
|
||||
example_test.go:40: multi
|
||||
line
|
||||
info
|
||||
=== RUN TestPassWithStdoutAndNoTestOutput
|
||||
multi
|
||||
line
|
||||
stdout
|
||||
single-line stdout
|
||||
--- PASS: TestPassWithStdoutAndNoTestOutput (0.35s)
|
||||
=== RUN TestPassWithTestOutput
|
||||
--- PASS: TestPassWithTestOutput (0.40s)
|
||||
example_test.go:51: single-line info
|
||||
example_test.go:52: multi
|
||||
line
|
||||
info
|
||||
=== RUN TestPassWithNoTestOutput
|
||||
--- PASS: TestPassWithNoTestOutput (0.50s)
|
||||
=== RUN TestSubtests
|
||||
=== RUN TestSubtests/TestFailWithStdoutAndTestOutput
|
||||
1 multi
|
||||
line
|
||||
stdout
|
||||
1 single-line stdout
|
||||
=== RUN TestSubtests/TestFailWithStdoutAndNoTestOutput
|
||||
2 multi
|
||||
line
|
||||
stdout
|
||||
2 single-line stdout
|
||||
=== RUN TestSubtests/TestFailWithTestOutput
|
||||
=== RUN TestSubtests/TestFailWithNoTestOutput
|
||||
=== RUN TestSubtests/TestPassWithStdoutAndTestOutput
|
||||
4 multi
|
||||
line
|
||||
stdout
|
||||
4 single-line stdout
|
||||
=== RUN TestSubtests/TestPassWithStdoutAndNoTestOutput
|
||||
5 multi
|
||||
line
|
||||
stdout
|
||||
5 single-line stdout
|
||||
=== RUN TestSubtests/TestPassWithTestOutput
|
||||
=== RUN TestSubtests/TestPassWithNoTestOutput
|
||||
--- FAIL: TestSubtests (2.27s)
|
||||
--- FAIL: TestSubtests/TestFailWithStdoutAndTestOutput (0.10s)
|
||||
example_test.go:65: 1 single-line error
|
||||
example_test.go:66: 1 multi
|
||||
line
|
||||
error
|
||||
--- FAIL: TestSubtests/TestFailWithStdoutAndNoTestOutput (0.15s)
|
||||
--- FAIL: TestSubtests/TestFailWithTestOutput (0.20s)
|
||||
example_test.go:78: 3 single-line error
|
||||
example_test.go:79: 3 multi
|
||||
line
|
||||
error
|
||||
--- FAIL: TestSubtests/TestFailWithNoTestOutput (0.25s)
|
||||
--- PASS: TestSubtests/TestPassWithStdoutAndTestOutput (0.30s)
|
||||
example_test.go:91: 4 single-line info
|
||||
example_test.go:92: 4 multi
|
||||
line
|
||||
info
|
||||
--- PASS: TestSubtests/TestPassWithStdoutAndNoTestOutput (0.35s)
|
||||
--- PASS: TestSubtests/TestPassWithTestOutput (0.40s)
|
||||
example_test.go:103: 6 single-line info
|
||||
example_test.go:104: 6 multi
|
||||
line
|
||||
info
|
||||
--- PASS: TestSubtests/TestPassWithNoTestOutput (0.50s)
|
||||
FAIL
|
||||
FAIL package/name1 4.567s
|
Loading…
x
Reference in New Issue
Block a user