pax_global_header00006660000000000000000000000064145140657500014521gustar00rootroot0000000000000052 comment=14d61e6e75e3f3c74551d757ad936e8e88014464 go-junit-report-2.1.0/000077500000000000000000000000001451406575000145665ustar00rootroot00000000000000go-junit-report-2.1.0/.github/000077500000000000000000000000001451406575000161265ustar00rootroot00000000000000go-junit-report-2.1.0/.github/workflows/000077500000000000000000000000001451406575000201635ustar00rootroot00000000000000go-junit-report-2.1.0/.github/workflows/main.yml000066400000000000000000000007451451406575000216400ustar00rootroot00000000000000name: 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/.gitignore000066400000000000000000000000271451406575000165550ustar00rootroot00000000000000go-junit-report build/ go-junit-report-2.1.0/CONTRIBUTING.md000066400000000000000000000015231451406575000170200ustar00rootroot00000000000000# 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/LICENSE000066400000000000000000000020401451406575000155670ustar00rootroot00000000000000Copyright (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/Makefile000066400000000000000000000017561451406575000162370ustar00rootroot00000000000000VERSION=$(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.md000066400000000000000000000146031451406575000160510ustar00rootroot00000000000000# 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]. [![Build status](https://github.com/jstemmer/go-junit-report/actions/workflows/main.yml/badge.svg)](https://github.com/jstemmer/go-junit-report/actions) [![Go Reference](https://pkg.go.dev/badge/github.com/jstemmer/go-junit-report/v2.svg)](https://pkg.go.dev/github.com/jstemmer/go-junit-report/v2) [![Go Report Card](https://goreportcard.com/badge/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.mod000066400000000000000000000001401451406575000156670ustar00rootroot00000000000000module 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.sum000066400000000000000000000002471451406575000157240ustar00rootroot00000000000000github.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/000077500000000000000000000000001451406575000153625ustar00rootroot00000000000000go-junit-report-2.1.0/gtr/gtr.go000066400000000000000000000072131451406575000165100ustar00rootroot00000000000000// 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.go000066400000000000000000000017631451406575000175530ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000164025ustar00rootroot00000000000000go-junit-report-2.1.0/internal/gojunitreport/000077500000000000000000000000001451406575000213155ustar00rootroot00000000000000go-junit-report-2.1.0/internal/gojunitreport/go-junit-report.go000066400000000000000000000037031451406575000247140ustar00rootroot00000000000000package 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.go000066400000000000000000000053361451406575000257570ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000157175ustar00rootroot00000000000000go-junit-report-2.1.0/junit/junit.go000066400000000000000000000163401451406575000174030ustar00rootroot00000000000000// 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.go000066400000000000000000000112761451406575000204450ustar00rootroot00000000000000package 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.go000066400000000000000000000100051451406575000160350ustar00rootroot00000000000000// 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/000077500000000000000000000000001451406575000160625ustar00rootroot00000000000000go-junit-report-2.1.0/parser/gotest/000077500000000000000000000000001451406575000173675ustar00rootroot00000000000000go-junit-report-2.1.0/parser/gotest/benchmark.go000066400000000000000000000022721451406575000216530ustar00rootroot00000000000000package 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.go000066400000000000000000000021011451406575000210310ustar00rootroot00000000000000package 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.go000066400000000000000000000244511451406575000212310ustar00rootroot00000000000000// 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.go000066400000000000000000000005231451406575000233400ustar00rootroot00000000000000//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.go000066400000000000000000000153221451406575000222650ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000212035ustar00rootroot00000000000000go-junit-report-2.1.0/parser/gotest/internal/collector/000077500000000000000000000000001451406575000231715ustar00rootroot00000000000000go-junit-report-2.1.0/parser/gotest/internal/collector/collector.go000066400000000000000000000051501451406575000255070ustar00rootroot00000000000000// 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.go000066400000000000000000000044451451406575000265540ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000224455ustar00rootroot00000000000000go-junit-report-2.1.0/parser/gotest/internal/reader/reader.go000066400000000000000000000057731451406575000242520ustar00rootroot00000000000000package 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.go000066400000000000000000000053061451406575000253010ustar00rootroot00000000000000package 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.go000066400000000000000000000013241451406575000206670ustar00rootroot00000000000000package 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.go000066400000000000000000000354121451406575000227440ustar00rootroot00000000000000package 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.go000066400000000000000000000313611451406575000240020ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000163775ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/001-pass-fail-skip.txt000066400000000000000000000010771451406575000222660ustar00rootroot00000000000000=== 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.xml000066400000000000000000000032121451406575000207300ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/005-no-xml-header.txt000066400000000000000000000003211451406575000220760ustar00rootroot00000000000000=== 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.xml000066400000000000000000000010601451406575000207330ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/007-compiled_test.txt000066400000000000000000000001301451406575000222710ustar00rootroot00000000000000=== RUN TestOne --- PASS: TestOne (0.06s) === RUN TestTwo --- PASS: TestTwo (0.10s) PASSgo-junit-report-2.1.0/testdata/007-report.xml000066400000000000000000000007261451406575000207450ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/008-parallel.txt000066400000000000000000000007471451406575000212510ustar00rootroot00000000000000=== 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.xml000066400000000000000000000017051451406575000207440ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/009-coverage.txt000066400000000000000000000002271451406575000212420ustar00rootroot00000000000000=== 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.xml000066400000000000000000000010301451406575000207340ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/010-multipkg-coverage.txt000066400000000000000000000004731451406575000230670ustar00rootroot00000000000000=== 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.xml000066400000000000000000000016311451406575000207330ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/011-go_1_5.txt000066400000000000000000000001661451406575000205130ustar00rootroot00000000000000=== 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.xml000066400000000000000000000007261451406575000207400ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/012-report.xml000066400000000000000000000037761451406575000207510ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/012-subtests.txt000066400000000000000000000023671451406575000213240ustar00rootroot00000000000000=== 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.xml000066400000000000000000000042461451406575000207430ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/013-syntax-error.txt000066400000000000000000000012131451406575000221130ustar00rootroot00000000000000# 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.txt000066400000000000000000000001531451406575000205330ustar00rootroot00000000000000panic: init stacktrace FAIL package/panic 0.003s panic: init stacktrace FAIL package/panic2 0.003s go-junit-report-2.1.0/testdata/014-report.xml000066400000000000000000000015671451406575000207470ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/015-empty.txt000066400000000000000000000001011451406575000205710ustar00rootroot00000000000000testing: warning: no tests to run PASS ok package/empty 0.001s go-junit-report-2.1.0/testdata/015-report.xml000066400000000000000000000005741451406575000207450ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/016-repeated-names.txt000066400000000000000000000003041451406575000223330ustar00rootroot00000000000000=== 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.xml000066400000000000000000000011241451406575000207360ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/017-race.txt000066400000000000000000000030251451406575000203570ustar00rootroot00000000000000=== 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.xml000066400000000000000000000036621451406575000207500ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/018-coverpkg.txt000066400000000000000000000006171451406575000212720ustar00rootroot00000000000000=== 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.xml000066400000000000000000000016311451406575000207430ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/019-pass.txt000066400000000000000000000002101451406575000204060ustar00rootroot00000000000000=== 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.xml000066400000000000000000000010161451406575000207410ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/021-cached.txt000066400000000000000000000001131451406575000206420ustar00rootroot00000000000000=== RUN TestOne --- PASS: TestOne (0.00s) PASS ok package/one (cached) go-junit-report-2.1.0/testdata/021-report.xml000066400000000000000000000006071451406575000207370ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/022-bench.txt000066400000000000000000000010371451406575000205210ustar00rootroot00000000000000=== 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.xml000066400000000000000000000020061451406575000207330ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/023-benchmem.txt000066400000000000000000000003351451406575000212210ustar00rootroot00000000000000goos: 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.xml000066400000000000000000000011221451406575000207320ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/024-benchtests.txt000066400000000000000000000003341451406575000216050ustar00rootroot00000000000000goos: 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.xml000066400000000000000000000011451451406575000207400ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/025-benchcount.txt000066400000000000000000000014351451406575000215770ustar00rootroot00000000000000BenchmarkNew-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.211sgo-junit-report-2.1.0/testdata/025-report.xml000066400000000000000000000007301451406575000207400ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/026-report.xml000066400000000000000000000024471451406575000207500ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/026-testbenchmultiple.txt000066400000000000000000000007721451406575000232060ustar00rootroot00000000000000pkg: 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.084sgo-junit-report-2.1.0/testdata/027-benchdecimal.txt000066400000000000000000000003461451406575000220470ustar00rootroot00000000000000goos: 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.xml000066400000000000000000000012131451406575000207370ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/028-bench-1cpu.txt000066400000000000000000000001351451406575000213730ustar00rootroot00000000000000pkg: single/cpu BenchmarkRing 20000000 74.2 ns/op PASS ok single/cpu 9.467sgo-junit-report-2.1.0/testdata/028-report.xml000066400000000000000000000007021451406575000207420ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/029-bench-16cpu.txt000066400000000000000000000001421451406575000214600ustar00rootroot00000000000000pkg: sixteen/cpu BenchmarkRingaround-16 100000 13571 ns/op PASS ok sixteen/cpu 1.522sgo-junit-report-2.1.0/testdata/029-report.xml000066400000000000000000000007131451406575000207450ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/030-report.xml000066400000000000000000000075451451406575000207470ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/030-stdout.txt000066400000000000000000000053141451406575000207650ustar00rootroot00000000000000=== 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.xml000066400000000000000000000042461451406575000207430ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/031-syntax-error-test-binary.txt000066400000000000000000000013471451406575000243620ustar00rootroot00000000000000# 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.txt000066400000000000000000000001611451406575000223570ustar00rootroot00000000000000=== 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.xml000066400000000000000000000011651451406575000207410ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/033-bench-mb.txt000066400000000000000000000004321451406575000211150ustar00rootroot00000000000000goos: 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.xml000066400000000000000000000011501451406575000207340ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/034-notest.txt000066400000000000000000000002411451406575000207550ustar00rootroot00000000000000? 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.xml000066400000000000000000000015331451406575000207420ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/035-report.xml000066400000000000000000000060141451406575000207420ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/035-whitespace.txt000066400000000000000000000042601451406575000216030ustar00rootroot00000000000000=== 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.txt000066400000000000000000000005141451406575000213610ustar00rootroot00000000000000goos: 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.xml000066400000000000000000000017741451406575000207530ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/037-legacy-fail.txt000066400000000000000000000003321451406575000216220ustar00rootroot00000000000000=== 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.xml000066400000000000000000000012171451406575000207440ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/038-report.xml000066400000000000000000000010271451406575000207440ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/038-test-pkg-name.txt000066400000000000000000000002251451406575000221230ustar00rootroot00000000000000# 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.txt000066400000000000000000000001141451406575000222530ustar00rootroot00000000000000=== RUN TestPass --- PASS: TestPass (0.06s) PASS ok package/pass 0.160s go-junit-report-2.1.0/testdata/039-report.xml000066400000000000000000000004641451406575000207510ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/100-pass.gojson.txt000066400000000000000000000015411451406575000217030ustar00rootroot00000000000000{"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.xml000066400000000000000000000006161451406575000207350ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/101-fail.gojson.txt000066400000000000000000000041151451406575000216510ustar00rootroot00000000000000{"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.xml000066400000000000000000000012711451406575000207340ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/102-broken.gojson.txt000066400000000000000000000003041451406575000222130ustar00rootroot00000000000000# 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.xml000066400000000000000000000011131451406575000207300ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/103-report.xml000066400000000000000000000016351451406575000207420ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/103-subtests.gojson.txt000066400000000000000000000060701451406575000226160ustar00rootroot00000000000000{"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.txt000066400000000000000000000174331451406575000216620ustar00rootroot00000000000000{"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.xml000066400000000000000000000037051451406575000207430ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/105-panic.gojson.txt000066400000000000000000000020071451406575000220320ustar00rootroot00000000000000{"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.xml000066400000000000000000000011251451406575000207360ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/106-report.xml000066400000000000000000000024411451406575000207410ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/106-testmain.gojson.txt000066400000000000000000000047411451406575000225740ustar00rootroot00000000000000{"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.xml000066400000000000000000000012621451406575000207420ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/107-skip.gojson.txt000066400000000000000000000033421451406575000217130ustar00rootroot00000000000000{"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.txt000066400000000000000000000037531451406575000227140ustar00rootroot00000000000000{"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.xml000066400000000000000000000014251451406575000207440ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/109-bench.gojson.txt000066400000000000000000000071321451406575000220270ustar00rootroot00000000000000{"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.xml000066400000000000000000000021121451406575000207370ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/110-benchfail.gojson.txt000066400000000000000000000051631451406575000226550ustar00rootroot00000000000000{"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.xml000066400000000000000000000017741451406575000207440ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/111-empty.gojson.txt000066400000000000000000000007741451406575000221040ustar00rootroot00000000000000{"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.xml000066400000000000000000000006011451406575000207310ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/112-parallel.gojson.txt000066400000000000000000000126531451406575000225420ustar00rootroot00000000000000{"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.xml000066400000000000000000000020061451406575000207330ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/113-race.gojson.txt000066400000000000000000000035041451406575000216540ustar00rootroot00000000000000{"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.xml000066400000000000000000000013601451406575000207360ustar00rootroot00000000000000 go-junit-report-2.1.0/testdata/generate-golden-reports.go000066400000000000000000000046161451406575000234710ustar00rootroot00000000000000//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/000077500000000000000000000000001451406575000171665ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/bench/000077500000000000000000000000001451406575000202455ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/bench/bench_test.go000066400000000000000000000005631451406575000227160ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000201015ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/fail/fail_test.go000066400000000000000000000001771451406575000224070ustar00rootroot00000000000000package 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.mod000066400000000000000000000000301451406575000202650ustar00rootroot00000000000000module package go 1.13 go-junit-report-2.1.0/testdata/src/parallel/000077500000000000000000000000001451406575000207625ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/parallel/pkg_test.go000066400000000000000000000006321451406575000231320ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000201345ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/pass/pass.go000066400000000000000000000002371451406575000214330ustar00rootroot00000000000000package 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.go000066400000000000000000000002341451406575000224670ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000210475ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/race-json/pkg1/000077500000000000000000000000001451406575000217115ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/race-json/pkg1/pkg1_test.go000066400000000000000000000001001451406575000241300ustar00rootroot00000000000000package pkg1 import "testing" func TestPkg1(t *testing.T) { } go-junit-report-2.1.0/testdata/src/race-json/pkg2/000077500000000000000000000000001451406575000217125ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/race-json/pkg2/pkg2_test.go000066400000000000000000000001001451406575000241320ustar00rootroot00000000000000package pkg2 import "testing" func TestPkg2(t *testing.T) { } go-junit-report-2.1.0/testdata/src/race/000077500000000000000000000000001451406575000201005ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/race/race_test.go000066400000000000000000000002601451406575000223760ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000201345ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/skip/skip_test.go000066400000000000000000000002371451406575000224720ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000205105ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/stdout/stdout_test.go000066400000000000000000000030621451406575000234210ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000210425ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/subtests/subtests_test.go000066400000000000000000000011731451406575000243060ustar00rootroot00000000000000package 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/000077500000000000000000000000001451406575000213225ustar00rootroot00000000000000go-junit-report-2.1.0/testdata/src/whitespace/whitespace_test.go000066400000000000000000000022231451406575000250430ustar00rootroot00000000000000package 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) }