package main import ( "bufio" "encoding/json" "encoding/xml" "fmt" "log" "os" "path/filepath" "strings" ) func (t *Test) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if len(t.Tests) == 0 { start.Name = xml.Name{Local: "testcase"} classname := "" if t.parent != nil { classname = t.parent.Name } var skipped *Result if t.Skipped > 0 { skipped = &Result{ Message: "skipped", } } var failed *Result if t.Failures > 0 { failed = &Result{ Message: "failed", } } log.Printf("TIME %f", t.Time) parts := strings.Split(t.Name, "/") tc := Testcase{ Name: parts[len(parts)-1], // parent class name Classname: classname, Time: t.Time, Skipped: skipped, Error: nil, Failure: failed, SystemOut: t.SystemOut, } return e.EncodeElement(tc, start) } type Alias Test start.Name = xml.Name{Local: "testsuite"} return e.EncodeElement(Alias(*t), start) } func main() { testsuites := Testsuites{} if len(os.Args) != 2 && len(os.Args) != 3 { fmt.Fprintf(os.Stderr, "Usage: go2junit []\n") os.Exit(1) } path := os.Args[1] path = filepath.Clean(path) err := os.MkdirAll(path, 0755) if err != nil { panic(err) } prefix := "" if len(os.Args) == 3 { prefix = os.Args[2] } var file = os.Stdin scanner := bufio.NewScanner(file) lineno := 0 testsuites = Testsuites{} for scanner.Scan() { lineno++ var item TestEvent line := scanner.Bytes() if err := json.Unmarshal(line, &item); err != nil { fmt.Fprintf(os.Stderr, "%d: %s: %v", lineno, line, err) continue } //.fmt.Printf("Parsed %d:\n%v\n\n", lineno, item) pkg := prefix + item.Package switch item.Action { case "start": testsuites.Start(item.Time, pkg) case "run": fmt.Println() testsuites.Test(item.Time, pkg, item.Test) case "output": testsuites.Output(item.Time, pkg, item.Test, escapeIllegalChars(item.Output)) fmt.Printf("%s", item.Output) case "pause": testsuites.Output(item.Time, pkg, item.Test, "PAUSED") case "cont": testsuites.Output(item.Time, pkg, item.Test, "CONTINUED") case "pass": testsuites.Pass(item.Time, pkg, item.Test) case "bench": testsuites.Bench(item.Time, pkg, item.Test, escapeIllegalChars(item.Output)) case "fail": testsuites.Fail(item.Time, pkg, item.Test) case "skip": testsuites.Skip(item.Time, pkg, item.Test) } } testsuites.Complete() for _, suite := range testsuites.Suites { xml, err := xml.MarshalIndent(suite, "", " ") if err != nil { panic(err) } fname := path + "/" + suite.Name + ".xml" dir := filepath.Dir(fname) err = os.MkdirAll(dir, 0755) if err != nil { panic(err) } fmt.Fprintf(os.Stderr, "Writing %s\n", fname) err = os.WriteFile(fname, xml, 0644) if err != nil { panic(err) } } fmt.Printf("\n\nSUMMARY\n\n") fmt.Printf("%-60s %-10s %-10s %-10s %-10s %-10s %-10s\n\n", "SUITE", "COUNT", "PASSED", "FAILURES", "ERRORS", "DISABLED", "SKIPPED") for _, suite := range testsuites.Suites { fmt.Printf("%-60s %-10d %-10d %-10d %-10d %-10d %-10d\n", suite.Name, suite.TestCount, suite.TestCount-suite.Failures-suite.Errors-suite.Skipped-suite.Disabled, suite.Failures, suite.Errors, suite.Disabled, suite.Skipped) } fmt.Printf("\n%-60s %-10d %-10d %-10d %-10d %-10d %-10d\n", "TOTAL", testsuites.Tests, testsuites.Tests-testsuites.Failures-testsuites.Errors-testsuites.Skipped-testsuites.Disabled, testsuites.Failures, testsuites.Errors, testsuites.Disabled, testsuites.Skipped) if testsuites.Failures+testsuites.Errors+testsuites.Skipped+testsuites.Disabled > 0 { fmt.Printf("\nFAILED TESTS\n\n") printFailedTests("", "", testsuites.Suites) } } func printFailedTests(indent string, parentTest string, tests []*Test) { for _, test := range tests { if test.Failures > 0 { testName := strings.TrimPrefix(test.Name, parentTest+"/") fmt.Printf("%s%s\n", indent, testName) printFailedTests(indent+" ", test.Name, test.Tests) } } }