more error details, refactor arguments to interface type
Этот коммит содержится в:
родитель
774d3d1837
коммит
cb47b27090
8 изменённых файлов: 122 добавлений и 55 удалений
90
arguments.go
90
arguments.go
|
@ -7,84 +7,122 @@ import (
|
||||||
|
|
||||||
// Arg is an argument for StepHandler parsed from
|
// Arg is an argument for StepHandler parsed from
|
||||||
// the regexp submatch to handle the step
|
// the regexp submatch to handle the step
|
||||||
type Arg string
|
type Arg struct {
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// Float64 converts an argument to float64
|
// Float64 converts an argument to float64
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Float64() float64 {
|
func (a *Arg) Float64() float64 {
|
||||||
v, err := strconv.ParseFloat(string(a), 64)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseFloat(s, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float32 converts an argument to float32
|
// Float32 converts an argument to float32
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Float32() float32 {
|
func (a *Arg) Float32() float32 {
|
||||||
v, err := strconv.ParseFloat(string(a), 32)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseFloat(s, 32)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return float32(v)
|
return float32(v)
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to float32: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to float32: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int converts an argument to int
|
// Int converts an argument to int
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Int() int {
|
func (a *Arg) Int() int {
|
||||||
v, err := strconv.ParseInt(string(a), 10, 0)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseInt(s, 10, 0)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return int(v)
|
return int(v)
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to int: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to int: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int64 converts an argument to int64
|
// Int64 converts an argument to int64
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Int64() int64 {
|
func (a *Arg) Int64() int64 {
|
||||||
v, err := strconv.ParseInt(string(a), 10, 64)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseInt(s, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int32 converts an argument to int32
|
// Int32 converts an argument to int32
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Int32() int32 {
|
func (a *Arg) Int32() int32 {
|
||||||
v, err := strconv.ParseInt(string(a), 10, 32)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseInt(s, 10, 32)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return int32(v)
|
return int32(v)
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to int32: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to int32: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int16 converts an argument to int16
|
// Int16 converts an argument to int16
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Int16() int16 {
|
func (a *Arg) Int16() int16 {
|
||||||
v, err := strconv.ParseInt(string(a), 10, 16)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseInt(s, 10, 16)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return int16(v)
|
return int16(v)
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to int16: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to int16: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int8 converts an argument to int8
|
// Int8 converts an argument to int8
|
||||||
// or panics if unable to convert it
|
// or panics if unable to convert it
|
||||||
func (a Arg) Int8() int8 {
|
func (a *Arg) Int8() int8 {
|
||||||
v, err := strconv.ParseInt(string(a), 10, 8)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseInt(s, 10, 8)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return int8(v)
|
return int8(v)
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf(`cannot convert "%s" to int8: %s`, a, err))
|
panic(fmt.Sprintf(`cannot convert "%s" to int8: %s`, s, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// String converts an argument to string
|
// String converts an argument to string
|
||||||
func (a Arg) String() string {
|
func (a *Arg) String() string {
|
||||||
return string(a)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes converts an argument string to bytes
|
// Bytes converts an argument string to bytes
|
||||||
func (a Arg) Bytes() []byte {
|
func (a *Arg) Bytes() []byte {
|
||||||
return []byte(a)
|
s, ok := a.value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf(`cannot convert "%v" to string`, a.value))
|
||||||
|
}
|
||||||
|
return []byte(s)
|
||||||
}
|
}
|
||||||
|
|
12
config.go
12
config.go
|
@ -108,6 +108,7 @@ func (c *config) validate() error {
|
||||||
|
|
||||||
func (c *config) features() (lst []*gherkin.Feature, err error) {
|
func (c *config) features() (lst []*gherkin.Feature, err error) {
|
||||||
for _, pat := range c.paths {
|
for _, pat := range c.paths {
|
||||||
|
// check if line number is specified
|
||||||
parts := strings.Split(pat, ":")
|
parts := strings.Split(pat, ":")
|
||||||
path := parts[0]
|
path := parts[0]
|
||||||
line := -1
|
line := -1
|
||||||
|
@ -117,6 +118,7 @@ func (c *config) features() (lst []*gherkin.Feature, err error) {
|
||||||
return lst, fmt.Errorf("line number should follow after colon path delimiter")
|
return lst, fmt.Errorf("line number should follow after colon path delimiter")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// parse features
|
||||||
err = filepath.Walk(path, func(p string, f os.FileInfo, err error) error {
|
err = filepath.Walk(path, func(p string, f os.FileInfo, err error) error {
|
||||||
if err == nil && !f.IsDir() && strings.HasSuffix(p, ".feature") {
|
if err == nil && !f.IsDir() && strings.HasSuffix(p, ".feature") {
|
||||||
ft, err := gherkin.Parse(p)
|
ft, err := gherkin.Parse(p)
|
||||||
|
@ -142,8 +144,14 @@ func (c *config) features() (lst []*gherkin.Feature, err error) {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
// check error
|
||||||
return lst, fmt.Errorf(`feature path "%s" is not available or accessible`, path)
|
switch {
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
return lst, fmt.Errorf(`feature path "%s" is not available`, path)
|
||||||
|
case os.IsPermission(err):
|
||||||
|
return lst, fmt.Errorf(`feature path "%s" is not accessible`, path)
|
||||||
|
case err != nil:
|
||||||
|
return lst, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -1 +1,9 @@
|
||||||
Feature: suite hooks
|
Feature: suite hooks
|
||||||
|
In order to run tasks before and after important events
|
||||||
|
As a test suite
|
||||||
|
I need to provide a way to hook into these events
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given I have a before scenario hook
|
||||||
|
And a feature path "features/load_features.feature:6"
|
||||||
|
# When I parse and run features
|
||||||
|
|
|
@ -99,6 +99,10 @@ func (f *pretty) canPrintStep(step *gherkin.Step) bool {
|
||||||
func (f *pretty) Node(node interface{}) {
|
func (f *pretty) Node(node interface{}) {
|
||||||
switch t := node.(type) {
|
switch t := node.(type) {
|
||||||
case *gherkin.Feature:
|
case *gherkin.Feature:
|
||||||
|
if f.feature != nil {
|
||||||
|
// not a first feature, add a newline
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
f.feature = t
|
f.feature = t
|
||||||
f.doneBackground = false
|
f.doneBackground = false
|
||||||
f.background = nil
|
f.background = nil
|
||||||
|
|
|
@ -281,6 +281,9 @@ func (p *parser) parseFeature() (ft *Feature, err error) {
|
||||||
|
|
||||||
// there must be a scenario or scenario outline otherwise
|
// there must be a scenario or scenario outline otherwise
|
||||||
if !tok.OfType(SCENARIO, SCENARIO_OUTLINE) {
|
if !tok.OfType(SCENARIO, SCENARIO_OUTLINE) {
|
||||||
|
if tok.Type == EOF {
|
||||||
|
return ft, nil // there may not be a scenario defined after background
|
||||||
|
}
|
||||||
return ft, p.err("expected a scenario or scenario outline, but got '"+tok.Type.String()+"' instead", tok.Line)
|
return ft, p.err("expected a scenario or scenario outline, but got '"+tok.Type.String()+"' instead", tok.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,8 @@ func Test_feature_read(t *testing.T) {
|
||||||
if tok.Value != val {
|
if tok.Value != val {
|
||||||
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
||||||
}
|
}
|
||||||
if tok.Line != 0 {
|
if tok.Line != 1 {
|
||||||
t.Fatalf("Expected a token line to be '0', but got: '%d'", tok.Line)
|
t.Fatalf("Expected a token line to be '1', but got: '%d'", tok.Line)
|
||||||
}
|
}
|
||||||
if tok.Indent != 0 {
|
if tok.Indent != 0 {
|
||||||
t.Fatalf("Expected a token identation to be '0', but got: '%d'", tok.Indent)
|
t.Fatalf("Expected a token identation to be '0', but got: '%d'", tok.Indent)
|
||||||
|
@ -66,21 +66,6 @@ func Test_feature_read(t *testing.T) {
|
||||||
if tok.Value != val {
|
if tok.Value != val {
|
||||||
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
||||||
}
|
}
|
||||||
if tok.Line != 1 {
|
|
||||||
t.Fatalf("Expected a token line to be '1', but got: '%d'", tok.Line)
|
|
||||||
}
|
|
||||||
if tok.Indent != 2 {
|
|
||||||
t.Fatalf("Expected a token identation to be '2', but got: '%d'", tok.Indent)
|
|
||||||
}
|
|
||||||
|
|
||||||
tok = l.read()
|
|
||||||
if tok.Type != TEXT {
|
|
||||||
t.Fatalf("Expected a 'text' type, but got: '%s'", tok.Type)
|
|
||||||
}
|
|
||||||
val = "as gherkin lexer"
|
|
||||||
if tok.Value != val {
|
|
||||||
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
|
||||||
}
|
|
||||||
if tok.Line != 2 {
|
if tok.Line != 2 {
|
||||||
t.Fatalf("Expected a token line to be '2', but got: '%d'", tok.Line)
|
t.Fatalf("Expected a token line to be '2', but got: '%d'", tok.Line)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +77,7 @@ func Test_feature_read(t *testing.T) {
|
||||||
if tok.Type != TEXT {
|
if tok.Type != TEXT {
|
||||||
t.Fatalf("Expected a 'text' type, but got: '%s'", tok.Type)
|
t.Fatalf("Expected a 'text' type, but got: '%s'", tok.Type)
|
||||||
}
|
}
|
||||||
val = "I need to be able to parse a feature"
|
val = "as gherkin lexer"
|
||||||
if tok.Value != val {
|
if tok.Value != val {
|
||||||
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
||||||
}
|
}
|
||||||
|
@ -103,6 +88,21 @@ func Test_feature_read(t *testing.T) {
|
||||||
t.Fatalf("Expected a token identation to be '2', but got: '%d'", tok.Indent)
|
t.Fatalf("Expected a token identation to be '2', but got: '%d'", tok.Indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tok = l.read()
|
||||||
|
if tok.Type != TEXT {
|
||||||
|
t.Fatalf("Expected a 'text' type, but got: '%s'", tok.Type)
|
||||||
|
}
|
||||||
|
val = "I need to be able to parse a feature"
|
||||||
|
if tok.Value != val {
|
||||||
|
t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value)
|
||||||
|
}
|
||||||
|
if tok.Line != 4 {
|
||||||
|
t.Fatalf("Expected a token line to be '4', but got: '%d'", tok.Line)
|
||||||
|
}
|
||||||
|
if tok.Indent != 2 {
|
||||||
|
t.Fatalf("Expected a token identation to be '2', but got: '%d'", tok.Indent)
|
||||||
|
}
|
||||||
|
|
||||||
tok = l.read()
|
tok = l.read()
|
||||||
if tok.Type != EOF {
|
if tok.Type != EOF {
|
||||||
t.Fatalf("Expected an 'eof' type, but got: '%s'", tok.Type)
|
t.Fatalf("Expected an 'eof' type, but got: '%s'", tok.Type)
|
||||||
|
|
16
suite.go
16
suite.go
|
@ -30,17 +30,17 @@ func (f BeforeScenarioHandlerFunc) BeforeScenario(scenario *gherkin.Scenario) {
|
||||||
// and that the feature runner can move on to the next
|
// and that the feature runner can move on to the next
|
||||||
// step.
|
// step.
|
||||||
type StepHandler interface {
|
type StepHandler interface {
|
||||||
HandleStep(args ...Arg) error
|
HandleStep(args ...*Arg) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// StepHandlerFunc type is an adapter to allow the use of
|
// StepHandlerFunc type is an adapter to allow the use of
|
||||||
// ordinary functions as Step handlers. If f is a function
|
// ordinary functions as Step handlers. If f is a function
|
||||||
// with the appropriate signature, StepHandlerFunc(f) is a
|
// with the appropriate signature, StepHandlerFunc(f) is a
|
||||||
// StepHandler object that calls f.
|
// StepHandler object that calls f.
|
||||||
type StepHandlerFunc func(...Arg) error
|
type StepHandlerFunc func(...*Arg) error
|
||||||
|
|
||||||
// HandleStep calls f(step_arguments...).
|
// HandleStep calls f(step_arguments...).
|
||||||
func (f StepHandlerFunc) HandleStep(args ...Arg) error {
|
func (f StepHandlerFunc) HandleStep(args ...*Arg) error {
|
||||||
return f(args...)
|
return f(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,12 +113,18 @@ func (s *suite) Run() {
|
||||||
|
|
||||||
func (s *suite) runStep(step *gherkin.Step) (err error) {
|
func (s *suite) runStep(step *gherkin.Step) (err error) {
|
||||||
var match *stepMatchHandler
|
var match *stepMatchHandler
|
||||||
var args []Arg
|
var args []*Arg
|
||||||
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 {
|
||||||
match = h
|
match = h
|
||||||
for _, a := range m[1:] {
|
for _, a := range m[1:] {
|
||||||
args = append(args, Arg(a))
|
args = append(args, &Arg{value: a})
|
||||||
|
}
|
||||||
|
if step.Table != nil {
|
||||||
|
args = append(args, &Arg{value: step.Table})
|
||||||
|
}
|
||||||
|
if step.PyString != nil {
|
||||||
|
args = append(args, &Arg{value: step.PyString})
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,24 +16,24 @@ func (s *suiteFeature) BeforeScenario(scenario *gherkin.Scenario) {
|
||||||
cfg.paths = []string{}
|
cfg.paths = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) featurePath(args ...Arg) error {
|
func (s *suiteFeature) featurePath(args ...*Arg) error {
|
||||||
cfg.paths = append(cfg.paths, args[0].String())
|
cfg.paths = append(cfg.paths, args[0].String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) parseFeatures(args ...Arg) (err error) {
|
func (s *suiteFeature) parseFeatures(args ...*Arg) (err error) {
|
||||||
s.features, err = cfg.features()
|
s.features, err = cfg.features()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) numParsed(args ...Arg) (err error) {
|
func (s *suiteFeature) numParsed(args ...*Arg) (err error) {
|
||||||
if len(s.features) != args[0].Int() {
|
if len(s.features) != args[0].Int() {
|
||||||
err = fmt.Errorf("expected %d features to be parsed, but have %d", args[0].Int(), len(s.features))
|
err = fmt.Errorf("expected %d features to be parsed, but have %d", args[0].Int(), len(s.features))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) numScenariosRegistered(args ...Arg) (err error) {
|
func (s *suiteFeature) numScenariosRegistered(args ...*Arg) (err error) {
|
||||||
var num int
|
var num int
|
||||||
for _, ft := range s.features {
|
for _, ft := range s.features {
|
||||||
num += len(ft.Scenarios)
|
num += len(ft.Scenarios)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче