package main import ( "encoding/xml" "log" "strings" "time" ) type Testsuites struct { XMLName xml.Name `xml:"testsuites"` Tests int `xml:"tests,attr"` Failures int `xml:"failures,attr"` Errors int `xml:"errors,attr"` Disabled int `xml:"disabled,attr,omitempty"` Skipped int `xml:"skipped,attr,omitempty"` Time float64 `xml:"time,attr"` Suites []*Testsuite `xml:"testsuite,omitempty"` } type Testsuite struct { XMLName xml.Name `xml:"testsuite"` // required attributes Name string `xml:"name,attr"` Tests int `xml:"tests,attr"` Failures int `xml:"failures,attr"` Errors int `xml:"errors,attr"` // optional attributes Disabled int `xml:"disabled,attr,omitempty"` Package string `xml:"package,attr,omitempty"` Skipped int `xml:"skipped,attr,omitempty"` Time string `xml:"time,attr"` Timestamp time.Time `xml:"timestamp,attr,omitempty"` Testsuites []*Testsuite `xml:"testsuite,omitempty"` Testcases []*Testcase `xml:"testcase,omitempty"` SystemOut string `xml:"system-out,omitempty"` } type Result struct { Message string `xml:"message,attr"` } type Testcase struct { // required attributes Name string `xml:"name,attr"` Classname string `xml:"classname,attr"` // optional attributes Time float64 `xml:"time,attr,omitempty"` Skipped *Result `xml:"skipped,omitempty"` Error *Result `xml:"error,omitempty"` Failure *Result `xml:"failure,omitempty"` SystemOut string `xml:"system-out,omitempty"` } func (testsuites *Testsuites) getSuite(t time.Time, pkg string) *Testsuite { for _, suite := range testsuites.Suites { if suite.Name == pkg { return suite } } suite := Testsuite{ Name: pkg, Skipped: 0, Timestamp: t, } log.Printf("Adding suite %s", pkg) testsuites.Suites = append(testsuites.Suites, &suite) return &suite } func (suite *Testsuite) getSuite(t time.Time, name string) *Testsuite { for _, s := range suite.Testsuites { if s.Name == name { return s } } s := Testsuite{ Name: name, Timestamp: t, } suite.Testsuites = append(suite.Testsuites, &s) return &s } func (suite *Testsuite) getTest(t time.Time, testname string) *Testcase { path := strings.Split(testname, "/") for i := 0; i < len(path)-1; i++ { suite = suite.getSuite(t, path[i]) } for _, test := range suite.Testcases { if test.Name == path[len(path)-1] { return test } } if path[len(path)-1] == "" { panic("Empty testcase") } test := Testcase{ Name: path[len(path)-1], } suite.Testcases = append(suite.Testcases, &test) return &test } func (testsuites *Testsuites) getTest(t time.Time, pkg string, testname string) *Testcase { suite := testsuites.getSuite(t, pkg) test := suite.getTest(t, testname) return test } func (testsuites *Testsuites) Suite(t time.Time, pkg string) { testsuites.getSuite(t, pkg) } func (testsuites *Testsuites) Test(t time.Time, pkg string, test string) { testsuites.getTest(t, pkg, test) } func (testsuites *Testsuites) Output(t time.Time, pkg string, test string, output string) { if test == "" { ts := testsuites.getSuite(t, pkg) ts.SystemOut = ts.SystemOut + output return } tc := testsuites.getTest(t, pkg, test) tc.SystemOut = tc.SystemOut + output } func (testsuites *Testsuites) Pass(t time.Time, pkg string, test string, elapsed float64) { if test == "" { return } testsuites.getTest(t, pkg, test) } func (testsuites *Testsuites) Bench(t time.Time, pkg string, test string, output string, elapsed float64) { tc := testsuites.getTest(t, pkg, test) tc.SystemOut = tc.SystemOut + output + "\n" } func (testsuites *Testsuites) Fail(t time.Time, pkg string, test string, elapsed float64) { if test == "" { return } tc := testsuites.getTest(t, pkg, test) tc.Time = elapsed tc.Failure = &Result{ Message: "failed", } } func (testsuites *Testsuites) Skip(t time.Time, pkg string, test string) { if test == "" { return } tc := testsuites.getTest(t, pkg, test) tc.Failure = &Result{ Message: "skipped", } } func (suite *Testsuite) Complete() { suite.Tests = 0 suite.Failures = 0 suite.Errors = 0 suite.Disabled = 0 suite.Skipped = 0 for _, ts := range suite.Testsuites { ts.Complete() suite.Tests += ts.Tests suite.Failures += ts.Failures suite.Errors += ts.Errors suite.Disabled += ts.Disabled suite.Skipped += ts.Skipped } for _, tc := range suite.Testcases { suite.Tests += 1 if tc.Failure != nil { switch tc.Failure.Message { case "skipped": suite.Skipped++ default: suite.Failures++ } } } } func (testsuites *Testsuites) Complete() { testsuites.Tests = 0 testsuites.Failures = 0 testsuites.Errors = 0 testsuites.Disabled = 0 testsuites.Skipped = 0 for _, ts := range testsuites.Suites { ts.Complete() testsuites.Tests += ts.Tests testsuites.Failures += ts.Failures testsuites.Errors += ts.Errors testsuites.Disabled += ts.Disabled testsuites.Skipped += ts.Skipped } }