pax_global_header 0000666 0000000 0000000 00000000064 14514065750 0014521 g ustar 00root root 0000000 0000000 52 comment=14d61e6e75e3f3c74551d757ad936e8e88014464
go-junit-report-2.1.0/ 0000775 0000000 0000000 00000000000 14514065750 0014566 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/.github/ 0000775 0000000 0000000 00000000000 14514065750 0016126 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14514065750 0020163 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/.github/workflows/main.yml 0000664 0000000 0000000 00000000745 14514065750 0021640 0 ustar 00root root 0000000 0000000 name: Go
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.21', '1.20', '1.13' ]
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
go-junit-report-2.1.0/.gitignore 0000664 0000000 0000000 00000000027 14514065750 0016555 0 ustar 00root root 0000000 0000000 go-junit-report
build/
go-junit-report-2.1.0/CONTRIBUTING.md 0000664 0000000 0000000 00000001523 14514065750 0017020 0 ustar 00root root 0000000 0000000 # Contributing
## Bug reports
- Before reporting a bug, have a look at the [issue
list](https://github.com/jstemmer/go-junit-report/issues) to see if an issue
already exists for your problem.
- Include as much information as you can in the bug report, e.g.: the versions
of go-junit-report and the Go compiler, how go-junit-report was called, what
input was given to go-junit-report, what the actual output was, was the
expected output was.
## Pull requests
- Before sending a pull request for new features, open an issue to discuss it.
- Run `go fmt` to format your code.
- Add test coverage and run all tests.
- Prefer small PRs, avoid making unrelated changes in the same PR.
- Limit the first line of the commit message to 72 characters.
- Write commit messages in the imperative mood ("Fix bug", not "Fixed bug" or
"Fixes bug") .
go-junit-report-2.1.0/LICENSE 0000664 0000000 0000000 00000002040 14514065750 0015567 0 ustar 00root root 0000000 0000000 Copyright (c) 2012 Joel Stemmer
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
go-junit-report-2.1.0/Makefile 0000664 0000000 0000000 00000001756 14514065750 0016237 0 ustar 00root root 0000000 0000000 VERSION=$(shell git describe --match="v*")
REVISION=$(shell git rev-parse HEAD)
TIMESTAMP=$(shell date +%FT%T)
test:
go test ./...
build/go-junit-report build/go-junit-report.exe: clean
go build --ldflags "-s -X main.Version=$(VERSION) -X main.Revision=$(REVISION) -X main.BuildTime=$(TIMESTAMP)" -o $@
build/go-junit-report-$(VERSION)-$(GOOS)-$(GOARCH).tar.gz: build/go-junit-report
tar czf $@ -C build go-junit-report
build/go-junit-report-$(VERSION)-windows-amd64.zip: build/go-junit-report.exe
zip -j $@ build/go-junit-report.exe
release: test
$(MAKE) GOOS=linux GOARCH=amd64 build/go-junit-report-$(VERSION)-linux-amd64.tar.gz
$(MAKE) GOOS=windows GOARCH=amd64 build/go-junit-report-$(VERSION)-windows-amd64.zip
$(MAKE) GOOS=darwin GOARCH=amd64 build/go-junit-report-$(VERSION)-darwin-amd64.tar.gz
$(MAKE) GOOS=darwin GOARCH=arm64 build/go-junit-report-$(VERSION)-darwin-arm64.tar.gz
clean:
rm -f build/go-junit-report
rm -f build/go-junit-report.exe
.PHONY: build clean release test
go-junit-report-2.1.0/README.md 0000664 0000000 0000000 00000014603 14514065750 0016051 0 ustar 00root root 0000000 0000000 # go-junit-report
go-junit-report is a tool that converts [`go test`] output to a JUnit compatible
XML report, suitable for use with applications such as [Jenkins].
[](https://github.com/jstemmer/go-junit-report/actions)
[](https://pkg.go.dev/github.com/jstemmer/go-junit-report/v2)
[](https://goreportcard.com/report/github.com/jstemmer/go-junit-report/v2)
## Install from package (recommended)
Pre-built packages for Windows, macOS and Linux are found on the [Releases]
page.
## Install from source
Download and install the latest stable version from source by running:
```bash
go install github.com/jstemmer/go-junit-report/v2@latest
```
## Usage
By default, go-junit-report reads `go test -v` output generated by the standard
library [testing] package from `stdin` and writes a JUnit XML report to
`stdout`.
Go build and runtime errors are also supported, but this requires that `stderr`
is redirected to go-junit-report as well.
Typical use looks like this:
```bash
go test -v 2>&1 ./... | go-junit-report -set-exit-code > report.xml
```
### More examples
JSON produced by `go test -json` is supported by the `gojson` parser. Note that
`stderr` still needs to be redirected to go-junit-report in order for build
errors to be detected. For example:
```bash
go test -json 2>&1 | go-junit-report -parser gojson > report.xml
```
Go benchmark output is also supported. The following example runs benchmarks for
the package in the current directory and uses the `-out` flag to write the
output to a file called `report.xml`.
```bash
go test -v -bench . -count 5 2>&1 | go-junit-report -out report.xml
```
The `-iocopy` flag copies `stdin` directly to `stdout`, which is helpful if you
want to see what was sent to go-junit-report. The following example reads test
input from a file called `tests.txt`, copies the input to `stdout` and writes
the output to a file called `report.xml`.
```bash
go-junit-report -in tests.txt -iocopy -out report.xml
```
### Flags
Run `go-junit-report -help` for a list of all supported flags.
| Flag | Description |
| -------------------- | ----------- |
| `-in file` | read go test log from `file` |
| `-iocopy` | copy input to stdout; can only be used in conjunction with -out |
| `-no-xml-header` | do not print xml header |
| `-out file` | write XML report to `file` |
| `-package-name name` | specify a default package name to use if output does not contain a package name |
| `-parser parser` | specify the parser to use, available parsers are: `gotest` (default), `gojson` |
| `-p key=value` | add property to generated report; properties should be specified as `key=value` |
| `-set-exit-code` | set exit code to 1 if tests failed |
| `-subtest-mode` | set subtest `mode`, modes are: `ignore-parent-results`, `exclude-parents` |
| `-version` | print version and exit |
## Go packages
The test output parser and JUnit XML report generator are also available as Go
packages. This can be helpful if you want to use the `go test` output parser or
create your own custom JUnit reports for example. See the package documentation
on pkg.go.dev for more information:
- [github.com/jstemmer/go-junit-report/v2/parser/gotest]
- [github.com/jstemmer/go-junit-report/v2/junit]
## Changelog
### v2.1.0
- Fix #147: Make timestamps in generated report more accurate.
- Fix #140: Escape illegal XML characters in junit output.
- Fix #145: Handle build errors in test packages with the `_test` suffix.
- Fix #145: Don't ignore build errors that did not belong to a package.
- Fix #134: Json test output was not parsed correctly when using the `-race` flag in `go test`.
- Add support for `=== NAME` lines introduced in Go1.20
- junit: Add File attribute to `testsuite`.
- junit: Allow multiple properties with the same name.
- junit: Add the `Testsuites.WriteXML` convenience method.
### v2.0.0
- Support for parsing `go test -json` output.
- Distinguish between build/runtime errors and test failures.
- JUnit report now includes output for all tests and benchmarks, and global output that doesn't belong to any test.
- Use full Go package name in generated report instead of only last path segment.
- Add support for reading skipped/failed benchmarks.
- Add `-subtest-mode` flag to exclude or ignore results of subtest parent tests.
- Add `-in` and `-out` flags for specifying input and output files respectively.
- Add `-iocopy` flag to copy stdin directly to stdout.
- Add `-prop` flags to set key/value properties in generated report.
- Add `-parser` flag to switch between regular `go test` (default) and `go test -json` parsing.
- Output in JUnit XML is written in `` tags for improved readability.
- Add `hostname`, `timestamp` and `id` attributes to JUnit XML.
- Improve accuracy of benchmark time calculation and update formatting in report.
- No longer strip leading whitespace from test output.
- The `formatter` and `parser` packages have been replaced with `junit` and `parser/gotest` packages respectively.
- Add support for parsing lines longer than 64KiB.
- The JUnit errors/failures attributes are now required fields.
- Drop support for parsing pre-Go1.13 test output.
- Deprecate `-go-version` flag.
## Contributing
See [CONTRIBUTING.md].
[`go test`]: https://pkg.go.dev/cmd/go#hdr-Test_packages
[Jenkins]: https://www.jenkins.io/
[github.com/jstemmer/go-junit-report/v2/parser/gotest]: https://pkg.go.dev/github.com/jstemmer/go-junit-report/v2/parser/gotest
[github.com/jstemmer/go-junit-report/v2/junit]: https://pkg.go.dev/github.com/jstemmer/go-junit-report/v2/junit
[Releases]: https://github.com/jstemmer/go-junit-report/releases
[testing]: https://pkg.go.dev/testing
[CONTRIBUTING.md]: https://github.com/jstemmer/go-junit-report/blob/master/CONTRIBUTING.md
go-junit-report-2.1.0/go.mod 0000664 0000000 0000000 00000000140 14514065750 0015667 0 ustar 00root root 0000000 0000000 module github.com/jstemmer/go-junit-report/v2
go 1.13
require github.com/google/go-cmp v0.5.8
go-junit-report-2.1.0/go.sum 0000664 0000000 0000000 00000000247 14514065750 0015724 0 ustar 00root root 0000000 0000000 github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
go-junit-report-2.1.0/gtr/ 0000775 0000000 0000000 00000000000 14514065750 0015362 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/gtr/gtr.go 0000664 0000000 0000000 00000007213 14514065750 0016510 0 ustar 00root root 0000000 0000000 // Package gtr defines a standard test report format and provides convenience
// methods to create and convert reports.
package gtr
import (
"strings"
"time"
)
// Result is the result of a test.
type Result int
// Test results.
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 and test results of a collection of packages.
type Report struct {
Packages []Package
}
// IsSuccessful returns true if none of the packages in this report have build
// or runtime errors and all tests passed without failures or were skipped.
func (r *Report) IsSuccessful() bool {
for _, pkg := range r.Packages {
if pkg.BuildError.Name != "" || pkg.RunError.Name != "" {
return false
}
for _, t := range pkg.Tests {
if t.Result != Pass && t.Result != Skip {
return false
}
}
}
return true
}
// Package contains build and test results for a single package.
type Package struct {
Name string
Timestamp time.Time
Duration time.Duration
Coverage float64
Output []string
Properties []Property
Tests []Test
BuildError Error
RunError Error
}
// SetProperty stores a key/value property in the current package. If a
// property with the given key already exists, its old value will be
// overwritten with the given value.
func (p *Package) SetProperty(key, value string) {
// TODO(jstemmer): Delete this method in the next major release.
// Delete all the properties whose name is the specified key,
// then add the specified key-value property.
i := 0
for _, prop := range p.Properties {
if key != prop.Name {
p.Properties[i] = prop
i++
}
}
p.Properties = p.Properties[:i]
p.AddProperty(key, value)
}
// AddProperty appends a name/value property in the current package.
func (p *Package) AddProperty(name, value string) {
p.Properties = append(p.Properties, Property{Name: name, Value: value})
}
// Property is a name/value property.
type Property struct {
Name, Value string
}
// Test contains the results of a single test.
type Test struct {
ID int
Name string
Duration time.Duration
Result Result
Level int
Output []string
Data map[string]interface{}
}
// NewTest creates a new Test with the given id and name.
func NewTest(id int, name string) Test {
return Test{ID: id, Name: name, Data: make(map[string]interface{})}
}
// Error contains details of a build or runtime error.
type Error struct {
ID int
Name string
Duration time.Duration
Cause string
Output []string
}
// 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
// output. TrimPrefixSpaces intends to only trim the whitespace added by the Go
// test command, without inadvertently trimming whitespace added by the test
// author.
func TrimPrefixSpaces(line string, indent int) string {
// We only want to trim the whitespace prefix if it was part of the test
// output. Test output is usually prefixed by a series of 4-space indents,
// so we'll check for that to decide whether this output was likely to be
// from a test.
prefixLen := strings.IndexFunc(line, func(r rune) bool { return r != ' ' })
if prefixLen%4 == 0 {
// Use the subtest level to trim a consistently sized prefix from the
// output lines.
for i := 0; i <= indent; i++ {
line = strings.TrimPrefix(line, " ")
}
}
return strings.TrimPrefix(line, "\t")
}
go-junit-report-2.1.0/gtr/gtr_test.go 0000664 0000000 0000000 00000001763 14514065750 0017553 0 ustar 00root root 0000000 0000000 package gtr
import (
"testing"
"github.com/google/go-cmp/cmp"
)
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"},
}
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)
}
}
}
func TestSetProperty(t *testing.T) {
pkg := Package{}
pkg.SetProperty("a", "b")
pkg.SetProperty("c", "d")
pkg.SetProperty("a", "e")
want := []Property{{Name: "c", Value: "d"}, {Name: "a", Value: "e"}}
if diff := cmp.Diff(want, pkg.Properties); diff != "" {
t.Errorf("SetProperty got unexpected diff: %s", diff)
}
}
go-junit-report-2.1.0/internal/ 0000775 0000000 0000000 00000000000 14514065750 0016402 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/internal/gojunitreport/ 0000775 0000000 0000000 00000000000 14514065750 0021315 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/internal/gojunitreport/go-junit-report.go 0000664 0000000 0000000 00000003703 14514065750 0024714 0 ustar 00root root 0000000 0000000 package gojunitreport
import (
"encoding/json"
"encoding/xml"
"fmt"
"io"
"os"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
"github.com/jstemmer/go-junit-report/v2/junit"
"github.com/jstemmer/go-junit-report/v2/parser/gotest"
)
type parser interface {
Parse(r io.Reader) (gtr.Report, error)
Events() []gotest.Event
}
// Config contains the go-junit-report command configuration.
type Config struct {
Parser string
Hostname string
PackageName string
SkipXMLHeader bool
SubtestMode gotest.SubtestMode
Properties map[string]string
TimestampFunc func() time.Time
// For debugging
PrintEvents bool
}
// Run runs the go-junit-report command and returns the generated report.
func (c Config) Run(input io.Reader, output io.Writer) (*gtr.Report, error) {
var p parser
switch c.Parser {
case "gotest":
p = gotest.NewParser(c.gotestOptions()...)
case "gojson":
p = gotest.NewJSONParser(c.gotestOptions()...)
default:
return nil, fmt.Errorf("invalid parser: %s", c.Parser)
}
report, err := p.Parse(input)
if err != nil {
return nil, fmt.Errorf("error parsing input: %w", err)
}
if c.PrintEvents {
enc := json.NewEncoder(os.Stderr)
for _, event := range p.Events() {
if err := enc.Encode(event); err != nil {
return nil, err
}
}
}
for i := range report.Packages {
for k, v := range c.Properties {
report.Packages[i].SetProperty(k, v)
}
}
if err = c.writeJunitXML(output, report); err != nil {
return nil, err
}
return &report, nil
}
func (c Config) writeJunitXML(w io.Writer, report gtr.Report) error {
testsuites := junit.CreateFromReport(report, c.Hostname)
if !c.SkipXMLHeader {
_, err := fmt.Fprintf(w, xml.Header)
if err != nil {
return err
}
}
return testsuites.WriteXML(w)
}
func (c Config) gotestOptions() []gotest.Option {
return []gotest.Option{
gotest.PackageName(c.PackageName),
gotest.SetSubtestMode(c.SubtestMode),
gotest.TimestampFunc(c.TimestampFunc),
}
}
go-junit-report-2.1.0/internal/gojunitreport/go-junit-report_test.go 0000664 0000000 0000000 00000005336 14514065750 0025757 0 ustar 00root root 0000000 0000000 package gojunitreport
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
)
const testDataDir = "../../testdata/"
var matchTest = flag.String("match", "", "only test testdata matching this pattern")
var testConfigs = map[int]Config{
5: {SkipXMLHeader: true},
6: {SkipXMLHeader: true},
7: {PackageName: "test/package"},
39: {Properties: make(map[string]string)},
}
func TestRun(t *testing.T) {
matchRegex := compileMatch(t)
files, err := filepath.Glob(testDataDir + "*.txt")
if err != nil {
t.Fatalf("error finding files in testdata: %v", err)
}
if len(files) == 0 {
t.Fatalf("no files found in %s", testDataDir)
}
for _, file := range files {
if !matchRegex.MatchString(file) {
continue
}
conf, reportFile, err := testFileConfig(strings.TrimPrefix(file, testDataDir))
if err != nil {
t.Errorf("testFileConfig error: %v", err)
continue
}
t.Run(filepath.Base(file), func(t *testing.T) {
testRun(file, testDataDir+reportFile, conf, t)
})
}
}
func testRun(inputFile, reportFile string, config Config, t *testing.T) {
input, err := os.Open(inputFile)
if err != nil {
t.Fatalf("error opening input file: %v", err)
}
defer input.Close()
wantReport, err := ioutil.ReadFile(reportFile)
if os.IsNotExist(err) {
t.Skipf("Skipping test with missing report file: %s", reportFile)
} else if err != nil {
t.Fatalf("error loading report file: %v", err)
}
config.Parser = "gotest"
if strings.HasSuffix(inputFile, ".gojson.txt") {
config.Parser = "gojson"
}
config.Hostname = "hostname"
if config.Properties == nil {
config.Properties = map[string]string{"go.version": "1.0"}
}
config.TimestampFunc = func() time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
}
var output bytes.Buffer
if _, err := config.Run(input, &output); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(string(wantReport), output.String()); diff != "" {
t.Errorf("Unexpected report diff (-want, +got):\n%v", diff)
}
}
func testFileConfig(filename string) (config Config, reportFile string, err error) {
idx := strings.IndexByte(filename, '-')
if idx < 0 {
return config, "", fmt.Errorf("testdata file does not contain a dash (-); expected name `{id}-{name}.txt` got `%s`", filename)
}
prefix := filename[:idx]
id, err := strconv.Atoi(prefix)
if err != nil {
return config, "", fmt.Errorf("testdata file did not start with a valid number: %w", err)
}
return testConfigs[id], fmt.Sprintf("%s-report.xml", prefix), nil
}
func compileMatch(t *testing.T) *regexp.Regexp {
rx, err := regexp.Compile(*matchTest)
if err != nil {
t.Fatalf("Error compiling -match flag %q: %v", *matchTest, err)
}
return rx
}
go-junit-report-2.1.0/junit/ 0000775 0000000 0000000 00000000000 14514065750 0015717 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/junit/junit.go 0000664 0000000 0000000 00000016340 14514065750 0017403 0 ustar 00root root 0000000 0000000 // Package junit defines a JUnit XML report and includes convenience methods
// for working with these reports.
package junit
import (
"encoding/xml"
"fmt"
"io"
"strings"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
)
// Testsuites is a collection of JUnit testsuites.
type Testsuites struct {
XMLName xml.Name `xml:"testsuites"`
Name string `xml:"name,attr,omitempty"`
Time string `xml:"time,attr,omitempty"` // total duration in seconds
Tests int `xml:"tests,attr,omitempty"`
Errors int `xml:"errors,attr,omitempty"`
Failures int `xml:"failures,attr,omitempty"`
Skipped int `xml:"skipped,attr,omitempty"`
Disabled int `xml:"disabled,attr,omitempty"`
Suites []Testsuite `xml:"testsuite,omitempty"`
}
// AddSuite adds a Testsuite and updates this testssuites' totals.
func (t *Testsuites) AddSuite(ts Testsuite) {
t.Suites = append(t.Suites, ts)
t.Tests += ts.Tests
t.Errors += ts.Errors
t.Failures += ts.Failures
t.Skipped += ts.Skipped
t.Disabled += ts.Disabled
}
// WriteXML writes the XML representation of Testsuites t to writer w.
func (t *Testsuites) WriteXML(w io.Writer) error {
enc := xml.NewEncoder(w)
enc.Indent("", "\t")
if err := enc.Encode(t); err != nil {
return err
}
if err := enc.Flush(); err != nil {
return err
}
_, err := fmt.Fprintf(w, "\n")
return err
}
// Testsuite is a single JUnit testsuite containing testcases.
type Testsuite struct {
// required attributes
Name string `xml:"name,attr"`
Tests int `xml:"tests,attr"`
Failures int `xml:"failures,attr"`
Errors int `xml:"errors,attr"`
ID int `xml:"id,attr"`
// optional attributes
Disabled int `xml:"disabled,attr,omitempty"`
Hostname string `xml:"hostname,attr,omitempty"`
Package string `xml:"package,attr,omitempty"`
Skipped int `xml:"skipped,attr,omitempty"`
Time string `xml:"time,attr"` // duration in seconds
Timestamp string `xml:"timestamp,attr,omitempty"` // date and time in ISO8601
File string `xml:"file,attr,omitempty"`
Properties *[]Property `xml:"properties>property,omitempty"`
Testcases []Testcase `xml:"testcase,omitempty"`
SystemOut *Output `xml:"system-out,omitempty"`
SystemErr *Output `xml:"system-err,omitempty"`
}
// AddProperty adds a property with the given name and value to this Testsuite.
func (t *Testsuite) AddProperty(name, value string) {
prop := Property{Name: name, Value: value}
if t.Properties == nil {
t.Properties = &[]Property{prop}
return
}
props := append(*t.Properties, prop)
t.Properties = &props
}
// AddTestcase adds Testcase tc to this Testsuite.
func (t *Testsuite) AddTestcase(tc Testcase) {
t.Testcases = append(t.Testcases, tc)
t.Tests++
if tc.Error != nil {
t.Errors++
}
if tc.Failure != nil {
t.Failures++
}
if tc.Skipped != nil {
t.Skipped++
}
}
// SetTimestamp sets the timestamp in this Testsuite.
func (t *Testsuite) SetTimestamp(timestamp time.Time) {
t.Timestamp = timestamp.Format(time.RFC3339)
}
// Testcase represents a single test with its results.
type Testcase struct {
// required attributes
Name string `xml:"name,attr"`
Classname string `xml:"classname,attr"`
// optional attributes
Time string `xml:"time,attr,omitempty"` // duration in seconds
Status string `xml:"status,attr,omitempty"`
Skipped *Result `xml:"skipped,omitempty"`
Error *Result `xml:"error,omitempty"`
Failure *Result `xml:"failure,omitempty"`
SystemOut *Output `xml:"system-out,omitempty"`
SystemErr *Output `xml:"system-err,omitempty"`
}
// Property represents a key/value pair.
type Property struct {
Name string `xml:"name,attr"`
Value string `xml:"value,attr"`
}
// Result represents the result of a single test.
type Result struct {
Message string `xml:"message,attr"`
Type string `xml:"type,attr,omitempty"`
Data string `xml:",cdata"`
}
// Output represents output written to stdout or sderr.
type Output struct {
Data string `xml:",cdata"`
}
// CreateFromReport creates a JUnit representation of the given gtr.Report.
func CreateFromReport(report gtr.Report, hostname string) Testsuites {
var suites Testsuites
for _, pkg := range report.Packages {
var duration time.Duration
suite := Testsuite{
Name: pkg.Name,
Hostname: hostname,
ID: len(suites.Suites),
}
if !pkg.Timestamp.IsZero() {
suite.SetTimestamp(pkg.Timestamp)
}
for _, p := range pkg.Properties {
suite.AddProperty(p.Name, p.Value)
}
if len(pkg.Output) > 0 {
suite.SystemOut = &Output{Data: formatOutput(pkg.Output)}
}
if pkg.Coverage > 0 {
suite.AddProperty("coverage.statements.pct", fmt.Sprintf("%.2f", pkg.Coverage))
}
for _, test := range pkg.Tests {
duration += test.Duration
suite.AddTestcase(createTestcaseForTest(pkg.Name, test))
}
// JUnit doesn't have a good way of dealing with build or runtime
// errors that happen before a test has started, so we create a single
// failing test that contains the build error details.
if pkg.BuildError.Name != "" {
tc := Testcase{
Classname: pkg.BuildError.Name,
Name: pkg.BuildError.Cause,
Time: formatDuration(0),
Error: &Result{
Message: "Build error",
Data: strings.Join(pkg.BuildError.Output, "\n"),
},
}
suite.AddTestcase(tc)
}
if pkg.RunError.Name != "" {
tc := Testcase{
Classname: pkg.RunError.Name,
Name: "Failure",
Time: formatDuration(0),
Error: &Result{
Message: "Runtime error",
Data: strings.Join(pkg.RunError.Output, "\n"),
},
}
suite.AddTestcase(tc)
}
if (pkg.Duration) == 0 {
suite.Time = formatDuration(duration)
} else {
suite.Time = formatDuration(pkg.Duration)
}
suites.AddSuite(suite)
}
return suites
}
func createTestcaseForTest(pkgName string, test gtr.Test) Testcase {
tc := Testcase{
Classname: pkgName,
Name: test.Name,
Time: formatDuration(test.Duration),
}
if test.Result == gtr.Fail {
tc.Failure = &Result{
Message: "Failed",
Data: formatOutput(test.Output),
}
} else if test.Result == gtr.Skip {
tc.Skipped = &Result{
Message: "Skipped",
Data: formatOutput(test.Output),
}
} else if test.Result == gtr.Unknown {
tc.Error = &Result{
Message: "No test result found",
Data: formatOutput(test.Output),
}
} else if len(test.Output) > 0 {
tc.SystemOut = &Output{Data: formatOutput(test.Output)}
}
return tc
}
// formatDuration returns the JUnit string representation of the given
// duration.
func formatDuration(d time.Duration) string {
return fmt.Sprintf("%.3f", d.Seconds())
}
// formatOutput combines the lines from the given output into a single string.
func formatOutput(output []string) string {
return escapeIllegalChars(strings.Join(output, "\n"))
}
func escapeIllegalChars(str string) string {
return strings.Map(func(r rune) rune {
if isInCharacterRange(r) {
return r
}
return '\uFFFD'
}, str)
}
// Decide whether the given rune is in the XML Character Range, per
// the Char production of https://www.xml.com/axml/testaxml.htm,
// Section 2.2 Characters.
// From: encoding/xml/xml.go
func isInCharacterRange(r rune) (inrange bool) {
return r == 0x09 ||
r == 0x0A ||
r == 0x0D ||
r >= 0x20 && r <= 0xD7FF ||
r >= 0xE000 && r <= 0xFFFD ||
r >= 0x10000 && r <= 0x10FFFF
}
go-junit-report-2.1.0/junit/junit_test.go 0000664 0000000 0000000 00000011276 14514065750 0020445 0 ustar 00root root 0000000 0000000 package junit
import (
"bytes"
"encoding/xml"
"testing"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
"github.com/google/go-cmp/cmp"
)
func TestCreateFromReport(t *testing.T) {
report := gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Timestamp: time.Date(2022, 6, 26, 0, 0, 0, 0, time.UTC),
Duration: 1 * time.Second,
Coverage: 0.9,
Output: []string{"output"},
Properties: []gtr.Property{{Name: "go.version", Value: "go1.18"}},
Tests: []gtr.Test{
{
Name: "TestPass",
Result: gtr.Pass,
Output: []string{"ok"},
},
{
Name: "TestEscapeOutput",
Result: gtr.Pass,
Output: []string{"\x00\v\f \t\\"},
},
{
Name: "TestFail",
Result: gtr.Fail,
Output: []string{"fail"},
},
{
Name: "TestSkip",
Result: gtr.Skip,
},
{
Name: "TestIncomplete",
Result: gtr.Unknown,
},
},
BuildError: gtr.Error{Name: "Build error"},
RunError: gtr.Error{Name: "Run error"},
},
},
}
want := Testsuites{
Tests: 7,
Errors: 3,
Failures: 1,
Skipped: 1,
Suites: []Testsuite{
{
Name: "package/name",
Tests: 7,
Errors: 3,
ID: 0,
Failures: 1,
Skipped: 1,
Time: "1.000",
Timestamp: "2022-06-26T00:00:00Z",
Properties: &[]Property{
{Name: "go.version", Value: "go1.18"},
{Name: "coverage.statements.pct", Value: "0.90"},
},
Testcases: []Testcase{
{
Name: "TestPass",
Classname: "package/name",
Time: "0.000",
SystemOut: &Output{Data: "ok"},
},
{
Name: "TestEscapeOutput",
Classname: "package/name",
Time: "0.000",
SystemOut: &Output{Data: `��� \`},
},
{
Name: "TestFail",
Classname: "package/name",
Time: "0.000",
Failure: &Result{Message: "Failed", Data: "fail"},
},
{
Name: "TestSkip",
Classname: "package/name",
Time: "0.000",
Skipped: &Result{Message: "Skipped"},
},
{
Name: "TestIncomplete",
Classname: "package/name",
Time: "0.000",
Error: &Result{Message: "No test result found"},
},
{
Classname: "Build error",
Time: "0.000",
Error: &Result{Message: "Build error"},
},
{
Name: "Failure",
Classname: "Run error",
Time: "0.000",
Error: &Result{Message: "Runtime error"},
},
},
SystemOut: &Output{Data: "output"},
},
},
}
got := CreateFromReport(report, "")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("CreateFromReport incorrect, diff (-want, +got):\n%s\n", diff)
}
}
func TestMarshalUnmarshal(t *testing.T) {
want := Testsuites{
Name: "name",
Time: "12.345",
Tests: 1,
Errors: 1,
Failures: 1,
Disabled: 1,
Suites: []Testsuite{
{
Name: "suite1",
Tests: 1,
Errors: 1,
Failures: 1,
Hostname: "localhost",
ID: 0,
Package: "package",
Skipped: 1,
Time: "12.345",
Timestamp: "2012-03-09T14:38:06+01:00",
Properties: &[]Property{
{Name: "key", Value: "value"},
},
Testcases: []Testcase{
{
Name: "test1",
Classname: "class",
Time: "12.345",
Status: "status",
Skipped: &Result{Message: "skipped", Type: "type", Data: "data"},
Error: &Result{Message: "error", Type: "type", Data: "data"},
Failure: &Result{Message: "failure", Type: "type", Data: "data"},
SystemOut: &Output{"system-out"},
SystemErr: &Output{"system-err"},
},
},
SystemOut: &Output{"system-out"},
SystemErr: &Output{"system-err"},
},
},
}
data, err := xml.MarshalIndent(want, "", "\t")
if err != nil {
t.Fatal(err)
}
var got Testsuites
if err := xml.Unmarshal(data, &got); err != nil {
t.Fatal(err)
}
want.XMLName.Local = "testsuites"
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Unmarshal result incorrect, diff (-want +got):\n%s\n", diff)
}
}
func TestWriteXML(t *testing.T) {
want := `
`
var suites Testsuites
ts := Testsuite{Name:"Example"}
ts.AddTestcase(Testcase{Name: "Test", })
suites.AddSuite(ts)
var buf bytes.Buffer
if err := suites.WriteXML(&buf); err != nil {
t.Fatalf("WriteXML failed: %v\n", err)
}
got := buf.String()
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("WriteXML mismatch, diff (-want +got):\n%s\n", diff)
}
}
go-junit-report-2.1.0/main.go 0000664 0000000 0000000 00000010005 14514065750 0016035 0 ustar 00root root 0000000 0000000 // go-junit-report converts `go test` output to a JUnit compatible XML report.
//
// See README.md for more information and usage examples.
package main
import (
"flag"
"fmt"
"io"
"os"
"strings"
"github.com/jstemmer/go-junit-report/v2/internal/gojunitreport"
"github.com/jstemmer/go-junit-report/v2/parser/gotest"
)
// Current release information printed by the -version flag.
var (
Version = "v2.1.0-dev"
Revision = "HEAD"
BuildTime string
)
var (
noXMLHeader = flag.Bool("no-xml-header", false, "do not print xml header")
packageName = flag.String("package-name", "", "specify a default package `name` to use if output does not contain a package name")
setExitCode = flag.Bool("set-exit-code", false, "set exit code to 1 if tests failed")
version = flag.Bool("version", false, "print version")
input = flag.String("in", "", "read go test log from `file`")
output = flag.String("out", "", "write XML report to `file`")
iocopy = flag.Bool("iocopy", false, "copy input to stdout; can only be used in conjunction with -out")
properties = make(keyValueFlag)
parser = flag.String("parser", "gotest", "set input parser: gotest, gojson")
mode = flag.String("subtest-mode", "", "set subtest `mode`: ignore-parent-results (subtest parents always pass), exclude-parents (subtest parents are excluded from the report)")
// debug flags
printEvents = flag.Bool("debug.print-events", false, "print events generated by the go test parser")
// deprecated flags
goVersionFlag = flag.String("go-version", "", "(deprecated, use -prop) the value to use for the go.version property in the generated XML")
)
func main() {
flag.Var(&properties, "p", "add `key=value` property to generated report; repeat this flag to add multiple properties.")
flag.Parse()
if *iocopy && *output == "" {
exitf("you must specify an output file with -out when using -iocopy")
}
if *version {
fmt.Printf("go-junit-report %s %s (%s)\n", Version, BuildTime, Revision)
return
}
if *goVersionFlag != "" {
fmt.Fprintf(os.Stderr, "the -go-version flag is deprecated and will be removed in the future, use the -p flag instead.\n")
properties["go.version"] = *goVersionFlag
}
subtestMode := gotest.SubtestModeDefault
if *mode != "" {
var err error
if subtestMode, err = gotest.ParseSubtestMode(*mode); err != nil {
exitf("invalid value for -subtest-mode: %s\n", err)
}
}
if flag.NArg() != 0 {
fmt.Fprintf(os.Stderr, "invalid argument(s): %s\n", strings.Join(flag.Args(), " "))
fmt.Fprintf(os.Stderr, "%s does not accept positional arguments\n", os.Args[0])
flag.Usage()
exitf("")
}
var in io.Reader = os.Stdin
if *input != "" {
f, err := os.Open(*input)
if err != nil {
exitf("error opening input file: %v", err)
}
defer f.Close()
in = f
}
var out io.Writer = os.Stdout
if *output != "" {
f, err := os.Create(*output)
if err != nil {
exitf("error creating output file: %v", err)
}
defer f.Close()
out = f
}
if *iocopy {
in = io.TeeReader(in, os.Stdout)
}
hostname, _ := os.Hostname() // ignore error
config := gojunitreport.Config{
Parser: *parser,
Hostname: hostname,
PackageName: *packageName,
SkipXMLHeader: *noXMLHeader,
SubtestMode: subtestMode,
Properties: properties,
PrintEvents: *printEvents,
}
report, err := config.Run(in, out)
if err != nil {
exitf("error: %v\n", err)
}
if *setExitCode && !report.IsSuccessful() {
os.Exit(1)
}
}
func exitf(msg string, args ...interface{}) {
if msg != "" {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
}
os.Exit(2)
}
type keyValueFlag map[string]string
func (f *keyValueFlag) String() string {
if f != nil {
var pairs []string
for k, v := range *f {
pairs = append(pairs, fmt.Sprintf("%s=%s", k, v))
}
return strings.Join(pairs, ",")
}
return ""
}
func (f *keyValueFlag) Set(value string) error {
idx := strings.IndexByte(value, '=')
if idx == -1 {
return fmt.Errorf("%v is not specified as \"key=value\"", value)
}
k, v := value[:idx], value[idx+1:]
(*f)[k] = v
return nil
}
go-junit-report-2.1.0/parser/ 0000775 0000000 0000000 00000000000 14514065750 0016062 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/parser/gotest/ 0000775 0000000 0000000 00000000000 14514065750 0017367 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/parser/gotest/benchmark.go 0000664 0000000 0000000 00000002272 14514065750 0021653 0 ustar 00root root 0000000 0000000 package gotest
import (
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
)
const (
key = "gotest.benchmark"
)
// Benchmark contains benchmark results and is intended to be used as extra
// data in a gtr.Test.
type Benchmark struct {
Iterations int64
NsPerOp float64
MBPerSec float64
BytesPerOp int64
AllocsPerOp int64
}
// ApproximateDuration returns the duration calculated by multiplying the
// iterations and average time per iteration (NsPerOp).
func (b Benchmark) ApproximateDuration() time.Duration {
return time.Duration(float64(b.Iterations)*b.NsPerOp) * time.Nanosecond
}
// GetBenchmarkData is a helper function that returns the benchmark contained
// in the data field of the given gtr.Test t. If no (valid) benchmark is
// present, ok will be set to false.
func GetBenchmarkData(t gtr.Test) (b Benchmark, ok bool) {
if t.Data != nil {
if data, exists := t.Data[key]; exists {
bm, ok := data.(Benchmark)
return bm, ok
}
}
return Benchmark{}, false
}
// SetBenchmarkData is a helper function that writes the benchmark b to the
// data field of the given gtr.Test t.
func SetBenchmarkData(t *gtr.Test, b Benchmark) {
if t.Data != nil {
t.Data[key] = b
}
}
go-junit-report-2.1.0/parser/gotest/event.go 0000664 0000000 0000000 00000002101 14514065750 0021031 0 ustar 00root root 0000000 0000000 package gotest
import (
"time"
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/reader"
)
// Event is a single event in a Go test or benchmark.
type Event struct {
Type string `json:"type"`
Name string `json:"name,omitempty"`
Package string `json:"pkg,omitempty"`
Result string `json:"result,omitempty"`
Duration time.Duration `json:"duration,omitempty"`
Data string `json:"data,omitempty"`
Indent int `json:"indent,omitempty"`
// Code coverage
CovPct float64 `json:"coverage_percentage,omitempty"`
CovPackages []string `json:"coverage_packages,omitempty"`
// Benchmarks
Iterations int64 `json:"benchmark_iterations,omitempty"`
NsPerOp float64 `json:"benchmark_ns_per_op,omitempty"`
MBPerSec float64 `json:"benchmark_mb_per_sec,omitempty"`
BytesPerOp int64 `json:"benchmark_bytes_per_op,omitempty"`
AllocsPerOp int64 `json:"benchmark_allocs_per_op,omitempty"`
}
func (e *Event) applyMetadata(m *reader.Metadata) {
if e == nil || m == nil {
return
}
e.Package = m.Package
}
go-junit-report-2.1.0/parser/gotest/gotest.go 0000664 0000000 0000000 00000024451 14514065750 0021231 0 ustar 00root root 0000000 0000000 // Package gotest is a standard Go test output parser.
package gotest
import (
"bufio"
"fmt"
"io"
"regexp"
"strconv"
"strings"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/reader"
)
const (
// maxLineSize is the maximum amount of bytes we'll read for a single line.
// Lines longer than maxLineSize will be truncated.
maxLineSize = 4 * 1024 * 1024
)
var (
// regexBenchInfo captures 3-5 groups: benchmark name, number of times ran, ns/op (with or without decimal), MB/sec (optional), B/op (optional), and allocs/op (optional).
regexBenchmark = regexp.MustCompile(`^(Benchmark[^ -]+)$`)
regexBenchSummary = regexp.MustCompile(`^(Benchmark[^ -]+)(?:-\d+\s+|\s+)(\d+)\s+(\d+|\d+\.\d+)\sns\/op(?:\s+(\d+|\d+\.\d+)\sMB\/s)?(?:\s+(\d+)\sB\/op)?(?:\s+(\d+)\sallocs/op)?`)
regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+|\d+\.\d+)%\s+of\s+statements(?:\sin\s(.+))?$`)
regexEndBenchmark = regexp.MustCompile(`^--- (BENCH|FAIL|SKIP): (Benchmark[^ -]+)(?:-\d+)?$`)
regexEndTest = regexp.MustCompile(`((?: )*)--- (PASS|FAIL|SKIP): ([^ ]+) \((\d+\.\d+)(?: seconds|s)\)`)
regexStatus = regexp.MustCompile(`^(PASS|FAIL|SKIP)$`)
regexSummary = regexp.MustCompile(`` +
// 1: result
`^(\?|ok|FAIL)` +
// 2: package name
`\s+([^ \t]+)` +
// 3: duration (optional)
`(?:\s+(\d+\.\d+)s)?` +
// 4: cached indicator (optional)
`(?:\s+(\(cached\)))?` +
// 5: coverage percentage (optional)
// 6: coverage package list (optional)
`(?:\s+coverage:\s+(?:\[no\sstatements\]|(\d+\.\d+)%\sof\sstatements(?:\sin\s(.+))?))?` +
// 7: [status message] (optional)
`(?:\s+(\[[^\]]+\]))?` +
`$`)
)
// Option defines options that can be passed to gotest.New.
type Option func(*Parser)
// PackageName is an Option that 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
}
}
// TimestampFunc is an Option that sets the timestamp function that is used to
// determine the current time when creating the Report. This can be used to
// override the default behaviour of using time.Now().
func TimestampFunc(f func() time.Time) Option {
return func(p *Parser) {
p.timestampFunc = f
}
}
// SubtestMode configures how Go subtests should be handled by the parser.
type SubtestMode string
const (
// SubtestModeDefault is the default subtest mode. It treats tests with
// subtests as any other tests.
SubtestModeDefault SubtestMode = ""
// IgnoreParentResults ignores test results for tests with subtests. Use
// this mode if you use subtest parents for common setup/teardown, but are
// not interested in counting them as failed tests. Ignoring their results
// still preserves these tests and their captured output in the report.
IgnoreParentResults SubtestMode = "ignore-parent-results"
// ExcludeParents excludes tests that contain subtests from the report.
// Note that the subtests themselves are not removed. Use this mode if you
// use subtest parents for common setup/teardown, but are not actually
// interested in their presence in the created report. If output was
// captured for tests that are removed, the output is preserved in the
// global report output.
ExcludeParents SubtestMode = "exclude-parents"
)
// ParseSubtestMode returns a SubtestMode for the given string.
func ParseSubtestMode(in string) (SubtestMode, error) {
switch in {
case string(IgnoreParentResults):
return IgnoreParentResults, nil
case string(ExcludeParents):
return ExcludeParents, nil
default:
return SubtestModeDefault, fmt.Errorf("unknown subtest mode: %v", in)
}
}
// SetSubtestMode is an Option to change how the parser handles tests with
// subtests. See the documentation for the individual SubtestModes for more
// information.
func SetSubtestMode(mode SubtestMode) Option {
return func(p *Parser) {
p.subtestMode = mode
}
}
// Parser is a Go test output Parser.
type Parser struct {
packageName string
subtestMode SubtestMode
timestampFunc func() time.Time
events []Event
}
// NewParser returns a new Go test output parser.
func NewParser(options ...Option) *Parser {
p := &Parser{}
for _, option := range options {
option(p)
}
return p
}
// 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) {
return p.parse(reader.NewLimitedLineReader(r, maxLineSize))
}
func (p *Parser) parse(r reader.LineReader) (gtr.Report, error) {
p.events = nil
rb := newReportBuilder()
rb.packageName = p.packageName
rb.subtestMode = p.subtestMode
if p.timestampFunc != nil {
rb.timestampFunc = p.timestampFunc
}
for {
line, metadata, err := r.ReadLine()
if err == io.EOF {
break
} else if err != nil {
return gtr.Report{}, err
}
var evs []Event
// Lines that exceed bufio.MaxScanTokenSize are not expected to contain
// any relevant test infrastructure output, so instead of parsing them
// we treat them as regular output to increase performance.
//
// Parser used a bufio.Scanner in the past, which only supported
// reading lines up to bufio.MaxScanTokenSize in length. Since this
// turned out to be fine in almost all cases, it seemed an appropriate
// value to use to decide whether or not to attempt parsing this line.
if len(line) > bufio.MaxScanTokenSize {
evs = p.output(line)
} else {
evs = p.parseLine(line)
}
for _, ev := range evs {
ev.applyMetadata(metadata)
rb.ProcessEvent(ev)
p.events = append(p.events, ev)
}
}
return rb.Build(), nil
}
// 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) (events []Event) {
if strings.HasPrefix(line, "=== RUN ") {
return p.runTest(strings.TrimSpace(line[8:]))
} else if strings.HasPrefix(line, "=== PAUSE ") {
return p.pauseTest(strings.TrimSpace(line[10:]))
} else if strings.HasPrefix(line, "=== CONT ") {
return p.contTest(strings.TrimSpace(line[9:]))
} else if strings.HasPrefix(line, "=== NAME ") {
// for compatibility with gotest 1.20+ https://go-review.git.corp.google.com/c/go/+/443596
return p.contTest(strings.TrimSpace(line[9:]))
} else if matches := regexEndTest.FindStringSubmatch(line); len(matches) == 5 {
return p.endTest(line, matches[1], matches[2], matches[3], matches[4])
} else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 2 {
return p.status(matches[1])
} else if matches := regexSummary.FindStringSubmatch(line); len(matches) == 8 {
return p.summary(matches[1], matches[2], matches[3], matches[4], matches[7], matches[5], matches[6])
} else if matches := regexCoverage.FindStringSubmatch(line); len(matches) == 3 {
return p.coverage(matches[1], matches[2])
} else if matches := regexBenchmark.FindStringSubmatch(line); len(matches) == 2 {
return p.runBench(matches[1])
} else if matches := regexBenchSummary.FindStringSubmatch(line); len(matches) == 7 {
return p.benchSummary(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6])
} else if matches := regexEndBenchmark.FindStringSubmatch(line); len(matches) == 3 {
return p.endBench(matches[1], matches[2])
} else if strings.HasPrefix(line, "# ") {
fields := strings.Fields(strings.TrimPrefix(line, "# "))
if len(fields) == 1 || len(fields) == 2 {
return p.buildOutput(fields[0])
}
}
return p.output(line)
}
func (p *Parser) runTest(name string) []Event {
return []Event{{Type: "run_test", Name: name}}
}
func (p *Parser) pauseTest(name string) []Event {
return []Event{{Type: "pause_test", Name: name}}
}
func (p *Parser) contTest(name string) []Event {
return []Event{{Type: "cont_test", Name: name}}
}
func (p *Parser) endTest(line, indent, result, name, duration string) []Event {
var events []Event
if idx := strings.Index(line, fmt.Sprintf("%s--- %s:", indent, result)); idx > 0 {
events = append(events, p.output(line[:idx])...)
}
_, n := stripIndent(indent)
events = append(events, Event{
Type: "end_test",
Name: name,
Result: result,
Indent: n,
Duration: parseSeconds(duration),
})
return events
}
func (p *Parser) status(result string) []Event {
return []Event{{Type: "status", Result: result}}
}
func (p *Parser) summary(result, name, duration, cached, status, covpct, packages string) []Event {
return []Event{{
Type: "summary",
Result: result,
Name: name,
Duration: parseSeconds(duration),
Data: strings.TrimSpace(cached + " " + status),
CovPct: parseFloat(covpct),
CovPackages: parsePackages(packages),
}}
}
func (p *Parser) coverage(percent, packages string) []Event {
return []Event{{
Type: "coverage",
CovPct: parseFloat(percent),
CovPackages: parsePackages(packages),
}}
}
func (p *Parser) runBench(name string) []Event {
return []Event{{
Type: "run_benchmark",
Name: name,
}}
}
func (p *Parser) benchSummary(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp string) []Event {
return []Event{{
Type: "benchmark",
Name: name,
Iterations: parseInt(iterations),
NsPerOp: parseFloat(nsPerOp),
MBPerSec: parseFloat(mbPerSec),
BytesPerOp: parseInt(bytesPerOp),
AllocsPerOp: parseInt(allocsPerOp),
}}
}
func (p *Parser) endBench(result, name string) []Event {
return []Event{{
Type: "end_benchmark",
Name: name,
Result: result,
}}
}
func (p *Parser) buildOutput(packageName string) []Event {
return []Event{{
Type: "build_output",
Name: packageName,
}}
}
func (p *Parser) output(line string) []Event {
return []Event{{Type: "output", Data: line}}
}
func parseSeconds(s string) time.Duration {
if s == "" {
return time.Duration(0)
}
// ignore error
d, _ := time.ParseDuration(s + "s")
return d
}
func parseFloat(s string) float64 {
if s == "" {
return 0
}
// ignore error
pct, _ := strconv.ParseFloat(s, 64)
return pct
}
func parsePackages(pkgList string) []string {
if len(pkgList) == 0 {
return nil
}
return strings.Split(pkgList, ", ")
}
func parseInt(s string) int64 {
// ignore error
n, _ := strconv.ParseInt(s, 10, 64)
return n
}
func stripIndent(line string) (string, int) {
var indent int
for indent = 0; strings.HasPrefix(line, " "); indent++ {
line = line[4:]
}
return line, indent
}
go-junit-report-2.1.0/parser/gotest/gotest_fuzz_test.go 0000664 0000000 0000000 00000000523 14514065750 0023340 0 ustar 00root root 0000000 0000000 //go:build go1.18
// +build go1.18
package gotest
import "testing"
func FuzzParseLine(f *testing.F) {
for _, test := range parseLineTests {
f.Add(test.input)
}
f.Fuzz(func(t *testing.T, in string) {
events := NewParser().parseLine(in)
if len(events) == 0 {
t.Fatalf("parseLine(%q) did not return any results", in)
}
})
}
go-junit-report-2.1.0/parser/gotest/gotest_test.go 0000664 0000000 0000000 00000015322 14514065750 0022265 0 ustar 00root root 0000000 0000000 package gotest
import (
"fmt"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
)
var (
testTimestamp = time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
testTimestampFunc = func() time.Time { return testTimestamp }
)
type parseLineTest struct {
input string
events []Event
}
func (t parseLineTest) Name() string {
var types []string
for _, e := range t.events {
types = append(types, e.Type)
}
return strings.Join(types, "-")
}
var parseLineTests = []parseLineTest{
{
"=== RUN TestOne",
[]Event{{Type: "run_test", Name: "TestOne"}},
},
{
"=== RUN TestTwo/Subtest",
[]Event{{Type: "run_test", Name: "TestTwo/Subtest"}},
},
{
"=== PAUSE TestOne",
[]Event{{Type: "pause_test", Name: "TestOne"}},
},
{
"=== CONT TestOne",
[]Event{{Type: "cont_test", Name: "TestOne"}},
},
{
"=== NAME TestOne",
[]Event{{Type: "cont_test", Name: "TestOne"}},
},
{
"--- PASS: TestOne (12.34 seconds)",
[]Event{{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 12_340 * time.Millisecond}},
},
{
" --- SKIP: TestOne/Subtest (0.00s)",
[]Event{{Type: "end_test", Name: "TestOne/Subtest", Result: "SKIP", Indent: 1}},
},
{
" --- FAIL: TestOne/Subtest/#01 (0.35s)",
[]Event{{Type: "end_test", Name: "TestOne/Subtest/#01", Result: "FAIL", Duration: 350 * time.Millisecond, Indent: 2}},
},
{
"some text--- PASS: TestTwo (0.06 seconds)",
[]Event{
{Type: "output", Data: "some text"},
{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 60 * time.Millisecond},
},
},
{
"PASS",
[]Event{{Type: "status", Result: "PASS"}},
},
{
"FAIL",
[]Event{{Type: "status", Result: "FAIL"}},
},
{
"SKIP",
[]Event{{Type: "status", Result: "SKIP"}},
},
{
"ok package/name/ok 0.100s",
[]Event{{Type: "summary", Name: "package/name/ok", Result: "ok", Duration: 100 * time.Millisecond}},
},
{
"FAIL package/name/failing [build failed]",
[]Event{{Type: "summary", Name: "package/name/failing", Result: "FAIL", Data: "[build failed]"}},
},
{
"FAIL package/other/failing [setup failed]",
[]Event{{Type: "summary", Name: "package/other/failing", Result: "FAIL", Data: "[setup failed]"}},
},
{
"ok package/other (cached)",
[]Event{{Type: "summary", Name: "package/other", Result: "ok", Data: "(cached)"}},
},
{
"ok package/name 0.400s coverage: [no statements]",
[]Event{{Type: "summary", Name: "package/name", Result: "ok", Duration: 400 * time.Millisecond}},
},
{
"ok package/name 0.400s (cached) coverage: [no statements]",
[]Event{{Type: "summary", Name: "package/name", Result: "ok", Duration: 400 * time.Millisecond, Data: "(cached)"}},
},
{
"ok package/name 0.001s coverage: [no statements] [no tests to run]",
[]Event{{Type: "summary", Name: "package/name", Result: "ok", Duration: 1 * time.Millisecond, Data: "[no tests to run]"}},
},
{
"ok package/name 0.400s coverage: 10.0% of statements",
[]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",
[]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]",
[]Event{{Type: "summary", Name: "package/name", Result: "?", Data: "[no test files]"}},
},
{
"ok package/name 0.001s [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]",
[]Event{{Type: "summary", Name: "package/name", Result: "ok", Data: "(cached) [no tests to run]"}},
},
{
"ok package/name 0.042s coverage: 0.0% of statements [no tests to run]",
[]Event{{Type: "summary", Name: "package/name", Result: "ok", Duration: 42 * time.Millisecond, CovPct: 0, Data: "[no tests to run]"}},
},
{
"coverage: 10% of statements",
[]Event{{Type: "coverage", CovPct: 10}},
},
{
"coverage: 10% of statements in fmt, encoding/xml",
[]Event{{Type: "coverage", CovPct: 10, CovPackages: []string{"fmt", "encoding/xml"}}},
},
{
"coverage: 13.37% of statements",
[]Event{{Type: "coverage", CovPct: 13.37}},
},
{
"coverage: 99.8% of statements in fmt, encoding/xml",
[]Event{{Type: "coverage", CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}}},
},
{
"BenchmarkOK",
[]Event{{Type: "run_benchmark", Name: "BenchmarkOK"}},
},
{
"BenchmarkOne-8 2000000 604 ns/op",
[]Event{{Type: "benchmark", Name: "BenchmarkOne", Iterations: 2_000_000, NsPerOp: 604}},
},
{
"BenchmarkTwo-16 30000 52568 ns/op 24879 B/op 494 allocs/op",
[]Event{{Type: "benchmark", Name: "BenchmarkTwo", Iterations: 30_000, NsPerOp: 52_568, BytesPerOp: 24_879, AllocsPerOp: 494}},
},
{
"BenchmarkThree 2000000000 0.26 ns/op",
[]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",
[]Event{{Type: "benchmark", Name: "BenchmarkFour", Iterations: 10_000, NsPerOp: 104_427, MBPerSec: 95.76, BytesPerOp: 40_629, AllocsPerOp: 5}},
},
{
"--- BENCH: BenchmarkOK-8",
[]Event{{Type: "end_benchmark", Name: "BenchmarkOK", Result: "BENCH"}},
},
{
"--- FAIL: BenchmarkError",
[]Event{{Type: "end_benchmark", Name: "BenchmarkError", Result: "FAIL"}},
},
{
"--- SKIP: BenchmarkSkip",
[]Event{{Type: "end_benchmark", Name: "BenchmarkSkip", Result: "SKIP"}},
},
{
"# package/name/failing1",
[]Event{{Type: "build_output", Name: "package/name/failing1"}},
},
{
"# package/name/failing2 [package/name/failing2.test]",
[]Event{{Type: "build_output", Name: "package/name/failing2"}},
},
{
"single line stdout",
[]Event{{Type: "output", Data: "single line stdout"}},
},
{
"# some more output",
[]Event{{Type: "output", Data: "# some more output"}},
},
{
"\tfile_test.go:11: Error message",
[]Event{{Type: "output", Data: "\tfile_test.go:11: Error message"}},
},
{
"\tfile_test.go:12: Longer",
[]Event{{Type: "output", Data: "\tfile_test.go:12: Longer"}},
},
{
"\t\terror",
[]Event{{Type: "output", Data: "\t\terror"}},
},
{
"\t\tmessage.",
[]Event{{Type: "output", Data: "\t\tmessage."}},
},
}
func TestParseLine(t *testing.T) {
for i, test := range parseLineTests {
name := fmt.Sprintf("%d-%s", i, test.Name())
t.Run(name, func(t *testing.T) {
parser := NewParser()
events := parser.parseLine(test.input)
if diff := cmp.Diff(test.events, events); diff != "" {
t.Errorf("parseLine(%q) returned unexpected events, diff (-want, +got):\n%v", test.input, diff)
}
})
}
}
go-junit-report-2.1.0/parser/gotest/internal/ 0000775 0000000 0000000 00000000000 14514065750 0021203 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/parser/gotest/internal/collector/ 0000775 0000000 0000000 00000000000 14514065750 0023171 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/parser/gotest/internal/collector/collector.go 0000664 0000000 0000000 00000005150 14514065750 0025507 0 ustar 00root root 0000000 0000000 // Package collector collects output lines grouped by id and provides ways to
// retrieve and merge output ordered by the time each line was added.
package collector
import (
"sort"
"time"
)
// line is a single line of output captured at some point in time.
type line struct {
Timestamp time.Time
Text string
}
// Output stores output lines grouped by id. Output can be retrieved for one or
// more ids and output for different ids can be merged together, while
// preserving their insertion original order based on the time it was
// collected.
// Output also tracks the active id, so you can append output without providing
// an id.
type Output struct {
m map[int][]line
id int // active id
}
// New returns a new output collector.
func New() *Output {
return &Output{m: make(map[int][]line)}
}
// Clear deletes all output for the given id.
func (o *Output) Clear(id int) {
delete(o.m, id)
}
// Append appends the given line of text to the output of the currently active
// id.
func (o *Output) Append(text string) {
o.m[o.id] = append(o.m[o.id], line{time.Now(), text})
}
// AppendToID appends the given line of text to the output of the given id.
func (o *Output) AppendToID(id int, text string) {
o.m[id] = append(o.m[id], line{time.Now(), text})
}
// Contains returns true if any output lines were collected for the given id.
func (o *Output) Contains(id int) bool {
return len(o.m[id]) > 0
}
// Get returns the output lines for the given id.
func (o *Output) Get(id int) []string {
var lines []string
for _, line := range o.m[id] {
lines = append(lines, line.Text)
}
return lines
}
// GetAll returns the output lines for all ids sorted by the collection
// timestamp of each line of output.
func (o *Output) GetAll(ids ...int) []string {
var output []line
for _, id := range ids {
output = append(output, o.m[id]...)
}
sort.Slice(output, func(i, j int) bool {
return output[i].Timestamp.Before(output[j].Timestamp)
})
var lines []string
for _, line := range output {
lines = append(lines, line.Text)
}
return lines
}
// Merge merges the output lines from fromID into intoID, and sorts the output
// by the collection timestamp of each line of output.
func (o *Output) Merge(fromID, intoID int) {
var merged []line
for _, id := range []int{fromID, intoID} {
merged = append(merged, o.m[id]...)
}
sort.Slice(merged, func(i, j int) bool {
return merged[i].Timestamp.Before(merged[j].Timestamp)
})
o.m[intoID] = merged
delete(o.m, fromID)
}
// SetActiveID sets the active id. Text appended to this output will be
// associated with the active id.
func (o *Output) SetActiveID(id int) {
o.id = id
}
go-junit-report-2.1.0/parser/gotest/internal/collector/collector_test.go 0000664 0000000 0000000 00000004445 14514065750 0026554 0 ustar 00root root 0000000 0000000 package collector
import (
"strconv"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestClear(t *testing.T) {
o := New()
o.AppendToID(1, "1")
o.AppendToID(2, "2")
o.Clear(1)
want := []string(nil)
got := o.Get(1)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Clear(1) did not clear output (-want +got):\n%s", diff)
}
want = []string{"2"}
got = o.Get(2)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Clear(1) cleared wrong output (-want +got):\n%s", diff)
}
}
func TestAppendAndGet(t *testing.T) {
o := New()
o.AppendToID(1, "1.1")
o.AppendToID(1, "1.2")
o.AppendToID(2, "2")
o.AppendToID(1, "1.3")
want := []string{"1.1", "1.2", "1.3"}
got := o.Get(1)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("AppendToID() incorrect (-want +got):\n%s", diff)
}
}
func TestContains(t *testing.T) {
o := New()
o.AppendToID(1, "1")
o.AppendToID(2, "2")
o.Clear(1)
if !o.Contains(2) {
t.Errorf("Contains(1) incorrect, got true want false")
}
for i := -100; i < 100; i++ {
if i != 2 && o.Contains(i) {
t.Errorf("Contains(%d) incorrect, got true want false", i)
}
}
}
func TestGetAll(t *testing.T) {
o := New()
for i := 1; i <= 10; i++ {
o.AppendToID(i%3, strconv.Itoa(i))
}
want := []string{"1", "2", "4", "5", "7", "8", "10"}
got := o.GetAll(1, 2)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("GetAll(1, 2) incorrect (-want +got):\n%s", diff)
}
}
func TestMerge(t *testing.T) {
o := New()
for i := 1; i <= 10; i++ {
o.AppendToID(i%3, strconv.Itoa(i))
}
o.Merge(2, 1)
want := []string{"1", "2", "4", "5", "7", "8", "10"}
got := o.Get(1)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Get(1) after Merge(2, 1) incorrect (-want +got):\n%s", diff)
}
want = []string(nil)
got = o.Get(2)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Get(2) after Merge(2, 1) incorrect (-want +got):\n%s", diff)
}
}
func TestActiveID(t *testing.T) {
o := New()
o.Append("0")
o.SetActiveID(2)
o.Append("2")
o.SetActiveID(1)
o.Append("1")
o.SetActiveID(0)
o.Append("0")
expected := [][]string{
{"0", "0"},
{"1"},
{"2"},
}
for i := 0; i < 2; i++ {
want := expected[i]
got := o.Get(i)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Get(0) after SetActiveID incorrect (-want +got):\n%s", diff)
}
}
}
go-junit-report-2.1.0/parser/gotest/internal/reader/ 0000775 0000000 0000000 00000000000 14514065750 0022445 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/parser/gotest/internal/reader/reader.go 0000664 0000000 0000000 00000005773 14514065750 0024252 0 ustar 00root root 0000000 0000000 package reader
import (
"bufio"
"bytes"
"encoding/json"
"io"
"strings"
"time"
)
// LineReader is an interface to read lines with optional Metadata.
type LineReader interface {
ReadLine() (string, *Metadata, error)
}
// Metadata contains metadata that belongs to a line.
type Metadata struct {
Package string
}
// LimitedLineReader reads lines from an io.Reader object with a configurable
// line size limit. Lines exceeding the limit will be truncated, but read
// completely from the underlying io.Reader.
type LimitedLineReader struct {
r *bufio.Reader
limit int
}
var _ LineReader = &LimitedLineReader{}
// NewLimitedLineReader returns a LimitedLineReader to read lines from r with a
// maximum line size of limit.
func NewLimitedLineReader(r io.Reader, limit int) *LimitedLineReader {
return &LimitedLineReader{r: bufio.NewReader(r), limit: limit}
}
// ReadLine returns the next line from the underlying reader. The length of the
// line will not exceed the configured limit. ReadLine either returns a line or
// it returns an error, never both.
func (r *LimitedLineReader) ReadLine() (string, *Metadata, error) {
line, isPrefix, err := r.r.ReadLine()
if err != nil {
return "", nil, err
}
if !isPrefix {
return string(line), nil, nil
}
// Line is incomplete, keep reading until we reach the end of the line.
var buf bytes.Buffer
buf.Write(line) // ignore err, always nil
for isPrefix {
line, isPrefix, err = r.r.ReadLine()
if err != nil {
return "", nil, err
}
if buf.Len() >= r.limit {
// Stop writing to buf if we exceed the limit. We continue reading
// however to make sure we consume the entire line.
continue
}
buf.Write(line) // ignore err, always nil
}
if buf.Len() > r.limit {
buf.Truncate(r.limit)
}
return buf.String(), nil, nil
}
// Event represents a JSON event emitted by `go test -json`.
type Event struct {
Time time.Time
Action string
Package string
Test string
Elapsed float64 // seconds
Output string
}
// JSONEventReader reads JSON events from an io.Reader object.
type JSONEventReader struct {
r *LimitedLineReader
}
var _ LineReader = &JSONEventReader{}
// jsonLineLimit is the maximum size of a single JSON line emitted by `go test
// -json`.
const jsonLineLimit = 64 * 1024
// NewJSONEventReader returns a JSONEventReader to read the data in JSON
// events from r.
func NewJSONEventReader(r io.Reader) *JSONEventReader {
return &JSONEventReader{NewLimitedLineReader(r, jsonLineLimit)}
}
// ReadLine returns the next line from the underlying reader.
func (r *JSONEventReader) ReadLine() (string, *Metadata, error) {
for {
line, _, err := r.r.ReadLine()
if err != nil {
return "", nil, err
}
if len(line) == 0 || line[0] != '{' {
return line, nil, nil
}
event := &Event{}
if err := json.Unmarshal([]byte(line), event); err != nil {
return "", nil, err
}
if event.Output == "" {
// Skip events without output
continue
}
return strings.TrimSuffix(event.Output, "\n"), &Metadata{Package: event.Package}, nil
}
}
go-junit-report-2.1.0/parser/gotest/internal/reader/reader_test.go 0000664 0000000 0000000 00000005306 14514065750 0025301 0 ustar 00root root 0000000 0000000 package reader
import (
"bufio"
"io"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
const testingLimit = 4 * 1024 * 1024
func TestLimitedLineReader(t *testing.T) {
tests := []struct {
desc string
inputSize int
}{
{"small size", 128},
{"under buf size", 4095},
{"buf size", 4096},
{"multiple of buf size ", 4096 * 2},
{"not multiple of buf size", 10 * 1024},
{"bufio.MaxScanTokenSize", bufio.MaxScanTokenSize},
{"over bufio.MaxScanTokenSize", bufio.MaxScanTokenSize + 1},
{"under limit", testingLimit - 1},
{"at limit", testingLimit},
{"just over limit", testingLimit + 1},
{"over limit", testingLimit + 128},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
line1 := string(make([]byte, test.inputSize))
line2 := "other line"
input := strings.NewReader(strings.Join([]string{line1, line2}, "\n"))
r := NewLimitedLineReader(input, testingLimit)
got, _, err := r.ReadLine()
if err != nil {
t.Fatalf("ReadLine() returned error %v", err)
}
want := line1
if len(line1) > testingLimit {
want = want[:testingLimit]
}
if got != want {
t.Fatalf("ReadLine() returned incorrect line, got len %d want len %d", len(got), len(want))
}
got, _, err = r.ReadLine()
if err != nil {
t.Fatalf("ReadLine() returned error %v", err)
}
want = line2
if got != want {
t.Fatalf("ReadLine() returned incorrect line, got len %d want len %d", len(got), len(want))
}
got, _, err = r.ReadLine()
if err != io.EOF {
t.Fatalf("ReadLine() returned unexpected error, got %v want %v\n", err, io.EOF)
}
if got != "" {
t.Fatalf("ReadLine() returned unexpected line, got %v want nothing\n", got)
}
})
}
}
func TestJSONEventReader(t *testing.T) {
input := `some other output
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK"}
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK","Output":"=== RUN TestOK\n"}
`
want := []struct {
line string
metadata *Metadata
}{
{"some other output", nil},
{"=== RUN TestOK", &Metadata{Package: "package/name/ok"}},
}
r := NewJSONEventReader(strings.NewReader(input))
for i := 0; i < len(want); i++ {
line, metadata, err := r.ReadLine()
if err == io.EOF {
return
} else if err != nil {
t.Fatalf("ReadLine() returned error %v", err)
}
if diff := cmp.Diff(want[i].line, line); diff != "" {
t.Errorf("ReadLine() returned incorrect line, diff (-want, +got):\n%s\n", diff)
}
if diff := cmp.Diff(want[i].metadata, metadata); diff != "" {
t.Errorf("ReadLine() Returned incorrect metadata, diff (-want, +got):\n%s\n", diff)
}
}
}
go-junit-report-2.1.0/parser/gotest/json.go 0000664 0000000 0000000 00000001324 14514065750 0020667 0 ustar 00root root 0000000 0000000 package gotest
import (
"io"
"github.com/jstemmer/go-junit-report/v2/gtr"
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/reader"
)
// NewJSONParser returns a new Go test json output parser.
func NewJSONParser(options ...Option) *JSONParser {
return &JSONParser{gp: NewParser(options...)}
}
// JSONParser is a `go test -json` output Parser.
type JSONParser struct {
gp *Parser
}
// Parse parses Go test json output from the given io.Reader r and returns
// gtr.Report.
func (p *JSONParser) Parse(r io.Reader) (gtr.Report, error) {
return p.gp.parse(reader.NewJSONEventReader(r))
}
// Events returns the events created by the parser.
func (p *JSONParser) Events() []Event {
return p.gp.Events()
}
go-junit-report-2.1.0/parser/gotest/report_builder.go 0000664 0000000 0000000 00000035412 14514065750 0022744 0 ustar 00root root 0000000 0000000 package gotest
import (
"fmt"
"sort"
"strings"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/collector"
)
const (
globalID = 0
)
// reportBuilder helps build a test Report from a collection of events.
//
// The reportBuilder delegates to the packageBuilder for creating packages from
// basic test events, but keeps track of build errors itself. The reportBuilder
// is also responsible for generating unique test id's.
//
// Test output is collected by the output collector, which also keeps track of
// the currently active test so output is automatically associated with the
// correct test.
type reportBuilder struct {
packageBuilders map[string]*packageBuilder
buildErrors map[int]gtr.Error
nextID int // next free unused id
output *collector.Output // output collected for each id
packages []gtr.Package // completed packages
// options
packageName string
subtestMode SubtestMode
timestampFunc func() time.Time
}
// newReportBuilder creates a new reportBuilder.
func newReportBuilder() *reportBuilder {
return &reportBuilder{
packageBuilders: make(map[string]*packageBuilder),
buildErrors: make(map[int]gtr.Error),
nextID: 1,
output: collector.New(),
timestampFunc: time.Now,
}
}
// getPackageBuilder returns the packageBuilder for the given packageName. If
// no packageBuilder exists for the given package, a new one is created.
func (b *reportBuilder) getPackageBuilder(packageName string) *packageBuilder {
pb, ok := b.packageBuilders[packageName]
if !ok {
output := b.output
if packageName != "" {
output = collector.New()
}
pb = newPackageBuilder(b.generateID, output)
b.packageBuilders[packageName] = pb
}
return pb
}
// ProcessEvent takes a test event and adds it to the report.
func (b *reportBuilder) ProcessEvent(ev Event) {
switch ev.Type {
case "run_test":
b.getPackageBuilder(ev.Package).CreateTest(ev.Name)
case "pause_test":
b.getPackageBuilder(ev.Package).PauseTest(ev.Name)
case "cont_test":
b.getPackageBuilder(ev.Package).ContinueTest(ev.Name)
case "end_test":
b.getPackageBuilder(ev.Package).EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent)
case "run_benchmark":
b.getPackageBuilder(ev.Package).CreateTest(ev.Name)
case "benchmark":
b.getPackageBuilder(ev.Package).BenchmarkResult(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp)
case "end_benchmark":
b.getPackageBuilder(ev.Package).EndTest(ev.Name, ev.Result, 0, 0)
case "status":
b.getPackageBuilder(ev.Package).End()
case "summary":
// The summary marks the end of a package. We can now create the actual
// package from all the events we've processed so far for this package.
b.packages = append(b.packages, b.CreatePackage(ev.Package, ev.Name, ev.Result, ev.Duration, ev.Data))
case "coverage":
b.getPackageBuilder(ev.Package).Coverage(ev.CovPct, ev.CovPackages)
case "build_output":
b.CreateBuildError(ev.Name)
case "output":
if ev.Package != "" {
b.getPackageBuilder(ev.Package).Output(ev.Data)
} else {
b.output.Append(ev.Data)
}
default:
// This shouldn't happen, but just in case print a warning and ignore
// this event.
fmt.Printf("reportBuilder: unhandled event type: %v\n", ev.Type)
}
}
// newID returns a new unique id.
func (b *reportBuilder) generateID() int {
id := b.nextID
b.nextID++
return id
}
// Build returns the new Report containing all the tests, build errors and
// their output created from the processed events.
func (b *reportBuilder) Build() gtr.Report {
// Create packages for any leftover package builders.
for name, pb := range b.packageBuilders {
if pb.IsEmpty() {
continue
}
b.packages = append(b.packages, b.CreatePackage(name, b.packageName, "", 0, ""))
}
// Create packages for any leftover build errors.
for _, buildErr := range b.buildErrors {
b.packages = append(b.packages, b.CreatePackage("", buildErr.Name, "", 0, ""))
}
return gtr.Report{Packages: b.packages}
}
// CreateBuildError creates a new build error and marks it as active.
func (b *reportBuilder) CreateBuildError(packageName string) {
id := b.generateID()
b.output.SetActiveID(id)
b.buildErrors[id] = gtr.Error{ID: id, Name: packageName}
}
// CreatePackage returns a new package containing all the build errors, output,
// tests and benchmarks created so far. The optional packageName is used to
// find the correct reportBuilder. The newPackageName is the actual package
// name that will be given to the returned package, which should be used in
// case the packageName was unknown until this point.
func (b *reportBuilder) CreatePackage(packageName, newPackageName, result string, duration time.Duration, data string) gtr.Package {
pkg := gtr.Package{
Name: newPackageName,
Duration: duration,
Timestamp: b.timestampFunc(),
}
// First check if this package contained a build error. If that's the case,
// we won't find any tests in this package.
for id, buildErr := range b.buildErrors {
if buildErr.Name == newPackageName || strings.TrimSuffix(buildErr.Name, "_test") == newPackageName {
pkg.BuildError = buildErr
pkg.BuildError.ID = id
pkg.BuildError.Duration = duration
pkg.BuildError.Cause = data
pkg.BuildError.Output = b.output.Get(id)
delete(b.buildErrors, id)
b.output.SetActiveID(0)
return pkg
}
}
// Get the packageBuilder for this package and make sure it's deleted, so
// future events for this package will use a new packageBuilder.
pb := b.getPackageBuilder(packageName)
delete(b.packageBuilders, packageName)
pb.output.SetActiveID(0)
// If the packageBuilder is empty, we never received any events for this
// package so there's no need to continue.
if pb.IsEmpty() {
// However, we should at least report an error if the result says we
// failed.
if parseResult(result) == gtr.Fail {
pkg.RunError = gtr.Error{
Name: newPackageName,
}
}
return pkg
}
// If we've collected output, but there were no tests, then this package
// had a runtime error or it simply didn't have any tests.
if pb.output.Contains(globalID) && len(pb.tests) == 0 {
if parseResult(result) == gtr.Fail {
pkg.RunError = gtr.Error{
Name: newPackageName,
Output: pb.output.Get(globalID),
}
} else {
pkg.Output = pb.output.Get(globalID)
}
pb.output.Clear(globalID)
return pkg
}
// If the summary result says we failed, but there were no failing tests
// then something else must have failed.
if parseResult(result) == gtr.Fail && len(pb.tests) > 0 && !pb.containsFailures() {
pkg.RunError = gtr.Error{
Name: newPackageName,
Output: pb.output.Get(globalID),
}
pb.output.Clear(globalID)
}
// Collect tests for this package
var tests []gtr.Test
for id, t := range pb.tests {
if pb.isParent(id) {
if b.subtestMode == IgnoreParentResults {
t.Result = gtr.Pass
} else if b.subtestMode == ExcludeParents {
pb.output.Merge(id, globalID)
continue
}
}
t.Output = pb.output.Get(id)
tests = append(tests, t)
}
tests = groupBenchmarksByName(tests, b.output)
// Sort packages by id to ensure we maintain insertion order.
sort.Slice(tests, func(i, j int) bool {
return tests[i].ID < tests[j].ID
})
pkg.Tests = groupBenchmarksByName(tests, pb.output)
pkg.Coverage = pb.coverage
pkg.Output = pb.output.Get(globalID)
pb.output.Clear(globalID)
return pkg
}
// parseResult returns a gtr.Result for the given result string r.
func parseResult(r string) gtr.Result {
switch r {
case "PASS":
return gtr.Pass
case "FAIL":
return gtr.Fail
case "SKIP":
return gtr.Skip
case "BENCH":
return gtr.Pass
default:
return gtr.Unknown
}
}
// groupBenchmarksByName groups tests with the Benchmark prefix if they have
// the same name and combines their output.
func groupBenchmarksByName(tests []gtr.Test, output *collector.Output) []gtr.Test {
if len(tests) == 0 {
return nil
}
var grouped []gtr.Test
byName := make(map[string][]gtr.Test)
for _, test := range tests {
if !strings.HasPrefix(test.Name, "Benchmark") {
// If this test is not a benchmark, we won't group it by name but
// just add it to the final result.
grouped = append(grouped, test)
continue
}
if _, ok := byName[test.Name]; !ok {
grouped = append(grouped, gtr.NewTest(test.ID, test.Name))
}
byName[test.Name] = append(byName[test.Name], test)
}
for i, group := range grouped {
if !strings.HasPrefix(group.Name, "Benchmark") {
continue
}
var (
ids []int
total Benchmark
count int
)
for _, test := range byName[group.Name] {
ids = append(ids, test.ID)
if test.Result != gtr.Pass {
continue
}
if bench, ok := GetBenchmarkData(test); ok {
total.Iterations += bench.Iterations
total.NsPerOp += bench.NsPerOp
total.MBPerSec += bench.MBPerSec
total.BytesPerOp += bench.BytesPerOp
total.AllocsPerOp += bench.AllocsPerOp
count++
}
}
group.Duration = combinedDuration(byName[group.Name])
group.Result = groupResults(byName[group.Name])
group.Output = output.GetAll(ids...)
if count > 0 {
total.Iterations /= int64(count)
total.NsPerOp /= float64(count)
total.MBPerSec /= float64(count)
total.BytesPerOp /= int64(count)
total.AllocsPerOp /= int64(count)
SetBenchmarkData(&group, total)
}
grouped[i] = group
}
return grouped
}
// combinedDuration returns the sum of the durations of the given tests.
func combinedDuration(tests []gtr.Test) time.Duration {
var total time.Duration
for _, test := range tests {
total += test.Duration
}
return total
}
// groupResults returns the result we should use for a collection of tests.
func groupResults(tests []gtr.Test) gtr.Result {
var result gtr.Result
for _, test := range tests {
if test.Result == gtr.Fail {
return gtr.Fail
}
if result != gtr.Pass {
result = test.Result
}
}
return result
}
// packageBuilder helps build a gtr.Package from a collection of test events.
type packageBuilder struct {
generateID func() int
output *collector.Output
tests map[int]gtr.Test
parentIDs map[int]struct{} // set of test id's that contain subtests
coverage float64 // coverage percentage
}
// newPackageBuilder creates a new packageBuilder. New tests will be assigned
// an ID returned by the generateID function. The activeIDSetter is called to
// set or reset the active test id.
func newPackageBuilder(generateID func() int, output *collector.Output) *packageBuilder {
return &packageBuilder{
generateID: generateID,
output: output,
tests: make(map[int]gtr.Test),
parentIDs: make(map[int]struct{}),
}
}
// IsEmpty returns true if this package builder does not have any tests and has
// not collected any global output.
func (b packageBuilder) IsEmpty() bool {
return len(b.tests) == 0 && !b.output.Contains(0)
}
// CreateTest adds a test with the given name to the package, marks it as
// active and returns its generated id.
func (b *packageBuilder) CreateTest(name string) int {
if parentID, ok := b.findTestParentID(name); ok {
b.parentIDs[parentID] = struct{}{}
}
id := b.generateID()
b.output.SetActiveID(id)
b.tests[id] = gtr.NewTest(id, name)
return id
}
// PauseTest marks the test with the given name no longer active. Any results
// or output added to the package after calling PauseTest will no longer be
// associated with this test.
func (b *packageBuilder) PauseTest(name string) {
b.output.SetActiveID(0)
}
// ContinueTest finds the test with the given name and marks it as active. If
// more than one test exist with this name, the most recently created test will
// be used.
func (b *packageBuilder) ContinueTest(name string) {
id, _ := b.findTest(name)
b.output.SetActiveID(id)
}
// EndTest finds the test with the given name, sets the result, duration and
// level. If more than one test exists with this name, the most recently
// created test will be used. If no test exists with this name, a new test is
// created. The test is then marked as no longer active.
func (b *packageBuilder) EndTest(name, result string, duration time.Duration, level int) {
id, ok := b.findTest(name)
if !ok {
// test did not exist, create one
// TODO: Likely reason is that the user ran go test without the -v
// flag, should we report this somewhere?
id = b.CreateTest(name)
}
t := b.tests[id]
t.Result = parseResult(result)
t.Duration = duration
t.Level = level
b.tests[id] = t
b.output.SetActiveID(0)
}
// End resets the active test.
func (b *packageBuilder) End() {
b.output.SetActiveID(0)
}
// BenchmarkResult updates an existing or adds a new test with the given
// results and marks it as active. If an existing test with this name exists
// but without result, then that one is updated. Otherwise a new one is added
// to the report.
func (b *packageBuilder) BenchmarkResult(name string, iterations int64, nsPerOp, mbPerSec float64, bytesPerOp, allocsPerOp int64) {
id, ok := b.findTest(name)
if !ok || b.tests[id].Result != gtr.Unknown {
id = b.CreateTest(name)
}
b.output.SetActiveID(id)
benchmark := Benchmark{iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp}
test := gtr.NewTest(id, name)
test.Result = gtr.Pass
test.Duration = benchmark.ApproximateDuration()
SetBenchmarkData(&test, benchmark)
b.tests[id] = test
}
// Coverage sets the code coverage percentage.
func (b *packageBuilder) Coverage(pct float64, packages []string) {
b.coverage = pct
}
// Output appends data to the output of this package.
func (b *packageBuilder) Output(data string) {
b.output.Append(data)
}
// findTest returns the id of the most recently created test with the given
// name if it exists.
func (b *packageBuilder) findTest(name string) (int, bool) {
var maxid int
for id, test := range b.tests {
if maxid < id && test.Name == name {
maxid = id
}
}
return maxid, maxid > 0
}
// findTestParentID searches the existing tests in this package for a parent of
// the test with the given name, and returns its id if one is found.
func (b *packageBuilder) findTestParentID(name string) (int, bool) {
parent := dropLastSegment(name)
for parent != "" {
if id, ok := b.findTest(parent); ok {
return id, true
}
parent = dropLastSegment(parent)
}
return 0, false
}
// isParent returns true if the test with the given id has sub tests.
func (b *packageBuilder) isParent(id int) bool {
_, ok := b.parentIDs[id]
return ok
}
// dropLastSegment strips the last `/` and everything following it from the
// given name. If no `/` was found, the empty string is returned.
func dropLastSegment(name string) string {
if idx := strings.LastIndexByte(name, '/'); idx >= 0 {
return name[:idx]
}
return ""
}
// containsFailures return true if this package contains at least one failing
// test or a test with an unknown result.
func (b *packageBuilder) containsFailures() bool {
for _, test := range b.tests {
if test.Result == gtr.Fail || test.Result == gtr.Unknown {
return true
}
}
return false
}
go-junit-report-2.1.0/parser/gotest/report_builder_test.go 0000664 0000000 0000000 00000031361 14514065750 0024002 0 ustar 00root root 0000000 0000000 package gotest
import (
"fmt"
"testing"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/collector"
"github.com/google/go-cmp/cmp"
)
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: "run_benchmark", Name: "BenchmarkOne"},
{Type: "benchmark", Name: "BenchmarkOne", NsPerOp: 100},
{Type: "end_benchmark", Name: "BenchmarkOne", Result: "BENCH"},
{Type: "run_benchmark", Name: "BenchmarkTwo"},
{Type: "benchmark", Name: "BenchmarkTwo"},
{Type: "end_benchmark", Name: "BenchmarkTwo", Result: "FAIL"},
{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]"},
}
want := gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 1,
Name: "TestOne",
Duration: 1 * time.Millisecond,
Result: gtr.Pass,
Output: []string{
"\tHello", // TODO: strip tabs?
},
Data: map[string]interface{}{},
},
{
ID: 2,
Name: "TestSkip",
Duration: 1 * time.Millisecond,
Result: gtr.Skip,
Data: map[string]interface{}{},
},
},
},
{
Name: "package/name2",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 3,
Name: "TestOne",
Duration: 1 * time.Millisecond,
Result: gtr.Fail,
Output: []string{
"\tfile_test.go:10: error",
},
Data: map[string]interface{}{},
},
},
},
{
Name: "package/name3",
Duration: 1234 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 4,
Name: "BenchmarkOne",
Result: gtr.Pass,
Data: map[string]interface{}{key: Benchmark{NsPerOp: 100}},
},
{
ID: 5,
Name: "BenchmarkTwo",
Result: gtr.Fail,
Data: map[string]interface{}{},
},
},
Output: []string{"goarch: amd64"},
},
{
Name: "package/failing1",
Timestamp: testTimestamp,
BuildError: gtr.Error{
ID: 6,
Name: "package/failing1",
Cause: "[build failed]",
Output: []string{"error message"},
},
},
},
}
rb := newReportBuilder()
rb.timestampFunc = testTimestampFunc
for _, ev := range events {
rb.ProcessEvent(ev)
}
got := rb.Build()
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Incorrect report created, diff (-want, +got):\n%v", diff)
}
}
func TestBuildReportMultiplePackages(t *testing.T) {
events := []Event{
{Package: "package/name1", Type: "run_test", Name: "TestOne"},
{Package: "package/name2", Type: "run_test", Name: "TestOne"},
{Package: "package/name1", Type: "output", Data: "\tHello"},
{Package: "package/name1", Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 1 * time.Millisecond},
{Package: "package/name2", Type: "output", Data: "\tfile_test.go:10: error"},
{Package: "package/name2", Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 1 * time.Millisecond},
{Package: "package/name2", Type: "status", Result: "FAIL"},
{Package: "package/name2", Type: "summary", Result: "FAIL", Name: "package/name2", Duration: 1 * time.Millisecond},
{Package: "package/name1", Type: "status", Result: "PASS"},
{Package: "package/name1", Type: "summary", Result: "ok", Name: "package/name1", Duration: 1 * time.Millisecond},
}
want := gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name2",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 2,
Name: "TestOne",
Duration: 1 * time.Millisecond,
Result: gtr.Fail,
Output: []string{"\tfile_test.go:10: error"},
Data: make(map[string]interface{}),
},
},
},
{
Name: "package/name1",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 1,
Name: "TestOne",
Duration: 1 * time.Millisecond,
Result: gtr.Pass,
Output: []string{"\tHello"},
Data: make(map[string]interface{}),
},
},
},
},
}
rb := newReportBuilder()
rb.timestampFunc = testTimestampFunc
for _, ev := range events {
rb.ProcessEvent(ev)
}
got := rb.Build()
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Incorrect report created, diff (-want, +got):\n%v", diff)
}
}
func TestSubtestModes(t *testing.T) {
events := []Event{
{Type: "run_test", Name: "TestParent"},
{Type: "output", Data: "TestParent before"},
{Type: "run_test", Name: "TestParent/Subtest#1"},
{Type: "output", Data: "Subtest#1 output"},
{Type: "run_test", Name: "TestParent/Subtest#2"},
{Type: "output", Data: "Subtest#2 output"},
{Type: "cont_test", Name: "TestParent"},
{Type: "output", Data: "TestParent after"},
{Type: "end_test", Name: "TestParent", Result: "PASS", Duration: 1 * time.Millisecond},
{Type: "end_test", Name: "TestParent/Subtest#1", Result: "FAIL", Duration: 2 * time.Millisecond},
{Type: "end_test", Name: "TestParent/Subtest#2", Result: "PASS", Duration: 3 * time.Millisecond},
{Type: "output", Data: "output"},
{Type: "summary", Result: "FAIL", Name: "package/name", Duration: 1 * time.Millisecond},
}
tests := []struct {
name string
mode SubtestMode
want gtr.Report
}{
{
name: "ignore subtest parent results",
mode: IgnoreParentResults,
want: gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 1,
Name: "TestParent",
Duration: 1 * time.Millisecond,
Result: gtr.Pass,
Output: []string{"TestParent before", "TestParent after"},
Data: map[string]interface{}{},
},
{
ID: 2,
Name: "TestParent/Subtest#1",
Duration: 2 * time.Millisecond,
Result: gtr.Fail,
Output: []string{"Subtest#1 output"},
Data: map[string]interface{}{},
},
{
ID: 3,
Name: "TestParent/Subtest#2",
Duration: 3 * time.Millisecond,
Result: gtr.Pass,
Output: []string{"Subtest#2 output"},
Data: map[string]interface{}{},
},
},
Output: []string{"output"},
},
},
},
},
{
name: "exclude subtest parents",
mode: ExcludeParents,
want: gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
Tests: []gtr.Test{
{
ID: 2,
Name: "TestParent/Subtest#1",
Duration: 2 * time.Millisecond,
Result: gtr.Fail,
Output: []string{"Subtest#1 output"},
Data: map[string]interface{}{},
},
{
ID: 3,
Name: "TestParent/Subtest#2",
Duration: 3 * time.Millisecond,
Result: gtr.Pass,
Output: []string{"Subtest#2 output"},
Data: map[string]interface{}{},
},
},
Output: []string{"TestParent before", "TestParent after", "output"},
},
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
rb := newReportBuilder()
rb.timestampFunc = testTimestampFunc
rb.subtestMode = test.mode
for _, ev := range events {
rb.ProcessEvent(ev)
}
got := rb.Build()
if diff := cmp.Diff(test.want, got); diff != "" {
t.Errorf("Invalid report created from events, diff (-want, +got):\n%v", diff)
}
})
}
}
func TestGroupBenchmarksByName(t *testing.T) {
output := collector.New()
for i := 1; i <= 4; i++ {
output.AppendToID(i, fmt.Sprintf("output-%d", i))
}
tests := []struct {
name string
in []gtr.Test
want []gtr.Test
}{
{"nil", nil, nil},
{
"one failing benchmark",
[]gtr.Test{{ID: 1, Name: "BenchmarkFailed", Result: gtr.Fail, Data: map[string]interface{}{}}},
[]gtr.Test{{ID: 1, Name: "BenchmarkFailed", Result: gtr.Fail, Output: []string{"output-1"}, Data: map[string]interface{}{}}},
},
{
"four passing benchmarks",
[]gtr.Test{
{ID: 1, Name: "BenchmarkOne", Result: gtr.Pass, Data: map[string]interface{}{key: Benchmark{NsPerOp: 10, MBPerSec: 400, BytesPerOp: 1, AllocsPerOp: 2}}},
{ID: 2, Name: "BenchmarkOne", Result: gtr.Pass, Data: map[string]interface{}{key: Benchmark{NsPerOp: 20, MBPerSec: 300, BytesPerOp: 1, AllocsPerOp: 4}}},
{ID: 3, Name: "BenchmarkOne", Result: gtr.Pass, Data: map[string]interface{}{key: Benchmark{NsPerOp: 30, MBPerSec: 200, BytesPerOp: 1, AllocsPerOp: 8}}},
{ID: 4, Name: "BenchmarkOne", Result: gtr.Pass, Data: map[string]interface{}{key: Benchmark{NsPerOp: 40, MBPerSec: 100, BytesPerOp: 5, AllocsPerOp: 2}}},
},
[]gtr.Test{
{ID: 1, Name: "BenchmarkOne", Result: gtr.Pass, Output: []string{"output-1", "output-2", "output-3", "output-4"}, Data: map[string]interface{}{key: Benchmark{NsPerOp: 25, MBPerSec: 250, BytesPerOp: 2, AllocsPerOp: 4}}},
},
},
{
"four mixed result benchmarks",
[]gtr.Test{
{ID: 1, Name: "BenchmarkMixed", Result: gtr.Unknown},
{ID: 2, Name: "BenchmarkMixed", Result: gtr.Pass, Data: map[string]interface{}{key: Benchmark{NsPerOp: 10, MBPerSec: 400, BytesPerOp: 1, AllocsPerOp: 2}}},
{ID: 3, Name: "BenchmarkMixed", Result: gtr.Pass, Data: map[string]interface{}{key: Benchmark{NsPerOp: 40, MBPerSec: 100, BytesPerOp: 3, AllocsPerOp: 4}}},
{ID: 4, Name: "BenchmarkMixed", Result: gtr.Fail},
},
[]gtr.Test{
{ID: 1, Name: "BenchmarkMixed", Result: gtr.Fail, Output: []string{"output-1", "output-2", "output-3", "output-4"}, Data: map[string]interface{}{key: Benchmark{NsPerOp: 25, MBPerSec: 250, BytesPerOp: 2, AllocsPerOp: 3}}},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := groupBenchmarksByName(test.in, output)
if diff := cmp.Diff(test.want, got); diff != "" {
t.Errorf("groupBenchmarksByName result incorrect, diff (-want, +got):\n%s\n", diff)
}
})
}
}
func TestReportSpecialCases(t *testing.T) {
tests := []struct {
name string
events []Event
want gtr.Report
}{
{
"failed-summary-only",
[]Event{{Type: "summary", Result: "FAIL", Name: "package/name", Duration: 1 * time.Millisecond}},
gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Duration: 1 * time.Millisecond,
Timestamp: testTimestamp,
RunError: gtr.Error{
Name: "package/name",
},
},
},
},
},
{
"leftover-builderror",
[]Event{
{Type: "build_output", Name: "package/name"},
{Type: "output", Data: "error message"},
},
gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Timestamp: testTimestamp,
BuildError: gtr.Error{
ID: 1,
Name: "package/name",
Output: []string{"error message"},
},
},
},
},
},
{
"build error in package with _test suffix",
[]Event{
{Type: "build_output", Name: "package/name_test"},
{Type: "summary", Name: "package/name", Result: "FAIL", Data: "[build failed]"},
},
gtr.Report{
Packages: []gtr.Package{
{
Name: "package/name",
Timestamp: testTimestamp,
BuildError: gtr.Error{
ID: 1,
Name: "package/name_test",
Cause: "[build failed]",
},
},
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
rb := newReportBuilder()
rb.timestampFunc = testTimestampFunc
for _, ev := range test.events {
rb.ProcessEvent(ev)
}
got := rb.Build()
if diff := cmp.Diff(test.want, got); diff != "" {
t.Errorf("Incorrect report created, diff (-want, +got):\n%v\n", diff)
}
})
}
}
go-junit-report-2.1.0/testdata/ 0000775 0000000 0000000 00000000000 14514065750 0016377 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/001-pass-fail-skip.txt 0000664 0000000 0000000 00000001077 14514065750 0022266 0 ustar 00root root 0000000 0000000 === RUN TestPass
--- PASS: TestPass (0.06s)
=== RUN TestPassLog
pass_test.go:9: log line
pass_test.go:10: log
multi
line
--- PASS: TestPassLog (0.10s)
PASS
ok package/pass 0.160s
=== RUN TestOne
fail_test.go:6: Error message
fail_test.go:7: Longer
error
message.
--- FAIL: TestOne (0.151s)
FAIL
FAIL package/fail 0.151s
=== RUN TestSkip
skip_test.go:6: skip message
--- SKIP: TestSkip (0.02s)
=== RUN TestSkipNow
skip_test.go:10: log message
--- SKIP: TestSkipNow (0.13s)
PASS
ok package/skip 0.150s
FAIL
go-junit-report-2.1.0/testdata/001-report.xml 0000664 0000000 0000000 00000003212 14514065750 0020730 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/005-no-xml-header.txt 0000664 0000000 0000000 00000000321 14514065750 0022076 0 ustar 00root root 0000000 0000000 === RUN TestPass
--- PASS: TestPass (0.06s)
=== RUN TestPassLog
pass_test.go:9: log line
pass_test.go:10: log
multi
line
--- PASS: TestPassLog (0.10s)
PASS
ok package/pass 0.160s
go-junit-report-2.1.0/testdata/005-report.xml 0000664 0000000 0000000 00000001060 14514065750 0020733 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/007-compiled_test.txt 0000664 0000000 0000000 00000000130 14514065750 0022271 0 ustar 00root root 0000000 0000000 === RUN TestOne
--- PASS: TestOne (0.06s)
=== RUN TestTwo
--- PASS: TestTwo (0.10s)
PASS go-junit-report-2.1.0/testdata/007-report.xml 0000664 0000000 0000000 00000000726 14514065750 0020745 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/008-parallel.txt 0000664 0000000 0000000 00000000747 14514065750 0021251 0 ustar 00root root 0000000 0000000 === RUN TestP1
=== PAUSE TestP1
=== RUN TestP2
=== PAUSE TestP2
=== RUN TestP3
=== PAUSE TestP3
=== CONT TestP1
pkg_test.go:10: t.Log(P1)
=== CONT TestP3
pkg_test.go:24: t.Log(P3)
=== CONT TestP2
pkg_test.go:17: t.Log(P2)
pkg_test.go:19: P2 error
--- FAIL: TestP2 (0.05s)
=== CONT TestP3
pkg_test.go:26: P3 error
--- FAIL: TestP3 (0.08s)
=== CONT TestP1
pkg_test.go:12: P1 error
--- FAIL: TestP1 (0.10s)
FAIL
exit status 1
FAIL package/parallel 0.102s
go-junit-report-2.1.0/testdata/008-report.xml 0000664 0000000 0000000 00000001705 14514065750 0020744 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/009-coverage.txt 0000664 0000000 0000000 00000000227 14514065750 0021242 0 ustar 00root root 0000000 0000000 === 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
go-junit-report-2.1.0/testdata/009-report.xml 0000664 0000000 0000000 00000001030 14514065750 0020734 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/010-multipkg-coverage.txt 0000664 0000000 0000000 00000000473 14514065750 0023067 0 ustar 00root root 0000000 0000000 === 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
go-junit-report-2.1.0/testdata/010-report.xml 0000664 0000000 0000000 00000001631 14514065750 0020733 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/011-go_1_5.txt 0000664 0000000 0000000 00000000166 14514065750 0020513 0 ustar 00root root 0000000 0000000 === RUN TestOne
--- PASS: TestOne (0.02s)
=== RUN TestTwo
--- PASS: TestTwo (0.03s)
PASS
ok package/name 0.050s
go-junit-report-2.1.0/testdata/011-report.xml 0000664 0000000 0000000 00000000726 14514065750 0020740 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/012-report.xml 0000664 0000000 0000000 00000003776 14514065750 0020751 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/012-subtests.txt 0000664 0000000 0000000 00000002367 14514065750 0021324 0 ustar 00root root 0000000 0000000 === RUN TestSubtests
=== RUN TestSubtests/Subtest
subtests_test.go:7: ok
=== RUN TestSubtests/Subtest#01
subtests_test.go:10: error message
=== RUN TestSubtests/Subtest#02
subtests_test.go:13: skip message
--- FAIL: TestSubtests (0.00s)
--- PASS: TestSubtests/Subtest (0.00s)
--- FAIL: TestSubtests/Subtest#01 (0.00s)
--- SKIP: TestSubtests/Subtest#02 (0.00s)
=== RUN TestNestedSubtests
=== RUN TestNestedSubtests/a#1
=== RUN TestNestedSubtests/a#1/b#1
=== RUN TestNestedSubtests/a#1/b#1/c#1
--- PASS: TestNestedSubtests (0.00s)
--- PASS: TestNestedSubtests/a#1 (0.00s)
--- PASS: TestNestedSubtests/a#1/b#1 (0.00s)
--- PASS: TestNestedSubtests/a#1/b#1/c#1 (0.00s)
=== RUN TestFailingSubtestWithNestedSubtest
=== RUN TestFailingSubtestWithNestedSubtest/Subtest
=== RUN TestFailingSubtestWithNestedSubtest/Subtest/Subsubtest
subtests_test.go:29: ok
=== CONT TestFailingSubtestWithNestedSubtest/Subtest
subtests_test.go:31: Subtest error message
--- FAIL: TestFailingSubtestWithNestedSubtest (0.00s)
--- FAIL: TestFailingSubtestWithNestedSubtest/Subtest (0.00s)
--- PASS: TestFailingSubtestWithNestedSubtest/Subtest/Subsubtest (0.00s)
FAIL
exit status 1
FAIL package/subtests 0.001s
go-junit-report-2.1.0/testdata/013-report.xml 0000664 0000000 0000000 00000004246 14514065750 0020743 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/013-syntax-error.txt 0000664 0000000 0000000 00000001213 14514065750 0022113 0 ustar 00root root 0000000 0000000 # package/name/failing1
failing1/failing_test.go:15: undefined: x
# package/name/failing2
failing2/another_failing_test.go:20: undefined: y
# package/name/setupfailing1
setupfailing1/failing_test.go:4: cannot find package "other/package" in any of:
/path/vendor (vendor tree)
/path/go/root (from $GOROOT)
/path/go/path (from $GOPATH)
=== RUN TestA
--- PASS: TestA (0.10 seconds)
PASS
ok package/name/passing1 0.100s
=== RUN TestB
--- PASS: TestB (0.10 seconds)
PASS
ok package/name/passing2 0.100s
FAIL package/name/failing1 [build failed]
FAIL package/name/failing2 [build failed]
FAIL package/name/setupfailing1 [setup failed]
go-junit-report-2.1.0/testdata/014-panic.txt 0000664 0000000 0000000 00000000153 14514065750 0020533 0 ustar 00root root 0000000 0000000 panic: init
stacktrace
FAIL package/panic 0.003s
panic: init
stacktrace
FAIL package/panic2 0.003s
go-junit-report-2.1.0/testdata/014-report.xml 0000664 0000000 0000000 00000001567 14514065750 0020747 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/015-empty.txt 0000664 0000000 0000000 00000000101 14514065750 0020571 0 ustar 00root root 0000000 0000000 testing: warning: no tests to run
PASS
ok package/empty 0.001s
go-junit-report-2.1.0/testdata/015-report.xml 0000664 0000000 0000000 00000000574 14514065750 0020745 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/016-repeated-names.txt 0000664 0000000 0000000 00000000304 14514065750 0022333 0 ustar 00root root 0000000 0000000 === RUN TestRepeat
--- PASS: TestRepeat (0.00s)
=== RUN TestRepeat
--- PASS: TestRepeat (0.00s)
=== RUN TestRepeat
--- PASS: TestRepeat (0.00s)
PASS
ok package/repeated-names 0.001s
go-junit-report-2.1.0/testdata/016-report.xml 0000664 0000000 0000000 00000001124 14514065750 0020736 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/017-race.txt 0000664 0000000 0000000 00000003025 14514065750 0020357 0 ustar 00root root 0000000 0000000 === RUN TestRace
race_test.go:13: x = 3
==================
WARNING: DATA RACE
Write at 0x00c000138168 by goroutine 8:
package/race.TestRace.func1()
/src/github.com/jstemmer/go-junit-report/testdata/src/race/race_test.go:9 +0x39
Previous write at 0x00c000138168 by goroutine 7:
package/race.TestRace()
/src/github.com/jstemmer/go-junit-report/testdata/src/race/race_test.go:12 +0x105
testing.tRunner()
/go-src/go1.18/src/testing/testing.go:1439 +0x213
testing.(*T).Run.func1()
/go-src/go1.18/src/testing/testing.go:1486 +0x47
Goroutine 8 (running) created at:
package/race.TestRace()
/src/github.com/jstemmer/go-junit-report/testdata/src/race/race_test.go:8 +0xfb
testing.tRunner()
/go-src/go1.18/src/testing/testing.go:1439 +0x213
testing.(*T).Run.func1()
/go-src/go1.18/src/testing/testing.go:1486 +0x47
Goroutine 7 (running) created at:
testing.(*T).Run()
/go-src/go1.18/src/testing/testing.go:1486 +0x724
testing.runTests.func1()
/go-src/go1.18/src/testing/testing.go:1839 +0x99
testing.tRunner()
/go-src/go1.18/src/testing/testing.go:1439 +0x213
testing.runTests()
/go-src/go1.18/src/testing/testing.go:1837 +0x7e4
testing.(*M).Run()
/go-src/go1.18/src/testing/testing.go:1719 +0xa71
main.main()
_testmain.go:47 +0x2e4
==================
testing.go:1312: race detected during execution of test
--- FAIL: TestRace (0.00s)
=== CONT
testing.go:1312: race detected during execution of test
FAIL
exit status 1
FAIL package/race 0.005s
go-junit-report-2.1.0/testdata/017-report.xml 0000664 0000000 0000000 00000003662 14514065750 0020750 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/018-coverpkg.txt 0000664 0000000 0000000 00000000617 14514065750 0021272 0 ustar 00root root 0000000 0000000 === RUN TestA
--- PASS: TestA (0.10 seconds)
=== RUN TestB
--- PASS: TestB (0.30 seconds)
PASS
coverage: 10% of statements in fmt, encoding/xml
ok package1/foo 0.400s coverage: 10.0% of statements in fmt, encoding/xml
=== RUN TestC
--- PASS: TestC (4.20 seconds)
PASS
coverage: 99.8% of statements in fmt, encoding/xml
ok package2/bar 4.200s coverage: 99.8% of statements in fmt, encoding/xml
go-junit-report-2.1.0/testdata/018-report.xml 0000664 0000000 0000000 00000001631 14514065750 0020743 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/019-pass.txt 0000664 0000000 0000000 00000000210 14514065750 0020406 0 ustar 00root root 0000000 0000000 === RUN TestZ
some inline text--- PASS: TestZ (0.06 seconds)
=== RUN TestA
--- PASS: TestA (0.10 seconds)
PASS
ok package/name 0.160s
go-junit-report-2.1.0/testdata/019-report.xml 0000664 0000000 0000000 00000001016 14514065750 0020741 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/021-cached.txt 0000664 0000000 0000000 00000000113 14514065750 0020642 0 ustar 00root root 0000000 0000000 === RUN TestOne
--- PASS: TestOne (0.00s)
PASS
ok package/one (cached)
go-junit-report-2.1.0/testdata/021-report.xml 0000664 0000000 0000000 00000000607 14514065750 0020737 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/022-bench.txt 0000664 0000000 0000000 00000001037 14514065750 0020521 0 ustar 00root root 0000000 0000000 === RUN TestOne
bench_test.go:9: test log
--- PASS: TestOne (0.00s)
goos: linux
goarch: amd64
pkg: package/bench
BenchmarkOne
bench_test.go:13: benchmark log (1)
bench_test.go:13: benchmark log (100)
bench_test.go:13: benchmark log (10000)
bench_test.go:13: benchmark log (1000000)
bench_test.go:13: benchmark log (100000000)
bench_test.go:13: benchmark log (1000000000)
BenchmarkOne-8 1000000000 0.2642 ns/op
BenchmarkTwo
BenchmarkTwo-8 39560503 33.21 ns/op
PASS
ok package/bench 1.640s
go-junit-report-2.1.0/testdata/022-report.xml 0000664 0000000 0000000 00000002006 14514065750 0020733 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/023-benchmem.txt 0000664 0000000 0000000 00000000335 14514065750 0021221 0 ustar 00root root 0000000 0000000 goos: darwin
goarch: amd64
pkg: code.internal/state
BenchmarkIpsHistoryInsert-8 30000 52568 ns/op 24879 B/op 494 allocs/op
BenchmarkIpsHistoryLookup-8 100000 15208 ns/op 7369 B/op 143 allocs/op
PASS
ok package/one 9.415s
go-junit-report-2.1.0/testdata/023-report.xml 0000664 0000000 0000000 00000001122 14514065750 0020732 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/024-benchtests.txt 0000664 0000000 0000000 00000000334 14514065750 0021605 0 ustar 00root root 0000000 0000000 goos: linux
goarch: amd64
pkg: package/bench
cpu: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
BenchmarkOne-8 1000000000 0.2640 ns/op
BenchmarkTwo-8 39787592 33.10 ns/op
PASS
ok package/bench 1.642s
go-junit-report-2.1.0/testdata/024-report.xml 0000664 0000000 0000000 00000001145 14514065750 0020740 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/025-benchcount.txt 0000664 0000000 0000000 00000001435 14514065750 0021577 0 ustar 00root root 0000000 0000000 BenchmarkNew-8 5000000 350 ns/op 80 B/op 3 allocs/op
BenchmarkNew-8 5000000 357 ns/op 80 B/op 3 allocs/op
BenchmarkNew-8 5000000 354 ns/op 80 B/op 3 allocs/op
BenchmarkNew-8 5000000 358 ns/op 80 B/op 3 allocs/op
BenchmarkNew-8 5000000 345 ns/op 80 B/op 3 allocs/op
BenchmarkFew-8 5000000 100 ns/op 20 B/op 1 allocs/op
BenchmarkFew-8 5000000 105 ns/op 20 B/op 1 allocs/op
BenchmarkFew-8 5000000 102 ns/op 20 B/op 1 allocs/op
BenchmarkFew-8 5000000 102 ns/op 20 B/op 1 allocs/op
BenchmarkFew-8 5000000 102 ns/op 20 B/op 1 allocs/op
PASS
ok pkg/count 14.211s go-junit-report-2.1.0/testdata/025-report.xml 0000664 0000000 0000000 00000000730 14514065750 0020740 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/026-report.xml 0000664 0000000 0000000 00000002447 14514065750 0020750 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/026-testbenchmultiple.txt 0000664 0000000 0000000 00000000772 14514065750 0023206 0 ustar 00root root 0000000 0000000 pkg: mycode/common
BenchmarkParse-8 1000000 1591 ns/op
BenchmarkNewTask-8 3000000 391 ns/op
PASS
ok mycode/common 7.267s
pkg: mycode/benchmarks/channels
BenchmarkFanout/Channel/10-8 500000 4673 ns/op
BenchmarkFanout/Channel/100-8 50000 24965 ns/op
BenchmarkFanout/Channel/1000-8 10000 195672 ns/op
BenchmarkFanout/Channel/10000-8 500 2410200 ns/op
PASS
ok mycode/benchmarks/channels 47.084s go-junit-report-2.1.0/testdata/027-benchdecimal.txt 0000664 0000000 0000000 00000000346 14514065750 0022047 0 ustar 00root root 0000000 0000000 goos: darwin
goarch: amd64
pkg: really/small
BenchmarkItsy-8 30000000 45.7 ns/op
BenchmarkTeeny-8 1000000000 2.12 ns/op
BenchmarkWeeny-8 2000000000 0.26 ns/op
PASS
ok really/small 4.344s
go-junit-report-2.1.0/testdata/027-report.xml 0000664 0000000 0000000 00000001213 14514065750 0020737 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/028-bench-1cpu.txt 0000664 0000000 0000000 00000000135 14514065750 0021373 0 ustar 00root root 0000000 0000000 pkg: single/cpu
BenchmarkRing 20000000 74.2 ns/op
PASS
ok single/cpu 9.467s go-junit-report-2.1.0/testdata/028-report.xml 0000664 0000000 0000000 00000000702 14514065750 0020742 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/029-bench-16cpu.txt 0000664 0000000 0000000 00000000142 14514065750 0021460 0 ustar 00root root 0000000 0000000 pkg: sixteen/cpu
BenchmarkRingaround-16 100000 13571 ns/op
PASS
ok sixteen/cpu 1.522s go-junit-report-2.1.0/testdata/029-report.xml 0000664 0000000 0000000 00000000713 14514065750 0020745 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/030-report.xml 0000664 0000000 0000000 00000007545 14514065750 0020747 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/030-stdout.txt 0000664 0000000 0000000 00000005314 14514065750 0020765 0 ustar 00root root 0000000 0000000 === RUN TestFailWithStdoutAndTestOutput
multi
line
stdout
single-line stdout
stdout_test.go:11: single-line error
stdout_test.go:12: multi
line
error
--- FAIL: TestFailWithStdoutAndTestOutput (0.00s)
=== RUN TestFailWithStdoutAndNoTestOutput
multi
line
stdout
single-line stdout
--- FAIL: TestFailWithStdoutAndNoTestOutput (0.00s)
=== RUN TestFailWithTestOutput
stdout_test.go:22: single-line error
stdout_test.go:23: multi
line
error
--- FAIL: TestFailWithTestOutput (0.00s)
=== RUN TestFailWithNoTestOutput
--- FAIL: TestFailWithNoTestOutput (0.00s)
=== RUN TestPassWithStdoutAndTestOutput
multi
line
stdout
single-line stdout
stdout_test.go:33: single-line info
stdout_test.go:34: multi
line
info
--- PASS: TestPassWithStdoutAndTestOutput (0.00s)
=== RUN TestPassWithStdoutAndNoTestOutput
multi
line
stdout
single-line stdout
--- PASS: TestPassWithStdoutAndNoTestOutput (0.00s)
=== RUN TestPassWithTestOutput
stdout_test.go:43: single-line info
stdout_test.go:44: multi
line
info
--- PASS: TestPassWithTestOutput (0.00s)
=== RUN TestPassWithNoTestOutput
--- PASS: TestPassWithNoTestOutput (0.00s)
=== RUN TestSubtests
=== RUN TestSubtests/TestFailWithStdoutAndTestOutput
multi
line
stdout
single-line stdout
stdout_test.go:11: single-line error
stdout_test.go:12: multi
line
error
=== RUN TestSubtests/TestFailWithStdoutAndNoTestOutput
multi
line
stdout
single-line stdout
=== RUN TestSubtests/TestFailWithTestOutput
stdout_test.go:22: single-line error
stdout_test.go:23: multi
line
error
=== RUN TestSubtests/TestFailWithNoTestOutput
=== RUN TestSubtests/TestPassWithStdoutAndTestOutput
multi
line
stdout
single-line stdout
stdout_test.go:33: single-line info
stdout_test.go:34: multi
line
info
=== RUN TestSubtests/TestPassWithStdoutAndNoTestOutput
multi
line
stdout
single-line stdout
=== RUN TestSubtests/TestPassWithTestOutput
stdout_test.go:43: single-line info
stdout_test.go:44: multi
line
info
=== RUN TestSubtests/TestPassWithNoTestOutput
--- FAIL: TestSubtests (0.00s)
--- FAIL: TestSubtests/TestFailWithStdoutAndTestOutput (0.00s)
--- FAIL: TestSubtests/TestFailWithStdoutAndNoTestOutput (0.00s)
--- FAIL: TestSubtests/TestFailWithTestOutput (0.00s)
--- FAIL: TestSubtests/TestFailWithNoTestOutput (0.00s)
--- PASS: TestSubtests/TestPassWithStdoutAndTestOutput (0.00s)
--- PASS: TestSubtests/TestPassWithStdoutAndNoTestOutput (0.00s)
--- PASS: TestSubtests/TestPassWithTestOutput (0.00s)
--- PASS: TestSubtests/TestPassWithNoTestOutput (0.00s)
FAIL
exit status 1
FAIL package/stdout 0.001s
go-junit-report-2.1.0/testdata/031-report.xml 0000664 0000000 0000000 00000004246 14514065750 0020743 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/031-syntax-error-test-binary.txt 0000664 0000000 0000000 00000001347 14514065750 0024362 0 ustar 00root root 0000000 0000000 # package/name/failing1 [package/name/failing1.test]
failing1/failing_test.go:15: undefined: x
# package/name/failing2 [package/name/failing2.test]
failing2/another_failing_test.go:20: undefined: y
# package/name/setupfailing1 [package/name/setupfailing1.test]
setupfailing1/failing_test.go:4: cannot find package "other/package" in any of:
/path/vendor (vendor tree)
/path/go/root (from $GOROOT)
/path/go/path (from $GOPATH)
=== RUN TestA
--- PASS: TestA (0.10 seconds)
PASS
ok package/name/passing1 0.100s
=== RUN TestB
--- PASS: TestB (0.10 seconds)
PASS
ok package/name/passing2 0.100s
FAIL package/name/failing1 [build failed]
FAIL package/name/failing2 [build failed]
FAIL package/name/setupfailing1 [setup failed]
go-junit-report-2.1.0/testdata/032-failed-summary.txt 0000664 0000000 0000000 00000000161 14514065750 0022357 0 ustar 00root root 0000000 0000000 === RUN TestOne
--- PASS: TestOne (0.00s)
PASS
panic: panic
FAIL github.com/jstemmer/test/failedsummary 0.005s
go-junit-report-2.1.0/testdata/032-report.xml 0000664 0000000 0000000 00000001165 14514065750 0020741 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/033-bench-mb.txt 0000664 0000000 0000000 00000000432 14514065750 0021115 0 ustar 00root root 0000000 0000000 goos: linux
goarch: amd64
pkg: compress/flate
BenchmarkDecode/Digits/Huffman/1e4-8 10000 104427 ns/op 95.76 MB/s 40629 B/op 5 allocs/op
BenchmarkEncode/Digits/Huffman/1e4-8 50000 28334 ns/op 352.93 MB/s
PASS
ok compress/flate 83.202s
go-junit-report-2.1.0/testdata/033-report.xml 0000664 0000000 0000000 00000001150 14514065750 0020734 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/034-notest.txt 0000664 0000000 0000000 00000000241 14514065750 0020755 0 ustar 00root root 0000000 0000000 ? package/name [no test files]
testing: warning: no tests to run
PASS
ok package/name 0.001s [no tests to run]
ok package/name (cached) [no tests to run]
go-junit-report-2.1.0/testdata/034-report.xml 0000664 0000000 0000000 00000001533 14514065750 0020742 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/035-report.xml 0000664 0000000 0000000 00000006014 14514065750 0020742 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/035-whitespace.txt 0000664 0000000 0000000 00000004260 14514065750 0021603 0 ustar 00root root 0000000 0000000 === RUN TestFlat
whitespace_test.go:9: log 1
whitespace_test.go:10: log 2
printf 1
printf 2
--- PASS: TestFlat (0.00s)
=== RUN TestWithSpace
whitespace_test.go:16: no-space
whitespace_test.go:17: one-space
whitespace_test.go:18: two-space
whitespace_test.go:19: four-space
whitespace_test.go:20: eight-space
whitespace_test.go:21: no-space
no-space
one-space
two-space
four-space
eight-space
no-space
--- PASS: TestWithSpace (0.00s)
=== RUN TestWithTab
whitespace_test.go:31: no-tab
whitespace_test.go:32: one-tab
whitespace_test.go:33: two-tab
no-tab
one-tab
two-tab
--- PASS: TestWithTab (0.00s)
=== RUN TestWithNewlinesFlat
whitespace_test.go:40: no-newline
whitespace_test.go:41: one-newline
one-newline
whitespace_test.go:42: two-newlines
two-newlines
two-newlines
no-newline
one-newline
one-newline
two-newlines
two-newlines
two-newlines
--- PASS: TestWithNewlinesFlat (0.00s)
=== RUN TestSubTests
=== RUN TestSubTests/TestFlat
whitespace_test.go:9: log 1
whitespace_test.go:10: log 2
printf 1
printf 2
=== RUN TestSubTests/TestWithSpace
whitespace_test.go:16: no-space
whitespace_test.go:17: one-space
whitespace_test.go:18: two-space
whitespace_test.go:19: four-space
whitespace_test.go:20: eight-space
whitespace_test.go:21: no-space
no-space
one-space
two-space
four-space
eight-space
no-space
=== RUN TestSubTests/TestWithTab
whitespace_test.go:31: no-tab
whitespace_test.go:32: one-tab
whitespace_test.go:33: two-tab
no-tab
one-tab
two-tab
=== RUN TestSubTests/TestWithNewlinesFlat
whitespace_test.go:40: no-newline
whitespace_test.go:41: one-newline
one-newline
whitespace_test.go:42: two-newlines
two-newlines
two-newlines
no-newline
one-newline
one-newline
two-newlines
two-newlines
two-newlines
--- PASS: TestSubTests (0.00s)
--- PASS: TestSubTests/TestFlat (0.00s)
--- PASS: TestSubTests/TestWithSpace (0.00s)
--- PASS: TestSubTests/TestWithTab (0.00s)
--- PASS: TestSubTests/TestWithNewlinesFlat (0.00s)
PASS
ok package/whitespace 0.001s
go-junit-report-2.1.0/testdata/036-benchfail.txt 0000664 0000000 0000000 00000000514 14514065750 0021361 0 ustar 00root root 0000000 0000000 goos: linux
goarch: amd64
pkg: package/name/benchfail
BenchmarkError
bench_test.go:6: error message
--- FAIL: BenchmarkError
BenchmarkFatal
bench_test.go:10: fatal message
--- FAIL: BenchmarkFatal
BenchmarkSkip
bench_test.go:14: skip message
--- SKIP: BenchmarkSkip
FAIL
exit status 1
FAIL package/name/benchfail 0.002s
go-junit-report-2.1.0/testdata/036-report.xml 0000664 0000000 0000000 00000001774 14514065750 0020753 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/037-legacy-fail.txt 0000664 0000000 0000000 00000000332 14514065750 0021622 0 ustar 00root root 0000000 0000000 === RUN TestOne
--- FAIL: TestOne (0.02 seconds)
file_test.go:11: Error message
file_test.go:11: Longer
error
message.
=== RUN TestTwo
--- PASS: TestTwo (0.13 seconds)
FAIL
exit status 1
FAIL package/name 0.151s
go-junit-report-2.1.0/testdata/037-report.xml 0000664 0000000 0000000 00000001217 14514065750 0020744 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/038-report.xml 0000664 0000000 0000000 00000001027 14514065750 0020744 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/038-test-pkg-name.txt 0000664 0000000 0000000 00000000225 14514065750 0022123 0 ustar 00root root 0000000 0000000 # package/testpkg/pkg_test [package/testpkg/pkg.test]
pkg/pkg_test.go:5:2: imported and not used: "fmt"
FAIL package/testpkg/pkg [build failed]
FAIL
go-junit-report-2.1.0/testdata/039-no-properties.txt 0000664 0000000 0000000 00000000114 14514065750 0022253 0 ustar 00root root 0000000 0000000 === RUN TestPass
--- PASS: TestPass (0.06s)
PASS
ok package/pass 0.160s
go-junit-report-2.1.0/testdata/039-report.xml 0000664 0000000 0000000 00000000464 14514065750 0020751 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/100-pass.gojson.txt 0000664 0000000 0000000 00000001541 14514065750 0021703 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.708039352+00:00","Action":"run","Package":"package/name/ok","Test":"TestOK"}
{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK","Output":"=== RUN TestOK\n"}
{"Time":"2019-10-09T00:00:00.708148292+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK","Output":"--- PASS: TestOK (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.708154115+00:00","Action":"pass","Package":"package/name/ok","Test":"TestOK","Elapsed":0}
{"Time":"2019-10-09T00:00:00.708157995+00:00","Action":"output","Package":"package/name/ok","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.708199504+00:00","Action":"output","Package":"package/name/ok","Output":"ok \tpackage/name/ok\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.708212177+00:00","Action":"pass","Package":"package/name/ok","Elapsed":0.001}
go-junit-report-2.1.0/testdata/100-report.xml 0000664 0000000 0000000 00000000616 14514065750 0020735 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/101-fail.gojson.txt 0000664 0000000 0000000 00000004115 14514065750 0021651 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.978937959+00:00","Action":"run","Package":"package/name/fail","Test":"TestOne"}
{"Time":"2019-10-09T00:00:00.979041013+00:00","Action":"output","Package":"package/name/fail","Test":"TestOne","Output":"=== RUN TestOne\n"}
{"Time":"2019-10-09T00:00:00.979048927+00:00","Action":"output","Package":"package/name/fail","Test":"TestOne","Output":" main_test.go:6: Error message\n"}
{"Time":"2019-10-09T00:00:00.979053125+00:00","Action":"output","Package":"package/name/fail","Test":"TestOne","Output":" main_test.go:7: Longer\n"}
{"Time":"2019-10-09T00:00:00.97905703+00:00","Action":"output","Package":"package/name/fail","Test":"TestOne","Output":" error\n"}
{"Time":"2019-10-09T00:00:00.979060012+00:00","Action":"output","Package":"package/name/fail","Test":"TestOne","Output":" message.\n"}
{"Time":"2019-10-09T00:00:00.979064328+00:00","Action":"output","Package":"package/name/fail","Test":"TestOne","Output":"--- FAIL: TestOne (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.979067283+00:00","Action":"fail","Package":"package/name/fail","Test":"TestOne","Elapsed":0}
{"Time":"2019-10-09T00:00:00.979071228+00:00","Action":"run","Package":"package/name/fail","Test":"TestTwo"}
{"Time":"2019-10-09T00:00:00.979073638+00:00","Action":"output","Package":"package/name/fail","Test":"TestTwo","Output":"=== RUN TestTwo\n"}
{"Time":"2019-10-09T00:00:00.979076797+00:00","Action":"output","Package":"package/name/fail","Test":"TestTwo","Output":"--- PASS: TestTwo (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.979079302+00:00","Action":"pass","Package":"package/name/fail","Test":"TestTwo","Elapsed":0}
{"Time":"2019-10-09T00:00:00.979081855+00:00","Action":"output","Package":"package/name/fail","Output":"FAIL\n"}
{"Time":"2019-10-09T00:00:00.979133907+00:00","Action":"output","Package":"package/name/fail","Output":"exit status 1\n"}
{"Time":"2019-10-09T00:00:00.979146205+00:00","Action":"output","Package":"package/name/fail","Output":"FAIL\tpackage/name/fail\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.979150031+00:00","Action":"fail","Package":"package/name/fail","Elapsed":0.001}
go-junit-report-2.1.0/testdata/101-report.xml 0000664 0000000 0000000 00000001271 14514065750 0020734 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/102-broken.gojson.txt 0000664 0000000 0000000 00000000304 14514065750 0022213 0 ustar 00root root 0000000 0000000 # package/name/broken [package/name/broken.test]
./main.go:4:6: unused declared but not used
./main.go:5:2: undefined: fmt
./main.go:5:48: undefined: value
FAIL package/name/broken [build failed]
go-junit-report-2.1.0/testdata/102-report.xml 0000664 0000000 0000000 00000001113 14514065750 0020730 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/103-report.xml 0000664 0000000 0000000 00000001635 14514065750 0020742 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/103-subtests.gojson.txt 0000664 0000000 0000000 00000006070 14514065750 0022616 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.284172551+00:00","Action":"run","Package":"package/name/subtest","Test":"TestMultiple"}
{"Time":"2019-10-09T00:00:00.284270018+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple","Output":"=== RUN TestMultiple\n"}
{"Time":"2019-10-09T00:00:00.284277654+00:00","Action":"run","Package":"package/name/subtest","Test":"TestMultiple/Empty_string"}
{"Time":"2019-10-09T00:00:00.284280691+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Empty_string","Output":"=== RUN TestMultiple/Empty_string\n"}
{"Time":"2019-10-09T00:00:00.28428418+00:00","Action":"run","Package":"package/name/subtest","Test":"TestMultiple/Single"}
{"Time":"2019-10-09T00:00:00.284287002+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Single","Output":"=== RUN TestMultiple/Single\n"}
{"Time":"2019-10-09T00:00:00.284291242+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Single","Output":" pkg_test.go:20: Do(\"a\"): got aaaaaaaaaa, want a\n"}
{"Time":"2019-10-09T00:00:00.284294939+00:00","Action":"run","Package":"package/name/subtest","Test":"TestMultiple/Multi"}
{"Time":"2019-10-09T00:00:00.284297402+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Multi","Output":"=== RUN TestMultiple/Multi\n"}
{"Time":"2019-10-09T00:00:00.284301367+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple","Output":"--- FAIL: TestMultiple (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.284304576+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Empty_string","Output":" --- PASS: TestMultiple/Empty_string (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.284307585+00:00","Action":"pass","Package":"package/name/subtest","Test":"TestMultiple/Empty_string","Elapsed":0}
{"Time":"2019-10-09T00:00:00.284310972+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Single","Output":" --- FAIL: TestMultiple/Single (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.284313906+00:00","Action":"fail","Package":"package/name/subtest","Test":"TestMultiple/Single","Elapsed":0}
{"Time":"2019-10-09T00:00:00.284316515+00:00","Action":"output","Package":"package/name/subtest","Test":"TestMultiple/Multi","Output":" --- PASS: TestMultiple/Multi (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.284319052+00:00","Action":"pass","Package":"package/name/subtest","Test":"TestMultiple/Multi","Elapsed":0}
{"Time":"2019-10-09T00:00:00.284321427+00:00","Action":"fail","Package":"package/name/subtest","Test":"TestMultiple","Elapsed":0}
{"Time":"2019-10-09T00:00:00.284323862+00:00","Action":"output","Package":"package/name/subtest","Output":"FAIL\n"}
{"Time":"2019-10-09T00:00:00.284344993+00:00","Action":"output","Package":"package/name/subtest","Output":"exit status 1\n"}
{"Time":"2019-10-09T00:00:00.284351108+00:00","Action":"output","Package":"package/name/subtest","Output":"FAIL\tpackage/name/subtest\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.284354151+00:00","Action":"fail","Package":"package/name/subtest","Elapsed":0.001}
go-junit-report-2.1.0/testdata/104-race.gojson.txt 0000664 0000000 0000000 00000017433 14514065750 0021662 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.009775942+00:00","Action":"run","Package":"package/name/race","Test":"TestRace"}
{"Time":"2019-10-09T00:00:00.009912969+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"=== RUN TestRace\n"}
{"Time":"2019-10-09T00:00:00.010694278+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"==================\n"}
{"Time":"2019-10-09T00:00:00.010704964+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"WARNING: DATA RACE\n"}
{"Time":"2019-10-09T00:00:00.010709822+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"Write at 0x00c000016308 by goroutine 8:\n"}
{"Time":"2019-10-09T00:00:00.010715347+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" package/name/race.Race.func1()\n"}
{"Time":"2019-10-09T00:00:00.01072067+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /src/package/name/race/pkg.go:7 +0x39\n"}
{"Time":"2019-10-09T00:00:00.010727891+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"\n"}
{"Time":"2019-10-09T00:00:00.010733019+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"Previous read at 0x00c000016308 by goroutine 7:\n"}
{"Time":"2019-10-09T00:00:00.010737579+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" package/name/race.Race()\n"}
{"Time":"2019-10-09T00:00:00.010742091+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /src/package/name/race/pkg.go:10 +0x104\n"}
{"Time":"2019-10-09T00:00:00.010747459+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" package/name/race.TestRace()\n"}
{"Time":"2019-10-09T00:00:00.010751912+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /src/package/name/race/pkg_test.go:6 +0x24\n"}
{"Time":"2019-10-09T00:00:00.010756378+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.tRunner()\n"}
{"Time":"2019-10-09T00:00:00.010760742+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1439 +0x213\n"}
{"Time":"2019-10-09T00:00:00.010765116+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.(*T).Run.func1()\n"}
{"Time":"2019-10-09T00:00:00.01076937+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1486 +0x47\n"}
{"Time":"2019-10-09T00:00:00.010773791+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"\n"}
{"Time":"2019-10-09T00:00:00.010777779+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"Goroutine 8 (running) created at:\n"}
{"Time":"2019-10-09T00:00:00.010781771+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" package/name/race.Race()\n"}
{"Time":"2019-10-09T00:00:00.010785612+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /src/package/name/race/pkg.go:6 +0xfa\n"}
{"Time":"2019-10-09T00:00:00.010789234+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" package/name/race.TestRace()\n"}
{"Time":"2019-10-09T00:00:00.010793289+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /src/package/name/race/pkg_test.go:6 +0x24\n"}
{"Time":"2019-10-09T00:00:00.010797344+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.tRunner()\n"}
{"Time":"2019-10-09T00:00:00.010801445+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1439 +0x213\n"}
{"Time":"2019-10-09T00:00:00.010805494+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.(*T).Run.func1()\n"}
{"Time":"2019-10-09T00:00:00.010814391+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1486 +0x47\n"}
{"Time":"2019-10-09T00:00:00.010819498+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"\n"}
{"Time":"2019-10-09T00:00:00.010823969+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"Goroutine 7 (running) created at:\n"}
{"Time":"2019-10-09T00:00:00.010828574+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.(*T).Run()\n"}
{"Time":"2019-10-09T00:00:00.010832764+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1486 +0x724\n"}
{"Time":"2019-10-09T00:00:00.010837162+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.runTests.func1()\n"}
{"Time":"2019-10-09T00:00:00.010841644+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1839 +0x99\n"}
{"Time":"2019-10-09T00:00:00.010846126+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.tRunner()\n"}
{"Time":"2019-10-09T00:00:00.010850492+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1439 +0x213\n"}
{"Time":"2019-10-09T00:00:00.010854942+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.runTests()\n"}
{"Time":"2019-10-09T00:00:00.010859154+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1837 +0x7e4\n"}
{"Time":"2019-10-09T00:00:00.010863593+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.(*M).Run()\n"}
{"Time":"2019-10-09T00:00:00.010867851+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" /go-src/go1.18/src/testing/testing.go:1719 +0xa71\n"}
{"Time":"2019-10-09T00:00:00.010872159+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" main.main()\n"}
{"Time":"2019-10-09T00:00:00.010876434+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" _testmain.go:47 +0x2e4\n"}
{"Time":"2019-10-09T00:00:00.010881203+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"==================\n"}
{"Time":"2019-10-09T00:00:00.010887367+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":" testing.go:1312: race detected during execution of test\n"}
{"Time":"2019-10-09T00:00:00.010895484+00:00","Action":"output","Package":"package/name/race","Test":"TestRace","Output":"--- FAIL: TestRace (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.01090098+00:00","Action":"fail","Package":"package/name/race","Test":"TestRace","Elapsed":0}
{"Time":"2019-10-09T00:00:00.010906342+00:00","Action":"cont","Package":"package/name/race"}
{"Time":"2019-10-09T00:00:00.010911088+00:00","Action":"output","Package":"package/name/race","Output":"=== CONT \n"}
{"Time":"2019-10-09T00:00:00.010915454+00:00","Action":"output","Package":"package/name/race","Output":" testing.go:1312: race detected during execution of test\n"}
{"Time":"2019-10-09T00:00:00.010921778+00:00","Action":"output","Package":"package/name/race","Output":"FAIL\n"}
{"Time":"2019-10-09T00:00:00.011439867+00:00","Action":"output","Package":"package/name/race","Output":"exit status 1\n"}
{"Time":"2019-10-09T00:00:00.011448729+00:00","Action":"output","Package":"package/name/race","Output":"FAIL\tpackage/name/race\t0.005s\n"}
{"Time":"2019-10-09T00:00:00.011452178+00:00","Action":"fail","Package":"package/name/race","Elapsed":0.005}
go-junit-report-2.1.0/testdata/104-report.xml 0000664 0000000 0000000 00000003705 14514065750 0020743 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/105-panic.gojson.txt 0000664 0000000 0000000 00000002007 14514065750 0022032 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.596409464+00:00","Action":"output","Package":"package/name/panic","Output":"panic: init\n"}
{"Time":"2019-10-09T00:00:00.596508615+00:00","Action":"output","Package":"package/name/panic","Output":"\n"}
{"Time":"2019-10-09T00:00:00.596515201+00:00","Action":"output","Package":"package/name/panic","Output":"goroutine 1 [running]:\n"}
{"Time":"2019-10-09T00:00:00.596518457+00:00","Action":"output","Package":"package/name/panic","Output":"package/name/panic.init.0()\n"}
{"Time":"2019-10-09T00:00:00.596521268+00:00","Action":"output","Package":"package/name/panic","Output":"\t/src/package/name/panic/main_test.go:6 +0x27\n"}
{"Time":"2019-10-09T00:00:00.596604261+00:00","Action":"output","Package":"package/name/panic","Output":"exit status 2\n"}
{"Time":"2019-10-09T00:00:00.596615441+00:00","Action":"output","Package":"package/name/panic","Output":"FAIL\tpackage/name/panic\t0.003s\n"}
{"Time":"2019-10-09T00:00:00.596619695+00:00","Action":"fail","Package":"package/name/panic","Elapsed":0.003}
go-junit-report-2.1.0/testdata/105-report.xml 0000664 0000000 0000000 00000001125 14514065750 0020736 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/106-report.xml 0000664 0000000 0000000 00000002441 14514065750 0020741 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/106-testmain.gojson.txt 0000664 0000000 0000000 00000004741 14514065750 0022574 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.439383963+00:00","Action":"run","Package":"package/name/main/ack","Test":"TestAck"}
{"Time":"2019-10-09T00:00:00.439487748+00:00","Action":"output","Package":"package/name/main/ack","Test":"TestAck","Output":"=== RUN TestAck\n"}
{"Time":"2019-10-09T00:00:00.439496258+00:00","Action":"output","Package":"package/name/main/ack","Test":"TestAck","Output":" ack_test.go:13: ack\n"}
{"Time":"2019-10-09T00:00:00.439503036+00:00","Action":"output","Package":"package/name/main/ack","Test":"TestAck","Output":"--- PASS: TestAck (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.439507387+00:00","Action":"pass","Package":"package/name/main/ack","Test":"TestAck","Elapsed":0}
{"Time":"2019-10-09T00:00:00.439513347+00:00","Action":"output","Package":"package/name/main/ack","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.439517752+00:00","Action":"output","Package":"package/name/main/ack","Output":"ok \tpackage/name/main/ack\t(cached)\n"}
{"Time":"2019-10-09T00:00:00.439522697+00:00","Action":"pass","Package":"package/name/main/ack","Elapsed":0}
{"Time":"2019-10-09T00:00:00.439813777+00:00","Action":"run","Package":"package/name/main/ok","Test":"TestOk"}
{"Time":"2019-10-09T00:00:00.4398418+00:00","Action":"output","Package":"package/name/main/ok","Test":"TestOk","Output":"=== RUN TestOk\n"}
{"Time":"2019-10-09T00:00:00.439848365+00:00","Action":"output","Package":"package/name/main/ok","Test":"TestOk","Output":" ok_test.go:13: ok\n"}
{"Time":"2019-10-09T00:00:00.439855774+00:00","Action":"output","Package":"package/name/main/ok","Test":"TestOk","Output":"--- PASS: TestOk (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.439860255+00:00","Action":"pass","Package":"package/name/main/ok","Test":"TestOk","Elapsed":0}
{"Time":"2019-10-09T00:00:00.43986525+00:00","Action":"output","Package":"package/name/main/ok","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.439870064+00:00","Action":"output","Package":"package/name/main/ok","Output":"ok \tpackage/name/main/ok\t(cached)\n"}
{"Time":"2019-10-09T00:00:00.439881025+00:00","Action":"pass","Package":"package/name/main/ok","Elapsed":0}
{"Time":"2019-10-09T00:00:00.494446083+00:00","Action":"output","Package":"package/name/main/fail","Output":"TestMain failed, returning early\n"}
{"Time":"2019-10-09T00:00:00.494579248+00:00","Action":"output","Package":"package/name/main/fail","Output":"FAIL\tpackage/name/main/fail\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.494593522+00:00","Action":"fail","Package":"package/name/main/fail","Elapsed":0.001}
go-junit-report-2.1.0/testdata/107-report.xml 0000664 0000000 0000000 00000001262 14514065750 0020742 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/107-skip.gojson.txt 0000664 0000000 0000000 00000003342 14514065750 0021713 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.329193863+00:00","Action":"run","Package":"package/name/skip","Test":"TestSkip"}
{"Time":"2019-10-09T00:00:00.329288607+00:00","Action":"output","Package":"package/name/skip","Test":"TestSkip","Output":"=== RUN TestSkip\n"}
{"Time":"2019-10-09T00:00:00.32929713+00:00","Action":"output","Package":"package/name/skip","Test":"TestSkip","Output":" skip_test.go:6: skip message\n"}
{"Time":"2019-10-09T00:00:00.329302577+00:00","Action":"output","Package":"package/name/skip","Test":"TestSkip","Output":"--- SKIP: TestSkip (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.329305698+00:00","Action":"skip","Package":"package/name/skip","Test":"TestSkip","Elapsed":0}
{"Time":"2019-10-09T00:00:00.329309504+00:00","Action":"run","Package":"package/name/skip","Test":"TestSkipNow"}
{"Time":"2019-10-09T00:00:00.329312988+00:00","Action":"output","Package":"package/name/skip","Test":"TestSkipNow","Output":"=== RUN TestSkipNow\n"}
{"Time":"2019-10-09T00:00:00.329315853+00:00","Action":"output","Package":"package/name/skip","Test":"TestSkipNow","Output":" skip_test.go:10: log message\n"}
{"Time":"2019-10-09T00:00:00.329319388+00:00","Action":"output","Package":"package/name/skip","Test":"TestSkipNow","Output":"--- SKIP: TestSkipNow (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.329322008+00:00","Action":"skip","Package":"package/name/skip","Test":"TestSkipNow","Elapsed":0}
{"Time":"2019-10-09T00:00:00.329324691+00:00","Action":"output","Package":"package/name/skip","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.329392899+00:00","Action":"output","Package":"package/name/skip","Output":"ok \tpackage/name/skip\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.329615729+00:00","Action":"pass","Package":"package/name/skip","Elapsed":0.001}
go-junit-report-2.1.0/testdata/108-paniclate.gojson.txt 0000664 0000000 0000000 00000003753 14514065750 0022714 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.660908821+00:00","Action":"run","Package":"package/name/paniclate","Test":"TestOne"}
{"Time":"2019-10-09T00:00:00.660994505+00:00","Action":"output","Package":"package/name/paniclate","Test":"TestOne","Output":"=== RUN TestOne\n"}
{"Time":"2019-10-09T00:00:00.661001176+00:00","Action":"output","Package":"package/name/paniclate","Test":"TestOne","Output":" main_test.go:13: ok\n"}
{"Time":"2019-10-09T00:00:00.661007326+00:00","Action":"output","Package":"package/name/paniclate","Test":"TestOne","Output":"--- PASS: TestOne (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.661010216+00:00","Action":"pass","Package":"package/name/paniclate","Test":"TestOne","Elapsed":0}
{"Time":"2019-10-09T00:00:00.661014007+00:00","Action":"output","Package":"package/name/paniclate","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.663185752+00:00","Action":"output","Package":"package/name/paniclate","Output":"panic: panic\n"}
{"Time":"2019-10-09T00:00:00.663196708+00:00","Action":"output","Package":"package/name/paniclate","Output":"\n"}
{"Time":"2019-10-09T00:00:00.663201293+00:00","Action":"output","Package":"package/name/paniclate","Output":"goroutine 1 [running]:\n"}
{"Time":"2019-10-09T00:00:00.663206374+00:00","Action":"output","Package":"package/name/paniclate","Output":"package/name/paniclate.TestMain(...)\n"}
{"Time":"2019-10-09T00:00:00.663209509+00:00","Action":"output","Package":"package/name/paniclate","Output":"\t/src/package/name/paniclate/main_test.go:9\n"}
{"Time":"2019-10-09T00:00:00.663213452+00:00","Action":"output","Package":"package/name/paniclate","Output":"main.main()\n"}
{"Time":"2019-10-09T00:00:00.663216003+00:00","Action":"output","Package":"package/name/paniclate","Output":"\t_testmain.go:49 +0x17f\n"}
{"Time":"2019-10-09T00:00:00.66336185+00:00","Action":"output","Package":"package/name/paniclate","Output":"FAIL\tpackage/name/paniclate\t0.003s\n"}
{"Time":"2019-10-09T00:00:00.663374091+00:00","Action":"fail","Package":"package/name/paniclate","Elapsed":0.003}
go-junit-report-2.1.0/testdata/108-report.xml 0000664 0000000 0000000 00000001425 14514065750 0020744 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/109-bench.gojson.txt 0000664 0000000 0000000 00000007132 14514065750 0022027 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.143083156+00:00","Action":"run","Package":"package/name/bench","Test":"TestA"}
{"Time":"2019-10-09T00:00:00.143175255+00:00","Action":"output","Package":"package/name/bench","Test":"TestA","Output":"=== RUN TestA\n"}
{"Time":"2019-10-09T00:00:00.143186363+00:00","Action":"output","Package":"package/name/bench","Test":"TestA","Output":" a_test.go:6: ok\n"}
{"Time":"2019-10-09T00:00:00.143192278+00:00","Action":"output","Package":"package/name/bench","Test":"TestA","Output":"--- PASS: TestA (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.143196049+00:00","Action":"pass","Package":"package/name/bench","Test":"TestA","Elapsed":0}
{"Time":"2019-10-09T00:00:00.143200628+00:00","Action":"run","Package":"package/name/bench","Test":"TestZ"}
{"Time":"2019-10-09T00:00:00.143204984+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"=== RUN TestZ\n"}
{"Time":"2019-10-09T00:00:00.143208135+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" z_test.go:6: ok\n"}
{"Time":"2019-10-09T00:00:00.143212704+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"--- PASS: TestZ (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.143526651+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"goos: linux\n"}
{"Time":"2019-10-09T00:00:00.143536046+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"goarch: amd64\n"}
{"Time":"2019-10-09T00:00:00.143541285+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"pkg: package/name/bench\n"}
{"Time":"2019-10-09T00:00:00.143551889+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"BenchmarkTest\n"}
{"Time":"2019-10-09T00:00:00.143725381+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" bench_test.go:12: 1\n"}
{"Time":"2019-10-09T00:00:00.143902878+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" bench_test.go:12: 100\n"}
{"Time":"2019-10-09T00:00:00.144064852+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" bench_test.go:12: 10000\n"}
{"Time":"2019-10-09T00:00:00.144742621+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" bench_test.go:12: 1000000\n"}
{"Time":"2019-10-09T00:00:00.171286312+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" bench_test.go:12: 100000000\n"}
{"Time":"2019-10-09T00:00:00.612105586+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":" bench_test.go:12: 1000000000\n"}
{"Time":"2019-10-09T00:00:00.612121122+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"BenchmarkTest-8 \t1000000000\t 0.4407 ns/op\n"}
{"Time":"2019-10-09T00:00:00.612131677+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"BenchmarkOtherTest\n"}
{"Time":"2019-10-09T00:00:00.903727128+00:00","Action":"output","Package":"package/name/bench","Test":"TestZ","Output":"BenchmarkOtherTest-8 \t1000000000\t 0.2639 ns/op\n"}
{"Time":"2019-10-09T00:00:00.903751664+00:00","Action":"pass","Package":"package/name/bench","Test":"TestZ","Elapsed":0}
{"Time":"2019-10-09T00:00:00.903759733+00:00","Action":"output","Package":"package/name/bench","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.904057742+00:00","Action":"output","Package":"package/name/bench","Output":"ok \tpackage/name/bench\t0.762s\n"}
{"Time":"2019-10-09T00:00:00.904069084+00:00","Action":"pass","Package":"package/name/bench","Elapsed":0.762}
go-junit-report-2.1.0/testdata/109-report.xml 0000664 0000000 0000000 00000002112 14514065750 0020737 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/110-benchfail.gojson.txt 0000664 0000000 0000000 00000005163 14514065750 0022655 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.025742278+00:00","Action":"output","Package":"package/name/benchfail","Output":"goos: linux\n"}
{"Time":"2019-10-09T00:00:00.025842393+00:00","Action":"output","Package":"package/name/benchfail","Output":"goarch: amd64\n"}
{"Time":"2019-10-09T00:00:00.025848233+00:00","Action":"output","Package":"package/name/benchfail","Output":"pkg: package/name/benchfail\n"}
{"Time":"2019-10-09T00:00:00.025857524+00:00","Action":"output","Package":"package/name/benchfail","Output":"BenchmarkError\n"}
{"Time":"2019-10-09T00:00:00.025926237+00:00","Action":"output","Package":"package/name/benchfail","Output":" bench_test.go:6: error message\n"}
{"Time":"2019-10-09T00:00:00.025968693+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkError","Output":"--- FAIL: BenchmarkError\n"}
{"Time":"2019-10-09T00:00:00.025973906+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkError","Output":"BenchmarkFatal\n"}
{"Time":"2019-10-09T00:00:00.026152458+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkError","Output":" bench_test.go:10: fatal message\n"}
{"Time":"2019-10-09T00:00:00.026171221+00:00","Action":"fail","Package":"package/name/benchfail","Test":"BenchmarkError"}
{"Time":"2019-10-09T00:00:00.026174732+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkFatal","Output":"--- FAIL: BenchmarkFatal\n"}
{"Time":"2019-10-09T00:00:00.026188643+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkFatal","Output":"BenchmarkSkip\n"}
{"Time":"2019-10-09T00:00:00.026346331+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkFatal","Output":" bench_test.go:14: skip message\n"}
{"Time":"2019-10-09T00:00:00.026352372+00:00","Action":"fail","Package":"package/name/benchfail","Test":"BenchmarkFatal"}
{"Time":"2019-10-09T00:00:00.026355025+00:00","Action":"output","Package":"package/name/benchfail","Test":"BenchmarkSkip","Output":"--- SKIP: BenchmarkSkip\n"}
{"Time":"2019-10-09T00:00:00.026358242+00:00","Action":"skip","Package":"package/name/benchfail","Test":"BenchmarkSkip"}
{"Time":"2019-10-09T00:00:00.026361938+00:00","Action":"output","Package":"package/name/benchfail","Output":"FAIL\n"}
{"Time":"2019-10-09T00:00:00.026550031+00:00","Action":"output","Package":"package/name/benchfail","Output":"exit status 1\n"}
{"Time":"2019-10-09T00:00:00.026562733+00:00","Action":"output","Package":"package/name/benchfail","Output":"FAIL\tpackage/name/benchfail\t0.002s\n"}
{"Time":"2019-10-09T00:00:00.026568631+00:00","Action":"fail","Package":"package/name/benchfail","Elapsed":0.002}
go-junit-report-2.1.0/testdata/110-report.xml 0000664 0000000 0000000 00000001774 14514065750 0020744 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/111-empty.gojson.txt 0000664 0000000 0000000 00000000774 14514065750 0022104 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.740642406+00:00","Action":"output","Package":"package/name/empty","Output":"testing: warning: no tests to run\n"}
{"Time":"2019-10-09T00:00:00.740741069+00:00","Action":"output","Package":"package/name/empty","Output":"PASS\n"}
{"Time":"2019-10-09T00:00:00.740776164+00:00","Action":"output","Package":"package/name/empty","Output":"ok \tpackage/name/empty\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.74078812+00:00","Action":"pass","Package":"package/name/empty","Elapsed":0.001}
go-junit-report-2.1.0/testdata/111-report.xml 0000664 0000000 0000000 00000000601 14514065750 0020731 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/112-parallel.gojson.txt 0000664 0000000 0000000 00000012653 14514065750 0022542 0 ustar 00root root 0000000 0000000 {"Time":"2019-10-09T00:00:00.357524357+00:00","Action":"run","Package":"package/name/parallel","Test":"TestP1"}
{"Time":"2019-10-09T00:00:00.35763106+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":"=== RUN TestP1\n"}
{"Time":"2019-10-09T00:00:00.357639447+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":"=== PAUSE TestP1\n"}
{"Time":"2019-10-09T00:00:00.357642993+00:00","Action":"pause","Package":"package/name/parallel","Test":"TestP1"}
{"Time":"2019-10-09T00:00:00.357647811+00:00","Action":"run","Package":"package/name/parallel","Test":"TestP2"}
{"Time":"2019-10-09T00:00:00.357650618+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":"=== RUN TestP2\n"}
{"Time":"2019-10-09T00:00:00.357653576+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":"=== PAUSE TestP2\n"}
{"Time":"2019-10-09T00:00:00.35765612+00:00","Action":"pause","Package":"package/name/parallel","Test":"TestP2"}
{"Time":"2019-10-09T00:00:00.357659179+00:00","Action":"run","Package":"package/name/parallel","Test":"TestP3"}
{"Time":"2019-10-09T00:00:00.357661598+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":"=== RUN TestP3\n"}
{"Time":"2019-10-09T00:00:00.357664327+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":"=== PAUSE TestP3\n"}
{"Time":"2019-10-09T00:00:00.357666658+00:00","Action":"pause","Package":"package/name/parallel","Test":"TestP3"}
{"Time":"2019-10-09T00:00:00.357669385+00:00","Action":"cont","Package":"package/name/parallel","Test":"TestP1"}
{"Time":"2019-10-09T00:00:00.357672779+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":"=== CONT TestP1\n"}
{"Time":"2019-10-09T00:00:00.357675573+00:00","Action":"cont","Package":"package/name/parallel","Test":"TestP3"}
{"Time":"2019-10-09T00:00:00.357677968+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":"=== CONT TestP3\n"}
{"Time":"2019-10-09T00:00:00.357680531+00:00","Action":"cont","Package":"package/name/parallel","Test":"TestP2"}
{"Time":"2019-10-09T00:00:00.357683223+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":"=== CONT TestP2\n"}
{"Time":"2019-10-09T00:00:00.357686021+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":" pkg_test.go:19: t.Log(P2)\n"}
{"Time":"2019-10-09T00:00:00.357688933+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":"fmt.Printf(P2)\n"}
{"Time":"2019-10-09T00:00:00.357691543+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":" pkg_test.go:23: P2 error\n"}
{"Time":"2019-10-09T00:00:00.357695428+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP2","Output":"--- FAIL: TestP2 (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.357698172+00:00","Action":"fail","Package":"package/name/parallel","Test":"TestP2","Elapsed":0}
{"Time":"2019-10-09T00:00:00.357701575+00:00","Action":"cont","Package":"package/name/parallel","Test":"TestP3"}
{"Time":"2019-10-09T00:00:00.35770407+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":"=== CONT TestP3\n"}
{"Time":"2019-10-09T00:00:00.357706546+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":" pkg_test.go:28: t.Log(P3)\n"}
{"Time":"2019-10-09T00:00:00.357709127+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":"fmt.Printf(P3)\n"}
{"Time":"2019-10-09T00:00:00.357711692+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":" pkg_test.go:32: P3 error\n"}
{"Time":"2019-10-09T00:00:00.357714665+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP3","Output":"--- FAIL: TestP3 (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.357717319+00:00","Action":"fail","Package":"package/name/parallel","Test":"TestP3","Elapsed":0}
{"Time":"2019-10-09T00:00:00.357719718+00:00","Action":"cont","Package":"package/name/parallel","Test":"TestP1"}
{"Time":"2019-10-09T00:00:00.357725608+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":"=== CONT TestP1\n"}
{"Time":"2019-10-09T00:00:00.357728586+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":" pkg_test.go:10: t.Log(P1)\n"}
{"Time":"2019-10-09T00:00:00.357731205+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":"fmt.Printf(P1)\n"}
{"Time":"2019-10-09T00:00:00.357733751+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":" pkg_test.go:14: P1 error\n"}
{"Time":"2019-10-09T00:00:00.357736767+00:00","Action":"output","Package":"package/name/parallel","Test":"TestP1","Output":"--- FAIL: TestP1 (0.00s)\n"}
{"Time":"2019-10-09T00:00:00.357739279+00:00","Action":"fail","Package":"package/name/parallel","Test":"TestP1","Elapsed":0}
{"Time":"2019-10-09T00:00:00.357741786+00:00","Action":"output","Package":"package/name/parallel","Output":"FAIL\n"}
{"Time":"2019-10-09T00:00:00.357761811+00:00","Action":"output","Package":"package/name/parallel","Output":"exit status 1\n"}
{"Time":"2019-10-09T00:00:00.357766968+00:00","Action":"output","Package":"package/name/parallel","Output":"FAIL\tpackage/name/parallel\t0.001s\n"}
{"Time":"2019-10-09T00:00:00.357770181+00:00","Action":"fail","Package":"package/name/parallel","Elapsed":0.001}
go-junit-report-2.1.0/testdata/112-report.xml 0000664 0000000 0000000 00000002006 14514065750 0020733 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/113-race.gojson.txt 0000664 0000000 0000000 00000003504 14514065750 0021654 0 ustar 00root root 0000000 0000000 {"Time":"2022-07-17T22:24:20.065393432+01:00","Action":"run","Package":"package/race-json/pkg1","Test":"TestPkg1"}
{"Time":"2022-07-17T22:24:20.065595209+01:00","Action":"output","Package":"package/race-json/pkg1","Test":"TestPkg1","Output":"=== RUN TestPkg1\n"}
{"Time":"2022-07-17T22:24:20.065621488+01:00","Action":"output","Package":"package/race-json/pkg1","Test":"TestPkg1","Output":"--- PASS: TestPkg1 (0.00s)\n"}
{"Time":"2022-07-17T22:24:20.065633674+01:00","Action":"pass","Package":"package/race-json/pkg1","Test":"TestPkg1","Elapsed":0}
{"Time":"2022-07-17T22:24:20.065647242+01:00","Action":"output","Package":"package/race-json/pkg1","Output":"PASS\n"}
{"Time":"2022-07-17T22:24:20.065407525+01:00","Action":"run","Package":"package/race-json/pkg2","Test":"TestPkg2"}
{"Time":"2022-07-17T22:24:20.06568802+01:00","Action":"output","Package":"package/race-json/pkg2","Test":"TestPkg2","Output":"=== RUN TestPkg2\n"}
{"Time":"2022-07-17T22:24:20.065713342+01:00","Action":"output","Package":"package/race-json/pkg2","Test":"TestPkg2","Output":"--- PASS: TestPkg2 (0.00s)\n"}
{"Time":"2022-07-17T22:24:20.065725102+01:00","Action":"pass","Package":"package/race-json/pkg2","Test":"TestPkg2","Elapsed":0}
{"Time":"2022-07-17T22:24:20.065736721+01:00","Action":"output","Package":"package/race-json/pkg2","Output":"PASS\n"}
{"Time":"2022-07-17T22:24:20.06574776+01:00","Action":"output","Package":"package/race-json/pkg2","Output":"ok \tpackage/race-json/pkg2\t(cached)\n"}
{"Time":"2022-07-17T22:24:20.065763529+01:00","Action":"pass","Package":"package/race-json/pkg2","Elapsed":0}
{"Time":"2022-07-17T22:24:20.065657773+01:00","Action":"output","Package":"package/race-json/pkg1","Output":"ok \tpackage/race-json/pkg1\t(cached)\n"}
{"Time":"2022-07-17T22:24:20.065831715+01:00","Action":"pass","Package":"package/race-json/pkg1","Elapsed":0}
go-junit-report-2.1.0/testdata/113-report.xml 0000664 0000000 0000000 00000001360 14514065750 0020736 0 ustar 00root root 0000000 0000000
go-junit-report-2.1.0/testdata/generate-golden-reports.go 0000664 0000000 0000000 00000004616 14514065750 0023471 0 ustar 00root root 0000000 0000000 //go:generate go run generate-golden-reports.go -w
package main
import (
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
"github.com/jstemmer/go-junit-report/v2/internal/gojunitreport"
)
var verbose bool
var configs = map[string]gojunitreport.Config{
"005-no-xml-header.txt": {SkipXMLHeader: true},
"006-mixed.txt": {SkipXMLHeader: true},
"007-compiled_test.txt": {PackageName: "test/package"},
"039-no-properties.txt": {Properties: make(map[string]string)},
}
func main() {
var writeFiles bool
var id int
flag.BoolVar(&verbose, "v", false, "verbose logging")
flag.BoolVar(&writeFiles, "w", false, "write output xml files")
flag.IntVar(&id, "id", 0, "generate report for given id only")
flag.Parse()
files, err := filepath.Glob("*.txt")
if err != nil {
exitf("error listing files: %v\n", err)
}
var idPrefix string
if id > 0 {
idPrefix = fmt.Sprintf("%03d-", id)
}
for _, file := range files {
if idPrefix != "" && !strings.HasPrefix(file, idPrefix) {
continue
}
outName := outputName(file)
if err := createReportFromInput(file, outName, writeFiles); err != nil {
logf("error creating report: %v\n", err)
continue
}
if writeFiles {
logf("report written to %s\n", outName)
}
}
}
func logf(msg string, args ...interface{}) {
if verbose {
fmt.Printf(msg, args...)
}
}
func exitf(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg, args...)
os.Exit(1)
}
func outputName(input string) string {
dir, name := filepath.Split(input)
var out string
if idx := strings.IndexByte(name, '-'); idx > -1 {
out = input[:idx+1] + "report.xml"
} else {
out = strings.TrimSuffix(name, filepath.Ext(name)) + "report.xml"
}
return filepath.Join(dir, out)
}
func createReportFromInput(inputFile, outputFile string, write bool) error {
in, err := os.Open(inputFile)
if err != nil {
return err
}
defer in.Close()
out := io.Discard
if write {
f, err := os.Create(outputFile)
if err != nil {
return err
}
defer f.Close()
out = f
}
config := configs[inputFile]
config.Parser = "gotest"
if strings.HasSuffix(inputFile, ".gojson.txt") {
config.Parser = "gojson"
}
config.Hostname = "hostname"
config.TimestampFunc = func() time.Time {
return time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
}
if config.Properties == nil {
config.Properties = map[string]string{"go.version": "1.0"}
}
_, err = config.Run(in, out)
return err
}
go-junit-report-2.1.0/testdata/src/ 0000775 0000000 0000000 00000000000 14514065750 0017166 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/bench/ 0000775 0000000 0000000 00000000000 14514065750 0020245 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/bench/bench_test.go 0000664 0000000 0000000 00000000563 14514065750 0022716 0 ustar 00root root 0000000 0000000 package bench
import (
"strconv"
"testing"
)
func TestOne(t *testing.T) {
t.Logf("test log")
}
func BenchmarkOne(b *testing.B) {
b.Logf("benchmark log (%d)", b.N)
for i := 0; i < b.N; i++ {
test(i)
}
}
func BenchmarkTwo(b *testing.B) {
for i := 0; i < b.N; i++ {
n, _ := strconv.Atoi(strconv.Itoa(i))
test(n)
}
}
func test(x int) int {
return x + 1
}
go-junit-report-2.1.0/testdata/src/fail/ 0000775 0000000 0000000 00000000000 14514065750 0020101 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/fail/fail_test.go 0000664 0000000 0000000 00000000177 14514065750 0022407 0 ustar 00root root 0000000 0000000 package fail
import "testing"
func TestOne(t *testing.T) {
t.Errorf("Error message")
t.Errorf("Longer\nerror\nmessage.")
}
go-junit-report-2.1.0/testdata/src/go.mod 0000664 0000000 0000000 00000000030 14514065750 0020265 0 ustar 00root root 0000000 0000000 module package
go 1.13
go-junit-report-2.1.0/testdata/src/parallel/ 0000775 0000000 0000000 00000000000 14514065750 0020762 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/parallel/pkg_test.go 0000664 0000000 0000000 00000000632 14514065750 0023132 0 ustar 00root root 0000000 0000000 package pkg
import (
"testing"
"time"
)
func TestP1(t *testing.T) {
t.Parallel()
t.Log("t.Log(P1)")
time.Sleep(100 * time.Millisecond)
t.Errorf("P1 error")
}
func TestP2(t *testing.T) {
t.Parallel()
t.Log("t.Log(P2)")
time.Sleep(50 * time.Millisecond)
t.Errorf("P2 error")
}
func TestP3(t *testing.T) {
t.Parallel()
t.Log("t.Log(P3)")
time.Sleep(75 * time.Millisecond)
t.Errorf("P3 error")
}
go-junit-report-2.1.0/testdata/src/pass/ 0000775 0000000 0000000 00000000000 14514065750 0020134 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/pass/pass.go 0000664 0000000 0000000 00000000237 14514065750 0021433 0 ustar 00root root 0000000 0000000 package pass
import "fmt"
func message() string {
return "line"
}
func unused(n int) string {
if n < 0 {
return "0"
}
return fmt.Sprintf("%d\n", n)
}
go-junit-report-2.1.0/testdata/src/pass/pass_test.go 0000664 0000000 0000000 00000000234 14514065750 0022467 0 ustar 00root root 0000000 0000000 package pass
import "testing"
func TestPass(t *testing.T) {
}
func TestPassLog(t *testing.T) {
t.Logf("log %s", message())
t.Log("log\nmulti\nline")
}
go-junit-report-2.1.0/testdata/src/race-json/ 0000775 0000000 0000000 00000000000 14514065750 0021047 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/race-json/pkg1/ 0000775 0000000 0000000 00000000000 14514065750 0021711 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/race-json/pkg1/pkg1_test.go 0000664 0000000 0000000 00000000100 14514065750 0024130 0 ustar 00root root 0000000 0000000 package pkg1
import "testing"
func TestPkg1(t *testing.T) {
}
go-junit-report-2.1.0/testdata/src/race-json/pkg2/ 0000775 0000000 0000000 00000000000 14514065750 0021712 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/race-json/pkg2/pkg2_test.go 0000664 0000000 0000000 00000000100 14514065750 0024132 0 ustar 00root root 0000000 0000000 package pkg2
import "testing"
func TestPkg2(t *testing.T) {
}
go-junit-report-2.1.0/testdata/src/race/ 0000775 0000000 0000000 00000000000 14514065750 0020100 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/race/race_test.go 0000664 0000000 0000000 00000000260 14514065750 0022376 0 ustar 00root root 0000000 0000000 package race
import "testing"
func TestRace(t *testing.T) {
done := make(chan bool)
x := 0
go func() {
x = 5
done <- true
}()
x = 3
t.Logf("x = %d\n", x)
<-done
}
go-junit-report-2.1.0/testdata/src/skip/ 0000775 0000000 0000000 00000000000 14514065750 0020134 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/skip/skip_test.go 0000664 0000000 0000000 00000000237 14514065750 0022472 0 ustar 00root root 0000000 0000000 package skip
import "testing"
func TestSkip(t *testing.T) {
t.Skip("skip message")
}
func TestSkipNow(t *testing.T) {
t.Log("log message")
t.SkipNow()
}
go-junit-report-2.1.0/testdata/src/stdout/ 0000775 0000000 0000000 00000000000 14514065750 0020510 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/stdout/stdout_test.go 0000664 0000000 0000000 00000003062 14514065750 0023421 0 ustar 00root root 0000000 0000000 package stdout
import (
"fmt"
"testing"
)
func TestFailWithStdoutAndTestOutput(t *testing.T) {
fmt.Print("multi\nline\nstdout\n")
fmt.Print("single-line stdout\n")
t.Errorf("single-line error")
t.Errorf("multi\nline\nerror")
}
func TestFailWithStdoutAndNoTestOutput(t *testing.T) {
fmt.Print("multi\nline\nstdout\n")
fmt.Print("single-line stdout\n")
t.Fail()
}
func TestFailWithTestOutput(t *testing.T) {
t.Errorf("single-line error")
t.Errorf("multi\nline\nerror")
}
func TestFailWithNoTestOutput(t *testing.T) {
t.Fail()
}
func TestPassWithStdoutAndTestOutput(t *testing.T) {
fmt.Print("multi\nline\nstdout\n")
fmt.Print("single-line stdout\n")
t.Log("single-line info")
t.Log("multi\nline\ninfo")
}
func TestPassWithStdoutAndNoTestOutput(t *testing.T) {
fmt.Print("multi\nline\nstdout\n")
fmt.Print("single-line stdout\n")
}
func TestPassWithTestOutput(t *testing.T) {
t.Log("single-line info")
t.Log("multi\nline\ninfo")
}
func TestPassWithNoTestOutput(t *testing.T) {
}
func TestSubtests(t *testing.T) {
t.Run("TestFailWithStdoutAndTestOutput", TestFailWithStdoutAndTestOutput)
t.Run("TestFailWithStdoutAndNoTestOutput", TestFailWithStdoutAndNoTestOutput)
t.Run("TestFailWithTestOutput", TestFailWithTestOutput)
t.Run("TestFailWithNoTestOutput", TestFailWithNoTestOutput)
t.Run("TestPassWithStdoutAndTestOutput", TestPassWithStdoutAndTestOutput)
t.Run("TestPassWithStdoutAndNoTestOutput", TestPassWithStdoutAndNoTestOutput)
t.Run("TestPassWithTestOutput", TestPassWithTestOutput)
t.Run("TestPassWithNoTestOutput", TestPassWithNoTestOutput)
}
go-junit-report-2.1.0/testdata/src/subtests/ 0000775 0000000 0000000 00000000000 14514065750 0021042 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/subtests/subtests_test.go 0000664 0000000 0000000 00000001173 14514065750 0024306 0 ustar 00root root 0000000 0000000 package subtests
import "testing"
func TestSubtests(t *testing.T) {
t.Run("Subtest", func(t *testing.T) {
t.Log("ok")
})
t.Run("Subtest", func(t *testing.T) {
t.Error("error message")
})
t.Run("Subtest", func(t *testing.T) {
t.Skip("skip message")
})
}
func TestNestedSubtests(t *testing.T) {
t.Run("a#1", func(t *testing.T) {
t.Run("b#1", func(t *testing.T) {
t.Run("c#1", func(t *testing.T) {
})
})
})
}
func TestFailingSubtestWithNestedSubtest(t *testing.T) {
t.Run("Subtest", func(t *testing.T) {
t.Run("Subsubtest", func(t *testing.T) {
t.Log("ok")
})
t.Errorf("Subtest error message")
})
}
go-junit-report-2.1.0/testdata/src/whitespace/ 0000775 0000000 0000000 00000000000 14514065750 0021322 5 ustar 00root root 0000000 0000000 go-junit-report-2.1.0/testdata/src/whitespace/whitespace_test.go 0000664 0000000 0000000 00000002223 14514065750 0025043 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"testing"
)
func TestFlat(t *testing.T) {
t.Logf("log 1")
t.Logf("log 2")
fmt.Printf("printf 1\n")
fmt.Printf("printf 2\n")
}
func TestWithSpace(t *testing.T) {
t.Logf("no-space")
t.Logf(" one-space")
t.Logf(" two-space")
t.Logf(" four-space")
t.Logf(" eight-space")
t.Logf("no-space")
fmt.Printf("no-space\n")
fmt.Printf(" one-space\n")
fmt.Printf(" two-space\n")
fmt.Printf(" four-space\n")
fmt.Printf(" eight-space\n")
fmt.Printf("no-space\n")
}
func TestWithTab(t *testing.T) {
t.Logf("no-tab")
t.Logf("\tone-tab")
t.Logf("\t\ttwo-tab")
fmt.Printf("no-tab\n")
fmt.Printf("\tone-tab\n")
fmt.Printf("\t\ttwo-tab\n")
}
func TestWithNewlinesFlat(t *testing.T) {
t.Logf("no-newline")
t.Logf("one-newline\none-newline")
t.Logf("two-newlines\ntwo-newlines\ntwo-newlines")
fmt.Println("no-newline")
fmt.Println("one-newline\none-newline")
fmt.Println("two-newlines\ntwo-newlines\ntwo-newlines")
}
func TestSubTests(t *testing.T) {
t.Run("TestFlat", TestFlat)
t.Run("TestWithSpace", TestWithSpace)
t.Run("TestWithTab", TestWithTab)
t.Run("TestWithNewlinesFlat", TestWithNewlinesFlat)
}