add an ls feature example
Этот коммит содержится в:
		
							родитель
							
								
									6e65757f89
								
							
						
					
					
						коммит
						e824fde3f9
					
				
					 15 изменённых файлов: 244 добавлений и 100 удалений
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										предоставленный
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										предоставленный
									
									
								
							|  | @ -1 +1,2 @@ | ||||||
| /cmd/godog/godog | /cmd/godog/godog | ||||||
|  | /example/example | ||||||
|  |  | ||||||
|  | @ -9,6 +9,10 @@ describe a feature of your application and how it should work, and only then imp | ||||||
| 
 | 
 | ||||||
| The project is inspired by [behat][behat] and [cucumber][cucumber] and is based on cucumber [gherkin specification][gherkin]. | The project is inspired by [behat][behat] and [cucumber][cucumber] and is based on cucumber [gherkin specification][gherkin]. | ||||||
| 
 | 
 | ||||||
|  | ### Install | ||||||
|  | 
 | ||||||
|  |     go install github.com/DATA-DOG/godog/cmd/godog | ||||||
|  | 
 | ||||||
| ### Be aware that | ### Be aware that | ||||||
| 
 | 
 | ||||||
| The work is still in progress and is not functional yet, neither it is intended for production usage. | The work is still in progress and is not functional yet, neither it is intended for production usage. | ||||||
|  | @ -21,7 +25,9 @@ See **.travis.yml** for supported **go** versions. | ||||||
| 
 | 
 | ||||||
| ### License | ### License | ||||||
| 
 | 
 | ||||||
| Licensed under the [three clause BSD license][license] | All package dependencies are **MIT** or **BSD** licensed. | ||||||
|  | 
 | ||||||
|  | **Godog** is licensed under the [three clause BSD license][license] | ||||||
| 
 | 
 | ||||||
| [godoc]: http://godoc.org/github.com/DATA-DOG/godog "Documentation on godoc" | [godoc]: http://godoc.org/github.com/DATA-DOG/godog "Documentation on godoc" | ||||||
| [godoc_gherkin]: http://godoc.org/github.com/DATA-DOG/godog/gherkin "Documentation on godoc for gherkin" | [godoc_gherkin]: http://godoc.org/github.com/DATA-DOG/godog/gherkin "Documentation on godoc for gherkin" | ||||||
|  |  | ||||||
|  | @ -8,14 +8,18 @@ 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. | ||||||
|  | // | ||||||
|  | // In future versions, it may be replaced with | ||||||
|  | // an argument injection toolkit using reflect | ||||||
|  | // package. | ||||||
| type Arg struct { | type Arg struct { | ||||||
| 	value interface{} | 	value interface{} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // StepArgument func creates a step argument. | // StepArgument func creates a step argument. | ||||||
| // used in cases when calling another step from | // used in cases when calling another step from | ||||||
| // within a StepHandlerFunc | // within a StepHandler function. | ||||||
| func StepArgument(value interface{}) *Arg { | func StepArgument(value interface{}) *Arg { | ||||||
| 	return &Arg{value: value} | 	return &Arg{value: value} | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								builder.go
									
										
									
									
									
								
							
							
						
						
									
										42
									
								
								builder.go
									
										
									
									
									
								
							|  | @ -22,8 +22,8 @@ type builder struct { | ||||||
| 	tpl      *template.Template | 	tpl      *template.Template | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newBuilder() *builder { | func newBuilder(buildPath string) (*builder, error) { | ||||||
| 	return &builder{ | 	b := &builder{ | ||||||
| 		files: make(map[string]*ast.File), | 		files: make(map[string]*ast.File), | ||||||
| 		fset:  token.NewFileSet(), | 		fset:  token.NewFileSet(), | ||||||
| 		tpl: template.Must(template.New("main").Parse(`package main | 		tpl: template.Must(template.New("main").Parse(`package main | ||||||
|  | @ -39,6 +39,18 @@ func main() { | ||||||
| 	suite.Run() | 	suite.Run() | ||||||
| }`)), | }`)), | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	return b, filepath.Walk(buildPath, func(path string, file os.FileInfo, err error) error { | ||||||
|  | 		if file.IsDir() && file.Name() != "." { | ||||||
|  | 			return filepath.SkipDir | ||||||
|  | 		} | ||||||
|  | 		if err == nil && strings.HasSuffix(path, ".go") { | ||||||
|  | 			if err := b.parseFile(path); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return err | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (b *builder) parseFile(path string) error { | func (b *builder) parseFile(path string) error { | ||||||
|  | @ -129,24 +141,18 @@ func (b *builder) merge() (*ast.File, error) { | ||||||
| 	return ast.MergePackageFiles(pkg, ast.FilterImportDuplicates), nil | 	return ast.MergePackageFiles(pkg, ast.FilterImportDuplicates), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Build creates a runnable godog executable file | // Build creates a runnable Godog executable file | ||||||
| // from current package source and test files | // from current package source and test source files. | ||||||
| // it merges the files with the help of go/ast into | // | ||||||
|  | // The package files are merged with the help of go/ast into | ||||||
| // a single main package file which has a custom | // a single main package file which has a custom | ||||||
| // main function to run features | // main function to run test suite features. | ||||||
|  | // | ||||||
|  | // Currently, to manage imports we use "golang.org/x/tools/imports" | ||||||
|  | // package, but that may be replaced in order to have | ||||||
|  | // no external dependencies | ||||||
| func Build() ([]byte, error) { | func Build() ([]byte, error) { | ||||||
| 	b := newBuilder() | 	b, err := newBuilder(".") | ||||||
| 	err := filepath.Walk(".", func(path string, file os.FileInfo, err error) error { |  | ||||||
| 		if file.IsDir() && file.Name() != "." { |  | ||||||
| 			return filepath.SkipDir |  | ||||||
| 		} |  | ||||||
| 		if err == nil && strings.HasSuffix(path, ".go") { |  | ||||||
| 			if err := b.parseFile(path); err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return err |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								example/README.md
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										7
									
								
								example/README.md
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | # ls feature | ||||||
|  | 
 | ||||||
|  | In order to test our **ls** feature with **Godog**, run: | ||||||
|  | 
 | ||||||
|  |     go install github.com/DATA-DOG/godog/cmd/godog | ||||||
|  |     $GOPATH/bin/godog ls.feature | ||||||
|  | 
 | ||||||
							
								
								
									
										27
									
								
								example/ls.feature
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										27
									
								
								example/ls.feature
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | 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 | ||||||
|  |       """ | ||||||
							
								
								
									
										34
									
								
								example/ls.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										34
									
								
								example/ls.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | 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 | ||||||
|  | 	}) | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								example/ls_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										65
									
								
								example/ls_test.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,65 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/DATA-DOG/godog" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | 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(args ...*godog.Arg) error { | ||||||
|  | 	f.dir = os.TempDir() + "/" + args[0].String() | ||||||
|  | 	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) { | ||||||
|  | 	if len(f.dir) == 0 { | ||||||
|  | 		return fmt.Errorf("the directory was not chosen yet") | ||||||
|  | 	} | ||||||
|  | 	switch args[0].String() { | ||||||
|  | 	case "file": | ||||||
|  | 		err = ioutil.WriteFile(f.dir+"/"+args[1].String(), []byte{}, 0664) | ||||||
|  | 	case "directory": | ||||||
|  | 		err = os.Mkdir(f.dir+"/"+args[1].String(), 0775) | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (f *lsFeature) iShouldGetOutput(args ...*godog.Arg) error { | ||||||
|  | 	expected := args[0].PyString().Lines | ||||||
|  | 	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(args ...*godog.Arg) error { | ||||||
|  | 	f.buf.Reset() | ||||||
|  | 	return ls(f.dir, f.buf) | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								fmt.go
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								fmt.go
									
										
									
									
									
								
							|  | @ -7,7 +7,12 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Formatter is an interface for feature runner | // Formatter is an interface for feature runner | ||||||
| // output summary presentation | // output summary presentation. | ||||||
|  | // | ||||||
|  | // New formatters may be created to represent | ||||||
|  | // suite results in different ways. These new | ||||||
|  | // formatters needs to be registered with a | ||||||
|  | // RegisterFormatter function call | ||||||
| type Formatter interface { | type Formatter interface { | ||||||
| 	Node(interface{}) | 	Node(interface{}) | ||||||
| 	Failed(*gherkin.Step, *StepDef, error) | 	Failed(*gherkin.Step, *StepDef, error) | ||||||
|  |  | ||||||
|  | @ -22,11 +22,9 @@ var outlinePlaceholderRegexp *regexp.Regexp = regexp.MustCompile("<[^>]+>") | ||||||
| 
 | 
 | ||||||
| // a built in default pretty formatter | // a built in default pretty formatter | ||||||
| type pretty struct { | type pretty struct { | ||||||
| 	feature        *gherkin.Feature | 	feature         *gherkin.Feature | ||||||
| 	commentPos     int | 	commentPos      int | ||||||
| 	doneBackground bool | 	backgroundSteps int | ||||||
| 	background     *gherkin.Background |  | ||||||
| 	scenario       *gherkin.Scenario |  | ||||||
| 
 | 
 | ||||||
| 	// outline | 	// outline | ||||||
| 	outlineExamples int | 	outlineExamples int | ||||||
|  | @ -56,21 +54,17 @@ func (f *pretty) Node(node interface{}) { | ||||||
| 			fmt.Println("") | 			fmt.Println("") | ||||||
| 		} | 		} | ||||||
| 		f.feature = t | 		f.feature = t | ||||||
| 		f.scenario = nil |  | ||||||
| 		f.background = nil |  | ||||||
| 		f.features = append(f.features, t) | 		f.features = append(f.features, t) | ||||||
|  | 		// print feature header | ||||||
| 		fmt.Println(bcl(t.Token.Keyword+": ", white) + t.Title) | 		fmt.Println(bcl(t.Token.Keyword+": ", white) + t.Title) | ||||||
| 		fmt.Println(t.Description) | 		fmt.Println(t.Description) | ||||||
| 	case *gherkin.Background: | 		// print background header | ||||||
| 		// do not repeat background for the same feature | 		if t.Background != nil { | ||||||
| 		if f.background == nil && f.scenario == nil { | 			f.commentPos = longestStep(t.Background.Steps, t.Background.Token.Length()) | ||||||
| 			f.background = t | 			f.backgroundSteps = len(t.Background.Steps) | ||||||
| 			f.commentPos = longestStep(t.Steps, t.Token.Length()) | 			fmt.Println("\n" + s(t.Background.Token.Indent) + bcl(t.Background.Token.Keyword+":", white)) | ||||||
| 			// print background node |  | ||||||
| 			fmt.Println("\n" + s(t.Token.Indent) + bcl(t.Token.Keyword+":", white)) |  | ||||||
| 		} | 		} | ||||||
| 	case *gherkin.Scenario: | 	case *gherkin.Scenario: | ||||||
| 		f.scenario = t |  | ||||||
| 		f.commentPos = longestStep(t.Steps, t.Token.Length()) | 		f.commentPos = longestStep(t.Steps, t.Token.Length()) | ||||||
| 		if t.Outline != nil { | 		if t.Outline != nil { | ||||||
| 			f.outlineSteps = []interface{}{} // reset steps list | 			f.outlineSteps = []interface{}{} // reset steps list | ||||||
|  | @ -162,10 +156,10 @@ func (f *pretty) Summary() { | ||||||
| 	fmt.Println(elapsed) | 	fmt.Println(elapsed) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (f *pretty) printOutlineExample() { | func (f *pretty) printOutlineExample(scenario *gherkin.Scenario) { | ||||||
| 	var failed error | 	var failed error | ||||||
| 	clr := green | 	clr := green | ||||||
| 	tbl := f.scenario.Outline.Examples | 	tbl := scenario.Outline.Examples | ||||||
| 	firstExample := f.outlineExamples == len(tbl.Rows)-1 | 	firstExample := f.outlineExamples == len(tbl.Rows)-1 | ||||||
| 
 | 
 | ||||||
| 	for i, act := range f.outlineSteps { | 	for i, act := range f.outlineSteps { | ||||||
|  | @ -187,7 +181,7 @@ func (f *pretty) printOutlineExample() { | ||||||
| 		if firstExample { | 		if firstExample { | ||||||
| 			// in first example, we need to print steps | 			// in first example, we need to print steps | ||||||
| 			var text string | 			var text string | ||||||
| 			ostep := f.scenario.Outline.Steps[i] | 			ostep := scenario.Outline.Steps[i] | ||||||
| 			if def != nil { | 			if def != nil { | ||||||
| 				if m := outlinePlaceholderRegexp.FindAllStringIndex(ostep.Text, -1); len(m) > 0 { | 				if m := outlinePlaceholderRegexp.FindAllStringIndex(ostep.Text, -1); len(m) > 0 { | ||||||
| 					var pos int | 					var pos int | ||||||
|  | @ -216,7 +210,7 @@ func (f *pretty) printOutlineExample() { | ||||||
| 	max := longest(tbl) | 	max := longest(tbl) | ||||||
| 	// an example table header | 	// an example table header | ||||||
| 	if firstExample { | 	if firstExample { | ||||||
| 		out := f.scenario.Outline | 		out := scenario.Outline | ||||||
| 		fmt.Println("") | 		fmt.Println("") | ||||||
| 		fmt.Println(s(out.Token.Indent) + bcl(out.Token.Keyword+":", white)) | 		fmt.Println(s(out.Token.Indent) + bcl(out.Token.Keyword+":", white)) | ||||||
| 		row := tbl.Rows[0] | 		row := tbl.Rows[0] | ||||||
|  | @ -308,15 +302,18 @@ func (f *pretty) printStepKind(stepAction interface{}) { | ||||||
| 	step, def, c, err = f.stepDetails(stepAction) | 	step, def, c, err = f.stepDetails(stepAction) | ||||||
| 
 | 
 | ||||||
| 	// do not print background more than once | 	// do not print background more than once | ||||||
| 	if f.scenario == nil && step.Background != f.background { | 	switch { | ||||||
|  | 	case step.Background != nil && f.backgroundSteps == 0: | ||||||
| 		return | 		return | ||||||
|  | 	case step.Background != nil && f.backgroundSteps > 0: | ||||||
|  | 		f.backgroundSteps -= 1 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if f.outlineExamples != 0 { | 	if f.outlineExamples != 0 { | ||||||
| 		f.outlineSteps = append(f.outlineSteps, stepAction) | 		f.outlineSteps = append(f.outlineSteps, stepAction) | ||||||
| 		if len(f.outlineSteps) == f.outlineNumSteps { | 		if len(f.outlineSteps) == f.outlineNumSteps { | ||||||
| 			// an outline example steps has went through | 			// an outline example steps has went through | ||||||
| 			f.printOutlineExample() | 			f.printOutlineExample(step.Scenario) | ||||||
| 			f.outlineExamples -= 1 | 			f.outlineExamples -= 1 | ||||||
| 		} | 		} | ||||||
| 		return // wait till example steps | 		return // wait till example steps | ||||||
|  | @ -385,7 +382,7 @@ func longestStep(steps []*gherkin.Step, base int) int { | ||||||
| 	ret := base | 	ret := base | ||||||
| 	for _, step := range steps { | 	for _, step := range steps { | ||||||
| 		length := step.Token.Length() | 		length := step.Token.Length() | ||||||
| 		if length > base { | 		if length > ret { | ||||||
| 			ret = length | 			ret = length | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										
											Двоичные данные
										
									
								
								gherkin/example/example
									
										
									
									
									
								
							
							
						
						
									
										
											Двоичные данные
										
									
								
								gherkin/example/example
									
										
									
									
									
								
							
										
											Двоичный файл не отображается.
										
									
								
							|  | @ -1,15 +0,0 @@ | ||||||
| Feature: ls |  | ||||||
|   In order to see the directory structure |  | ||||||
|   As a UNIX user |  | ||||||
|   I need to be able to list the current directory's contents |  | ||||||
| 
 |  | ||||||
|   Scenario: |  | ||||||
|     Given I am in a directory "test" |  | ||||||
|     And I have a file named "foo" |  | ||||||
|     And I have a file named "bar" |  | ||||||
|     When I run "ls" |  | ||||||
|     Then I should get: |  | ||||||
|       """ |  | ||||||
|       bar |  | ||||||
|       foo |  | ||||||
|       """ |  | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| package main |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"log" |  | ||||||
| 	"os" |  | ||||||
| 
 |  | ||||||
| 	"github.com/DATA-DOG/godog/gherkin" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
| 	feature, err := gherkin.ParseFile("ls.feature") |  | ||||||
| 	switch { |  | ||||||
| 	case err == gherkin.ErrEmpty: |  | ||||||
| 		log.Println("the feature file is empty and does not describe any feature") |  | ||||||
| 		return |  | ||||||
| 	case err != nil: |  | ||||||
| 		log.Println("the feature file is incorrect or could not be read:", err) |  | ||||||
| 		os.Exit(1) |  | ||||||
| 	} |  | ||||||
| 	log.Println("have parsed a feature:", feature.Title, "with", len(feature.Scenarios), "scenarios") |  | ||||||
| } |  | ||||||
							
								
								
									
										66
									
								
								suite.go
									
										
									
									
									
								
							
							
						
						
									
										66
									
								
								suite.go
									
										
									
									
									
								
							|  | @ -16,26 +16,30 @@ import ( | ||||||
| // it can be either a string or a *regexp.Regexp | // it can be either a string or a *regexp.Regexp | ||||||
| type Regexp interface{} | type Regexp interface{} | ||||||
| 
 | 
 | ||||||
| // StepHandler is a function contract for | // StepHandler is a func to handle the step | ||||||
| // step handler |  | ||||||
| // | // | ||||||
| // It receives all arguments which | // The handler receives all arguments which | ||||||
| // will be matched according to the regular expression | // will be matched according to the Regexp | ||||||
| // which is passed with a step registration. | // which is passed with a step registration. | ||||||
| // The error in return - represents a reason of failure. |  | ||||||
| // | // | ||||||
| // Returning signals that the step has finished | // The error in return - represents a reason of failure. | ||||||
| // and that the feature runner can move on to the next | // All consequent scenario steps are skipped. | ||||||
| // step. | // | ||||||
|  | // Returning signals that the step has finished and that | ||||||
|  | // the feature runner can move on to the next step. | ||||||
| type StepHandler func(...*Arg) error | type StepHandler func(...*Arg) error | ||||||
| 
 | 
 | ||||||
| // ErrUndefined is returned in case if step definition was not found | // ErrUndefined is returned in case if step definition was not found | ||||||
| var ErrUndefined = fmt.Errorf("step is undefined") | var ErrUndefined = fmt.Errorf("step is undefined") | ||||||
| 
 | 
 | ||||||
| // StepDef is a registered step definition | // StepDef is a registered step definition | ||||||
| // contains a StepHandler, a regexp which | // contains a StepHandler and regexp which | ||||||
| // is used to match a step and Args which | // is used to match a step. Args which | ||||||
| // were matched by last step | // were matched by last executed step | ||||||
|  | // | ||||||
|  | // This structure is passed to the formatter | ||||||
|  | // when step is matched and is either failed | ||||||
|  | // or successful | ||||||
| type StepDef struct { | type StepDef struct { | ||||||
| 	Args    []*Arg | 	Args    []*Arg | ||||||
| 	Handler StepHandler | 	Handler StepHandler | ||||||
|  | @ -43,7 +47,16 @@ type StepDef struct { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Suite is an interface which allows various contexts | // Suite is an interface which allows various contexts | ||||||
| // to register step definitions and event handlers | // 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. | ||||||
|  | // | ||||||
|  | // 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 { | type Suite interface { | ||||||
| 	Step(expr Regexp, h StepHandler) | 	Step(expr Regexp, h StepHandler) | ||||||
| 	// suite events | 	// suite events | ||||||
|  | @ -80,17 +93,16 @@ func New() *suite { | ||||||
| 
 | 
 | ||||||
| // Step allows to register a StepHandler in Godog | // Step allows to register a StepHandler in Godog | ||||||
| // feature suite, the handler will be applied to all | // feature suite, the handler will be applied to all | ||||||
| // steps matching the given regexp expr | // 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 handler does not satisfy StepHandler interface |  | ||||||
| // | // | ||||||
| // Note that if there are two handlers which may match | // Note that if there are two handlers which may match | ||||||
| // the same step, then the only first matched handler | // the same step, then the only first matched handler | ||||||
| // will be applied | // will be applied. | ||||||
| // | // | ||||||
| // If none of the StepHandlers are matched, then a pending | // If none of the StepHandlers are matched, then | ||||||
| // step error will be raised. | // ErrUndefined error will be returned. | ||||||
| func (s *suite) Step(expr Regexp, h StepHandler) { | func (s *suite) Step(expr Regexp, h StepHandler) { | ||||||
| 	var regex *regexp.Regexp | 	var regex *regexp.Regexp | ||||||
| 
 | 
 | ||||||
|  | @ -112,13 +124,20 @@ func (s *suite) Step(expr Regexp, h StepHandler) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // BeforeSuite registers a function or method | // BeforeSuite registers a function or method | ||||||
| // to be run once before suite runner | // to be run once before suite runner. | ||||||
|  | // | ||||||
|  | // 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) | 	s.beforeSuiteHandlers = append(s.beforeSuiteHandlers, f) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // BeforeScenario registers a function or method | // BeforeScenario registers a function or method | ||||||
| // to be run before every scenario | // to be run before every scenario. | ||||||
|  | // | ||||||
|  | // 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(*gherkin.Scenario)) { | func (s *suite) BeforeScenario(f func(*gherkin.Scenario)) { | ||||||
| 	s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, f) | 	s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, f) | ||||||
| } | } | ||||||
|  | @ -131,6 +150,13 @@ func (s *suite) BeforeStep(f func(*gherkin.Step)) { | ||||||
| 
 | 
 | ||||||
| // AfterStep registers an function or method | // AfterStep registers an function or method | ||||||
| // to be run after every scenario | // to be run after every scenario | ||||||
|  | // | ||||||
|  | // It may be convenient to return a different kind of error | ||||||
|  | // in order to print more state details which may help | ||||||
|  | // in case of step failure | ||||||
|  | // | ||||||
|  | // 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) | 	s.afterStepHandlers = append(s.afterStepHandlers, f) | ||||||
| } | } | ||||||
|  | @ -147,7 +173,7 @@ func (s *suite) AfterSuite(f func()) { | ||||||
| 	s.afterSuiteHandlers = append(s.afterSuiteHandlers, f) | 	s.afterSuiteHandlers = append(s.afterSuiteHandlers, f) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Run - runs a godog feature suite | // Run starts the Godog feature suite | ||||||
| func (s *suite) Run() { | func (s *suite) Run() { | ||||||
| 	var err error | 	var err error | ||||||
| 	if !flag.Parsed() { | 	if !flag.Parsed() { | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								utils.go
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								utils.go
									
										
									
									
									
								
							|  | @ -6,10 +6,12 @@ import ( | ||||||
| 	"strings" | 	"strings" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // a color code type | ||||||
| type color int | type color int | ||||||
| 
 | 
 | ||||||
| const ansiEscape = "\x1b" | const ansiEscape = "\x1b" | ||||||
| 
 | 
 | ||||||
|  | // some ansi colors | ||||||
| const ( | const ( | ||||||
| 	black color = iota + 30 | 	black color = iota + 30 | ||||||
| 	red | 	red | ||||||
|  |  | ||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 gedi
						gedi