Этот коммит содержится в:
gedi 2015-06-15 14:42:40 +03:00
родитель b69fa26b8b
коммит 156613f767
5 изменённых файлов: 71 добавлений и 77 удалений

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

@ -2,6 +2,7 @@ package godog
import ( import (
"fmt" "fmt"
"math"
"strings" "strings"
"github.com/DATA-DOG/godog/gherkin" "github.com/DATA-DOG/godog/gherkin"
@ -14,8 +15,8 @@ func init() {
// Formatter is an interface for feature runner output // Formatter is an interface for feature runner output
type Formatter interface { type Formatter interface {
Node(interface{}) Node(interface{})
Failed(*gherkin.Step, error) Failed(*gherkin.Step, *stepMatchHandler, error)
Passed(*gherkin.Step) Passed(*gherkin.Step, *stepMatchHandler)
Skipped(*gherkin.Step) Skipped(*gherkin.Step)
Pending(*gherkin.Step) Pending(*gherkin.Step)
} }
@ -65,14 +66,48 @@ func (f *pretty) Node(node interface{}) {
f.background = t f.background = t
fmt.Println("\n" + bcl("Background:", white)) fmt.Println("\n" + bcl("Background:", white))
case *gherkin.Scenario: case *gherkin.Scenario:
f.scenario = t
fmt.Println("\n"+strings.Repeat(" ", t.Token.Indent)+bcl("Scenario: ", white)+t.Title, f.line(t.Token)) fmt.Println("\n"+strings.Repeat(" ", t.Token.Indent)+bcl("Scenario: ", white)+t.Title, f.line(t.Token))
} }
} }
func (f *pretty) Passed(step *gherkin.Step) { func (f *pretty) printMatchedStep(step *gherkin.Step, match *stepMatchHandler, c color) {
if f.canPrintStep(step) { if !f.canPrintStep(step) {
fmt.Println(cl(step.Token.Text, green)) return
} }
var text string
if m := (match.expr.FindStringSubmatchIndex(step.Text))[2:]; len(m) > 0 {
var pos, i int
for pos, i = 0, 0; i < len(m); i++ {
if math.Mod(float64(i), 2) == 0 {
text += cl(step.Text[pos:m[i]], c)
} else {
text += bcl(step.Text[pos:m[i]], c)
}
pos = m[i]
}
text += cl(step.Text[pos:len(step.Text)], c)
} else {
text = cl(step.Text, c)
}
switch step.Token.Type {
case gherkin.GIVEN:
text = cl("Given", c) + " " + text
case gherkin.WHEN:
text = cl("When", c) + " " + text
case gherkin.THEN:
text = cl("Then", c) + " " + text
case gherkin.AND:
text = cl("And", c) + " " + text
case gherkin.BUT:
text = cl("But", c) + " " + text
}
fmt.Println(strings.Repeat(" ", step.Token.Indent) + text)
}
func (f *pretty) Passed(step *gherkin.Step, match *stepMatchHandler) {
f.printMatchedStep(step, match, green)
} }
func (f *pretty) Skipped(step *gherkin.Step) { func (f *pretty) Skipped(step *gherkin.Step) {
@ -87,8 +122,6 @@ func (f *pretty) Pending(step *gherkin.Step) {
} }
} }
func (f *pretty) Failed(step *gherkin.Step, err error) { func (f *pretty) Failed(step *gherkin.Step, match *stepMatchHandler, err error) {
if f.canPrintStep(step) { f.printMatchedStep(step, match, red)
fmt.Println(cl(step.Token.Text, red))
}
} }

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

@ -111,20 +111,11 @@ type Background struct {
Steps []*Step Steps []*Step
} }
// StepType is a general type of step
type StepType string
const (
Given StepType = "Given"
When StepType = "When"
Then StepType = "Then"
)
// 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 StepType Type string
PyString *PyString PyString *PyString
Table *Table Table *Table
} }
@ -309,20 +300,6 @@ func (p *parser) parseScenario() (s *Scenario, err error) {
func (p *parser) parseSteps() (steps []*Step, err error) { func (p *parser) parseSteps() (steps []*Step, err error) {
for tok := p.peek(); tok.OfType(allSteps...); tok = p.peek() { for tok := p.peek(); tok.OfType(allSteps...); tok = p.peek() {
step := &Step{Text: tok.Value, Token: tok} step := &Step{Text: tok.Value, Token: tok}
switch tok.Type {
case GIVEN:
step.Type = Given
case WHEN:
step.Type = When
case THEN:
step.Type = Then
case AND, BUT:
if len(steps) > 0 {
step.Type = steps[len(steps)-1].Type
} else {
step.Type = Given
}
}
p.next() // have read a peeked step p.next() // have read a peeked step
if step.Text[len(step.Text)-1] == ':' { if step.Text[len(step.Text)-1] == ':' {

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

@ -44,12 +44,6 @@ var testStepSamples = map[string]string{
Then I expect the result`, Then I expect the result`,
} }
func (s *Step) assertType(typ StepType, t *testing.T) {
if s.Type != typ {
t.Fatalf("expected step '%s' type to be '%s', but got '%s'", s.Text, typ, s.Type)
}
}
func (s *Step) assertText(text string, t *testing.T) { func (s *Step) assertText(text string, t *testing.T) {
if s.Text != text { if s.Text != text {
t.Fatalf("expected step text to be '%s', but got '%s'", text, s.Text) t.Fatalf("expected step text to be '%s', but got '%s'", text, s.Text)
@ -102,7 +96,6 @@ func Test_parse_basic_given_step(t *testing.T) {
t.Fatalf("expected one step to be parsed") t.Fatalf("expected one step to be parsed")
} }
steps[0].assertType(Given, t)
steps[0].assertText("I'm a step", t) steps[0].assertText("I'm a step", t)
p.next() // step over to eof p.next() // step over to eof
@ -126,7 +119,6 @@ func Test_parse_step_with_comment(t *testing.T) {
t.Fatalf("expected one step to be parsed") t.Fatalf("expected one step to be parsed")
} }
steps[0].assertType(Given, t)
steps[0].assertText("I'm an admin", t) steps[0].assertText("I'm an admin", t)
steps[0].assertComment("sets admin permissions", t) steps[0].assertComment("sets admin permissions", t)
@ -151,7 +143,6 @@ func Test_parse_hash_table_given_step(t *testing.T) {
t.Fatalf("expected one step to be parsed") t.Fatalf("expected one step to be parsed")
} }
steps[0].assertType(Given, t)
steps[0].assertText("there are users:", t) steps[0].assertText("there are users:", t)
steps[0].assertTableRow(t, 0, "name", "John Doe") steps[0].assertTableRow(t, 0, "name", "John Doe")
@ -177,7 +168,6 @@ func Test_parse_table_given_step(t *testing.T) {
t.Fatalf("expected one step to be parsed") t.Fatalf("expected one step to be parsed")
} }
steps[0].assertType(Given, t)
steps[0].assertText("there are users:", t) steps[0].assertText("there are users:", t)
steps[0].assertTableRow(t, 0, "name", "lastname") steps[0].assertTableRow(t, 0, "name", "lastname")
steps[0].assertTableRow(t, 1, "John", "Doe") steps[0].assertTableRow(t, 1, "John", "Doe")
@ -207,7 +197,6 @@ func Test_parse_pystring_step(t *testing.T) {
t.Fatalf("expected one step to be parsed") t.Fatalf("expected one step to be parsed")
} }
steps[0].assertType(Then, t)
steps[0].assertText("there should be text:", t) steps[0].assertText("there should be text:", t)
steps[0].assertPyString(strings.Join([]string{ steps[0].assertPyString(strings.Join([]string{
indent(4, "Some text"), indent(4, "Some text"),
@ -239,7 +228,6 @@ func Test_parse_empty_pystring_step(t *testing.T) {
t.Fatalf("expected one step to be parsed") t.Fatalf("expected one step to be parsed")
} }
steps[0].assertType(When, t)
steps[0].assertText("I do request with body:", t) steps[0].assertText("I do request with body:", t)
steps[0].assertPyString("", t) steps[0].assertPyString("", t)
@ -285,13 +273,9 @@ func Test_parse_step_group(t *testing.T) {
t.Fatalf("expected four steps to be parsed, but got: %d", len(steps)) t.Fatalf("expected four steps to be parsed, but got: %d", len(steps))
} }
steps[0].assertType(Given, t)
steps[0].assertText("there are conditions", t) steps[0].assertText("there are conditions", t)
steps[1].assertType(Given, t)
steps[1].assertText("there are more conditions", t) steps[1].assertText("there are more conditions", t)
steps[2].assertType(When, t)
steps[2].assertText("I do something", t) steps[2].assertText("I do something", t)
steps[3].assertType(Then, t)
steps[3].assertText("something should happen", t) steps[3].assertText("something should happen", t)
p.next() // step over to eof p.next() // step over to eof
@ -318,13 +302,9 @@ func Test_parse_another_step_group(t *testing.T) {
t.Fatalf("expected four steps to be parsed, but got: %d", len(steps)) t.Fatalf("expected four steps to be parsed, but got: %d", len(steps))
} }
steps[0].assertType(Given, t)
steps[0].assertText(`an admin user "John Doe"`, t) steps[0].assertText(`an admin user "John Doe"`, t)
steps[1].assertType(Given, t)
steps[1].assertText(`user "John Doe" belongs to user group "editors"`, t) steps[1].assertText(`user "John Doe" belongs to user group "editors"`, t)
steps[2].assertType(When, t)
steps[2].assertText("I do something", t) steps[2].assertText("I do something", t)
steps[3].assertType(Then, t)
steps[3].assertText("I expect the result", t) steps[3].assertText("I expect the result", t)
p.next() // step over to eof p.next() // step over to eof

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

@ -66,6 +66,11 @@ func (f StepHandlerFunc) HandleStep(args ...Arg) error {
var errPending = fmt.Errorf("pending step") var errPending = fmt.Errorf("pending step")
type stepMatchHandler struct {
handler StepHandler
expr *regexp.Regexp
}
// 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 step definitions and event handlers
type Suite interface { type Suite interface {
@ -73,7 +78,7 @@ type Suite interface {
} }
type suite struct { type suite struct {
steps map[*regexp.Regexp]StepHandler steps []*stepMatchHandler
features []*gherkin.Feature features []*gherkin.Feature
fmt Formatter fmt Formatter
} }
@ -82,9 +87,7 @@ type suite struct {
// interface. The instance is passed around to all // interface. The instance is passed around to all
// context initialization functions from *_test.go files // context initialization functions from *_test.go files
func New() *suite { func New() *suite {
return &suite{ return &suite{}
steps: make(map[*regexp.Regexp]StepHandler),
}
} }
// Step allows to register a StepHandler in Godog // Step allows to register a StepHandler in Godog
@ -97,8 +100,11 @@ func New() *suite {
// //
// If none of the StepHandlers are matched, then a pending // If none of the StepHandlers are matched, then a pending
// step error will be raised. // step error will be raised.
func (s *suite) Step(exp *regexp.Regexp, h StepHandler) { func (s *suite) Step(expr *regexp.Regexp, h StepHandler) {
s.steps[exp] = h s.steps = append(s.steps, &stepMatchHandler{
handler: h,
expr: expr,
})
} }
// Run - runs a godog feature suite // Run - runs a godog feature suite
@ -122,33 +128,33 @@ func (s *suite) Run() {
} }
func (s *suite) runStep(step *gherkin.Step) (err error) { func (s *suite) runStep(step *gherkin.Step) (err error) {
defer func() { var match *stepMatchHandler
if e := recover(); e != nil {
err = e.(error)
s.fmt.Failed(step, err)
}
}()
var handler StepHandler
var args []Arg var args []Arg
for r, h := range s.steps { for _, h := range s.steps {
if m := r.FindStringSubmatch(step.Text); len(m) > 0 { if m := h.expr.FindStringSubmatch(step.Text); len(m) > 0 {
handler = h match = h
for _, a := range m[1:] { for _, a := range m[1:] {
args = append(args, Arg(a)) args = append(args, Arg(a))
} }
break break
} }
} }
if handler == nil { if match == nil {
s.fmt.Pending(step) s.fmt.Pending(step)
return errPending return errPending
} }
if err = handler.HandleStep(args...); err != nil { defer func() {
s.fmt.Failed(step, err) if e := recover(); e != nil {
err = e.(error)
s.fmt.Failed(step, match, err)
}
}()
if err = match.handler.HandleStep(args...); err != nil {
s.fmt.Failed(step, match, err)
} else { } else {
s.fmt.Passed(step) s.fmt.Passed(step, match)
} }
return return
} }

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

@ -28,9 +28,7 @@ func (s *suiteFeature) numParsed(args ...Arg) (err error) {
func SuiteContext(g Suite) { func SuiteContext(g Suite) {
s := &suiteFeature{ s := &suiteFeature{
suite: suite{ suite: suite{},
steps: make(map[*regexp.Regexp]StepHandler),
},
} }
g.Step( g.Step(