instead of Suite interface expose Suite struct
* 570d70a update examples regarding Suite interface removal, closes #11
Этот коммит содержится в:
		
							родитель
							
								
									46f5218d36
								
							
						
					
					
						коммит
						ca36316b7a
					
				
					 19 изменённых файлов: 142 добавлений и 234 удалений
				
			
		
							
								
								
									
										38
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										38
									
								
								README.md
									
										
									
									
									
								
							|  | @ -25,11 +25,15 @@ not changed most likely. I'll try to respect **backward compatibility** as much | |||
| 
 | ||||
| ### Example | ||||
| 
 | ||||
| The following example can be [found here](https://github.com/DATA-DOG/godog/tree/master/examples/godogs). | ||||
| 
 | ||||
| #### Step 1 | ||||
| 
 | ||||
| Imagine we have a **godog cart** to serve godogs for dinner. At first, we describe our feature | ||||
| in plain text: | ||||
| 
 | ||||
| ``` gherkin | ||||
| # file: /tmp/godog/godog.feature | ||||
| # file: examples/godogs/godog.feature | ||||
| Feature: eat godogs | ||||
|   In order to be happy | ||||
|   As a hungry gopher | ||||
|  | @ -44,22 +48,27 @@ Feature: eat godogs | |||
| As a developer, your work is done as soon as you’ve made the program behave as | ||||
| described in the Scenario. | ||||
| 
 | ||||
| If you run `godog godog.feature` inside the **/tmp/godog** directory. | ||||
| #### Step 2 | ||||
| 
 | ||||
| If you run `godog godog.feature` inside the **examples/godogs** directory. | ||||
| You should see that the steps are undefined: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| It gives you undefined step snippets to implement in your test context. You may copy these snippets | ||||
| into **godog_test.go** file. | ||||
| into your `*_test.go` file. | ||||
| 
 | ||||
| Now if you run the tests again. You should see that the definition is now pending. You may change | ||||
| **ErrPending** to **nil** and the scenario will pass successfully. | ||||
| 
 | ||||
| Since we need a working implementation, we may start by implementing what is necessary. | ||||
| We only need a number of **godogs** for now. | ||||
| Since we need a working implementation, we may start by implementing only what is necessary. | ||||
| 
 | ||||
| #### Step 3 | ||||
| 
 | ||||
| We only need a number of **godogs** for now. Lets define steps. | ||||
| 
 | ||||
| ``` go | ||||
| /* file: /tmp/godog/godog.go */ | ||||
| /* file: examples/godogs/godog.go */ | ||||
| package main | ||||
| 
 | ||||
| var Godogs int | ||||
|  | @ -67,10 +76,12 @@ var Godogs int | |||
| func main() { /* usual main func */ } | ||||
| ``` | ||||
| 
 | ||||
| #### Step 4 | ||||
| 
 | ||||
| Now lets finish our step implementations in order to test our feature requirements: | ||||
| 
 | ||||
| ``` go | ||||
| /* file: /tmp/godog/godog_test.go */ | ||||
| /* file: examples/godogs/godog_test.go */ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
|  | @ -99,7 +110,7 @@ func thereShouldBeRemaining(remaining int) error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func featureContext(s godog.Suite) { | ||||
| func featureContext(s *godog.Suite) { | ||||
| 	s.Step(`^there are (\d+) godogs$`, thereAreGodogs) | ||||
| 	s.Step(`^I eat (\d+)$`, iEat) | ||||
| 	s.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) | ||||
|  | @ -126,8 +137,15 @@ See `godog -h` for general command options. | |||
| 
 | ||||
| See implementation examples: | ||||
| 
 | ||||
| - [rest API server](https://github.com/DATA-DOG/godog/tree/master/examples/api) implementation and tests | ||||
| - [ls command](https://github.com/DATA-DOG/godog/tree/master/examples/ls) implementation and tests | ||||
| - [rest API server](https://github.com/DATA-DOG/godog/tree/master/examples/api) | ||||
| - [godogs](https://github.com/DATA-DOG/godog/tree/master/examples/godogs) | ||||
| 
 | ||||
| ### Changes | ||||
| 
 | ||||
| **2015-07-03** | ||||
| - changed **godog.Suite** from interface to struct. Context registration should be updated accordingly. The reason | ||||
| for change: since it exports the same methods and there is no need to mock a function in tests, there is no | ||||
| obvious reason to keep an interface. | ||||
| 
 | ||||
| ### FAQ | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										19
									
								
								builder.go
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								builder.go
									
										
									
									
									
								
							|  | @ -82,7 +82,7 @@ func (b *builder) parseFile(path string) error { | |||
| 		b.Internal = true | ||||
| 	} | ||||
| 	b.deleteMainFunc(f) | ||||
| 	b.registerSteps(f) | ||||
| 	b.registerContexts(f) | ||||
| 	b.deleteImports(f) | ||||
| 	b.files[path] = f | ||||
| 
 | ||||
|  | @ -122,22 +122,25 @@ func (b *builder) deleteMainFunc(f *ast.File) { | |||
| 	f.Decls = decls | ||||
| } | ||||
| 
 | ||||
| func (b *builder) registerSteps(f *ast.File) { | ||||
| func (b *builder) registerContexts(f *ast.File) { | ||||
| 	for _, d := range f.Decls { | ||||
| 		switch fun := d.(type) { | ||||
| 		case *ast.FuncDecl: | ||||
| 			for _, param := range fun.Type.Params.List { | ||||
| 				switch expr := param.Type.(type) { | ||||
| 				case *ast.SelectorExpr: | ||||
| 				case *ast.StarExpr: | ||||
| 					switch x := expr.X.(type) { | ||||
| 					case *ast.Ident: | ||||
| 						if x.Name == "godog" && expr.Sel.Name == "Suite" { | ||||
| 						if x.Name == "Suite" { | ||||
| 							b.Contexts = append(b.Contexts, fun.Name.Name) | ||||
| 						} | ||||
| 					} | ||||
| 				case *ast.Ident: | ||||
| 					if expr.Name == "Suite" { | ||||
| 						b.Contexts = append(b.Contexts, fun.Name.Name) | ||||
| 					case *ast.SelectorExpr: | ||||
| 						switch t := x.X.(type) { | ||||
| 						case *ast.Ident: | ||||
| 							if t.Name == "godog" && x.Sel.Name == "Suite" { | ||||
| 								b.Contexts = append(b.Contexts, fun.Name.Name) | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  |  | |||
|  | @ -75,7 +75,7 @@ func (a *apiFeature) theResponseShouldMatchJSON(body *gherkin.DocString) error { | |||
| 	return godog.ErrPending | ||||
| } | ||||
| 
 | ||||
| func featureContext(s godog.Suite) { | ||||
| func featureContext(s *godog.Suite) { | ||||
| 	api := &apiFeature{} | ||||
| 	s.Step(`^I send "([^"]*)" request to "([^"]*)"$`, api.iSendrequestTo) | ||||
| 	s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) | ||||
|  | @ -158,7 +158,7 @@ func (a *apiFeature) theResponseShouldMatchJSON(body *gherkin.DocString) (err er | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func featureContext(s godog.Suite) { | ||||
| func featureContext(s *godog.Suite) { | ||||
| 	api := &apiFeature{} | ||||
| 
 | ||||
| 	s.BeforeScenario(api.resetResponse) | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ func (a *apiFeature) theResponseShouldMatchJSON(body *gherkin.DocString) (err er | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func featureContext(s godog.Suite) { | ||||
| func featureContext(s *godog.Suite) { | ||||
| 	api := &apiFeature{} | ||||
| 
 | ||||
| 	s.BeforeScenario(api.resetResponse) | ||||
|  |  | |||
							
								
								
									
										
											Двоичные данные
										
									
								
								examples/api/screenshots/undefined.png
									
										
									
									
									
								
							
							
						
						
									
										
											Двоичные данные
										
									
								
								examples/api/screenshots/undefined.png
									
										
									
									
									
								
							
										
											Двоичный файл не отображается.
										
									
								
							| До Ширина: | Высота: | Размер: 151 КиБ После Ширина: | Высота: | Размер: 148 КиБ | 
|  | @ -117,7 +117,7 @@ func (a *apiFeature) thereAreUsers(users *gherkin.DataTable) error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func featureContext(s godog.Suite) { | ||||
| func featureContext(s *godog.Suite) { | ||||
| 	api := &apiFeature{} | ||||
| 
 | ||||
| 	s.BeforeScenario(api.resetResponse) | ||||
|  |  | |||
							
								
								
									
										9
									
								
								examples/godogs/godog.feature
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										9
									
								
								examples/godogs/godog.feature
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,9 @@ | |||
| Feature: eat godogs | ||||
|   In order to be happy | ||||
|   As a hungry gopher | ||||
|   I need to be able to eat godogs | ||||
| 
 | ||||
|   Scenario: Eat 5 out of 12 | ||||
|     Given there are 12 godogs | ||||
|     When I eat 5 | ||||
|     Then there should be 7 remaining | ||||
							
								
								
									
										5
									
								
								examples/godogs/godog.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										5
									
								
								examples/godogs/godog.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,5 @@ | |||
| package main | ||||
| 
 | ||||
| var Godogs int | ||||
| 
 | ||||
| func main() { /* usual main func */ } | ||||
							
								
								
									
										37
									
								
								examples/godogs/godog_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										37
									
								
								examples/godogs/godog_test.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,37 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/DATA-DOG/godog" | ||||
| ) | ||||
| 
 | ||||
| func thereAreGodogs(available int) error { | ||||
| 	Godogs = available | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func iEat(num int) error { | ||||
| 	if Godogs < num { | ||||
| 		return fmt.Errorf("you cannot eat %d godogs, there are %d available", num, Godogs) | ||||
| 	} | ||||
| 	Godogs -= num | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func thereShouldBeRemaining(remaining int) error { | ||||
| 	if Godogs != remaining { | ||||
| 		return fmt.Errorf("expected %d godogs to be remaining, but there is %d", remaining, Godogs) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func featureContext(s *godog.Suite) { | ||||
| 	s.Step(`^there are (\d+) godogs$`, thereAreGodogs) | ||||
| 	s.Step(`^I eat (\d+)$`, iEat) | ||||
| 	s.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) | ||||
| 
 | ||||
| 	s.BeforeScenario(func(interface{}) { | ||||
| 		Godogs = 0 // clean the state before every scenario | ||||
| 	}) | ||||
| } | ||||
|  | @ -1,7 +0,0 @@ | |||
| # ls feature | ||||
| 
 | ||||
| In order to test our **ls** feature with **Godog**, run: | ||||
| 
 | ||||
|     go get github.com/DATA-DOG/godog/cmd/godog | ||||
|     $GOPATH/bin/godog ls.feature | ||||
| 
 | ||||
|  | @ -1,27 +0,0 @@ | |||
| Feature: ls | ||||
|   In order to see the directory structure | ||||
|   As a UNIX user | ||||
|   I need to be able to list directory contents | ||||
| 
 | ||||
|   Background: | ||||
|     Given I am in a directory "test" | ||||
| 
 | ||||
|   Scenario: lists files in directory | ||||
|     Given I have a file named "foo" | ||||
|     And I have a file named "bar" | ||||
|     When I run ls | ||||
|     Then I should get output: | ||||
|       """ | ||||
|       bar | ||||
|       foo | ||||
|       """ | ||||
| 
 | ||||
|   Scenario: lists files and directories | ||||
|     Given I have a file named "foo" | ||||
|     And I have a directory named "dir" | ||||
|     When I run ls | ||||
|     Then I should get output: | ||||
|       """ | ||||
|       dir | ||||
|       foo | ||||
|       """ | ||||
|  | @ -1,35 +0,0 @@ | |||
| // Example - demonstrates ls command implementation tests. | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	var location string | ||||
| 	switch { | ||||
| 	case os.Args[1] != "": | ||||
| 		location = os.Args[1] | ||||
| 	default: | ||||
| 		location = "." | ||||
| 	} | ||||
| 	if err := ls(location, os.Stdout); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func ls(path string, w io.Writer) error { | ||||
| 	return filepath.Walk(path, func(p string, f os.FileInfo, err error) error { | ||||
| 		switch { | ||||
| 		case f.IsDir() && f.Name() != "." && f.Name() != ".." && filepath.Base(path) != f.Name(): | ||||
| 			w.Write([]byte(f.Name() + "\n")) | ||||
| 			return filepath.SkipDir | ||||
| 		case !f.IsDir(): | ||||
| 			w.Write([]byte(f.Name() + "\n")) | ||||
| 		} | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | @ -1,66 +0,0 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/DATA-DOG/godog" | ||||
| 	"github.com/cucumber/gherkin-go" | ||||
| ) | ||||
| 
 | ||||
| type lsFeature struct { | ||||
| 	dir string | ||||
| 	buf *bytes.Buffer | ||||
| } | ||||
| 
 | ||||
| func lsFeatureContext(s godog.Suite) { | ||||
| 	c := &lsFeature{buf: bytes.NewBuffer(make([]byte, 1024))} | ||||
| 
 | ||||
| 	s.Step(`^I am in a directory "([^"]*)"$`, c.iAmInDirectory) | ||||
| 	s.Step(`^I have a (file|directory) named "([^"]*)"$`, c.iHaveFileOrDirectoryNamed) | ||||
| 	s.Step(`^I run ls$`, c.iRunLs) | ||||
| 	s.Step(`^I should get output:$`, c.iShouldGetOutput) | ||||
| } | ||||
| 
 | ||||
| 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(typ, name string) (err error) { | ||||
| 	if len(f.dir) == 0 { | ||||
| 		return fmt.Errorf("the directory was not chosen yet") | ||||
| 	} | ||||
| 	switch typ { | ||||
| 	case "file": | ||||
| 		err = ioutil.WriteFile(f.dir+"/"+name, []byte{}, 0664) | ||||
| 	case "directory": | ||||
| 		err = os.Mkdir(f.dir+"/"+name, 0775) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| 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)) | ||||
| 	} | ||||
| 	for i, line := range actual { | ||||
| 		if line != expected[i] { | ||||
| 			return fmt.Errorf(`expected line "%s" at position: %d to match "%s", but it did not`, expected[i], i, line) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (f *lsFeature) iRunLs() error { | ||||
| 	f.buf.Reset() | ||||
| 	return ls(f.dir, f.buf) | ||||
| } | ||||
							
								
								
									
										4
									
								
								flags.go
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								flags.go
									
										
									
									
									
								
							|  | @ -5,7 +5,9 @@ import ( | |||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| func flags(s *suite) *flag.FlagSet { | ||||
| // Flags builds a *flag.FlagSet with all flags | ||||
| // required for the godog suite | ||||
| func flags(s *Suite) *flag.FlagSet { | ||||
| 	set := flag.NewFlagSet("godog", flag.ExitOnError) | ||||
| 	set.StringVar(&s.format, "format", "pretty", "") | ||||
| 	set.StringVar(&s.format, "f", "pretty", "") | ||||
|  |  | |||
							
								
								
									
										2
									
								
								fmt.go
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								fmt.go
									
										
									
									
									
								
							|  | @ -30,7 +30,7 @@ var undefinedSnippetsTpl = template.Must(template.New("snippets").Funcs(snippetH | |||
| 	return godog.ErrPending | ||||
| } | ||||
| 
 | ||||
| {{end}}func featureContext(s godog.Suite) { {{ range . }} | ||||
| {{end}}func featureContext(s *godog.Suite) { {{ range . }} | ||||
| 	s.Step({{ backticked .Expr }}, {{ .Method }}){{end}} | ||||
| } | ||||
| `)) | ||||
|  |  | |||
							
								
								
									
										
											Двоичные данные
										
									
								
								screenshots/undefined.png
									
										
									
									
									
								
							
							
						
						
									
										
											Двоичные данные
										
									
								
								screenshots/undefined.png
									
										
									
									
									
								
							
										
											Двоичный файл не отображается.
										
									
								
							| До Ширина: | Высота: | Размер: 96 КиБ После Ширина: | Высота: | Размер: 109 КиБ | 
							
								
								
									
										109
									
								
								suite.go
									
										
									
									
									
								
							
							
						
						
									
										109
									
								
								suite.go
									
										
									
									
									
								
							|  | @ -28,52 +28,18 @@ var ErrUndefined = fmt.Errorf("step is undefined") | |||
| // step implementation is pending | ||||
| var ErrPending = fmt.Errorf("step implementation is pending") | ||||
| 
 | ||||
| // Suite is an interface which allows various contexts | ||||
| // Suite allows various contexts | ||||
| // to register steps and event handlers. | ||||
| // | ||||
| // When running a test suite, this interface is passed | ||||
| // to all functions (contexts), which have it as a | ||||
| // first and only argument. | ||||
| // When running a test suite, the instance of Suite | ||||
| // is passed to all functions (contexts), which | ||||
| // have it as a first and only argument. | ||||
| // | ||||
| // Note that all event hooks does not catch panic errors | ||||
| // in order to have a trace information. Only step | ||||
| // executions are catching panic error since it may | ||||
| // be a context specific error. | ||||
| type Suite interface { | ||||
| 	// Run the test suite | ||||
| 	Run() | ||||
| 
 | ||||
| 	// 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()) | ||||
| } | ||||
| 
 | ||||
| type suite struct { | ||||
| type Suite struct { | ||||
| 	steps    []*StepDef | ||||
| 	features []*feature | ||||
| 	fmt      Formatter | ||||
|  | @ -98,24 +64,27 @@ type suite struct { | |||
| } | ||||
| 
 | ||||
| // New initializes a Suite. The instance is passed around | ||||
| // to all context initialization functions from *_test.go files | ||||
| func New() Suite { | ||||
| 	return &suite{} | ||||
| // to all context initialization functions from *_test.go files. | ||||
| func New() *Suite { | ||||
| 	return &Suite{} | ||||
| } | ||||
| 
 | ||||
| // Step allows to register a StepHandler in Godog | ||||
| // feature suite, the handler will be applied to all | ||||
| // steps matching the given Regexp expr | ||||
| // Step allows to register a *StepDef in Godog | ||||
| // feature suite, the definition will be applied | ||||
| // to all steps matching the given Regexp expr. | ||||
| // | ||||
| // It will panic if expr is not a valid regular expression | ||||
| // It will panic if expr is not a valid regular | ||||
| // expression or stepFunc is not a valid step | ||||
| // handler. | ||||
| // | ||||
| // Note that if there are two handlers which may match | ||||
| // the same step, then the only first matched handler | ||||
| // Note that if there are two definitions which may match | ||||
| // the same step, then only the first matched handler | ||||
| // will be applied. | ||||
| // | ||||
| // If none of the StepHandlers are matched, then | ||||
| // ErrUndefined error will be returned. | ||||
| func (s *suite) Step(expr interface{}, stepFunc interface{}) { | ||||
| // If none of the *StepDef is matched, then | ||||
| // ErrUndefined error will be returned when | ||||
| // running steps. | ||||
| func (s *Suite) Step(expr interface{}, stepFunc interface{}) { | ||||
| 	var regex *regexp.Regexp | ||||
| 
 | ||||
| 	switch t := expr.(type) { | ||||
|  | @ -152,7 +121,7 @@ func (s *suite) Step(expr interface{}, stepFunc interface{}) { | |||
| // | ||||
| // Use it to prepare the test suite for a spin. | ||||
| // Connect and prepare database for instance... | ||||
| func (s *suite) BeforeSuite(f func()) { | ||||
| func (s *Suite) BeforeSuite(f func()) { | ||||
| 	s.beforeSuiteHandlers = append(s.beforeSuiteHandlers, f) | ||||
| } | ||||
| 
 | ||||
|  | @ -165,13 +134,13 @@ func (s *suite) BeforeSuite(f func()) { | |||
| // It is a good practice to restore the default state | ||||
| // before every scenario so it would be isolated from | ||||
| // any kind of state. | ||||
| func (s *suite) BeforeScenario(f func(interface{})) { | ||||
| func (s *Suite) BeforeScenario(f func(interface{})) { | ||||
| 	s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, f) | ||||
| } | ||||
| 
 | ||||
| // BeforeStep registers a function or method | ||||
| // to be run before every scenario | ||||
| func (s *suite) BeforeStep(f func(*gherkin.Step)) { | ||||
| func (s *Suite) BeforeStep(f func(*gherkin.Step)) { | ||||
| 	s.beforeStepHandlers = append(s.beforeStepHandlers, f) | ||||
| } | ||||
| 
 | ||||
|  | @ -184,7 +153,7 @@ func (s *suite) BeforeStep(f func(*gherkin.Step)) { | |||
| // | ||||
| // In some cases, for example when running a headless | ||||
| // browser, to take a screenshot after failure. | ||||
| func (s *suite) AfterStep(f func(*gherkin.Step, error)) { | ||||
| func (s *Suite) AfterStep(f func(*gherkin.Step, error)) { | ||||
| 	s.afterStepHandlers = append(s.afterStepHandlers, f) | ||||
| } | ||||
| 
 | ||||
|  | @ -193,18 +162,18 @@ func (s *suite) AfterStep(f func(*gherkin.Step, error)) { | |||
| // | ||||
| // The interface argument may be *gherkin.Scenario | ||||
| // or *gherkin.ScenarioOutline | ||||
| func (s *suite) AfterScenario(f func(interface{}, error)) { | ||||
| func (s *Suite) AfterScenario(f func(interface{}, error)) { | ||||
| 	s.afterScenarioHandlers = append(s.afterScenarioHandlers, f) | ||||
| } | ||||
| 
 | ||||
| // AfterSuite registers a function or method | ||||
| // to be run once after suite runner | ||||
| func (s *suite) AfterSuite(f func()) { | ||||
| func (s *Suite) AfterSuite(f func()) { | ||||
| 	s.afterSuiteHandlers = append(s.afterSuiteHandlers, f) | ||||
| } | ||||
| 
 | ||||
| // Run starts the Godog feature suite | ||||
| func (s *suite) Run() { | ||||
| func (s *Suite) Run() { | ||||
| 	flagSet := flags(s) | ||||
| 	fatal(flagSet.Parse(os.Args[1:])) | ||||
| 
 | ||||
|  | @ -249,7 +218,7 @@ func (s *suite) Run() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *suite) run() { | ||||
| func (s *Suite) run() { | ||||
| 	// run before suite handlers | ||||
| 	for _, f := range s.beforeSuiteHandlers { | ||||
| 		f() | ||||
|  | @ -269,7 +238,7 @@ func (s *suite) run() { | |||
| 	s.fmt.Summary() | ||||
| } | ||||
| 
 | ||||
| func (s *suite) matchStep(step *gherkin.Step) *StepDef { | ||||
| func (s *Suite) matchStep(step *gherkin.Step) *StepDef { | ||||
| 	for _, h := range s.steps { | ||||
| 		if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 { | ||||
| 			var args []interface{} | ||||
|  | @ -286,7 +255,7 @@ func (s *suite) matchStep(step *gherkin.Step) *StepDef { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *suite) runStep(step *gherkin.Step, prevStepErr error) (err error) { | ||||
| func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) { | ||||
| 	match := s.matchStep(step) | ||||
| 	if match == nil { | ||||
| 		s.fmt.Undefined(step) | ||||
|  | @ -330,7 +299,7 @@ func (s *suite) runStep(step *gherkin.Step, prevStepErr error) (err error) { | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) { | ||||
| func (s *Suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) { | ||||
| 	err = prevErr | ||||
| 	for _, step := range steps { | ||||
| 		stepErr := s.runStep(step, err) | ||||
|  | @ -347,13 +316,13 @@ func (s *suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) { | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suite) skipSteps(steps []*gherkin.Step) { | ||||
| func (s *Suite) skipSteps(steps []*gherkin.Step) { | ||||
| 	for _, step := range steps { | ||||
| 		s.fmt.Skipped(step) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Background) (failErr error) { | ||||
| func (s *Suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Background) (failErr error) { | ||||
| 	s.fmt.Node(outline) | ||||
| 
 | ||||
| 	for _, example := range outline.Examples { | ||||
|  | @ -403,7 +372,7 @@ func (s *suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Backgrou | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suite) runFeature(f *feature) { | ||||
| func (s *Suite) runFeature(f *feature) { | ||||
| 	s.fmt.Feature(f.Feature, f.Path) | ||||
| 	for _, scenario := range f.ScenarioDefinitions { | ||||
| 		var err error | ||||
|  | @ -425,7 +394,7 @@ func (s *suite) runFeature(f *feature) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *suite) runScenario(scenario *gherkin.Scenario, b *gherkin.Background) (err error) { | ||||
| func (s *Suite) runScenario(scenario *gherkin.Scenario, b *gherkin.Background) (err error) { | ||||
| 	// run before scenario handlers | ||||
| 	for _, f := range s.beforeScenarioHandlers { | ||||
| 		f(scenario) | ||||
|  | @ -448,7 +417,7 @@ func (s *suite) runScenario(scenario *gherkin.Scenario, b *gherkin.Background) ( | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suite) printStepDefinitions() { | ||||
| func (s *Suite) printStepDefinitions() { | ||||
| 	var longest int | ||||
| 	for _, def := range s.steps { | ||||
| 		if longest < len(def.Expr.String()) { | ||||
|  | @ -465,7 +434,7 @@ func (s *suite) printStepDefinitions() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *suite) parseFeatures() (err error) { | ||||
| func (s *Suite) parseFeatures() (err error) { | ||||
| 	for _, pat := range s.paths { | ||||
| 		// check if line number is specified | ||||
| 		parts := strings.Split(pat, ":") | ||||
|  | @ -525,7 +494,7 @@ func (s *suite) parseFeatures() (err error) { | |||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (s *suite) applyTagFilter(ft *gherkin.Feature) { | ||||
| func (s *Suite) applyTagFilter(ft *gherkin.Feature) { | ||||
| 	if len(s.tags) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | @ -585,7 +554,7 @@ func hasTag(tags []string, tag string) bool { | |||
| } | ||||
| 
 | ||||
| // based on http://behat.readthedocs.org/en/v2.5/guides/6.cli.html#gherkin-filters | ||||
| func (s *suite) matchesTags(tags []string) (ok bool) { | ||||
| func (s *Suite) matchesTags(tags []string) (ok bool) { | ||||
| 	ok = true | ||||
| 	for _, andTags := range strings.Split(s.tags, "&&") { | ||||
| 		var okComma bool | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ import ( | |||
| 	"github.com/cucumber/gherkin-go" | ||||
| ) | ||||
| 
 | ||||
| func SuiteContext(s Suite) { | ||||
| func SuiteContext(s *Suite) { | ||||
| 	c := &suiteContext{} | ||||
| 
 | ||||
| 	s.BeforeScenario(c.ResetBeforeEachScenario) | ||||
|  | @ -50,7 +50,7 @@ type firedEvent struct { | |||
| } | ||||
| 
 | ||||
| type suiteContext struct { | ||||
| 	testedSuite *suite | ||||
| 	testedSuite *Suite | ||||
| 	events      []*firedEvent | ||||
| 	fmt         *testFormatter | ||||
| } | ||||
|  | @ -58,7 +58,7 @@ type suiteContext struct { | |||
| func (s *suiteContext) ResetBeforeEachScenario(interface{}) { | ||||
| 	// reset whole suite with the state | ||||
| 	s.fmt = &testFormatter{} | ||||
| 	s.testedSuite = &suite{fmt: s.fmt} | ||||
| 	s.testedSuite = &Suite{fmt: s.fmt} | ||||
| 	// our tested suite will have the same context registered | ||||
| 	SuiteContext(s.testedSuite) | ||||
| 	// reset all fired events | ||||
|  |  | |||
|  | @ -5,14 +5,14 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func assertNotMatchesTagFilter(tags []string, filter string, t *testing.T) { | ||||
| 	s := &suite{tags: filter} | ||||
| 	s := &Suite{tags: filter} | ||||
| 	if s.matchesTags(tags) { | ||||
| 		t.Errorf(`expected tags: %v not to match tag filter "%s", but it did`, tags, filter) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func assertMatchesTagFilter(tags []string, filter string, t *testing.T) { | ||||
| 	s := &suite{tags: filter} | ||||
| 	s := &Suite{tags: filter} | ||||
| 	if !s.matchesTags(tags) { | ||||
| 		t.Errorf(`expected tags: %v to match tag filter "%s", but it did not`, tags, filter) | ||||
| 	} | ||||
|  |  | |||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 gedi
						gedi