instead of Suite interface expose Suite struct

* 570d70a update examples regarding Suite interface removal, closes #11
Этот коммит содержится в:
gedi 2015-07-03 11:39:46 +03:00
родитель 46f5218d36
коммит ca36316b7a
19 изменённых файлов: 142 добавлений и 234 удалений

Просмотреть файл

@ -25,11 +25,15 @@ not changed most likely. I'll try to respect **backward compatibility** as much
### Example ### 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 Imagine we have a **godog cart** to serve godogs for dinner. At first, we describe our feature
in plain text: in plain text:
``` gherkin ``` gherkin
# file: /tmp/godog/godog.feature # file: examples/godogs/godog.feature
Feature: eat godogs Feature: eat godogs
In order to be happy In order to be happy
As a hungry gopher As a hungry gopher
@ -44,22 +48,27 @@ Feature: eat godogs
As a developer, your work is done as soon as youve made the program behave as As a developer, your work is done as soon as youve made the program behave as
described in the Scenario. 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: You should see that the steps are undefined:
![Screenshot](https://raw.github.com/DATA-DOG/godog/master/screenshots/undefined.png) ![Screenshot](https://raw.github.com/DATA-DOG/godog/master/screenshots/undefined.png)
It gives you undefined step snippets to implement in your test context. You may copy these snippets 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 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. **ErrPending** to **nil** and the scenario will pass successfully.
Since we need a working implementation, we may start by implementing what is necessary. Since we need a working implementation, we may start by implementing only what is necessary.
We only need a number of **godogs** for now.
#### Step 3
We only need a number of **godogs** for now. Lets define steps.
``` go ``` go
/* file: /tmp/godog/godog.go */ /* file: examples/godogs/godog.go */
package main package main
var Godogs int var Godogs int
@ -67,10 +76,12 @@ var Godogs int
func main() { /* usual main func */ } func main() { /* usual main func */ }
``` ```
#### Step 4
Now lets finish our step implementations in order to test our feature requirements: Now lets finish our step implementations in order to test our feature requirements:
``` go ``` go
/* file: /tmp/godog/godog_test.go */ /* file: examples/godogs/godog_test.go */
package main package main
import ( import (
@ -99,7 +110,7 @@ func thereShouldBeRemaining(remaining int) error {
return nil return nil
} }
func featureContext(s godog.Suite) { func featureContext(s *godog.Suite) {
s.Step(`^there are (\d+) godogs$`, thereAreGodogs) s.Step(`^there are (\d+) godogs$`, thereAreGodogs)
s.Step(`^I eat (\d+)$`, iEat) s.Step(`^I eat (\d+)$`, iEat)
s.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) s.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
@ -126,8 +137,15 @@ See `godog -h` for general command options.
See implementation examples: See implementation examples:
- [rest API server](https://github.com/DATA-DOG/godog/tree/master/examples/api) implementation and tests - [rest API server](https://github.com/DATA-DOG/godog/tree/master/examples/api)
- [ls command](https://github.com/DATA-DOG/godog/tree/master/examples/ls) implementation and tests - [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 ### FAQ

Просмотреть файл

@ -82,7 +82,7 @@ func (b *builder) parseFile(path string) error {
b.Internal = true b.Internal = true
} }
b.deleteMainFunc(f) b.deleteMainFunc(f)
b.registerSteps(f) b.registerContexts(f)
b.deleteImports(f) b.deleteImports(f)
b.files[path] = f b.files[path] = f
@ -122,22 +122,25 @@ func (b *builder) deleteMainFunc(f *ast.File) {
f.Decls = decls f.Decls = decls
} }
func (b *builder) registerSteps(f *ast.File) { func (b *builder) registerContexts(f *ast.File) {
for _, d := range f.Decls { for _, d := range f.Decls {
switch fun := d.(type) { switch fun := d.(type) {
case *ast.FuncDecl: case *ast.FuncDecl:
for _, param := range fun.Type.Params.List { for _, param := range fun.Type.Params.List {
switch expr := param.Type.(type) { switch expr := param.Type.(type) {
case *ast.SelectorExpr: case *ast.StarExpr:
switch x := expr.X.(type) { switch x := expr.X.(type) {
case *ast.Ident: case *ast.Ident:
if x.Name == "godog" && expr.Sel.Name == "Suite" { if x.Name == "Suite" {
b.Contexts = append(b.Contexts, fun.Name.Name) b.Contexts = append(b.Contexts, fun.Name.Name)
} }
} case *ast.SelectorExpr:
case *ast.Ident: switch t := x.X.(type) {
if expr.Name == "Suite" { case *ast.Ident:
b.Contexts = append(b.Contexts, fun.Name.Name) 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 return godog.ErrPending
} }
func featureContext(s godog.Suite) { func featureContext(s *godog.Suite) {
api := &apiFeature{} api := &apiFeature{}
s.Step(`^I send "([^"]*)" request to "([^"]*)"$`, api.iSendrequestTo) s.Step(`^I send "([^"]*)" request to "([^"]*)"$`, api.iSendrequestTo)
s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe)
@ -158,7 +158,7 @@ func (a *apiFeature) theResponseShouldMatchJSON(body *gherkin.DocString) (err er
return return
} }
func featureContext(s godog.Suite) { func featureContext(s *godog.Suite) {
api := &apiFeature{} api := &apiFeature{}
s.BeforeScenario(api.resetResponse) s.BeforeScenario(api.resetResponse)

Просмотреть файл

@ -67,7 +67,7 @@ func (a *apiFeature) theResponseShouldMatchJSON(body *gherkin.DocString) (err er
return return
} }
func featureContext(s godog.Suite) { func featureContext(s *godog.Suite) {
api := &apiFeature{} api := &apiFeature{}
s.BeforeScenario(api.resetResponse) s.BeforeScenario(api.resetResponse)

Двоичные данные
examples/api/screenshots/undefined.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 151 КиБ

После

Ширина:  |  Высота:  |  Размер: 148 КиБ

Просмотреть файл

@ -117,7 +117,7 @@ func (a *apiFeature) thereAreUsers(users *gherkin.DataTable) error {
return nil return nil
} }
func featureContext(s godog.Suite) { func featureContext(s *godog.Suite) {
api := &apiFeature{} api := &apiFeature{}
s.BeforeScenario(api.resetResponse) s.BeforeScenario(api.resetResponse)

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 Обычный файл
Просмотреть файл

@ -0,0 +1,5 @@
package main
var Godogs int
func main() { /* usual main func */ }

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)
}

Просмотреть файл

@ -5,7 +5,9 @@ import (
"fmt" "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 := flag.NewFlagSet("godog", flag.ExitOnError)
set.StringVar(&s.format, "format", "pretty", "") set.StringVar(&s.format, "format", "pretty", "")
set.StringVar(&s.format, "f", "pretty", "") set.StringVar(&s.format, "f", "pretty", "")

2
fmt.go
Просмотреть файл

@ -30,7 +30,7 @@ var undefinedSnippetsTpl = template.Must(template.New("snippets").Funcs(snippetH
return godog.ErrPending return godog.ErrPending
} }
{{end}}func featureContext(s godog.Suite) { {{ range . }} {{end}}func featureContext(s *godog.Suite) { {{ range . }}
s.Step({{ backticked .Expr }}, {{ .Method }}){{end}} s.Step({{ backticked .Expr }}, {{ .Method }}){{end}}
} }
`)) `))

Двоичные данные
screenshots/undefined.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 96 КиБ

После

Ширина:  |  Высота:  |  Размер: 109 КиБ

109
suite.go
Просмотреть файл

@ -28,52 +28,18 @@ var ErrUndefined = fmt.Errorf("step is undefined")
// step implementation is pending // step implementation is pending
var ErrPending = fmt.Errorf("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. // to register steps and event handlers.
// //
// When running a test suite, this interface is passed // When running a test suite, the instance of Suite
// to all functions (contexts), which have it as a // is passed to all functions (contexts), which
// first and only argument. // have it as a first and only argument.
// //
// Note that all event hooks does not catch panic errors // Note that all event hooks does not catch panic errors
// in order to have a trace information. Only step // in order to have a trace information. Only step
// executions are catching panic error since it may // executions are catching panic error since it may
// be a context specific error. // be a context specific error.
type Suite interface { type Suite struct {
// 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 {
steps []*StepDef steps []*StepDef
features []*feature features []*feature
fmt Formatter fmt Formatter
@ -98,24 +64,27 @@ type suite struct {
} }
// New initializes a Suite. The instance is passed around // New initializes a Suite. The instance is passed around
// to all context initialization functions from *_test.go files // to all context initialization functions from *_test.go files.
func New() Suite { func New() *Suite {
return &suite{} return &Suite{}
} }
// Step allows to register a StepHandler in Godog // Step allows to register a *StepDef in Godog
// feature suite, the handler will be applied to all // feature suite, the definition will be applied
// steps matching the given Regexp expr // 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 // Note that if there are two definitions which may match
// the same step, then the only first matched handler // the same step, then only the first matched handler
// will be applied. // will be applied.
// //
// If none of the StepHandlers are matched, then // If none of the *StepDef is matched, then
// ErrUndefined error will be returned. // ErrUndefined error will be returned when
func (s *suite) Step(expr interface{}, stepFunc interface{}) { // running steps.
func (s *Suite) Step(expr interface{}, stepFunc interface{}) {
var regex *regexp.Regexp var regex *regexp.Regexp
switch t := expr.(type) { 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. // Use it to prepare the test suite for a spin.
// Connect and prepare database for instance... // 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)
} }
@ -165,13 +134,13 @@ func (s *suite) BeforeSuite(f func()) {
// It is a good practice to restore the default state // It is a good practice to restore the default state
// before every scenario so it would be isolated from // before every scenario so it would be isolated from
// any kind of state. // any kind of state.
func (s *suite) BeforeScenario(f func(interface{})) { func (s *Suite) BeforeScenario(f func(interface{})) {
s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, f) s.beforeScenarioHandlers = append(s.beforeScenarioHandlers, f)
} }
// BeforeStep registers a function or method // BeforeStep registers a function or method
// to be run before every scenario // 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) 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 // In some cases, for example when running a headless
// browser, to take a screenshot after failure. // 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)
} }
@ -193,18 +162,18 @@ func (s *suite) AfterStep(f func(*gherkin.Step, error)) {
// //
// The interface argument may be *gherkin.Scenario // The interface argument may be *gherkin.Scenario
// or *gherkin.ScenarioOutline // 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) s.afterScenarioHandlers = append(s.afterScenarioHandlers, f)
} }
// AfterSuite registers a function or method // AfterSuite registers a function or method
// to be run once after suite runner // 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) s.afterSuiteHandlers = append(s.afterSuiteHandlers, f)
} }
// Run starts the Godog feature suite // Run starts the Godog feature suite
func (s *suite) Run() { func (s *Suite) Run() {
flagSet := flags(s) flagSet := flags(s)
fatal(flagSet.Parse(os.Args[1:])) 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 // run before suite handlers
for _, f := range s.beforeSuiteHandlers { for _, f := range s.beforeSuiteHandlers {
f() f()
@ -269,7 +238,7 @@ func (s *suite) run() {
s.fmt.Summary() s.fmt.Summary()
} }
func (s *suite) matchStep(step *gherkin.Step) *StepDef { func (s *Suite) matchStep(step *gherkin.Step) *StepDef {
for _, h := range s.steps { for _, h := range s.steps {
if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 { if m := h.Expr.FindStringSubmatch(step.Text); len(m) > 0 {
var args []interface{} var args []interface{}
@ -286,7 +255,7 @@ func (s *suite) matchStep(step *gherkin.Step) *StepDef {
return nil 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) match := s.matchStep(step)
if match == nil { if match == nil {
s.fmt.Undefined(step) s.fmt.Undefined(step)
@ -330,7 +299,7 @@ func (s *suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
return 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 err = prevErr
for _, step := range steps { for _, step := range steps {
stepErr := s.runStep(step, err) stepErr := s.runStep(step, err)
@ -347,13 +316,13 @@ func (s *suite) runSteps(steps []*gherkin.Step, prevErr error) (err error) {
return return
} }
func (s *suite) skipSteps(steps []*gherkin.Step) { func (s *Suite) skipSteps(steps []*gherkin.Step) {
for _, step := range steps { for _, step := range steps {
s.fmt.Skipped(step) 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) s.fmt.Node(outline)
for _, example := range outline.Examples { for _, example := range outline.Examples {
@ -403,7 +372,7 @@ func (s *suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Backgrou
return return
} }
func (s *suite) runFeature(f *feature) { func (s *Suite) runFeature(f *feature) {
s.fmt.Feature(f.Feature, f.Path) s.fmt.Feature(f.Feature, f.Path)
for _, scenario := range f.ScenarioDefinitions { for _, scenario := range f.ScenarioDefinitions {
var err error 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 // run before scenario handlers
for _, f := range s.beforeScenarioHandlers { for _, f := range s.beforeScenarioHandlers {
f(scenario) f(scenario)
@ -448,7 +417,7 @@ func (s *suite) runScenario(scenario *gherkin.Scenario, b *gherkin.Background) (
return return
} }
func (s *suite) printStepDefinitions() { func (s *Suite) printStepDefinitions() {
var longest int var longest int
for _, def := range s.steps { for _, def := range s.steps {
if longest < len(def.Expr.String()) { 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 { for _, pat := range s.paths {
// check if line number is specified // check if line number is specified
parts := strings.Split(pat, ":") parts := strings.Split(pat, ":")
@ -525,7 +494,7 @@ func (s *suite) parseFeatures() (err error) {
return return
} }
func (s *suite) applyTagFilter(ft *gherkin.Feature) { func (s *Suite) applyTagFilter(ft *gherkin.Feature) {
if len(s.tags) == 0 { if len(s.tags) == 0 {
return 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 // 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 ok = true
for _, andTags := range strings.Split(s.tags, "&&") { for _, andTags := range strings.Split(s.tags, "&&") {
var okComma bool var okComma bool

Просмотреть файл

@ -8,7 +8,7 @@ import (
"github.com/cucumber/gherkin-go" "github.com/cucumber/gherkin-go"
) )
func SuiteContext(s Suite) { func SuiteContext(s *Suite) {
c := &suiteContext{} c := &suiteContext{}
s.BeforeScenario(c.ResetBeforeEachScenario) s.BeforeScenario(c.ResetBeforeEachScenario)
@ -50,7 +50,7 @@ type firedEvent struct {
} }
type suiteContext struct { type suiteContext struct {
testedSuite *suite testedSuite *Suite
events []*firedEvent events []*firedEvent
fmt *testFormatter fmt *testFormatter
} }
@ -58,7 +58,7 @@ type suiteContext struct {
func (s *suiteContext) ResetBeforeEachScenario(interface{}) { func (s *suiteContext) ResetBeforeEachScenario(interface{}) {
// reset whole suite with the state // reset whole suite with the state
s.fmt = &testFormatter{} s.fmt = &testFormatter{}
s.testedSuite = &suite{fmt: s.fmt} s.testedSuite = &Suite{fmt: s.fmt}
// our tested suite will have the same context registered // our tested suite will have the same context registered
SuiteContext(s.testedSuite) SuiteContext(s.testedSuite)
// reset all fired events // reset all fired events

Просмотреть файл

@ -5,14 +5,14 @@ import (
) )
func assertNotMatchesTagFilter(tags []string, filter string, t *testing.T) { func assertNotMatchesTagFilter(tags []string, filter string, t *testing.T) {
s := &suite{tags: filter} s := &Suite{tags: filter}
if s.matchesTags(tags) { if s.matchesTags(tags) {
t.Errorf(`expected tags: %v not to match tag filter "%s", but it did`, tags, filter) 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) { func assertMatchesTagFilter(tags []string, filter string, t *testing.T) {
s := &suite{tags: filter} s := &Suite{tags: filter}
if !s.matchesTags(tags) { if !s.matchesTags(tags) {
t.Errorf(`expected tags: %v to match tag filter "%s", but it did not`, tags, filter) t.Errorf(`expected tags: %v to match tag filter "%s", but it did not`, tags, filter)
} }