use reflection to set step arguments #9

* 9226bc5 more expressive conversion errors
Этот коммит содержится в:
gedi 2015-06-27 22:40:15 +03:00
родитель d7334fd66e
коммит 2046da1611
5 изменённых файлов: 226 добавлений и 228 удалений

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

@ -79,19 +79,19 @@ func (c *GodogCart) resetReserve(interface{}) {
c.reserve = 0 c.reserve = 0
} }
func (c *GodogCart) thereAreNumGodogsInReserve(args ...*godog.Arg) error { func (c *GodogCart) thereAreNumGodogsInReserve(avail int) error {
c.reserve = args[0].Int() c.reserve = avail
return nil return nil
} }
func (c *GodogCart) iEatNum(args ...*godog.Arg) error { func (c *GodogCart) iEatNum(num int) error {
c.Eat(args[0].Int()) c.Eat(num)
return nil return nil
} }
func (c *GodogCart) thereShouldBeNumRemaining(args ...*godog.Arg) error { func (c *GodogCart) thereShouldBeNumRemaining(left int) error {
if c.Available() != args[0].Int() { if c.Available() != left {
return fmt.Errorf("expected %d godogs to be remaining, but there is %d", args[0].Int(), c.Available()) return fmt.Errorf("expected %d godogs to be remaining, but there is %d", left, c.Available())
} }
return nil return nil
} }

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

@ -1,143 +0,0 @@
package godog
import (
"fmt"
"strconv"
"github.com/cucumber/gherkin-go"
)
// Arg is an argument for StepHandler parsed from
// the regexp submatch to handle the step.
//
// In future versions, it may be replaced with
// an argument injection toolkit using reflect
// package.
type Arg struct {
value interface{}
}
// StepArgument func creates a step argument.
// used in cases when calling another step from
// within a StepHandler function.
func StepArgument(value interface{}) *Arg {
return &Arg{value: value}
}
// Float64 converts an argument to float64
// or panics if unable to convert it
func (a *Arg) Float64() float64 {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseFloat(s, 64)
if err == nil {
return v
}
panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, s, err))
}
// Float32 converts an argument to float32
// or panics if unable to convert it
func (a *Arg) Float32() float32 {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseFloat(s, 32)
if err == nil {
return float32(v)
}
panic(fmt.Sprintf(`cannot convert "%s" to float32: %s`, s, err))
}
// Int converts an argument to int
// or panics if unable to convert it
func (a *Arg) Int() int {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseInt(s, 10, 0)
if err == nil {
return int(v)
}
panic(fmt.Sprintf(`cannot convert "%s" to int: %s`, s, err))
}
// Int64 converts an argument to int64
// or panics if unable to convert it
func (a *Arg) Int64() int64 {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseInt(s, 10, 64)
if err == nil {
return v
}
panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, s, err))
}
// Int32 converts an argument to int32
// or panics if unable to convert it
func (a *Arg) Int32() int32 {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseInt(s, 10, 32)
if err == nil {
return int32(v)
}
panic(fmt.Sprintf(`cannot convert "%s" to int32: %s`, s, err))
}
// Int16 converts an argument to int16
// or panics if unable to convert it
func (a *Arg) Int16() int16 {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseInt(s, 10, 16)
if err == nil {
return int16(v)
}
panic(fmt.Sprintf(`cannot convert "%s" to int16: %s`, s, err))
}
// Int8 converts an argument to int8
// or panics if unable to convert it
func (a *Arg) Int8() int8 {
s, ok := a.value.(string)
a.must(ok, "string")
v, err := strconv.ParseInt(s, 10, 8)
if err == nil {
return int8(v)
}
panic(fmt.Sprintf(`cannot convert "%s" to int8: %s`, s, err))
}
// String converts an argument to string
func (a *Arg) String() string {
s, ok := a.value.(string)
a.must(ok, "string")
return s
}
// Bytes converts an argument string to bytes
func (a *Arg) Bytes() []byte {
s, ok := a.value.(string)
a.must(ok, "string")
return []byte(s)
}
// DocString converts an argument to *gherkin.DocString node
func (a *Arg) DocString() *gherkin.DocString {
s, ok := a.value.(*gherkin.DocString)
a.must(ok, "*gherkin.DocString")
return s
}
// DataTable converts an argument to *gherkin.DataTable node
func (a *Arg) DataTable() *gherkin.DataTable {
s, ok := a.value.(*gherkin.DataTable)
a.must(ok, "*gherkin.DataTable")
return s
}
func (a *Arg) must(ok bool, expected string) {
if !ok {
panic(fmt.Sprintf(`cannot convert "%v" of type "%T" to type "%s"`, a.value, a.value, expected))
}
}

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

@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/DATA-DOG/godog" "github.com/DATA-DOG/godog"
"github.com/cucumber/gherkin-go"
) )
type lsFeature struct { type lsFeature struct {
@ -24,29 +25,29 @@ func lsFeatureContext(s godog.Suite) {
s.Step(`^I should get output:$`, c.iShouldGetOutput) s.Step(`^I should get output:$`, c.iShouldGetOutput)
} }
func (f *lsFeature) iAmInDirectory(args ...*godog.Arg) error { func (f *lsFeature) iAmInDirectory(name string) error {
f.dir = os.TempDir() + "/" + args[0].String() f.dir = os.TempDir() + "/" + name
if err := os.RemoveAll(f.dir); err != nil && !os.IsNotExist(err) { if err := os.RemoveAll(f.dir); err != nil && !os.IsNotExist(err) {
return err return err
} }
return os.Mkdir(f.dir, 0775) return os.Mkdir(f.dir, 0775)
} }
func (f *lsFeature) iHaveFileOrDirectoryNamed(args ...*godog.Arg) (err error) { func (f *lsFeature) iHaveFileOrDirectoryNamed(typ, name string) (err error) {
if len(f.dir) == 0 { if len(f.dir) == 0 {
return fmt.Errorf("the directory was not chosen yet") return fmt.Errorf("the directory was not chosen yet")
} }
switch args[0].String() { switch typ {
case "file": case "file":
err = ioutil.WriteFile(f.dir+"/"+args[1].String(), []byte{}, 0664) err = ioutil.WriteFile(f.dir+"/"+name, []byte{}, 0664)
case "directory": case "directory":
err = os.Mkdir(f.dir+"/"+args[1].String(), 0775) err = os.Mkdir(f.dir+"/"+name, 0775)
} }
return err return err
} }
func (f *lsFeature) iShouldGetOutput(args ...*godog.Arg) error { func (f *lsFeature) iShouldGetOutput(names *gherkin.DocString) error {
expected := strings.Split(args[0].DocString().Content, "\n") expected := strings.Split(names.Content, "\n")
actual := strings.Split(strings.TrimSpace(f.buf.String()), "\n") actual := strings.Split(strings.TrimSpace(f.buf.String()), "\n")
if len(expected) != len(actual) { if len(expected) != len(actual) {
return fmt.Errorf("number of expected output lines %d, does not match actual: %d", len(expected), len(actual)) return fmt.Errorf("number of expected output lines %d, does not match actual: %d", len(expected), len(actual))
@ -59,7 +60,7 @@ func (f *lsFeature) iShouldGetOutput(args ...*godog.Arg) error {
return nil return nil
} }
func (f *lsFeature) iRunLs(args ...*godog.Arg) error { func (f *lsFeature) iRunLs() error {
f.buf.Reset() f.buf.Reset()
return ls(f.dir, f.buf) return ls(f.dir, f.buf)
} }

201
suite.go
Просмотреть файл

@ -13,28 +13,13 @@ import (
"github.com/cucumber/gherkin-go" "github.com/cucumber/gherkin-go"
) )
var errorInterface = reflect.TypeOf((*error)(nil)).Elem()
type feature struct { type feature struct {
*gherkin.Feature *gherkin.Feature
Path string `json:"path"` Path string `json:"path"`
} }
// Regexp is an unified type for regular expression
// it can be either a string or a *regexp.Regexp
type Regexp interface{}
// StepHandler is a func to handle the step
//
// The handler receives all arguments which
// will be matched according to the Regexp
// which is passed with a step registration.
//
// The error in return - represents a reason of failure.
// All consequent scenario steps are skipped.
//
// Returning signals that the step has finished and that
// the feature runner can move on to the next step.
type StepHandler func(...*Arg) error
// ErrUndefined is returned in case if step definition was not found // ErrUndefined is returned in case if step definition was not found
var ErrUndefined = fmt.Errorf("step is undefined") var ErrUndefined = fmt.Errorf("step is undefined")
@ -47,9 +32,133 @@ var ErrUndefined = fmt.Errorf("step is undefined")
// when step is matched and is either failed // when step is matched and is either failed
// or successful // or successful
type StepDef struct { type StepDef struct {
Args []*Arg args []interface{}
Handler StepHandler hv reflect.Value
Expr *regexp.Regexp Expr *regexp.Regexp
Handler interface{}
}
func (sd *StepDef) run() error {
typ := sd.hv.Type()
if len(sd.args) < typ.NumIn() {
return fmt.Errorf("func expects %d arguments, which is more than %d matched from step", typ.NumIn(), len(sd.args))
}
var values []reflect.Value
for i := 0; i < typ.NumIn(); i++ {
param := typ.In(i)
switch param.Kind() {
case reflect.Int:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseInt(s, 10, 0)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to int: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(int(v)))
case reflect.Int64:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to int64: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(int64(v)))
case reflect.Int32:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to int32: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(int32(v)))
case reflect.Int16:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseInt(s, 10, 16)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to int16: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(int16(v)))
case reflect.Int8:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseInt(s, 10, 8)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to int8: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(int8(v)))
case reflect.String:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
values = append(values, reflect.ValueOf(s))
case reflect.Float64:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseFloat(s, 64)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to float64: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(v))
case reflect.Float32:
s, err := sd.shouldBeString(i)
if err != nil {
return err
}
v, err := strconv.ParseFloat(s, 32)
if err != nil {
return fmt.Errorf(`cannot convert argument %d: "%s" to float32: %s`, i, s, err)
}
values = append(values, reflect.ValueOf(float32(v)))
case reflect.Ptr:
arg := sd.args[i]
switch param.Elem().String() {
case "gherkin.DocString":
v, ok := arg.(*gherkin.DocString)
if !ok {
return fmt.Errorf(`cannot convert argument %d: "%v" of type "%T" to *gherkin.DocString`, i, arg, arg)
}
values = append(values, reflect.ValueOf(v))
case "gherkin.DataTable":
v, ok := arg.(*gherkin.DataTable)
if !ok {
return fmt.Errorf(`cannot convert argument %d: "%v" of type "%T" to *gherkin.DocString`, i, arg, arg)
}
values = append(values, reflect.ValueOf(v))
default:
return fmt.Errorf("the argument %d type %T is not supported", i, arg)
}
default:
return fmt.Errorf("the argument %d type %s is not supported", i, param.Kind())
}
}
ret := sd.hv.Call(values)[0].Interface()
if nil == ret {
return nil
}
return ret.(error)
}
func (sd *StepDef) shouldBeString(idx int) (string, error) {
arg := sd.args[idx]
s, ok := arg.(string)
if !ok {
return "", fmt.Errorf(`cannot convert argument %d: "%v" of type "%T" to string`, idx, arg, arg)
}
return s, nil
} }
// Suite is an interface which allows various contexts // Suite is an interface which allows various contexts
@ -64,14 +173,36 @@ type StepDef struct {
// executions are catching panic error since it may // executions are catching panic error since it may
// be a context specific error. // be a context specific error.
type Suite interface { type Suite interface {
// Run the test suite
Run() Run()
Step(expr Regexp, h StepHandler)
// suite events // Registers a step which will execute stepFunc
// on step expr match
//
// expr can be either a string or a *regexp.Regexp
// stepFunc is a func to handle the step, arguments
// are set from matched step
Step(expr interface{}, h interface{})
// BeforeSuite registers a func to run on initial
// suite startup
BeforeSuite(f func()) BeforeSuite(f func())
// BeforeScenario registers a func to run before
// every *gherkin.Scenario or *gherkin.ScenarioOutline
BeforeScenario(f func(interface{})) BeforeScenario(f func(interface{}))
// BeforeStep register a handler before every step
BeforeStep(f func(*gherkin.Step)) BeforeStep(f func(*gherkin.Step))
// AfterStep register a handler after every step
AfterStep(f func(*gherkin.Step, error)) AfterStep(f func(*gherkin.Step, error))
// AfterScenario registers a func to run after
// every *gherkin.Scenario or *gherkin.ScenarioOutline
AfterScenario(f func(interface{}, error)) AfterScenario(f func(interface{}, error))
// AfterSuite runs func int the end of tests
AfterSuite(f func()) AfterSuite(f func())
} }
@ -117,7 +248,7 @@ func New() Suite {
// //
// If none of the StepHandlers are matched, then // If none of the StepHandlers are matched, then
// ErrUndefined error will be returned. // ErrUndefined error will be returned.
func (s *suite) Step(expr Regexp, h StepHandler) { func (s *suite) Step(expr interface{}, stepFunc interface{}) {
var regex *regexp.Regexp var regex *regexp.Regexp
switch t := expr.(type) { switch t := expr.(type) {
@ -131,9 +262,21 @@ func (s *suite) Step(expr Regexp, h StepHandler) {
panic(fmt.Sprintf("expecting expr to be a *regexp.Regexp or a string, got type: %T", expr)) 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 an error, but it has more values in return: %d", typ.NumOut()))
}
if typ.Out(0).Kind() != reflect.Interface || !typ.Out(0).Implements(errorInterface) {
panic(fmt.Sprintf("expected handler to return an error interface, but we have: %s", typ.Out(0).Kind()))
}
s.stepHandlers = append(s.stepHandlers, &StepDef{ s.stepHandlers = append(s.stepHandlers, &StepDef{
Handler: h, Handler: stepFunc,
Expr: regex, Expr: regex,
hv: v,
}) })
} }
@ -262,14 +405,14 @@ func (s *suite) run() {
func (s *suite) matchStep(step *gherkin.Step) *StepDef { func (s *suite) matchStep(step *gherkin.Step) *StepDef {
for _, h := range s.stepHandlers { for _, h := range s.stepHandlers {
if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 { if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 {
var args []*Arg var args []interface{}
for _, a := range m[1:] { for _, m := range m[1:] {
args = append(args, &Arg{value: a}) args = append(args, m)
} }
if step.Argument != nil { if step.Argument != nil {
args = append(args, &Arg{value: step.Argument}) args = append(args, step.Argument)
} }
h.Args = args h.args = args
return h return h
} }
} }
@ -293,7 +436,7 @@ func (s *suite) runStep(step *gherkin.Step) (err error) {
} }
}() }()
if err = match.Handler(match.Args...); err != nil { if err = match.run(); err != nil {
s.fmt.Failed(step, match, err) s.fmt.Failed(step, match, err)
} else { } else {
s.fmt.Passed(step, match) s.fmt.Passed(step, match)

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

@ -2,6 +2,7 @@ package godog
import ( import (
"fmt" "fmt"
"strconv"
"strings" "strings"
"github.com/cucumber/gherkin-go" "github.com/cucumber/gherkin-go"
@ -56,12 +57,12 @@ func (s *suiteContext) ResetBeforeEachScenario(interface{}) {
s.events = []*firedEvent{} s.events = []*firedEvent{}
} }
func (s *suiteContext) followingStepsShouldHave(args ...*Arg) error { func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.DocString) error {
var expected = strings.Split(args[1].DocString().Content, "\n") var expected = strings.Split(steps.Content, "\n")
var actual, unmatched []string var actual, unmatched []string
var matched []int var matched []int
switch args[0].String() { switch status {
case "passed": case "passed":
for _, st := range s.fmt.passed { for _, st := range s.fmt.passed {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
@ -79,11 +80,11 @@ func (s *suiteContext) followingStepsShouldHave(args ...*Arg) error {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
} }
default: default:
return fmt.Errorf("unexpected step status wanted: %s", args[0].String()) return fmt.Errorf("unexpected step status wanted: %s", status)
} }
if len(expected) > len(actual) { if len(expected) > len(actual) {
return fmt.Errorf("number of expected %s steps: %d is less than actual %s steps: %d", args[0].String(), len(expected), args[0].String(), 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 _, a := range actual {
@ -111,10 +112,10 @@ func (s *suiteContext) followingStepsShouldHave(args ...*Arg) error {
} }
} }
return fmt.Errorf("the steps: %s - is not %s", strings.Join(unmatched, ", "), args[0].String()) return fmt.Errorf("the steps: %s - is not %s", strings.Join(unmatched, ", "), status)
} }
func (s *suiteContext) iAmListeningToSuiteEvents(args ...*Arg) error { func (s *suiteContext) iAmListeningToSuiteEvents() error {
s.testedSuite.BeforeSuite(func() { s.testedSuite.BeforeSuite(func() {
s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}}) s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}})
}) })
@ -136,43 +137,41 @@ func (s *suiteContext) iAmListeningToSuiteEvents(args ...*Arg) error {
return nil return nil
} }
func (s *suiteContext) aFailingStep(...*Arg) error { func (s *suiteContext) aFailingStep() error {
return fmt.Errorf("intentional failure") return fmt.Errorf("intentional failure")
} }
// parse a given feature file body as a feature // parse a given feature file body as a feature
func (s *suiteContext) aFeatureFile(args ...*Arg) error { func (s *suiteContext) aFeatureFile(name string, body *gherkin.DocString) error {
name := args[0].String() ft, err := gherkin.ParseFeature(strings.NewReader(body.Content))
body := args[1].DocString().Content
ft, err := gherkin.ParseFeature(strings.NewReader(body))
s.testedSuite.features = append(s.testedSuite.features, &feature{Feature: ft, Path: name}) s.testedSuite.features = append(s.testedSuite.features, &feature{Feature: ft, Path: name})
return err return err
} }
func (s *suiteContext) featurePath(args ...*Arg) error { func (s *suiteContext) featurePath(path string) error {
s.testedSuite.paths = append(s.testedSuite.paths, args[0].String()) s.testedSuite.paths = append(s.testedSuite.paths, path)
return nil return nil
} }
func (s *suiteContext) parseFeatures(args ...*Arg) error { func (s *suiteContext) parseFeatures() error {
return s.testedSuite.parseFeatures() return s.testedSuite.parseFeatures()
} }
func (s *suiteContext) theSuiteShouldHave(args ...*Arg) error { func (s *suiteContext) theSuiteShouldHave(state string) error {
if s.testedSuite.failed && args[0].String() == "passed" { if s.testedSuite.failed && state == "passed" {
return fmt.Errorf("the feature suite has failed") return fmt.Errorf("the feature suite has failed")
} }
if !s.testedSuite.failed && args[0].String() == "failed" { if !s.testedSuite.failed && state == "failed" {
return fmt.Errorf("the feature suite has passed") return fmt.Errorf("the feature suite has passed")
} }
return nil return nil
} }
func (s *suiteContext) iShouldHaveNumFeatureFiles(args ...*Arg) error { func (s *suiteContext) iShouldHaveNumFeatureFiles(num int, files *gherkin.DocString) error {
if len(s.testedSuite.features) != args[0].Int() { if len(s.testedSuite.features) != num {
return fmt.Errorf("expected %d features to be parsed, but have %d", args[0].Int(), len(s.testedSuite.features)) return fmt.Errorf("expected %d features to be parsed, but have %d", num, len(s.testedSuite.features))
} }
expected := strings.Split(args[1].DocString().Content, "\n") expected := strings.Split(files.Content, "\n")
var actual []string var actual []string
for _, ft := range s.testedSuite.features { for _, ft := range s.testedSuite.features {
actual = append(actual, ft.Path) actual = append(actual, ft.Path)
@ -188,7 +187,7 @@ func (s *suiteContext) iShouldHaveNumFeatureFiles(args ...*Arg) error {
return nil return nil
} }
func (s *suiteContext) iRunFeatureSuite(args ...*Arg) error { func (s *suiteContext) iRunFeatureSuite() error {
if err := s.parseFeatures(); err != nil { if err := s.parseFeatures(); err != nil {
return err return err
} }
@ -196,31 +195,31 @@ func (s *suiteContext) iRunFeatureSuite(args ...*Arg) error {
return nil return nil
} }
func (s *suiteContext) numScenariosRegistered(args ...*Arg) (err error) { func (s *suiteContext) numScenariosRegistered(expected int) (err error) {
var num int var num int
for _, ft := range s.testedSuite.features { for _, ft := range s.testedSuite.features {
num += len(ft.ScenarioDefinitions) num += len(ft.ScenarioDefinitions)
} }
if num != args[0].Int() { if num != expected {
err = fmt.Errorf("expected %d scenarios to be registered, but got %d", args[0].Int(), num) err = fmt.Errorf("expected %d scenarios to be registered, but got %d", expected, num)
} }
return return
} }
func (s *suiteContext) thereWereNumEventsFired(args ...*Arg) error { func (s *suiteContext) thereWereNumEventsFired(_ string, expected int, typ string) error {
var num int var num int
for _, event := range s.events { for _, event := range s.events {
if event.name == args[2].String() { if event.name == typ {
num++ num++
} }
} }
if num != args[1].Int() { if num != expected {
return fmt.Errorf("expected %d %s events to be fired, but got %d", args[1].Int(), args[2].String(), num) return fmt.Errorf("expected %d %s events to be fired, but got %d", expected, typ, num)
} }
return nil return nil
} }
func (s *suiteContext) thereWasEventTriggeredBeforeScenario(args ...*Arg) error { func (s *suiteContext) thereWasEventTriggeredBeforeScenario(expected string) error {
var found []string var found []string
for _, event := range s.events { for _, event := range s.events {
if event.name != "BeforeScenario" { if event.name != "BeforeScenario" {
@ -234,7 +233,7 @@ func (s *suiteContext) thereWasEventTriggeredBeforeScenario(args ...*Arg) error
case *gherkin.ScenarioOutline: case *gherkin.ScenarioOutline:
name = t.Name name = t.Name
} }
if name == args[0].String() { if name == expected {
return nil return nil
} }
@ -245,22 +244,20 @@ func (s *suiteContext) thereWasEventTriggeredBeforeScenario(args ...*Arg) error
return fmt.Errorf("before scenario event was never triggered or listened") return fmt.Errorf("before scenario event was never triggered or listened")
} }
return fmt.Errorf(`expected "%s" scenario, but got these fired %s`, args[0].String(), `"`+strings.Join(found, `", "`)+`"`) return fmt.Errorf(`expected "%s" scenario, but got these fired %s`, expected, `"`+strings.Join(found, `", "`)+`"`)
} }
func (s *suiteContext) theseEventsHadToBeFiredForNumberOfTimes(args ...*Arg) error { func (s *suiteContext) theseEventsHadToBeFiredForNumberOfTimes(tbl *gherkin.DataTable) error {
tbl := args[0].DataTable()
if len(tbl.Rows[0].Cells) != 2 { if len(tbl.Rows[0].Cells) != 2 {
return fmt.Errorf("expected two columns for event table row, got: %d", len(tbl.Rows[0].Cells)) return fmt.Errorf("expected two columns for event table row, got: %d", len(tbl.Rows[0].Cells))
} }
for _, row := range tbl.Rows { for _, row := range tbl.Rows {
args := []*Arg{ num, err := strconv.ParseInt(row.Cells[1].Value, 10, 0)
StepArgument(""), // ignored if err != nil {
StepArgument(row.Cells[1].Value), return err
StepArgument(row.Cells[0].Value),
} }
if err := s.thereWereNumEventsFired(args...); err != nil { if err := s.thereWereNumEventsFired("", int(num), row.Cells[0].Value); err != nil {
return err return err
} }
} }