From e9afe7438f165296cfdf92c68dfffeb7b3a2efa7 Mon Sep 17 00:00:00 2001 From: Brian Hnat Date: Mon, 30 May 2022 09:10:22 -0400 Subject: [PATCH] Pretty Print when using rules (#440) --- features/formatter/pretty.feature | 55 ++++++++++++++++++ internal/formatters/fmt_pretty.go | 26 ++++++++- ...les_with_examples_with_backgrounds.feature | 30 ++++++++++ .../rules_with_examples_with_backgrounds | 29 ++++++++++ internal/models/feature.go | 58 ++++++++++++++++++- run_test.go | 12 ++-- 6 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 internal/formatters/formatter-tests/features/rules_with_examples_with_backgrounds.feature create mode 100644 internal/formatters/formatter-tests/pretty/rules_with_examples_with_backgrounds diff --git a/features/formatter/pretty.feature b/features/formatter/pretty.feature index 7b307bea..9a764e0a 100644 --- a/features/formatter/pretty.feature +++ b/features/formatter/pretty.feature @@ -449,3 +449,58 @@ Feature: pretty formatter 16 steps (16 passed) 0s """ + + Scenario: Support of Feature Plus Rule + Given a feature "features/simple.feature" file: + """ + Feature: simple feature with a rule + simple feature description + Rule: simple rule + simple rule description + Example: simple scenario + simple scenario description + Given passing step + """ + When I run feature suite with formatter "pretty" + Then the rendered output will be as follows: + """ + Feature: simple feature with a rule + simple feature description + + Example: simple scenario # features/simple.feature:5 + Given passing step # suite_context.go:0 -> SuiteContext.func2 + + 1 scenarios (1 passed) + 1 steps (1 passed) + 0s + """ + +Scenario: Support of Feature Plus Rule with Background + Given a feature "features/simple.feature" file: + """ + Feature: simple feature with a rule with Background + simple feature description + Rule: simple rule + simple rule description + Background: + Given passing step + Example: simple scenario + simple scenario description + Given passing step + """ + When I run feature suite with formatter "pretty" + Then the rendered output will be as follows: + """ + Feature: simple feature with a rule with Background + simple feature description + + Background: + Given passing step # suite_context.go:0 -> SuiteContext.func2 + + Example: simple scenario # features/simple.feature:7 + Given passing step # suite_context.go:0 -> SuiteContext.func2 + + 1 scenarios (1 passed) + 2 steps (2 passed) + 0s + """ diff --git a/internal/formatters/fmt_pretty.go b/internal/formatters/fmt_pretty.go index 0860dda9..070627a3 100644 --- a/internal/formatters/fmt_pretty.go +++ b/internal/formatters/fmt_pretty.go @@ -12,6 +12,7 @@ import ( "github.com/cucumber/godog/colors" "github.com/cucumber/godog/formatters" + "github.com/cucumber/godog/internal/models" ) func init() { @@ -350,15 +351,38 @@ func (f *Pretty) printTableHeader(row *messages.TableRow, max []int) { f.printTableRow(row, max, cyan) } +func isFirstScenarioInRule(rule *messages.Rule, scenario *messages.Scenario) bool { + if rule == nil || scenario == nil { + return false + } + var firstScenario *messages.Scenario + for _, c := range rule.Children { + if c.Scenario != nil { + firstScenario = c.Scenario + break + } + } + return firstScenario != nil && firstScenario.Id == scenario.Id +} + +func isFirstPickleAndNoRule(feature *models.Feature, pickle *messages.Pickle, rule *messages.Rule) bool { + if rule != nil { + return false + } + return feature.Pickles[0].Id == pickle.Id +} + func (f *Pretty) printStep(pickle *messages.Pickle, pickleStep *messages.PickleStep) { feature := f.Storage.MustGetFeature(pickle.Uri) astBackground := feature.FindBackground(pickle.AstNodeIds[0]) astScenario := feature.FindScenario(pickle.AstNodeIds[0]) + astRule := feature.FindRule(pickle.AstNodeIds[0]) astStep := feature.FindStep(pickleStep.AstNodeIds[0]) var astBackgroundStep bool var firstExecutedBackgroundStep bool var backgroundSteps int + if astBackground != nil { backgroundSteps = len(astBackground.Steps) @@ -371,7 +395,7 @@ func (f *Pretty) printStep(pickle *messages.Pickle, pickleStep *messages.PickleS } } - firstPickle := feature.Pickles[0].Id == pickle.Id + firstPickle := isFirstPickleAndNoRule(feature, pickle, astRule) || isFirstScenarioInRule(astRule, astScenario) if astBackgroundStep && !firstPickle { return diff --git a/internal/formatters/formatter-tests/features/rules_with_examples_with_backgrounds.feature b/internal/formatters/formatter-tests/features/rules_with_examples_with_backgrounds.feature new file mode 100644 index 00000000..06d44a9c --- /dev/null +++ b/internal/formatters/formatter-tests/features/rules_with_examples_with_backgrounds.feature @@ -0,0 +1,30 @@ +Feature: rules with examples with backgrounds + + Rule: first rule + + Background: for first rule + Given passing step + And passing step + + Example: rule 1 example 1 + When passing step + Then passing step + + Example: rule 1 example 2 + When passing step + Then passing step + + + Rule: second rule + + Background: for second rule + Given passing step + And passing step + + Example: rule 1 example 1 + When passing step + Then passing step + + Example: rule 2 example 2 + When passing step + Then passing step diff --git a/internal/formatters/formatter-tests/pretty/rules_with_examples_with_backgrounds b/internal/formatters/formatter-tests/pretty/rules_with_examples_with_backgrounds new file mode 100644 index 00000000..b3d36c3b --- /dev/null +++ b/internal/formatters/formatter-tests/pretty/rules_with_examples_with_backgrounds @@ -0,0 +1,29 @@ +Feature: rules with examples with backgrounds + + Background: for first rule + Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + And passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + + Example: rule 1 example 1 # formatter-tests/features/rules_with_examples_with_backgrounds.feature:9 + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + + Example: rule 1 example 2 # formatter-tests/features/rules_with_examples_with_backgrounds.feature:13 + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + + Background: for second rule + Given passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + And passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + + Example: rule 1 example 1 # formatter-tests/features/rules_with_examples_with_backgrounds.feature:24 + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + + Example: rule 2 example 2 # formatter-tests/features/rules_with_examples_with_backgrounds.feature:28 + When passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + Then passing step # fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef + +4 scenarios (4 passed) +16 steps (16 passed) +0s diff --git a/internal/models/feature.go b/internal/models/feature.go index d38a224a..d9cbd3c3 100644 --- a/internal/models/feature.go +++ b/internal/models/feature.go @@ -13,12 +13,35 @@ type Feature struct { Content []byte } -// FindScenario ... +// FindRule returns the rule to which the given scenario belongs +func (f Feature) FindRule(astScenarioID string) *messages.Rule { + for _, child := range f.GherkinDocument.Feature.Children { + if ru := child.Rule; ru != nil { + if rc := child.Rule; rc != nil { + for _, rcc := range rc.Children { + if sc := rcc.Scenario; sc != nil && sc.Id == astScenarioID { + return ru + } + } + } + } + } + return nil +} + +// FindScenario returns the scenario in the feature or in a rule in the feature func (f Feature) FindScenario(astScenarioID string) *messages.Scenario { for _, child := range f.GherkinDocument.Feature.Children { if sc := child.Scenario; sc != nil && sc.Id == astScenarioID { return sc } + if rc := child.Rule; rc != nil { + for _, rcc := range rc.Children { + if sc := rcc.Scenario; sc != nil && sc.Id == astScenarioID { + return sc + } + } + } } return nil @@ -36,6 +59,18 @@ func (f Feature) FindBackground(astScenarioID string) *messages.Background { if sc := child.Scenario; sc != nil && sc.Id == astScenarioID { return bg } + + if ru := child.Rule; ru != nil { + for _, rc := range ru.Children { + if tmp := rc.Background; tmp != nil { + bg = tmp + } + + if sc := rc.Scenario; sc != nil && sc.Id == astScenarioID { + return bg + } + } + } } return nil @@ -61,6 +96,27 @@ func (f Feature) FindExample(exampleAstID string) (*messages.Examples, *messages // FindStep ... func (f Feature) FindStep(astStepID string) *messages.Step { for _, child := range f.GherkinDocument.Feature.Children { + + if ru := child.Rule; ru != nil { + for _, ch := range ru.Children { + if sc := ch.Scenario; sc != nil { + for _, step := range sc.Steps { + if step.Id == astStepID { + return step + } + } + } + + if bg := ch.Background; bg != nil { + for _, step := range bg.Steps { + if step.Id == astStepID { + return step + } + } + } + } + } + if sc := child.Scenario; sc != nil { for _, step := range sc.Steps { if step.Id == astStepID { diff --git a/run_test.go b/run_test.go index bbe4843b..da4fd874 100644 --- a/run_test.go +++ b/run_test.go @@ -432,11 +432,11 @@ func Test_AllFeaturesRun(t *testing.T) { ...................................................................... 140 ...................................................................... 210 ...................................................................... 280 -........................................ 320 +.............................................. 326 -83 scenarios (83 passed) -320 steps (320 passed) +85 scenarios (85 passed) +326 steps (326 passed) 0s ` @@ -459,11 +459,11 @@ func Test_AllFeaturesRunAsSubtests(t *testing.T) { ...................................................................... 140 ...................................................................... 210 ...................................................................... 280 -........................................ 320 +.............................................. 326 -83 scenarios (83 passed) -320 steps (320 passed) +85 scenarios (85 passed) +326 steps (326 passed) 0s `