use reflection to set step arguments #9
* 9226bc5 more expressive conversion errors
Этот коммит содержится в:
родитель
d7334fd66e
коммит
2046da1611
5 изменённых файлов: 226 добавлений и 228 удалений
14
README.md
14
README.md
|
@ -79,19 +79,19 @@ func (c *GodogCart) resetReserve(interface{}) {
|
|||
c.reserve = 0
|
||||
}
|
||||
|
||||
func (c *GodogCart) thereAreNumGodogsInReserve(args ...*godog.Arg) error {
|
||||
c.reserve = args[0].Int()
|
||||
func (c *GodogCart) thereAreNumGodogsInReserve(avail int) error {
|
||||
c.reserve = avail
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GodogCart) iEatNum(args ...*godog.Arg) error {
|
||||
c.Eat(args[0].Int())
|
||||
func (c *GodogCart) iEatNum(num int) error {
|
||||
c.Eat(num)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GodogCart) thereShouldBeNumRemaining(args ...*godog.Arg) error {
|
||||
if c.Available() != args[0].Int() {
|
||||
return fmt.Errorf("expected %d godogs to be remaining, but there is %d", args[0].Int(), c.Available())
|
||||
func (c *GodogCart) thereShouldBeNumRemaining(left int) error {
|
||||
if c.Available() != left {
|
||||
return fmt.Errorf("expected %d godogs to be remaining, but there is %d", left, c.Available())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
143
arguments.go
143
arguments.go
|
@ -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"
|
||||
|
||||
"github.com/DATA-DOG/godog"
|
||||
"github.com/cucumber/gherkin-go"
|
||||
)
|
||||
|
||||
type lsFeature struct {
|
||||
|
@ -24,29 +25,29 @@ func lsFeatureContext(s godog.Suite) {
|
|||
s.Step(`^I should get output:$`, c.iShouldGetOutput)
|
||||
}
|
||||
|
||||
func (f *lsFeature) iAmInDirectory(args ...*godog.Arg) error {
|
||||
f.dir = os.TempDir() + "/" + args[0].String()
|
||||
func (f *lsFeature) iAmInDirectory(name string) error {
|
||||
f.dir = os.TempDir() + "/" + name
|
||||
if err := os.RemoveAll(f.dir); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
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 {
|
||||
return fmt.Errorf("the directory was not chosen yet")
|
||||
}
|
||||
switch args[0].String() {
|
||||
switch typ {
|
||||
case "file":
|
||||
err = ioutil.WriteFile(f.dir+"/"+args[1].String(), []byte{}, 0664)
|
||||
err = ioutil.WriteFile(f.dir+"/"+name, []byte{}, 0664)
|
||||
case "directory":
|
||||
err = os.Mkdir(f.dir+"/"+args[1].String(), 0775)
|
||||
err = os.Mkdir(f.dir+"/"+name, 0775)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *lsFeature) iShouldGetOutput(args ...*godog.Arg) error {
|
||||
expected := strings.Split(args[0].DocString().Content, "\n")
|
||||
func (f *lsFeature) iShouldGetOutput(names *gherkin.DocString) error {
|
||||
expected := strings.Split(names.Content, "\n")
|
||||
actual := strings.Split(strings.TrimSpace(f.buf.String()), "\n")
|
||||
if 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
|
||||
}
|
||||
|
||||
func (f *lsFeature) iRunLs(args ...*godog.Arg) error {
|
||||
func (f *lsFeature) iRunLs() error {
|
||||
f.buf.Reset()
|
||||
return ls(f.dir, f.buf)
|
||||
}
|
||||
|
|
201
suite.go
201
suite.go
|
@ -13,28 +13,13 @@ import (
|
|||
"github.com/cucumber/gherkin-go"
|
||||
)
|
||||
|
||||
var errorInterface = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
type feature struct {
|
||||
*gherkin.Feature
|
||||
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
|
||||
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
|
||||
// or successful
|
||||
type StepDef struct {
|
||||
Args []*Arg
|
||||
Handler StepHandler
|
||||
args []interface{}
|
||||
hv reflect.Value
|
||||
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
|
||||
|
@ -64,14 +173,36 @@ type StepDef struct {
|
|||
// executions are catching panic error since it may
|
||||
// be a context specific error.
|
||||
type Suite interface {
|
||||
// Run the test suite
|
||||
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())
|
||||
|
||||
// BeforeScenario registers a func to run before
|
||||
// every *gherkin.Scenario or *gherkin.ScenarioOutline
|
||||
BeforeScenario(f func(interface{}))
|
||||
|
||||
// BeforeStep register a handler before every step
|
||||
BeforeStep(f func(*gherkin.Step))
|
||||
|
||||
// AfterStep register a handler after every step
|
||||
AfterStep(f func(*gherkin.Step, error))
|
||||
|
||||
// AfterScenario registers a func to run after
|
||||
// every *gherkin.Scenario or *gherkin.ScenarioOutline
|
||||
AfterScenario(f func(interface{}, error))
|
||||
|
||||
// AfterSuite runs func int the end of tests
|
||||
AfterSuite(f func())
|
||||
}
|
||||
|
||||
|
@ -117,7 +248,7 @@ func New() Suite {
|
|||
//
|
||||
// If none of the StepHandlers are matched, then
|
||||
// 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
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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{
|
||||
Handler: h,
|
||||
Handler: stepFunc,
|
||||
Expr: regex,
|
||||
hv: v,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -262,14 +405,14 @@ func (s *suite) run() {
|
|||
func (s *suite) matchStep(step *gherkin.Step) *StepDef {
|
||||
for _, h := range s.stepHandlers {
|
||||
if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 {
|
||||
var args []*Arg
|
||||
for _, a := range m[1:] {
|
||||
args = append(args, &Arg{value: a})
|
||||
var args []interface{}
|
||||
for _, m := range m[1:] {
|
||||
args = append(args, m)
|
||||
}
|
||||
if step.Argument != nil {
|
||||
args = append(args, &Arg{value: step.Argument})
|
||||
args = append(args, step.Argument)
|
||||
}
|
||||
h.Args = args
|
||||
h.args = args
|
||||
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)
|
||||
} else {
|
||||
s.fmt.Passed(step, match)
|
||||
|
|
|
@ -2,6 +2,7 @@ package godog
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cucumber/gherkin-go"
|
||||
|
@ -56,12 +57,12 @@ func (s *suiteContext) ResetBeforeEachScenario(interface{}) {
|
|||
s.events = []*firedEvent{}
|
||||
}
|
||||
|
||||
func (s *suiteContext) followingStepsShouldHave(args ...*Arg) error {
|
||||
var expected = strings.Split(args[1].DocString().Content, "\n")
|
||||
func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.DocString) error {
|
||||
var expected = strings.Split(steps.Content, "\n")
|
||||
var actual, unmatched []string
|
||||
var matched []int
|
||||
|
||||
switch args[0].String() {
|
||||
switch status {
|
||||
case "passed":
|
||||
for _, st := range s.fmt.passed {
|
||||
actual = append(actual, st.step.Text)
|
||||
|
@ -79,11 +80,11 @@ func (s *suiteContext) followingStepsShouldHave(args ...*Arg) error {
|
|||
actual = append(actual, st.step.Text)
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
|
@ -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.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
||||
})
|
||||
|
@ -136,43 +137,41 @@ func (s *suiteContext) iAmListeningToSuiteEvents(args ...*Arg) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) aFailingStep(...*Arg) error {
|
||||
func (s *suiteContext) aFailingStep() error {
|
||||
return fmt.Errorf("intentional failure")
|
||||
}
|
||||
|
||||
// parse a given feature file body as a feature
|
||||
func (s *suiteContext) aFeatureFile(args ...*Arg) error {
|
||||
name := args[0].String()
|
||||
body := args[1].DocString().Content
|
||||
ft, err := gherkin.ParseFeature(strings.NewReader(body))
|
||||
func (s *suiteContext) aFeatureFile(name string, body *gherkin.DocString) error {
|
||||
ft, err := gherkin.ParseFeature(strings.NewReader(body.Content))
|
||||
s.testedSuite.features = append(s.testedSuite.features, &feature{Feature: ft, Path: name})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *suiteContext) featurePath(args ...*Arg) error {
|
||||
s.testedSuite.paths = append(s.testedSuite.paths, args[0].String())
|
||||
func (s *suiteContext) featurePath(path string) error {
|
||||
s.testedSuite.paths = append(s.testedSuite.paths, path)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) parseFeatures(args ...*Arg) error {
|
||||
func (s *suiteContext) parseFeatures() error {
|
||||
return s.testedSuite.parseFeatures()
|
||||
}
|
||||
|
||||
func (s *suiteContext) theSuiteShouldHave(args ...*Arg) error {
|
||||
if s.testedSuite.failed && args[0].String() == "passed" {
|
||||
func (s *suiteContext) theSuiteShouldHave(state string) error {
|
||||
if s.testedSuite.failed && state == "passed" {
|
||||
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 nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) iShouldHaveNumFeatureFiles(args ...*Arg) error {
|
||||
if len(s.testedSuite.features) != args[0].Int() {
|
||||
return fmt.Errorf("expected %d features to be parsed, but have %d", args[0].Int(), len(s.testedSuite.features))
|
||||
func (s *suiteContext) iShouldHaveNumFeatureFiles(num int, files *gherkin.DocString) error {
|
||||
if len(s.testedSuite.features) != num {
|
||||
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
|
||||
for _, ft := range s.testedSuite.features {
|
||||
actual = append(actual, ft.Path)
|
||||
|
@ -188,7 +187,7 @@ func (s *suiteContext) iShouldHaveNumFeatureFiles(args ...*Arg) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) iRunFeatureSuite(args ...*Arg) error {
|
||||
func (s *suiteContext) iRunFeatureSuite() error {
|
||||
if err := s.parseFeatures(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -196,31 +195,31 @@ func (s *suiteContext) iRunFeatureSuite(args ...*Arg) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) numScenariosRegistered(args ...*Arg) (err error) {
|
||||
func (s *suiteContext) numScenariosRegistered(expected int) (err error) {
|
||||
var num int
|
||||
for _, ft := range s.testedSuite.features {
|
||||
num += len(ft.ScenarioDefinitions)
|
||||
}
|
||||
if num != args[0].Int() {
|
||||
err = fmt.Errorf("expected %d scenarios to be registered, but got %d", args[0].Int(), num)
|
||||
if num != expected {
|
||||
err = fmt.Errorf("expected %d scenarios to be registered, but got %d", expected, num)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *suiteContext) thereWereNumEventsFired(args ...*Arg) error {
|
||||
func (s *suiteContext) thereWereNumEventsFired(_ string, expected int, typ string) error {
|
||||
var num int
|
||||
for _, event := range s.events {
|
||||
if event.name == args[2].String() {
|
||||
if event.name == typ {
|
||||
num++
|
||||
}
|
||||
}
|
||||
if num != args[1].Int() {
|
||||
return fmt.Errorf("expected %d %s events to be fired, but got %d", args[1].Int(), args[2].String(), num)
|
||||
if num != expected {
|
||||
return fmt.Errorf("expected %d %s events to be fired, but got %d", expected, typ, num)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) thereWasEventTriggeredBeforeScenario(args ...*Arg) error {
|
||||
func (s *suiteContext) thereWasEventTriggeredBeforeScenario(expected string) error {
|
||||
var found []string
|
||||
for _, event := range s.events {
|
||||
if event.name != "BeforeScenario" {
|
||||
|
@ -234,7 +233,7 @@ func (s *suiteContext) thereWasEventTriggeredBeforeScenario(args ...*Arg) error
|
|||
case *gherkin.ScenarioOutline:
|
||||
name = t.Name
|
||||
}
|
||||
if name == args[0].String() {
|
||||
if name == expected {
|
||||
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(`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 {
|
||||
tbl := args[0].DataTable()
|
||||
func (s *suiteContext) theseEventsHadToBeFiredForNumberOfTimes(tbl *gherkin.DataTable) error {
|
||||
if len(tbl.Rows[0].Cells) != 2 {
|
||||
return fmt.Errorf("expected two columns for event table row, got: %d", len(tbl.Rows[0].Cells))
|
||||
}
|
||||
|
||||
for _, row := range tbl.Rows {
|
||||
args := []*Arg{
|
||||
StepArgument(""), // ignored
|
||||
StepArgument(row.Cells[1].Value),
|
||||
StepArgument(row.Cells[0].Value),
|
||||
num, err := strconv.ParseInt(row.Cells[1].Value, 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.thereWereNumEventsFired(args...); err != nil {
|
||||
if err := s.thereWereNumEventsFired("", int(num), row.Cells[0].Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче