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

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

@ -4,6 +4,8 @@ import "fmt"
type color int
const ansiEscape = "\x1b"
const (
black color = iota + 30
red
@ -16,5 +18,9 @@ const (
)
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) {
if err != nil {
fmt.Println(err)

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

@ -3,7 +3,7 @@ Feature: godog bdd suite
As a suite
I need to be able to register and run features
Scenario:
Scenario: parses all features in path
Given a feature path "features"
When I parse features
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
type Tags []Tag
// Has checks whether the tag list has a tag
func (t Tags) Has(tag Tag) bool {
for _, tg := range t {
if tg == tag {
@ -97,17 +98,17 @@ func (t Tags) Has(tag Tag) bool {
// be used to filter out or run specific
// initialization tasks
type Scenario struct {
*Token
Title string
Steps []*Step
Tags Tags
Examples *Table
Comment string
}
// Background steps are run before every scenario
type Background struct {
Steps []*Step
Comment string
*Token
Steps []*Step
}
// StepType is a general type of step
@ -121,8 +122,8 @@ const (
// Step describes a Scenario or Background step
type Step struct {
*Token
Text string
Comment string
Type StepType
PyString *PyString
Table *Table
@ -130,6 +131,7 @@ type Step struct {
// Feature describes the whole feature
type Feature struct {
*Token
Path string
Tags Tags
Description string
@ -137,16 +139,17 @@ type Feature struct {
Background *Background
Scenarios []*Scenario
AST *AST
Comment string
}
// PyString is a multiline text object used with step definition
type PyString struct {
*Token
Body string
}
// Table is a row group object used with step definition
type Table struct {
*Token
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)
}
ft.Title = tok.Value
ft.Comment = tok.Comment
ft.Token = tok
var desc []string
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")
@ -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)
}
ft.Background = &Background{Comment: tok.Comment}
ft.Background = &Background{Token: tok}
p.next() // jump to background steps
if ft.Background.Steps, err = p.parseSteps(); err != nil {
return ft, err
@ -283,7 +286,7 @@ func (p *parser) parseFeature() (ft *Feature, err error) {
func (p *parser) parseScenario() (s *Scenario, err error) {
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 {
return s, err
}
@ -305,7 +308,7 @@ func (p *parser) parseScenario() (s *Scenario, err error) {
func (p *parser) parseSteps() (steps []*Step, err error) {
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 {
case 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) {
if s.Comment != comment {
t.Fatalf("expected step '%s' comment to be '%s', but got '%s'", s.Text, comment, s.Comment)
if s.Token.Comment != 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 {
steps map[*regexp.Regexp]StepHandler
features []*gherkin.Feature
fmt formatter
}
// 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
func (s *suite) Run() {
var err error
s.fmt = cfg.formatter()
s.features, err = cfg.features()
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) {
s.fmt.node(f)
var background bool
for _, scenario := range f.Scenarios {
if f.Background != nil {
if !background {
s.fmt.node(f.Background)
}
for _, step := range f.Background.Steps {
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 {
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")
s.runStep(step)
if !background {
s.fmt.node(step)
}
}
background = true
}
s.fmt.node(scenario)
for _, step := range scenario.Steps {
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 {
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")
}
s.runStep(step)
s.fmt.node(step)
}
}
}