diff --git a/go-junit-report.go b/go-junit-report.go index 30d8145..e88a670 100644 --- a/go-junit-report.go +++ b/go-junit-report.go @@ -6,12 +6,9 @@ import ( "os" ) -type Report struct { -} - func main() { // Read input - report, err := parse(os.Stdin) + report, err := Parse(os.Stdin) if err != nil { fmt.Printf("Error reading input: %s\n", err) os.Exit(1) @@ -25,10 +22,6 @@ func main() { } } -func parse(reader io.Reader) (Report, error) { - return Report{}, nil -} - func (r Report) XML(io.Writer) error { return nil } diff --git a/go-junit-report_test.go b/go-junit-report_test.go index b5c6d9d..ea110d7 100644 --- a/go-junit-report_test.go +++ b/go-junit-report_test.go @@ -5,18 +5,85 @@ import ( "testing" ) -const testOutputPass = `=== RUN TestOne +func TestOutputPass(t *testing.T) { + testOutputPass := `=== RUN TestOne --- PASS: TestOne (0.06 seconds) === RUN TestTwo --- PASS: TestTwo (0.10 seconds) PASS ok package/name 0.160s` -func TestOutputPass(t *testing.T) { - _, err := parse(strings.NewReader(testOutputPass)) + expected := Report{ + Packages: []Package{ + { + Name: "package/name", + Time: 160, + Tests: []Test{ + { + Name: "TestOne", + Time: 60, + Result: PASS, + Output: "", + }, + { + Name: "TestTwo", + Time: 100, + Result: PASS, + Output: "", + }, + }, + }, + }, + } + + report, err := Parse(strings.NewReader(testOutputPass)) if err != nil { t.Fatalf("error parsing: %s", err) } + + if report == nil { + t.Fatalf("Report == nil") + } + + if len(report.Packages) != len(expected.Packages) { + t.Fatalf("Report packages == %d, want %d", len(report.Packages), len(expected.Packages)) + } + + for i, pkg := range report.Packages { + expPkg := expected.Packages[i] + + if pkg.Name != expPkg.Name { + t.Errorf("Package.Name == %s, want %s", pkg.Name, expPkg.Name) + } + + if pkg.Time != expPkg.Time { + t.Errorf("Package.Time == %d, want %d", pkg.Time, expPkg.Time) + } + + if len(pkg.Tests) != len(expPkg.Tests) { + t.Fatalf("Package Tests == %d, want %d", len(pkg.Tests), len(expPkg.Tests)) + } + + for j, test := range pkg.Tests { + expTest := expPkg.Tests[j] + + if test.Name != expTest.Name { + t.Errorf("Test.Name == %s, want %s", test.Name, expTest.Name) + } + + if test.Time != expTest.Time { + t.Errorf("Test.Time == %d, want %d", test.Time, expTest.Time) + } + + if test.Result != expTest.Result { + t.Errorf("Test.Result == %d, want %d", test.Result, expTest.Result) + } + + if test.Output != expTest.Output { + t.Errorf("Test.Output == %s, want %s", test.Output, expTest.Output) + } + } + } } const testOutputFail = `=== RUN TestOne @@ -32,7 +99,7 @@ exit status 1 FAIL package/name 0.151s` func TestOutputFail(t *testing.T) { - _, err := parse(strings.NewReader(testOutputPass)) + _, err := Parse(strings.NewReader(testOutputFail)) if err != nil { t.Fatalf("error parsing: %s", err) } diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..03f5d3e --- /dev/null +++ b/parser.go @@ -0,0 +1,109 @@ +package main + +import ( + "bufio" + "io" + "regexp" + "strconv" + "strings" +) + +type Result int + +const ( + PASS Result = iota + FAIL Result = iota +) + +type Report struct { + Packages []Package +} + +type Package struct { + Name string + Time int + Tests []Test +} + +type Test struct { + Name string + Time int + Result Result + Output string +} + +var ( + regexStatus = regexp.MustCompile(`^--- (PASS|FAIL): (.+) \((\d+\.\d+) seconds\)$`) + regexResult = regexp.MustCompile(`^(ok|FAIL)\s+(.+)\s(\d+\.\d+)s$`) +) + +func Parse(r io.Reader) (*Report, error) { + reader := bufio.NewReader(r) + + report := &Report{make([]Package, 0)} + + // keep track of tests we find + tests := make([]Test, 0) + + // current test + var test *Test + + // parse lines + for { + l, _, err := reader.ReadLine() + if err != nil && err == io.EOF { + break + } else if err != nil { + return nil, err + } + + line := string(l) + if test == nil { + // expecting new test or package result + if strings.HasPrefix(line, "=== RUN ") { + test = &Test{ + Name: line[8:], + } + } else if matches := regexResult.FindStringSubmatch(line); len(matches) == 4 { + report.Packages = append(report.Packages, Package{ + Name: matches[2], + Time: parseTime(matches[3]), + Tests: tests, + }) + + tests = make([]Test, 0) + } + } else { + // expecting test output or test status + if matches := regexStatus.FindStringSubmatch(line); len(matches) == 4 { + if matches[1] == "PASS" { + test.Result = PASS + } else { + test.Result = FAIL + } + + test.Name = matches[2] + test.Time = parseTime(matches[3]) * 10 + + tests = append(tests, *test) + test = nil + } else { + if len(test.Output) > 0 { + test.Output += "\n" + line + } else { + test.Output = line + } + } + } + } + + return report, nil +} + +func parseTime(time string) int { + t, err := strconv.Atoi(strings.Replace(time, ".", "", -1)) + if err != nil { + return 0 + } + return t +}