package main import ( "encoding/xml" "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 []*Test `xml:"testsuite,omitempty"` } type Test struct { XMLName xml.Name `xml:"testsuite"` // required attributes Name string `xml:"name,attr"` TestCount 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 float64 `xml:"time,attr"` Timestamp time.Time `xml:"timestamp,attr,omitempty"` Tests []*Test `xml:"testsuite,omitempty"` SystemOut string `xml:"system-out,omitempty"` hasTests bool parent *Test t0 time.Time } 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"` } // Looks for a test in root func (testsuites *Testsuites) getRootSuite(t time.Time, pkg string, create bool) *Test { for _, suite := range testsuites.Suites { if suite.Name == pkg { return suite } } if !create { return nil } suite := Test{ Name: pkg, Skipped: 0, Timestamp: t, t0: t, } testsuites.Suites = append(testsuites.Suites, &suite) return &suite } func (suite *Test) getSuite(t time.Time, name string) *Test { for _, s := range suite.Tests { if s.Name == suite.Name+"/"+name { return s } } s := Test{ Name: suite.Name + "/" + name, Timestamp: t, t0: t, } suite.Tests = append(suite.Tests, &s) return &s } func (suite *Test) getTest(t time.Time, testname string) *Test { if testname == "" { return suite } suitename := suite.Name path := strings.Split(testname, "/") for i := 0; i < len(path); i++ { suite = suite.getSuite(t, path[i]) suitename = suitename + "/" + path[i] } return suite } func (testsuites *Testsuites) getTest(t time.Time, pkg string, testname string) *Test { suite := testsuites.getRootSuite(t, pkg, true) test := suite.getTest(t, testname) return test } func (testsuites *Testsuites) Start(t time.Time, pkg string) { testsuites.getRootSuite(t, pkg, true) } func (testsuites *Testsuites) Test(t time.Time, pkg string, test string) { // This can be a test suite as well testobj := testsuites.getTest(t, pkg, test) testobj.hasTests = true } func (testsuites *Testsuites) Output(t time.Time, pkg string, test string, output string) { tc := testsuites.getTest(t, pkg, test) tc.SystemOut = tc.SystemOut + output } func (testsuites *Testsuites) Pass(t time.Time, pkg string, test string) { tc := testsuites.getTest(t, pkg, test) tc.Time = float64(t.Sub(tc.t0).Nanoseconds()) / 1000_000_000.0 } func (testsuites *Testsuites) Bench(t time.Time, pkg string, test string, output string) { tc := testsuites.getTest(t, pkg, test) tc.SystemOut = tc.SystemOut + output + "\n" } func (testsuites *Testsuites) Fail(t time.Time, pkg string, test string) { tc := testsuites.getTest(t, pkg, test) tc.Time = float64(t.Sub(tc.t0).Nanoseconds()) / 1000_000_000.0 tc.Failures = 1 } func (testsuites *Testsuites) Skip(t time.Time, pkg string, test string) { tc := testsuites.getTest(t, pkg, test) tc.Time = float64(t.Sub(tc.t0).Nanoseconds()) / 1000_000_000.0 tc.Skipped = 1 } func (suite *Test) Complete() { suite.TestCount = 0 if len(suite.Tests) > 0 { suite.Failures = 0 suite.Errors = 0 suite.Disabled = 0 suite.Skipped = 0 } if len(suite.Tests) == 0 && suite.hasTests { suite.TestCount = 1 } for _, ts := range suite.Tests { ts.Complete() suite.TestCount += ts.TestCount suite.Failures += ts.Failures suite.Errors += ts.Errors suite.Disabled += ts.Disabled suite.Skipped += ts.Skipped ts.parent = suite } } 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.TestCount testsuites.Failures += ts.Failures testsuites.Errors += ts.Errors testsuites.Disabled += ts.Disabled testsuites.Skipped += ts.Skipped } }