some necessary command line options

Этот коммит содержится в:
gedi 2015-06-17 16:44:42 +03:00
родитель cb47b27090
коммит a3ef3361f8
6 изменённых файлов: 115 добавлений и 16 удалений

Просмотреть файл

@ -41,6 +41,11 @@ func init() {
flag.StringVar(&cfg.format, "format", "pretty", "") flag.StringVar(&cfg.format, "format", "pretty", "")
flag.StringVar(&cfg.format, "f", "pretty", "") flag.StringVar(&cfg.format, "f", "pretty", "")
flag.BoolVar(&cfg.definitions, "definitions", false, "")
flag.BoolVar(&cfg.definitions, "d", false, "")
flag.BoolVar(&cfg.stopOnFailure, "stop-on-failure", false, "")
flag.BoolVar(&cfg.version, "version", false, "")
flag.Usage = func() { flag.Usage = func() {
// prints an option or argument with a description, or only description // prints an option or argument with a description, or only description
opt := func(name, desc string) string { opt := func(name, desc string) string {
@ -66,11 +71,17 @@ func init() {
// --- OPTIONS --- // --- OPTIONS ---
fmt.Println(cl("Options:", yellow)) fmt.Println(cl("Options:", yellow))
// --> step definitions
fmt.Println(opt("-d, --definitions", "Print all available step definitions."))
// --> format // --> format
fmt.Println(opt("-f, --format=pretty", "How to format tests output. Available formats:")) fmt.Println(opt("-f, --format=pretty", "How to format tests output. Available formats:"))
for _, f := range formatters { for _, f := range formatters {
fmt.Println(opt("", s(4)+"- "+cl(f.name, yellow)+": "+f.description)) fmt.Println(opt("", s(4)+"- "+cl(f.name, yellow)+": "+f.description))
} }
// --> stop on failure
fmt.Println(opt("--stop-on-failure", "Stop processing on first failed scenario."))
// --> version
fmt.Println(opt("--version", "Show current "+cl("godog", yellow)+" version."))
fmt.Println("") fmt.Println("")
} }
} }
@ -78,6 +89,10 @@ func init() {
type config struct { type config struct {
paths []string paths []string
format string format string
definitions bool
stopOnFailure bool
version bool
} }
func (c *config) validate() error { func (c *config) validate() error {

Просмотреть файл

@ -6,4 +6,12 @@ Feature: suite hooks
Background: Background:
Given I have a before scenario hook Given I have a before scenario hook
And a feature path "features/load_features.feature:6" And a feature path "features/load_features.feature:6"
# When I parse and run features And I parse features
Scenario: hi there
When I run features
Then I should have a scenario "" recorded in the hook
Scenario: and there
When I run features
Then I should have a scenario "" recorded in the hook

Просмотреть файл

@ -89,10 +89,16 @@ func (f *pretty) line(tok *gherkin.Token) string {
// checks whether it should not print a background step once again // checks whether it should not print a background step once again
func (f *pretty) canPrintStep(step *gherkin.Step) bool { func (f *pretty) canPrintStep(step *gherkin.Step) bool {
if f.background != nil { if f.background == nil {
return step.Background != nil return true
} }
return true
if step.Background == nil {
f.doneBackground = true
return true
}
return !f.doneBackground
} }
// Node takes a gherkin node for formatting // Node takes a gherkin node for formatting
@ -110,9 +116,20 @@ func (f *pretty) Node(node interface{}) {
fmt.Println(bcl("Feature: ", white) + t.Title) fmt.Println(bcl("Feature: ", white) + t.Title)
fmt.Println(t.Description) fmt.Println(t.Description)
case *gherkin.Background: case *gherkin.Background:
f.background = t // determine comment position based on step length
fmt.Println("\n" + bcl("Background:", white)) f.commentPos = len(t.Token.Text)
for _, step := range t.Steps {
if len(step.Token.Text) > f.commentPos {
f.commentPos = len(step.Token.Text)
}
}
// do not repeat background
if !f.doneBackground {
f.background = t
fmt.Println("\n" + strings.Repeat(" ", t.Token.Indent) + bcl("Background:", white))
}
case *gherkin.Scenario: case *gherkin.Scenario:
// determine comment position based on step length
f.commentPos = len(t.Token.Text) f.commentPos = len(t.Token.Text)
for _, step := range t.Steps { for _, step := range t.Steps {
if len(step.Token.Text) > f.commentPos { if len(step.Token.Text) > f.commentPos {
@ -187,9 +204,6 @@ func (f *pretty) Summary() {
// prints a single matched step // prints a single matched step
func (f *pretty) printMatchedStep(step *gherkin.Step, match *stepMatchHandler, c color) { func (f *pretty) printMatchedStep(step *gherkin.Step, match *stepMatchHandler, c color) {
if !f.canPrintStep(step) {
return
}
var text string var text string
if m := (match.expr.FindStringSubmatchIndex(step.Text))[2:]; len(m) > 0 { if m := (match.expr.FindStringSubmatchIndex(step.Text))[2:]; len(m) > 0 {
var pos, i int var pos, i int
@ -228,7 +242,9 @@ func (f *pretty) printMatchedStep(step *gherkin.Step, match *stepMatchHandler, c
// Passed is called to represent a passed step // Passed is called to represent a passed step
func (f *pretty) Passed(step *gherkin.Step, match *stepMatchHandler) { func (f *pretty) Passed(step *gherkin.Step, match *stepMatchHandler) {
f.printMatchedStep(step, match, green) if f.canPrintStep(step) {
f.printMatchedStep(step, match, green)
}
f.passed = append(f.passed, &passed{step}) f.passed = append(f.passed, &passed{step})
} }
@ -250,7 +266,9 @@ func (f *pretty) Undefined(step *gherkin.Step) {
// Failed is called to represent a failed step // Failed is called to represent a failed step
func (f *pretty) Failed(step *gherkin.Step, match *stepMatchHandler, err error) { func (f *pretty) Failed(step *gherkin.Step, match *stepMatchHandler, err error) {
f.printMatchedStep(step, match, red) if f.canPrintStep(step) {
fmt.Println(strings.Repeat(" ", step.Token.Indent) + bcl(err, red)) f.printMatchedStep(step, match, red)
fmt.Println(strings.Repeat(" ", step.Token.Indent) + bcl(err, red))
}
f.failed = append(f.failed, &failed{step, err}) f.failed = append(f.failed, &failed{step, err})
} }

Просмотреть файл

@ -33,3 +33,5 @@ As youll see, Godog is easy to learn, quick to use, and will put the fun back
Godog was inspired by Behat and the above description is taken from it's documentation. Godog was inspired by Behat and the above description is taken from it's documentation.
*/ */
package godog package godog
const Version = "v0.1.0-alpha"

Просмотреть файл

@ -3,7 +3,9 @@ package godog
import ( import (
"flag" "flag"
"fmt" "fmt"
"reflect"
"regexp" "regexp"
"runtime"
"github.com/DATA-DOG/godog/gherkin" "github.com/DATA-DOG/godog/gherkin"
) )
@ -63,6 +65,8 @@ type suite struct {
stepHandlers []*stepMatchHandler stepHandlers []*stepMatchHandler
features []*gherkin.Feature features []*gherkin.Feature
fmt Formatter fmt Formatter
stop bool
} }
// New initializes a suite which supports the Suite // New initializes a suite which supports the Suite
@ -99,14 +103,29 @@ func (s *suite) Run() {
if !flag.Parsed() { if !flag.Parsed() {
flag.Parse() flag.Parse()
} }
fatal(cfg.validate())
// check if we need to just show something first
switch {
case cfg.version:
fmt.Println(cl("Godog", green) + " version is " + cl(Version, yellow))
return
case cfg.definitions:
s.printStepDefinitions()
return
}
// run a feature suite
fatal(cfg.validate())
s.fmt = cfg.formatter() s.fmt = cfg.formatter()
s.features, err = cfg.features() s.features, err = cfg.features()
fatal(err) fatal(err)
for _, f := range s.features { for _, f := range s.features {
s.runFeature(f) s.runFeature(f)
if s.stop {
// stop on first failure
break
}
} }
s.fmt.Summary() s.fmt.Summary()
} }
@ -171,14 +190,16 @@ func (s *suite) skipSteps(steps []*gherkin.Step) {
func (s *suite) runFeature(f *gherkin.Feature) { func (s *suite) runFeature(f *gherkin.Feature) {
s.fmt.Node(f) s.fmt.Node(f)
var failed bool
for _, scenario := range f.Scenarios { for _, scenario := range f.Scenarios {
var failed bool
// run before scenario handlers // run before scenario handlers
for _, h := range s.beforeScenarioHandlers { for _, h := range s.beforeScenarioHandlers {
h.BeforeScenario(scenario) h.BeforeScenario(scenario)
} }
// background // background
if f.Background != nil && !failed { if f.Background != nil {
s.fmt.Node(f.Background) s.fmt.Node(f.Background)
failed = s.runSteps(f.Background.Steps) failed = s.runSteps(f.Background.Steps)
} }
@ -188,7 +209,28 @@ func (s *suite) runFeature(f *gherkin.Feature) {
if failed { if failed {
s.skipSteps(scenario.Steps) s.skipSteps(scenario.Steps)
} else { } else {
s.runSteps(scenario.Steps) failed = s.runSteps(scenario.Steps)
}
if failed && cfg.stopOnFailure {
s.stop = true
return
} }
} }
} }
func (st *suite) printStepDefinitions() {
var longest int
for _, def := range st.stepHandlers {
if longest < len(def.expr.String()) {
longest = len(def.expr.String())
}
}
for _, def := range st.stepHandlers {
location := runtime.FuncForPC(reflect.ValueOf(def.handler).Pointer()).Name()
fmt.Println(cl(def.expr.String(), yellow)+s(longest-len(def.expr.String())), cl("# "+location, black))
}
if len(st.stepHandlers) == 0 {
fmt.Println("there were no contexts registered, could not find any step definition..")
}
}

Просмотреть файл

@ -9,11 +9,22 @@ import (
type suiteFeature struct { type suiteFeature struct {
suite suite
// for hook tests
befScenarioHook *gherkin.Scenario
} }
func (s *suiteFeature) BeforeScenario(scenario *gherkin.Scenario) { func (s *suiteFeature) BeforeScenario(scenario *gherkin.Scenario) {
// reset feature paths // reset feature paths
cfg.paths = []string{} cfg.paths = []string{}
// reset hook test references
s.befScenarioHook = nil
}
func (s *suiteFeature) iHaveBeforeScenarioHook(args ...*Arg) error {
s.suite.BeforeScenario(BeforeScenarioHandlerFunc(func(scenario *gherkin.Scenario) {
s.befScenarioHook = scenario
}))
return nil
} }
func (s *suiteFeature) featurePath(args ...*Arg) error { func (s *suiteFeature) featurePath(args ...*Arg) error {
@ -63,4 +74,7 @@ func SuiteContext(g Suite) {
g.Step( g.Step(
regexp.MustCompile(`^I should have ([\d]+) scenarios? registered$`), regexp.MustCompile(`^I should have ([\d]+) scenarios? registered$`),
StepHandlerFunc(s.numScenariosRegistered)) StepHandlerFunc(s.numScenariosRegistered))
g.Step(
regexp.MustCompile(`^I have a before scenario hook$`),
StepHandlerFunc(s.iHaveBeforeScenarioHook))
} }