Added Pickle and PickleStep results to the in-mem storage
Этот коммит содержится в:
родитель
f50bd30ec0
коммит
cd7663fccf
12 изменённых файлов: 508 добавлений и 384 удалений
156
fmt.go
156
fmt.go
|
@ -139,25 +139,25 @@ func (st stepResultStatus) String() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stepResult struct {
|
type pickleStepResult struct {
|
||||||
status stepResultStatus
|
Status stepResultStatus
|
||||||
time time.Time
|
finishedAt time.Time
|
||||||
err error
|
err error
|
||||||
|
|
||||||
pickleID string
|
PickleID string
|
||||||
pickleStepID string
|
PickleStepID string
|
||||||
|
|
||||||
def *StepDefinition
|
def *StepDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStepResult(pickleID, pickleStepID string, match *StepDefinition) *stepResult {
|
func newStepResult(pickleID, pickleStepID string, match *StepDefinition) pickleStepResult {
|
||||||
return &stepResult{time: timeNowFunc(), pickleID: pickleID, pickleStepID: pickleStepID, def: match}
|
return pickleStepResult{finishedAt: timeNowFunc(), PickleID: pickleID, PickleStepID: pickleStepID, def: match}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBaseFmt(suite string, out io.Writer) *basefmt {
|
func newBaseFmt(suite string, out io.Writer) *basefmt {
|
||||||
return &basefmt{
|
return &basefmt{
|
||||||
suiteName: suite,
|
suiteName: suite,
|
||||||
started: timeNowFunc(),
|
startedAt: timeNowFunc(),
|
||||||
indent: 2,
|
indent: 2,
|
||||||
out: out,
|
out: out,
|
||||||
lock: new(sync.Mutex),
|
lock: new(sync.Mutex),
|
||||||
|
@ -173,8 +173,8 @@ type basefmt struct {
|
||||||
|
|
||||||
storage *storage
|
storage *storage
|
||||||
|
|
||||||
started time.Time
|
startedAt time.Time
|
||||||
features []*feature
|
features []*feature
|
||||||
|
|
||||||
firstFeature *bool
|
firstFeature *bool
|
||||||
lock *sync.Mutex
|
lock *sync.Mutex
|
||||||
|
@ -188,10 +188,6 @@ func (f *basefmt) lastFeature() *feature {
|
||||||
return f.features[len(f.features)-1]
|
return f.features[len(f.features)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) lastStepResult() *stepResult {
|
|
||||||
return f.lastFeature().lastStepResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *basefmt) findFeature(scenarioAstID string) *feature {
|
func (f *basefmt) findFeature(scenarioAstID string) *feature {
|
||||||
for _, ft := range f.features {
|
for _, ft := range f.features {
|
||||||
if sc := ft.findScenario(scenarioAstID); sc != nil {
|
if sc := ft.findScenario(scenarioAstID); sc != nil {
|
||||||
|
@ -250,15 +246,7 @@ func (f *basefmt) TestRunStarted() {
|
||||||
f.firstFeature = &firstFeature
|
f.firstFeature = &firstFeature
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Pickle(p *messages.Pickle) {
|
func (f *basefmt) Pickle(p *messages.Pickle) {}
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
feature := f.features[len(f.features)-1]
|
|
||||||
|
|
||||||
pr := pickleResult{pickleID: p.Id, time: timeNowFunc()}
|
|
||||||
feature.pickleResults = append(feature.pickleResults, &pr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *basefmt) Defined(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition) {}
|
func (f *basefmt) Defined(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition) {}
|
||||||
|
|
||||||
|
@ -268,94 +256,60 @@ func (f *basefmt) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
||||||
|
|
||||||
*f.firstFeature = false
|
*f.firstFeature = false
|
||||||
|
|
||||||
f.features = append(f.features, &feature{path: p, GherkinDocument: ft, time: timeNowFunc()})
|
f.features = append(f.features, &feature{GherkinDocument: ft, time: timeNowFunc()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *basefmt) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
s := newStepResult(pickle.Id, step.Id, match)
|
|
||||||
s.status = passed
|
|
||||||
f.lastFeature().appendStepResult(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *basefmt) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
s := newStepResult(pickle.Id, step.Id, match)
|
|
||||||
s.status = skipped
|
|
||||||
f.lastFeature().appendStepResult(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *basefmt) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
s := newStepResult(pickle.Id, step.Id, match)
|
|
||||||
s.status = undefined
|
|
||||||
f.lastFeature().appendStepResult(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
func (f *basefmt) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
s := newStepResult(pickle.Id, step.Id, match)
|
|
||||||
s.status = failed
|
|
||||||
s.err = err
|
|
||||||
f.lastFeature().appendStepResult(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *basefmt) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
s := newStepResult(pickle.Id, step.Id, match)
|
|
||||||
s.status = pending
|
|
||||||
f.lastFeature().appendStepResult(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Summary() {
|
func (f *basefmt) Summary() {
|
||||||
var totalSc, passedSc, undefinedSc int
|
var totalSc, passedSc, undefinedSc int
|
||||||
var totalSt, passedSt, failedSt, skippedSt, pendingSt, undefinedSt int
|
var totalSt, passedSt, failedSt, skippedSt, pendingSt, undefinedSt int
|
||||||
|
|
||||||
for _, feat := range f.features {
|
pickleResults := f.storage.mustGetPickleResults()
|
||||||
for _, pr := range feat.pickleResults {
|
for _, pr := range pickleResults {
|
||||||
var prStatus stepResultStatus
|
var prStatus stepResultStatus
|
||||||
totalSc++
|
totalSc++
|
||||||
|
|
||||||
if len(pr.stepResults) == 0 {
|
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pr.PickleID)
|
||||||
|
|
||||||
|
if len(pickleStepResults) == 0 {
|
||||||
|
prStatus = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sr := range pickleStepResults {
|
||||||
|
totalSt++
|
||||||
|
|
||||||
|
switch sr.Status {
|
||||||
|
case passed:
|
||||||
|
prStatus = passed
|
||||||
|
passedSt++
|
||||||
|
case failed:
|
||||||
|
prStatus = failed
|
||||||
|
failedSt++
|
||||||
|
case skipped:
|
||||||
|
skippedSt++
|
||||||
|
case undefined:
|
||||||
prStatus = undefined
|
prStatus = undefined
|
||||||
|
undefinedSt++
|
||||||
|
case pending:
|
||||||
|
prStatus = pending
|
||||||
|
pendingSt++
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, sr := range pr.stepResults {
|
if prStatus == passed {
|
||||||
totalSt++
|
passedSc++
|
||||||
|
} else if prStatus == undefined {
|
||||||
switch sr.status {
|
undefinedSc++
|
||||||
case passed:
|
|
||||||
prStatus = passed
|
|
||||||
passedSt++
|
|
||||||
case failed:
|
|
||||||
prStatus = failed
|
|
||||||
failedSt++
|
|
||||||
case skipped:
|
|
||||||
skippedSt++
|
|
||||||
case undefined:
|
|
||||||
prStatus = undefined
|
|
||||||
undefinedSt++
|
|
||||||
case pending:
|
|
||||||
prStatus = pending
|
|
||||||
pendingSt++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if prStatus == passed {
|
|
||||||
passedSc++
|
|
||||||
} else if prStatus == undefined {
|
|
||||||
undefinedSc++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +339,7 @@ func (f *basefmt) Summary() {
|
||||||
scenarios = append(scenarios, green(fmt.Sprintf("%d passed", passedSc)))
|
scenarios = append(scenarios, green(fmt.Sprintf("%d passed", passedSc)))
|
||||||
}
|
}
|
||||||
scenarios = append(scenarios, parts...)
|
scenarios = append(scenarios, parts...)
|
||||||
elapsed := timeNowFunc().Sub(f.started)
|
elapsed := timeNowFunc().Sub(f.startedAt)
|
||||||
|
|
||||||
fmt.Fprintln(f.out, "")
|
fmt.Fprintln(f.out, "")
|
||||||
|
|
||||||
|
@ -437,22 +391,8 @@ func (f *basefmt) Copy(cf ConcurrentFormatter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) findStepResults(status stepResultStatus) (res []*stepResult) {
|
|
||||||
for _, feat := range f.features {
|
|
||||||
for _, pr := range feat.pickleResults {
|
|
||||||
for _, sr := range pr.stepResults {
|
|
||||||
if sr.status == status {
|
|
||||||
res = append(res, sr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *basefmt) snippets() string {
|
func (f *basefmt) snippets() string {
|
||||||
undefinedStepResults := f.findStepResults(undefined)
|
undefinedStepResults := f.storage.mustGetPickleStepResultsByStatus(undefined)
|
||||||
if len(undefinedStepResults) == 0 {
|
if len(undefinedStepResults) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -461,7 +401,7 @@ func (f *basefmt) snippets() string {
|
||||||
var snips []undefinedSnippet
|
var snips []undefinedSnippet
|
||||||
// build snippets
|
// build snippets
|
||||||
for _, u := range undefinedStepResults {
|
for _, u := range undefinedStepResults {
|
||||||
pickleStep := f.storage.mustGetPickleStep(u.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(u.PickleStepID)
|
||||||
|
|
||||||
steps := []string{pickleStep.Text}
|
steps := []string{pickleStep.Text}
|
||||||
arg := pickleStep.Argument
|
arg := pickleStep.Argument
|
||||||
|
|
|
@ -17,6 +17,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cucumber/messages-go/v10"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -61,7 +63,11 @@ func (f *cukefmt) buildCukeFeatures(features []*feature) (res []cukeFeatureJSON)
|
||||||
|
|
||||||
for idx, feat := range features {
|
for idx, feat := range features {
|
||||||
cukeFeature := buildCukeFeature(feat)
|
cukeFeature := buildCukeFeature(feat)
|
||||||
cukeFeature.Elements = f.buildCukeElements(feat.pickleResults)
|
|
||||||
|
pickles := f.storage.mustGetPickles(feat.Uri)
|
||||||
|
sort.Sort(sortPicklesByID(pickles))
|
||||||
|
|
||||||
|
cukeFeature.Elements = f.buildCukeElements(pickles)
|
||||||
|
|
||||||
for jdx, elem := range cukeFeature.Elements {
|
for jdx, elem := range cukeFeature.Elements {
|
||||||
elem.ID = cukeFeature.ID + ";" + makeCukeID(elem.Name) + elem.ID
|
elem.ID = cukeFeature.ID + ";" + makeCukeID(elem.Name) + elem.ID
|
||||||
|
@ -75,26 +81,29 @@ func (f *cukefmt) buildCukeFeatures(features []*feature) (res []cukeFeatureJSON)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) buildCukeElements(pickleResults []*pickleResult) (res []cukeElement) {
|
func (f *cukefmt) buildCukeElements(pickles []*messages.Pickle) (res []cukeElement) {
|
||||||
res = make([]cukeElement, len(pickleResults))
|
res = make([]cukeElement, len(pickles))
|
||||||
|
|
||||||
for idx, pickleResult := range pickleResults {
|
for idx, pickle := range pickles {
|
||||||
pickle := f.storage.mustGetPickle(pickleResult.pickleID)
|
pickleResult := f.storage.mustGetPickleResult(pickle.Id)
|
||||||
|
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
|
|
||||||
cukeElement := f.buildCukeElement(pickle.Name, pickle.AstNodeIds)
|
cukeElement := f.buildCukeElement(pickle.Name, pickle.AstNodeIds)
|
||||||
|
|
||||||
stepStartedAt := pickleResult.startedAt()
|
stepStartedAt := pickleResult.StartedAt
|
||||||
|
|
||||||
cukeElement.Steps = make([]cukeStep, len(pickleResult.stepResults))
|
cukeElement.Steps = make([]cukeStep, len(pickleStepResults))
|
||||||
for jdx, stepResult := range pickleResult.stepResults {
|
sort.Sort(sortPickleStepResultsByPickleStepID(pickleStepResults))
|
||||||
cukeStep := f.buildCukeStep(stepResult)
|
|
||||||
|
|
||||||
stepResultFinishedAt := stepResult.time
|
for jdx, stepResult := range pickleStepResults {
|
||||||
|
cukeStep := f.buildCukeStep(pickle, stepResult)
|
||||||
|
|
||||||
|
stepResultFinishedAt := stepResult.finishedAt
|
||||||
d := int(stepResultFinishedAt.Sub(stepStartedAt).Nanoseconds())
|
d := int(stepResultFinishedAt.Sub(stepStartedAt).Nanoseconds())
|
||||||
stepStartedAt = stepResultFinishedAt
|
stepStartedAt = stepResultFinishedAt
|
||||||
|
|
||||||
cukeStep.Result.Duration = &d
|
cukeStep.Result.Duration = &d
|
||||||
if stepResult.status == undefined || stepResult.status == pending || stepResult.status == skipped {
|
if stepResult.Status == undefined || stepResult.Status == pending || stepResult.Status == skipped {
|
||||||
cukeStep.Result.Duration = nil
|
cukeStep.Result.Duration = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +181,7 @@ type cukeFeatureJSON struct {
|
||||||
|
|
||||||
func buildCukeFeature(feat *feature) cukeFeatureJSON {
|
func buildCukeFeature(feat *feature) cukeFeatureJSON {
|
||||||
cukeFeature := cukeFeatureJSON{
|
cukeFeature := cukeFeatureJSON{
|
||||||
URI: feat.path,
|
URI: feat.Uri,
|
||||||
ID: makeCukeID(feat.Feature.Name),
|
ID: makeCukeID(feat.Feature.Name),
|
||||||
Keyword: feat.Feature.Keyword,
|
Keyword: feat.Feature.Keyword,
|
||||||
Name: feat.Feature.Name,
|
Name: feat.Feature.Name,
|
||||||
|
@ -238,9 +247,8 @@ func (f *cukefmt) buildCukeElement(pickleName string, pickleAstNodeIDs []string)
|
||||||
return cukeElement
|
return cukeElement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) buildCukeStep(stepResult *stepResult) (cukeStep cukeStep) {
|
func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult pickleStepResult) (cukeStep cukeStep) {
|
||||||
pickle := f.storage.mustGetPickle(stepResult.pickleID)
|
pickleStep := f.storage.mustGetPickleStep(stepResult.PickleStepID)
|
||||||
pickleStep := f.storage.mustGetPickleStep(stepResult.pickleStepID)
|
|
||||||
step := f.findStep(pickleStep.AstNodeIds[0])
|
step := f.findStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
line := step.Location.Line
|
line := step.Location.Line
|
||||||
|
@ -277,12 +285,12 @@ func (f *cukefmt) buildCukeStep(stepResult *stepResult) (cukeStep cukeStep) {
|
||||||
cukeStep.Match.Location = strings.Split(stepResult.def.definitionID(), " ")[0]
|
cukeStep.Match.Location = strings.Split(stepResult.def.definitionID(), " ")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
cukeStep.Result.Status = stepResult.status.String()
|
cukeStep.Result.Status = stepResult.Status.String()
|
||||||
if stepResult.err != nil {
|
if stepResult.err != nil {
|
||||||
cukeStep.Result.Error = stepResult.err.Error()
|
cukeStep.Result.Error = stepResult.err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if stepResult.status == undefined || stepResult.status == pending {
|
if stepResult.Status == undefined || stepResult.Status == pending {
|
||||||
cukeStep.Match.Location = fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line)
|
cukeStep.Match.Location = fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,10 +103,13 @@ func (f *events) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
||||||
func (f *events) Summary() {
|
func (f *events) Summary() {
|
||||||
// @TODO: determine status
|
// @TODO: determine status
|
||||||
status := passed
|
status := passed
|
||||||
if len(f.findStepResults(failed)) > 0 {
|
|
||||||
|
f.storage.mustGetPickleStepResultsByStatus(failed)
|
||||||
|
|
||||||
|
if len(f.storage.mustGetPickleStepResultsByStatus(failed)) > 0 {
|
||||||
status = failed
|
status = failed
|
||||||
} else if len(f.findStepResults(passed)) == 0 {
|
} else if len(f.storage.mustGetPickleStepResultsByStatus(passed)) == 0 {
|
||||||
if len(f.findStepResults(undefined)) > len(f.findStepResults(pending)) {
|
if len(f.storage.mustGetPickleStepResultsByStatus(undefined)) > len(f.storage.mustGetPickleStepResultsByStatus(pending)) {
|
||||||
status = undefined
|
status = undefined
|
||||||
} else {
|
} else {
|
||||||
status = pending
|
status = pending
|
||||||
|
@ -145,13 +148,13 @@ func (f *events) Copy(cf ConcurrentFormatter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) step(pickle *messages.Pickle, res *stepResult) {
|
func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(res.pickleStepID)
|
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStep.Id)
|
||||||
step := f.findStep(pickleStep.AstNodeIds[0])
|
step := f.findStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
var errMsg string
|
var errMsg string
|
||||||
if res.err != nil {
|
if pickleStepResult.err != nil {
|
||||||
errMsg = res.err.Error()
|
errMsg = pickleStepResult.err.Error()
|
||||||
}
|
}
|
||||||
f.event(&struct {
|
f.event(&struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
|
@ -163,15 +166,16 @@ func (f *events) step(pickle *messages.Pickle, res *stepResult) {
|
||||||
"TestStepFinished",
|
"TestStepFinished",
|
||||||
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
timeNowFunc().UnixNano() / nanoSec,
|
||||||
res.status.String(),
|
pickleStepResult.Status.String(),
|
||||||
errMsg,
|
errMsg,
|
||||||
})
|
})
|
||||||
|
|
||||||
if isLastStep(pickle, pickleStep) {
|
if isLastStep(pickle, pickleStep) {
|
||||||
var status string
|
var status string
|
||||||
|
|
||||||
for _, stepResult := range f.lastFeature().lastPickleResult().stepResults {
|
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
switch stepResult.status {
|
for _, stepResult := range pickleStepResults {
|
||||||
|
switch stepResult.Status {
|
||||||
case passed:
|
case passed:
|
||||||
status = passed.String()
|
status = passed.String()
|
||||||
case failed:
|
case failed:
|
||||||
|
@ -250,7 +254,7 @@ func (f *events) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(pickle, f.lastStepResult())
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -259,7 +263,7 @@ func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(pickle, f.lastStepResult())
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -268,7 +272,7 @@ func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(pickle, f.lastStepResult())
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||||
|
@ -277,7 +281,7 @@ func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(pickle, f.lastStepResult())
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -286,7 +290,7 @@ func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(pickle, f.lastStepResult())
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) scenarioLocation(pickle *messages.Pickle) string {
|
func (f *events) scenarioLocation(pickle *messages.Pickle) string {
|
||||||
|
|
46
fmt_junit.go
46
fmt_junit.go
|
@ -57,30 +57,53 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||||
suite := junitPackageSuite{
|
suite := junitPackageSuite{
|
||||||
Name: f.suiteName,
|
Name: f.suiteName,
|
||||||
TestSuites: make([]*junitTestSuite, len(f.features)),
|
TestSuites: make([]*junitTestSuite, len(f.features)),
|
||||||
Time: junitTimeDuration(f.started, timeNowFunc()),
|
Time: junitTimeDuration(f.startedAt, timeNowFunc()),
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sortByName(f.features))
|
sort.Sort(sortByName(f.features))
|
||||||
|
|
||||||
for idx, feat := range f.features {
|
for idx, feat := range f.features {
|
||||||
|
pickles := f.storage.mustGetPickles(feat.Uri)
|
||||||
|
sort.Sort(sortPicklesByID(pickles))
|
||||||
|
|
||||||
|
var finishedAt = feat.startedAt()
|
||||||
|
|
||||||
|
if len(pickles) > 0 {
|
||||||
|
lastPickle := pickles[len(pickles)-1]
|
||||||
|
|
||||||
|
if len(lastPickle.Steps) > 0 {
|
||||||
|
lastStep := lastPickle.Steps[len(lastPickle.Steps)-1]
|
||||||
|
lastPickleStepResult := f.storage.mustGetPickleStepResult(lastStep.Id)
|
||||||
|
finishedAt = lastPickleStepResult.finishedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ts := junitTestSuite{
|
ts := junitTestSuite{
|
||||||
Name: feat.GherkinDocument.Feature.Name,
|
Name: feat.GherkinDocument.Feature.Name,
|
||||||
Time: junitTimeDuration(feat.startedAt(), feat.finishedAt()),
|
Time: junitTimeDuration(feat.startedAt(), finishedAt),
|
||||||
TestCases: make([]*junitTestCase, len(feat.pickleResults)),
|
TestCases: make([]*junitTestCase, len(pickles)),
|
||||||
}
|
}
|
||||||
|
|
||||||
var testcaseNames = make(map[string]int)
|
var testcaseNames = make(map[string]int)
|
||||||
for _, pickleResult := range feat.pickleResults {
|
for _, pickle := range pickles {
|
||||||
pickle := f.storage.mustGetPickle(pickleResult.pickleID)
|
|
||||||
testcaseNames[pickle.Name] = testcaseNames[pickle.Name] + 1
|
testcaseNames[pickle.Name] = testcaseNames[pickle.Name] + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var outlineNo = make(map[string]int)
|
var outlineNo = make(map[string]int)
|
||||||
for idx, pickleResult := range feat.pickleResults {
|
for idx, pickle := range pickles {
|
||||||
tc := junitTestCase{}
|
tc := junitTestCase{}
|
||||||
tc.Time = junitTimeDuration(pickleResult.startedAt(), pickleResult.finishedAt())
|
|
||||||
|
|
||||||
pickle := f.storage.mustGetPickle(pickleResult.pickleID)
|
pickleResult := f.storage.mustGetPickleResult(pickle.Id)
|
||||||
|
|
||||||
|
var finishedAt = pickleResult.StartedAt
|
||||||
|
|
||||||
|
if len(pickle.Steps) > 0 {
|
||||||
|
lastStep := pickle.Steps[len(pickle.Steps)-1]
|
||||||
|
lastPickleStepResult := f.storage.mustGetPickleStepResult(lastStep.Id)
|
||||||
|
finishedAt = lastPickleStepResult.finishedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
tc.Time = junitTimeDuration(pickleResult.StartedAt, finishedAt)
|
||||||
|
|
||||||
tc.Name = pickle.Name
|
tc.Name = pickle.Name
|
||||||
if testcaseNames[tc.Name] > 1 {
|
if testcaseNames[tc.Name] > 1 {
|
||||||
|
@ -91,10 +114,11 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||||
ts.Tests++
|
ts.Tests++
|
||||||
suite.Tests++
|
suite.Tests++
|
||||||
|
|
||||||
for _, stepResult := range pickleResult.stepResults {
|
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
pickleStep := f.storage.mustGetPickleStep(stepResult.pickleStepID)
|
for _, stepResult := range pickleStepResults {
|
||||||
|
pickleStep := f.storage.mustGetPickleStep(stepResult.PickleStepID)
|
||||||
|
|
||||||
switch stepResult.status {
|
switch stepResult.Status {
|
||||||
case passed:
|
case passed:
|
||||||
tc.Status = passed.String()
|
tc.Status = passed.String()
|
||||||
case failed:
|
case failed:
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ func (f *pretty) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.printStep(pickle, f.lastStepResult())
|
f.printStep(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -70,7 +71,7 @@ func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.printStep(pickle, f.lastStepResult())
|
f.printStep(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -79,7 +80,7 @@ func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.printStep(pickle, f.lastStepResult())
|
f.printStep(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||||
|
@ -88,7 +89,7 @@ func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.printStep(pickle, f.lastStepResult())
|
f.printStep(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *pretty) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -97,7 +98,7 @@ func (f *pretty) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.printStep(pickle, f.lastStepResult())
|
f.printStep(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Sync(cf ConcurrentFormatter) {
|
func (f *pretty) Sync(cf ConcurrentFormatter) {
|
||||||
|
@ -145,7 +146,7 @@ func (f *pretty) scenarioLengths(scenarioAstID string) (scenarioHeaderLength int
|
||||||
|
|
||||||
func (f *pretty) printScenarioHeader(astScenario *messages.GherkinDocument_Feature_Scenario, spaceFilling int) {
|
func (f *pretty) printScenarioHeader(astScenario *messages.GherkinDocument_Feature_Scenario, spaceFilling int) {
|
||||||
text := s(f.indent) + keywordAndName(astScenario.Keyword, astScenario.Name)
|
text := s(f.indent) + keywordAndName(astScenario.Keyword, astScenario.Name)
|
||||||
text += s(spaceFilling) + f.line(f.lastFeature().path, astScenario.Location)
|
text += s(spaceFilling) + f.line(f.lastFeature().Uri, astScenario.Location)
|
||||||
fmt.Fprintln(f.out, "\n"+text)
|
fmt.Fprintln(f.out, "\n"+text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,12 +193,15 @@ func (f *pretty) printUndefinedPickle(pickle *messages.Pickle) {
|
||||||
|
|
||||||
// Summary sumarize the feature formatter output
|
// Summary sumarize the feature formatter output
|
||||||
func (f *pretty) Summary() {
|
func (f *pretty) Summary() {
|
||||||
failedStepResults := f.findStepResults(failed)
|
failedStepResults := f.storage.mustGetPickleStepResultsByStatus(failed)
|
||||||
if len(failedStepResults) > 0 {
|
if len(failedStepResults) > 0 {
|
||||||
fmt.Fprintln(f.out, "\n--- "+red("Failed steps:")+"\n")
|
fmt.Fprintln(f.out, "\n--- "+red("Failed steps:")+"\n")
|
||||||
|
|
||||||
|
sort.Sort(sortPickleStepResultsByPickleStepID(failedStepResults))
|
||||||
|
|
||||||
for _, fail := range failedStepResults {
|
for _, fail := range failedStepResults {
|
||||||
pickle := f.storage.mustGetPickle(fail.pickleID)
|
pickle := f.storage.mustGetPickle(fail.PickleID)
|
||||||
pickleStep := f.storage.mustGetPickleStep(fail.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(fail.PickleStepID)
|
||||||
|
|
||||||
feature := f.findFeature(pickle.AstNodeIds[0])
|
feature := f.findFeature(pickle.AstNodeIds[0])
|
||||||
|
|
||||||
|
@ -207,8 +211,8 @@ func (f *pretty) Summary() {
|
||||||
astStep := f.findStep(pickleStep.AstNodeIds[0])
|
astStep := f.findStep(pickleStep.AstNodeIds[0])
|
||||||
stepDesc := strings.TrimSpace(astStep.Keyword) + " " + pickleStep.Text
|
stepDesc := strings.TrimSpace(astStep.Keyword) + " " + pickleStep.Text
|
||||||
|
|
||||||
fmt.Fprintln(f.out, s(f.indent)+red(scenarioDesc)+f.line(feature.path, astScenario.Location))
|
fmt.Fprintln(f.out, s(f.indent)+red(scenarioDesc)+f.line(feature.Uri, astScenario.Location))
|
||||||
fmt.Fprintln(f.out, s(f.indent*2)+red(stepDesc)+f.line(feature.path, astStep.Location))
|
fmt.Fprintln(f.out, s(f.indent*2)+red(stepDesc)+f.line(feature.Uri, astStep.Location))
|
||||||
fmt.Fprintln(f.out, s(f.indent*3)+red("Error: ")+redb(fmt.Sprintf("%+v", fail.err))+"\n")
|
fmt.Fprintln(f.out, s(f.indent*3)+red("Error: ")+redb(fmt.Sprintf("%+v", fail.err))+"\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +231,9 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
||||||
printExampleHeader := exampleTable.TableBody[0].Id == exampleRow.Id
|
printExampleHeader := exampleTable.TableBody[0].Id == exampleRow.Id
|
||||||
firstExamplesTable := astScenario.Examples[0].Location.Line == exampleTable.Location.Line
|
firstExamplesTable := astScenario.Examples[0].Location.Line == exampleTable.Location.Line
|
||||||
|
|
||||||
firstExecutedScenarioStep := len(f.lastFeature().lastPickleResult().stepResults) == backgroundSteps+1
|
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
|
|
||||||
|
firstExecutedScenarioStep := len(pickleStepResults) == backgroundSteps+1
|
||||||
if firstExamplesTable && printExampleHeader && firstExecutedScenarioStep {
|
if firstExamplesTable && printExampleHeader && firstExecutedScenarioStep {
|
||||||
f.printScenarioHeader(astScenario, maxLength-scenarioHeaderLength)
|
f.printScenarioHeader(astScenario, maxLength-scenarioHeaderLength)
|
||||||
}
|
}
|
||||||
|
@ -237,32 +243,31 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lastStep := len(f.lastFeature().lastPickleResult().stepResults) == len(pickle.Steps)
|
lastStep := len(pickleStepResults) == len(pickle.Steps)
|
||||||
if !lastStep {
|
if !lastStep {
|
||||||
// do not print examples unless all steps has finished
|
// do not print examples unless all steps has finished
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPickleResult := f.lastFeature().lastPickleResult()
|
for _, result := range pickleStepResults {
|
||||||
for _, result := range lastPickleResult.stepResults {
|
|
||||||
// determine example row status
|
// determine example row status
|
||||||
switch {
|
switch {
|
||||||
case result.status == failed:
|
case result.Status == failed:
|
||||||
errorMsg = result.err.Error()
|
errorMsg = result.err.Error()
|
||||||
clr = result.status.clr()
|
clr = result.Status.clr()
|
||||||
case result.status == undefined || result.status == pending:
|
case result.Status == undefined || result.Status == pending:
|
||||||
clr = result.status.clr()
|
clr = result.Status.clr()
|
||||||
case result.status == skipped && clr == nil:
|
case result.Status == skipped && clr == nil:
|
||||||
clr = cyan
|
clr = cyan
|
||||||
}
|
}
|
||||||
|
|
||||||
if firstExamplesTable && printExampleHeader {
|
if firstExamplesTable && printExampleHeader {
|
||||||
// in first example, we need to print steps
|
// in first example, we need to print steps
|
||||||
var text string
|
|
||||||
|
|
||||||
pickleStep := f.storage.mustGetPickleStep(result.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(result.PickleStepID)
|
||||||
astStep := f.findStep(pickleStep.AstNodeIds[0])
|
astStep := f.findStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
|
var text = ""
|
||||||
if result.def != nil {
|
if result.def != nil {
|
||||||
if m := outlinePlaceholderRegexp.FindAllStringIndex(astStep.Text, -1); len(m) > 0 {
|
if m := outlinePlaceholderRegexp.FindAllStringIndex(astStep.Text, -1); len(m) > 0 {
|
||||||
var pos int
|
var pos int
|
||||||
|
@ -277,16 +282,13 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
||||||
text = cyan(astStep.Text)
|
text = cyan(astStep.Text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pickle := f.storage.mustGetPickle(lastPickleResult.pickleID)
|
|
||||||
|
|
||||||
_, maxLength := f.scenarioLengths(pickle.AstNodeIds[0])
|
_, maxLength := f.scenarioLengths(pickle.AstNodeIds[0])
|
||||||
stepLength := f.lengthPickleStep(astStep.Keyword, astStep.Text)
|
stepLength := f.lengthPickleStep(astStep.Keyword, astStep.Text)
|
||||||
|
|
||||||
text += s(maxLength - stepLength)
|
text += s(maxLength - stepLength)
|
||||||
text += " " + blackb("# "+result.def.definitionID())
|
text += " " + blackb("# "+result.def.definitionID())
|
||||||
} else {
|
|
||||||
text = cyan(astStep.Text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// print the step outline
|
// print the step outline
|
||||||
fmt.Fprintln(f.out, s(f.indent*2)+cyan(strings.TrimSpace(astStep.Keyword))+" "+text)
|
fmt.Fprintln(f.out, s(f.indent*2)+cyan(strings.TrimSpace(astStep.Keyword))+" "+text)
|
||||||
|
|
||||||
|
@ -333,9 +335,7 @@ func (f *pretty) printTableHeader(row *messages.GherkinDocument_Feature_TableRow
|
||||||
f.printTableRow(row, max, cyan)
|
f.printTableRow(row, max, cyan)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printStep(pickle *messages.Pickle, result *stepResult) {
|
func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(result.pickleStepID)
|
|
||||||
|
|
||||||
astBackground := f.findBackground(pickle.AstNodeIds[0])
|
astBackground := f.findBackground(pickle.AstNodeIds[0])
|
||||||
astScenario := f.findScenario(pickle.AstNodeIds[0])
|
astScenario := f.findScenario(pickle.AstNodeIds[0])
|
||||||
astStep := f.findStep(pickleStep.AstNodeIds[0])
|
astStep := f.findStep(pickleStep.AstNodeIds[0])
|
||||||
|
@ -345,14 +345,25 @@ func (f *pretty) printStep(pickle *messages.Pickle, result *stepResult) {
|
||||||
backgroundSteps = len(astBackground.Steps)
|
backgroundSteps = len(astBackground.Steps)
|
||||||
}
|
}
|
||||||
|
|
||||||
astBackgroundStep := backgroundSteps > 0 && backgroundSteps >= len(f.lastFeature().lastPickleResult().stepResults)
|
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
|
astBackgroundStep := backgroundSteps > 0 && backgroundSteps >= len(pickleStepResults)
|
||||||
|
|
||||||
if astBackgroundStep {
|
if astBackgroundStep {
|
||||||
if len(f.lastFeature().pickleResults) > 1 {
|
pickles := f.storage.mustGetPickles(pickle.Uri)
|
||||||
|
|
||||||
|
var pickleResults []pickleResult
|
||||||
|
for _, pickle := range pickles {
|
||||||
|
pr, err := f.storage.getPickleResult(pickle.Id)
|
||||||
|
if err == nil {
|
||||||
|
pickleResults = append(pickleResults, pr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pickleResults) > 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
firstExecutedBackgroundStep := astBackground != nil && len(f.lastFeature().lastPickleResult().stepResults) == 1
|
firstExecutedBackgroundStep := astBackground != nil && len(pickleStepResults) == 1
|
||||||
if firstExecutedBackgroundStep {
|
if firstExecutedBackgroundStep {
|
||||||
fmt.Fprintln(f.out, "\n"+s(f.indent)+keywordAndName(astBackground.Keyword, astBackground.Name))
|
fmt.Fprintln(f.out, "\n"+s(f.indent)+keywordAndName(astBackground.Keyword, astBackground.Name))
|
||||||
}
|
}
|
||||||
|
@ -366,15 +377,16 @@ func (f *pretty) printStep(pickle *messages.Pickle, result *stepResult) {
|
||||||
scenarioHeaderLength, maxLength := f.scenarioLengths(pickle.AstNodeIds[0])
|
scenarioHeaderLength, maxLength := f.scenarioLengths(pickle.AstNodeIds[0])
|
||||||
stepLength := f.lengthPickleStep(astStep.Keyword, pickleStep.Text)
|
stepLength := f.lengthPickleStep(astStep.Keyword, pickleStep.Text)
|
||||||
|
|
||||||
firstExecutedScenarioStep := len(f.lastFeature().lastPickleResult().stepResults) == backgroundSteps+1
|
firstExecutedScenarioStep := len(pickleStepResults) == backgroundSteps+1
|
||||||
if !astBackgroundStep && firstExecutedScenarioStep {
|
if !astBackgroundStep && firstExecutedScenarioStep {
|
||||||
f.printScenarioHeader(astScenario, maxLength-scenarioHeaderLength)
|
f.printScenarioHeader(astScenario, maxLength-scenarioHeaderLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
text := s(f.indent*2) + result.status.clr()(strings.TrimSpace(astStep.Keyword)) + " " + result.status.clr()(pickleStep.Text)
|
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStep.Id)
|
||||||
if result.def != nil {
|
text := s(f.indent*2) + pickleStepResult.Status.clr()(strings.TrimSpace(astStep.Keyword)) + " " + pickleStepResult.Status.clr()(pickleStep.Text)
|
||||||
|
if pickleStepResult.def != nil {
|
||||||
text += s(maxLength - stepLength + 1)
|
text += s(maxLength - stepLength + 1)
|
||||||
text += blackb("# " + result.def.definitionID())
|
text += blackb("# " + pickleStepResult.def.definitionID())
|
||||||
}
|
}
|
||||||
fmt.Fprintln(f.out, text)
|
fmt.Fprintln(f.out, text)
|
||||||
|
|
||||||
|
@ -386,11 +398,11 @@ func (f *pretty) printStep(pickle *messages.Pickle, result *stepResult) {
|
||||||
f.printDocString(docString)
|
f.printDocString(docString)
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.err != nil {
|
if pickleStepResult.err != nil {
|
||||||
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", result.err)))
|
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", pickleStepResult.err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.status == pending {
|
if pickleStepResult.Status == pending {
|
||||||
fmt.Fprintln(f.out, s(f.indent*3)+yellow("TODO: write pending definition"))
|
fmt.Fprintln(f.out, s(f.indent*3)+yellow("TODO: write pending definition"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
@ -39,10 +40,14 @@ func (f *progress) Summary() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var failedStepsOutput []string
|
var failedStepsOutput []string
|
||||||
for _, sr := range f.findStepResults(failed) {
|
|
||||||
if sr.status == failed {
|
failedSteps := f.storage.mustGetPickleStepResultsByStatus(failed)
|
||||||
pickle := f.storage.mustGetPickle(sr.pickleID)
|
sort.Sort(sortPickleStepResultsByPickleStepID(failedSteps))
|
||||||
pickleStep := f.storage.mustGetPickleStep(sr.pickleStepID)
|
|
||||||
|
for _, sr := range failedSteps {
|
||||||
|
if sr.Status == failed {
|
||||||
|
pickle := f.storage.mustGetPickle(sr.PickleID)
|
||||||
|
pickleStep := f.storage.mustGetPickleStep(sr.PickleStepID)
|
||||||
|
|
||||||
sc := f.findScenario(pickle.AstNodeIds[0])
|
sc := f.findScenario(pickle.AstNodeIds[0])
|
||||||
scenarioDesc := fmt.Sprintf("%s: %s", sc.Keyword, pickle.Name)
|
scenarioDesc := fmt.Sprintf("%s: %s", sc.Keyword, pickle.Name)
|
||||||
|
@ -71,8 +76,10 @@ func (f *progress) Summary() {
|
||||||
f.basefmt.Summary()
|
f.basefmt.Summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) step(res *stepResult) {
|
func (f *progress) step(pickleStepID string) {
|
||||||
switch res.status {
|
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStepID)
|
||||||
|
|
||||||
|
switch pickleStepResult.Status {
|
||||||
case passed:
|
case passed:
|
||||||
fmt.Fprint(f.out, green("."))
|
fmt.Fprint(f.out, green("."))
|
||||||
case skipped:
|
case skipped:
|
||||||
|
@ -98,7 +105,7 @@ func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleS
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(f.lastStepResult())
|
f.step(step.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -107,7 +114,7 @@ func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(f.lastStepResult())
|
f.step(step.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -116,7 +123,7 @@ func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pick
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(f.lastStepResult())
|
f.step(step.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||||
|
@ -125,7 +132,7 @@ func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleS
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(f.lastStepResult())
|
f.step(step.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *progress) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||||
|
@ -134,7 +141,7 @@ func (f *progress) Pending(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.step(f.lastStepResult())
|
f.step(step.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Sync(cf ConcurrentFormatter) {
|
func (f *progress) Sync(cf ConcurrentFormatter) {
|
||||||
|
|
19
run.go
19
run.go
|
@ -26,13 +26,15 @@ type scenarioInitializer func(*ScenarioContext)
|
||||||
type runner struct {
|
type runner struct {
|
||||||
randomSeed int64
|
randomSeed int64
|
||||||
stopOnFailure, strict bool
|
stopOnFailure, strict bool
|
||||||
features []*feature
|
|
||||||
fmt Formatter
|
features []*feature
|
||||||
initializer initializer
|
|
||||||
testSuiteInitializer testSuiteInitializer
|
initializer initializer
|
||||||
scenarioInitializer scenarioInitializer
|
testSuiteInitializer testSuiteInitializer
|
||||||
|
scenarioInitializer scenarioInitializer
|
||||||
|
|
||||||
storage *storage
|
storage *storage
|
||||||
|
fmt Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) concurrent(rate int, formatterFn func() Formatter) (failed bool) {
|
func (r *runner) concurrent(rate int, formatterFn func() Formatter) (failed bool) {
|
||||||
|
@ -67,21 +69,24 @@ func (r *runner) concurrent(rate int, formatterFn func() Formatter) (failed bool
|
||||||
|
|
||||||
go func(fail *bool, feat *feature) {
|
go func(fail *bool, feat *feature) {
|
||||||
var fmtCopy Formatter
|
var fmtCopy Formatter
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
<-queue // free a space in queue
|
<-queue // free a space in queue
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if r.stopOnFailure && *fail {
|
if r.stopOnFailure && *fail {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
suite := &Suite{
|
suite := &Suite{
|
||||||
fmt: r.fmt,
|
fmt: r.fmt,
|
||||||
randomSeed: r.randomSeed,
|
randomSeed: r.randomSeed,
|
||||||
stopOnFailure: r.stopOnFailure,
|
stopOnFailure: r.stopOnFailure,
|
||||||
strict: r.strict,
|
strict: r.strict,
|
||||||
features: []*feature{feat},
|
features: []*feature{feat},
|
||||||
|
storage: r.storage,
|
||||||
}
|
}
|
||||||
|
|
||||||
suite.fmt = r.fmt
|
|
||||||
if useFmtCopy {
|
if useFmtCopy {
|
||||||
fmtCopy = formatterFn()
|
fmtCopy = formatterFn()
|
||||||
suite.fmt = fmtCopy
|
suite.fmt = fmtCopy
|
||||||
|
@ -107,11 +112,13 @@ func (r *runner) concurrent(rate int, formatterFn func() Formatter) (failed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
suite.run()
|
suite.run()
|
||||||
|
|
||||||
if suite.failed {
|
if suite.failed {
|
||||||
copyLock.Lock()
|
copyLock.Lock()
|
||||||
*fail = true
|
*fail = true
|
||||||
copyLock.Unlock()
|
copyLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if useFmtCopy {
|
if useFmtCopy {
|
||||||
copyLock.Lock()
|
copyLock.Lock()
|
||||||
|
|
||||||
|
|
179
storage.go
179
storage.go
|
@ -1,6 +1,8 @@
|
||||||
package godog
|
package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
"github.com/hashicorp/go-memdb"
|
"github.com/hashicorp/go-memdb"
|
||||||
)
|
)
|
||||||
|
@ -9,11 +11,20 @@ const (
|
||||||
writeMode bool = true
|
writeMode bool = true
|
||||||
readMode bool = false
|
readMode bool = false
|
||||||
|
|
||||||
tablePickle string = "pickle"
|
tablePickle string = "pickle"
|
||||||
tablePickleIndexID string = "id"
|
tablePickleIndexID string = "id"
|
||||||
|
tablePickleIndexURI string = "uri"
|
||||||
|
|
||||||
tablePickleStep string = "pickle_step"
|
tablePickleStep string = "pickle_step"
|
||||||
tablePickleStepIndexID string = "id"
|
tablePickleStepIndexID string = "id"
|
||||||
|
|
||||||
|
tablePickleResult string = "pickle_result"
|
||||||
|
tablePickleResultIndexPickleID string = "id"
|
||||||
|
|
||||||
|
tablePickleStepResult string = "pickle_step_result"
|
||||||
|
tablePickleStepResultIndexPickleStepID string = "id"
|
||||||
|
tablePickleStepResultIndexPickleID string = "pickle_id"
|
||||||
|
tablePickleStepResultIndexStatus string = "status"
|
||||||
)
|
)
|
||||||
|
|
||||||
type storage struct {
|
type storage struct {
|
||||||
|
@ -32,6 +43,11 @@ func newStorage() *storage {
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Indexer: &memdb.StringFieldIndex{Field: "Id"},
|
Indexer: &memdb.StringFieldIndex{Field: "Id"},
|
||||||
},
|
},
|
||||||
|
tablePickleIndexURI: {
|
||||||
|
Name: tablePickleIndexURI,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{Field: "Uri"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tablePickleStep: {
|
tablePickleStep: {
|
||||||
|
@ -44,6 +60,36 @@ func newStorage() *storage {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
tablePickleResult: {
|
||||||
|
Name: tablePickleResult,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
tablePickleResultIndexPickleID: {
|
||||||
|
Name: tablePickleResultIndexPickleID,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.StringFieldIndex{Field: "PickleID"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tablePickleStepResult: {
|
||||||
|
Name: tablePickleStepResult,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
tablePickleStepResultIndexPickleStepID: {
|
||||||
|
Name: tablePickleStepResultIndexPickleStepID,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.StringFieldIndex{Field: "PickleStepID"},
|
||||||
|
},
|
||||||
|
tablePickleStepResultIndexPickleID: {
|
||||||
|
Name: tablePickleStepResultIndexPickleID,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{Field: "PickleID"},
|
||||||
|
},
|
||||||
|
tablePickleStepResultIndexStatus: {
|
||||||
|
Name: tablePickleStepResultIndexStatus,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.IntFieldIndex{Field: "Status"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,21 +102,20 @@ func newStorage() *storage {
|
||||||
return &storage{db}
|
return &storage{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsertPickle(p *messages.Pickle) (err error) {
|
func (s *storage) mustInsertPickle(p *messages.Pickle) {
|
||||||
txn := s.db.Txn(writeMode)
|
txn := s.db.Txn(writeMode)
|
||||||
|
|
||||||
if err = txn.Insert(tablePickle, p); err != nil {
|
if err := txn.Insert(tablePickle, p); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, step := range p.Steps {
|
for _, step := range p.Steps {
|
||||||
if err = txn.Insert(tablePickleStep, step); err != nil {
|
if err := txn.Insert(tablePickleStep, step); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.Commit()
|
txn.Commit()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickle(id string) *messages.Pickle {
|
func (s *storage) mustGetPickle(id string) *messages.Pickle {
|
||||||
|
@ -88,6 +133,22 @@ func (s *storage) mustGetPickle(id string) *messages.Pickle {
|
||||||
return v.(*messages.Pickle)
|
return v.(*messages.Pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustGetPickles(uri string) (ps []*messages.Pickle) {
|
||||||
|
txn := s.db.Txn(readMode)
|
||||||
|
defer txn.Abort()
|
||||||
|
|
||||||
|
it, err := txn.Get(tablePickle, tablePickleIndexURI, uri)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
|
ps = append(ps, v.(*messages.Pickle))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleStep(id string) *messages.Pickle_PickleStep {
|
func (s *storage) mustGetPickleStep(id string) *messages.Pickle_PickleStep {
|
||||||
txn := s.db.Txn(readMode)
|
txn := s.db.Txn(readMode)
|
||||||
defer txn.Abort()
|
defer txn.Abort()
|
||||||
|
@ -102,3 +163,109 @@ func (s *storage) mustGetPickleStep(id string) *messages.Pickle_PickleStep {
|
||||||
|
|
||||||
return v.(*messages.Pickle_PickleStep)
|
return v.(*messages.Pickle_PickleStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustInsertPickleResult(pr pickleResult) {
|
||||||
|
txn := s.db.Txn(writeMode)
|
||||||
|
|
||||||
|
if err := txn.Insert(tablePickleResult, pr); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
txn.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustInsertPickleStepResult(psr pickleStepResult) {
|
||||||
|
txn := s.db.Txn(writeMode)
|
||||||
|
|
||||||
|
if err := txn.Insert(tablePickleStepResult, psr); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
txn.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustGetPickleResult(id string) pickleResult {
|
||||||
|
pr, err := s.getPickleResult(id)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) getPickleResult(id string) (_ pickleResult, err error) {
|
||||||
|
txn := s.db.Txn(readMode)
|
||||||
|
defer txn.Abort()
|
||||||
|
|
||||||
|
v, err := txn.First(tablePickleResult, tablePickleResultIndexPickleID, id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
} else if v == nil {
|
||||||
|
err = fmt.Errorf("Couldn't find pickle result with ID: %s", id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.(pickleResult), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustGetPickleResults() (prs []pickleResult) {
|
||||||
|
txn := s.db.Txn(readMode)
|
||||||
|
defer txn.Abort()
|
||||||
|
|
||||||
|
it, err := txn.Get(tablePickleResult, tablePickleResultIndexPickleID)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
|
prs = append(prs, v.(pickleResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
return prs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustGetPickleStepResult(id string) pickleStepResult {
|
||||||
|
txn := s.db.Txn(readMode)
|
||||||
|
defer txn.Abort()
|
||||||
|
|
||||||
|
v, err := txn.First(tablePickleStepResult, tablePickleStepResultIndexPickleStepID, id)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else if v == nil {
|
||||||
|
panic("Couldn't find pickle step result with ID: " + id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.(pickleStepResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustGetPickleStepResultsByPickleID(pickleID string) (psrs []pickleStepResult) {
|
||||||
|
txn := s.db.Txn(readMode)
|
||||||
|
defer txn.Abort()
|
||||||
|
|
||||||
|
it, err := txn.Get(tablePickleStepResult, tablePickleStepResultIndexPickleID, pickleID)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
|
psrs = append(psrs, v.(pickleStepResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
return psrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) mustGetPickleStepResultsByStatus(status stepResultStatus) (psrs []pickleStepResult) {
|
||||||
|
txn := s.db.Txn(readMode)
|
||||||
|
defer txn.Abort()
|
||||||
|
|
||||||
|
it, err := txn.Get(tablePickleStepResult, tablePickleStepResultIndexStatus, status)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
|
psrs = append(psrs, v.(pickleStepResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
return psrs
|
||||||
|
}
|
||||||
|
|
138
suite.go
138
suite.go
|
@ -23,12 +23,10 @@ var typeOfBytes = reflect.TypeOf([]byte(nil))
|
||||||
|
|
||||||
type feature struct {
|
type feature struct {
|
||||||
*messages.GherkinDocument
|
*messages.GherkinDocument
|
||||||
pickles []*messages.Pickle
|
pickles []*messages.Pickle
|
||||||
pickleResults []*pickleResult
|
|
||||||
|
|
||||||
time time.Time
|
time time.Time
|
||||||
content []byte
|
content []byte
|
||||||
path string
|
|
||||||
order int
|
order int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,51 +98,44 @@ func (f feature) startedAt() time.Time {
|
||||||
return f.time
|
return f.time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f feature) finishedAt() time.Time {
|
|
||||||
if len(f.pickleResults) == 0 {
|
|
||||||
return f.startedAt()
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.pickleResults[len(f.pickleResults)-1].finishedAt()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f feature) appendStepResult(s *stepResult) {
|
|
||||||
pickles := f.pickleResults[len(f.pickleResults)-1]
|
|
||||||
pickles.stepResults = append(pickles.stepResults, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f feature) lastPickleResult() *pickleResult {
|
|
||||||
return f.pickleResults[len(f.pickleResults)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f feature) lastStepResult() *stepResult {
|
|
||||||
last := f.lastPickleResult()
|
|
||||||
return last.stepResults[len(last.stepResults)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortByName []*feature
|
type sortByName []*feature
|
||||||
|
|
||||||
func (s sortByName) Len() int { return len(s) }
|
func (s sortByName) Len() int { return len(s) }
|
||||||
func (s sortByName) Less(i, j int) bool { return s[i].Feature.Name < s[j].Feature.Name }
|
func (s sortByName) Less(i, j int) bool { return s[i].Feature.Name < s[j].Feature.Name }
|
||||||
func (s sortByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s sortByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
type pickleResult struct {
|
type sortPicklesByID []*messages.Pickle
|
||||||
pickleID string
|
|
||||||
|
|
||||||
time time.Time
|
func (s sortPicklesByID) Len() int { return len(s) }
|
||||||
stepResults []*stepResult
|
func (s sortPicklesByID) Less(i, j int) bool {
|
||||||
|
iID := mustConvertStringToInt(s[i].Id)
|
||||||
|
jID := mustConvertStringToInt(s[j].Id)
|
||||||
|
return iID < jID
|
||||||
}
|
}
|
||||||
|
func (s sortPicklesByID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
func (s pickleResult) startedAt() time.Time {
|
type sortPickleStepResultsByPickleStepID []pickleStepResult
|
||||||
return s.time
|
|
||||||
|
func (s sortPickleStepResultsByPickleStepID) Len() int { return len(s) }
|
||||||
|
func (s sortPickleStepResultsByPickleStepID) Less(i, j int) bool {
|
||||||
|
iID := mustConvertStringToInt(s[i].PickleStepID)
|
||||||
|
jID := mustConvertStringToInt(s[j].PickleStepID)
|
||||||
|
return iID < jID
|
||||||
}
|
}
|
||||||
|
func (s sortPickleStepResultsByPickleStepID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
func (s pickleResult) finishedAt() time.Time {
|
func mustConvertStringToInt(s string) int {
|
||||||
if len(s.stepResults) == 0 {
|
i, err := strconv.Atoi(s)
|
||||||
return s.startedAt()
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.stepResults[len(s.stepResults)-1].time
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
type pickleResult struct {
|
||||||
|
PickleID string
|
||||||
|
StartedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrUndefined is returned in case if step definition was not found
|
// ErrUndefined is returned in case if step definition was not found
|
||||||
|
@ -172,7 +163,9 @@ var ErrPending = fmt.Errorf("step implementation is pending")
|
||||||
type Suite struct {
|
type Suite struct {
|
||||||
steps []*StepDefinition
|
steps []*StepDefinition
|
||||||
features []*feature
|
features []*feature
|
||||||
fmt Formatter
|
|
||||||
|
fmt Formatter
|
||||||
|
storage *storage
|
||||||
|
|
||||||
failed bool
|
failed bool
|
||||||
randomSeed int64
|
randomSeed int64
|
||||||
|
@ -417,12 +410,24 @@ func (s *Suite) runStep(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sr := newStepResult(pickle.Id, step.Id, match)
|
||||||
|
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
|
sr.Status = passed
|
||||||
|
s.storage.mustInsertPickleStepResult(sr)
|
||||||
|
|
||||||
s.fmt.Passed(pickle, step, match)
|
s.fmt.Passed(pickle, step, match)
|
||||||
case ErrPending:
|
case ErrPending:
|
||||||
|
sr.Status = pending
|
||||||
|
s.storage.mustInsertPickleStepResult(sr)
|
||||||
|
|
||||||
s.fmt.Pending(pickle, step, match)
|
s.fmt.Pending(pickle, step, match)
|
||||||
default:
|
default:
|
||||||
|
sr.Status = failed
|
||||||
|
sr.err = err
|
||||||
|
s.storage.mustInsertPickleStepResult(sr)
|
||||||
|
|
||||||
s.fmt.Failed(pickle, step, match, err)
|
s.fmt.Failed(pickle, step, match, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,11 +450,20 @@ func (s *Suite) runStep(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
undefined: undef,
|
undefined: undef,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sr := newStepResult(pickle.Id, step.Id, match)
|
||||||
|
sr.Status = undefined
|
||||||
|
s.storage.mustInsertPickleStepResult(sr)
|
||||||
|
|
||||||
s.fmt.Undefined(pickle, step, match)
|
s.fmt.Undefined(pickle, step, match)
|
||||||
return ErrUndefined
|
return ErrUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if prevStepErr != nil {
|
if prevStepErr != nil {
|
||||||
|
sr := newStepResult(pickle.Id, step.Id, match)
|
||||||
|
sr.Status = skipped
|
||||||
|
s.storage.mustInsertPickleStepResult(sr)
|
||||||
|
|
||||||
s.fmt.Skipped(pickle, step, match)
|
s.fmt.Skipped(pickle, step, match)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -575,7 +589,7 @@ func (s *Suite) runFeature(f *feature) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.fmt.Feature(f.GherkinDocument, f.path, f.content)
|
s.fmt.Feature(f.GherkinDocument, f.Uri, f.content)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if !isEmptyFeature(f.pickles) {
|
if !isEmptyFeature(f.pickles) {
|
||||||
|
@ -613,6 +627,9 @@ func isEmptyFeature(pickles []*messages.Pickle) bool {
|
||||||
|
|
||||||
func (s *Suite) runPickle(pickle *messages.Pickle) (err error) {
|
func (s *Suite) runPickle(pickle *messages.Pickle) (err error) {
|
||||||
if len(pickle.Steps) == 0 {
|
if len(pickle.Steps) == 0 {
|
||||||
|
pr := pickleResult{PickleID: pickle.Id, StartedAt: timeNowFunc()}
|
||||||
|
s.storage.mustInsertPickleResult(pr)
|
||||||
|
|
||||||
s.fmt.Pickle(pickle)
|
s.fmt.Pickle(pickle)
|
||||||
return ErrUndefined
|
return ErrUndefined
|
||||||
}
|
}
|
||||||
|
@ -622,6 +639,9 @@ func (s *Suite) runPickle(pickle *messages.Pickle) (err error) {
|
||||||
f(pickle)
|
f(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pr := pickleResult{PickleID: pickle.Id, StartedAt: timeNowFunc()}
|
||||||
|
s.storage.mustInsertPickleResult(pr)
|
||||||
|
|
||||||
s.fmt.Pickle(pickle)
|
s.fmt.Pickle(pickle)
|
||||||
|
|
||||||
// scenario
|
// scenario
|
||||||
|
@ -673,6 +693,7 @@ func parseFeatureFile(path string, newIDFunc func() string) (*feature, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -681,14 +702,11 @@ func parseFeatureFile(path string, newIDFunc func() string) (*feature, error) {
|
||||||
return nil, fmt.Errorf("%s - %v", path, err)
|
return nil, fmt.Errorf("%s - %v", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gherkinDocument.Uri = path
|
||||||
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
|
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
|
||||||
|
|
||||||
return &feature{
|
f := feature{GherkinDocument: gherkinDocument, pickles: pickles, content: buf.Bytes()}
|
||||||
GherkinDocument: gherkinDocument,
|
return &f, nil
|
||||||
pickles: pickles,
|
|
||||||
content: buf.Bytes(),
|
|
||||||
path: path,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
||||||
|
@ -710,6 +728,7 @@ func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
features = append(features, feat)
|
features = append(features, feat)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -751,10 +770,12 @@ func parsePath(path string) ([]*feature, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
||||||
byPath := make(map[string]*feature)
|
|
||||||
var order int
|
var order int
|
||||||
|
|
||||||
|
uniqueFeatureURI := make(map[string]*feature)
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
feats, err := parsePath(path)
|
feats, err := parsePath(path)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case os.IsNotExist(err):
|
case os.IsNotExist(err):
|
||||||
return nil, fmt.Errorf(`feature path "%s" is not available`, path)
|
return nil, fmt.Errorf(`feature path "%s" is not available`, path)
|
||||||
|
@ -765,50 +786,49 @@ func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ft := range feats {
|
for _, ft := range feats {
|
||||||
if _, duplicate := byPath[ft.path]; duplicate {
|
if _, duplicate := uniqueFeatureURI[ft.Uri]; duplicate {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ft.order = order
|
ft.order = order
|
||||||
order++
|
order++
|
||||||
byPath[ft.path] = ft
|
uniqueFeatureURI[ft.Uri] = ft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filterFeatures(filter, byPath), nil
|
return filterFeatures(filter, uniqueFeatureURI), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type sortByOrderGiven []*feature
|
type sortFeaturesByOrder []*feature
|
||||||
|
|
||||||
func (s sortByOrderGiven) Len() int { return len(s) }
|
func (s sortFeaturesByOrder) Len() int { return len(s) }
|
||||||
func (s sortByOrderGiven) Less(i, j int) bool { return s[i].order < s[j].order }
|
func (s sortFeaturesByOrder) Less(i, j int) bool { return s[i].order < s[j].order }
|
||||||
func (s sortByOrderGiven) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s sortFeaturesByOrder) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
func filterFeatures(tags string, collected map[string]*feature) (features []*feature) {
|
func filterFeatures(tags string, collected map[string]*feature) (features []*feature) {
|
||||||
for _, ft := range collected {
|
for _, ft := range collected {
|
||||||
applyTagFilter(tags, ft)
|
ft.pickles = applyTagFilter(tags, ft.pickles)
|
||||||
|
|
||||||
if ft.Feature != nil {
|
if ft.Feature != nil {
|
||||||
features = append(features, ft)
|
features = append(features, ft)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sortByOrderGiven(features))
|
sort.Sort(sortFeaturesByOrder(features))
|
||||||
|
|
||||||
return features
|
return features
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyTagFilter(tags string, ft *feature) {
|
func applyTagFilter(tags string, pickles []*messages.Pickle) (result []*messages.Pickle) {
|
||||||
if len(tags) == 0 {
|
if len(tags) == 0 {
|
||||||
return
|
return pickles
|
||||||
}
|
}
|
||||||
|
|
||||||
var pickles []*messages.Pickle
|
for _, pickle := range pickles {
|
||||||
for _, pickle := range ft.pickles {
|
|
||||||
if matchesTags(tags, pickle.Tags) {
|
if matchesTags(tags, pickle.Tags) {
|
||||||
pickles = append(pickles, pickle)
|
result = append(result, pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ft.pickles = pickles
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ func SuiteContext(s *Suite, additionalContextInitializers ...func(suite *Suite))
|
||||||
s.Step(`^(?:a )?failing step`, c.aFailingStep)
|
s.Step(`^(?:a )?failing step`, c.aFailingStep)
|
||||||
s.Step(`^this step should fail`, c.aFailingStep)
|
s.Step(`^this step should fail`, c.aFailingStep)
|
||||||
s.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, c.followingStepsShouldHave)
|
s.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, c.followingStepsShouldHave)
|
||||||
s.Step(`^all steps should (?:be|have|have been) (passed|failed|skipped|undefined|pending)$`, c.allStepsShouldHave)
|
|
||||||
s.Step(`^the undefined step snippets should be:$`, c.theUndefinedStepSnippetsShouldBe)
|
s.Step(`^the undefined step snippets should be:$`, c.theUndefinedStepSnippetsShouldBe)
|
||||||
|
|
||||||
// event stream
|
// event stream
|
||||||
|
@ -180,18 +179,18 @@ func (s *suiteContext) iRunFeatureSuiteWithTags(tags string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, feat := range s.testedSuite.features {
|
for _, feat := range s.testedSuite.features {
|
||||||
applyTagFilter(tags, feat)
|
feat.pickles = applyTagFilter(tags, feat.pickles)
|
||||||
}
|
}
|
||||||
|
|
||||||
st := newStorage()
|
s.testedSuite.storage = newStorage()
|
||||||
for _, feat := range s.testedSuite.features {
|
for _, feat := range s.testedSuite.features {
|
||||||
for _, pickle := range feat.pickles {
|
for _, pickle := range feat.pickles {
|
||||||
st.mustInsertPickle(pickle)
|
s.testedSuite.storage.mustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt := newBaseFmt("godog", &s.out)
|
fmt := newBaseFmt("godog", &s.out)
|
||||||
fmt.setStorage(st)
|
fmt.setStorage(s.testedSuite.storage)
|
||||||
s.testedSuite.fmt = fmt
|
s.testedSuite.fmt = fmt
|
||||||
|
|
||||||
s.testedSuite.fmt.TestRunStarted()
|
s.testedSuite.fmt.TestRunStarted()
|
||||||
|
@ -211,16 +210,16 @@ func (s *suiteContext) iRunFeatureSuiteWithFormatter(name string) error {
|
||||||
return fmt.Errorf(`formatter "%s" is not available`, name)
|
return fmt.Errorf(`formatter "%s" is not available`, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
st := newStorage()
|
s.testedSuite.storage = newStorage()
|
||||||
for _, feat := range s.testedSuite.features {
|
for _, feat := range s.testedSuite.features {
|
||||||
for _, pickle := range feat.pickles {
|
for _, pickle := range feat.pickles {
|
||||||
st.mustInsertPickle(pickle)
|
s.testedSuite.storage.mustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.testedSuite.fmt = f("godog", colors.Uncolored(&s.out))
|
s.testedSuite.fmt = f("godog", colors.Uncolored(&s.out))
|
||||||
if fmt, ok := s.testedSuite.fmt.(storageFormatter); ok {
|
if fmt, ok := s.testedSuite.fmt.(storageFormatter); ok {
|
||||||
fmt.setStorage(st)
|
fmt.setStorage(s.testedSuite.storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.testedSuite.fmt.TestRunStarted()
|
s.testedSuite.fmt.TestRunStarted()
|
||||||
|
@ -294,28 +293,28 @@ func (s *suiteContext) followingStepsShouldHave(status string, steps *DocString)
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case "passed":
|
case "passed":
|
||||||
for _, st := range f.findStepResults(passed) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(passed) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "failed":
|
case "failed":
|
||||||
for _, st := range f.findStepResults(failed) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(failed) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "skipped":
|
case "skipped":
|
||||||
for _, st := range f.findStepResults(skipped) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(skipped) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "undefined":
|
case "undefined":
|
||||||
for _, st := range f.findStepResults(undefined) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(undefined) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "pending":
|
case "pending":
|
||||||
for _, st := range f.findStepResults(pending) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(pending) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -356,42 +355,6 @@ func (s *suiteContext) followingStepsShouldHave(status string, steps *DocString)
|
||||||
return fmt.Errorf("the steps: %s - are not %s", strings.Join(unmatched, ", "), status)
|
return fmt.Errorf("the steps: %s - are not %s", strings.Join(unmatched, ", "), status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteContext) allStepsShouldHave(status string) error {
|
|
||||||
f, ok := s.testedSuite.fmt.(*basefmt)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("this step requires *basefmt, but there is: %T", s.testedSuite.fmt)
|
|
||||||
}
|
|
||||||
|
|
||||||
total := len(f.findStepResults(passed)) +
|
|
||||||
len(f.findStepResults(failed)) +
|
|
||||||
len(f.findStepResults(skipped)) +
|
|
||||||
len(f.findStepResults(undefined)) +
|
|
||||||
len(f.findStepResults(pending))
|
|
||||||
|
|
||||||
var actual int
|
|
||||||
|
|
||||||
switch status {
|
|
||||||
case "passed":
|
|
||||||
actual = len(f.findStepResults(passed))
|
|
||||||
case "failed":
|
|
||||||
actual = len(f.findStepResults(failed))
|
|
||||||
case "skipped":
|
|
||||||
actual = len(f.findStepResults(skipped))
|
|
||||||
case "undefined":
|
|
||||||
actual = len(f.findStepResults(undefined))
|
|
||||||
case "pending":
|
|
||||||
actual = len(f.findStepResults(pending))
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected step status wanted: %s", status)
|
|
||||||
}
|
|
||||||
|
|
||||||
if total > actual {
|
|
||||||
return fmt.Errorf("number of expected %s steps: %d is less than actual %s steps: %d", status, total, status, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *suiteContext) iAmListeningToSuiteEvents() error {
|
func (s *suiteContext) iAmListeningToSuiteEvents() error {
|
||||||
s.testedSuite.BeforeSuite(func() {
|
s.testedSuite.BeforeSuite(func() {
|
||||||
s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
||||||
|
@ -435,8 +398,10 @@ func (s *suiteContext) aFailingStep() error {
|
||||||
// parse a given feature file body as a feature
|
// parse a given feature file body as a feature
|
||||||
func (s *suiteContext) aFeatureFile(path string, body *DocString) error {
|
func (s *suiteContext) aFeatureFile(path string, body *DocString) error {
|
||||||
gd, err := gherkin.ParseGherkinDocument(strings.NewReader(body.Content), (&messages.Incrementing{}).NewId)
|
gd, err := gherkin.ParseGherkinDocument(strings.NewReader(body.Content), (&messages.Incrementing{}).NewId)
|
||||||
|
gd.Uri = path
|
||||||
|
|
||||||
pickles := gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
pickles := gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
s.testedSuite.features = append(s.testedSuite.features, &feature{GherkinDocument: gd, pickles: pickles, path: path})
|
s.testedSuite.features = append(s.testedSuite.features, &feature{GherkinDocument: gd, pickles: pickles})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -479,7 +444,7 @@ func (s *suiteContext) iShouldHaveNumFeatureFiles(num int, files *DocString) err
|
||||||
var actual []string
|
var actual []string
|
||||||
|
|
||||||
for _, ft := range s.testedSuite.features {
|
for _, ft := range s.testedSuite.features {
|
||||||
actual = append(actual, ft.path)
|
actual = append(actual, ft.Uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(expected) != len(actual) {
|
if len(expected) != len(actual) {
|
||||||
|
|
|
@ -41,7 +41,6 @@ func InitializeScenario(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^(?:a )?failing step`, tc.aFailingStep)
|
ctx.Step(`^(?:a )?failing step`, tc.aFailingStep)
|
||||||
ctx.Step(`^this step should fail`, tc.aFailingStep)
|
ctx.Step(`^this step should fail`, tc.aFailingStep)
|
||||||
ctx.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, tc.followingStepsShouldHave)
|
ctx.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, tc.followingStepsShouldHave)
|
||||||
ctx.Step(`^all steps should (?:be|have|have been) (passed|failed|skipped|undefined|pending)$`, tc.allStepsShouldHave)
|
|
||||||
ctx.Step(`^the undefined step snippets should be:$`, tc.theUndefinedStepSnippetsShouldBe)
|
ctx.Step(`^the undefined step snippets should be:$`, tc.theUndefinedStepSnippetsShouldBe)
|
||||||
|
|
||||||
// event stream
|
// event stream
|
||||||
|
@ -142,18 +141,18 @@ func (tc *godogFeaturesScenario) iRunFeatureSuiteWithTags(tags string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, feat := range tc.testedSuite.features {
|
for _, feat := range tc.testedSuite.features {
|
||||||
applyTagFilter(tags, feat)
|
feat.pickles = applyTagFilter(tags, feat.pickles)
|
||||||
}
|
}
|
||||||
|
|
||||||
st := newStorage()
|
tc.testedSuite.storage = newStorage()
|
||||||
for _, feat := range tc.testedSuite.features {
|
for _, feat := range tc.testedSuite.features {
|
||||||
for _, pickle := range feat.pickles {
|
for _, pickle := range feat.pickles {
|
||||||
st.mustInsertPickle(pickle)
|
tc.testedSuite.storage.mustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt := newBaseFmt("godog", &tc.out)
|
fmt := newBaseFmt("godog", &tc.out)
|
||||||
fmt.setStorage(st)
|
fmt.setStorage(tc.testedSuite.storage)
|
||||||
tc.testedSuite.fmt = fmt
|
tc.testedSuite.fmt = fmt
|
||||||
|
|
||||||
tc.testedSuite.fmt.TestRunStarted()
|
tc.testedSuite.fmt.TestRunStarted()
|
||||||
|
@ -173,16 +172,16 @@ func (tc *godogFeaturesScenario) iRunFeatureSuiteWithFormatter(name string) erro
|
||||||
return fmt.Errorf(`formatter "%s" is not available`, name)
|
return fmt.Errorf(`formatter "%s" is not available`, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
st := newStorage()
|
tc.testedSuite.storage = newStorage()
|
||||||
for _, feat := range tc.testedSuite.features {
|
for _, feat := range tc.testedSuite.features {
|
||||||
for _, pickle := range feat.pickles {
|
for _, pickle := range feat.pickles {
|
||||||
st.mustInsertPickle(pickle)
|
tc.testedSuite.storage.mustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tc.testedSuite.fmt = f("godog", colors.Uncolored(&tc.out))
|
tc.testedSuite.fmt = f("godog", colors.Uncolored(&tc.out))
|
||||||
if fmt, ok := tc.testedSuite.fmt.(storageFormatter); ok {
|
if fmt, ok := tc.testedSuite.fmt.(storageFormatter); ok {
|
||||||
fmt.setStorage(st)
|
fmt.setStorage(tc.testedSuite.storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
tc.testedSuite.fmt.TestRunStarted()
|
tc.testedSuite.fmt.TestRunStarted()
|
||||||
|
@ -256,28 +255,28 @@ func (tc *godogFeaturesScenario) followingStepsShouldHave(status string, steps *
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case "passed":
|
case "passed":
|
||||||
for _, st := range f.findStepResults(passed) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(passed) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "failed":
|
case "failed":
|
||||||
for _, st := range f.findStepResults(failed) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(failed) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "skipped":
|
case "skipped":
|
||||||
for _, st := range f.findStepResults(skipped) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(skipped) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "undefined":
|
case "undefined":
|
||||||
for _, st := range f.findStepResults(undefined) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(undefined) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
case "pending":
|
case "pending":
|
||||||
for _, st := range f.findStepResults(pending) {
|
for _, st := range f.storage.mustGetPickleStepResultsByStatus(pending) {
|
||||||
pickleStep := f.storage.mustGetPickleStep(st.pickleStepID)
|
pickleStep := f.storage.mustGetPickleStep(st.PickleStepID)
|
||||||
actual = append(actual, pickleStep.Text)
|
actual = append(actual, pickleStep.Text)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -318,42 +317,6 @@ func (tc *godogFeaturesScenario) followingStepsShouldHave(status string, steps *
|
||||||
return fmt.Errorf("the steps: %s - are not %s", strings.Join(unmatched, ", "), status)
|
return fmt.Errorf("the steps: %s - are not %s", strings.Join(unmatched, ", "), status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *godogFeaturesScenario) allStepsShouldHave(status string) error {
|
|
||||||
f, ok := tc.testedSuite.fmt.(*basefmt)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("this step requires *basefmt, but there is: %T", tc.testedSuite.fmt)
|
|
||||||
}
|
|
||||||
|
|
||||||
total := len(f.findStepResults(passed)) +
|
|
||||||
len(f.findStepResults(failed)) +
|
|
||||||
len(f.findStepResults(skipped)) +
|
|
||||||
len(f.findStepResults(undefined)) +
|
|
||||||
len(f.findStepResults(pending))
|
|
||||||
|
|
||||||
var actual int
|
|
||||||
|
|
||||||
switch status {
|
|
||||||
case "passed":
|
|
||||||
actual = len(f.findStepResults(passed))
|
|
||||||
case "failed":
|
|
||||||
actual = len(f.findStepResults(failed))
|
|
||||||
case "skipped":
|
|
||||||
actual = len(f.findStepResults(skipped))
|
|
||||||
case "undefined":
|
|
||||||
actual = len(f.findStepResults(undefined))
|
|
||||||
case "pending":
|
|
||||||
actual = len(f.findStepResults(pending))
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected step status wanted: %s", status)
|
|
||||||
}
|
|
||||||
|
|
||||||
if total > actual {
|
|
||||||
return fmt.Errorf("number of expected %s steps: %d is less than actual %s steps: %d", status, total, status, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tc *godogFeaturesScenario) iAmListeningToSuiteEvents() error {
|
func (tc *godogFeaturesScenario) iAmListeningToSuiteEvents() error {
|
||||||
tc.testedSuite.BeforeSuite(func() {
|
tc.testedSuite.BeforeSuite(func() {
|
||||||
tc.events = append(tc.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
tc.events = append(tc.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
||||||
|
@ -397,8 +360,10 @@ func (tc *godogFeaturesScenario) aFailingStep() error {
|
||||||
// parse a given feature file body as a feature
|
// parse a given feature file body as a feature
|
||||||
func (tc *godogFeaturesScenario) aFeatureFile(path string, body *DocString) error {
|
func (tc *godogFeaturesScenario) aFeatureFile(path string, body *DocString) error {
|
||||||
gd, err := gherkin.ParseGherkinDocument(strings.NewReader(body.Content), (&messages.Incrementing{}).NewId)
|
gd, err := gherkin.ParseGherkinDocument(strings.NewReader(body.Content), (&messages.Incrementing{}).NewId)
|
||||||
|
gd.Uri = path
|
||||||
|
|
||||||
pickles := gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
pickles := gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
tc.testedSuite.features = append(tc.testedSuite.features, &feature{GherkinDocument: gd, pickles: pickles, path: path})
|
tc.testedSuite.features = append(tc.testedSuite.features, &feature{GherkinDocument: gd, pickles: pickles})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -441,7 +406,7 @@ func (tc *godogFeaturesScenario) iShouldHaveNumFeatureFiles(num int, files *DocS
|
||||||
var actual []string
|
var actual []string
|
||||||
|
|
||||||
for _, ft := range tc.testedSuite.features {
|
for _, ft := range tc.testedSuite.features {
|
||||||
actual = append(actual, ft.path)
|
actual = append(actual, ft.Uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(expected) != len(actual) {
|
if len(expected) != len(actual) {
|
||||||
|
|
|
@ -33,6 +33,11 @@ func Test_TestContext(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.storage = newStorage()
|
||||||
|
for _, pickle := range pickles {
|
||||||
|
r.storage.mustInsertPickle(pickle)
|
||||||
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) })
|
failed := r.concurrent(1, func() Formatter { return progressFunc("progress", w) })
|
||||||
require.False(t, failed)
|
require.False(t, failed)
|
||||||
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче