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 | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 gedi
						gedi