more specific types and references for gherkin nodes
Этот коммит содержится в:
родитель
7f214c702b
коммит
2d3d04e0e6
5 изменённых файлов: 114 добавлений и 99 удалений
35
arguments.go
Обычный файл
35
arguments.go
Обычный файл
|
@ -0,0 +1,35 @@
|
|||
package godog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Arg is an argument for StepHandler parsed from
|
||||
// the regexp submatch to handle the step
|
||||
type Arg string
|
||||
|
||||
// Float converts an argument to float64
|
||||
// or panics if unable to convert it
|
||||
func (a Arg) Float() float64 {
|
||||
v, err := strconv.ParseFloat(string(a), 64)
|
||||
if err == nil {
|
||||
return v
|
||||
}
|
||||
panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, a, err))
|
||||
}
|
||||
|
||||
// Int converts an argument to int64
|
||||
// or panics if unable to convert it
|
||||
func (a Arg) Int() int64 {
|
||||
v, err := strconv.ParseInt(string(a), 10, 0)
|
||||
if err == nil {
|
||||
return v
|
||||
}
|
||||
panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, a, err))
|
||||
}
|
||||
|
||||
// String converts an argument to string
|
||||
func (a Arg) String() string {
|
||||
return string(a)
|
||||
}
|
|
@ -37,6 +37,8 @@ func main() {
|
|||
// @TODO: support for windows
|
||||
cmd := exec.Command("sh", "-c", c)
|
||||
cmd.Stdout = stdout
|
||||
// @TODO: do not read stderr on production version
|
||||
cmd.Stderr = stdout
|
||||
|
||||
err = cmd.Run()
|
||||
switch err.(type) {
|
||||
|
|
92
formatter.go
92
formatter.go
|
@ -31,7 +31,6 @@ type Formatter interface {
|
|||
// general pretty formatter structure
|
||||
type pretty struct {
|
||||
feature *gherkin.Feature
|
||||
scenario *gherkin.Scenario
|
||||
commentPos int
|
||||
doneBackground bool
|
||||
background *gherkin.Background
|
||||
|
@ -48,34 +47,39 @@ type pretty struct {
|
|||
// failed represents a failed step data structure
|
||||
// with all necessary references
|
||||
type failed struct {
|
||||
feature *gherkin.Feature
|
||||
scenario *gherkin.Scenario
|
||||
step *gherkin.Step
|
||||
err error
|
||||
step *gherkin.Step
|
||||
err error
|
||||
}
|
||||
|
||||
func (f failed) line() string {
|
||||
var tok *gherkin.Token
|
||||
var ft *gherkin.Feature
|
||||
if f.step.Scenario != nil {
|
||||
tok = f.step.Scenario.Token
|
||||
ft = f.step.Scenario.Feature
|
||||
} else {
|
||||
tok = f.step.Background.Token
|
||||
ft = f.step.Background.Feature
|
||||
}
|
||||
return fmt.Sprintf("%s:%d", ft.Path, tok.Line)
|
||||
}
|
||||
|
||||
// passed represents a successful step data structure
|
||||
// with all necessary references
|
||||
type passed struct {
|
||||
feature *gherkin.Feature
|
||||
scenario *gherkin.Scenario
|
||||
step *gherkin.Step
|
||||
step *gherkin.Step
|
||||
}
|
||||
|
||||
// skipped represents a skipped step data structure
|
||||
// with all necessary references
|
||||
type skipped struct {
|
||||
feature *gherkin.Feature
|
||||
scenario *gherkin.Scenario
|
||||
step *gherkin.Step
|
||||
step *gherkin.Step
|
||||
}
|
||||
|
||||
// undefined represents a pending step data structure
|
||||
// with all necessary references
|
||||
type undefined struct {
|
||||
feature *gherkin.Feature
|
||||
scenario *gherkin.Scenario
|
||||
step *gherkin.Step
|
||||
step *gherkin.Step
|
||||
}
|
||||
|
||||
// a line number representation in feature file
|
||||
|
@ -85,24 +89,10 @@ func (f *pretty) line(tok *gherkin.Token) string {
|
|||
|
||||
// checks whether it should not print a background step once again
|
||||
func (f *pretty) canPrintStep(step *gherkin.Step) bool {
|
||||
if f.background == nil {
|
||||
return true
|
||||
if f.background != nil {
|
||||
return step.Background != nil
|
||||
}
|
||||
|
||||
var backgroundStep bool
|
||||
for _, s := range f.background.Steps {
|
||||
if s == step {
|
||||
backgroundStep = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !backgroundStep {
|
||||
f.doneBackground = true
|
||||
return true
|
||||
}
|
||||
|
||||
return !f.doneBackground
|
||||
return true
|
||||
}
|
||||
|
||||
// Node takes a gherkin node for formatting
|
||||
|
@ -111,7 +101,6 @@ func (f *pretty) Node(node interface{}) {
|
|||
case *gherkin.Feature:
|
||||
f.feature = t
|
||||
f.doneBackground = false
|
||||
f.scenario = nil
|
||||
f.background = nil
|
||||
f.features = append(f.features, t)
|
||||
fmt.Println(bcl("Feature: ", white) + t.Title + "\n")
|
||||
|
@ -120,7 +109,6 @@ func (f *pretty) Node(node interface{}) {
|
|||
f.background = t
|
||||
fmt.Println(bcl("Background:", white) + "\n")
|
||||
case *gherkin.Scenario:
|
||||
f.scenario = t
|
||||
f.commentPos = len(t.Token.Text)
|
||||
for _, step := range t.Steps {
|
||||
if len(step.Token.Text) > f.commentPos {
|
||||
|
@ -135,10 +123,17 @@ func (f *pretty) Node(node interface{}) {
|
|||
|
||||
// Summary sumarize the feature formatter output
|
||||
func (f *pretty) Summary() {
|
||||
if len(f.failed) > 0 {
|
||||
// failed steps on background are not scenarios
|
||||
var failedScenarios []*failed
|
||||
for _, fail := range f.failed {
|
||||
if fail.step.Scenario != nil {
|
||||
failedScenarios = append(failedScenarios, fail)
|
||||
}
|
||||
}
|
||||
if len(failedScenarios) > 0 {
|
||||
fmt.Println("\n--- " + cl("Failed scenarios:", red) + "\n")
|
||||
for _, fail := range f.failed {
|
||||
fmt.Println(" " + cl(fmt.Sprintf("%s:%d", fail.feature.Path, fail.scenario.Token.Line), red))
|
||||
for _, fail := range failedScenarios {
|
||||
fmt.Println(" " + cl(fail.line(), red))
|
||||
}
|
||||
}
|
||||
var total, passed int
|
||||
|
@ -230,11 +225,7 @@ func (f *pretty) printMatchedStep(step *gherkin.Step, match *stepMatchHandler, c
|
|||
// Passed is called to represent a passed step
|
||||
func (f *pretty) Passed(step *gherkin.Step, match *stepMatchHandler) {
|
||||
f.printMatchedStep(step, match, green)
|
||||
f.passed = append(f.passed, &passed{
|
||||
feature: f.feature,
|
||||
scenario: f.scenario,
|
||||
step: step,
|
||||
})
|
||||
f.passed = append(f.passed, &passed{step})
|
||||
}
|
||||
|
||||
// Skipped is called to represent a passed step
|
||||
|
@ -242,11 +233,7 @@ func (f *pretty) Skipped(step *gherkin.Step) {
|
|||
if f.canPrintStep(step) {
|
||||
fmt.Println(cl(step.Token.Text, cyan))
|
||||
}
|
||||
f.skipped = append(f.skipped, &skipped{
|
||||
feature: f.feature,
|
||||
scenario: f.scenario,
|
||||
step: step,
|
||||
})
|
||||
f.skipped = append(f.skipped, &skipped{step})
|
||||
}
|
||||
|
||||
// Undefined is called to represent a pending step
|
||||
|
@ -254,21 +241,12 @@ func (f *pretty) Undefined(step *gherkin.Step) {
|
|||
if f.canPrintStep(step) {
|
||||
fmt.Println(cl(step.Token.Text, yellow))
|
||||
}
|
||||
f.undefined = append(f.undefined, &undefined{
|
||||
feature: f.feature,
|
||||
scenario: f.scenario,
|
||||
step: step,
|
||||
})
|
||||
f.undefined = append(f.undefined, &undefined{step})
|
||||
}
|
||||
|
||||
// Failed is called to represent a failed step
|
||||
func (f *pretty) Failed(step *gherkin.Step, match *stepMatchHandler, err error) {
|
||||
f.printMatchedStep(step, match, red)
|
||||
fmt.Println(strings.Repeat(" ", step.Token.Indent) + bcl(err, red))
|
||||
f.failed = append(f.failed, &failed{
|
||||
feature: f.feature,
|
||||
scenario: f.scenario,
|
||||
step: step,
|
||||
err: err,
|
||||
})
|
||||
f.failed = append(f.failed, &failed{step, err})
|
||||
}
|
||||
|
|
|
@ -102,22 +102,26 @@ type Scenario struct {
|
|||
Title string
|
||||
Steps []*Step
|
||||
Tags Tags
|
||||
Examples *Table
|
||||
Examples *ExampleTable
|
||||
Feature *Feature
|
||||
}
|
||||
|
||||
// Background steps are run before every scenario
|
||||
type Background struct {
|
||||
*Token
|
||||
Steps []*Step
|
||||
Steps []*Step
|
||||
Feature *Feature
|
||||
}
|
||||
|
||||
// Step describes a Scenario or Background step
|
||||
type Step struct {
|
||||
*Token
|
||||
Text string
|
||||
Type string
|
||||
PyString *PyString
|
||||
Table *Table
|
||||
Text string
|
||||
Type string
|
||||
PyString *PyString
|
||||
Table *StepTable
|
||||
Scenario *Scenario
|
||||
Background *Background
|
||||
}
|
||||
|
||||
// Feature describes the whole feature
|
||||
|
@ -136,14 +140,28 @@ type Feature struct {
|
|||
type PyString struct {
|
||||
*Token
|
||||
Body string
|
||||
Step *Step
|
||||
}
|
||||
|
||||
// Table is a row group object used with step definition
|
||||
type Table struct {
|
||||
type table struct {
|
||||
*Token
|
||||
rows [][]string
|
||||
}
|
||||
|
||||
// ExampleTable is a row group object for
|
||||
// scenario outline examples
|
||||
type ExampleTable struct {
|
||||
*table
|
||||
OutlineScenario *Scenario
|
||||
}
|
||||
|
||||
// StepTable is a row group object for steps
|
||||
type StepTable struct {
|
||||
*table
|
||||
Step *Step
|
||||
}
|
||||
|
||||
var allSteps = []TokenType{
|
||||
GIVEN,
|
||||
WHEN,
|
||||
|
@ -238,11 +256,14 @@ 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{Token: tok}
|
||||
ft.Background = &Background{Token: tok, Feature: ft}
|
||||
p.next() // jump to background steps
|
||||
if ft.Background.Steps, err = p.parseSteps(); err != nil {
|
||||
return ft, err
|
||||
}
|
||||
for _, step := range ft.Background.Steps {
|
||||
step.Background = ft.Background
|
||||
}
|
||||
tok = p.peek() // peek to scenario or tags
|
||||
}
|
||||
|
||||
|
@ -269,6 +290,7 @@ func (p *parser) parseFeature() (ft *Feature, err error) {
|
|||
}
|
||||
|
||||
scenario.Tags = tags
|
||||
scenario.Feature = ft
|
||||
ft.Scenarios = append(ft.Scenarios, scenario)
|
||||
}
|
||||
|
||||
|
@ -281,6 +303,9 @@ func (p *parser) parseScenario() (s *Scenario, err error) {
|
|||
if s.Steps, err = p.parseSteps(); err != nil {
|
||||
return s, err
|
||||
}
|
||||
for _, step := range s.Steps {
|
||||
step.Scenario = s
|
||||
}
|
||||
if examples := p.peek(); examples.Type == EXAMPLES {
|
||||
p.next() // jump over the peeked token
|
||||
peek := p.peek()
|
||||
|
@ -290,9 +315,11 @@ func (p *parser) parseScenario() (s *Scenario, err error) {
|
|||
"but got '" + peek.Type.String() + "' instead, for scenario outline examples",
|
||||
}, " "), examples.Line)
|
||||
}
|
||||
if s.Examples, err = p.parseTable(); err != nil {
|
||||
tbl, err := p.parseTable()
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
s.Examples = &ExampleTable{OutlineScenario: s, table: tbl}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
@ -309,10 +336,13 @@ func (p *parser) parseSteps() (steps []*Step, err error) {
|
|||
if step.PyString, err = p.parsePystring(); err != nil {
|
||||
return steps, err
|
||||
}
|
||||
step.PyString.Step = step
|
||||
case TABLE_ROW:
|
||||
if step.Table, err = p.parseTable(); err != nil {
|
||||
tbl, err := p.parseTable()
|
||||
if err != nil {
|
||||
return steps, err
|
||||
}
|
||||
step.Table = &StepTable{Step: step, table: tbl}
|
||||
default:
|
||||
return steps, p.err("pystring or table row was expected, but got: '"+tok.Type.String()+"' instead", tok.Line)
|
||||
}
|
||||
|
@ -339,8 +369,8 @@ func (p *parser) parsePystring() (*PyString, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseTable() (*Table, error) {
|
||||
tbl := &Table{}
|
||||
func (p *parser) parseTable() (*table, error) {
|
||||
tbl := &table{}
|
||||
for row := p.peek(); row.Type == TABLE_ROW; row = p.peek() {
|
||||
var cols []string
|
||||
for _, r := range strings.Split(strings.Trim(row.Value, "|"), "|") {
|
||||
|
|
30
suite.go
30
suite.go
|
@ -4,40 +4,10 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/DATA-DOG/godog/gherkin"
|
||||
)
|
||||
|
||||
// Arg is an argument for StepHandler parsed from
|
||||
// the regexp submatch to handle the step
|
||||
type Arg string
|
||||
|
||||
// Float converts an argument to float64
|
||||
// or panics if unable to convert it
|
||||
func (a Arg) Float() float64 {
|
||||
v, err := strconv.ParseFloat(string(a), 64)
|
||||
if err == nil {
|
||||
return v
|
||||
}
|
||||
panic(fmt.Sprintf(`cannot convert "%s" to float64: %s`, a, err))
|
||||
}
|
||||
|
||||
// Int converts an argument to int64
|
||||
// or panics if unable to convert it
|
||||
func (a Arg) Int() int64 {
|
||||
v, err := strconv.ParseInt(string(a), 10, 0)
|
||||
if err == nil {
|
||||
return v
|
||||
}
|
||||
panic(fmt.Sprintf(`cannot convert "%s" to int64: %s`, a, err))
|
||||
}
|
||||
|
||||
// String converts an argument to string
|
||||
func (a Arg) String() string {
|
||||
return string(a)
|
||||
}
|
||||
|
||||
// Objects implementing the StepHandler interface can be
|
||||
// registered as step definitions in godog
|
||||
//
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче