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 | ||||
| // the regexp submatch to handle the step | ||||
| type Arg string | ||||
| type Arg struct { | ||||
| 	value interface{} | ||||
| } | ||||
| 
 | ||||
| // Float64 converts an argument to float64 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Float64() float64 { | ||||
| 	v, err := strconv.ParseFloat(string(a), 64) | ||||
| func (a *Arg) Float64() float64 { | ||||
| 	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 { | ||||
| 		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 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Float32() float32 { | ||||
| 	v, err := strconv.ParseFloat(string(a), 32) | ||||
| func (a *Arg) Float32() float32 { | ||||
| 	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 { | ||||
| 		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 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Int() int { | ||||
| 	v, err := strconv.ParseInt(string(a), 10, 0) | ||||
| func (a *Arg) Int() int { | ||||
| 	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 { | ||||
| 		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 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Int64() int64 { | ||||
| 	v, err := strconv.ParseInt(string(a), 10, 64) | ||||
| func (a *Arg) Int64() int64 { | ||||
| 	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 { | ||||
| 		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 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Int32() int32 { | ||||
| 	v, err := strconv.ParseInt(string(a), 10, 32) | ||||
| func (a *Arg) Int32() int32 { | ||||
| 	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 { | ||||
| 		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 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Int16() int16 { | ||||
| 	v, err := strconv.ParseInt(string(a), 10, 16) | ||||
| func (a *Arg) Int16() int16 { | ||||
| 	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 { | ||||
| 		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 | ||||
| // or panics if unable to convert it | ||||
| func (a Arg) Int8() int8 { | ||||
| 	v, err := strconv.ParseInt(string(a), 10, 8) | ||||
| func (a *Arg) Int8() int8 { | ||||
| 	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 { | ||||
| 		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 | ||||
| func (a Arg) String() string { | ||||
| 	return string(a) | ||||
| func (a *Arg) String() string { | ||||
| 	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 | ||||
| func (a Arg) Bytes() []byte { | ||||
| 	return []byte(a) | ||||
| func (a *Arg) Bytes() []byte { | ||||
| 	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) { | ||||
| 	for _, pat := range c.paths { | ||||
| 		// check if line number is specified | ||||
| 		parts := strings.Split(pat, ":") | ||||
| 		path := parts[0] | ||||
| 		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") | ||||
| 			} | ||||
| 		} | ||||
| 		// parse features | ||||
| 		err = filepath.Walk(path, func(p string, f os.FileInfo, err error) error { | ||||
| 			if err == nil && !f.IsDir() && strings.HasSuffix(p, ".feature") { | ||||
| 				ft, err := gherkin.Parse(p) | ||||
|  | @ -142,8 +144,14 @@ func (c *config) features() (lst []*gherkin.Feature, err error) { | |||
| 			} | ||||
| 			return err | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return lst, fmt.Errorf(`feature path "%s" is not available or accessible`, path) | ||||
| 		// check error | ||||
| 		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 | ||||
|  |  | |||
|  | @ -1 +1,9 @@ | |||
| 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{}) { | ||||
| 	switch t := node.(type) { | ||||
| 	case *gherkin.Feature: | ||||
| 		if f.feature != nil { | ||||
| 			// not a first feature, add a newline | ||||
| 			fmt.Println("") | ||||
| 		} | ||||
| 		f.feature = t | ||||
| 		f.doneBackground = false | ||||
| 		f.background = nil | ||||
|  |  | |||
|  | @ -281,6 +281,9 @@ func (p *parser) parseFeature() (ft *Feature, err error) { | |||
| 
 | ||||
| 		// there must be a scenario or scenario outline otherwise | ||||
| 		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) | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,8 +51,8 @@ func Test_feature_read(t *testing.T) { | |||
| 	if tok.Value != val { | ||||
| 		t.Fatalf("Expected a token value to be '%s', but got: '%s'", val, tok.Value) | ||||
| 	} | ||||
| 	if tok.Line != 0 { | ||||
| 		t.Fatalf("Expected a token line to be '0', but got: '%d'", tok.Line) | ||||
| 	if tok.Line != 1 { | ||||
| 		t.Fatalf("Expected a token line to be '1', but got: '%d'", tok.Line) | ||||
| 	} | ||||
| 	if tok.Indent != 0 { | ||||
| 		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 { | ||||
| 		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 { | ||||
| 		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 { | ||||
| 		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 { | ||||
| 		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) | ||||
| 	} | ||||
| 
 | ||||
| 	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() | ||||
| 	if tok.Type != EOF { | ||||
| 		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 | ||||
| // step. | ||||
| type StepHandler interface { | ||||
| 	HandleStep(args ...Arg) error | ||||
| 	HandleStep(args ...*Arg) error | ||||
| } | ||||
| 
 | ||||
| // StepHandlerFunc type is an adapter to allow the use of | ||||
| // ordinary functions as Step handlers.  If f is a function | ||||
| // with the appropriate signature, StepHandlerFunc(f) is a | ||||
| // StepHandler object that calls f. | ||||
| type StepHandlerFunc func(...Arg) error | ||||
| type StepHandlerFunc func(...*Arg) error | ||||
| 
 | ||||
| // HandleStep calls f(step_arguments...). | ||||
| func (f StepHandlerFunc) HandleStep(args ...Arg) error { | ||||
| func (f StepHandlerFunc) HandleStep(args ...*Arg) error { | ||||
| 	return f(args...) | ||||
| } | ||||
| 
 | ||||
|  | @ -113,12 +113,18 @@ func (s *suite) Run() { | |||
| 
 | ||||
| func (s *suite) runStep(step *gherkin.Step) (err error) { | ||||
| 	var match *stepMatchHandler | ||||
| 	var args []Arg | ||||
| 	var args []*Arg | ||||
| 	for _, h := range s.stepHandlers { | ||||
| 		if m := h.expr.FindStringSubmatch(step.Text); len(m) > 0 { | ||||
| 			match = h | ||||
| 			for _, a := range m[1:] { | ||||
| 				args = append(args, Arg(a)) | ||||
| 				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 | ||||
| 		} | ||||
|  |  | |||
|  | @ -16,24 +16,24 @@ func (s *suiteFeature) BeforeScenario(scenario *gherkin.Scenario) { | |||
| 	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()) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *suiteFeature) parseFeatures(args ...Arg) (err error) { | ||||
| func (s *suiteFeature) parseFeatures(args ...*Arg) (err error) { | ||||
| 	s.features, err = cfg.features() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suiteFeature) numParsed(args ...Arg) (err error) { | ||||
| func (s *suiteFeature) numParsed(args ...*Arg) (err error) { | ||||
| 	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)) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suiteFeature) numScenariosRegistered(args ...Arg) (err error) { | ||||
| func (s *suiteFeature) numScenariosRegistered(args ...*Arg) (err error) { | ||||
| 	var num int | ||||
| 	for _, ft := range s.features { | ||||
| 		num += len(ft.Scenarios) | ||||
|  |  | |||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 gedi
						gedi