From dbd8cdf723fd5aa1a1701854cbbbae931da3d4ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20L=C3=B6nnblad?= Date: Sat, 27 Jun 2020 18:59:14 +0200 Subject: [PATCH] Removed deprecated code --- fmt.go | 11 - fmt_output_test.go | 19 +- fmt_progress_test.go | 62 +- formatter-tests/cucumber/scenario_outline | 30 +- .../cucumber/scenario_with_background | 8 +- .../single_scenario_with_passing_step | 2 +- .../some_scenarions_including_failing | 10 +- .../two_scenarios_with_background_fail | 14 +- formatter-tests/events/scenario_outline | 30 +- .../events/scenario_with_background | 8 +- .../events/single_scenario_with_passing_step | 2 +- .../events/some_scenarions_including_failing | 12 +- .../events/two_scenarios_with_background_fail | 14 +- formatter-tests/pretty/scenario_outline | 6 +- .../pretty/scenario_with_background | 8 +- .../pretty/single_scenario_with_passing_step | 2 +- .../pretty/some_scenarions_including_failing | 12 +- .../pretty/two_scenarios_with_background_fail | 10 +- run.go | 196 +----- run_test.go | 142 ++-- suite.go | 233 +------ suite_context.go | 632 ------------------ suite_context_test.go | 71 +- suite_test.go | 6 - test_context.go | 64 +- 25 files changed, 309 insertions(+), 1295 deletions(-) delete mode 100644 suite_context.go delete mode 100644 suite_test.go diff --git a/fmt.go b/fmt.go index 5327d01c..ee4dab4f 100644 --- a/fmt.go +++ b/fmt.go @@ -75,17 +75,6 @@ type Formatter interface { Summary() } -// ConcurrentFormatter is an interface for a Concurrent -// version of the Formatter interface. -// -// Deprecated: The formatters need to handle concurrency -// instead of being copied and synchronized for each thread. -type ConcurrentFormatter interface { - Formatter - Copy(ConcurrentFormatter) - Sync(ConcurrentFormatter) -} - type storageFormatter interface { setStorage(*storage) } diff --git a/fmt_output_test.go b/fmt_output_test.go index 4d7e8352..329676e5 100644 --- a/fmt_output_test.go +++ b/fmt_output_test.go @@ -60,13 +60,6 @@ func listFmtOutputTestsFeatureFiles() (featureFiles []string, err error) { } func fmtOutputTest(fmtName, testName, featureFilePath string) func(*testing.T) { - fmtOutputSuiteInitializer := func(s *godog.Suite) { - s.Step(`^(?:a )?failing step`, failingStepDef) - s.Step(`^(?:a )?pending step$`, pendingStepDef) - s.Step(`^(?:a )?passing step$`, passingStepDef) - s.Step(`^odd (\d+) and even (\d+) number$`, oddEvenStepDef) - } - fmtOutputScenarioInitializer := func(ctx *godog.ScenarioContext) { ctx.Step(`^(?:a )?failing step`, failingStepDef) ctx.Step(`^(?:a )?pending step$`, pendingStepDef) @@ -93,22 +86,14 @@ func fmtOutputTest(fmtName, testName, featureFilePath string) func(*testing.T) { Output: out, } - godog.RunWithOptions(fmtName, fmtOutputSuiteInitializer, opts) - - expected := string(expectedOutput) - actual := buf.String() - assert.Equalf(t, expected, actual, "path: %s", expectOutputPath) - - buf.Reset() - godog.TestSuite{ Name: fmtName, ScenarioInitializer: fmtOutputScenarioInitializer, Options: &opts, }.Run() - expected = string(expectedOutput) - actual = buf.String() + expected := string(expectedOutput) + actual := buf.String() assert.Equalf(t, expected, actual, "path: %s", expectOutputPath) } } diff --git a/fmt_progress_test.go b/fmt_progress_test.go index 454d2321..a2b281c6 100644 --- a/fmt_progress_test.go +++ b/fmt_progress_test.go @@ -21,7 +21,7 @@ Feature: basic Then two ` -func TestProgressFormatterWhenStepPanics(t *testing.T) { +func Test_ProgressFormatterWhenStepPanics(t *testing.T) { const path = "any.feature" gd, err := gherkin.ParseGherkinDocument(strings.NewReader(basicGherkinFeature), (&messages.Incrementing{}).NewId) @@ -36,9 +36,9 @@ func TestProgressFormatterWhenStepPanics(t *testing.T) { r := runner{ fmt: progressFunc("progress", w), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^one$`, func() error { return nil }) - s.Step(`^two$`, func() error { panic("omg") }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^two$`, func() error { panic("omg") }) }, } @@ -48,14 +48,14 @@ func TestProgressFormatterWhenStepPanics(t *testing.T) { r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) }) + failed := r.concurrent(1) require.True(t, failed) actual := buf.String() assert.Contains(t, actual, "godog/fmt_progress_test.go:41") } -func TestProgressFormatterWithPanicInMultistep(t *testing.T) { +func Test_ProgressFormatterWithPanicInMultistep(t *testing.T) { const path = "any.feature" gd, err := gherkin.ParseGherkinDocument(strings.NewReader(basicGherkinFeature), (&messages.Incrementing{}).NewId) @@ -70,12 +70,12 @@ func TestProgressFormatterWithPanicInMultistep(t *testing.T) { r := runner{ fmt: progressFunc("progress", w), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^sub1$`, func() error { return nil }) - s.Step(`^sub-sub$`, func() error { return nil }) - s.Step(`^sub2$`, func() []string { return []string{"sub-sub", "sub1", "one"} }) - s.Step(`^one$`, func() error { return nil }) - s.Step(`^two$`, func() []string { return []string{"sub1", "sub2"} }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^sub1$`, func() error { return nil }) + ctx.Step(`^sub-sub$`, func() error { return nil }) + ctx.Step(`^sub2$`, func() []string { return []string{"sub-sub", "sub1", "one"} }) + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^two$`, func() []string { return []string{"sub1", "sub2"} }) }, } @@ -85,11 +85,11 @@ func TestProgressFormatterWithPanicInMultistep(t *testing.T) { r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) }) + failed := r.concurrent(1) require.True(t, failed) } -func TestProgressFormatterMultistepTemplates(t *testing.T) { +func Test_ProgressFormatterMultistepTemplates(t *testing.T) { const path = "any.feature" gd, err := gherkin.ParseGherkinDocument(strings.NewReader(basicGherkinFeature), (&messages.Incrementing{}).NewId) @@ -104,11 +104,11 @@ func TestProgressFormatterMultistepTemplates(t *testing.T) { r := runner{ fmt: progressFunc("progress", w), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^sub-sub$`, func() error { return nil }) - s.Step(`^substep$`, func() Steps { return Steps{"sub-sub", `unavailable "John" cost 5`, "one", "three"} }) - s.Step(`^one$`, func() error { return nil }) - s.Step(`^(t)wo$`, func(s string) Steps { return Steps{"undef", "substep"} }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^sub-sub$`, func() error { return nil }) + ctx.Step(`^substep$`, func() Steps { return Steps{"sub-sub", `unavailable "John" cost 5`, "one", "three"} }) + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^(t)wo$`, func(s string) Steps { return Steps{"undef", "substep"} }) }, } @@ -118,7 +118,7 @@ func TestProgressFormatterMultistepTemplates(t *testing.T) { r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) }) + failed := r.concurrent(1) require.False(t, failed) expected := `.U 2 @@ -154,7 +154,7 @@ func FeatureContext(s *godog.Suite) { assert.Equal(t, expected, actual) } -func TestProgressFormatterWhenMultiStepHasArgument(t *testing.T) { +func Test_ProgressFormatterWhenMultiStepHasArgument(t *testing.T) { const path = "any.feature" var featureSource = ` @@ -180,9 +180,9 @@ Feature: basic r := runner{ fmt: progressFunc("progress", w), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^one$`, func() error { return nil }) - s.Step(`^two:$`, func(doc *messages.PickleStepArgument_PickleDocString) Steps { return Steps{"one"} }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^two:$`, func(doc *messages.PickleStepArgument_PickleDocString) Steps { return Steps{"one"} }) }, } @@ -192,11 +192,11 @@ Feature: basic r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) }) + failed := r.concurrent(1) require.False(t, failed) } -func TestProgressFormatterWhenMultiStepHasStepWithArgument(t *testing.T) { +func Test_ProgressFormatterWhenMultiStepHasStepWithArgument(t *testing.T) { const path = "any.feature" var featureSource = ` @@ -223,10 +223,10 @@ Feature: basic r := runner{ fmt: progressFunc("progress", w), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^one$`, func() error { return nil }) - s.Step(`^two$`, func() Steps { return Steps{subStep} }) - s.Step(`^three:$`, func(doc *messages.PickleStepArgument_PickleDocString) error { return nil }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^two$`, func() Steps { return Steps{subStep} }) + ctx.Step(`^three:$`, func(doc *messages.PickleStepArgument_PickleDocString) error { return nil }) }, } @@ -236,7 +236,7 @@ Feature: basic r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) }) + failed := r.concurrent(1) require.True(t, failed) expected := `.F 2 diff --git a/formatter-tests/cucumber/scenario_outline b/formatter-tests/cucumber/scenario_outline index 295188c4..5b442522 100644 --- a/formatter-tests/cucumber/scenario_outline +++ b/formatter-tests/cucumber/scenario_outline @@ -48,7 +48,7 @@ "name": "passing step", "line": 13, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -60,7 +60,7 @@ "name": "passing step", "line": 13, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -72,7 +72,7 @@ "name": "odd 1 and even 2 number", "line": 13, "match": { - "location": "fmt_output_test.go:118" + "location": "fmt_output_test.go:103" }, "result": { "status": "passed", @@ -112,7 +112,7 @@ "name": "passing step", "line": 14, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -124,7 +124,7 @@ "name": "passing step", "line": 14, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -136,7 +136,7 @@ "name": "odd 2 and even 0 number", "line": 14, "match": { - "location": "fmt_output_test.go:118" + "location": "fmt_output_test.go:103" }, "result": { "status": "failed", @@ -177,7 +177,7 @@ "name": "passing step", "line": 15, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -189,7 +189,7 @@ "name": "passing step", "line": 15, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -201,7 +201,7 @@ "name": "odd 3 and even 11 number", "line": 15, "match": { - "location": "fmt_output_test.go:118" + "location": "fmt_output_test.go:103" }, "result": { "status": "failed", @@ -242,7 +242,7 @@ "name": "passing step", "line": 20, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -254,7 +254,7 @@ "name": "passing step", "line": 20, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -266,7 +266,7 @@ "name": "odd 1 and even 14 number", "line": 20, "match": { - "location": "fmt_output_test.go:118" + "location": "fmt_output_test.go:103" }, "result": { "status": "passed", @@ -306,7 +306,7 @@ "name": "passing step", "line": 21, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -318,7 +318,7 @@ "name": "passing step", "line": 21, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -330,7 +330,7 @@ "name": "odd 3 and even 9 number", "line": 21, "match": { - "location": "fmt_output_test.go:118" + "location": "fmt_output_test.go:103" }, "result": { "status": "failed", diff --git a/formatter-tests/cucumber/scenario_with_background b/formatter-tests/cucumber/scenario_with_background index f5362ef5..b6248dbc 100644 --- a/formatter-tests/cucumber/scenario_with_background +++ b/formatter-tests/cucumber/scenario_with_background @@ -20,7 +20,7 @@ "name": "passing step", "line": 4, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -32,7 +32,7 @@ "name": "passing step", "line": 5, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -44,7 +44,7 @@ "name": "passing step", "line": 8, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -56,7 +56,7 @@ "name": "passing step", "line": 9, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", diff --git a/formatter-tests/cucumber/single_scenario_with_passing_step b/formatter-tests/cucumber/single_scenario_with_passing_step index f1a676e8..0a98c048 100644 --- a/formatter-tests/cucumber/single_scenario_with_passing_step +++ b/formatter-tests/cucumber/single_scenario_with_passing_step @@ -20,7 +20,7 @@ "name": "a passing step", "line": 7, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", diff --git a/formatter-tests/cucumber/some_scenarions_including_failing b/formatter-tests/cucumber/some_scenarions_including_failing index 02544281..a1864e13 100644 --- a/formatter-tests/cucumber/some_scenarions_including_failing +++ b/formatter-tests/cucumber/some_scenarions_including_failing @@ -20,7 +20,7 @@ "name": "passing step", "line": 4, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -32,7 +32,7 @@ "name": "failing step", "line": 5, "match": { - "location": "fmt_output_test.go:132" + "location": "fmt_output_test.go:117" }, "result": { "status": "failed", @@ -45,7 +45,7 @@ "name": "passing step", "line": 6, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "skipped" @@ -77,7 +77,7 @@ "name": "passing step", "line": 10, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "skipped" @@ -109,7 +109,7 @@ "name": "passing step", "line": 14, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "skipped" diff --git a/formatter-tests/cucumber/two_scenarios_with_background_fail b/formatter-tests/cucumber/two_scenarios_with_background_fail index 52b99f80..d4f25c3d 100644 --- a/formatter-tests/cucumber/two_scenarios_with_background_fail +++ b/formatter-tests/cucumber/two_scenarios_with_background_fail @@ -20,7 +20,7 @@ "name": "passing step", "line": 4, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -32,7 +32,7 @@ "name": "failing step", "line": 5, "match": { - "location": "fmt_output_test.go:132" + "location": "fmt_output_test.go:117" }, "result": { "status": "failed", @@ -45,7 +45,7 @@ "name": "passing step", "line": 8, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "skipped" @@ -56,7 +56,7 @@ "name": "passing step", "line": 9, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "skipped" @@ -77,7 +77,7 @@ "name": "passing step", "line": 4, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "passed", @@ -89,7 +89,7 @@ "name": "failing step", "line": 5, "match": { - "location": "fmt_output_test.go:132" + "location": "fmt_output_test.go:117" }, "result": { "status": "failed", @@ -102,7 +102,7 @@ "name": "passing step", "line": 12, "match": { - "location": "fmt_output_test.go:116" + "location": "fmt_output_test.go:101" }, "result": { "status": "skipped" diff --git a/formatter-tests/events/scenario_outline b/formatter-tests/events/scenario_outline index 54271a6c..bfb9dc66 100644 --- a/formatter-tests/events/scenario_outline +++ b/formatter-tests/events/scenario_outline @@ -1,57 +1,57 @@ {"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"} {"event":"TestSource","location":"formatter-tests/features/scenario_outline.feature:2","source":"@outline @tag\nFeature: outline\n\n @scenario\n Scenario Outline: outline\n Given passing step\n When passing step\n Then odd \u003codd\u003e and even \u003ceven\u003e number\n\n @tagged\n Examples: tagged\n | odd | even |\n | 1 | 2 |\n | 2 | 0 |\n | 3 | 11 |\n\n @tag2\n Examples:\n | odd | even |\n | 1 | 14 |\n | 3 | 9 |\n"} {"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:13","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:118 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"passed"} {"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:13","timestamp":-6795364578871,"status":"passed"} {"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:14","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:118 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"2 is not odd"} {"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:14","timestamp":-6795364578871,"status":"failed"} {"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:15","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:118 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"11 is not even"} {"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:15","timestamp":-6795364578871,"status":"failed"} {"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:20","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:118 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"passed"} {"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:20","timestamp":-6795364578871,"status":"passed"} {"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:21","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:118 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"9 is not even"} {"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:21","timestamp":-6795364578871,"status":"failed"} diff --git a/formatter-tests/events/scenario_with_background b/formatter-tests/events/scenario_with_background index 815b88d6..629e76a0 100644 --- a/formatter-tests/events/scenario_with_background +++ b/formatter-tests/events/scenario_with_background @@ -1,16 +1,16 @@ {"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"} {"event":"TestSource","location":"formatter-tests/features/scenario_with_background.feature:1","source":"Feature: single scenario with background\n\n Background: named\n Given passing step\n And passing step\n\n Scenario: scenario\n When passing step\n Then passing step\n"} {"event":"TestCaseStarted","location":"formatter-tests/features/scenario_with_background.feature:7","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:4","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:4","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:4","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:5","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:5","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:5","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:5","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:8","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:8","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:8","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:9","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:9","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:9","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:9","timestamp":-6795364578871,"status":"passed"} {"event":"TestCaseFinished","location":"formatter-tests/features/scenario_with_background.feature:7","timestamp":-6795364578871,"status":"passed"} diff --git a/formatter-tests/events/single_scenario_with_passing_step b/formatter-tests/events/single_scenario_with_passing_step index db1b5789..b487e601 100644 --- a/formatter-tests/events/single_scenario_with_passing_step +++ b/formatter-tests/events/single_scenario_with_passing_step @@ -1,7 +1,7 @@ {"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"} {"event":"TestSource","location":"formatter-tests/features/single_scenario_with_passing_step.feature:1","source":"Feature: single passing scenario\n describes\n a single scenario\n feature\n\n Scenario: one step passing\n Given a passing step\n"} {"event":"TestCaseStarted","location":"formatter-tests/features/single_scenario_with_passing_step.feature:6","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","timestamp":-6795364578871,"status":"passed"} {"event":"TestCaseFinished","location":"formatter-tests/features/single_scenario_with_passing_step.feature:6","timestamp":-6795364578871,"status":"passed"} diff --git a/formatter-tests/events/some_scenarions_including_failing b/formatter-tests/events/some_scenarions_including_failing index e159e225..d4bee676 100644 --- a/formatter-tests/events/some_scenarions_including_failing +++ b/formatter-tests/events/some_scenarions_including_failing @@ -1,28 +1,28 @@ {"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"} {"event":"TestSource","location":"formatter-tests/features/some_scenarions_including_failing.feature:1","source":"Feature: some scenarios\n\n Scenario: failing\n Given passing step\n When failing step\n Then passing step\n\n Scenario: pending\n When pending step\n Then passing step\n\n Scenario: undefined\n When undefined\n Then passing step\n"} {"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","definition_id":"fmt_output_test.go:132 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871,"status":"skipped"} {"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871,"status":"failed"} {"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","definition_id":"fmt_output_test.go:130 -\u003e github.com/cucumber/godog_test.pendingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","definition_id":"fmt_output_test.go:115 -\u003e github.com/cucumber/godog_test.pendingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871,"status":"pending"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871,"status":"skipped"} {"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871,"status":"pending"} {"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871,"status":"undefined"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871,"status":"skipped"} {"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871,"status":"undefined"} diff --git a/formatter-tests/events/two_scenarios_with_background_fail b/formatter-tests/events/two_scenarios_with_background_fail index 8973ac9c..faa05b6a 100644 --- a/formatter-tests/events/two_scenarios_with_background_fail +++ b/formatter-tests/events/two_scenarios_with_background_fail @@ -1,27 +1,27 @@ {"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"} {"event":"TestSource","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:1","source":"Feature: two scenarios with background fail\n\n Background:\n Given passing step\n And failing step\n\n Scenario: one\n When passing step\n Then passing step\n\n Scenario: two\n Then passing step\n"} {"event":"TestCaseStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:7","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:132 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","timestamp":-6795364578871,"status":"skipped"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","timestamp":-6795364578871,"status":"skipped"} {"event":"TestCaseFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:7","timestamp":-6795364578871,"status":"failed"} {"event":"TestCaseStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:11","timestamp":-6795364578871} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871,"status":"passed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:132 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"} -{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","definition_id":"fmt_output_test.go:116 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} +{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]} {"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","timestamp":-6795364578871} {"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","timestamp":-6795364578871,"status":"skipped"} {"event":"TestCaseFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:11","timestamp":-6795364578871,"status":"failed"} diff --git a/formatter-tests/pretty/scenario_outline b/formatter-tests/pretty/scenario_outline index f66bd5de..372412e1 100644 --- a/formatter-tests/pretty/scenario_outline +++ b/formatter-tests/pretty/scenario_outline @@ -1,9 +1,9 @@ Feature: outline Scenario Outline: outline # formatter-tests/features/scenario_outline.feature:5 - Given passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - When passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - Then odd and even number # fmt_output_test.go:118 -> github.com/cucumber/godog_test.oddEvenStepDef + Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + Then odd and even number # fmt_output_test.go:103 -> github.com/cucumber/godog_test.oddEvenStepDef Examples: tagged | odd | even | diff --git a/formatter-tests/pretty/scenario_with_background b/formatter-tests/pretty/scenario_with_background index f65cc06a..22c75e39 100644 --- a/formatter-tests/pretty/scenario_with_background +++ b/formatter-tests/pretty/scenario_with_background @@ -1,12 +1,12 @@ Feature: single scenario with background Background: named - Given passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - And passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + And passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef Scenario: scenario # formatter-tests/features/scenario_with_background.feature:7 - When passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - Then passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef 1 scenarios (1 passed) 4 steps (4 passed) diff --git a/formatter-tests/pretty/single_scenario_with_passing_step b/formatter-tests/pretty/single_scenario_with_passing_step index a21eca32..d24086fa 100644 --- a/formatter-tests/pretty/single_scenario_with_passing_step +++ b/formatter-tests/pretty/single_scenario_with_passing_step @@ -4,7 +4,7 @@ feature Scenario: one step passing # formatter-tests/features/single_scenario_with_passing_step.feature:6 - Given a passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + Given a passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef 1 scenarios (1 passed) 1 steps (1 passed) diff --git a/formatter-tests/pretty/some_scenarions_including_failing b/formatter-tests/pretty/some_scenarions_including_failing index 1a634ca2..689e4d4c 100644 --- a/formatter-tests/pretty/some_scenarions_including_failing +++ b/formatter-tests/pretty/some_scenarions_including_failing @@ -1,19 +1,19 @@ Feature: some scenarios Scenario: failing # formatter-tests/features/some_scenarions_including_failing.feature:3 - Given passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - When failing step # fmt_output_test.go:132 -> github.com/cucumber/godog_test.failingStepDef + Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + When failing step # fmt_output_test.go:117 -> github.com/cucumber/godog_test.failingStepDef step failed - Then passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef Scenario: pending # formatter-tests/features/some_scenarions_including_failing.feature:8 - When pending step # fmt_output_test.go:130 -> github.com/cucumber/godog_test.pendingStepDef + When pending step # fmt_output_test.go:115 -> github.com/cucumber/godog_test.pendingStepDef TODO: write pending definition - Then passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef Scenario: undefined # formatter-tests/features/some_scenarions_including_failing.feature:12 When undefined - Then passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef --- Failed steps: diff --git a/formatter-tests/pretty/two_scenarios_with_background_fail b/formatter-tests/pretty/two_scenarios_with_background_fail index 4f9959ce..643c910e 100644 --- a/formatter-tests/pretty/two_scenarios_with_background_fail +++ b/formatter-tests/pretty/two_scenarios_with_background_fail @@ -1,16 +1,16 @@ Feature: two scenarios with background fail Background: - Given passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - And failing step # fmt_output_test.go:132 -> github.com/cucumber/godog_test.failingStepDef + Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + And failing step # fmt_output_test.go:117 -> github.com/cucumber/godog_test.failingStepDef step failed Scenario: one # formatter-tests/features/two_scenarios_with_background_fail.feature:7 - When passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef - Then passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef Scenario: two # formatter-tests/features/two_scenarios_with_background_fail.feature:11 - Then passing step # fmt_output_test.go:116 -> github.com/cucumber/godog_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef --- Failed steps: diff --git a/run.go b/run.go index 580142d9..2d95a84e 100644 --- a/run.go +++ b/run.go @@ -21,7 +21,6 @@ const ( exitOptionError ) -type initializer func(*Suite) type testSuiteInitializer func(*TestSuiteContext) type scenarioInitializer func(*ScenarioContext) @@ -31,7 +30,6 @@ type runner struct { features []*feature - initializer initializer testSuiteInitializer testSuiteInitializer scenarioInitializer scenarioInitializer @@ -39,104 +37,7 @@ type runner struct { fmt Formatter } -func (r *runner) concurrent(rate int, formatterFn func() Formatter) (failed bool) { - var useFmtCopy bool - var copyLock sync.Mutex - - // special mode for concurrent-formatter - if _, ok := r.fmt.(ConcurrentFormatter); ok { - useFmtCopy = true - } - - if fmt, ok := r.fmt.(storageFormatter); ok { - fmt.setStorage(r.storage) - } - - testRunStarted := testRunStarted{StartedAt: timeNowFunc()} - r.storage.mustInsertTestRunStarted(testRunStarted) - r.fmt.TestRunStarted() - - queue := make(chan int, rate) - for i, ft := range r.features { - queue <- i // reserve space in queue - ft := *ft - - go func(fail *bool, feat *feature) { - var fmtCopy Formatter - - defer func() { - <-queue // free a space in queue - }() - - if r.stopOnFailure && *fail { - return - } - - suite := &Suite{ - fmt: r.fmt, - randomSeed: r.randomSeed, - stopOnFailure: r.stopOnFailure, - strict: r.strict, - features: []*feature{feat}, - storage: r.storage, - } - - if useFmtCopy { - fmtCopy = formatterFn() - suite.fmt = fmtCopy - - concurrentDestFmt, dOk := fmtCopy.(ConcurrentFormatter) - concurrentSourceFmt, sOk := r.fmt.(ConcurrentFormatter) - - if dOk && sOk { - concurrentDestFmt.Sync(concurrentSourceFmt) - } - } - - if fmt, ok := suite.fmt.(storageFormatter); ok { - fmt.setStorage(r.storage) - } - - r.initializer(suite) - - suite.run() - - if suite.failed { - copyLock.Lock() - *fail = true - copyLock.Unlock() - } - - if useFmtCopy { - copyLock.Lock() - - concurrentDestFmt, dOk := r.fmt.(ConcurrentFormatter) - concurrentSourceFmt, sOk := fmtCopy.(ConcurrentFormatter) - - if dOk && sOk { - concurrentDestFmt.Copy(concurrentSourceFmt) - } else if !dOk { - panic("cant cast dest formatter to progress-typed") - } else if !sOk { - panic("cant cast source formatter to progress-typed") - } - - copyLock.Unlock() - } - }(&failed, &ft) - } - // wait until last are processed - for i := 0; i < rate; i++ { - queue <- i - } - close(queue) - - // print summary - r.fmt.Summary() - return -} - -func (r *runner) scenarioConcurrent(rate int) (failed bool) { +func (r *runner) concurrent(rate int) (failed bool) { var copyLock sync.Mutex if fmt, ok := r.fmt.(storageFormatter); ok { @@ -188,7 +89,7 @@ func (r *runner) scenarioConcurrent(rate int) (failed bool) { return } - suite := &Suite{ + suite := &suite{ fmt: r.fmt, randomSeed: r.randomSeed, strict: r.strict, @@ -227,38 +128,7 @@ func (r *runner) scenarioConcurrent(rate int) (failed bool) { return } -// RunWithOptions is same as Run function, except -// it uses Options provided in order to run the -// test suite without parsing flags -// -// This method is useful in case if you run -// godog in for example TestMain function together -// with go tests -// -// The exit codes may vary from: -// 0 - success -// 1 - failed -// 2 - command line usage error -// 128 - or higher, os signal related error exit codes -// -// If there are flag related errors they will -// be directed to os.Stderr -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. -// Use: -// godog.TestSuite{ -// Name: name, -// TestSuiteInitializer: testSuiteInitializer, -// ScenarioInitializer: scenarioInitializer, -// Options: &opts, -// }.Run() -// instead. -func RunWithOptions(suite string, initializer func(*Suite), opt Options) int { - return runWithOptions(suite, runner{initializer: initializer}, opt) -} - -func runWithOptions(suite string, runner runner, opt Options) int { +func runWithOptions(suiteName string, runner runner, opt Options) int { var output io.Writer = os.Stdout if nil != opt.Output { output = opt.Output @@ -271,8 +141,9 @@ func runWithOptions(suite string, runner runner, opt Options) int { } if opt.ShowStepDefinitions { - s := &Suite{} - runner.initializer(s) + s := suite{} + sc := ScenarioContext{suite: &s} + runner.scenarioInitializer(&sc) printStepDefinitions(s.steps, output) return exitOptionError } @@ -301,7 +172,7 @@ func runWithOptions(suite string, runner runner, opt Options) int { )) return exitOptionError } - runner.fmt = formatter(suite, output) + runner.fmt = formatter(suiteName, output) var err error if runner.features, err = parseFeatures(opt.Tags, opt.Paths); err != nil { @@ -333,12 +204,7 @@ func runWithOptions(suite string, runner runner, opt Options) int { _, filename, _, _ := runtime.Caller(1) os.Setenv("GODOG_TESTED_PACKAGE", runsFromPackage(filename)) - var failed bool - if runner.initializer != nil { - failed = runner.concurrent(opt.Concurrency, func() Formatter { return formatter(suite, output) }) - } else { - failed = runner.scenarioConcurrent(opt.Concurrency) - } + failed := runner.concurrent(opt.Concurrency) // @TODO: should prevent from having these os.Setenv("GODOG_SEED", "") @@ -360,52 +226,6 @@ func runsFromPackage(fp string) string { return dir } -// Run creates and runs the feature suite. -// Reads all configuration options from flags. -// uses contextInitializer to register contexts -// -// the concurrency option allows runner to -// initialize a number of suites to be run -// separately. Only progress formatter -// is supported when concurrency level is -// higher than 1 -// -// contextInitializer must be able to register -// the step definitions and event handlers. -// -// The exit codes may vary from: -// 0 - success -// 1 - failed -// 2 - command line usage error -// 128 - or higher, os signal related error exit codes -// -// If there are flag related errors they will -// be directed to os.Stderr -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. -// Use: -// godog.TestSuite{ -// Name: name, -// TestSuiteInitializer: testSuiteInitializer, -// ScenarioInitializer: scenarioInitializer, -// }.Run() -// instead. -func Run(suite string, initializer func(*Suite)) int { - var opt Options - opt.Output = colors.Colored(os.Stdout) - - flagSet := FlagSet(&opt) - if err := flagSet.Parse(os.Args[1:]); err != nil { - fmt.Fprintln(os.Stderr, err) - return exitOptionError - } - - opt.Paths = flagSet.Args() - - return RunWithOptions(suite, initializer, opt) -} - // TestSuite allows for configuration // of the Test Suite Execution type TestSuite struct { diff --git a/run_test.go b/run_test.go index ab3611b6..78a77be2 100644 --- a/run_test.go +++ b/run_test.go @@ -26,7 +26,8 @@ func okStep() error { func TestPrintsStepDefinitions(t *testing.T) { var buf bytes.Buffer w := colors.Uncolored(&buf) - s := &Suite{} + s := suite{} + ctx := ScenarioContext{suite: &s} steps := []string{ "^passing step$", @@ -34,7 +35,7 @@ func TestPrintsStepDefinitions(t *testing.T) { } for _, step := range steps { - s.Step(step, okStep) + ctx.Step(step, okStep) } printStepDefinitions(s.steps, w) @@ -54,7 +55,7 @@ func TestPrintsStepDefinitions(t *testing.T) { func TestPrintsNoStepDefinitionsIfNoneFound(t *testing.T) { var buf bytes.Buffer w := colors.Uncolored(&buf) - s := &Suite{} + s := &suite{} printStepDefinitions(s.steps, w) @@ -62,7 +63,7 @@ func TestPrintsNoStepDefinitionsIfNoneFound(t *testing.T) { assert.Equal(t, "there were no contexts registered, could not find any step definition..", out) } -func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) { +func Test_FailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) { const path = "any.feature" gd, err := gherkin.ParseGherkinDocument(strings.NewReader(basicGherkinFeature), (&messages.Incrementing{}).NewId) @@ -75,9 +76,9 @@ func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) { r := runner{ fmt: progressFunc("progress", ioutil.Discard), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^one$`, func() error { return nil }) - s.Step(`^two$`, func() error { return ErrPending }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^two$`, func() error { return ErrPending }) }, } @@ -87,15 +88,15 @@ func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) { r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", ioutil.Discard) }) + failed := r.concurrent(1) require.False(t, failed) r.strict = true - failed = r.concurrent(1, func() Formatter { return progressFunc("progress", ioutil.Discard) }) + failed = r.concurrent(1) require.True(t, failed) } -func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) { +func Test_FailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) { const path = "any.feature" gd, err := gherkin.ParseGherkinDocument(strings.NewReader(basicGherkinFeature), (&messages.Incrementing{}).NewId) @@ -108,8 +109,8 @@ func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) { r := runner{ fmt: progressFunc("progress", ioutil.Discard), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^one$`, func() error { return nil }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^one$`, func() error { return nil }) // two - is undefined }, } @@ -120,15 +121,15 @@ func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) { r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", ioutil.Discard) }) + failed := r.concurrent(1) require.False(t, failed) r.strict = true - failed = r.concurrent(1, func() Formatter { return progressFunc("progress", ioutil.Discard) }) + failed = r.concurrent(1) require.True(t, failed) } -func TestShouldFailOnError(t *testing.T) { +func Test_ShouldFailOnError(t *testing.T) { const path = "any.feature" gd, err := gherkin.ParseGherkinDocument(strings.NewReader(basicGherkinFeature), (&messages.Incrementing{}).NewId) @@ -141,9 +142,9 @@ func TestShouldFailOnError(t *testing.T) { r := runner{ fmt: progressFunc("progress", ioutil.Discard), features: []*feature{&ft}, - initializer: func(s *Suite) { - s.Step(`^one$`, func() error { return nil }) - s.Step(`^two$`, func() error { return fmt.Errorf("error") }) + scenarioInitializer: func(ctx *ScenarioContext) { + ctx.Step(`^one$`, func() error { return nil }) + ctx.Step(`^two$`, func() error { return fmt.Errorf("error") }) }, } @@ -153,22 +154,27 @@ func TestShouldFailOnError(t *testing.T) { r.storage.mustInsertPickle(pickle) } - failed := r.concurrent(1, func() Formatter { return progressFunc("progress", ioutil.Discard) }) + failed := r.concurrent(1) require.True(t, failed) } -func TestFailsWithUnknownFormatterOptionError(t *testing.T) { +func Test_FailsWithUnknownFormatterOptionError(t *testing.T) { stderr, closer := bufErrorPipe(t) defer closer() defer stderr.Close() - opt := Options{ + opts := Options{ Format: "unknown", Paths: []string{"features/load:6"}, Output: ioutil.Discard, } - status := RunWithOptions("fails", func(_ *Suite) {}, opt) + status := TestSuite{ + Name: "fails", + ScenarioInitializer: func(_ *ScenarioContext) {}, + Options: &opts, + }.Run() + require.Equal(t, exitOptionError, status) closer() @@ -180,18 +186,23 @@ func TestFailsWithUnknownFormatterOptionError(t *testing.T) { assert.Contains(t, out, `unregistered formatter name: "unknown", use one of`) } -func TestFailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing.T) { +func Test_FailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing.T) { stderr, closer := bufErrorPipe(t) defer closer() defer stderr.Close() - opt := Options{ + opts := Options{ Format: "progress", Paths: []string{"unavailable"}, Output: ioutil.Discard, } - status := RunWithOptions("fails", func(_ *Suite) {}, opt) + status := TestSuite{ + Name: "fails", + ScenarioInitializer: func(_ *ScenarioContext) {}, + Options: &opts, + }.Run() + require.Equal(t, exitOptionError, status) closer() @@ -203,19 +214,29 @@ func TestFailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing. assert.Equal(t, `feature path "unavailable" is not available`, out) } -func TestByDefaultRunsFeaturesPath(t *testing.T) { - opt := Options{ +func Test_ByDefaultRunsFeaturesPath(t *testing.T) { + opts := Options{ Format: "progress", Output: ioutil.Discard, Strict: true, } - status := RunWithOptions("fails", func(_ *Suite) {}, opt) + status := TestSuite{ + Name: "fails", + ScenarioInitializer: func(_ *ScenarioContext) {}, + Options: &opts, + }.Run() + // should fail in strict mode due to undefined steps assert.Equal(t, exitFailure, status) - opt.Strict = false - status = RunWithOptions("succeeds", func(_ *Suite) {}, opt) + opts.Strict = false + status = TestSuite{ + Name: "succeeds", + ScenarioInitializer: func(_ *ScenarioContext) {}, + Options: &opts, + }.Run() + // should succeed in non strict mode due to undefined steps assert.Equal(t, exitSuccess, status) } @@ -232,7 +253,7 @@ func bufErrorPipe(t *testing.T) (io.ReadCloser, func()) { } } -func TestFeatureFilePathParser(t *testing.T) { +func Test_FeatureFilePathParser(t *testing.T) { type Case struct { input string @@ -327,19 +348,8 @@ func Test_AllFeaturesRun(t *testing.T) { 0s ` - fmtOutputSuiteInitializer := func(s *Suite) { SuiteContext(s) } - fmtOutputScenarioInitializer := InitializeScenario - - actualStatus, actualOutput := testRunWithOptions(t, - fmtOutputSuiteInitializer, - format, concurrency, []string{"features"}, - ) - - assert.Equal(t, exitSuccess, actualStatus) - assert.Equal(t, expected, actualOutput) - - actualStatus, actualOutput = testRun(t, - fmtOutputScenarioInitializer, + actualStatus, actualOutput := testRun(t, + InitializeScenario, format, concurrency, noRandomFlag, []string{"features"}, ) @@ -348,7 +358,7 @@ func Test_AllFeaturesRun(t *testing.T) { assert.Equal(t, expected, actualOutput) } -func TestFormatterConcurrencyRun(t *testing.T) { +func Test_FormatterConcurrencyRun(t *testing.T) { formatters := []string{ "progress", "junit", @@ -363,13 +373,6 @@ func TestFormatterConcurrencyRun(t *testing.T) { const noRandomFlag = 0 const noConcurrency = 1 - fmtOutputSuiteInitializer := func(s *Suite) { - s.Step(`^(?:a )?failing step`, failingStepDef) - s.Step(`^(?:a )?pending step$`, pendingStepDef) - s.Step(`^(?:a )?passing step$`, passingStepDef) - s.Step(`^odd (\d+) and even (\d+) number$`, oddEvenStepDef) - } - fmtOutputScenarioInitializer := func(ctx *ScenarioContext) { ctx.Step(`^(?:a )?failing step`, failingStepDef) ctx.Step(`^(?:a )?pending step$`, pendingStepDef) @@ -381,24 +384,12 @@ func TestFormatterConcurrencyRun(t *testing.T) { t.Run( fmt.Sprintf("%s/concurrency/%d", formatter, concurrency), func(t *testing.T) { - expectedStatus, expectedOutput := testRunWithOptions(t, - fmtOutputSuiteInitializer, - formatter, noConcurrency, featurePaths, - ) - actualStatus, actualOutput := testRunWithOptions(t, - fmtOutputSuiteInitializer, - formatter, concurrency, featurePaths, - ) - - assert.Equal(t, expectedStatus, actualStatus) - assertOutput(t, formatter, expectedOutput, actualOutput) - - expectedStatus, expectedOutput = testRun(t, + expectedStatus, expectedOutput := testRun(t, fmtOutputScenarioInitializer, formatter, noConcurrency, noRandomFlag, featurePaths, ) - actualStatus, actualOutput = testRun(t, + actualStatus, actualOutput := testRun(t, fmtOutputScenarioInitializer, formatter, concurrency, noRandomFlag, featurePaths, @@ -411,25 +402,6 @@ func TestFormatterConcurrencyRun(t *testing.T) { } } -func testRunWithOptions(t *testing.T, initializer func(*Suite), format string, concurrency int, featurePaths []string) (int, string) { - output := new(bytes.Buffer) - - opts := Options{ - Format: format, - NoColors: true, - Paths: featurePaths, - Concurrency: concurrency, - Output: output, - } - - status := RunWithOptions("succeed", initializer, opts) - - actual, err := ioutil.ReadAll(output) - require.NoError(t, err) - - return status, string(actual) -} - func testRun( t *testing.T, scenarioInitializer func(*ScenarioContext), diff --git a/suite.go b/suite.go index ff13788f..7ce2f26c 100644 --- a/suite.go +++ b/suite.go @@ -2,9 +2,7 @@ package godog import ( "fmt" - "math/rand" "reflect" - "regexp" "strings" "github.com/cucumber/messages-go/v10" @@ -20,24 +18,8 @@ var ErrUndefined = fmt.Errorf("step is undefined") // step implementation is pending var ErrPending = fmt.Errorf("step implementation is pending") -// Suite allows various contexts -// to register steps and event handlers. -// -// When running a test suite, the instance of Suite -// is passed to all functions (contexts), which -// have it as a first and only argument. -// -// Note that all event hooks does not catch panic errors -// in order to have a trace information. Only step -// executions are catching panic error since it may -// be a context specific error. -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. -// This struct will therefore not be exported in the future. -type Suite struct { - steps []*StepDefinition - features []*feature +type suite struct { + steps []*StepDefinition fmt Formatter storage *storage @@ -48,175 +30,13 @@ type Suite struct { strict bool // suite event handlers - beforeSuiteHandlers []func() - beforeScenarioHandlers []func(*messages.Pickle) - beforeStepHandlers []func(*messages.Pickle_PickleStep) - afterStepHandlers []func(*messages.Pickle_PickleStep, error) - afterScenarioHandlers []func(*messages.Pickle, error) - afterSuiteHandlers []func() + beforeScenarioHandlers []func(*Scenario) + beforeStepHandlers []func(*Step) + afterStepHandlers []func(*Step, error) + afterScenarioHandlers []func(*Scenario, error) } -// Step allows to register a *StepDefinition in Godog -// feature suite, the definition will be applied -// to all steps matching the given Regexp expr. -// -// It will panic if expr is not a valid regular -// expression or stepFunc is not a valid step -// handler. -// -// Note that if there are two definitions which may match -// the same step, then only the first matched handler -// will be applied. -// -// If none of the *StepDefinition is matched, then -// ErrUndefined error will be returned when -// running steps. -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *ScenarioContext) Step instead. -func (s *Suite) Step(expr interface{}, stepFunc interface{}) { - var regex *regexp.Regexp - - switch t := expr.(type) { - case *regexp.Regexp: - regex = t - case string: - regex = regexp.MustCompile(t) - case []byte: - regex = regexp.MustCompile(string(t)) - default: - panic(fmt.Sprintf("expecting expr to be a *regexp.Regexp or a string, got type: %T", expr)) - } - - v := reflect.ValueOf(stepFunc) - typ := v.Type() - if typ.Kind() != reflect.Func { - panic(fmt.Sprintf("expected handler to be func, but got: %T", stepFunc)) - } - - if typ.NumOut() != 1 { - panic(fmt.Sprintf("expected handler to return only one value, but it has: %d", typ.NumOut())) - } - - def := &StepDefinition{ - Handler: stepFunc, - Expr: regex, - hv: v, - } - - typ = typ.Out(0) - switch typ.Kind() { - case reflect.Interface: - if !typ.Implements(errorInterface) { - panic(fmt.Sprintf("expected handler to return an error, but got: %s", typ.Kind())) - } - case reflect.Slice: - if typ.Elem().Kind() != reflect.String { - panic(fmt.Sprintf("expected handler to return []string for multistep, but got: []%s", typ.Kind())) - } - def.nested = true - default: - panic(fmt.Sprintf("expected handler to return an error or []string, but got: %s", typ.Kind())) - } - - s.steps = append(s.steps, def) -} - -// BeforeSuite registers a function or method -// to be run once before suite runner. -// -// Use it to prepare the test suite for a spin. -// Connect and prepare database for instance... -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *TestSuiteContext) BeforeSuite instead. -func (s *Suite) BeforeSuite(fn func()) { - s.beforeSuiteHandlers = append(s.beforeSuiteHandlers, fn) -} - -// BeforeScenario registers a function or method -// to be run before every pickle. -// -// It is a good practice to restore the default state -// before every scenario so it would be isolated from -// any kind of state. -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *ScenarioContext) BeforeScenario instead. -func (s *Suite) BeforeScenario(fn func(*messages.Pickle)) { - s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, fn) -} - -// BeforeStep registers a function or method -// to be run before every step. -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *ScenarioContext) BeforeStep instead. -func (s *Suite) BeforeStep(fn func(*messages.Pickle_PickleStep)) { - s.beforeStepHandlers = append(s.beforeStepHandlers, fn) -} - -// AfterStep registers an function or method -// to be run after every step. -// -// It may be convenient to return a different kind of error -// in order to print more state details which may help -// in case of step failure -// -// In some cases, for example when running a headless -// browser, to take a screenshot after failure. -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *ScenarioContext) AfterStep instead. -func (s *Suite) AfterStep(fn func(*messages.Pickle_PickleStep, error)) { - s.afterStepHandlers = append(s.afterStepHandlers, fn) -} - -// AfterScenario registers an function or method -// to be run after every pickle. -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *ScenarioContext) AfterScenario instead. -func (s *Suite) AfterScenario(fn func(*messages.Pickle, error)) { - s.afterScenarioHandlers = append(s.afterScenarioHandlers, fn) -} - -// AfterSuite registers a function or method -// to be run once after suite runner -// -// Deprecated: The current Suite initializer will be removed and replaced by -// two initializers, one for the Test Suite and one for the Scenarios. Use -// func (ctx *TestSuiteContext) AfterSuite instead. -func (s *Suite) AfterSuite(fn func()) { - s.afterSuiteHandlers = append(s.afterSuiteHandlers, fn) -} - -func (s *Suite) run() { - // run before suite handlers - for _, f := range s.beforeSuiteHandlers { - f() - } - // run features - for _, f := range s.features { - s.runFeature(f) - if s.failed && s.stopOnFailure { - // stop on first failure - break - } - } - // run after suite handlers - for _, f := range s.afterSuiteHandlers { - f() - } -} - -func (s *Suite) matchStep(step *messages.Pickle_PickleStep) *StepDefinition { +func (s *suite) matchStep(step *messages.Pickle_PickleStep) *StepDefinition { def := s.matchStepText(step.Text) if def != nil && step.Argument != nil { def.args = append(def.args, step.Argument) @@ -224,7 +44,7 @@ func (s *Suite) matchStep(step *messages.Pickle_PickleStep) *StepDefinition { return def } -func (s *Suite) runStep(pickle *messages.Pickle, step *messages.Pickle_PickleStep, prevStepErr error) (err error) { +func (s *suite) runStep(pickle *messages.Pickle, step *messages.Pickle_PickleStep, prevStepErr error) (err error) { // run before step handlers for _, f := range s.beforeStepHandlers { f(step) @@ -312,7 +132,7 @@ func (s *Suite) runStep(pickle *messages.Pickle, step *messages.Pickle_PickleSte return } -func (s *Suite) maybeUndefined(text string, arg interface{}) ([]string, error) { +func (s *suite) maybeUndefined(text string, arg interface{}) ([]string, error) { step := s.matchStepText(text) if nil == step { return []string{text}, nil @@ -345,7 +165,7 @@ func (s *Suite) maybeUndefined(text string, arg interface{}) ([]string, error) { return undefined, nil } -func (s *Suite) maybeSubSteps(result interface{}) error { +func (s *suite) maybeSubSteps(result interface{}) error { if nil == result { return nil } @@ -369,7 +189,7 @@ func (s *Suite) maybeSubSteps(result interface{}) error { return nil } -func (s *Suite) matchStepText(text string) *StepDefinition { +func (s *suite) matchStepText(text string) *StepDefinition { for _, h := range s.steps { if m := h.Expr.FindStringSubmatch(text); len(m) > 0 { var args []interface{} @@ -391,7 +211,7 @@ func (s *Suite) matchStepText(text string) *StepDefinition { return nil } -func (s *Suite) runSteps(pickle *messages.Pickle, steps []*messages.Pickle_PickleStep) (err error) { +func (s *suite) runSteps(pickle *messages.Pickle, steps []*messages.Pickle_PickleStep) (err error) { for _, step := range steps { stepErr := s.runStep(pickle, step, err) switch stepErr { @@ -410,7 +230,7 @@ func (s *Suite) runSteps(pickle *messages.Pickle, steps []*messages.Pickle_Pickl return } -func (s *Suite) shouldFail(err error) bool { +func (s *suite) shouldFail(err error) bool { if err == nil { return false } @@ -422,31 +242,6 @@ func (s *Suite) shouldFail(err error) bool { return true } -func (s *Suite) runFeature(f *feature) { - s.fmt.Feature(f.GherkinDocument, f.Uri, f.content) - - pickles := make([]*messages.Pickle, len(f.pickles)) - if s.randomSeed != 0 { - r := rand.New(rand.NewSource(s.randomSeed)) - perm := r.Perm(len(f.pickles)) - for i, v := range perm { - pickles[v] = f.pickles[i] - } - } else { - copy(pickles, f.pickles) - } - - for _, pickle := range pickles { - err := s.runPickle(pickle) - if s.shouldFail(err) { - s.failed = true - if s.stopOnFailure { - return - } - } - } -} - func isEmptyFeature(pickles []*messages.Pickle) bool { for _, pickle := range pickles { if len(pickle.Steps) > 0 { @@ -457,7 +252,7 @@ func isEmptyFeature(pickles []*messages.Pickle) bool { return true } -func (s *Suite) runPickle(pickle *messages.Pickle) (err error) { +func (s *suite) runPickle(pickle *messages.Pickle) (err error) { if len(pickle.Steps) == 0 { pr := pickleResult{PickleID: pickle.Id, StartedAt: timeNowFunc()} s.storage.mustInsertPickleResult(pr) diff --git a/suite_context.go b/suite_context.go deleted file mode 100644 index 94079c8e..00000000 --- a/suite_context.go +++ /dev/null @@ -1,632 +0,0 @@ -package godog - -import ( - "bytes" - "encoding/json" - "encoding/xml" - "fmt" - "path/filepath" - "regexp" - "strconv" - "strings" - - "github.com/cucumber/gherkin-go/v11" - "github.com/cucumber/messages-go/v10" - "github.com/stretchr/testify/assert" - - "github.com/cucumber/godog/colors" -) - -// SuiteContext provides steps for godog suite execution and -// can be used for meta-testing of godog features/steps themselves. -// -// Beware, steps or their definitions might change without backward -// compatibility guarantees. A typical user of the godog library should never -// need this, rather it is provided for those developing add-on libraries for godog. -// -// For an example of how to use, see godog's own `features/` and `suite_test.go`. -// -// Deprecated: Use InitializeScenario instead. -func SuiteContext(s *Suite, additionalContextInitializers ...func(suite *Suite)) { - c := &suiteContext{ - extraCIs: additionalContextInitializers, - } - - // apply any additional context intializers to modify the context that the - // meta-tests will be run in - for _, ci := range additionalContextInitializers { - ci(s) - } - - s.BeforeScenario(c.ResetBeforeEachScenario) - - s.Step(`^(?:a )?feature path "([^"]*)"$`, c.featurePath) - s.Step(`^I parse features$`, c.parseFeatures) - s.Step(`^I'm listening to suite events$`, c.iAmListeningToSuiteEvents) - s.Step(`^I run feature suite$`, c.iRunFeatureSuite) - s.Step(`^I run feature suite with tags "([^"]*)"$`, c.iRunFeatureSuiteWithTags) - s.Step(`^I run feature suite with formatter "([^"]*)"$`, c.iRunFeatureSuiteWithFormatter) - s.Step(`^(?:I )(allow|disable) variable injection`, c.iSetVariableInjectionTo) - s.Step(`^(?:a )?feature "([^"]*)"(?: file)?:$`, c.aFeatureFile) - s.Step(`^the suite should have (passed|failed)$`, c.theSuiteShouldHave) - - s.Step(`^I should have ([\d]+) features? files?:$`, c.iShouldHaveNumFeatureFiles) - s.Step(`^I should have ([\d]+) scenarios? registered$`, c.numScenariosRegistered) - s.Step(`^there (was|were) ([\d]+) "([^"]*)" events? fired$`, c.thereWereNumEventsFired) - s.Step(`^there was event triggered before scenario "([^"]*)"$`, c.thereWasEventTriggeredBeforeScenario) - s.Step(`^these events had to be fired for a number of times:$`, c.theseEventsHadToBeFiredForNumberOfTimes) - - s.Step(`^(?:a )?failing step`, c.aFailingStep) - s.Step(`^this step should fail`, c.aFailingStep) - s.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, c.followingStepsShouldHave) - s.Step(`^the undefined step snippets should be:$`, c.theUndefinedStepSnippetsShouldBe) - - // event stream - s.Step(`^the following events should be fired:$`, c.thereShouldBeEventsFired) - - // lt - s.Step(`^savybių aplankas "([^"]*)"$`, c.featurePath) - s.Step(`^aš išskaitau savybes$`, c.parseFeatures) - s.Step(`^aš turėčiau turėti ([\d]+) savybių failus:$`, c.iShouldHaveNumFeatureFiles) - - s.Step(`^(?:a )?pending step$`, func() error { - return ErrPending - }) - s.Step(`^(?:a )?passing step$`, func() error { - return nil - }) - - // Introduced to test formatter/cucumber.feature - s.Step(`^the rendered json will be as follows:$`, c.theRenderJSONWillBe) - - // Introduced to test formatter/pretty.feature - s.Step(`^the rendered output will be as follows:$`, c.theRenderOutputWillBe) - - // Introduced to test formatter/junit.feature - s.Step(`^the rendered xml will be as follows:$`, c.theRenderXMLWillBe) - - s.Step(`^(?:a )?failing multistep$`, func() Steps { - return Steps{"passing step", "failing step"} - }) - - s.Step(`^(?:a |an )?undefined multistep$`, func() Steps { - return Steps{"passing step", "undefined step", "passing step"} - }) - - s.Step(`^(?:a )?passing multistep$`, func() Steps { - return Steps{"passing step", "passing step", "passing step"} - }) - - s.Step(`^(?:a )?failing nested multistep$`, func() Steps { - return Steps{"passing step", "passing multistep", "failing multistep"} - }) - // Default recovery step - s.Step(`Ignore.*`, func() error { - return nil - }) - - s.BeforeStep(c.inject) -} - -func (s *suiteContext) inject(step *Step) { - if !s.allowInjection { - return - } - - step.Text = injectAll(step.Text) - - if table := step.Argument.GetDataTable(); table != nil { - for i := 0; i < len(table.Rows); i++ { - for n, cell := range table.Rows[i].Cells { - table.Rows[i].Cells[n].Value = injectAll(cell.Value) - } - } - } - - if doc := step.Argument.GetDocString(); doc != nil { - doc.Content = injectAll(doc.Content) - } -} - -func injectAll(src string) string { - re := regexp.MustCompile(`{{[^{}]+}}`) - return re.ReplaceAllStringFunc( - src, - func(key string) string { - injectRegex := regexp.MustCompile(`^{{.+}}$`) - - if injectRegex.MatchString(key) { - return "someverylonginjectionsoweacanbesureitsurpasstheinitiallongeststeplenghtanditwillhelptestsmethodsafety" - } - - return key - }, - ) -} - -type firedEvent struct { - name string - args []interface{} -} - -type suiteContext struct { - paths []string - testedSuite *Suite - extraCIs []func(suite *Suite) - events []*firedEvent - out bytes.Buffer - allowInjection bool -} - -func (s *suiteContext) ResetBeforeEachScenario(*Scenario) { - // reset whole suite with the state - s.out.Reset() - s.paths = []string{} - s.testedSuite = &Suite{} - // our tested suite will have the same context registered - SuiteContext(s.testedSuite, s.extraCIs...) - // reset all fired events - s.events = []*firedEvent{} - s.allowInjection = false -} - -func (s *suiteContext) iSetVariableInjectionTo(to string) error { - s.allowInjection = to == "allow" - return nil -} - -func (s *suiteContext) iRunFeatureSuiteWithTags(tags string) error { - if err := s.parseFeatures(); err != nil { - return err - } - - for _, feat := range s.testedSuite.features { - feat.pickles = applyTagFilter(tags, feat.pickles) - } - - s.testedSuite.storage = newStorage() - for _, feat := range s.testedSuite.features { - s.testedSuite.storage.mustInsertFeature(feat) - - for _, pickle := range feat.pickles { - s.testedSuite.storage.mustInsertPickle(pickle) - } - } - - fmt := newBaseFmt("godog", &s.out) - fmt.setStorage(s.testedSuite.storage) - s.testedSuite.fmt = fmt - - testRunStarted := testRunStarted{StartedAt: timeNowFunc()} - s.testedSuite.storage.mustInsertTestRunStarted(testRunStarted) - - s.testedSuite.fmt.TestRunStarted() - s.testedSuite.run() - s.testedSuite.fmt.Summary() - - return nil -} - -func (s *suiteContext) iRunFeatureSuiteWithFormatter(name string) error { - if err := s.parseFeatures(); err != nil { - return err - } - - f := FindFmt(name) - if f == nil { - return fmt.Errorf(`formatter "%s" is not available`, name) - } - - s.testedSuite.storage = newStorage() - for _, feat := range s.testedSuite.features { - s.testedSuite.storage.mustInsertFeature(feat) - - for _, pickle := range feat.pickles { - s.testedSuite.storage.mustInsertPickle(pickle) - } - } - - s.testedSuite.fmt = f("godog", colors.Uncolored(&s.out)) - if fmt, ok := s.testedSuite.fmt.(storageFormatter); ok { - fmt.setStorage(s.testedSuite.storage) - } - - testRunStarted := testRunStarted{StartedAt: timeNowFunc()} - s.testedSuite.storage.mustInsertTestRunStarted(testRunStarted) - - s.testedSuite.fmt.TestRunStarted() - s.testedSuite.run() - s.testedSuite.fmt.Summary() - - return nil -} - -func (s *suiteContext) thereShouldBeEventsFired(doc *DocString) error { - actual := strings.Split(strings.TrimSpace(s.out.String()), "\n") - expect := strings.Split(strings.TrimSpace(doc.Content), "\n") - - if len(expect) != len(actual) { - return fmt.Errorf("expected %d events, but got %d", len(expect), len(actual)) - } - - type ev struct { - Event string - } - - for i, event := range actual { - exp := strings.TrimSpace(expect[i]) - var act ev - - if err := json.Unmarshal([]byte(event), &act); err != nil { - return fmt.Errorf("failed to read event data: %v", err) - } - - if act.Event != exp { - return fmt.Errorf(`expected event: "%s" at position: %d, but actual was "%s"`, exp, i, act.Event) - } - } - - return nil -} - -func (s *suiteContext) cleanupSnippet(snip string) string { - lines := strings.Split(strings.TrimSpace(snip), "\n") - for i := 0; i < len(lines); i++ { - lines[i] = strings.TrimSpace(lines[i]) - } - - return strings.Join(lines, "\n") -} - -func (s *suiteContext) theUndefinedStepSnippetsShouldBe(body *DocString) error { - f, ok := s.testedSuite.fmt.(*basefmt) - if !ok { - return fmt.Errorf("this step requires *basefmt, but there is: %T", s.testedSuite.fmt) - } - - actual := s.cleanupSnippet(f.snippets()) - expected := s.cleanupSnippet(body.Content) - - if actual != expected { - return fmt.Errorf("snippets do not match actual: %s", f.snippets()) - } - - return nil -} - -func (s *suiteContext) followingStepsShouldHave(status string, steps *DocString) error { - var expected = strings.Split(steps.Content, "\n") - var actual, unmatched, matched []string - - f, ok := s.testedSuite.fmt.(*basefmt) - if !ok { - return fmt.Errorf("this step requires *basefmt, but there is: %T", s.testedSuite.fmt) - } - - switch status { - case "passed": - for _, st := range f.storage.mustGetPickleStepResultsByStatus(passed) { - pickleStep := f.storage.mustGetPickleStep(st.PickleStepID) - actual = append(actual, pickleStep.Text) - } - case "failed": - for _, st := range f.storage.mustGetPickleStepResultsByStatus(failed) { - pickleStep := f.storage.mustGetPickleStep(st.PickleStepID) - actual = append(actual, pickleStep.Text) - } - case "skipped": - for _, st := range f.storage.mustGetPickleStepResultsByStatus(skipped) { - pickleStep := f.storage.mustGetPickleStep(st.PickleStepID) - actual = append(actual, pickleStep.Text) - } - case "undefined": - for _, st := range f.storage.mustGetPickleStepResultsByStatus(undefined) { - pickleStep := f.storage.mustGetPickleStep(st.PickleStepID) - actual = append(actual, pickleStep.Text) - } - case "pending": - for _, st := range f.storage.mustGetPickleStepResultsByStatus(pending) { - pickleStep := f.storage.mustGetPickleStep(st.PickleStepID) - actual = append(actual, pickleStep.Text) - } - default: - return fmt.Errorf("unexpected step status wanted: %s", status) - } - - if len(expected) > len(actual) { - return fmt.Errorf("number of expected %s steps: %d is less than actual %s steps: %d", status, len(expected), status, len(actual)) - } - - for _, a := range actual { - for _, e := range expected { - if a == e { - matched = append(matched, e) - break - } - } - } - - if len(matched) >= len(expected) { - return nil - } - - for _, s := range expected { - var found bool - for _, m := range matched { - if s == m { - found = true - break - } - } - - if !found { - unmatched = append(unmatched, s) - } - } - - return fmt.Errorf("the steps: %s - are not %s", strings.Join(unmatched, ", "), status) -} - -func (s *suiteContext) iAmListeningToSuiteEvents() error { - s.testedSuite.BeforeSuite(func() { - s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}}) - }) - - s.testedSuite.AfterSuite(func() { - s.events = append(s.events, &firedEvent{"AfterSuite", []interface{}{}}) - }) - - s.testedSuite.BeforeScenario(func(pickle *Scenario) { - s.events = append(s.events, &firedEvent{"BeforeScenario", []interface{}{pickle}}) - }) - - s.testedSuite.AfterScenario(func(pickle *Scenario, err error) { - s.events = append(s.events, &firedEvent{"AfterScenario", []interface{}{pickle, err}}) - }) - - s.testedSuite.BeforeStep(func(step *Step) { - s.events = append(s.events, &firedEvent{"BeforeStep", []interface{}{step}}) - }) - - s.testedSuite.AfterStep(func(step *Step, err error) { - s.events = append(s.events, &firedEvent{"AfterStep", []interface{}{step, err}}) - }) - - return nil -} - -func (s *suiteContext) aFailingStep() error { - return fmt.Errorf("intentional failure") -} - -// parse a given feature file body as a feature -func (s *suiteContext) aFeatureFile(path string, body *DocString) error { - gd, err := gherkin.ParseGherkinDocument(strings.NewReader(body.Content), (&messages.Incrementing{}).NewId) - gd.Uri = path - - pickles := gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId) - s.testedSuite.features = append(s.testedSuite.features, &feature{GherkinDocument: gd, pickles: pickles}) - - return err -} - -func (s *suiteContext) featurePath(path string) error { - s.paths = append(s.paths, path) - return nil -} - -func (s *suiteContext) parseFeatures() error { - fts, err := parseFeatures("", s.paths) - if err != nil { - return err - } - - s.testedSuite.features = append(s.testedSuite.features, fts...) - - return nil -} - -func (s *suiteContext) theSuiteShouldHave(state string) error { - if s.testedSuite.failed && state == "passed" { - return fmt.Errorf("the feature suite has failed") - } - - if !s.testedSuite.failed && state == "failed" { - return fmt.Errorf("the feature suite has passed") - } - - return nil -} - -func (s *suiteContext) iShouldHaveNumFeatureFiles(num int, files *DocString) error { - if len(s.testedSuite.features) != num { - return fmt.Errorf("expected %d features to be parsed, but have %d", num, len(s.testedSuite.features)) - } - - expected := strings.Split(files.Content, "\n") - - var actual []string - - for _, ft := range s.testedSuite.features { - actual = append(actual, ft.Uri) - } - - if len(expected) != len(actual) { - return fmt.Errorf("expected %d feature paths to be parsed, but have %d", len(expected), len(actual)) - } - - for i := 0; i < len(expected); i++ { - var matched bool - split := strings.Split(expected[i], "/") - exp := filepath.Join(split...) - - for j := 0; j < len(actual); j++ { - split = strings.Split(actual[j], "/") - act := filepath.Join(split...) - - if exp == act { - matched = true - break - } - } - - if !matched { - return fmt.Errorf(`expected feature path "%s" at position: %d, was not parsed, actual are %+v`, exp, i, actual) - } - } - - return nil -} - -func (s *suiteContext) iRunFeatureSuite() error { - return s.iRunFeatureSuiteWithTags("") -} - -func (s *suiteContext) numScenariosRegistered(expected int) (err error) { - var num int - for _, ft := range s.testedSuite.features { - num += len(ft.pickles) - } - - if num != expected { - err = fmt.Errorf("expected %d scenarios to be registered, but got %d", expected, num) - } - - return -} - -func (s *suiteContext) thereWereNumEventsFired(_ string, expected int, typ string) error { - var num int - for _, event := range s.events { - if event.name == typ { - num++ - } - } - - if num != expected { - return fmt.Errorf("expected %d %s events to be fired, but got %d", expected, typ, num) - } - - return nil -} - -func (s *suiteContext) thereWasEventTriggeredBeforeScenario(expected string) error { - var found []string - for _, event := range s.events { - if event.name != "BeforeScenario" { - continue - } - - var name string - switch t := event.args[0].(type) { - case *Scenario: - name = t.Name - } - - if name == expected { - return nil - } - - found = append(found, name) - } - - if len(found) == 0 { - return fmt.Errorf("before scenario event was never triggered or listened") - } - - return fmt.Errorf(`expected "%s" scenario, but got these fired %s`, expected, `"`+strings.Join(found, `", "`)+`"`) -} - -func (s *suiteContext) theseEventsHadToBeFiredForNumberOfTimes(tbl *Table) error { - if len(tbl.Rows[0].Cells) != 2 { - return fmt.Errorf("expected two columns for event table row, got: %d", len(tbl.Rows[0].Cells)) - } - - for _, row := range tbl.Rows { - num, err := strconv.ParseInt(row.Cells[1].Value, 10, 0) - if err != nil { - return err - } - - if err := s.thereWereNumEventsFired("", int(num), row.Cells[0].Value); err != nil { - return err - } - } - - return nil -} - -func (s *suiteContext) theRenderJSONWillBe(docstring *DocString) error { - suiteCtxReg := regexp.MustCompile(`suite_context.go:\d+`) - - expectedString := docstring.Content - expectedString = suiteCtxReg.ReplaceAllString(expectedString, `suite_context.go:0`) - - actualString := s.out.String() - actualString = suiteCtxReg.ReplaceAllString(actualString, `suite_context.go:0`) - - var expected []cukeFeatureJSON - if err := json.Unmarshal([]byte(expectedString), &expected); err != nil { - return err - } - - var actual []cukeFeatureJSON - if err := json.Unmarshal([]byte(actualString), &actual); err != nil { - return err - } - - return assertExpectedAndActual(assert.Equal, expected, actual) -} - -func (s *suiteContext) theRenderOutputWillBe(docstring *DocString) error { - suiteCtxReg := regexp.MustCompile(`suite_context.go:\d+`) - suiteCtxFuncReg := regexp.MustCompile(`github.com/cucumber/godog.SuiteContext.func(\d+)`) - - expected := docstring.Content - expected = trimAllLines(expected) - expected = suiteCtxReg.ReplaceAllString(expected, "suite_context.go:0") - expected = suiteCtxFuncReg.ReplaceAllString(expected, "SuiteContext.func$1") - - actual := s.out.String() - actual = trimAllLines(actual) - actual = suiteCtxReg.ReplaceAllString(actual, "suite_context.go:0") - actual = suiteCtxFuncReg.ReplaceAllString(actual, "SuiteContext.func$1") - - expectedRows := strings.Split(expected, "\n") - actualRows := strings.Split(actual, "\n") - - return assertExpectedAndActual(assert.ElementsMatch, expectedRows, actualRows) -} - -func (s *suiteContext) theRenderXMLWillBe(docstring *DocString) error { - expectedString := docstring.Content - actualString := s.out.String() - - var expected junitPackageSuite - if err := xml.Unmarshal([]byte(expectedString), &expected); err != nil { - return err - } - - var actual junitPackageSuite - if err := xml.Unmarshal([]byte(actualString), &actual); err != nil { - return err - } - - return assertExpectedAndActual(assert.Equal, expected, actual) -} - -func assertExpectedAndActual(a expectedAndActualAssertion, expected, actual interface{}, msgAndArgs ...interface{}) error { - var t asserter - a(&t, expected, actual, msgAndArgs...) - return t.err -} - -type expectedAndActualAssertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool - -type asserter struct { - err error -} - -func (a *asserter) Errorf(format string, args ...interface{}) { - a.err = fmt.Errorf(format, args...) -} diff --git a/suite_context_test.go b/suite_context_test.go index 507eb2d1..bc91b005 100644 --- a/suite_context_test.go +++ b/suite_context_test.go @@ -117,9 +117,31 @@ func (tc *godogFeaturesScenario) inject(step *Step) { } } +func injectAll(src string) string { + re := regexp.MustCompile(`{{[^{}]+}}`) + return re.ReplaceAllStringFunc( + src, + func(key string) string { + injectRegex := regexp.MustCompile(`^{{.+}}$`) + + if injectRegex.MatchString(key) { + return "someverylonginjectionsoweacanbesureitsurpasstheinitiallongeststeplenghtanditwillhelptestsmethodsafety" + } + + return key + }, + ) +} + +type firedEvent struct { + name string + args []interface{} +} + type godogFeaturesScenario struct { paths []string - testedSuite *Suite + features []*feature + testedSuite *suite testSuiteContext TestSuiteContext events []*firedEvent out bytes.Buffer @@ -131,7 +153,8 @@ func (tc *godogFeaturesScenario) ResetBeforeEachScenario(*Scenario) { tc.out.Reset() tc.paths = []string{} - tc.testedSuite = &Suite{} + tc.features = []*feature{} + tc.testedSuite = &suite{} tc.testSuiteContext = TestSuiteContext{} // reset all fired events @@ -162,12 +185,12 @@ func (tc *godogFeaturesScenario) iRunFeatureSuiteWithTagsAndFormatter(tags strin return err } - for _, feat := range tc.testedSuite.features { + for _, feat := range tc.features { feat.pickles = applyTagFilter(tags, feat.pickles) } tc.testedSuite.storage = newStorage() - for _, feat := range tc.testedSuite.features { + for _, feat := range tc.features { tc.testedSuite.storage.mustInsertFeature(feat) for _, pickle := range feat.pickles { @@ -188,7 +211,7 @@ func (tc *godogFeaturesScenario) iRunFeatureSuiteWithTagsAndFormatter(tags strin f() } - for _, ft := range tc.testedSuite.features { + for _, ft := range tc.features { tc.testedSuite.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.content) for _, pickle := range ft.pickles { @@ -350,19 +373,21 @@ func (tc *godogFeaturesScenario) iAmListeningToSuiteEvents() error { tc.events = append(tc.events, &firedEvent{"AfterSuite", []interface{}{}}) }) - tc.testedSuite.BeforeScenario(func(pickle *Scenario) { + scenarioContext := ScenarioContext{suite: tc.testedSuite} + + scenarioContext.BeforeScenario(func(pickle *Scenario) { tc.events = append(tc.events, &firedEvent{"BeforeScenario", []interface{}{pickle}}) }) - tc.testedSuite.AfterScenario(func(pickle *Scenario, err error) { + scenarioContext.AfterScenario(func(pickle *Scenario, err error) { tc.events = append(tc.events, &firedEvent{"AfterScenario", []interface{}{pickle, err}}) }) - tc.testedSuite.BeforeStep(func(step *Step) { + scenarioContext.BeforeStep(func(step *Step) { tc.events = append(tc.events, &firedEvent{"BeforeStep", []interface{}{step}}) }) - tc.testedSuite.AfterStep(func(step *Step, err error) { + scenarioContext.AfterStep(func(step *Step, err error) { tc.events = append(tc.events, &firedEvent{"AfterStep", []interface{}{step, err}}) }) @@ -379,7 +404,7 @@ func (tc *godogFeaturesScenario) aFeatureFile(path string, body *DocString) erro gd.Uri = path pickles := gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId) - tc.testedSuite.features = append(tc.testedSuite.features, &feature{GherkinDocument: gd, pickles: pickles}) + tc.features = append(tc.features, &feature{GherkinDocument: gd, pickles: pickles}) return err } @@ -395,7 +420,7 @@ func (tc *godogFeaturesScenario) parseFeatures() error { return err } - tc.testedSuite.features = append(tc.testedSuite.features, fts...) + tc.features = append(tc.features, fts...) return nil } @@ -413,15 +438,15 @@ func (tc *godogFeaturesScenario) theSuiteShouldHave(state string) error { } func (tc *godogFeaturesScenario) iShouldHaveNumFeatureFiles(num int, files *DocString) error { - if len(tc.testedSuite.features) != num { - return fmt.Errorf("expected %d features to be parsed, but have %d", num, len(tc.testedSuite.features)) + if len(tc.features) != num { + return fmt.Errorf("expected %d features to be parsed, but have %d", num, len(tc.features)) } expected := strings.Split(files.Content, "\n") var actual []string - for _, ft := range tc.testedSuite.features { + for _, ft := range tc.features { actual = append(actual, ft.Uri) } @@ -458,7 +483,7 @@ func (tc *godogFeaturesScenario) iRunFeatureSuite() error { func (tc *godogFeaturesScenario) numScenariosRegistered(expected int) (err error) { var num int - for _, ft := range tc.testedSuite.features { + for _, ft := range tc.features { num += len(ft.pickles) } @@ -599,3 +624,19 @@ func (tc *godogFeaturesScenario) theRenderXMLWillBe(docstring *DocString) error return assertExpectedAndActual(assert.Equal, expected, actual) } + +func assertExpectedAndActual(a expectedAndActualAssertion, expected, actual interface{}, msgAndArgs ...interface{}) error { + var t asserter + a(&t, expected, actual, msgAndArgs...) + return t.err +} + +type expectedAndActualAssertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool + +type asserter struct { + err error +} + +func (a *asserter) Errorf(format string, args ...interface{}) { + a.err = fmt.Errorf(format, args...) +} diff --git a/suite_test.go b/suite_test.go deleted file mode 100644 index 9d2f71de..00000000 --- a/suite_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package godog - -// needed in order to use godog cli -func GodogContext(s *Suite) { - SuiteContext(s) -} diff --git a/test_context.go b/test_context.go index dfe3e618..d67a31ed 100644 --- a/test_context.go +++ b/test_context.go @@ -1,6 +1,12 @@ package godog -import "github.com/cucumber/messages-go/v10" +import ( + "fmt" + "reflect" + "regexp" + + "github.com/cucumber/messages-go/v10" +) // Scenario represents the executed scenario type Scenario = messages.Pickle @@ -55,7 +61,7 @@ func (ctx *TestSuiteContext) AfterSuite(fn func()) { // executions are catching panic error since it may // be a context specific error. type ScenarioContext struct { - suite *Suite + suite *suite } // BeforeScenario registers a function or method @@ -65,19 +71,19 @@ type ScenarioContext struct { // before every scenario so it would be isolated from // any kind of state. func (ctx *ScenarioContext) BeforeScenario(fn func(sc *Scenario)) { - ctx.suite.BeforeScenario(fn) + ctx.suite.beforeScenarioHandlers = append(ctx.suite.beforeScenarioHandlers, fn) } // AfterScenario registers an function or method // to be run after every scenario. func (ctx *ScenarioContext) AfterScenario(fn func(sc *Scenario, err error)) { - ctx.suite.AfterScenario(fn) + ctx.suite.afterScenarioHandlers = append(ctx.suite.afterScenarioHandlers, fn) } // BeforeStep registers a function or method // to be run before every step. func (ctx *ScenarioContext) BeforeStep(fn func(st *Step)) { - ctx.suite.BeforeStep(fn) + ctx.suite.beforeStepHandlers = append(ctx.suite.beforeStepHandlers, fn) } // AfterStep registers an function or method @@ -90,7 +96,7 @@ func (ctx *ScenarioContext) BeforeStep(fn func(st *Step)) { // In some cases, for example when running a headless // browser, to take a screenshot after failure. func (ctx *ScenarioContext) AfterStep(fn func(st *Step, err error)) { - ctx.suite.AfterStep(fn) + ctx.suite.afterStepHandlers = append(ctx.suite.afterStepHandlers, fn) } // Step allows to register a *StepDefinition in the @@ -121,5 +127,49 @@ func (ctx *ScenarioContext) AfterStep(fn func(st *Step, err error)) { // ErrUndefined error will be returned when // running steps. func (ctx *ScenarioContext) Step(expr, stepFunc interface{}) { - ctx.suite.Step(expr, stepFunc) + var regex *regexp.Regexp + + switch t := expr.(type) { + case *regexp.Regexp: + regex = t + case string: + regex = regexp.MustCompile(t) + case []byte: + regex = regexp.MustCompile(string(t)) + default: + panic(fmt.Sprintf("expecting expr to be a *regexp.Regexp or a string, got type: %T", expr)) + } + + v := reflect.ValueOf(stepFunc) + typ := v.Type() + if typ.Kind() != reflect.Func { + panic(fmt.Sprintf("expected handler to be func, but got: %T", stepFunc)) + } + + if typ.NumOut() != 1 { + panic(fmt.Sprintf("expected handler to return only one value, but it has: %d", typ.NumOut())) + } + + def := &StepDefinition{ + Handler: stepFunc, + Expr: regex, + hv: v, + } + + typ = typ.Out(0) + switch typ.Kind() { + case reflect.Interface: + if !typ.Implements(errorInterface) { + panic(fmt.Sprintf("expected handler to return an error, but got: %s", typ.Kind())) + } + case reflect.Slice: + if typ.Elem().Kind() != reflect.String { + panic(fmt.Sprintf("expected handler to return []string for multistep, but got: []%s", typ.Kind())) + } + def.nested = true + default: + panic(fmt.Sprintf("expected handler to return an error or []string, but got: %s", typ.Kind())) + } + + ctx.suite.steps = append(ctx.suite.steps, def) }