Этот коммит содержится в:
gedi 2015-06-14 00:32:47 +03:00
родитель fa9419c2d3
коммит 3a2a357bd0
7 изменённых файлов: 96 добавлений и 57 удалений

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

@ -4,6 +4,8 @@ import "fmt"
type color int type color int
const ansiEscape = "\x1b"
const ( const (
black color = iota + 30 black color = iota + 30
red red
@ -16,5 +18,9 @@ const (
) )
func cl(s interface{}, c color) string { func cl(s interface{}, c color) string {
return fmt.Sprintf("\033[%dm%v\033[0m", c, s) return fmt.Sprintf("%s[%dm%v%s[0m", ansiEscape, c, s, ansiEscape)
}
func bcl(s interface{}, c color) string {
return fmt.Sprintf("%s[1;%dm%v%s[0m", ansiEscape, c, s, ansiEscape)
} }

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

@ -46,6 +46,10 @@ func (c config) features() (lst []*gherkin.Feature, err error) {
}) })
} }
func (c config) formatter() formatter {
return &pretty{}
}
func fatal(err error) { func fatal(err error) {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

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

@ -3,7 +3,7 @@ Feature: godog bdd suite
As a suite As a suite
I need to be able to register and run features I need to be able to register and run features
Scenario: Scenario: parses all features in path
Given a feature path "features" Given a feature path "features"
When I parse features When I parse features
Then I should have 1 feature file Then I should have 1 feature file

27
formatter.go Обычный файл
Просмотреть файл

@ -0,0 +1,27 @@
package godog
import (
"fmt"
"github.com/DATA-DOG/godog/gherkin"
)
type formatter interface {
node(interface{})
}
type pretty struct{}
func (f *pretty) node(node interface{}) {
switch t := node.(type) {
case *gherkin.Feature:
fmt.Println(bcl("Feature: ", white) + t.Title)
fmt.Println(t.Description + "\n")
case *gherkin.Background:
fmt.Println(bcl("Background:", white))
case *gherkin.Scenario:
fmt.Println(bcl("Scenario: ", white) + t.Title)
case *gherkin.Step:
fmt.Println(bcl(t.Token.Text, green))
}
}

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

@ -77,6 +77,7 @@ type Tag string
// Tags is an array of tags // Tags is an array of tags
type Tags []Tag type Tags []Tag
// Has checks whether the tag list has a tag
func (t Tags) Has(tag Tag) bool { func (t Tags) Has(tag Tag) bool {
for _, tg := range t { for _, tg := range t {
if tg == tag { if tg == tag {
@ -97,17 +98,17 @@ func (t Tags) Has(tag Tag) bool {
// be used to filter out or run specific // be used to filter out or run specific
// initialization tasks // initialization tasks
type Scenario struct { type Scenario struct {
*Token
Title string Title string
Steps []*Step Steps []*Step
Tags Tags Tags Tags
Examples *Table Examples *Table
Comment string
} }
// Background steps are run before every scenario // Background steps are run before every scenario
type Background struct { type Background struct {
Steps []*Step *Token
Comment string Steps []*Step
} }
// StepType is a general type of step // StepType is a general type of step
@ -121,8 +122,8 @@ const (
// Step describes a Scenario or Background step // Step describes a Scenario or Background step
type Step struct { type Step struct {
*Token
Text string Text string
Comment string
Type StepType Type StepType
PyString *PyString PyString *PyString
Table *Table Table *Table
@ -130,6 +131,7 @@ type Step struct {
// Feature describes the whole feature // Feature describes the whole feature
type Feature struct { type Feature struct {
*Token
Path string Path string
Tags Tags Tags Tags
Description string Description string
@ -137,16 +139,17 @@ type Feature struct {
Background *Background Background *Background
Scenarios []*Scenario Scenarios []*Scenario
AST *AST AST *AST
Comment string
} }
// PyString is a multiline text object used with step definition // PyString is a multiline text object used with step definition
type PyString struct { type PyString struct {
*Token
Body string Body string
} }
// Table is a row group object used with step definition // Table is a row group object used with step definition
type Table struct { type Table struct {
*Token
rows [][]string rows [][]string
} }
@ -229,11 +232,11 @@ func (p *parser) parseFeature() (ft *Feature, err error) {
return ft, p.err("expected a file to begin with a feature definition, but got '"+tok.Type.String()+"' instead", tok.Line) return ft, p.err("expected a file to begin with a feature definition, but got '"+tok.Type.String()+"' instead", tok.Line)
} }
ft.Title = tok.Value ft.Title = tok.Value
ft.Comment = tok.Comment ft.Token = tok
var desc []string var desc []string
for ; p.peek().Type == TEXT; tok = p.next() { for ; p.peek().Type == TEXT; tok = p.next() {
desc = append(desc, tok.Value) desc = append(desc, p.peek().Text)
} }
ft.Description = strings.Join(desc, "\n") ft.Description = strings.Join(desc, "\n")
@ -244,7 +247,7 @@ func (p *parser) parseFeature() (ft *Feature, err error) {
return ft, p.err("there can only be a single background section, but found another", tok.Line) return ft, p.err("there can only be a single background section, but found another", tok.Line)
} }
ft.Background = &Background{Comment: tok.Comment} ft.Background = &Background{Token: tok}
p.next() // jump to background steps p.next() // jump to background steps
if ft.Background.Steps, err = p.parseSteps(); err != nil { if ft.Background.Steps, err = p.parseSteps(); err != nil {
return ft, err return ft, err
@ -283,7 +286,7 @@ func (p *parser) parseFeature() (ft *Feature, err error) {
func (p *parser) parseScenario() (s *Scenario, err error) { func (p *parser) parseScenario() (s *Scenario, err error) {
tok := p.next() tok := p.next()
s = &Scenario{Title: tok.Value, Comment: tok.Comment} s = &Scenario{Title: tok.Value, Token: tok}
if s.Steps, err = p.parseSteps(); err != nil { if s.Steps, err = p.parseSteps(); err != nil {
return s, err return s, err
} }
@ -305,7 +308,7 @@ 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, Comment: tok.Comment} step := &Step{Text: tok.Value, Token: tok}
switch tok.Type { switch tok.Type {
case GIVEN: case GIVEN:
step.Type = Given step.Type = Given

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

@ -66,8 +66,8 @@ func (s *Step) assertPyString(text string, t *testing.T) {
} }
func (s *Step) assertComment(comment string, t *testing.T) { func (s *Step) assertComment(comment string, t *testing.T) {
if s.Comment != comment { if s.Token.Comment != comment {
t.Fatalf("expected step '%s' comment to be '%s', but got '%s'", s.Text, comment, s.Comment) t.Fatalf("expected step '%s' comment to be '%s', but got '%s'", s.Text, comment, s.Token.Comment)
} }
} }

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

@ -73,6 +73,7 @@ type Suite interface {
type suite struct { type suite struct {
steps map[*regexp.Regexp]StepHandler steps map[*regexp.Regexp]StepHandler
features []*gherkin.Feature features []*gherkin.Feature
fmt formatter
} }
// New initializes a suite which supports the Suite // New initializes a suite which supports the Suite
@ -107,6 +108,7 @@ func (s *suite) Step(exp *regexp.Regexp, h StepHandler) {
// Run - runs a godog feature suite // Run - runs a godog feature suite
func (s *suite) Run() { func (s *suite) Run() {
var err error var err error
s.fmt = cfg.formatter()
s.features, err = cfg.features() s.features, err = cfg.features()
fatal(err) fatal(err)
@ -118,57 +120,54 @@ func (s *suite) Run() {
} }
} }
func (s *suite) runStep(step *gherkin.Step) {
var handler StepHandler
var args []Arg
for r, h := range s.steps {
if m := r.FindStringSubmatch(step.Text); len(m) > 0 {
handler = h
for _, a := range m[1:] {
args = append(args, Arg(a))
}
break
}
}
if handler == nil {
fmt.Println("PENDING")
return
}
defer func() {
if e := recover(); e != nil {
fmt.Println("PANIC")
}
}()
if err := handler.HandleStep(args...); err != nil {
fmt.Println("ERR")
} else {
fmt.Println("OK")
}
}
func (s *suite) runFeature(f *gherkin.Feature) { func (s *suite) runFeature(f *gherkin.Feature) {
s.fmt.node(f)
var background bool
for _, scenario := range f.Scenarios { for _, scenario := range f.Scenarios {
if f.Background != nil { if f.Background != nil {
if !background {
s.fmt.node(f.Background)
}
for _, step := range f.Background.Steps { for _, step := range f.Background.Steps {
var handler StepHandler s.runStep(step)
var args []Arg if !background {
for r, h := range s.steps { s.fmt.node(step)
if m := r.FindStringSubmatch(step.Text); len(m) > 0 {
handler = h
for _, a := range m[1:] {
args = append(args, Arg(a))
}
break
}
}
if handler != nil {
if err := handler.HandleStep(args...); err != nil {
// @TODO: scenario fails, step failed
fmt.Println("ERR")
} else {
fmt.Println("OK")
}
// @TODO: handle panic and recover
} else {
fmt.Println("PENDING")
} }
} }
background = true
} }
s.fmt.node(scenario)
for _, step := range scenario.Steps { for _, step := range scenario.Steps {
var handler StepHandler s.runStep(step)
var args []Arg s.fmt.node(step)
for r, h := range s.steps {
if m := r.FindStringSubmatch(step.Text); len(m) > 0 {
handler = h
for _, a := range m[1:] {
args = append(args, Arg(a))
}
break
}
}
if handler != nil {
if err := handler.HandleStep(args...); err != nil {
// @TODO: scenario fails, step failed
fmt.Println("ERR")
} else {
fmt.Println("OK")
}
// @TODO: handle panic and recover
} else {
fmt.Println("PENDING")
}
} }
} }
} }