188 строки
4,2 КиБ
Go
188 строки
4,2 КиБ
Go
package godog
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"github.com/DATA-DOG/godog/gherkin"
|
|
)
|
|
|
|
type BeforeScenarioHandler interface {
|
|
BeforeScenario(scenario *gherkin.Scenario)
|
|
}
|
|
|
|
type BeforeScenarioHandlerFunc func(scenario *gherkin.Scenario)
|
|
|
|
func (f BeforeScenarioHandlerFunc) BeforeScenario(scenario *gherkin.Scenario) {
|
|
f(scenario)
|
|
}
|
|
|
|
// Objects implementing the StepHandler interface can be
|
|
// registered as step definitions in godog
|
|
//
|
|
// HandleStep method receives all arguments which
|
|
// will be matched according to the regular expression
|
|
// which is passed with a step registration.
|
|
// The error in return - represents a reason of failure.
|
|
//
|
|
// Returning signals that the step has finished
|
|
// and that the feature runner can move on to the next
|
|
// step.
|
|
type StepHandler interface {
|
|
HandleStep(args ...Arg) error
|
|
}
|
|
|
|
// StepHandlerFunc type is an adapter to allow the use of
|
|
// ordinary functions as Step handlers. If f is a function
|
|
// with the appropriate signature, StepHandlerFunc(f) is a
|
|
// StepHandler object that calls f.
|
|
type StepHandlerFunc func(...Arg) error
|
|
|
|
// HandleStep calls f(step_arguments...).
|
|
func (f StepHandlerFunc) HandleStep(args ...Arg) error {
|
|
return f(args...)
|
|
}
|
|
|
|
var errPending = fmt.Errorf("pending step")
|
|
|
|
type stepMatchHandler struct {
|
|
handler StepHandler
|
|
expr *regexp.Regexp
|
|
}
|
|
|
|
// Suite is an interface which allows various contexts
|
|
// to register step definitions and event handlers
|
|
type Suite interface {
|
|
Step(expr *regexp.Regexp, h StepHandler)
|
|
BeforeScenario(h BeforeScenarioHandler)
|
|
}
|
|
|
|
type suite struct {
|
|
beforeScenarioHandlers []BeforeScenarioHandler
|
|
stepHandlers []*stepMatchHandler
|
|
features []*gherkin.Feature
|
|
fmt Formatter
|
|
}
|
|
|
|
// New initializes a suite which supports the Suite
|
|
// interface. The instance is passed around to all
|
|
// context initialization functions from *_test.go files
|
|
func New() *suite {
|
|
return &suite{}
|
|
}
|
|
|
|
// Step allows to register a StepHandler in Godog
|
|
// feature suite, the handler will be applied to all
|
|
// steps matching the given regexp
|
|
//
|
|
// Note that if there are two handlers which may match
|
|
// the same step, then the only first matched handler
|
|
// will be applied
|
|
//
|
|
// If none of the StepHandlers are matched, then a pending
|
|
// step error will be raised.
|
|
func (s *suite) Step(expr *regexp.Regexp, h StepHandler) {
|
|
s.stepHandlers = append(s.stepHandlers, &stepMatchHandler{
|
|
handler: h,
|
|
expr: expr,
|
|
})
|
|
}
|
|
|
|
func (s *suite) BeforeScenario(h BeforeScenarioHandler) {
|
|
s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, h)
|
|
}
|
|
|
|
// Run - runs a godog feature suite
|
|
func (s *suite) Run() {
|
|
var err error
|
|
if !flag.Parsed() {
|
|
flag.Parse()
|
|
}
|
|
fatal(cfg.validate())
|
|
|
|
s.fmt = cfg.formatter()
|
|
s.features, err = cfg.features()
|
|
fatal(err)
|
|
|
|
for _, f := range s.features {
|
|
s.runFeature(f)
|
|
}
|
|
s.fmt.Summary()
|
|
}
|
|
|
|
func (s *suite) runStep(step *gherkin.Step) (err error) {
|
|
var match *stepMatchHandler
|
|
var args []Arg
|
|
for _, h := range s.stepHandlers {
|
|
if m := h.expr.FindStringSubmatch(step.Text); len(m) > 0 {
|
|
match = h
|
|
for _, a := range m[1:] {
|
|
args = append(args, Arg(a))
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if match == nil {
|
|
s.fmt.Undefined(step)
|
|
return errPending
|
|
}
|
|
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
err = e.(error)
|
|
s.fmt.Failed(step, match, err)
|
|
}
|
|
}()
|
|
|
|
if err = match.handler.HandleStep(args...); err != nil {
|
|
s.fmt.Failed(step, match, err)
|
|
} else {
|
|
s.fmt.Passed(step, match)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *suite) runSteps(steps []*gherkin.Step) bool {
|
|
var failed bool
|
|
for _, step := range steps {
|
|
if failed {
|
|
s.fmt.Skipped(step)
|
|
continue
|
|
}
|
|
if err := s.runStep(step); err != nil {
|
|
failed = true
|
|
}
|
|
}
|
|
return failed
|
|
}
|
|
|
|
func (s *suite) skipSteps(steps []*gherkin.Step) {
|
|
for _, step := range steps {
|
|
s.fmt.Skipped(step)
|
|
}
|
|
}
|
|
|
|
func (s *suite) runFeature(f *gherkin.Feature) {
|
|
s.fmt.Node(f)
|
|
var failed bool
|
|
for _, scenario := range f.Scenarios {
|
|
// run before scenario handlers
|
|
for _, h := range s.beforeScenarioHandlers {
|
|
h.BeforeScenario(scenario)
|
|
}
|
|
// background
|
|
if f.Background != nil && !failed {
|
|
s.fmt.Node(f.Background)
|
|
failed = s.runSteps(f.Background.Steps)
|
|
}
|
|
|
|
// scenario
|
|
s.fmt.Node(scenario)
|
|
if failed {
|
|
s.skipSteps(scenario.Steps)
|
|
} else {
|
|
s.runSteps(scenario.Steps)
|
|
}
|
|
}
|
|
}
|