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