From 1a35035f3e2e7734ffbeb0ec5b1a35a7a46f620b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20L=C3=B6nnblad?= Date: Wed, 26 Feb 2020 16:15:39 -0300 Subject: [PATCH 1/2] Fixed a bug regarding JUnit time field --- features/formatter/junit.feature | 60 +++++----- fixtures/cucumber_output.json | 18 +-- fixtures/junit_output.xml | 184 +++++++++++++++---------------- fmt_junit.go | 6 +- fmt_junit_test.go | 23 ++-- 5 files changed, 145 insertions(+), 146 deletions(-) diff --git a/features/formatter/junit.feature b/features/formatter/junit.feature index 68d9ff01..0b3dbca6 100644 --- a/features/formatter/junit.feature +++ b/features/formatter/junit.feature @@ -14,9 +14,9 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - + + + """ @@ -35,9 +35,9 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - + + + """ @@ -59,10 +59,10 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - - + + + + """ @@ -88,10 +88,10 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - - + + + + """ @@ -112,9 +112,9 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - + + + @@ -141,10 +141,10 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - - + + + + @@ -167,9 +167,9 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - + + + """ @@ -191,9 +191,9 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - + + + """ @@ -216,9 +216,9 @@ Feature: JUnit XML formatter Then the rendered xml will be as follows: """ application/xml - - - + + + diff --git a/fixtures/cucumber_output.json b/fixtures/cucumber_output.json index 9113b17d..54f419dc 100644 --- a/fixtures/cucumber_output.json +++ b/fixtures/cucumber_output.json @@ -1624,7 +1624,7 @@ "name": "the rendered xml will be as follows:", "line": 14, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 15 }, @@ -1680,7 +1680,7 @@ "name": "the rendered xml will be as follows:", "line": 35, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 36 }, @@ -1736,7 +1736,7 @@ "name": "the rendered xml will be as follows:", "line": 59, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario #1\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003ctestcase name=\"simple scenario #2\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario #1\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003ctestcase name=\"simple scenario #2\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 60 }, @@ -1792,7 +1792,7 @@ "name": "the rendered xml will be as follows:", "line": 88, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario #1\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003ctestcase name=\"simple scenario #2\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"2\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario #1\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003ctestcase name=\"simple scenario #2\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 89 }, @@ -1848,7 +1848,7 @@ "name": "the rendered xml will be as follows:", "line": 112, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"failed\" time=\"0s\"\u003e\n \u003cfailure message=\"Step a failing step: intentional failure\"\u003e\u003c/failure\u003e\n \u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"failed\" time=\"0\"\u003e\n \u003cfailure message=\"Step a failing step: intentional failure\"\u003e\u003c/failure\u003e\n \u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 113 }, @@ -1904,7 +1904,7 @@ "name": "the rendered xml will be as follows:", "line": 141, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"2\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"2\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario #1\" status=\"passed\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003ctestcase name=\"simple scenario #2\" status=\"failed\" time=\"0s\"\u003e\n \u003cfailure message=\"Step failing step: intentional failure\"\u003e\u003c/failure\u003e\n \u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"2\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"2\" skipped=\"0\" failures=\"1\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario #1\" status=\"passed\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003ctestcase name=\"simple scenario #2\" status=\"failed\" time=\"0\"\u003e\n \u003cfailure message=\"Step failing step: intentional failure\"\u003e\u003c/failure\u003e\n \u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 142 }, @@ -1960,7 +1960,7 @@ "name": "the rendered xml will be as follows:", "line": 167, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 168 }, @@ -2016,7 +2016,7 @@ "name": "the rendered xml will be as follows:", "line": 191, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"passed\" time=\"0s\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"0\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"passed\" time=\"0\"\u003e\u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 192 }, @@ -2072,7 +2072,7 @@ "name": "the rendered xml will be as follows:", "line": 216, "doc_string": { - "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"1\" time=\"0s\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"1\" time=\"0s\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"undefined\" time=\"0s\"\u003e\n \u003cerror message=\"Step pending step: TODO: write pending definition\" type=\"pending\"\u003e\u003c/error\u003e\n \u003cerror message=\"Step undefined\" type=\"undefined\"\u003e\u003c/error\u003e\n \u003cerror message=\"Step passing step\" type=\"skipped\"\u003e\u003c/error\u003e\n \u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", + "value": " \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003ctestsuites name=\"godog\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"1\" time=\"0\"\u003e\n \u003ctestsuite name=\"simple feature\" tests=\"1\" skipped=\"0\" failures=\"0\" errors=\"1\" time=\"0\"\u003e\n \u003ctestcase name=\"simple scenario\" status=\"undefined\" time=\"0\"\u003e\n \u003cerror message=\"Step pending step: TODO: write pending definition\" type=\"pending\"\u003e\u003c/error\u003e\n \u003cerror message=\"Step undefined\" type=\"undefined\"\u003e\u003c/error\u003e\n \u003cerror message=\"Step passing step\" type=\"skipped\"\u003e\u003c/error\u003e\n \u003c/testcase\u003e\n \u003c/testsuite\u003e\n \u003c/testsuites\u003e", "content_type": "application/xml", "line": 217 }, diff --git a/fixtures/junit_output.xml b/fixtures/junit_output.xml index c1f0d806..cc036828 100644 --- a/fixtures/junit_output.xml +++ b/fixtures/junit_output.xml @@ -1,107 +1,107 @@ - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - + + \ No newline at end of file diff --git a/fmt_junit.go b/fmt_junit.go index 20148895..fc43fe9b 100644 --- a/fmt_junit.go +++ b/fmt_junit.go @@ -123,7 +123,7 @@ func buildJUNITPackageSuite(suiteName string, startedAt time.Time, features []*f suite := junitPackageSuite{ Name: suiteName, TestSuites: make([]*junitTestSuite, len(features)), - Time: timeNowFunc().Sub(startedAt).String(), + Time: fmt.Sprintf("%.f", timeNowFunc().Sub(startedAt).Seconds()), } sort.Sort(sortByName(features)) @@ -131,14 +131,14 @@ func buildJUNITPackageSuite(suiteName string, startedAt time.Time, features []*f for idx, feat := range features { ts := junitTestSuite{ Name: feat.Name, - Time: feat.finishedAt().Sub(feat.startedAt()).String(), + Time: fmt.Sprintf("%.f", feat.finishedAt().Sub(feat.startedAt()).Seconds()), TestCases: make([]*junitTestCase, len(feat.Scenarios)), } for idx, scenario := range feat.Scenarios { tc := junitTestCase{} tc.Name = scenario.Name - tc.Time = scenario.finishedAt().Sub(scenario.startedAt()).String() + tc.Time = fmt.Sprintf("%.f", scenario.finishedAt().Sub(scenario.startedAt()).Seconds()) ts.Tests++ suite.Tests++ diff --git a/fmt_junit_test.go b/fmt_junit_test.go index 30669805..137923c2 100644 --- a/fmt_junit_test.go +++ b/fmt_junit_test.go @@ -7,7 +7,6 @@ import ( "io" "strings" "testing" - "time" "github.com/cucumber/godog/colors" "github.com/cucumber/godog/gherkin" @@ -70,31 +69,31 @@ func TestJUnitFormatterOutput(t *testing.T) { s.Step(`^failing$`, func() error { return fmt.Errorf("errored") }) s.Step(`^pending$`, func() error { return ErrPending }) - var zeroDuration time.Duration + const zeroDuration = "0" expected := junitPackageSuite{ Name: "junit", Tests: 8, Skipped: 0, Failures: 2, Errors: 4, - Time: zeroDuration.String(), + Time: zeroDuration, TestSuites: []*junitTestSuite{{ Name: "junit formatter", Tests: 8, Skipped: 0, Failures: 2, Errors: 4, - Time: zeroDuration.String(), + Time: zeroDuration, TestCases: []*junitTestCase{ { Name: "passing scenario", Status: "passed", - Time: zeroDuration.String(), + Time: zeroDuration, }, { Name: "failing scenario", Status: "failed", - Time: zeroDuration.String(), + Time: zeroDuration, Failure: &junitFailure{ Message: "Step failing: errored", }, @@ -105,7 +104,7 @@ func TestJUnitFormatterOutput(t *testing.T) { { Name: "pending scenario", Status: "pending", - Time: zeroDuration.String(), + Time: zeroDuration, Error: []*junitError{ {Message: "Step pending: TODO: write pending definition", Type: "pending"}, {Message: "Step passing", Type: "skipped"}, @@ -114,7 +113,7 @@ func TestJUnitFormatterOutput(t *testing.T) { { Name: "undefined scenario", Status: "undefined", - Time: zeroDuration.String(), + Time: zeroDuration, Error: []*junitError{ {Message: "Step undefined", Type: "undefined"}, {Message: "Step next undefined", Type: "undefined"}, @@ -123,12 +122,12 @@ func TestJUnitFormatterOutput(t *testing.T) { { Name: "outline #1", Status: "passed", - Time: zeroDuration.String(), + Time: zeroDuration, }, { Name: "outline #2", Status: "failed", - Time: zeroDuration.String(), + Time: zeroDuration, Failure: &junitFailure{ Message: "Step failing: errored", }, @@ -136,7 +135,7 @@ func TestJUnitFormatterOutput(t *testing.T) { { Name: "outline #3", Status: "pending", - Time: zeroDuration.String(), + Time: zeroDuration, Error: []*junitError{ {Message: "Step pending: TODO: write pending definition", Type: "pending"}, }, @@ -144,7 +143,7 @@ func TestJUnitFormatterOutput(t *testing.T) { { Name: "outline #4", Status: "undefined", - Time: zeroDuration.String(), + Time: zeroDuration, Error: []*junitError{ {Message: "Step undefined", Type: "undefined"}, }, From 7565a32d2124ba7468ac07d05a7a0badfe305a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20L=C3=B6nnblad?= Date: Wed, 26 Feb 2020 17:24:04 -0300 Subject: [PATCH 2/2] Fixed an issue with missing decimals in JUnit --- fmt_junit.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fmt_junit.go b/fmt_junit.go index fc43fe9b..22f6772f 100644 --- a/fmt_junit.go +++ b/fmt_junit.go @@ -6,6 +6,7 @@ import ( "io" "os" "sort" + "strconv" "sync" "time" @@ -119,11 +120,15 @@ func (f *junitFormatter) Copy(cf ConcurrentFormatter) { } } +func junitTimeDuration(from, to time.Time) string { + return strconv.FormatFloat(to.Sub(from).Seconds(), 'f', -1, 64) +} + func buildJUNITPackageSuite(suiteName string, startedAt time.Time, features []*feature) junitPackageSuite { suite := junitPackageSuite{ Name: suiteName, TestSuites: make([]*junitTestSuite, len(features)), - Time: fmt.Sprintf("%.f", timeNowFunc().Sub(startedAt).Seconds()), + Time: junitTimeDuration(startedAt, timeNowFunc()), } sort.Sort(sortByName(features)) @@ -131,14 +136,15 @@ func buildJUNITPackageSuite(suiteName string, startedAt time.Time, features []*f for idx, feat := range features { ts := junitTestSuite{ Name: feat.Name, - Time: fmt.Sprintf("%.f", feat.finishedAt().Sub(feat.startedAt()).Seconds()), + Time: junitTimeDuration(feat.startedAt(), feat.finishedAt()), TestCases: make([]*junitTestCase, len(feat.Scenarios)), } for idx, scenario := range feat.Scenarios { - tc := junitTestCase{} - tc.Name = scenario.Name - tc.Time = fmt.Sprintf("%.f", scenario.finishedAt().Sub(scenario.startedAt()).Seconds()) + tc := junitTestCase{ + Name: scenario.Name, + Time: junitTimeDuration(scenario.startedAt(), scenario.finishedAt()), + } ts.Tests++ suite.Tests++