an initial formatter impl
Этот коммит содержится в:
родитель
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
Обычный файл
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
85
suite.go
85
suite.go
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче