diff --git a/features/run.feature b/features/run.feature index a4e7173..b8f033c 100644 --- a/features/run.feature +++ b/features/run.feature @@ -163,3 +163,30 @@ Feature: run features """ I should have 1 scenario registered """ + + Scenario: should mark undefined steps after pending + Given a feature "pending.feature" file: + """ + Feature: pending feature + + Scenario: parse a scenario + Given pending step + When undefined + Then undefined 2 + And I should have 1 scenario registered + """ + When I run feature suite + Then the suite should have passed + And the following steps should be undefined: + """ + undefined + undefined 2 + """ + And the following step should be pending: + """ + pending step + """ + And the following step should be skipped: + """ + I should have 1 scenario registered + """ diff --git a/fmt.go b/fmt.go index e38887b..e34fc19 100644 --- a/fmt.go +++ b/fmt.go @@ -2,6 +2,8 @@ package godog import ( "fmt" + "strings" + "time" "github.com/cucumber/gherkin-go" ) @@ -90,3 +92,121 @@ type pending struct { step *gherkin.Step def *StepDef } + +type basefmt struct { + owner interface{} + indent int + + started time.Time + features []*feature + failed []*failed + passed []*passed + skipped []*skipped + undefined []*undefined + pending []*pending +} + +func (f *basefmt) Node(n interface{}) { + switch t := n.(type) { + case *gherkin.ScenarioOutline: + f.owner = t + case *gherkin.Scenario: + f.owner = t + case *gherkin.Background: + f.owner = t + } +} + +func (f *basefmt) Feature(ft *gherkin.Feature, p string) { + f.features = append(f.features, &feature{Path: p, Feature: ft}) +} + +func (f *basefmt) Passed(step *gherkin.Step, match *StepDef) { + s := &passed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match} + f.passed = append(f.passed, s) +} + +func (f *basefmt) Skipped(step *gherkin.Step) { + s := &skipped{owner: f.owner, feature: f.features[len(f.features)-1], step: step} + f.skipped = append(f.skipped, s) +} + +func (f *basefmt) Undefined(step *gherkin.Step) { + s := &undefined{owner: f.owner, feature: f.features[len(f.features)-1], step: step} + f.undefined = append(f.undefined, s) +} + +func (f *basefmt) Failed(step *gherkin.Step, match *StepDef, err error) { + s := &failed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match, err: err} + f.failed = append(f.failed, s) +} + +func (f *basefmt) Pending(step *gherkin.Step, match *StepDef) { + s := &pending{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match} + f.pending = append(f.pending, s) +} + +func (f *basefmt) Summary() { + var total, passed, undefined int + for _, ft := range f.features { + for _, def := range ft.ScenarioDefinitions { + switch t := def.(type) { + case *gherkin.Scenario: + total++ + case *gherkin.ScenarioOutline: + for _, ex := range t.Examples { + total += len(ex.TableBody) + } + } + } + } + passed = total + var owner interface{} + for _, undef := range f.undefined { + if owner != undef.owner { + undefined++ + owner = undef.owner + } + } + + var steps, parts, scenarios []string + nsteps := len(f.passed) + len(f.failed) + len(f.skipped) + len(f.undefined) + len(f.pending) + if len(f.passed) > 0 { + steps = append(steps, cl(fmt.Sprintf("%d passed", len(f.passed)), green)) + } + if len(f.failed) > 0 { + passed -= len(f.failed) + parts = append(parts, cl(fmt.Sprintf("%d failed", len(f.failed)), red)) + steps = append(steps, parts[len(parts)-1]) + } + if len(f.pending) > 0 { + steps = append(steps, cl(fmt.Sprintf("%d pending", len(f.pending)), yellow)) + } + if len(f.undefined) > 0 { + passed -= undefined + parts = append(parts, cl(fmt.Sprintf("%d undefined", undefined), yellow)) + steps = append(steps, cl(fmt.Sprintf("%d undefined", len(f.undefined)), yellow)) + } + if len(f.skipped) > 0 { + steps = append(steps, cl(fmt.Sprintf("%d skipped", len(f.skipped)), cyan)) + } + if passed > 0 { + scenarios = append(scenarios, cl(fmt.Sprintf("%d passed", passed), green)) + } + scenarios = append(scenarios, parts...) + elapsed := time.Since(f.started) + + fmt.Println("") + if total == 0 { + fmt.Println("No scenarios") + } else { + fmt.Println(fmt.Sprintf("%d scenarios (%s)", total, strings.Join(scenarios, ", "))) + } + + if nsteps == 0 { + fmt.Println("No steps") + } else { + fmt.Println(fmt.Sprintf("%d steps (%s)", nsteps, strings.Join(steps, ", "))) + } + fmt.Println(elapsed) +} diff --git a/fmt_pretty.go b/fmt_pretty.go index b47540b..37e511d 100644 --- a/fmt_pretty.go +++ b/fmt_pretty.go @@ -12,8 +12,10 @@ import ( func init() { RegisterFormatter("pretty", "Prints every feature with runtime statuses.", &pretty{ - started: time.Now(), - indent: 2, + basefmt: basefmt{ + started: time.Now(), + indent: 2, + }, }) } @@ -21,8 +23,7 @@ var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>") // a built in default pretty formatter type pretty struct { - scope interface{} - indent int + basefmt commentPos int backgroundSteps int @@ -30,15 +31,6 @@ type pretty struct { outlineSteps []interface{} outlineNumExample int outlineNumExamples int - - // summary - started time.Time - features []*feature - failed []*failed - passed []*passed - skipped []*skipped - undefined []*undefined - pending []*pending } // a line number representation in feature file @@ -81,20 +73,18 @@ func (f *pretty) Feature(ft *gherkin.Feature, p string) { // Node takes a gherkin node for formatting func (f *pretty) Node(node interface{}) { + f.basefmt.Node(node) + switch t := node.(type) { case *gherkin.Examples: f.outlineNumExamples = len(t.TableBody) f.outlineNumExample++ - case *gherkin.Background: - f.scope = t case *gherkin.Scenario: - f.scope = t f.commentPos = f.longestStep(t.Steps, f.length(t)) text := s(f.indent) + bcl(t.Keyword+": ", white) + t.Name text += s(f.commentPos-f.length(t)+1) + f.line(t.Location) fmt.Println("\n" + text) case *gherkin.ScenarioOutline: - f.scope = t f.commentPos = f.longestStep(t.Steps, f.length(t)) text := s(f.indent) + bcl(t.Keyword+": ", white) + t.Name text += s(f.commentPos-f.length(t)+1) + f.line(t.Location) @@ -135,68 +125,7 @@ func (f *pretty) Summary() { fmt.Println(" " + cl(fail, red)) } } - var total, passed, undefined int - for _, ft := range f.features { - for _, def := range ft.ScenarioDefinitions { - switch t := def.(type) { - case *gherkin.Scenario: - total++ - case *gherkin.ScenarioOutline: - for _, ex := range t.Examples { - total += len(ex.TableBody) - } - } - } - } - passed = total - var owner interface{} - for _, undef := range f.undefined { - if owner != undef.owner { - undefined++ - owner = undef.owner - } - } - - var steps, parts, scenarios []string - nsteps := len(f.passed) + len(f.failed) + len(f.skipped) + len(f.undefined) + len(f.pending) - if len(f.passed) > 0 { - steps = append(steps, cl(fmt.Sprintf("%d passed", len(f.passed)), green)) - } - if len(f.pending) > 0 { - steps = append(steps, cl(fmt.Sprintf("%d pending", len(f.pending)), yellow)) - } - if len(f.failed) > 0 { - passed -= len(f.failed) - parts = append(parts, cl(fmt.Sprintf("%d failed", len(f.failed)), red)) - steps = append(steps, parts[len(parts)-1]) - } - if len(f.skipped) > 0 { - steps = append(steps, cl(fmt.Sprintf("%d skipped", len(f.skipped)), cyan)) - } - if len(f.undefined) > 0 { - passed -= undefined - parts = append(parts, cl(fmt.Sprintf("%d undefined", undefined), yellow)) - steps = append(steps, cl(fmt.Sprintf("%d undefined", len(f.undefined)), yellow)) - } - if passed > 0 { - scenarios = append(scenarios, cl(fmt.Sprintf("%d passed", passed), green)) - } - scenarios = append(scenarios, parts...) - elapsed := time.Since(f.started) - - fmt.Println("") - if total == 0 { - fmt.Println("No scenarios") - } else { - fmt.Println(fmt.Sprintf("%d scenarios (%s)", total, strings.Join(scenarios, ", "))) - } - - if nsteps == 0 { - fmt.Println("No steps") - } else { - fmt.Println(fmt.Sprintf("%d steps (%s)", nsteps, strings.Join(steps, ", "))) - } - fmt.Println(elapsed) + f.basefmt.Summary() } func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) { @@ -389,38 +318,29 @@ func (f *pretty) printTable(t *gherkin.DataTable, c color) { } } -// Passed is called to represent a passed step func (f *pretty) Passed(step *gherkin.Step, match *StepDef) { - s := &passed{owner: f.scope, feature: f.features[len(f.features)-1], step: step, def: match} - f.printStepKind(s) - f.passed = append(f.passed, s) + f.basefmt.Passed(step, match) + f.printStepKind(f.passed[len(f.passed)-1]) } -// Skipped is called to represent a passed step func (f *pretty) Skipped(step *gherkin.Step) { - s := &skipped{owner: f.scope, feature: f.features[len(f.features)-1], step: step} - f.printStepKind(s) - f.skipped = append(f.skipped, s) + f.basefmt.Skipped(step) + f.printStepKind(f.skipped[len(f.skipped)-1]) } -// Undefined is called to represent a pending step func (f *pretty) Undefined(step *gherkin.Step) { - s := &undefined{owner: f.scope, feature: f.features[len(f.features)-1], step: step} - f.printStepKind(s) - f.undefined = append(f.undefined, s) + f.basefmt.Undefined(step) + f.printStepKind(f.undefined[len(f.undefined)-1]) } -// Failed is called to represent a failed step func (f *pretty) Failed(step *gherkin.Step, match *StepDef, err error) { - s := &failed{owner: f.scope, feature: f.features[len(f.features)-1], step: step, def: match, err: err} - f.printStepKind(s) - f.failed = append(f.failed, s) + f.basefmt.Failed(step, match, err) + f.printStepKind(f.failed[len(f.failed)-1]) } func (f *pretty) Pending(step *gherkin.Step, match *StepDef) { - s := &pending{owner: f.scope, feature: f.features[len(f.features)-1], step: step, def: match} - f.printStepKind(s) - f.pending = append(f.pending, s) + f.basefmt.Pending(step, match) + f.printStepKind(f.pending[len(f.pending)-1]) } // longest gives a list of longest columns of all rows in Table diff --git a/fmt_progress.go b/fmt_progress.go index 72a4ddc..3c229ba 100644 --- a/fmt_progress.go +++ b/fmt_progress.go @@ -3,7 +3,6 @@ package godog import ( "fmt" "math" - "strings" "time" "github.com/cucumber/gherkin-go" @@ -11,39 +10,18 @@ import ( func init() { RegisterFormatter("progress", "Prints a character per step.", &progress{ - started: time.Now(), + basefmt: basefmt{ + started: time.Now(), + indent: 2, + }, stepsPerRow: 70, }) } type progress struct { + basefmt stepsPerRow int - started time.Time steps int - - features []*feature - owner interface{} - - failed []*failed - passed []*passed - skipped []*skipped - undefined []*undefined - pending []*pending -} - -func (f *progress) Feature(ft *gherkin.Feature, p string) { - f.features = append(f.features, &feature{Path: p, Feature: ft}) -} - -func (f *progress) Node(n interface{}) { - switch t := n.(type) { - case *gherkin.ScenarioOutline: - f.owner = t - case *gherkin.Scenario: - f.owner = t - case *gherkin.Background: - f.owner = t - } } func (f *progress) Summary() { @@ -64,68 +42,7 @@ func (f *progress) Summary() { fmt.Println(s(6) + cl("Error: ", red) + bcl(fail.err, red) + "\n") } } - var total, passed, undefined int - for _, ft := range f.features { - for _, def := range ft.ScenarioDefinitions { - switch t := def.(type) { - case *gherkin.Scenario: - total++ - case *gherkin.ScenarioOutline: - for _, ex := range t.Examples { - total += len(ex.TableBody) - } - } - } - } - passed = total - var owner interface{} - for _, undef := range f.undefined { - if owner != undef.owner { - undefined++ - owner = undef.owner - } - } - - var steps, parts, scenarios []string - nsteps := len(f.passed) + len(f.failed) + len(f.skipped) + len(f.undefined) + len(f.pending) - if len(f.passed) > 0 { - steps = append(steps, cl(fmt.Sprintf("%d passed", len(f.passed)), green)) - } - if len(f.pending) > 0 { - steps = append(steps, cl(fmt.Sprintf("%d pending", len(f.pending)), yellow)) - } - if len(f.failed) > 0 { - passed -= len(f.failed) - parts = append(parts, cl(fmt.Sprintf("%d failed", len(f.failed)), red)) - steps = append(steps, parts[len(parts)-1]) - } - if len(f.skipped) > 0 { - steps = append(steps, cl(fmt.Sprintf("%d skipped", len(f.skipped)), cyan)) - } - if len(f.undefined) > 0 { - passed -= undefined - parts = append(parts, cl(fmt.Sprintf("%d undefined", undefined), yellow)) - steps = append(steps, cl(fmt.Sprintf("%d undefined", len(f.undefined)), yellow)) - } - if passed > 0 { - scenarios = append(scenarios, cl(fmt.Sprintf("%d passed", passed), green)) - } - scenarios = append(scenarios, parts...) - elapsed := time.Since(f.started) - - fmt.Println("") - if total == 0 { - fmt.Println("No scenarios") - } else { - fmt.Println(fmt.Sprintf("%d scenarios (%s)", total, strings.Join(scenarios, ", "))) - } - - if nsteps == 0 { - fmt.Println("No steps") - } else { - fmt.Println(fmt.Sprintf("%d steps (%s)", nsteps, strings.Join(steps, ", "))) - } - fmt.Println(elapsed) + f.basefmt.Summary() } func (f *progress) step(step interface{}) { @@ -148,31 +65,26 @@ func (f *progress) step(step interface{}) { } func (f *progress) Passed(step *gherkin.Step, match *StepDef) { - s := &passed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match} - f.passed = append(f.passed, s) - f.step(s) + f.basefmt.Passed(step, match) + f.step(f.passed[len(f.passed)-1]) } func (f *progress) Skipped(step *gherkin.Step) { - s := &skipped{owner: f.owner, feature: f.features[len(f.features)-1], step: step} - f.skipped = append(f.skipped, s) - f.step(s) + f.basefmt.Skipped(step) + f.step(f.skipped[len(f.skipped)-1]) } func (f *progress) Undefined(step *gherkin.Step) { - s := &undefined{owner: f.owner, feature: f.features[len(f.features)-1], step: step} - f.undefined = append(f.undefined, s) - f.step(s) + f.basefmt.Undefined(step) + f.step(f.undefined[len(f.undefined)-1]) } func (f *progress) Failed(step *gherkin.Step, match *StepDef, err error) { - s := &failed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match, err: err} - f.failed = append(f.failed, s) - f.step(s) + f.basefmt.Failed(step, match, err) + f.step(f.failed[len(f.failed)-1]) } func (f *progress) Pending(step *gherkin.Step, match *StepDef) { - s := &pending{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match} - f.pending = append(f.pending, s) - f.step(s) + f.basefmt.Pending(step, match) + f.step(f.pending[len(f.pending)-1]) } diff --git a/fmt_test.go b/fmt_test.go index d46d605..b6b5bd3 100644 --- a/fmt_test.go +++ b/fmt_test.go @@ -3,53 +3,18 @@ package godog import "github.com/cucumber/gherkin-go" type testFormatter struct { - owner interface{} - features []*feature + basefmt scenarios []interface{} - - failed []*failed - passed []*passed - skipped []*skipped - undefined []*undefined - pending []*pending -} - -func (f *testFormatter) Feature(ft *gherkin.Feature, p string) { - f.features = append(f.features, &feature{Path: p, Feature: ft}) } func (f *testFormatter) Node(node interface{}) { + f.basefmt.Node(node) switch t := node.(type) { case *gherkin.Scenario: f.scenarios = append(f.scenarios, t) - f.owner = t case *gherkin.ScenarioOutline: f.scenarios = append(f.scenarios, t) - f.owner = t - case *gherkin.Background: - f.owner = t } } func (f *testFormatter) Summary() {} - -func (f *testFormatter) Passed(step *gherkin.Step, match *StepDef) { - f.passed = append(f.passed, &passed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match}) -} - -func (f *testFormatter) Skipped(step *gherkin.Step) { - f.skipped = append(f.skipped, &skipped{owner: f.owner, feature: f.features[len(f.features)-1], step: step}) -} - -func (f *testFormatter) Undefined(step *gherkin.Step) { - f.undefined = append(f.undefined, &undefined{owner: f.owner, feature: f.features[len(f.features)-1], step: step}) -} - -func (f *testFormatter) Failed(step *gherkin.Step, match *StepDef, err error) { - f.failed = append(f.failed, &failed{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match, err: err}) -} - -func (f *testFormatter) Pending(step *gherkin.Step, match *StepDef) { - s := &pending{owner: f.owner, feature: f.features[len(f.features)-1], step: step, def: match} - f.pending = append(f.pending, s) -} diff --git a/suite_test.go b/suite_test.go index e5954bb..b6fd7dd 100644 --- a/suite_test.go +++ b/suite_test.go @@ -35,7 +35,7 @@ func SuiteContext(s Suite) { s.Step(`^aš išskaitau savybes$`, c.parseFeatures) s.Step(`^aš turėčiau turėti ([\d]+) savybių failus:$`, c.iShouldHaveNumFeatureFiles) - s.Step(`^pending step$`, func(...*Arg) error { + s.Step(`^pending step$`, func() error { return ErrPending }) }