more specific types and references for gherkin nodes
Этот коммит содержится в:
		
							родитель
							
								
									7f214c702b
								
							
						
					
					
						коммит
						2d3d04e0e6
					
				
					 5 изменённых файлов: 114 добавлений и 99 удалений
				
			
		
							
								
								
									
										35
									
								
								arguments.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										35
									
								
								arguments.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | package godog | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Arg is an argument for StepHandler parsed from | ||||||
|  | // the regexp submatch to handle the step | ||||||
|  | type Arg string | ||||||
|  | 
 | ||||||
|  | // Float converts an argument to float64 | ||||||
|  | // or panics if unable to convert it | ||||||
|  | func (a Arg) Float() float64 { | ||||||
|  | 	v, err := strconv.ParseFloat(string(a), 64) | ||||||
|  | 	if err == nil { | ||||||
|  | 		return v | ||||||
|  | 	} | ||||||
|  | 	panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, a, err)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Int converts an argument to int64 | ||||||
|  | // or panics if unable to convert it | ||||||
|  | func (a Arg) Int() int64 { | ||||||
|  | 	v, err := strconv.ParseInt(string(a), 10, 0) | ||||||
|  | 	if err == nil { | ||||||
|  | 		return v | ||||||
|  | 	} | ||||||
|  | 	panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, a, err)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // String converts an argument to string | ||||||
|  | func (a Arg) String() string { | ||||||
|  | 	return string(a) | ||||||
|  | } | ||||||
|  | @ -37,6 +37,8 @@ func main() { | ||||||
| 	// @TODO: support for windows | 	// @TODO: support for windows | ||||||
| 	cmd := exec.Command("sh", "-c", c) | 	cmd := exec.Command("sh", "-c", c) | ||||||
| 	cmd.Stdout = stdout | 	cmd.Stdout = stdout | ||||||
|  | 	// @TODO: do not read stderr on production version | ||||||
|  | 	cmd.Stderr = stdout | ||||||
| 
 | 
 | ||||||
| 	err = cmd.Run() | 	err = cmd.Run() | ||||||
| 	switch err.(type) { | 	switch err.(type) { | ||||||
|  |  | ||||||
							
								
								
									
										92
									
								
								formatter.go
									
										
									
									
									
								
							
							
						
						
									
										92
									
								
								formatter.go
									
										
									
									
									
								
							|  | @ -31,7 +31,6 @@ type Formatter interface { | ||||||
| // general pretty formatter structure | // general pretty formatter structure | ||||||
| type pretty struct { | type pretty struct { | ||||||
| 	feature        *gherkin.Feature | 	feature        *gherkin.Feature | ||||||
| 	scenario       *gherkin.Scenario |  | ||||||
| 	commentPos     int | 	commentPos     int | ||||||
| 	doneBackground bool | 	doneBackground bool | ||||||
| 	background     *gherkin.Background | 	background     *gherkin.Background | ||||||
|  | @ -48,34 +47,39 @@ type pretty struct { | ||||||
| // failed represents a failed step data structure | // failed represents a failed step data structure | ||||||
| // with all necessary references | // with all necessary references | ||||||
| type failed struct { | type failed struct { | ||||||
| 	feature  *gherkin.Feature | 	step *gherkin.Step | ||||||
| 	scenario *gherkin.Scenario | 	err  error | ||||||
| 	step     *gherkin.Step | } | ||||||
| 	err      error | 
 | ||||||
|  | func (f failed) line() string { | ||||||
|  | 	var tok *gherkin.Token | ||||||
|  | 	var ft *gherkin.Feature | ||||||
|  | 	if f.step.Scenario != nil { | ||||||
|  | 		tok = f.step.Scenario.Token | ||||||
|  | 		ft = f.step.Scenario.Feature | ||||||
|  | 	} else { | ||||||
|  | 		tok = f.step.Background.Token | ||||||
|  | 		ft = f.step.Background.Feature | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("%s:%d", ft.Path, tok.Line) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // passed represents a successful step data structure | // passed represents a successful step data structure | ||||||
| // with all necessary references | // with all necessary references | ||||||
| type passed struct { | type passed struct { | ||||||
| 	feature  *gherkin.Feature | 	step *gherkin.Step | ||||||
| 	scenario *gherkin.Scenario |  | ||||||
| 	step     *gherkin.Step |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // skipped represents a skipped step data structure | // skipped represents a skipped step data structure | ||||||
| // with all necessary references | // with all necessary references | ||||||
| type skipped struct { | type skipped struct { | ||||||
| 	feature  *gherkin.Feature | 	step *gherkin.Step | ||||||
| 	scenario *gherkin.Scenario |  | ||||||
| 	step     *gherkin.Step |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // undefined represents a pending step data structure | // undefined represents a pending step data structure | ||||||
| // with all necessary references | // with all necessary references | ||||||
| type undefined struct { | type undefined struct { | ||||||
| 	feature  *gherkin.Feature | 	step *gherkin.Step | ||||||
| 	scenario *gherkin.Scenario |  | ||||||
| 	step     *gherkin.Step |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // a line number representation in feature file | // a line number representation in feature file | ||||||
|  | @ -85,24 +89,10 @@ func (f *pretty) line(tok *gherkin.Token) string { | ||||||
| 
 | 
 | ||||||
| // checks whether it should not print a background step once again | // checks whether it should not print a background step once again | ||||||
| func (f *pretty) canPrintStep(step *gherkin.Step) bool { | func (f *pretty) canPrintStep(step *gherkin.Step) bool { | ||||||
| 	if f.background == nil { | 	if f.background != nil { | ||||||
| 		return true | 		return step.Background != nil | ||||||
| 	} | 	} | ||||||
| 
 | 	return true | ||||||
| 	var backgroundStep bool |  | ||||||
| 	for _, s := range f.background.Steps { |  | ||||||
| 		if s == step { |  | ||||||
| 			backgroundStep = true |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if !backgroundStep { |  | ||||||
| 		f.doneBackground = true |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return !f.doneBackground |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Node takes a gherkin node for formatting | // Node takes a gherkin node for formatting | ||||||
|  | @ -111,7 +101,6 @@ func (f *pretty) Node(node interface{}) { | ||||||
| 	case *gherkin.Feature: | 	case *gherkin.Feature: | ||||||
| 		f.feature = t | 		f.feature = t | ||||||
| 		f.doneBackground = false | 		f.doneBackground = false | ||||||
| 		f.scenario = nil |  | ||||||
| 		f.background = nil | 		f.background = nil | ||||||
| 		f.features = append(f.features, t) | 		f.features = append(f.features, t) | ||||||
| 		fmt.Println(bcl("Feature: ", white) + t.Title + "\n") | 		fmt.Println(bcl("Feature: ", white) + t.Title + "\n") | ||||||
|  | @ -120,7 +109,6 @@ func (f *pretty) Node(node interface{}) { | ||||||
| 		f.background = t | 		f.background = t | ||||||
| 		fmt.Println(bcl("Background:", white) + "\n") | 		fmt.Println(bcl("Background:", white) + "\n") | ||||||
| 	case *gherkin.Scenario: | 	case *gherkin.Scenario: | ||||||
| 		f.scenario = t |  | ||||||
| 		f.commentPos = len(t.Token.Text) | 		f.commentPos = len(t.Token.Text) | ||||||
| 		for _, step := range t.Steps { | 		for _, step := range t.Steps { | ||||||
| 			if len(step.Token.Text) > f.commentPos { | 			if len(step.Token.Text) > f.commentPos { | ||||||
|  | @ -135,10 +123,17 @@ func (f *pretty) Node(node interface{}) { | ||||||
| 
 | 
 | ||||||
| // Summary sumarize the feature formatter output | // Summary sumarize the feature formatter output | ||||||
| func (f *pretty) Summary() { | func (f *pretty) Summary() { | ||||||
| 	if len(f.failed) > 0 { | 	// failed steps on background are not scenarios | ||||||
|  | 	var failedScenarios []*failed | ||||||
|  | 	for _, fail := range f.failed { | ||||||
|  | 		if fail.step.Scenario != nil { | ||||||
|  | 			failedScenarios = append(failedScenarios, fail) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(failedScenarios) > 0 { | ||||||
| 		fmt.Println("\n--- " + cl("Failed scenarios:", red) + "\n") | 		fmt.Println("\n--- " + cl("Failed scenarios:", red) + "\n") | ||||||
| 		for _, fail := range f.failed { | 		for _, fail := range failedScenarios { | ||||||
| 			fmt.Println("    " + cl(fmt.Sprintf("%s:%d", fail.feature.Path, fail.scenario.Token.Line), red)) | 			fmt.Println("    " + cl(fail.line(), red)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	var total, passed int | 	var total, passed int | ||||||
|  | @ -230,11 +225,7 @@ func (f *pretty) printMatchedStep(step *gherkin.Step, match *stepMatchHandler, c | ||||||
| // Passed is called to represent a passed step | // Passed is called to represent a passed step | ||||||
| func (f *pretty) Passed(step *gherkin.Step, match *stepMatchHandler) { | func (f *pretty) Passed(step *gherkin.Step, match *stepMatchHandler) { | ||||||
| 	f.printMatchedStep(step, match, green) | 	f.printMatchedStep(step, match, green) | ||||||
| 	f.passed = append(f.passed, &passed{ | 	f.passed = append(f.passed, &passed{step}) | ||||||
| 		feature:  f.feature, |  | ||||||
| 		scenario: f.scenario, |  | ||||||
| 		step:     step, |  | ||||||
| 	}) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Skipped is called to represent a passed step | // Skipped is called to represent a passed step | ||||||
|  | @ -242,11 +233,7 @@ func (f *pretty) Skipped(step *gherkin.Step) { | ||||||
| 	if f.canPrintStep(step) { | 	if f.canPrintStep(step) { | ||||||
| 		fmt.Println(cl(step.Token.Text, cyan)) | 		fmt.Println(cl(step.Token.Text, cyan)) | ||||||
| 	} | 	} | ||||||
| 	f.skipped = append(f.skipped, &skipped{ | 	f.skipped = append(f.skipped, &skipped{step}) | ||||||
| 		feature:  f.feature, |  | ||||||
| 		scenario: f.scenario, |  | ||||||
| 		step:     step, |  | ||||||
| 	}) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Undefined is called to represent a pending step | // Undefined is called to represent a pending step | ||||||
|  | @ -254,21 +241,12 @@ func (f *pretty) Undefined(step *gherkin.Step) { | ||||||
| 	if f.canPrintStep(step) { | 	if f.canPrintStep(step) { | ||||||
| 		fmt.Println(cl(step.Token.Text, yellow)) | 		fmt.Println(cl(step.Token.Text, yellow)) | ||||||
| 	} | 	} | ||||||
| 	f.undefined = append(f.undefined, &undefined{ | 	f.undefined = append(f.undefined, &undefined{step}) | ||||||
| 		feature:  f.feature, |  | ||||||
| 		scenario: f.scenario, |  | ||||||
| 		step:     step, |  | ||||||
| 	}) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Failed is called to represent a failed step | // Failed is called to represent a failed step | ||||||
| func (f *pretty) Failed(step *gherkin.Step, match *stepMatchHandler, err error) { | func (f *pretty) Failed(step *gherkin.Step, match *stepMatchHandler, err error) { | ||||||
| 	f.printMatchedStep(step, match, red) | 	f.printMatchedStep(step, match, red) | ||||||
| 	fmt.Println(strings.Repeat(" ", step.Token.Indent) + bcl(err, red)) | 	fmt.Println(strings.Repeat(" ", step.Token.Indent) + bcl(err, red)) | ||||||
| 	f.failed = append(f.failed, &failed{ | 	f.failed = append(f.failed, &failed{step, err}) | ||||||
| 		feature:  f.feature, |  | ||||||
| 		scenario: f.scenario, |  | ||||||
| 		step:     step, |  | ||||||
| 		err:      err, |  | ||||||
| 	}) |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -102,22 +102,26 @@ type Scenario struct { | ||||||
| 	Title    string | 	Title    string | ||||||
| 	Steps    []*Step | 	Steps    []*Step | ||||||
| 	Tags     Tags | 	Tags     Tags | ||||||
| 	Examples *Table | 	Examples *ExampleTable | ||||||
|  | 	Feature  *Feature | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Background steps are run before every scenario | // Background steps are run before every scenario | ||||||
| type Background struct { | type Background struct { | ||||||
| 	*Token | 	*Token | ||||||
| 	Steps []*Step | 	Steps   []*Step | ||||||
|  | 	Feature *Feature | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Step describes a Scenario or Background step | // Step describes a Scenario or Background step | ||||||
| type Step struct { | type Step struct { | ||||||
| 	*Token | 	*Token | ||||||
| 	Text     string | 	Text       string | ||||||
| 	Type     string | 	Type       string | ||||||
| 	PyString *PyString | 	PyString   *PyString | ||||||
| 	Table    *Table | 	Table      *StepTable | ||||||
|  | 	Scenario   *Scenario | ||||||
|  | 	Background *Background | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Feature describes the whole feature | // Feature describes the whole feature | ||||||
|  | @ -136,14 +140,28 @@ type Feature struct { | ||||||
| type PyString struct { | type PyString struct { | ||||||
| 	*Token | 	*Token | ||||||
| 	Body string | 	Body string | ||||||
|  | 	Step *Step | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Table is a row group object used with step definition | // Table is a row group object used with step definition | ||||||
| type Table struct { | type table struct { | ||||||
| 	*Token | 	*Token | ||||||
| 	rows [][]string | 	rows [][]string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // ExampleTable is a row group object for | ||||||
|  | // scenario outline examples | ||||||
|  | type ExampleTable struct { | ||||||
|  | 	*table | ||||||
|  | 	OutlineScenario *Scenario | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // StepTable is a row group object for steps | ||||||
|  | type StepTable struct { | ||||||
|  | 	*table | ||||||
|  | 	Step *Step | ||||||
|  | } | ||||||
|  | 
 | ||||||
| var allSteps = []TokenType{ | var allSteps = []TokenType{ | ||||||
| 	GIVEN, | 	GIVEN, | ||||||
| 	WHEN, | 	WHEN, | ||||||
|  | @ -238,11 +256,14 @@ func (p *parser) parseFeature() (ft *Feature, err error) { | ||||||
| 				return ft, p.err("there can only be a single background section, but found another", tok.Line) | 				return ft, p.err("there can only be a single background section, but found another", tok.Line) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			ft.Background = &Background{Token: tok} | 			ft.Background = &Background{Token: tok, Feature: ft} | ||||||
| 			p.next() // jump to background steps | 			p.next() // jump to background steps | ||||||
| 			if ft.Background.Steps, err = p.parseSteps(); err != nil { | 			if ft.Background.Steps, err = p.parseSteps(); err != nil { | ||||||
| 				return ft, err | 				return ft, err | ||||||
| 			} | 			} | ||||||
|  | 			for _, step := range ft.Background.Steps { | ||||||
|  | 				step.Background = ft.Background | ||||||
|  | 			} | ||||||
| 			tok = p.peek() // peek to scenario or tags | 			tok = p.peek() // peek to scenario or tags | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -269,6 +290,7 @@ func (p *parser) parseFeature() (ft *Feature, err error) { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		scenario.Tags = tags | 		scenario.Tags = tags | ||||||
|  | 		scenario.Feature = ft | ||||||
| 		ft.Scenarios = append(ft.Scenarios, scenario) | 		ft.Scenarios = append(ft.Scenarios, scenario) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -281,6 +303,9 @@ func (p *parser) parseScenario() (s *Scenario, err error) { | ||||||
| 	if s.Steps, err = p.parseSteps(); err != nil { | 	if s.Steps, err = p.parseSteps(); err != nil { | ||||||
| 		return s, err | 		return s, err | ||||||
| 	} | 	} | ||||||
|  | 	for _, step := range s.Steps { | ||||||
|  | 		step.Scenario = s | ||||||
|  | 	} | ||||||
| 	if examples := p.peek(); examples.Type == EXAMPLES { | 	if examples := p.peek(); examples.Type == EXAMPLES { | ||||||
| 		p.next() // jump over the peeked token | 		p.next() // jump over the peeked token | ||||||
| 		peek := p.peek() | 		peek := p.peek() | ||||||
|  | @ -290,9 +315,11 @@ func (p *parser) parseScenario() (s *Scenario, err error) { | ||||||
| 				"but got '" + peek.Type.String() + "' instead, for scenario outline examples", | 				"but got '" + peek.Type.String() + "' instead, for scenario outline examples", | ||||||
| 			}, " "), examples.Line) | 			}, " "), examples.Line) | ||||||
| 		} | 		} | ||||||
| 		if s.Examples, err = p.parseTable(); err != nil { | 		tbl, err := p.parseTable() | ||||||
|  | 		if err != nil { | ||||||
| 			return s, err | 			return s, err | ||||||
| 		} | 		} | ||||||
|  | 		s.Examples = &ExampleTable{OutlineScenario: s, table: tbl} | ||||||
| 	} | 	} | ||||||
| 	return s, nil | 	return s, nil | ||||||
| } | } | ||||||
|  | @ -309,10 +336,13 @@ func (p *parser) parseSteps() (steps []*Step, err error) { | ||||||
| 				if step.PyString, err = p.parsePystring(); err != nil { | 				if step.PyString, err = p.parsePystring(); err != nil { | ||||||
| 					return steps, err | 					return steps, err | ||||||
| 				} | 				} | ||||||
|  | 				step.PyString.Step = step | ||||||
| 			case TABLE_ROW: | 			case TABLE_ROW: | ||||||
| 				if step.Table, err = p.parseTable(); err != nil { | 				tbl, err := p.parseTable() | ||||||
|  | 				if err != nil { | ||||||
| 					return steps, err | 					return steps, err | ||||||
| 				} | 				} | ||||||
|  | 				step.Table = &StepTable{Step: step, table: tbl} | ||||||
| 			default: | 			default: | ||||||
| 				return steps, p.err("pystring or table row was expected, but got: '"+tok.Type.String()+"' instead", tok.Line) | 				return steps, p.err("pystring or table row was expected, but got: '"+tok.Type.String()+"' instead", tok.Line) | ||||||
| 			} | 			} | ||||||
|  | @ -339,8 +369,8 @@ func (p *parser) parsePystring() (*PyString, error) { | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *parser) parseTable() (*Table, error) { | func (p *parser) parseTable() (*table, error) { | ||||||
| 	tbl := &Table{} | 	tbl := &table{} | ||||||
| 	for row := p.peek(); row.Type == TABLE_ROW; row = p.peek() { | 	for row := p.peek(); row.Type == TABLE_ROW; row = p.peek() { | ||||||
| 		var cols []string | 		var cols []string | ||||||
| 		for _, r := range strings.Split(strings.Trim(row.Value, "|"), "|") { | 		for _, r := range strings.Split(strings.Trim(row.Value, "|"), "|") { | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								suite.go
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								suite.go
									
										
									
									
									
								
							|  | @ -4,40 +4,10 @@ import ( | ||||||
| 	"flag" | 	"flag" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strconv" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/DATA-DOG/godog/gherkin" | 	"github.com/DATA-DOG/godog/gherkin" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Arg is an argument for StepHandler parsed from |  | ||||||
| // the regexp submatch to handle the step |  | ||||||
| type Arg string |  | ||||||
| 
 |  | ||||||
| // Float converts an argument to float64 |  | ||||||
| // or panics if unable to convert it |  | ||||||
| func (a Arg) Float() float64 { |  | ||||||
| 	v, err := strconv.ParseFloat(string(a), 64) |  | ||||||
| 	if err == nil { |  | ||||||
| 		return v |  | ||||||
| 	} |  | ||||||
| 	panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, a, err)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int converts an argument to int64 |  | ||||||
| // or panics if unable to convert it |  | ||||||
| func (a Arg) Int() int64 { |  | ||||||
| 	v, err := strconv.ParseInt(string(a), 10, 0) |  | ||||||
| 	if err == nil { |  | ||||||
| 		return v |  | ||||||
| 	} |  | ||||||
| 	panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, a, err)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // String converts an argument to string |  | ||||||
| func (a Arg) String() string { |  | ||||||
| 	return string(a) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Objects implementing the StepHandler interface can be | // Objects implementing the StepHandler interface can be | ||||||
| // registered as step definitions in godog | // registered as step definitions in godog | ||||||
| // | // | ||||||
|  |  | ||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 gedi
						gedi