package main import ( "encoding/xml" "flag" "fmt" "io/ioutil" "os" "regexp" "runtime" "strconv" "strings" "testing" "time" "github.com/jstemmer/go-junit-report/v2/pkg/junit" "github.com/jstemmer/go-junit-report/v2/pkg/parser/gotest" "github.com/google/go-cmp/cmp" ) var matchTest = flag.String("match", "", "only test testdata matching this pattern") type TestCase struct { name string reportName string noXMLHeader bool packageName string } var testCases = []TestCase{ { name: "001-pass.txt", reportName: "001-report.xml", }, { name: "002-fail.txt", reportName: "002-report.xml", }, { name: "003-skip.txt", reportName: "003-report.xml", }, { name: "004-go_1_4.txt", reportName: "004-report.xml", }, { name: "005-no_xml_header.txt", reportName: "005-report.xml", noXMLHeader: true, }, { name: "006-mixed.txt", reportName: "006-report.xml", noXMLHeader: true, }, { name: "007-compiled_test.txt", reportName: "007-report.xml", packageName: "test/package", }, { name: "008-parallel.txt", reportName: "008-report.xml", }, { name: "009-coverage.txt", reportName: "009-report.xml", }, { name: "010-multipkg-coverage.txt", reportName: "010-report.xml", }, { name: "011-go_1_5.txt", reportName: "011-report.xml", }, { name: "012-go_1_7.txt", reportName: "012-report.xml", }, { name: "013-syntax-error.txt", reportName: "013-report.xml", }, { name: "014-panic.txt", reportName: "014-report.xml", }, { name: "015-empty.txt", reportName: "015-report.xml", }, { name: "016-repeated-names.txt", reportName: "016-report.xml", }, { name: "017-race.txt", reportName: "017-report.xml", }, { name: "018-coverpkg.txt", reportName: "018-report.xml", }, { name: "019-pass.txt", reportName: "019-report.xml", }, { name: "020-parallel.txt", reportName: "020-report.xml", }, { name: "021-cached.txt", reportName: "021-report.xml", }, { name: "022-bench.txt", reportName: "022-report.xml", }, { name: "023-benchmem.txt", reportName: "023-report.xml", }, { name: "024-benchtests.txt", reportName: "024-report.xml", }, { name: "025-benchcount.txt", reportName: "025-report.xml", }, { name: "026-testbenchmultiple.txt", reportName: "026-report.xml", }, { name: "027-benchdecimal.txt", reportName: "027-report.xml", }, { name: "028-bench-1cpu.txt", reportName: "028-report.xml", }, { name: "029-bench-16cpu.txt", reportName: "029-report.xml", }, { // generated by running go test on https://gist.github.com/liggitt/09a021ccec988b19917e0c2d60a18ee9 name: "030-stdout.txt", reportName: "030-report.xml", }, { name: "031-syntax-error-test-binary.txt", reportName: "031-report.xml", }, { name: "032-failed-summary.txt", reportName: "032-report.xml", }, { name: "033-bench-mb.txt", reportName: "033-report.xml", }, { name: "034-notest.txt", reportName: "034-report.xml", }, { name: "035-whitespace.txt", reportName: "035-report.xml", }, } func TestNewOutput(t *testing.T) { matchRegex := compileMatch(t) for _, testCase := range testCases { if !matchRegex.MatchString(testCase.name) { continue } t.Run(testCase.name, func(t *testing.T) { testReport(testCase.name, testCase.reportName, testCase.packageName, t) }) } } func testReport(input, reportFile, packageName string, t *testing.T) { file, err := os.Open("testdata/" + input) if err != nil { t.Fatal(err) } defer file.Close() parser := gotest.New( gotest.PackageName(packageName), gotest.TimestampFunc(func() time.Time { return time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC) }), ) report, err := parser.Parse(file) if err != nil { t.Fatal(err) } if *printEvents { for _, event := range parser.Events() { t.Logf("Event: %+v", event) } } actual := junit.CreateFromReport(report, "hostname") expectedXML, err := loadTestReport(reportFile, "") if err != nil { t.Fatal(err) } var expected junit.Testsuites if err := xml.Unmarshal([]byte(expectedXML), &expected); err != nil { t.Fatal(err) } expected = modifyForBackwardsCompat(expected) if diff := cmp.Diff(actual, expected); diff != "" { t.Errorf("Unexpected report diff (-got, +want):\n%v", diff) } } func modifyForBackwardsCompat(testsuites junit.Testsuites) junit.Testsuites { testsuites.XMLName.Local = "" for i, suite := range testsuites.Suites { for j := range suite.Testcases { testsuites.Suites[i].Testcases[j].Classname = suite.Name } if suite.Properties != nil { if covIdx, covProp := getProperty("coverage.statements.pct", *suite.Properties); covIdx > -1 { pct, _ := strconv.ParseFloat(covProp.Value, 64) (*testsuites.Suites[i].Properties)[covIdx].Value = fmt.Sprintf("%.2f", pct) } testsuites.Suites[i].Properties = dropProperty("go.version", suite.Properties) } } return testsuites } func dropProperty(name string, properties *[]junit.Property) *[]junit.Property { if properties == nil { return nil } var props []junit.Property for _, prop := range *properties { if prop.Name != name { props = append(props, prop) } } if len(props) == 0 { return nil } return &props } func getProperty(name string, properties []junit.Property) (int, junit.Property) { for i, prop := range properties { if prop.Name == name { return i, prop } } return -1, junit.Property{} } func loadTestReport(name, goVersion string) (string, error) { contents, err := ioutil.ReadFile("testdata/" + name) if err != nil { return "", err } if goVersion == "" { // if goVersion is not specified, default to runtime version goVersion = runtime.Version() } // replace value="1.0" With actual version report := strings.Replace(string(contents), `value="1.0"`, fmt.Sprintf(`value="%s"`, goVersion), -1) return report, 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 }