gotools/cmd/go2junit/go2junit.go
2024-12-24 22:38:49 +01:00

174 lines
4.2 KiB
Go

package main
import (
"bufio"
"encoding/json"
"encoding/xml"
"fmt"
"log"
"os"
"path/filepath"
"runtime/debug"
"strings"
)
func getVersion() string {
if info, ok := debug.ReadBuildInfo(); ok {
return info.Main.Version
}
return "unknown"
}
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() {
fmt.Fprintf(os.Stderr, "go2junit version %s\n", getVersion())
testsuites := Testsuites{}
if len(os.Args) != 2 && len(os.Args) != 3 {
fmt.Fprintf(os.Stderr, "Usage: go2junit <outputdir> [<prefix>]\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)
os.Exit(1)
}
os.Exit(0)
}
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)
}
}
}