From c9c0e1877cf525588dda192686c757e9e456c765 Mon Sep 17 00:00:00 2001 From: Joel Stemmer Date: Fri, 9 Mar 2012 17:51:34 +0100 Subject: [PATCH] Write JUnit report xml Add tests --- go-junit-report.go | 7 +-- go-junit-report_test.go | 39 ++++++++++++++--- junit-formatter.go | 97 +++++++++++++++++++++++++++++++++++++++++ tests/01-report.xml | 5 +++ tests/02-report.xml | 7 +++ 5 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 junit-formatter.go create mode 100644 tests/01-report.xml create mode 100644 tests/02-report.xml diff --git a/go-junit-report.go b/go-junit-report.go index e88a670..309c964 100644 --- a/go-junit-report.go +++ b/go-junit-report.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "io" "os" ) @@ -15,13 +14,9 @@ func main() { } // Write xml - err = report.XML(os.Stdout) + err = JUnitReportXML(report, os.Stdout) if err != nil { fmt.Printf("Error writing XML: %s\n", err) os.Exit(1) } } - -func (r Report) XML(io.Writer) error { - return nil -} diff --git a/go-junit-report_test.go b/go-junit-report_test.go index 7aa2c02..886b379 100644 --- a/go-junit-report_test.go +++ b/go-junit-report_test.go @@ -1,19 +1,23 @@ package main import ( + "bytes" + "io/ioutil" "os" "testing" ) type TestCase struct { - name string - expectedReport Report + name string + reportName string + report *Report } var testCases []TestCase = []TestCase{ { - name: "01-pass.txt", - expectedReport: Report{ + name: "01-pass.txt", + reportName: "01-report.xml", + report: &Report{ Packages: []Package{ { Name: "package/name", @@ -37,8 +41,9 @@ var testCases []TestCase = []TestCase{ }, }, { - name: "02-fail.txt", - expectedReport: Report{ + name: "02-fail.txt", + reportName: "02-report.xml", + report: &Report{ Packages: []Package{ { Name: "package/name", @@ -79,7 +84,7 @@ func TestParser(t *testing.T) { t.Fatalf("Report == nil") } - expected := testCase.expectedReport + expected := testCase.report if len(report.Packages) != len(expected.Packages) { t.Fatalf("Report packages == %d, want %d", len(report.Packages), len(expected.Packages)) } @@ -121,3 +126,23 @@ func TestParser(t *testing.T) { } } } + +func TestJUnitFormatter(t *testing.T) { + for _, testCase := range testCases { + file, err := ioutil.ReadFile("tests/" + testCase.reportName) + if err != nil { + t.Fatal(err) + } + + var junitReport bytes.Buffer + + err = JUnitReportXML(testCase.report, &junitReport) + if err != nil { + t.Fatal(err) + } + + if string(junitReport.Bytes()) != string(file) { + t.Fatalf("Report xml ==\n%s, want\n%s", string(junitReport.Bytes()), string(file)) + } + } +} diff --git a/junit-formatter.go b/junit-formatter.go new file mode 100644 index 0000000..da7bb13 --- /dev/null +++ b/junit-formatter.go @@ -0,0 +1,97 @@ +package main + +import ( + "bufio" + "encoding/xml" + "fmt" + "io" + "strings" +) + +type JUnitTestSuite struct { + XMLName xml.Name `xml:"testsuite"` + Tests int `xml:"tests,attr"` + Failures int `xml:"failures,attr"` + Time string `xml:"time,attr"` + Name string `xml:"name,attr"` + TestCases []JUnitTestCase +} + +type JUnitTestCase struct { + XMLName xml.Name `xml:"testcase"` + Classname string `xml:"classname,attr"` + Name string `xml:"name,attr"` + Time string `xml:"time,attr"` + Failure *string `xml:"failure"` +} + +func JUnitReportXML(report *Report, w io.Writer) error { + suites := []JUnitTestSuite{} + + // convert Report to JUnit test suites + for _, pkg := range report.Packages { + ts := JUnitTestSuite{ + Tests: len(pkg.Tests), + Failures: 0, + Time: formatTime(pkg.Time), + Name: pkg.Name, + TestCases: []JUnitTestCase{}, + } + + classname := pkg.Name + if idx := strings.LastIndex(classname, "/"); idx > -1 && idx < len(pkg.Name) { + classname = pkg.Name[idx+1:] + } + + // individual test cases + for _, test := range pkg.Tests { + testCase := JUnitTestCase{ + Classname: classname, + Name: test.Name, + Time: formatTime(test.Time), + Failure: nil, + } + + if test.Result == FAIL { + ts.Failures += 1 + + // TODO: set error message + msg := "" + testCase.Failure = &msg + } + + ts.TestCases = append(ts.TestCases, testCase) + } + + suites = append(suites, ts) + } + + // to xml + bytes, err := xml.MarshalIndent(suites, "", "\t") + if err != nil { + return err + } + + writer := bufio.NewWriter(w) + + // remove newline from xml.Header, because xml.MarshalIndent starts with a newline + writer.WriteString(xml.Header[:len(xml.Header)-1]) + writer.Write(bytes) + writer.WriteByte('\n') + writer.Flush() + + return nil +} + +func countFailures(tests []Test) (result int) { + for _, test := range tests { + if test.Result == FAIL { + result += 1 + } + } + return +} + +func formatTime(time int) string { + return fmt.Sprintf("%.3f", float64(time)/1000.0) +} diff --git a/tests/01-report.xml b/tests/01-report.xml new file mode 100644 index 0000000..2729148 --- /dev/null +++ b/tests/01-report.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/02-report.xml b/tests/02-report.xml new file mode 100644 index 0000000..80933bc --- /dev/null +++ b/tests/02-report.xml @@ -0,0 +1,7 @@ + + + + + + +