junit formatter implementation, adapt pretty formatter
closes #14 background was not printed with outline scenarios in feature
Этот коммит содержится в:
родитель
b192f0bd23
коммит
8a07e4cae3
7 изменённых файлов: 203 добавлений и 264 удалений
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses)
|
The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses)
|
||||||
|
|
||||||
Copyright (c) 2015, DataDog.lt team
|
Copyright (c) 2015-2016, DataDog.lt team
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
@ -144,6 +144,12 @@ See implementation examples:
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
|
**2016-03-04**
|
||||||
|
- added **junit** compatible output formatter, which prints **xml**
|
||||||
|
results to **os.Stdout**
|
||||||
|
- fixed #14 which skipped printing background steps when there was
|
||||||
|
scenario outline in feature.
|
||||||
|
|
||||||
**2015-07-03**
|
**2015-07-03**
|
||||||
- changed **godog.Suite** from interface to struct. Context registration should be updated accordingly. The reason
|
- changed **godog.Suite** from interface to struct. Context registration should be updated accordingly. The reason
|
||||||
for change: since it exports the same methods and there is no need to mock a function in tests, there is no
|
for change: since it exports the same methods and there is no need to mock a function in tests, there is no
|
||||||
|
|
230
fmt_junit.go
230
fmt_junit.go
|
@ -3,6 +3,7 @@ package godog
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -10,198 +11,175 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("junit", "Prints out in junit compatible xml format", &junitFormatter{
|
Format("junit", "Prints junit compatible xml to stdout", &junitFormatter{
|
||||||
suites: make([]*junitTestSuites, 0),
|
suite: &junitPackageSuite{
|
||||||
|
Name: "main", // @TODO: it should extract package name
|
||||||
|
TestSuites: make([]*junitTestSuite, 0),
|
||||||
|
},
|
||||||
|
started: time.Now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitFormatter struct {
|
type junitFormatter struct {
|
||||||
suites []*junitTestSuites
|
suite *junitPackageSuite
|
||||||
|
|
||||||
|
// timing
|
||||||
|
started time.Time
|
||||||
|
caseStarted time.Time
|
||||||
|
featStarted time.Time
|
||||||
|
|
||||||
|
outline *gherkin.ScenarioOutline
|
||||||
|
outlineExample int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Feature(feature *gherkin.Feature, path string) {
|
func (j *junitFormatter) Feature(feature *gherkin.Feature, path string) {
|
||||||
testSuites := &junitTestSuites{
|
testSuite := &junitTestSuite{
|
||||||
Name: feature.Name,
|
TestCases: make([]*TestCase, 0),
|
||||||
TestSuites: make([]*junitTestSuite, 0),
|
Name: feature.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
j.suites = append(j.suites, testSuites)
|
if len(j.suite.TestSuites) > 0 {
|
||||||
|
j.current().Time = time.Since(j.featStarted).String()
|
||||||
|
}
|
||||||
|
j.featStarted = time.Now()
|
||||||
|
j.suite.TestSuites = append(j.suite.TestSuites, testSuite)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Node(node interface{}) {
|
func (j *junitFormatter) Node(node interface{}) {
|
||||||
testSuite := &junitTestSuite{
|
suite := j.current()
|
||||||
TestCases: make([]*TestCase, 0),
|
tcase := &TestCase{}
|
||||||
Timestamp: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := node.(type) {
|
switch t := node.(type) {
|
||||||
case *gherkin.ScenarioOutline:
|
case *gherkin.ScenarioOutline:
|
||||||
testSuite.Name = t.Name
|
j.outline = t
|
||||||
|
return
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
testSuite.Name = t.Name
|
tcase.Name = t.Name
|
||||||
case *gherkin.Background:
|
suite.Tests++
|
||||||
testSuite.Name = "Background"
|
j.suite.Tests++
|
||||||
|
case *gherkin.Examples:
|
||||||
|
j.outlineExample = 0
|
||||||
|
return
|
||||||
|
case *gherkin.TableRow:
|
||||||
|
j.outlineExample++
|
||||||
|
tcase.Name = fmt.Sprintf("%s #%d", j.outline.Name, j.outlineExample)
|
||||||
|
suite.Tests++
|
||||||
|
j.suite.Tests++
|
||||||
|
default:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
if len(suite.TestCases) > 0 {
|
||||||
currentSuites := j.currentSuites()
|
suite.current().Time = time.Since(j.caseStarted).String()
|
||||||
currentSuites.TestSuites = append(currentSuites.TestSuites, testSuite)
|
}
|
||||||
|
j.caseStarted = time.Now()
|
||||||
|
suite.TestCases = append(suite.TestCases, tcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Failed(step *gherkin.Step, match *StepDef, err error) {
|
func (j *junitFormatter) Failed(step *gherkin.Step, match *StepDef, err error) {
|
||||||
testCase := &TestCase{
|
suite := j.current()
|
||||||
Name: step.Text,
|
suite.Failures++
|
||||||
}
|
j.suite.Failures++
|
||||||
|
|
||||||
testCase.Failure = &junitFailure{
|
tcase := suite.current()
|
||||||
Contents: err.Error(),
|
tcase.Status = "failed"
|
||||||
|
tcase.Failure = &junitFailure{
|
||||||
|
Message: fmt.Sprintf("%s %s: %s", step.Type, step.Text, err.Error()),
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSuites := j.currentSuites()
|
|
||||||
currentSuites.Failures++
|
|
||||||
currentSuite := currentSuites.currentSuite()
|
|
||||||
currentSuite.Failures++
|
|
||||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Passed(step *gherkin.Step, match *StepDef) {
|
func (j *junitFormatter) Passed(step *gherkin.Step, match *StepDef) {
|
||||||
testCase := &TestCase{
|
suite := j.current()
|
||||||
Name: step.Text,
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSuites := j.currentSuites()
|
tcase := suite.current()
|
||||||
currentSuites.Tests++
|
tcase.Status = "passed"
|
||||||
currentSuite := currentSuites.currentSuite()
|
|
||||||
currentSuite.Tests++
|
|
||||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Skipped(step *gherkin.Step) {
|
func (j *junitFormatter) Skipped(step *gherkin.Step) {
|
||||||
testCase := &TestCase{
|
|
||||||
Name: step.Text,
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSuites := j.currentSuites()
|
|
||||||
currentSuite := currentSuites.currentSuite()
|
|
||||||
currentSuite.Skipped++
|
|
||||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Undefined(step *gherkin.Step) {
|
func (j *junitFormatter) Undefined(step *gherkin.Step) {
|
||||||
testCase := &TestCase{
|
suite := j.current()
|
||||||
Name: step.Text,
|
suite.Errors++
|
||||||
}
|
j.suite.Errors++
|
||||||
|
|
||||||
currentSuites := j.currentSuites()
|
tcase := suite.current()
|
||||||
currentSuites.Disabled++
|
tcase.Status = "undefined"
|
||||||
currentSuite := currentSuites.currentSuite()
|
tcase.Error = append(tcase.Error, &junitError{
|
||||||
currentSuite.Disabled++
|
Type: "undefined",
|
||||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
Message: fmt.Sprintf("%s %s", step.Type, step.Text),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Pending(step *gherkin.Step, match *StepDef) {
|
func (j *junitFormatter) Pending(step *gherkin.Step, match *StepDef) {
|
||||||
testCase := &TestCase{
|
suite := j.current()
|
||||||
Name: step.Text,
|
suite.Errors++
|
||||||
}
|
j.suite.Errors++
|
||||||
|
|
||||||
testCase.Skipped = &junitSkipped{
|
tcase := suite.current()
|
||||||
Contents: step.Text,
|
tcase.Status = "pending"
|
||||||
}
|
tcase.Error = append(tcase.Error, &junitError{
|
||||||
|
Type: "pending",
|
||||||
currentSuites := j.currentSuites()
|
Message: fmt.Sprintf("%s %s: TODO: write pending definition", step.Type, step.Text),
|
||||||
currentSuite := currentSuites.currentSuite()
|
})
|
||||||
currentSuite.Skipped++
|
|
||||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *junitFormatter) Summary() {
|
func (j *junitFormatter) Summary() {
|
||||||
|
j.suite.Time = time.Since(j.started).String()
|
||||||
|
io.WriteString(os.Stdout, xml.Header)
|
||||||
|
|
||||||
enc := xml.NewEncoder(os.Stdout)
|
enc := xml.NewEncoder(os.Stdout)
|
||||||
enc.Indent(" ", " ")
|
enc.Indent("", s(2))
|
||||||
if err := enc.Encode(j.suites); err != nil {
|
if err := enc.Encode(j.suite); err != nil {
|
||||||
fmt.Printf("error: %v\n", err)
|
fmt.Println("failed to write junit xml:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitFailure struct {
|
type junitFailure struct {
|
||||||
Message string `xml:"message,attr"`
|
Message string `xml:"message,attr"`
|
||||||
Type string `xml:"type,attr"`
|
Type string `xml:"type,attr,omitempty"`
|
||||||
Contents string `xml:",chardata"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitError struct {
|
type junitError struct {
|
||||||
Message string `xml:"message,attr"`
|
XMLName xml.Name `xml:"error,omitempty"`
|
||||||
Type string `xml:"type,attr"`
|
Message string `xml:"message,attr"`
|
||||||
Contents string `xml:",chardata"`
|
Type string `xml:"type,attr"`
|
||||||
}
|
|
||||||
|
|
||||||
type junitProperty struct {
|
|
||||||
Name string `xml:"name,attr"`
|
|
||||||
Value string `xml:"value,attr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type junitSkipped struct {
|
|
||||||
Contents string `xml:",chardata"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SystemErr struct {
|
|
||||||
Contents string `xml:",chardata"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SystemOut struct {
|
|
||||||
Contents string `xml:",chardata"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
XMLName xml.Name `xml:"testcase"`
|
XMLName xml.Name `xml:"testcase"`
|
||||||
Name string `xml:"name,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Classname string `xml:"classname,attr"`
|
Status string `xml:"status,attr"`
|
||||||
Assertions string `xml:"assertions,attr"`
|
Time string `xml:"time,attr"`
|
||||||
Status string `xml:"status,attr"`
|
Failure *junitFailure `xml:"failure,omitempty"`
|
||||||
Time string `xml:"time,attr"`
|
Error []*junitError
|
||||||
Skipped *junitSkipped `xml:"skipped,omitempty"`
|
|
||||||
Failure *junitFailure `xml:"failure,omitempty"`
|
|
||||||
Error *junitError `xml:"error,omitempty"`
|
|
||||||
SystemOut *SystemOut `xml:"system-out,omitempty"`
|
|
||||||
SystemErr *SystemErr `xml:"system-err,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitTestSuite struct {
|
type junitTestSuite struct {
|
||||||
XMLName xml.Name `xml:"testsuite"`
|
XMLName xml.Name `xml:"testsuite"`
|
||||||
Name string `xml:"name,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Tests int `xml:"tests,attr"`
|
Tests int `xml:"tests,attr"`
|
||||||
Failures int `xml:"failures,attr"`
|
Skipped int `xml:"skipped,attr"`
|
||||||
Errors int `xml:"errors,attr"`
|
Failures int `xml:"failures,attr"`
|
||||||
Disabled int `xml:"disabled,attr"`
|
Errors int `xml:"errors,attr"`
|
||||||
Skipped int `xml:"skipped,attr"`
|
Time string `xml:"time,attr"`
|
||||||
Time string `xml:"time,attr"`
|
TestCases []*TestCase
|
||||||
Hostname string `xml:"hostname,attr"`
|
|
||||||
ID string `xml:"id,attr"`
|
|
||||||
Package string `xml:"package,attr"`
|
|
||||||
Timestamp time.Time `xml:"timestamp,attr"`
|
|
||||||
SystemOut *SystemOut `xml:"system-out,omitempty"`
|
|
||||||
SystemErr *SystemErr `xml:"system-err,omitempty"`
|
|
||||||
Properties []*junitProperty `xml:"properties>property,omitempty"`
|
|
||||||
TestCases []*TestCase
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *junitTestSuite) currentCase() *TestCase {
|
func (ts *junitTestSuite) current() *TestCase {
|
||||||
return ts.TestCases[len(ts.TestCases)-1]
|
return ts.TestCases[len(ts.TestCases)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitTestSuites struct {
|
type junitPackageSuite struct {
|
||||||
XMLName xml.Name `xml:"testsuites"`
|
XMLName xml.Name `xml:"testsuites"`
|
||||||
Name string `xml:"name,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Tests int `xml:"tests,attr"`
|
Tests int `xml:"tests,attr"`
|
||||||
|
Skipped int `xml:"skipped,attr"`
|
||||||
Failures int `xml:"failures,attr"`
|
Failures int `xml:"failures,attr"`
|
||||||
Errors int `xml:"errors,attr"`
|
Errors int `xml:"errors,attr"`
|
||||||
Disabled int `xml:"disabled,attr"`
|
|
||||||
Time string `xml:"time,attr"`
|
Time string `xml:"time,attr"`
|
||||||
TestSuites []*junitTestSuite
|
TestSuites []*junitTestSuite
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *junitTestSuites) currentSuite() *junitTestSuite {
|
func (j *junitFormatter) current() *junitTestSuite {
|
||||||
return ts.TestSuites[len(ts.TestSuites)-1]
|
return j.suite.TestSuites[len(j.suite.TestSuites)-1]
|
||||||
}
|
|
||||||
|
|
||||||
func (j *junitFormatter) currentSuites() *junitTestSuites {
|
|
||||||
return j.suites[len(j.suites)-1]
|
|
||||||
}
|
}
|
||||||
|
|
130
fmt_pretty.go
130
fmt_pretty.go
|
@ -24,8 +24,16 @@ var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>")
|
||||||
// a built in default pretty formatter
|
// a built in default pretty formatter
|
||||||
type pretty struct {
|
type pretty struct {
|
||||||
basefmt
|
basefmt
|
||||||
commentPos int
|
|
||||||
backgroundSteps int
|
// currently processed
|
||||||
|
feature *gherkin.Feature
|
||||||
|
scenario *gherkin.Scenario
|
||||||
|
outline *gherkin.ScenarioOutline
|
||||||
|
|
||||||
|
// state
|
||||||
|
bgSteps int
|
||||||
|
steps int
|
||||||
|
commentPos int
|
||||||
|
|
||||||
// outline
|
// outline
|
||||||
outlineSteps []*stepResult
|
outlineSteps []*stepResult
|
||||||
|
@ -33,25 +41,6 @@ type pretty struct {
|
||||||
outlineNumExamples int
|
outlineNumExamples int
|
||||||
}
|
}
|
||||||
|
|
||||||
// a line number representation in feature file
|
|
||||||
func (f *pretty) line(loc *gherkin.Location) string {
|
|
||||||
return cl(fmt.Sprintf("# %s:%d", f.features[len(f.features)-1].Path, loc.Line), black)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *pretty) length(node interface{}) int {
|
|
||||||
switch t := node.(type) {
|
|
||||||
case *gherkin.Background:
|
|
||||||
return f.indent + len(strings.TrimSpace(t.Keyword)+": "+t.Name)
|
|
||||||
case *gherkin.Step:
|
|
||||||
return f.indent*2 + len(strings.TrimSpace(t.Keyword)+" "+t.Text)
|
|
||||||
case *gherkin.Scenario:
|
|
||||||
return f.indent + len(strings.TrimSpace(t.Keyword)+": "+t.Name)
|
|
||||||
case *gherkin.ScenarioOutline:
|
|
||||||
return f.indent + len(strings.TrimSpace(t.Keyword)+": "+t.Name)
|
|
||||||
}
|
|
||||||
panic(fmt.Sprintf("unexpected node %T to determine length", node))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *pretty) Feature(ft *gherkin.Feature, p string) {
|
func (f *pretty) Feature(ft *gherkin.Feature, p string) {
|
||||||
if len(f.features) != 0 {
|
if len(f.features) != 0 {
|
||||||
// not a first feature, add a newline
|
// not a first feature, add a newline
|
||||||
|
@ -64,10 +53,13 @@ func (f *pretty) Feature(ft *gherkin.Feature, p string) {
|
||||||
fmt.Println(s(f.indent) + strings.TrimSpace(line))
|
fmt.Println(s(f.indent) + strings.TrimSpace(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.feature = ft
|
||||||
|
f.scenario = nil
|
||||||
|
f.outline = nil
|
||||||
|
f.bgSteps = 0
|
||||||
if ft.Background != nil {
|
if ft.Background != nil {
|
||||||
f.commentPos = f.longestStep(ft.Background.Steps, f.length(ft.Background))
|
f.bgSteps = len(ft.Background.Steps)
|
||||||
f.backgroundSteps = len(ft.Background.Steps)
|
|
||||||
fmt.Println("\n" + s(f.indent) + bcl(ft.Background.Keyword+": "+ft.Background.Name, white))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,15 +72,13 @@ func (f *pretty) Node(node interface{}) {
|
||||||
f.outlineNumExamples = len(t.TableBody)
|
f.outlineNumExamples = len(t.TableBody)
|
||||||
f.outlineNumExample++
|
f.outlineNumExample++
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
f.commentPos = f.longestStep(t.Steps, f.length(t))
|
f.scenario = t
|
||||||
text := s(f.indent) + bcl(t.Keyword+": ", white) + t.Name
|
f.outline = nil
|
||||||
text += s(f.commentPos-f.length(t)+1) + f.line(t.Location)
|
f.steps = len(t.Steps)
|
||||||
fmt.Println("\n" + text)
|
|
||||||
case *gherkin.ScenarioOutline:
|
case *gherkin.ScenarioOutline:
|
||||||
f.commentPos = f.longestStep(t.Steps, f.length(t))
|
f.outline = t
|
||||||
text := s(f.indent) + bcl(t.Keyword+": ", white) + t.Name
|
f.scenario = nil
|
||||||
text += s(f.commentPos-f.length(t)+1) + f.line(t.Location)
|
f.steps = len(t.Steps)
|
||||||
fmt.Println("\n" + text)
|
|
||||||
f.outlineNumExample = -1
|
f.outlineNumExample = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,21 +230,54 @@ func (f *pretty) printStep(step *gherkin.Step, def *StepDef, c color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printStepKind(res *stepResult) {
|
func (f *pretty) printStepKind(res *stepResult) {
|
||||||
// do not print background more than once
|
_, isBgStep := res.owner.(*gherkin.Background)
|
||||||
if _, ok := res.owner.(*gherkin.Background); ok {
|
|
||||||
switch {
|
|
||||||
case f.backgroundSteps == 0:
|
|
||||||
return
|
|
||||||
case f.backgroundSteps > 0:
|
|
||||||
f.backgroundSteps--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if outline, ok := res.owner.(*gherkin.ScenarioOutline); ok {
|
// if has not printed background yet
|
||||||
|
switch {
|
||||||
|
// first background step
|
||||||
|
case f.bgSteps > 0 && f.bgSteps == len(f.feature.Background.Steps):
|
||||||
|
f.commentPos = f.longestStep(f.feature.Background.Steps, f.length(f.feature.Background))
|
||||||
|
fmt.Println("\n" + s(f.indent) + bcl(f.feature.Background.Keyword+": "+f.feature.Background.Name, white))
|
||||||
|
f.bgSteps--
|
||||||
|
// subsequent background steps
|
||||||
|
case f.bgSteps > 0:
|
||||||
|
f.bgSteps--
|
||||||
|
// a background step for another scenario, but all bg steps are
|
||||||
|
// already printed. so just skip it
|
||||||
|
case isBgStep:
|
||||||
|
return
|
||||||
|
// first step of scenario, print header and calculate comment position
|
||||||
|
case f.scenario != nil && f.steps == len(f.scenario.Steps):
|
||||||
|
f.commentPos = f.longestStep(f.scenario.Steps, f.length(f.scenario))
|
||||||
|
text := s(f.indent) + bcl(f.scenario.Keyword+": ", white) + f.scenario.Name
|
||||||
|
text += s(f.commentPos-f.length(f.scenario)+1) + f.line(f.scenario.Location)
|
||||||
|
fmt.Println("\n" + text)
|
||||||
|
f.steps--
|
||||||
|
// all subsequent scenario steps
|
||||||
|
case f.scenario != nil:
|
||||||
|
f.steps--
|
||||||
|
// first step of outline scenario, print header and calculate comment position
|
||||||
|
case f.outline != nil && f.steps == len(f.outline.Steps):
|
||||||
|
f.commentPos = f.longestStep(f.outline.Steps, f.length(f.outline))
|
||||||
|
text := s(f.indent) + bcl(f.outline.Keyword+": ", white) + f.outline.Name
|
||||||
|
text += s(f.commentPos-f.length(f.outline)+1) + f.line(f.outline.Location)
|
||||||
|
fmt.Println("\n" + text)
|
||||||
f.outlineSteps = append(f.outlineSteps, res)
|
f.outlineSteps = append(f.outlineSteps, res)
|
||||||
if len(f.outlineSteps) == len(outline.Steps) {
|
f.steps--
|
||||||
|
if len(f.outlineSteps) == len(f.outline.Steps) {
|
||||||
// an outline example steps has went through
|
// an outline example steps has went through
|
||||||
f.printOutlineExample(outline)
|
f.printOutlineExample(f.outline)
|
||||||
|
f.outlineSteps = []*stepResult{}
|
||||||
|
f.outlineNumExamples--
|
||||||
|
}
|
||||||
|
return
|
||||||
|
// all subsequent outline steps
|
||||||
|
case f.outline != nil:
|
||||||
|
f.outlineSteps = append(f.outlineSteps, res)
|
||||||
|
f.steps--
|
||||||
|
if len(f.outlineSteps) == len(f.outline.Steps) {
|
||||||
|
// an outline example steps has went through
|
||||||
|
f.printOutlineExample(f.outline)
|
||||||
f.outlineSteps = []*stepResult{}
|
f.outlineSteps = []*stepResult{}
|
||||||
f.outlineNumExamples--
|
f.outlineNumExamples--
|
||||||
}
|
}
|
||||||
|
@ -339,3 +362,22 @@ func (f *pretty) longestStep(steps []*gherkin.Step, base int) int {
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a line number representation in feature file
|
||||||
|
func (f *pretty) line(loc *gherkin.Location) string {
|
||||||
|
return cl(fmt.Sprintf("# %s:%d", f.features[len(f.features)-1].Path, loc.Line), black)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *pretty) length(node interface{}) int {
|
||||||
|
switch t := node.(type) {
|
||||||
|
case *gherkin.Background:
|
||||||
|
return f.indent + len(strings.TrimSpace(t.Keyword)+": "+t.Name)
|
||||||
|
case *gherkin.Step:
|
||||||
|
return f.indent*2 + len(strings.TrimSpace(t.Keyword)+" "+t.Text)
|
||||||
|
case *gherkin.Scenario:
|
||||||
|
return f.indent + len(strings.TrimSpace(t.Keyword)+": "+t.Name)
|
||||||
|
case *gherkin.ScenarioOutline:
|
||||||
|
return f.indent + len(strings.TrimSpace(t.Keyword)+": "+t.Name)
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected node %T to determine length", node))
|
||||||
|
}
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
||||||
|
|
||||||
<xs:element name="failure">
|
|
||||||
<xs:complexType mixed="true">
|
|
||||||
<xs:attribute name="type" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="message" type="xs:string" use="optional"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name="error">
|
|
||||||
<xs:complexType mixed="true">
|
|
||||||
<xs:attribute name="type" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="message" type="xs:string" use="optional"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name="properties">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="property" maxOccurs="unbounded"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name="property">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
|
||||||
<xs:attribute name="value" type="xs:string" use="required"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name="skipped" type="xs:string"/>
|
|
||||||
<xs:element name="system-err" type="xs:string"/>
|
|
||||||
<xs:element name="system-out" type="xs:string"/>
|
|
||||||
|
|
||||||
<xs:element name="testcase">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
<xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
<xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
<xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
|
||||||
<xs:attribute name="assertions" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="time" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="classname" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="status" type="xs:string" use="optional"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name="testsuite">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="properties" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element ref="testcase" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
<xs:element ref="system-out" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element ref="system-err" minOccurs="0" maxOccurs="1"/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
|
||||||
<xs:attribute name="tests" type="xs:string" use="required"/>
|
|
||||||
<xs:attribute name="failures" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="errors" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="time" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="disabled" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="skipped" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="timestamp" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="hostname" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="id" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="package" type="xs:string" use="optional"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name="testsuites">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="name" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="time" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="tests" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="failures" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="disabled" type="xs:string" use="optional"/>
|
|
||||||
<xs:attribute name="errors" type="xs:string" use="optional"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
|
|
||||||
</xs:schema>
|
|
|
@ -1 +0,0 @@
|
||||||
package junit
|
|
7
suite.go
7
suite.go
|
@ -290,6 +290,10 @@ func (s *Suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Backgrou
|
||||||
}
|
}
|
||||||
steps = append(steps, step)
|
steps = append(steps, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run example table row
|
||||||
|
s.fmt.Node(group)
|
||||||
|
|
||||||
// run background
|
// run background
|
||||||
var err error
|
var err error
|
||||||
if b != nil {
|
if b != nil {
|
||||||
|
@ -340,13 +344,14 @@ func (s *Suite) runScenario(scenario *gherkin.Scenario, b *gherkin.Background) (
|
||||||
f(scenario)
|
f(scenario)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.fmt.Node(scenario)
|
||||||
|
|
||||||
// background
|
// background
|
||||||
if b != nil {
|
if b != nil {
|
||||||
err = s.runSteps(b.Steps, err)
|
err = s.runSteps(b.Steps, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scenario
|
// scenario
|
||||||
s.fmt.Node(scenario)
|
|
||||||
err = s.runSteps(scenario.Steps, err)
|
err = s.runSteps(scenario.Steps, err)
|
||||||
|
|
||||||
// run after scenario handlers
|
// run after scenario handlers
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче