Created internal packages for formatters, storage and models
Этот коммит содержится в:
родитель
28ad994ad1
коммит
150c400163
105 изменённых файлов: 1493 добавлений и 872 удалений
|
@ -36,7 +36,7 @@ commands:
|
||||||
go_test:
|
go_test:
|
||||||
description: "Run go test"
|
description: "Run go test"
|
||||||
steps:
|
steps:
|
||||||
- run: sed -i 's#github.com/cucumber/godog_test#_test#g' formatter-tests/*/*
|
- run: sed -i 's#github.com/cucumber/godog/internal/formatters_test#/internal/formatters_test#g' internal/formatters/formatter-tests/*/*
|
||||||
- run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
|
- run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||||
godog:
|
godog:
|
||||||
description: "Run godog"
|
description: "Run godog"
|
||||||
|
|
4
flags.go
4
flags.go
|
@ -10,8 +10,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// repeats a space n times
|
||||||
|
var s = utils.S
|
||||||
|
|
||||||
var descFeaturesArgument = "Optional feature(s) to run. Can be:\n" +
|
var descFeaturesArgument = "Optional feature(s) to run. Can be:\n" +
|
||||||
s(4) + "- dir " + colors.Yellow("(features/)") + "\n" +
|
s(4) + "- dir " + colors.Yellow("(features/)") + "\n" +
|
||||||
s(4) + "- feature " + colors.Yellow("(*.feature)") + "\n" +
|
s(4) + "- feature " + colors.Yellow("(*.feature)") + "\n" +
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/formatters"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFlagsShouldRandomizeAndGenerateSeed(t *testing.T) {
|
func TestFlagsShouldRandomizeAndGenerateSeed(t *testing.T) {
|
||||||
|
@ -61,7 +62,7 @@ func TestFlagsUsageShouldIncludeFormatDescriptons(t *testing.T) {
|
||||||
output := colors.Uncolored(&buf)
|
output := colors.Uncolored(&buf)
|
||||||
|
|
||||||
// register some custom formatter
|
// register some custom formatter
|
||||||
Format("custom", "custom format description", junitFunc)
|
Format("custom", "custom format description", formatters.JUnitFormatterFunc)
|
||||||
|
|
||||||
var opt Options
|
var opt Options
|
||||||
flags := FlagSet(&opt)
|
flags := FlagSet(&opt)
|
||||||
|
|
65
fmt.go
65
fmt.go
|
@ -6,28 +6,18 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
internal_fmt "github.com/cucumber/godog/internal/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type registeredFormatter struct {
|
|
||||||
name string
|
|
||||||
description string
|
|
||||||
fmt FormatterFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
var formatters []*registeredFormatter
|
|
||||||
|
|
||||||
// FindFmt searches available formatters registered
|
// FindFmt searches available formatters registered
|
||||||
// and returns FormaterFunc matched by given
|
// and returns FormaterFunc matched by given
|
||||||
// format name or nil otherwise
|
// format name or nil otherwise
|
||||||
func FindFmt(name string) FormatterFunc {
|
func FindFmt(name string) FormatterFunc {
|
||||||
for _, el := range formatters {
|
return formatters.FindFmt(name)
|
||||||
if el.name == name {
|
|
||||||
return el.fmt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format registers a feature suite output
|
// Format registers a feature suite output
|
||||||
|
@ -35,24 +25,14 @@ func FindFmt(name string) FormatterFunc {
|
||||||
// FormatterFunc constructor function, to initialize
|
// FormatterFunc constructor function, to initialize
|
||||||
// formatter with the output recorder.
|
// formatter with the output recorder.
|
||||||
func Format(name, description string, f FormatterFunc) {
|
func Format(name, description string, f FormatterFunc) {
|
||||||
formatters = append(formatters, ®isteredFormatter{
|
formatters.Format(name, description, f)
|
||||||
name: name,
|
|
||||||
fmt: f,
|
|
||||||
description: description,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvailableFormatters gives a map of all
|
// AvailableFormatters gives a map of all
|
||||||
// formatters registered with their name as key
|
// formatters registered with their name as key
|
||||||
// and description as value
|
// and description as value
|
||||||
func AvailableFormatters() map[string]string {
|
func AvailableFormatters() map[string]string {
|
||||||
fmts := make(map[string]string, len(formatters))
|
return formatters.AvailableFormatters()
|
||||||
|
|
||||||
for _, f := range formatters {
|
|
||||||
fmts[f.name] = f.description
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatter is an interface for feature runner
|
// Formatter is an interface for feature runner
|
||||||
|
@ -62,32 +42,17 @@ func AvailableFormatters() map[string]string {
|
||||||
// suite results in different ways. These new
|
// suite results in different ways. These new
|
||||||
// formatters needs to be registered with a
|
// formatters needs to be registered with a
|
||||||
// godog.Format function call
|
// godog.Format function call
|
||||||
type Formatter interface {
|
type Formatter = formatters.Formatter
|
||||||
TestRunStarted()
|
|
||||||
Feature(*messages.GherkinDocument, string, []byte)
|
|
||||||
Pickle(*messages.Pickle)
|
|
||||||
Defined(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition)
|
|
||||||
Failed(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition, error)
|
|
||||||
Passed(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition)
|
|
||||||
Skipped(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition)
|
|
||||||
Undefined(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition)
|
|
||||||
Pending(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition)
|
|
||||||
Summary()
|
|
||||||
}
|
|
||||||
|
|
||||||
type storageFormatter interface {
|
type storageFormatter interface {
|
||||||
setStorage(*storage)
|
SetStorage(*storage.Storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatterFunc builds a formatter with given
|
// FormatterFunc builds a formatter with given
|
||||||
// suite name and io.Writer to record output
|
// suite name and io.Writer to record output
|
||||||
type FormatterFunc func(string, io.Writer) Formatter
|
type FormatterFunc = formatters.FormatterFunc
|
||||||
|
|
||||||
func isLastStep(pickle *messages.Pickle, step *messages.Pickle_PickleStep) bool {
|
func printStepDefinitions(steps []*models.StepDefinition, w io.Writer) {
|
||||||
return pickle.Steps[len(pickle.Steps)-1].Id == step.Id
|
|
||||||
}
|
|
||||||
|
|
||||||
func printStepDefinitions(steps []*StepDefinition, w io.Writer) {
|
|
||||||
var longest int
|
var longest int
|
||||||
for _, def := range steps {
|
for _, def := range steps {
|
||||||
n := utf8.RuneCountInString(def.Expr.String())
|
n := utf8.RuneCountInString(def.Expr.String())
|
||||||
|
@ -98,9 +63,11 @@ func printStepDefinitions(steps []*StepDefinition, w io.Writer) {
|
||||||
|
|
||||||
for _, def := range steps {
|
for _, def := range steps {
|
||||||
n := utf8.RuneCountInString(def.Expr.String())
|
n := utf8.RuneCountInString(def.Expr.String())
|
||||||
location := def.definitionID()
|
location := internal_fmt.DefinitionID(def)
|
||||||
spaces := strings.Repeat(" ", longest-n)
|
spaces := strings.Repeat(" ", longest-n)
|
||||||
fmt.Fprintln(w, yellow(def.Expr.String())+spaces, blackb("# "+location))
|
fmt.Fprintln(w,
|
||||||
|
colors.Yellow(def.Expr.String())+spaces,
|
||||||
|
colors.Bold(colors.Black)("# "+location))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(steps) == 0 {
|
if len(steps) == 0 {
|
||||||
|
|
79
formatters/fmt.go
Обычный файл
79
formatters/fmt.go
Обычный файл
|
@ -0,0 +1,79 @@
|
||||||
|
package formatters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type registeredFormatter struct {
|
||||||
|
name string
|
||||||
|
description string
|
||||||
|
fmt FormatterFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
var registeredFormatters []*registeredFormatter
|
||||||
|
|
||||||
|
// FindFmt searches available formatters registered
|
||||||
|
// and returns FormaterFunc matched by given
|
||||||
|
// format name or nil otherwise
|
||||||
|
func FindFmt(name string) FormatterFunc {
|
||||||
|
for _, el := range registeredFormatters {
|
||||||
|
if el.name == name {
|
||||||
|
return el.fmt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format registers a feature suite output
|
||||||
|
// formatter by given name, description and
|
||||||
|
// FormatterFunc constructor function, to initialize
|
||||||
|
// formatter with the output recorder.
|
||||||
|
func Format(name, description string, f FormatterFunc) {
|
||||||
|
registeredFormatters = append(registeredFormatters, ®isteredFormatter{
|
||||||
|
name: name,
|
||||||
|
fmt: f,
|
||||||
|
description: description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailableFormatters gives a map of all
|
||||||
|
// formatters registered with their name as key
|
||||||
|
// and description as value
|
||||||
|
func AvailableFormatters() map[string]string {
|
||||||
|
fmts := make(map[string]string, len(registeredFormatters))
|
||||||
|
|
||||||
|
for _, f := range registeredFormatters {
|
||||||
|
fmts[f.name] = f.description
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatter is an interface for feature runner
|
||||||
|
// output summary presentation.
|
||||||
|
//
|
||||||
|
// New formatters may be created to represent
|
||||||
|
// suite results in different ways. These new
|
||||||
|
// formatters needs to be registered with a
|
||||||
|
// godog.Format function call
|
||||||
|
type Formatter interface {
|
||||||
|
TestRunStarted()
|
||||||
|
Feature(*messages.GherkinDocument, string, []byte)
|
||||||
|
Pickle(*messages.Pickle)
|
||||||
|
Defined(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition)
|
||||||
|
Failed(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition, error)
|
||||||
|
Passed(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition)
|
||||||
|
Skipped(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition)
|
||||||
|
Undefined(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition)
|
||||||
|
Pending(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition)
|
||||||
|
Summary()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatterFunc builds a formatter with given
|
||||||
|
// suite name and io.Writer to record output
|
||||||
|
type FormatterFunc func(string, io.Writer) Formatter
|
65
formatters/fmt_test.go
Обычный файл
65
formatters/fmt_test.go
Обычный файл
|
@ -0,0 +1,65 @@
|
||||||
|
package formatters_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_FindFmt(t *testing.T) {
|
||||||
|
cases := map[string]bool{
|
||||||
|
"cucumber": true,
|
||||||
|
"events": true,
|
||||||
|
"junit": true,
|
||||||
|
"pretty": true,
|
||||||
|
"progress": true,
|
||||||
|
"unknown": false,
|
||||||
|
"undef": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, expected := range cases {
|
||||||
|
t.Run(
|
||||||
|
name,
|
||||||
|
func(t *testing.T) {
|
||||||
|
actual := godog.FindFmt(name)
|
||||||
|
|
||||||
|
if expected {
|
||||||
|
assert.NotNilf(t, actual, "expected %s formatter should be available", name)
|
||||||
|
} else {
|
||||||
|
assert.Nilf(t, actual, "expected %s formatter should be available", name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AvailableFormatters(t *testing.T) {
|
||||||
|
expected := map[string]string{
|
||||||
|
"cucumber": "Produces cucumber JSON format output.",
|
||||||
|
"events": "Produces JSON event stream, based on spec: 0.1.0.",
|
||||||
|
"junit": "Prints junit compatible xml to stdout",
|
||||||
|
"pretty": "Prints every feature with runtime statuses.",
|
||||||
|
"progress": "Prints a character per step.",
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := godog.AvailableFormatters()
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Format(t *testing.T) {
|
||||||
|
actual := godog.FindFmt("Test_Format")
|
||||||
|
require.Nil(t, actual)
|
||||||
|
|
||||||
|
godog.Format("Test_Format", "...", testFormatterFunc)
|
||||||
|
actual = godog.FindFmt("Test_Format")
|
||||||
|
|
||||||
|
assert.NotNil(t, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFormatterFunc(suiteName string, out io.Writer) godog.Formatter {
|
||||||
|
return nil
|
||||||
|
}
|
104
internal/formatters/fmt.go
Обычный файл
104
internal/formatters/fmt.go
Обычный файл
|
@ -0,0 +1,104 @@
|
||||||
|
package formatters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
red = colors.Red
|
||||||
|
redb = colors.Bold(colors.Red)
|
||||||
|
green = colors.Green
|
||||||
|
blackb = colors.Bold(colors.Black)
|
||||||
|
yellow = colors.Yellow
|
||||||
|
cyan = colors.Cyan
|
||||||
|
cyanb = colors.Bold(colors.Cyan)
|
||||||
|
whiteb = colors.Bold(colors.White)
|
||||||
|
)
|
||||||
|
|
||||||
|
// repeats a space n times
|
||||||
|
var s = utils.S
|
||||||
|
|
||||||
|
var (
|
||||||
|
passed = models.Passed
|
||||||
|
failed = models.Failed
|
||||||
|
skipped = models.Skipped
|
||||||
|
undefined = models.Undefined
|
||||||
|
pending = models.Pending
|
||||||
|
)
|
||||||
|
|
||||||
|
type sortFeaturesByName []*models.Feature
|
||||||
|
|
||||||
|
func (s sortFeaturesByName) Len() int { return len(s) }
|
||||||
|
func (s sortFeaturesByName) Less(i, j int) bool { return s[i].Feature.Name < s[j].Feature.Name }
|
||||||
|
func (s sortFeaturesByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
type sortPicklesByID []*messages.Pickle
|
||||||
|
|
||||||
|
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] }
|
||||||
|
|
||||||
|
type sortPickleStepResultsByPickleStepID []models.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 mustConvertStringToInt(s string) int {
|
||||||
|
i, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefinitionID ...
|
||||||
|
func DefinitionID(sd *models.StepDefinition) string {
|
||||||
|
ptr := sd.HandlerValue.Pointer()
|
||||||
|
f := runtime.FuncForPC(ptr)
|
||||||
|
file, line := f.FileLine(ptr)
|
||||||
|
dir := filepath.Dir(file)
|
||||||
|
|
||||||
|
fn := strings.Replace(f.Name(), dir, "", -1)
|
||||||
|
var parts []string
|
||||||
|
for _, gr := range matchFuncDefRef.FindAllStringSubmatch(fn, -1) {
|
||||||
|
parts = append(parts, strings.Trim(gr[1], "_."))
|
||||||
|
}
|
||||||
|
if len(parts) > 0 {
|
||||||
|
// case when suite is a structure with methods
|
||||||
|
fn = strings.Join(parts, ".")
|
||||||
|
} else {
|
||||||
|
// case when steps are just plain funcs
|
||||||
|
fn = strings.Trim(fn, "_.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg := os.Getenv("GODOG_TESTED_PACKAGE"); len(pkg) > 0 {
|
||||||
|
fn = strings.Replace(fn, pkg, "", 1)
|
||||||
|
fn = strings.TrimLeft(fn, ".")
|
||||||
|
fn = strings.Replace(fn, "..", ".", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s:%d -> %s", filepath.Base(file), line, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchFuncDefRef = regexp.MustCompile(`\(([^\)]+)\)`)
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -14,14 +14,20 @@ import (
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/storage"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func baseFmtFunc(suite string, out io.Writer) Formatter {
|
// BaseFormatterFunc implements the FormatterFunc for the base formatter
|
||||||
return newBaseFmt(suite, out)
|
func BaseFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||||
|
return NewBaseFmt(suite, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBaseFmt(suite string, out io.Writer) *basefmt {
|
// NewBaseFmt creates a new base formatter
|
||||||
return &basefmt{
|
func NewBaseFmt(suite string, out io.Writer) *Basefmt {
|
||||||
|
return &Basefmt{
|
||||||
suiteName: suite,
|
suiteName: suite,
|
||||||
indent: 2,
|
indent: 2,
|
||||||
out: out,
|
out: out,
|
||||||
|
@ -29,47 +35,63 @@ func newBaseFmt(suite string, out io.Writer) *basefmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type basefmt struct {
|
// Basefmt ...
|
||||||
|
type Basefmt struct {
|
||||||
suiteName string
|
suiteName string
|
||||||
out io.Writer
|
out io.Writer
|
||||||
indent int
|
indent int
|
||||||
|
|
||||||
storage *storage
|
storage *storage.Storage
|
||||||
lock *sync.Mutex
|
lock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) setStorage(st *storage) {
|
// SetStorage ...
|
||||||
|
func (f *Basefmt) SetStorage(st *storage.Storage) {
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
f.storage = st
|
f.storage = st
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) TestRunStarted() {}
|
// TestRunStarted ...
|
||||||
func (f *basefmt) Feature(ft *messages.GherkinDocument, p string, c []byte) {}
|
func (f *Basefmt) TestRunStarted() {}
|
||||||
func (f *basefmt) Pickle(p *messages.Pickle) {}
|
|
||||||
func (f *basefmt) Defined(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition) {}
|
// Feature ...
|
||||||
func (f *basefmt) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *Basefmt) Feature(*messages.GherkinDocument, string, []byte) {}
|
||||||
}
|
|
||||||
func (f *basefmt) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
// Pickle ...
|
||||||
}
|
func (f *Basefmt) Pickle(*messages.Pickle) {}
|
||||||
func (f *basefmt) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
|
||||||
}
|
// Defined ...
|
||||||
func (f *basefmt) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
func (f *Basefmt) Defined(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition) {}
|
||||||
}
|
|
||||||
func (f *basefmt) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
// Passed ...
|
||||||
|
func (f *Basefmt) Passed(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition) {}
|
||||||
|
|
||||||
|
// Skipped ...
|
||||||
|
func (f *Basefmt) Skipped(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition) {}
|
||||||
|
|
||||||
|
// Undefined ...
|
||||||
|
func (f *Basefmt) Undefined(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition) {}
|
||||||
|
|
||||||
|
// Failed ...
|
||||||
|
func (f *Basefmt) Failed(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) Summary() {
|
// Pending ...
|
||||||
|
func (f *Basefmt) Pending(*messages.Pickle, *messages.Pickle_PickleStep, *models.StepDefinition) {}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
pickleResults := f.storage.mustGetPickleResults()
|
pickleResults := f.storage.MustGetPickleResults()
|
||||||
for _, pr := range pickleResults {
|
for _, pr := range pickleResults {
|
||||||
var prStatus stepResultStatus
|
var prStatus models.StepResultStatus
|
||||||
totalSc++
|
totalSc++
|
||||||
|
|
||||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pr.PickleID)
|
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pr.PickleID)
|
||||||
|
|
||||||
if len(pickleStepResults) == 0 {
|
if len(pickleStepResults) == 0 {
|
||||||
prStatus = undefined
|
prStatus = undefined
|
||||||
|
@ -130,8 +152,8 @@ func (f *basefmt) Summary() {
|
||||||
}
|
}
|
||||||
scenarios = append(scenarios, parts...)
|
scenarios = append(scenarios, parts...)
|
||||||
|
|
||||||
testRunStartedAt := f.storage.mustGetTestRunStarted().StartedAt
|
testRunStartedAt := f.storage.MustGetTestRunStarted().StartedAt
|
||||||
elapsed := timeNowFunc().Sub(testRunStartedAt)
|
elapsed := utils.TimeNowFunc().Sub(testRunStartedAt)
|
||||||
|
|
||||||
fmt.Fprintln(f.out, "")
|
fmt.Fprintln(f.out, "")
|
||||||
|
|
||||||
|
@ -161,15 +183,16 @@ func (f *basefmt) Summary() {
|
||||||
fmt.Fprintln(f.out, "Randomized with seed:", colors.Yellow(seed))
|
fmt.Fprintln(f.out, "Randomized with seed:", colors.Yellow(seed))
|
||||||
}
|
}
|
||||||
|
|
||||||
if text := f.snippets(); text != "" {
|
if text := f.Snippets(); text != "" {
|
||||||
fmt.Fprintln(f.out, "")
|
fmt.Fprintln(f.out, "")
|
||||||
fmt.Fprintln(f.out, yellow("You can implement step definitions for undefined steps with these snippets:"))
|
fmt.Fprintln(f.out, yellow("You can implement step definitions for undefined steps with these snippets:"))
|
||||||
fmt.Fprintln(f.out, yellow(text))
|
fmt.Fprintln(f.out, yellow(text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *basefmt) snippets() string {
|
// Snippets ...
|
||||||
undefinedStepResults := f.storage.mustGetPickleStepResultsByStatus(undefined)
|
func (f *Basefmt) Snippets() string {
|
||||||
|
undefinedStepResults := f.storage.MustGetPickleStepResultsByStatus(undefined)
|
||||||
if len(undefinedStepResults) == 0 {
|
if len(undefinedStepResults) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -178,12 +201,12 @@ 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
|
||||||
if u.def != nil {
|
if u.Def != nil {
|
||||||
steps = u.def.undefined
|
steps = u.Def.Undefined
|
||||||
arg = nil
|
arg = nil
|
||||||
}
|
}
|
||||||
for _, step := range steps {
|
for _, step := range steps {
|
|
@ -1,4 +1,4 @@
|
||||||
package godog_test
|
package formatters_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The specification for the formatting originated from https://www.relishapp.com/cucumber/cucumber/docs/formatters/json-output-formatter.
|
The specification for the formatting originated from https://www.relishapp.com/cucumber/cucumber/docs/formatters/json-output-formatter.
|
||||||
|
@ -19,22 +19,26 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("cucumber", "Produces cucumber JSON format output.", cucumberFunc)
|
formatters.Format("cucumber", "Produces cucumber JSON format output.", CucumberFormatterFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cucumberFunc(suite string, out io.Writer) Formatter {
|
// CucumberFormatterFunc implements the FormatterFunc for the cucumber formatter
|
||||||
return &cukefmt{basefmt: newBaseFmt(suite, out)}
|
func CucumberFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||||
|
return &cukefmt{Basefmt: NewBaseFmt(suite, out)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type cukefmt struct {
|
type cukefmt struct {
|
||||||
*basefmt
|
*Basefmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) Summary() {
|
func (f *cukefmt) Summary() {
|
||||||
features := f.storage.mustGetFeatures()
|
features := f.storage.MustGetFeatures()
|
||||||
|
|
||||||
res := f.buildCukeFeatures(features)
|
res := f.buildCukeFeatures(features)
|
||||||
|
|
||||||
|
@ -46,15 +50,15 @@ func (f *cukefmt) Summary() {
|
||||||
fmt.Fprintf(f.out, "%s\n", string(dat))
|
fmt.Fprintf(f.out, "%s\n", string(dat))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) buildCukeFeatures(features []*feature) (res []cukeFeatureJSON) {
|
func (f *cukefmt) buildCukeFeatures(features []*models.Feature) (res []CukeFeatureJSON) {
|
||||||
sort.Sort(sortFeaturesByName(features))
|
sort.Sort(sortFeaturesByName(features))
|
||||||
|
|
||||||
res = make([]cukeFeatureJSON, len(features))
|
res = make([]CukeFeatureJSON, len(features))
|
||||||
|
|
||||||
for idx, feat := range features {
|
for idx, feat := range features {
|
||||||
cukeFeature := buildCukeFeature(feat)
|
cukeFeature := buildCukeFeature(feat)
|
||||||
|
|
||||||
pickles := f.storage.mustGetPickles(feat.Uri)
|
pickles := f.storage.MustGetPickles(feat.Uri)
|
||||||
sort.Sort(sortPicklesByID(pickles))
|
sort.Sort(sortPicklesByID(pickles))
|
||||||
|
|
||||||
cukeFeature.Elements = f.buildCukeElements(pickles)
|
cukeFeature.Elements = f.buildCukeElements(pickles)
|
||||||
|
@ -75,8 +79,8 @@ func (f *cukefmt) buildCukeElements(pickles []*messages.Pickle) (res []cukeEleme
|
||||||
res = make([]cukeElement, len(pickles))
|
res = make([]cukeElement, len(pickles))
|
||||||
|
|
||||||
for idx, pickle := range pickles {
|
for idx, pickle := range pickles {
|
||||||
pickleResult := f.storage.mustGetPickleResult(pickle.Id)
|
pickleResult := f.storage.MustGetPickleResult(pickle.Id)
|
||||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
|
|
||||||
cukeElement := f.buildCukeElement(pickle)
|
cukeElement := f.buildCukeElement(pickle)
|
||||||
|
|
||||||
|
@ -88,12 +92,14 @@ func (f *cukefmt) buildCukeElements(pickles []*messages.Pickle) (res []cukeEleme
|
||||||
for jdx, stepResult := range pickleStepResults {
|
for jdx, stepResult := range pickleStepResults {
|
||||||
cukeStep := f.buildCukeStep(pickle, stepResult)
|
cukeStep := f.buildCukeStep(pickle, stepResult)
|
||||||
|
|
||||||
stepResultFinishedAt := stepResult.finishedAt
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +163,8 @@ type cukeElement struct {
|
||||||
Steps []cukeStep `json:"steps,omitempty"`
|
Steps []cukeStep `json:"steps,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type cukeFeatureJSON struct {
|
// CukeFeatureJSON ...
|
||||||
|
type CukeFeatureJSON struct {
|
||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Keyword string `json:"keyword"`
|
Keyword string `json:"keyword"`
|
||||||
|
@ -169,8 +176,8 @@ type cukeFeatureJSON struct {
|
||||||
Elements []cukeElement `json:"elements,omitempty"`
|
Elements []cukeElement `json:"elements,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildCukeFeature(feat *feature) cukeFeatureJSON {
|
func buildCukeFeature(feat *models.Feature) CukeFeatureJSON {
|
||||||
cukeFeature := cukeFeatureJSON{
|
cukeFeature := CukeFeatureJSON{
|
||||||
URI: feat.Uri,
|
URI: feat.Uri,
|
||||||
ID: makeCukeID(feat.Feature.Name),
|
ID: makeCukeID(feat.Feature.Name),
|
||||||
Keyword: feat.Feature.Keyword,
|
Keyword: feat.Feature.Keyword,
|
||||||
|
@ -195,8 +202,8 @@ func buildCukeFeature(feat *feature) cukeFeatureJSON {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) buildCukeElement(pickle *messages.Pickle) (cukeElement cukeElement) {
|
func (f *cukefmt) buildCukeElement(pickle *messages.Pickle) (cukeElement cukeElement) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
scenario := feature.findScenario(pickle.AstNodeIds[0])
|
scenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
|
|
||||||
cukeElement.Name = pickle.Name
|
cukeElement.Name = pickle.Name
|
||||||
cukeElement.Line = int(scenario.Location.Line)
|
cukeElement.Line = int(scenario.Location.Line)
|
||||||
|
@ -214,7 +221,7 @@ func (f *cukefmt) buildCukeElement(pickle *messages.Pickle) (cukeElement cukeEle
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
example, _ := feature.findExample(pickle.AstNodeIds[1])
|
example, _ := feature.FindExample(pickle.AstNodeIds[1])
|
||||||
|
|
||||||
for _, tag := range example.Tags {
|
for _, tag := range example.Tags {
|
||||||
tag := cukeTag{Line: int(tag.Location.Line), Name: tag.Name}
|
tag := cukeTag{Line: int(tag.Location.Line), Name: tag.Name}
|
||||||
|
@ -238,14 +245,14 @@ func (f *cukefmt) buildCukeElement(pickle *messages.Pickle) (cukeElement cukeEle
|
||||||
return cukeElement
|
return cukeElement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult pickleStepResult) (cukeStep cukeStep) {
|
func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult models.PickleStepResult) (cukeStep cukeStep) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
pickleStep := f.storage.mustGetPickleStep(stepResult.PickleStepID)
|
pickleStep := f.storage.MustGetPickleStep(stepResult.PickleStepID)
|
||||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
line := step.Location.Line
|
line := step.Location.Line
|
||||||
if len(pickle.AstNodeIds) == 2 {
|
if len(pickle.AstNodeIds) == 2 {
|
||||||
_, row := feature.findExample(pickle.AstNodeIds[1])
|
_, row := feature.FindExample(pickle.AstNodeIds[1])
|
||||||
line = row.Location.Line
|
line = row.Location.Line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,13 +280,13 @@ func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult pickleStepRe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if stepResult.def != nil {
|
if stepResult.Def != nil {
|
||||||
cukeStep.Match.Location = strings.Split(stepResult.def.definitionID(), " ")[0]
|
cukeStep.Match.Location = strings.Split(DefinitionID(stepResult.Def), " ")[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 {
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -6,24 +6,29 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const nanoSec = 1000000
|
const nanoSec = 1000000
|
||||||
const spec = "0.1.0"
|
const spec = "0.1.0"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("events", fmt.Sprintf("Produces JSON event stream, based on spec: %s.", spec), eventsFunc)
|
formatters.Format("events", fmt.Sprintf("Produces JSON event stream, based on spec: %s.", spec), EventsFormatterFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eventsFunc(suite string, out io.Writer) Formatter {
|
// EventsFormatterFunc implements the FormatterFunc for the events formatter
|
||||||
return &events{basefmt: newBaseFmt(suite, out)}
|
func EventsFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||||
|
return &eventsFormatter{Basefmt: NewBaseFmt(suite, out)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type events struct {
|
type eventsFormatter struct {
|
||||||
*basefmt
|
*Basefmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) event(ev interface{}) {
|
func (f *eventsFormatter) event(ev interface{}) {
|
||||||
data, err := json.Marshal(ev)
|
data, err := json.Marshal(ev)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("failed to marshal stream event: %+v - %v", ev, err))
|
panic(fmt.Sprintf("failed to marshal stream event: %+v - %v", ev, err))
|
||||||
|
@ -31,8 +36,8 @@ func (f *events) event(ev interface{}) {
|
||||||
fmt.Fprintln(f.out, string(data))
|
fmt.Fprintln(f.out, string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Pickle(pickle *messages.Pickle) {
|
func (f *eventsFormatter) Pickle(pickle *messages.Pickle) {
|
||||||
f.basefmt.Pickle(pickle)
|
f.Basefmt.Pickle(pickle)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -44,7 +49,7 @@ func (f *events) Pickle(pickle *messages.Pickle) {
|
||||||
}{
|
}{
|
||||||
"TestCaseStarted",
|
"TestCaseStarted",
|
||||||
f.scenarioLocation(pickle),
|
f.scenarioLocation(pickle),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
})
|
})
|
||||||
|
|
||||||
if len(pickle.Steps) == 0 {
|
if len(pickle.Steps) == 0 {
|
||||||
|
@ -58,14 +63,14 @@ func (f *events) Pickle(pickle *messages.Pickle) {
|
||||||
}{
|
}{
|
||||||
"TestCaseFinished",
|
"TestCaseFinished",
|
||||||
f.scenarioLocation(pickle),
|
f.scenarioLocation(pickle),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
"undefined",
|
"undefined",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) TestRunStarted() {
|
func (f *eventsFormatter) TestRunStarted() {
|
||||||
f.basefmt.TestRunStarted()
|
f.Basefmt.TestRunStarted()
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -78,13 +83,13 @@ func (f *events) TestRunStarted() {
|
||||||
}{
|
}{
|
||||||
"TestRunStarted",
|
"TestRunStarted",
|
||||||
spec,
|
spec,
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
f.suiteName,
|
f.suiteName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
func (f *eventsFormatter) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
||||||
f.basefmt.Feature(ft, p, c)
|
f.Basefmt.Feature(ft, p, c)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -100,23 +105,23 @@ func (f *events) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Summary() {
|
func (f *eventsFormatter) Summary() {
|
||||||
// @TODO: determine status
|
// @TODO: determine status
|
||||||
status := passed
|
status := passed
|
||||||
|
|
||||||
f.storage.mustGetPickleStepResultsByStatus(failed)
|
f.storage.MustGetPickleStepResultsByStatus(failed)
|
||||||
|
|
||||||
if len(f.storage.mustGetPickleStepResultsByStatus(failed)) > 0 {
|
if len(f.storage.MustGetPickleStepResultsByStatus(failed)) > 0 {
|
||||||
status = failed
|
status = failed
|
||||||
} else if len(f.storage.mustGetPickleStepResultsByStatus(passed)) == 0 {
|
} else if len(f.storage.MustGetPickleStepResultsByStatus(passed)) == 0 {
|
||||||
if len(f.storage.mustGetPickleStepResultsByStatus(undefined)) > len(f.storage.mustGetPickleStepResultsByStatus(pending)) {
|
if len(f.storage.MustGetPickleStepResultsByStatus(undefined)) > len(f.storage.MustGetPickleStepResultsByStatus(pending)) {
|
||||||
status = undefined
|
status = undefined
|
||||||
} else {
|
} else {
|
||||||
status = pending
|
status = pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snips := f.snippets()
|
snips := f.Snippets()
|
||||||
if len(snips) > 0 {
|
if len(snips) > 0 {
|
||||||
snips = "You can implement step definitions for undefined steps with these snippets:\n" + snips
|
snips = "You can implement step definitions for undefined steps with these snippets:\n" + snips
|
||||||
}
|
}
|
||||||
|
@ -130,20 +135,20 @@ func (f *events) Summary() {
|
||||||
}{
|
}{
|
||||||
"TestRunFinished",
|
"TestRunFinished",
|
||||||
status.String(),
|
status.String(),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
snips,
|
snips,
|
||||||
"", // @TODO not sure that could be correctly implemented
|
"", // @TODO not sure that could be correctly implemented
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
func (f *eventsFormatter) step(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStep.Id)
|
pickleStepResult := f.storage.MustGetPickleStepResult(pickleStep.Id)
|
||||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
var errMsg string
|
var errMsg string
|
||||||
if pickleStepResult.err != nil {
|
if pickleStepResult.Err != nil {
|
||||||
errMsg = pickleStepResult.err.Error()
|
errMsg = pickleStepResult.Err.Error()
|
||||||
}
|
}
|
||||||
f.event(&struct {
|
f.event(&struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
|
@ -154,7 +159,7 @@ func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_Pickl
|
||||||
}{
|
}{
|
||||||
"TestStepFinished",
|
"TestStepFinished",
|
||||||
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
pickleStepResult.Status.String(),
|
pickleStepResult.Status.String(),
|
||||||
errMsg,
|
errMsg,
|
||||||
})
|
})
|
||||||
|
@ -162,17 +167,11 @@ func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_Pickl
|
||||||
if isLastStep(pickle, pickleStep) {
|
if isLastStep(pickle, pickleStep) {
|
||||||
var status string
|
var status string
|
||||||
|
|
||||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
for _, stepResult := range pickleStepResults {
|
for _, stepResult := range pickleStepResults {
|
||||||
switch stepResult.Status {
|
switch stepResult.Status {
|
||||||
case passed:
|
case passed, failed, undefined, pending:
|
||||||
status = passed.String()
|
status = stepResult.Status.String()
|
||||||
case failed:
|
|
||||||
status = failed.String()
|
|
||||||
case undefined:
|
|
||||||
status = undefined.String()
|
|
||||||
case pending:
|
|
||||||
status = pending.String()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,20 +183,20 @@ func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_Pickl
|
||||||
}{
|
}{
|
||||||
"TestCaseFinished",
|
"TestCaseFinished",
|
||||||
f.scenarioLocation(pickle),
|
f.scenarioLocation(pickle),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
status,
|
status,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep, def *StepDefinition) {
|
func (f *eventsFormatter) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep, def *models.StepDefinition) {
|
||||||
f.basefmt.Defined(pickle, pickleStep, def)
|
f.Basefmt.Defined(pickle, pickleStep, def)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
if def != nil {
|
if def != nil {
|
||||||
m := def.Expr.FindStringSubmatchIndex(pickleStep.Text)[2:]
|
m := def.Expr.FindStringSubmatchIndex(pickleStep.Text)[2:]
|
||||||
|
@ -222,7 +221,7 @@ func (f *events) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_Pi
|
||||||
}{
|
}{
|
||||||
"StepDefinitionFound",
|
"StepDefinitionFound",
|
||||||
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
||||||
def.definitionID(),
|
DefinitionID(def),
|
||||||
args,
|
args,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -234,12 +233,12 @@ func (f *events) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_Pi
|
||||||
}{
|
}{
|
||||||
"TestStepStarted",
|
"TestStepStarted",
|
||||||
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
||||||
timeNowFunc().UnixNano() / nanoSec,
|
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *eventsFormatter) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||||
f.basefmt.Passed(pickle, step, match)
|
f.Basefmt.Passed(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -247,8 +246,8 @@ func (f *events) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.step(pickle, step)
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *eventsFormatter) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||||
f.basefmt.Skipped(pickle, step, match)
|
f.Basefmt.Skipped(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -256,8 +255,8 @@ func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.step(pickle, step)
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *eventsFormatter) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||||
f.basefmt.Undefined(pickle, step, match)
|
f.Basefmt.Undefined(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -265,8 +264,8 @@ func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.step(pickle, step)
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
func (f *eventsFormatter) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition, err error) {
|
||||||
f.basefmt.Failed(pickle, step, match, err)
|
f.Basefmt.Failed(pickle, step, match, err)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -274,8 +273,8 @@ func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.step(pickle, step)
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *eventsFormatter) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||||
f.basefmt.Pending(pickle, step, match)
|
f.Basefmt.Pending(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -283,15 +282,19 @@ func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.step(pickle, step)
|
f.step(pickle, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) scenarioLocation(pickle *messages.Pickle) string {
|
func (f *eventsFormatter) scenarioLocation(pickle *messages.Pickle) string {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
scenario := feature.findScenario(pickle.AstNodeIds[0])
|
scenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
|
|
||||||
line := scenario.Location.Line
|
line := scenario.Location.Line
|
||||||
if len(pickle.AstNodeIds) == 2 {
|
if len(pickle.AstNodeIds) == 2 {
|
||||||
_, row := feature.findExample(pickle.AstNodeIds[1])
|
_, row := feature.FindExample(pickle.AstNodeIds[1])
|
||||||
line = row.Location.Line
|
line = row.Location.Line
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s:%d", pickle.Uri, line)
|
return fmt.Sprintf("%s:%d", pickle.Uri, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLastStep(pickle *messages.Pickle, step *messages.Pickle_PickleStep) bool {
|
||||||
|
return pickle.Steps[len(pickle.Steps)-1].Id == step.Id
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
@ -8,18 +8,22 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("junit", "Prints junit compatible xml to stdout", junitFunc)
|
formatters.Format("junit", "Prints junit compatible xml to stdout", JUnitFormatterFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func junitFunc(suite string, out io.Writer) Formatter {
|
// JUnitFormatterFunc implements the FormatterFunc for the junit formatter
|
||||||
return &junitFormatter{basefmt: newBaseFmt(suite, out)}
|
func JUnitFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||||
|
return &junitFormatter{Basefmt: NewBaseFmt(suite, out)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitFormatter struct {
|
type junitFormatter struct {
|
||||||
*basefmt
|
*Basefmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *junitFormatter) Summary() {
|
func (f *junitFormatter) Summary() {
|
||||||
|
@ -41,20 +45,20 @@ func junitTimeDuration(from, to time.Time) string {
|
||||||
return strconv.FormatFloat(to.Sub(from).Seconds(), 'f', -1, 64)
|
return strconv.FormatFloat(to.Sub(from).Seconds(), 'f', -1, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
func (f *junitFormatter) buildJUNITPackageSuite() JunitPackageSuite {
|
||||||
features := f.storage.mustGetFeatures()
|
features := f.storage.MustGetFeatures()
|
||||||
sort.Sort(sortFeaturesByName(features))
|
sort.Sort(sortFeaturesByName(features))
|
||||||
|
|
||||||
testRunStartedAt := f.storage.mustGetTestRunStarted().StartedAt
|
testRunStartedAt := f.storage.MustGetTestRunStarted().StartedAt
|
||||||
|
|
||||||
suite := junitPackageSuite{
|
suite := JunitPackageSuite{
|
||||||
Name: f.suiteName,
|
Name: f.suiteName,
|
||||||
TestSuites: make([]*junitTestSuite, len(features)),
|
TestSuites: make([]*junitTestSuite, len(features)),
|
||||||
Time: junitTimeDuration(testRunStartedAt, timeNowFunc()),
|
Time: junitTimeDuration(testRunStartedAt, utils.TimeNowFunc()),
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx, feature := range features {
|
for idx, feature := range features {
|
||||||
pickles := f.storage.mustGetPickles(feature.Uri)
|
pickles := f.storage.MustGetPickles(feature.Uri)
|
||||||
sort.Sort(sortPicklesByID(pickles))
|
sort.Sort(sortPicklesByID(pickles))
|
||||||
|
|
||||||
ts := junitTestSuite{
|
ts := junitTestSuite{
|
||||||
|
@ -74,7 +78,7 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||||
for idx, pickle := range pickles {
|
for idx, pickle := range pickles {
|
||||||
tc := junitTestCase{}
|
tc := junitTestCase{}
|
||||||
|
|
||||||
pickleResult := f.storage.mustGetPickleResult(pickle.Id)
|
pickleResult := f.storage.MustGetPickleResult(pickle.Id)
|
||||||
|
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
firstPickleStartedAt = pickleResult.StartedAt
|
firstPickleStartedAt = pickleResult.StartedAt
|
||||||
|
@ -84,8 +88,8 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||||
|
|
||||||
if len(pickle.Steps) > 0 {
|
if len(pickle.Steps) > 0 {
|
||||||
lastStep := pickle.Steps[len(pickle.Steps)-1]
|
lastStep := pickle.Steps[len(pickle.Steps)-1]
|
||||||
lastPickleStepResult := f.storage.mustGetPickleStepResult(lastStep.Id)
|
lastPickleStepResult := f.storage.MustGetPickleStepResult(lastStep.Id)
|
||||||
lastPickleFinishedAt = lastPickleStepResult.finishedAt
|
lastPickleFinishedAt = lastPickleStepResult.FinishedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
tc.Time = junitTimeDuration(pickleResult.StartedAt, lastPickleFinishedAt)
|
tc.Time = junitTimeDuration(pickleResult.StartedAt, lastPickleFinishedAt)
|
||||||
|
@ -99,9 +103,9 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||||
ts.Tests++
|
ts.Tests++
|
||||||
suite.Tests++
|
suite.Tests++
|
||||||
|
|
||||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
for _, stepResult := range pickleStepResults {
|
for _, stepResult := range pickleStepResults {
|
||||||
pickleStep := f.storage.mustGetPickleStep(stepResult.PickleStepID)
|
pickleStep := f.storage.MustGetPickleStep(stepResult.PickleStepID)
|
||||||
|
|
||||||
switch stepResult.Status {
|
switch stepResult.Status {
|
||||||
case passed:
|
case passed:
|
||||||
|
@ -109,7 +113,7 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||||
case failed:
|
case failed:
|
||||||
tc.Status = failed.String()
|
tc.Status = failed.String()
|
||||||
tc.Failure = &junitFailure{
|
tc.Failure = &junitFailure{
|
||||||
Message: fmt.Sprintf("Step %s: %s", pickleStep.Text, stepResult.err),
|
Message: fmt.Sprintf("Step %s: %s", pickleStep.Text, stepResult.Err),
|
||||||
}
|
}
|
||||||
case skipped:
|
case skipped:
|
||||||
tc.Error = append(tc.Error, &junitError{
|
tc.Error = append(tc.Error, &junitError{
|
||||||
|
@ -182,7 +186,8 @@ type junitTestSuite struct {
|
||||||
TestCases []*junitTestCase
|
TestCases []*junitTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitPackageSuite struct {
|
// JunitPackageSuite ...
|
||||||
|
type JunitPackageSuite struct {
|
||||||
XMLName xml.Name `xml:"testsuites"`
|
XMLName xml.Name `xml:"testsuites"`
|
||||||
Name string `xml:"name,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Tests int `xml:"tests,attr"`
|
Tests int `xml:"tests,attr"`
|
|
@ -1,4 +1,4 @@
|
||||||
package godog_test
|
package formatters_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -11,26 +11,29 @@ import (
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("pretty", "Prints every feature with runtime statuses.", prettyFunc)
|
formatters.Format("pretty", "Prints every feature with runtime statuses.", PrettyFormatterFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prettyFunc(suite string, out io.Writer) Formatter {
|
// PrettyFormatterFunc implements the FormatterFunc for the pretty formatter
|
||||||
return &pretty{basefmt: newBaseFmt(suite, out)}
|
func PrettyFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||||
|
return &pretty{Basefmt: NewBaseFmt(suite, out)}
|
||||||
}
|
}
|
||||||
|
|
||||||
var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>")
|
var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>")
|
||||||
|
|
||||||
// a built in default pretty formatter
|
// a built in default pretty formatter
|
||||||
type pretty struct {
|
type pretty struct {
|
||||||
*basefmt
|
*Basefmt
|
||||||
firstFeature *bool
|
firstFeature *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) TestRunStarted() {
|
func (f *pretty) TestRunStarted() {
|
||||||
f.basefmt.TestRunStarted()
|
f.Basefmt.TestRunStarted()
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -48,7 +51,7 @@ func (f *pretty) Feature(gd *messages.GherkinDocument, p string, c []byte) {
|
||||||
*f.firstFeature = false
|
*f.firstFeature = false
|
||||||
f.lock.Unlock()
|
f.lock.Unlock()
|
||||||
|
|
||||||
f.basefmt.Feature(gd, p, c)
|
f.Basefmt.Feature(gd, p, c)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -58,7 +61,7 @@ func (f *pretty) Feature(gd *messages.GherkinDocument, p string, c []byte) {
|
||||||
|
|
||||||
// Pickle takes a gherkin node for formatting
|
// Pickle takes a gherkin node for formatting
|
||||||
func (f *pretty) Pickle(pickle *messages.Pickle) {
|
func (f *pretty) Pickle(pickle *messages.Pickle) {
|
||||||
f.basefmt.Pickle(pickle)
|
f.Basefmt.Pickle(pickle)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -69,8 +72,8 @@ func (f *pretty) Pickle(pickle *messages.Pickle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *pretty) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||||
f.basefmt.Passed(pickle, step, match)
|
f.Basefmt.Passed(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -78,8 +81,8 @@ func (f *pretty) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.printStep(pickle, step)
|
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 *models.StepDefinition) {
|
||||||
f.basefmt.Skipped(pickle, step, match)
|
f.Basefmt.Skipped(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -87,8 +90,8 @@ func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
||||||
f.printStep(pickle, step)
|
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 *models.StepDefinition) {
|
||||||
f.basefmt.Undefined(pickle, step, match)
|
f.Basefmt.Undefined(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -96,8 +99,8 @@ func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.printStep(pickle, step)
|
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 *models.StepDefinition, err error) {
|
||||||
f.basefmt.Failed(pickle, step, match, err)
|
f.Basefmt.Failed(pickle, step, match, err)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -105,8 +108,8 @@ func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
||||||
f.printStep(pickle, step)
|
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 *models.StepDefinition) {
|
||||||
f.basefmt.Pending(pickle, step, match)
|
f.Basefmt.Pending(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -132,9 +135,9 @@ func keywordAndName(keyword, name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) scenarioLengths(pickle *messages.Pickle) (scenarioHeaderLength int, maxLength int) {
|
func (f *pretty) scenarioLengths(pickle *messages.Pickle) (scenarioHeaderLength int, maxLength int) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
astBackground := feature.findBackground(pickle.AstNodeIds[0])
|
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
|
||||||
|
|
||||||
scenarioHeaderLength = f.lengthPickle(astScenario.Keyword, astScenario.Name)
|
scenarioHeaderLength = f.lengthPickle(astScenario.Keyword, astScenario.Name)
|
||||||
maxLength = f.longestStep(astScenario.Steps, scenarioHeaderLength)
|
maxLength = f.longestStep(astScenario.Steps, scenarioHeaderLength)
|
||||||
|
@ -147,16 +150,16 @@ func (f *pretty) scenarioLengths(pickle *messages.Pickle) (scenarioHeaderLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printScenarioHeader(pickle *messages.Pickle, astScenario *messages.GherkinDocument_Feature_Scenario, spaceFilling int) {
|
func (f *pretty) printScenarioHeader(pickle *messages.Pickle, astScenario *messages.GherkinDocument_Feature_Scenario, spaceFilling int) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
text := s(f.indent) + keywordAndName(astScenario.Keyword, astScenario.Name)
|
text := s(f.indent) + keywordAndName(astScenario.Keyword, astScenario.Name)
|
||||||
text += s(spaceFilling) + line(feature.Uri, astScenario.Location)
|
text += s(spaceFilling) + line(feature.Uri, astScenario.Location)
|
||||||
fmt.Fprintln(f.out, "\n"+text)
|
fmt.Fprintln(f.out, "\n"+text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printUndefinedPickle(pickle *messages.Pickle) {
|
func (f *pretty) printUndefinedPickle(pickle *messages.Pickle) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
astBackground := feature.findBackground(pickle.AstNodeIds[0])
|
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
|
||||||
|
|
||||||
scenarioHeaderLength, maxLength := f.scenarioLengths(pickle)
|
scenarioHeaderLength, maxLength := f.scenarioLengths(pickle)
|
||||||
|
|
||||||
|
@ -170,7 +173,7 @@ func (f *pretty) printUndefinedPickle(pickle *messages.Pickle) {
|
||||||
|
|
||||||
// do not print scenario headers and examples multiple times
|
// do not print scenario headers and examples multiple times
|
||||||
if len(astScenario.Examples) > 0 {
|
if len(astScenario.Examples) > 0 {
|
||||||
exampleTable, exampleRow := feature.findExample(pickle.AstNodeIds[1])
|
exampleTable, exampleRow := feature.FindExample(pickle.AstNodeIds[1])
|
||||||
firstExampleRow := exampleTable.TableBody[0].Id == exampleRow.Id
|
firstExampleRow := exampleTable.TableBody[0].Id == exampleRow.Id
|
||||||
firstExamplesTable := astScenario.Examples[0].Location.Line == exampleTable.Location.Line
|
firstExamplesTable := astScenario.Examples[0].Location.Line == exampleTable.Location.Line
|
||||||
|
|
||||||
|
@ -197,45 +200,45 @@ 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.storage.mustGetPickleStepResultsByStatus(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))
|
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.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
|
|
||||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
scenarioDesc := fmt.Sprintf("%s: %s", astScenario.Keyword, pickle.Name)
|
scenarioDesc := fmt.Sprintf("%s: %s", astScenario.Keyword, pickle.Name)
|
||||||
|
|
||||||
astStep := feature.findStep(pickleStep.AstNodeIds[0])
|
astStep := feature.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)+line(feature.Uri, astScenario.Location))
|
fmt.Fprintln(f.out, s(f.indent)+red(scenarioDesc)+line(feature.Uri, astScenario.Location))
|
||||||
fmt.Fprintln(f.out, s(f.indent*2)+red(stepDesc)+line(feature.Uri, astStep.Location))
|
fmt.Fprintln(f.out, s(f.indent*2)+red(stepDesc)+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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.basefmt.Summary()
|
f.Basefmt.Summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps int) {
|
func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps int) {
|
||||||
var errorMsg string
|
var errorMsg string
|
||||||
var clr = green
|
var clr = green
|
||||||
|
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
scenarioHeaderLength, maxLength := f.scenarioLengths(pickle)
|
scenarioHeaderLength, maxLength := f.scenarioLengths(pickle)
|
||||||
|
|
||||||
exampleTable, exampleRow := feature.findExample(pickle.AstNodeIds[1])
|
exampleTable, exampleRow := feature.FindExample(pickle.AstNodeIds[1])
|
||||||
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
|
||||||
|
|
||||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||||
|
|
||||||
firstExecutedScenarioStep := len(pickleStepResults) == backgroundSteps+1
|
firstExecutedScenarioStep := len(pickleStepResults) == backgroundSteps+1
|
||||||
if firstExamplesTable && printExampleHeader && firstExecutedScenarioStep {
|
if firstExamplesTable && printExampleHeader && firstExecutedScenarioStep {
|
||||||
|
@ -257,10 +260,10 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
||||||
// 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.Color()
|
||||||
case result.Status == undefined || result.Status == pending:
|
case result.Status == undefined || result.Status == pending:
|
||||||
clr = result.Status.clr()
|
clr = result.Status.Color()
|
||||||
case result.Status == skipped && clr == nil:
|
case result.Status == skipped && clr == nil:
|
||||||
clr = cyan
|
clr = cyan
|
||||||
}
|
}
|
||||||
|
@ -268,11 +271,11 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
||||||
if firstExamplesTable && printExampleHeader {
|
if firstExamplesTable && printExampleHeader {
|
||||||
// in first example, we need to print steps
|
// in first example, we need to print steps
|
||||||
|
|
||||||
pickleStep := f.storage.mustGetPickleStep(result.PickleStepID)
|
pickleStep := f.storage.MustGetPickleStep(result.PickleStepID)
|
||||||
astStep := feature.findStep(pickleStep.AstNodeIds[0])
|
astStep := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
var text = ""
|
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
|
||||||
for i := 0; i < len(m); i++ {
|
for i := 0; i < len(m); i++ {
|
||||||
|
@ -290,7 +293,7 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
||||||
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("# "+DefinitionID(result.Def))
|
||||||
}
|
}
|
||||||
|
|
||||||
// print the step outline
|
// print the step outline
|
||||||
|
@ -340,10 +343,10 @@ func (f *pretty) printTableHeader(row *messages.GherkinDocument_Feature_TableRow
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
astBackground := feature.findBackground(pickle.AstNodeIds[0])
|
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
|
||||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
astStep := feature.findStep(pickleStep.AstNodeIds[0])
|
astStep := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||||
|
|
||||||
var astBackgroundStep bool
|
var astBackgroundStep bool
|
||||||
var firstExecutedBackgroundStep bool
|
var firstExecutedBackgroundStep bool
|
||||||
|
@ -360,7 +363,7 @@ func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
firstPickle := feature.pickles[0].Id == pickle.Id
|
firstPickle := feature.Pickles[0].Id == pickle.Id
|
||||||
|
|
||||||
if astBackgroundStep && !firstPickle {
|
if astBackgroundStep && !firstPickle {
|
||||||
return
|
return
|
||||||
|
@ -383,11 +386,11 @@ func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_
|
||||||
f.printScenarioHeader(pickle, astScenario, maxLength-scenarioHeaderLength)
|
f.printScenarioHeader(pickle, astScenario, maxLength-scenarioHeaderLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStep.Id)
|
pickleStepResult := f.storage.MustGetPickleStepResult(pickleStep.Id)
|
||||||
text := s(f.indent*2) + pickleStepResult.Status.clr()(strings.TrimSpace(astStep.Keyword)) + " " + pickleStepResult.Status.clr()(pickleStep.Text)
|
text := s(f.indent*2) + pickleStepResult.Status.Color()(strings.TrimSpace(astStep.Keyword)) + " " + pickleStepResult.Status.Color()(pickleStep.Text)
|
||||||
if pickleStepResult.def != nil {
|
if pickleStepResult.Def != nil {
|
||||||
text += s(maxLength - stepLength + 1)
|
text += s(maxLength - stepLength + 1)
|
||||||
text += blackb("# " + pickleStepResult.def.definitionID())
|
text += blackb("# " + DefinitionID(pickleStepResult.Def))
|
||||||
}
|
}
|
||||||
fmt.Fprintln(f.out, text)
|
fmt.Fprintln(f.out, text)
|
||||||
|
|
||||||
|
@ -399,8 +402,8 @@ func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_
|
||||||
f.printDocString(docString)
|
f.printDocString(docString)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pickleStepResult.err != nil {
|
if pickleStepResult.Err != nil {
|
||||||
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", pickleStepResult.err)))
|
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", pickleStepResult.Err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pickleStepResult.Status == pending {
|
if pickleStepResult.Status == pending {
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -8,23 +8,27 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("progress", "Prints a character per step.", progressFunc)
|
formatters.Format("progress", "Prints a character per step.", ProgressFormatterFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func progressFunc(suite string, out io.Writer) Formatter {
|
// ProgressFormatterFunc implements the FormatterFunc for the progress formatter
|
||||||
|
func ProgressFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||||
steps := 0
|
steps := 0
|
||||||
return &progress{
|
return &progress{
|
||||||
basefmt: newBaseFmt(suite, out),
|
Basefmt: NewBaseFmt(suite, out),
|
||||||
stepsPerRow: 70,
|
stepsPerRow: 70,
|
||||||
steps: &steps,
|
steps: &steps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type progress struct {
|
type progress struct {
|
||||||
*basefmt
|
*Basefmt
|
||||||
stepsPerRow int
|
stepsPerRow int
|
||||||
steps *int
|
steps *int
|
||||||
}
|
}
|
||||||
|
@ -41,20 +45,20 @@ func (f *progress) Summary() {
|
||||||
|
|
||||||
var failedStepsOutput []string
|
var failedStepsOutput []string
|
||||||
|
|
||||||
failedSteps := f.storage.mustGetPickleStepResultsByStatus(failed)
|
failedSteps := f.storage.MustGetPickleStepResultsByStatus(failed)
|
||||||
sort.Sort(sortPickleStepResultsByPickleStepID(failedSteps))
|
sort.Sort(sortPickleStepResultsByPickleStepID(failedSteps))
|
||||||
|
|
||||||
for _, sr := range failedSteps {
|
for _, sr := range failedSteps {
|
||||||
if sr.Status == failed {
|
if sr.Status == failed {
|
||||||
pickle := f.storage.mustGetPickle(sr.PickleID)
|
pickle := f.storage.MustGetPickle(sr.PickleID)
|
||||||
pickleStep := f.storage.mustGetPickleStep(sr.PickleStepID)
|
pickleStep := f.storage.MustGetPickleStep(sr.PickleStepID)
|
||||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||||
|
|
||||||
sc := feature.findScenario(pickle.AstNodeIds[0])
|
sc := feature.FindScenario(pickle.AstNodeIds[0])
|
||||||
scenarioDesc := fmt.Sprintf("%s: %s", sc.Keyword, pickle.Name)
|
scenarioDesc := fmt.Sprintf("%s: %s", sc.Keyword, pickle.Name)
|
||||||
scenarioLine := fmt.Sprintf("%s:%d", pickle.Uri, sc.Location.Line)
|
scenarioLine := fmt.Sprintf("%s:%d", pickle.Uri, sc.Location.Line)
|
||||||
|
|
||||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||||
stepDesc := strings.TrimSpace(step.Keyword) + " " + pickleStep.Text
|
stepDesc := strings.TrimSpace(step.Keyword) + " " + pickleStep.Text
|
||||||
stepLine := fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line)
|
stepLine := fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line)
|
||||||
|
|
||||||
|
@ -62,7 +66,7 @@ func (f *progress) Summary() {
|
||||||
failedStepsOutput,
|
failedStepsOutput,
|
||||||
s(2)+red(scenarioDesc)+blackb(" # "+scenarioLine),
|
s(2)+red(scenarioDesc)+blackb(" # "+scenarioLine),
|
||||||
s(4)+red(stepDesc)+blackb(" # "+stepLine),
|
s(4)+red(stepDesc)+blackb(" # "+stepLine),
|
||||||
s(6)+red("Error: ")+redb(fmt.Sprintf("%+v", sr.err)),
|
s(6)+red("Error: ")+redb(fmt.Sprintf("%+v", sr.Err)),
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -74,11 +78,11 @@ func (f *progress) Summary() {
|
||||||
}
|
}
|
||||||
fmt.Fprintln(f.out, "")
|
fmt.Fprintln(f.out, "")
|
||||||
|
|
||||||
f.basefmt.Summary()
|
f.Basefmt.Summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) step(pickleStepID string) {
|
func (f *progress) step(pickleStepID string) {
|
||||||
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStepID)
|
pickleStepResult := f.storage.MustGetPickleStepResult(pickleStepID)
|
||||||
|
|
||||||
switch pickleStepResult.Status {
|
switch pickleStepResult.Status {
|
||||||
case passed:
|
case passed:
|
||||||
|
@ -100,8 +104,8 @@ func (f *progress) step(pickleStepID string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||||
f.basefmt.Passed(pickle, step, match)
|
f.Basefmt.Passed(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -109,8 +113,8 @@ func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleS
|
||||||
f.step(step.Id)
|
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 *models.StepDefinition) {
|
||||||
f.basefmt.Skipped(pickle, step, match)
|
f.Basefmt.Skipped(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -118,8 +122,8 @@ func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
||||||
f.step(step.Id)
|
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 *models.StepDefinition) {
|
||||||
f.basefmt.Undefined(pickle, step, match)
|
f.Basefmt.Undefined(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -127,8 +131,8 @@ func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pick
|
||||||
f.step(step.Id)
|
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 *models.StepDefinition, err error) {
|
||||||
f.basefmt.Failed(pickle, step, match, err)
|
f.Basefmt.Failed(pickle, step, match, err)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
@ -136,8 +140,8 @@ func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleS
|
||||||
f.step(step.Id)
|
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 *models.StepDefinition) {
|
||||||
f.basefmt.Pending(pickle, step, match)
|
f.Basefmt.Pending(pickle, step, match)
|
||||||
|
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
|
@ -1,57 +1,57 @@
|
||||||
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
||||||
{"event":"TestSource","location":"formatter-tests/features/scenario_outline.feature:2","source":"@outline @tag\nFeature: outline\n\n @scenario\n Scenario Outline: outline\n Given passing step\n When passing step\n Then odd \u003codd\u003e and even \u003ceven\u003e number\n\n @tagged\n Examples: tagged\n | odd | even |\n | 1 | 2 |\n | 2 | 0 |\n | 3 | 11 |\n\n @tag2\n Examples:\n | odd | even |\n | 1 | 14 |\n | 3 | 9 |\n"}
|
{"event":"TestSource","location":"formatter-tests/features/scenario_outline.feature:2","source":"@outline @tag\nFeature: outline\n\n @scenario\n Scenario Outline: outline\n Given passing step\n When passing step\n Then odd \u003codd\u003e and even \u003ceven\u003e number\n\n @tagged\n Examples: tagged\n | odd | even |\n | 1 | 2 |\n | 2 | 0 |\n | 3 | 11 |\n\n @tag2\n Examples:\n | odd | even |\n | 1 | 14 |\n | 3 | 9 |\n"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:13","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:13","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog/internal/formatters_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:13","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:13","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:14","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:14","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog/internal/formatters_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"2 is not odd"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"2 is not odd"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:14","timestamp":-6795364578871,"status":"failed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:14","timestamp":-6795364578871,"status":"failed"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:15","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:15","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog/internal/formatters_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"11 is not even"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"11 is not even"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:15","timestamp":-6795364578871,"status":"failed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:15","timestamp":-6795364578871,"status":"failed"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:20","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:20","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog/internal/formatters_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:20","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:20","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:21","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_outline.feature:21","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:6","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:7","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_outline.feature:8","definition_id":"fmt_output_test.go:103 -\u003e github.com/cucumber/godog/internal/formatters_test.oddEvenStepDef","arguments":[[4,5],[5,15]]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"9 is not even"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_outline.feature:8","timestamp":-6795364578871,"status":"failed","summary":"9 is not even"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:21","timestamp":-6795364578871,"status":"failed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_outline.feature:21","timestamp":-6795364578871,"status":"failed"}
|
|
@ -1,16 +1,16 @@
|
||||||
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
||||||
{"event":"TestSource","location":"formatter-tests/features/scenario_with_background.feature:1","source":"Feature: single scenario with background\n\n Background: named\n Given passing step\n And passing step\n\n Scenario: scenario\n When passing step\n Then passing step\n"}
|
{"event":"TestSource","location":"formatter-tests/features/scenario_with_background.feature:1","source":"Feature: single scenario with background\n\n Background: named\n Given passing step\n And passing step\n\n Scenario: scenario\n When passing step\n Then passing step\n"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_with_background.feature:7","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/scenario_with_background.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:4","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:4","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:4","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:4","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:5","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:5","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:5","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:5","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:5","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:5","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:8","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:8","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:8","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:8","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:9","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/scenario_with_background.feature:9","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:9","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/scenario_with_background.feature:9","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:9","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/scenario_with_background.feature:9","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_with_background.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/scenario_with_background.feature:7","timestamp":-6795364578871,"status":"passed"}
|
|
@ -1,7 +1,7 @@
|
||||||
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
||||||
{"event":"TestSource","location":"formatter-tests/features/single_scenario_with_passing_step.feature:1","source":"Feature: single passing scenario\n describes\n a single scenario\n feature\n\n Scenario: one step passing\n Given a passing step\n"}
|
{"event":"TestSource","location":"formatter-tests/features/single_scenario_with_passing_step.feature:1","source":"Feature: single passing scenario\n describes\n a single scenario\n feature\n\n Scenario: one step passing\n Given a passing step\n"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/single_scenario_with_passing_step.feature:6","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/single_scenario_with_passing_step.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/single_scenario_with_passing_step.feature:7","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/single_scenario_with_passing_step.feature:6","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/single_scenario_with_passing_step.feature:6","timestamp":-6795364578871,"status":"passed"}
|
|
@ -1,28 +1,28 @@
|
||||||
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
||||||
{"event":"TestSource","location":"formatter-tests/features/some_scenarions_including_failing.feature:1","source":"Feature: some scenarios\n\n Scenario: failing\n Given passing step\n When failing step\n Then passing step\n\n Scenario: pending\n When pending step\n Then passing step\n\n Scenario: undefined\n When undefined\n Then passing step\n"}
|
{"event":"TestSource","location":"formatter-tests/features/some_scenarions_including_failing.feature:1","source":"Feature: some scenarios\n\n Scenario: failing\n Given passing step\n When failing step\n Then passing step\n\n Scenario: pending\n When pending step\n Then passing step\n\n Scenario: undefined\n When undefined\n Then passing step\n"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:4","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog/internal/formatters_test.failingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871,"status":"skipped"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:6","timestamp":-6795364578871,"status":"skipped"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871,"status":"failed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:3","timestamp":-6795364578871,"status":"failed"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","definition_id":"fmt_output_test.go:115 -\u003e github.com/cucumber/godog_test.pendingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","definition_id":"fmt_output_test.go:115 -\u003e github.com/cucumber/godog/internal/formatters_test.pendingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871,"status":"pending"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:9","timestamp":-6795364578871,"status":"pending"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871,"status":"skipped"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:10","timestamp":-6795364578871,"status":"skipped"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871,"status":"pending"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:8","timestamp":-6795364578871,"status":"pending"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871,"status":"undefined"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:13","timestamp":-6795364578871,"status":"undefined"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871,"status":"skipped"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:14","timestamp":-6795364578871,"status":"skipped"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871,"status":"undefined"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/some_scenarions_including_failing.feature:12","timestamp":-6795364578871,"status":"undefined"}
|
|
@ -1,27 +1,27 @@
|
||||||
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
{"event":"TestRunStarted","version":"0.1.0","timestamp":-6795364578871,"suite":"events"}
|
||||||
{"event":"TestSource","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:1","source":"Feature: two scenarios with background fail\n\n Background:\n Given passing step\n And failing step\n\n Scenario: one\n When passing step\n Then passing step\n\n Scenario: two\n Then passing step\n"}
|
{"event":"TestSource","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:1","source":"Feature: two scenarios with background fail\n\n Background:\n Given passing step\n And failing step\n\n Scenario: one\n When passing step\n Then passing step\n\n Scenario: two\n Then passing step\n"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:7","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:7","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog/internal/formatters_test.failingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","timestamp":-6795364578871,"status":"skipped"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:8","timestamp":-6795364578871,"status":"skipped"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","timestamp":-6795364578871,"status":"skipped"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:9","timestamp":-6795364578871,"status":"skipped"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:7","timestamp":-6795364578871,"status":"failed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:7","timestamp":-6795364578871,"status":"failed"}
|
||||||
{"event":"TestCaseStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:11","timestamp":-6795364578871}
|
{"event":"TestCaseStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:11","timestamp":-6795364578871}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871,"status":"passed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:4","timestamp":-6795364578871,"status":"passed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog_test.failingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","definition_id":"fmt_output_test.go:117 -\u003e github.com/cucumber/godog/internal/formatters_test.failingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:5","timestamp":-6795364578871,"status":"failed","summary":"step failed"}
|
||||||
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog_test.passingStepDef","arguments":[]}
|
{"event":"StepDefinitionFound","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","definition_id":"fmt_output_test.go:101 -\u003e github.com/cucumber/godog/internal/formatters_test.passingStepDef","arguments":[]}
|
||||||
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","timestamp":-6795364578871}
|
{"event":"TestStepStarted","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","timestamp":-6795364578871}
|
||||||
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","timestamp":-6795364578871,"status":"skipped"}
|
{"event":"TestStepFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:12","timestamp":-6795364578871,"status":"skipped"}
|
||||||
{"event":"TestCaseFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:11","timestamp":-6795364578871,"status":"failed"}
|
{"event":"TestCaseFinished","location":"formatter-tests/features/two_scenarios_with_background_fail.feature:11","timestamp":-6795364578871,"status":"failed"}
|
|
@ -1,9 +1,9 @@
|
||||||
<bold-white>Feature:</bold-white> outline
|
<bold-white>Feature:</bold-white> outline
|
||||||
|
|
||||||
<bold-white>Scenario Outline:</bold-white> outline <bold-black># formatter-tests/features/scenario_outline.feature:5</bold-black>
|
<bold-white>Scenario Outline:</bold-white> outline <bold-black># formatter-tests/features/scenario_outline.feature:5</bold-black>
|
||||||
<cyan>Given</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>Given</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<cyan>When</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>When</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<cyan>Then</cyan> <cyan>odd </cyan><bold-cyan><odd></bold-cyan><cyan> and even </cyan><bold-cyan><even></bold-cyan><cyan> number</cyan> <bold-black># fmt_output_test.go:103 -> github.com/cucumber/godog_test.oddEvenStepDef</bold-black>
|
<cyan>Then</cyan> <cyan>odd </cyan><bold-cyan><odd></bold-cyan><cyan> and even </cyan><bold-cyan><even></bold-cyan><cyan> number</cyan> <bold-black># fmt_output_test.go:103 -> github.com/cucumber/godog/internal/formatters_test.oddEvenStepDef</bold-black>
|
||||||
|
|
||||||
<bold-white>Examples:</bold-white> tagged
|
<bold-white>Examples:</bold-white> tagged
|
||||||
| <cyan>odd</cyan> | <cyan>even</cyan> |
|
| <cyan>odd</cyan> | <cyan>even</cyan> |
|
|
@ -1,12 +1,12 @@
|
||||||
<bold-white>Feature:</bold-white> single scenario with background
|
<bold-white>Feature:</bold-white> single scenario with background
|
||||||
|
|
||||||
<bold-white>Background:</bold-white> named
|
<bold-white>Background:</bold-white> named
|
||||||
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<green>And</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>And</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> scenario <bold-black># formatter-tests/features/scenario_with_background.feature:7</bold-black>
|
<bold-white>Scenario:</bold-white> scenario <bold-black># formatter-tests/features/scenario_with_background.feature:7</bold-black>
|
||||||
<green>When</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>When</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<green>Then</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>Then</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
1 scenarios (<green>1 passed</green>)
|
1 scenarios (<green>1 passed</green>)
|
||||||
4 steps (<green>4 passed</green>)
|
4 steps (<green>4 passed</green>)
|
|
@ -4,7 +4,7 @@
|
||||||
feature
|
feature
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> one step passing <bold-black># formatter-tests/features/single_scenario_with_passing_step.feature:6</bold-black>
|
<bold-white>Scenario:</bold-white> one step passing <bold-black># formatter-tests/features/single_scenario_with_passing_step.feature:6</bold-black>
|
||||||
<green>Given</green> <green>a passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>Given</green> <green>a passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
1 scenarios (<green>1 passed</green>)
|
1 scenarios (<green>1 passed</green>)
|
||||||
1 steps (<green>1 passed</green>)
|
1 steps (<green>1 passed</green>)
|
|
@ -1,19 +1,19 @@
|
||||||
<bold-white>Feature:</bold-white> some scenarios
|
<bold-white>Feature:</bold-white> some scenarios
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> failing <bold-black># formatter-tests/features/some_scenarions_including_failing.feature:3</bold-black>
|
<bold-white>Scenario:</bold-white> failing <bold-black># formatter-tests/features/some_scenarions_including_failing.feature:3</bold-black>
|
||||||
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<red>When</red> <red>failing step</red> <bold-black># fmt_output_test.go:117 -> github.com/cucumber/godog_test.failingStepDef</bold-black>
|
<red>When</red> <red>failing step</red> <bold-black># fmt_output_test.go:117 -> github.com/cucumber/godog/internal/formatters_test.failingStepDef</bold-black>
|
||||||
<bold-red>step failed</bold-red>
|
<bold-red>step failed</bold-red>
|
||||||
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> pending <bold-black># formatter-tests/features/some_scenarions_including_failing.feature:8</bold-black>
|
<bold-white>Scenario:</bold-white> pending <bold-black># formatter-tests/features/some_scenarions_including_failing.feature:8</bold-black>
|
||||||
<yellow>When</yellow> <yellow>pending step</yellow> <bold-black># fmt_output_test.go:115 -> github.com/cucumber/godog_test.pendingStepDef</bold-black>
|
<yellow>When</yellow> <yellow>pending step</yellow> <bold-black># fmt_output_test.go:115 -> github.com/cucumber/godog/internal/formatters_test.pendingStepDef</bold-black>
|
||||||
<yellow>TODO: write pending definition</yellow>
|
<yellow>TODO: write pending definition</yellow>
|
||||||
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> undefined <bold-black># formatter-tests/features/some_scenarions_including_failing.feature:12</bold-black>
|
<bold-white>Scenario:</bold-white> undefined <bold-black># formatter-tests/features/some_scenarions_including_failing.feature:12</bold-black>
|
||||||
<yellow>When</yellow> <yellow>undefined</yellow>
|
<yellow>When</yellow> <yellow>undefined</yellow>
|
||||||
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
--- <red>Failed steps:</red>
|
--- <red>Failed steps:</red>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<bold-white>Feature:</bold-white> two scenarios with background fail
|
<bold-white>Feature:</bold-white> two scenarios with background fail
|
||||||
|
|
||||||
<bold-white>Background:</bold-white>
|
<bold-white>Background:</bold-white>
|
||||||
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<red>And</red> <red>failing step</red> <bold-black># fmt_output_test.go:117 -> github.com/cucumber/godog_test.failingStepDef</bold-black>
|
<red>And</red> <red>failing step</red> <bold-black># fmt_output_test.go:117 -> github.com/cucumber/godog/internal/formatters_test.failingStepDef</bold-black>
|
||||||
<bold-red>step failed</bold-red>
|
<bold-red>step failed</bold-red>
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> one <bold-black># formatter-tests/features/two_scenarios_with_background_fail.feature:7</bold-black>
|
<bold-white>Scenario:</bold-white> one <bold-black># formatter-tests/features/two_scenarios_with_background_fail.feature:7</bold-black>
|
||||||
<cyan>When</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>When</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
<bold-white>Scenario:</bold-white> two <bold-black># formatter-tests/features/two_scenarios_with_background_fail.feature:11</bold-black>
|
<bold-white>Scenario:</bold-white> two <bold-black># formatter-tests/features/two_scenarios_with_background_fail.feature:11</bold-black>
|
||||||
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_test.passingStepDef</bold-black>
|
<cyan>Then</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog/internal/formatters_test.passingStepDef</bold-black>
|
||||||
|
|
||||||
--- <red>Failed steps:</red>
|
--- <red>Failed steps:</red>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package formatters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
24
internal/formatters/utils_test.go
Обычный файл
24
internal/formatters/utils_test.go
Обычный файл
|
@ -0,0 +1,24 @@
|
||||||
|
package formatters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// this zeroes the time throughout whole test suite
|
||||||
|
// and makes it easier to assert output
|
||||||
|
// activated only when godog tests are being run
|
||||||
|
func init() {
|
||||||
|
utils.TimeNowFunc = func() time.Time {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeNowFunc(t *testing.T) {
|
||||||
|
now := utils.TimeNowFunc()
|
||||||
|
if !now.IsZero() {
|
||||||
|
t.Fatalf("expected zeroed time, but got: %s", now.Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,20 @@
|
||||||
package godog
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
)
|
)
|
||||||
|
|
||||||
type feature struct {
|
// Feature is an internal object to group together
|
||||||
|
// the parsed gherkin document, the pickles and the
|
||||||
|
// raw content.
|
||||||
|
type Feature struct {
|
||||||
*messages.GherkinDocument
|
*messages.GherkinDocument
|
||||||
pickles []*messages.Pickle
|
Pickles []*messages.Pickle
|
||||||
content []byte
|
Content []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type sortFeaturesByName []*feature
|
// FindScenario ...
|
||||||
|
func (f Feature) FindScenario(astScenarioID string) *messages.GherkinDocument_Feature_Scenario {
|
||||||
func (s sortFeaturesByName) Len() int { return len(s) }
|
|
||||||
func (s sortFeaturesByName) Less(i, j int) bool { return s[i].Feature.Name < s[j].Feature.Name }
|
|
||||||
func (s sortFeaturesByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
func (f feature) findScenario(astScenarioID string) *messages.GherkinDocument_Feature_Scenario {
|
|
||||||
for _, child := range f.GherkinDocument.Feature.Children {
|
for _, child := range f.GherkinDocument.Feature.Children {
|
||||||
if sc := child.GetScenario(); sc != nil && sc.Id == astScenarioID {
|
if sc := child.GetScenario(); sc != nil && sc.Id == astScenarioID {
|
||||||
return sc
|
return sc
|
||||||
|
@ -26,7 +24,8 @@ func (f feature) findScenario(astScenarioID string) *messages.GherkinDocument_Fe
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f feature) findBackground(astScenarioID string) *messages.GherkinDocument_Feature_Background {
|
// FindBackground ...
|
||||||
|
func (f Feature) FindBackground(astScenarioID string) *messages.GherkinDocument_Feature_Background {
|
||||||
var bg *messages.GherkinDocument_Feature_Background
|
var bg *messages.GherkinDocument_Feature_Background
|
||||||
|
|
||||||
for _, child := range f.GherkinDocument.Feature.Children {
|
for _, child := range f.GherkinDocument.Feature.Children {
|
||||||
|
@ -42,7 +41,8 @@ func (f feature) findBackground(astScenarioID string) *messages.GherkinDocument_
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f feature) findExample(exampleAstID string) (*messages.GherkinDocument_Feature_Scenario_Examples, *messages.GherkinDocument_Feature_TableRow) {
|
// FindExample ...
|
||||||
|
func (f Feature) FindExample(exampleAstID string) (*messages.GherkinDocument_Feature_Scenario_Examples, *messages.GherkinDocument_Feature_TableRow) {
|
||||||
for _, child := range f.GherkinDocument.Feature.Children {
|
for _, child := range f.GherkinDocument.Feature.Children {
|
||||||
if sc := child.GetScenario(); sc != nil {
|
if sc := child.GetScenario(); sc != nil {
|
||||||
for _, example := range sc.Examples {
|
for _, example := range sc.Examples {
|
||||||
|
@ -58,7 +58,8 @@ func (f feature) findExample(exampleAstID string) (*messages.GherkinDocument_Fea
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f feature) findStep(astStepID string) *messages.GherkinDocument_Feature_Step {
|
// FindStep ...
|
||||||
|
func (f Feature) FindStep(astStepID string) *messages.GherkinDocument_Feature_Step {
|
||||||
for _, child := range f.GherkinDocument.Feature.Children {
|
for _, child := range f.GherkinDocument.Feature.Children {
|
||||||
if sc := child.GetScenario(); sc != nil {
|
if sc := child.GetScenario(); sc != nil {
|
||||||
for _, step := range sc.GetSteps() {
|
for _, step := range sc.GetSteps() {
|
60
internal/models/feature_test.go
Обычный файл
60
internal/models/feature_test.go
Обычный файл
|
@ -0,0 +1,60 @@
|
||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/testutils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Find(t *testing.T) {
|
||||||
|
ft := testutils.BuildTestFeature(t)
|
||||||
|
|
||||||
|
t.Run("scenario", func(t *testing.T) {
|
||||||
|
sc := ft.FindScenario(ft.Pickles[0].AstNodeIds[0])
|
||||||
|
assert.NotNilf(t, sc, "expected scenario to not be nil")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("background", func(t *testing.T) {
|
||||||
|
bg := ft.FindBackground(ft.Pickles[0].AstNodeIds[0])
|
||||||
|
assert.NotNilf(t, bg, "expected background to not be nil")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("example", func(t *testing.T) {
|
||||||
|
example, row := ft.FindExample(ft.Pickles[1].AstNodeIds[1])
|
||||||
|
assert.NotNilf(t, example, "expected example to not be nil")
|
||||||
|
assert.NotNilf(t, row, "expected table row to not be nil")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("step", func(t *testing.T) {
|
||||||
|
for _, ps := range ft.Pickles[0].Steps {
|
||||||
|
step := ft.FindStep(ps.AstNodeIds[0])
|
||||||
|
assert.NotNilf(t, step, "expected step to not be nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_NotFind(t *testing.T) {
|
||||||
|
ft := testutils.BuildTestFeature(t)
|
||||||
|
|
||||||
|
t.Run("scenario", func(t *testing.T) {
|
||||||
|
sc := ft.FindScenario("-")
|
||||||
|
assert.Nilf(t, sc, "expected scenario to be nil")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("background", func(t *testing.T) {
|
||||||
|
bg := ft.FindBackground("-")
|
||||||
|
assert.Nilf(t, bg, "expected background to be nil")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("example", func(t *testing.T) {
|
||||||
|
example, row := ft.FindExample("-")
|
||||||
|
assert.Nilf(t, example, "expected example to be nil")
|
||||||
|
assert.Nilf(t, row, "expected table row to be nil")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("step", func(t *testing.T) {
|
||||||
|
step := ft.FindStep("-")
|
||||||
|
assert.Nilf(t, step, "expected step to be nil")
|
||||||
|
})
|
||||||
|
}
|
84
internal/models/results.go
Обычный файл
84
internal/models/results.go
Обычный файл
|
@ -0,0 +1,84 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestRunStarted ...
|
||||||
|
type TestRunStarted struct {
|
||||||
|
StartedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// PickleResult ...
|
||||||
|
type PickleResult struct {
|
||||||
|
PickleID string
|
||||||
|
StartedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// PickleStepResult ...
|
||||||
|
type PickleStepResult struct {
|
||||||
|
Status StepResultStatus
|
||||||
|
FinishedAt time.Time
|
||||||
|
Err error
|
||||||
|
|
||||||
|
PickleID string
|
||||||
|
PickleStepID string
|
||||||
|
|
||||||
|
Def *StepDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStepResult ...
|
||||||
|
func NewStepResult(pickleID, pickleStepID string, match *StepDefinition) PickleStepResult {
|
||||||
|
return PickleStepResult{FinishedAt: utils.TimeNowFunc(), PickleID: pickleID, PickleStepID: pickleStepID, Def: match}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StepResultStatus ...
|
||||||
|
type StepResultStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Passed ...
|
||||||
|
Passed StepResultStatus = iota
|
||||||
|
// Failed ...
|
||||||
|
Failed
|
||||||
|
// Skipped ...
|
||||||
|
Skipped
|
||||||
|
// Undefined ...
|
||||||
|
Undefined
|
||||||
|
// Pending ...
|
||||||
|
Pending
|
||||||
|
)
|
||||||
|
|
||||||
|
// Color ...
|
||||||
|
func (st StepResultStatus) Color() colors.ColorFunc {
|
||||||
|
switch st {
|
||||||
|
case Passed:
|
||||||
|
return colors.Green
|
||||||
|
case Failed:
|
||||||
|
return colors.Red
|
||||||
|
case Skipped:
|
||||||
|
return colors.Cyan
|
||||||
|
default:
|
||||||
|
return colors.Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String ...
|
||||||
|
func (st StepResultStatus) String() string {
|
||||||
|
switch st {
|
||||||
|
case Passed:
|
||||||
|
return "passed"
|
||||||
|
case Failed:
|
||||||
|
return "failed"
|
||||||
|
case Skipped:
|
||||||
|
return "skipped"
|
||||||
|
case Undefined:
|
||||||
|
return "undefined"
|
||||||
|
case Pending:
|
||||||
|
return "pending"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
34
internal/models/results_test.go
Обычный файл
34
internal/models/results_test.go
Обычный файл
|
@ -0,0 +1,34 @@
|
||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepResultStatusTestCase struct {
|
||||||
|
st models.StepResultStatus
|
||||||
|
str string
|
||||||
|
clr colors.ColorFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
var stepResultStatusTestCases = []stepResultStatusTestCase{
|
||||||
|
{st: models.Passed, str: "passed", clr: colors.Green},
|
||||||
|
{st: models.Failed, str: "failed", clr: colors.Red},
|
||||||
|
{st: models.Skipped, str: "skipped", clr: colors.Cyan},
|
||||||
|
{st: models.Undefined, str: "undefined", clr: colors.Yellow},
|
||||||
|
{st: models.Pending, str: "pending", clr: colors.Yellow},
|
||||||
|
{st: -1, str: "unknown", clr: colors.Yellow},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_StepResultStatus(t *testing.T) {
|
||||||
|
for _, tc := range stepResultStatusTestCases {
|
||||||
|
t.Run(tc.str, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tc.str, tc.st.String())
|
||||||
|
assert.Equal(t, tc.clr(tc.str), tc.st.Color()(tc.str))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,35 +1,15 @@
|
||||||
package godog
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
)
|
)
|
||||||
|
|
||||||
var matchFuncDefRef = regexp.MustCompile(`\(([^\)]+)\)`)
|
var typeOfBytes = reflect.TypeOf([]byte(nil))
|
||||||
|
|
||||||
// Steps allows to nest steps
|
|
||||||
// instead of returning an error in step func
|
|
||||||
// it is possible to return combined steps:
|
|
||||||
//
|
|
||||||
// func multistep(name string) godog.Steps {
|
|
||||||
// return godog.Steps{
|
|
||||||
// fmt.Sprintf(`an user named "%s"`, name),
|
|
||||||
// fmt.Sprintf(`user "%s" is authenticated`, name),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// These steps will be matched and executed in
|
|
||||||
// sequential order. The first one which fails
|
|
||||||
// will result in main step failure.
|
|
||||||
type Steps []string
|
|
||||||
|
|
||||||
// StepDefinition is a registered step definition
|
// StepDefinition is a registered step definition
|
||||||
// contains a StepHandler and regexp which
|
// contains a StepHandler and regexp which
|
||||||
|
@ -40,50 +20,21 @@ type Steps []string
|
||||||
// when step is matched and is either failed
|
// when step is matched and is either failed
|
||||||
// or successful
|
// or successful
|
||||||
type StepDefinition struct {
|
type StepDefinition struct {
|
||||||
args []interface{}
|
Args []interface{}
|
||||||
hv reflect.Value
|
HandlerValue reflect.Value
|
||||||
Expr *regexp.Regexp
|
Expr *regexp.Regexp
|
||||||
Handler interface{}
|
Handler interface{}
|
||||||
|
|
||||||
// multistep related
|
// multistep related
|
||||||
nested bool
|
Nested bool
|
||||||
undefined []string
|
Undefined []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *StepDefinition) definitionID() string {
|
// Run a step with the matched arguments using reflect
|
||||||
ptr := sd.hv.Pointer()
|
func (sd *StepDefinition) Run() interface{} {
|
||||||
f := runtime.FuncForPC(ptr)
|
typ := sd.HandlerValue.Type()
|
||||||
file, line := f.FileLine(ptr)
|
if len(sd.Args) < typ.NumIn() {
|
||||||
dir := filepath.Dir(file)
|
return fmt.Errorf("func expects %d arguments, which is more than %d matched from step", typ.NumIn(), len(sd.Args))
|
||||||
|
|
||||||
fn := strings.Replace(f.Name(), dir, "", -1)
|
|
||||||
var parts []string
|
|
||||||
for _, gr := range matchFuncDefRef.FindAllStringSubmatch(fn, -1) {
|
|
||||||
parts = append(parts, strings.Trim(gr[1], "_."))
|
|
||||||
}
|
|
||||||
if len(parts) > 0 {
|
|
||||||
// case when suite is a structure with methods
|
|
||||||
fn = strings.Join(parts, ".")
|
|
||||||
} else {
|
|
||||||
// case when steps are just plain funcs
|
|
||||||
fn = strings.Trim(fn, "_.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if pkg := os.Getenv("GODOG_TESTED_PACKAGE"); len(pkg) > 0 {
|
|
||||||
fn = strings.Replace(fn, pkg, "", 1)
|
|
||||||
fn = strings.TrimLeft(fn, ".")
|
|
||||||
fn = strings.Replace(fn, "..", ".", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s:%d -> %s", filepath.Base(file), line, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// run a step with the matched arguments using
|
|
||||||
// reflect
|
|
||||||
func (sd *StepDefinition) run() interface{} {
|
|
||||||
typ := sd.hv.Type()
|
|
||||||
if len(sd.args) < typ.NumIn() {
|
|
||||||
return fmt.Errorf("func expects %d arguments, which is more than %d matched from step", typ.NumIn(), len(sd.args))
|
|
||||||
}
|
}
|
||||||
var values []reflect.Value
|
var values []reflect.Value
|
||||||
for i := 0; i < typ.NumIn(); i++ {
|
for i := 0; i < typ.NumIn(); i++ {
|
||||||
|
@ -166,7 +117,7 @@ func (sd *StepDefinition) run() interface{} {
|
||||||
}
|
}
|
||||||
values = append(values, reflect.ValueOf(float32(v)))
|
values = append(values, reflect.ValueOf(float32(v)))
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
arg := sd.args[i]
|
arg := sd.Args[i]
|
||||||
switch param.Elem().String() {
|
switch param.Elem().String() {
|
||||||
case "messages.PickleStepArgument_PickleDocString":
|
case "messages.PickleStepArgument_PickleDocString":
|
||||||
if v, ok := arg.(*messages.PickleStepArgument); ok {
|
if v, ok := arg.(*messages.PickleStepArgument); ok {
|
||||||
|
@ -211,11 +162,11 @@ func (sd *StepDefinition) run() interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd.hv.Call(values)[0].Interface()
|
return sd.HandlerValue.Call(values)[0].Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *StepDefinition) shouldBeString(idx int) (string, error) {
|
func (sd *StepDefinition) shouldBeString(idx int) (string, error) {
|
||||||
arg := sd.args[idx]
|
arg := sd.Args[idx]
|
||||||
s, ok := arg.(string)
|
s, ok := arg.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf(`cannot convert argument %d: "%v" of type "%T" to string`, idx, arg, arg)
|
return "", fmt.Errorf(`cannot convert argument %d: "%v" of type "%T" to string`, idx, arg, arg)
|
107
internal/models/stepdef_test.go
Обычный файл
107
internal/models/stepdef_test.go
Обычный файл
|
@ -0,0 +1,107 @@
|
||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShouldSupportIntTypes(t *testing.T) {
|
||||||
|
fn := func(a int64, b int32, c int16, d int8) error { return nil }
|
||||||
|
|
||||||
|
def := &models.StepDefinition{
|
||||||
|
Handler: fn,
|
||||||
|
HandlerValue: reflect.ValueOf(fn),
|
||||||
|
}
|
||||||
|
|
||||||
|
def.Args = []interface{}{"1", "1", "1", "1"}
|
||||||
|
if err := def.Run(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
def.Args = []interface{}{"1", "1", "1", strings.Repeat("1", 9)}
|
||||||
|
if err := def.Run(); err == nil {
|
||||||
|
t.Fatalf("expected convertion fail for int8, but got none")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldSupportFloatTypes(t *testing.T) {
|
||||||
|
fn := func(a float64, b float32) error { return nil }
|
||||||
|
|
||||||
|
def := &models.StepDefinition{
|
||||||
|
Handler: fn,
|
||||||
|
HandlerValue: reflect.ValueOf(fn),
|
||||||
|
}
|
||||||
|
|
||||||
|
def.Args = []interface{}{"1.1", "1.09"}
|
||||||
|
if err := def.Run(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
def.Args = []interface{}{"1.08", strings.Repeat("1", 65) + ".67"}
|
||||||
|
if err := def.Run(); err == nil {
|
||||||
|
t.Fatalf("expected convertion fail for float32, but got none")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldNotSupportOtherPointerTypesThanGherkin(t *testing.T) {
|
||||||
|
fn1 := func(a *int) error { return nil }
|
||||||
|
fn2 := func(a *messages.PickleStepArgument_PickleDocString) error { return nil }
|
||||||
|
fn3 := func(a *messages.PickleStepArgument_PickleTable) error { return nil }
|
||||||
|
|
||||||
|
def1 := &models.StepDefinition{Handler: fn1, HandlerValue: reflect.ValueOf(fn1), Args: []interface{}{(*int)(nil)}}
|
||||||
|
def2 := &models.StepDefinition{Handler: fn2, HandlerValue: reflect.ValueOf(fn2), Args: []interface{}{&messages.PickleStepArgument_PickleDocString{}}}
|
||||||
|
def3 := &models.StepDefinition{Handler: fn3, HandlerValue: reflect.ValueOf(fn3), Args: []interface{}{(*messages.PickleStepArgument_PickleTable)(nil)}}
|
||||||
|
|
||||||
|
if err := def1.Run(); err == nil {
|
||||||
|
t.Fatalf("expected conversion error, but got none")
|
||||||
|
}
|
||||||
|
if err := def2.Run(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if err := def3.Run(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldSupportOnlyByteSlice(t *testing.T) {
|
||||||
|
fn1 := func(a []byte) error { return nil }
|
||||||
|
fn2 := func(a []string) error { return nil }
|
||||||
|
|
||||||
|
def1 := &models.StepDefinition{Handler: fn1, HandlerValue: reflect.ValueOf(fn1), Args: []interface{}{"str"}}
|
||||||
|
def2 := &models.StepDefinition{Handler: fn2, HandlerValue: reflect.ValueOf(fn2), Args: []interface{}{[]string{}}}
|
||||||
|
|
||||||
|
if err := def1.Run(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if err := def2.Run(); err == nil {
|
||||||
|
t.Fatalf("expected conversion error, but got none")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnexpectedArguments(t *testing.T) {
|
||||||
|
fn := func(a, b int) error { return nil }
|
||||||
|
def := &models.StepDefinition{Handler: fn, HandlerValue: reflect.ValueOf(fn)}
|
||||||
|
|
||||||
|
def.Args = []interface{}{"1"}
|
||||||
|
if err := def.Run(); err == nil {
|
||||||
|
t.Fatalf("expected an error due to wrong number of arguments, but got none")
|
||||||
|
}
|
||||||
|
|
||||||
|
def.Args = []interface{}{"one", "two"}
|
||||||
|
if err := def.Run(); err == nil {
|
||||||
|
t.Fatalf("expected conversion error, but got none")
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO maybe we should support duration
|
||||||
|
// fn2 := func(err time.Duration) error { return nil }
|
||||||
|
// def = &models.StepDefinition{Handler: fn2, HandlerValue: reflect.ValueOf(fn2)}
|
||||||
|
|
||||||
|
// def.Args = []interface{}{"1"}
|
||||||
|
// if err := def.Run(); err == nil {
|
||||||
|
// t.Fatalf("expected an error due to wrong argument type, but got none")
|
||||||
|
// }
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package godog
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -6,6 +6,8 @@ import (
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
"github.com/hashicorp/go-memdb"
|
"github.com/hashicorp/go-memdb"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -31,15 +33,17 @@ const (
|
||||||
tablePickleStepResultIndexStatus string = "status"
|
tablePickleStepResultIndexStatus string = "status"
|
||||||
)
|
)
|
||||||
|
|
||||||
type storage struct {
|
// Storage is a thread safe in-mem storage
|
||||||
|
type Storage struct {
|
||||||
db *memdb.MemDB
|
db *memdb.MemDB
|
||||||
|
|
||||||
testRunStarted testRunStarted
|
testRunStarted models.TestRunStarted
|
||||||
lock *sync.Mutex
|
testRunStartedLock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorage() *storage {
|
// NewStorage will create an in-mem storage that
|
||||||
// Create the DB schema
|
// is used across concurrent runners and formatters
|
||||||
|
func NewStorage() *Storage {
|
||||||
schema := memdb.DBSchema{
|
schema := memdb.DBSchema{
|
||||||
Tables: map[string]*memdb.TableSchema{
|
Tables: map[string]*memdb.TableSchema{
|
||||||
tableFeature: {
|
tableFeature: {
|
||||||
|
@ -115,10 +119,12 @@ func newStorage() *storage {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &storage{db: db, lock: new(sync.Mutex)}
|
return &Storage{db: db, testRunStartedLock: new(sync.Mutex)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsertPickle(p *messages.Pickle) {
|
// MustInsertPickle will insert a pickle and it's steps,
|
||||||
|
// will panic on 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 {
|
||||||
|
@ -134,12 +140,14 @@ func (s *storage) mustInsertPickle(p *messages.Pickle) {
|
||||||
txn.Commit()
|
txn.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickle(id string) *messages.Pickle {
|
// MustGetPickle will retrieve a pickle by id and panic on error.
|
||||||
|
func (s *Storage) MustGetPickle(id string) *messages.Pickle {
|
||||||
v := s.mustFirst(tablePickle, tablePickleIndexID, id)
|
v := s.mustFirst(tablePickle, tablePickleIndexID, id)
|
||||||
return v.(*messages.Pickle)
|
return v.(*messages.Pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickles(uri string) (ps []*messages.Pickle) {
|
// MustGetPickles will retrieve pickles by URI and panic on error.
|
||||||
|
func (s *Storage) MustGetPickles(uri string) (ps []*messages.Pickle) {
|
||||||
it := s.mustGet(tablePickle, tablePickleIndexURI, uri)
|
it := s.mustGet(tablePickle, tablePickleIndexURI, uri)
|
||||||
for v := it.Next(); v != nil; v = it.Next() {
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
ps = append(ps, v.(*messages.Pickle))
|
ps = append(ps, v.(*messages.Pickle))
|
||||||
|
@ -148,89 +156,102 @@ func (s *storage) mustGetPickles(uri string) (ps []*messages.Pickle) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleStep(id string) *messages.Pickle_PickleStep {
|
// MustGetPickleStep will retrieve a pickle step and panic on error.
|
||||||
|
func (s *Storage) MustGetPickleStep(id string) *messages.Pickle_PickleStep {
|
||||||
v := s.mustFirst(tablePickleStep, tablePickleStepIndexID, id)
|
v := s.mustFirst(tablePickleStep, tablePickleStepIndexID, id)
|
||||||
return v.(*messages.Pickle_PickleStep)
|
return v.(*messages.Pickle_PickleStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsertTestRunStarted(trs testRunStarted) {
|
// MustInsertTestRunStarted will set the test run started event and panic on error.
|
||||||
s.lock.Lock()
|
func (s *Storage) MustInsertTestRunStarted(trs models.TestRunStarted) {
|
||||||
defer s.lock.Unlock()
|
s.testRunStartedLock.Lock()
|
||||||
|
defer s.testRunStartedLock.Unlock()
|
||||||
|
|
||||||
s.testRunStarted = trs
|
s.testRunStarted = trs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetTestRunStarted() testRunStarted {
|
// MustGetTestRunStarted will retrieve the test run started event and panic on error.
|
||||||
s.lock.Lock()
|
func (s *Storage) MustGetTestRunStarted() models.TestRunStarted {
|
||||||
defer s.lock.Unlock()
|
s.testRunStartedLock.Lock()
|
||||||
|
defer s.testRunStartedLock.Unlock()
|
||||||
|
|
||||||
return s.testRunStarted
|
return s.testRunStarted
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsertPickleResult(pr pickleResult) {
|
// MustInsertPickleResult will instert a pickle result and panic on error.
|
||||||
|
func (s *Storage) MustInsertPickleResult(pr models.PickleResult) {
|
||||||
s.mustInsert(tablePickleResult, pr)
|
s.mustInsert(tablePickleResult, pr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsertPickleStepResult(psr pickleStepResult) {
|
// MustInsertPickleStepResult will insert a pickle step result and panic on error.
|
||||||
|
func (s *Storage) MustInsertPickleStepResult(psr models.PickleStepResult) {
|
||||||
s.mustInsert(tablePickleStepResult, psr)
|
s.mustInsert(tablePickleStepResult, psr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleResult(id string) pickleResult {
|
// MustGetPickleResult will retrieve a pickle result by id and panic on error.
|
||||||
|
func (s *Storage) MustGetPickleResult(id string) models.PickleResult {
|
||||||
v := s.mustFirst(tablePickleResult, tablePickleResultIndexPickleID, id)
|
v := s.mustFirst(tablePickleResult, tablePickleResultIndexPickleID, id)
|
||||||
return v.(pickleResult)
|
return v.(models.PickleResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleResults() (prs []pickleResult) {
|
// MustGetPickleResults will retrieve all pickle results and panic on error.
|
||||||
|
func (s *Storage) MustGetPickleResults() (prs []models.PickleResult) {
|
||||||
it := s.mustGet(tablePickleResult, tablePickleResultIndexPickleID)
|
it := s.mustGet(tablePickleResult, tablePickleResultIndexPickleID)
|
||||||
for v := it.Next(); v != nil; v = it.Next() {
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
prs = append(prs, v.(pickleResult))
|
prs = append(prs, v.(models.PickleResult))
|
||||||
}
|
}
|
||||||
|
|
||||||
return prs
|
return prs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleStepResult(id string) pickleStepResult {
|
// MustGetPickleStepResult will retrieve a pickle strep result by id and panic on error.
|
||||||
|
func (s *Storage) MustGetPickleStepResult(id string) models.PickleStepResult {
|
||||||
v := s.mustFirst(tablePickleStepResult, tablePickleStepResultIndexPickleStepID, id)
|
v := s.mustFirst(tablePickleStepResult, tablePickleStepResultIndexPickleStepID, id)
|
||||||
return v.(pickleStepResult)
|
return v.(models.PickleStepResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleStepResultsByPickleID(pickleID string) (psrs []pickleStepResult) {
|
// MustGetPickleStepResultsByPickleID will retrieve pickle strep results by pickle id and panic on error.
|
||||||
|
func (s *Storage) MustGetPickleStepResultsByPickleID(pickleID string) (psrs []models.PickleStepResult) {
|
||||||
it := s.mustGet(tablePickleStepResult, tablePickleStepResultIndexPickleID, pickleID)
|
it := s.mustGet(tablePickleStepResult, tablePickleStepResultIndexPickleID, pickleID)
|
||||||
for v := it.Next(); v != nil; v = it.Next() {
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
psrs = append(psrs, v.(pickleStepResult))
|
psrs = append(psrs, v.(models.PickleStepResult))
|
||||||
}
|
}
|
||||||
|
|
||||||
return psrs
|
return psrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetPickleStepResultsByStatus(status stepResultStatus) (psrs []pickleStepResult) {
|
// MustGetPickleStepResultsByStatus will retrieve pickle strep results by status and panic on error.
|
||||||
|
func (s *Storage) MustGetPickleStepResultsByStatus(status models.StepResultStatus) (psrs []models.PickleStepResult) {
|
||||||
it := s.mustGet(tablePickleStepResult, tablePickleStepResultIndexStatus, status)
|
it := s.mustGet(tablePickleStepResult, tablePickleStepResultIndexStatus, status)
|
||||||
for v := it.Next(); v != nil; v = it.Next() {
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
psrs = append(psrs, v.(pickleStepResult))
|
psrs = append(psrs, v.(models.PickleStepResult))
|
||||||
}
|
}
|
||||||
|
|
||||||
return psrs
|
return psrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsertFeature(f *feature) {
|
// MustInsertFeature will insert a feature and panic on error.
|
||||||
|
func (s *Storage) MustInsertFeature(f *models.Feature) {
|
||||||
s.mustInsert(tableFeature, f)
|
s.mustInsert(tableFeature, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetFeature(uri string) *feature {
|
// MustGetFeature will retrieve a feature by URI and panic on error.
|
||||||
|
func (s *Storage) MustGetFeature(uri string) *models.Feature {
|
||||||
v := s.mustFirst(tableFeature, tableFeatureIndexURI, uri)
|
v := s.mustFirst(tableFeature, tableFeatureIndexURI, uri)
|
||||||
return v.(*feature)
|
return v.(*models.Feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGetFeatures() (fs []*feature) {
|
// MustGetFeatures will retrieve all features by and panic on error.
|
||||||
|
func (s *Storage) MustGetFeatures() (fs []*models.Feature) {
|
||||||
it := s.mustGet(tableFeature, tableFeatureIndexURI)
|
it := s.mustGet(tableFeature, tableFeatureIndexURI)
|
||||||
for v := it.Next(); v != nil; v = it.Next() {
|
for v := it.Next(); v != nil; v = it.Next() {
|
||||||
fs = append(fs, v.(*feature))
|
fs = append(fs, v.(*models.Feature))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustInsert(table string, obj interface{}) {
|
func (s *Storage) mustInsert(table string, obj interface{}) {
|
||||||
txn := s.db.Txn(writeMode)
|
txn := s.db.Txn(writeMode)
|
||||||
|
|
||||||
if err := txn.Insert(table, obj); err != nil {
|
if err := txn.Insert(table, obj); err != nil {
|
||||||
|
@ -240,7 +261,7 @@ func (s *storage) mustInsert(table string, obj interface{}) {
|
||||||
txn.Commit()
|
txn.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustFirst(table, index string, args ...interface{}) interface{} {
|
func (s *Storage) mustFirst(table, index string, args ...interface{}) interface{} {
|
||||||
txn := s.db.Txn(readMode)
|
txn := s.db.Txn(readMode)
|
||||||
defer txn.Abort()
|
defer txn.Abort()
|
||||||
|
|
||||||
|
@ -255,7 +276,7 @@ func (s *storage) mustFirst(table, index string, args ...interface{}) interface{
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) mustGet(table, index string, args ...interface{}) memdb.ResultIterator {
|
func (s *Storage) mustGet(table, index string, args ...interface{}) memdb.ResultIterator {
|
||||||
txn := s.db.Txn(readMode)
|
txn := s.db.Txn(readMode)
|
||||||
defer txn.Abort()
|
defer txn.Abort()
|
||||||
|
|
187
internal/storage/storage_test.go
Обычный файл
187
internal/storage/storage_test.go
Обычный файл
|
@ -0,0 +1,187 @@
|
||||||
|
package storage_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/storage"
|
||||||
|
"github.com/cucumber/godog/internal/testutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_MustGetPickle(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
ft := testutils.BuildTestFeature(t)
|
||||||
|
|
||||||
|
expected := ft.Pickles[0]
|
||||||
|
s.MustInsertPickle(expected)
|
||||||
|
|
||||||
|
actual := s.MustGetPickle(expected.Id)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickles(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
ft := testutils.BuildTestFeature(t)
|
||||||
|
|
||||||
|
expected := ft.Pickles
|
||||||
|
for _, pickle := range expected {
|
||||||
|
s.MustInsertPickle(pickle)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := s.MustGetPickles(ft.Uri)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickleStep(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
ft := testutils.BuildTestFeature(t)
|
||||||
|
|
||||||
|
for _, pickle := range ft.Pickles {
|
||||||
|
s.MustInsertPickle(pickle)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pickle := range ft.Pickles {
|
||||||
|
for _, expected := range pickle.Steps {
|
||||||
|
actual := s.MustGetPickleStep(expected.Id)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetTestRunStarted(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
expected := models.TestRunStarted{StartedAt: time.Now()}
|
||||||
|
s.MustInsertTestRunStarted(expected)
|
||||||
|
|
||||||
|
actual := s.MustGetTestRunStarted()
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickleResult(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
const pickleID = "1"
|
||||||
|
expected := models.PickleResult{PickleID: pickleID}
|
||||||
|
s.MustInsertPickleResult(expected)
|
||||||
|
|
||||||
|
actual := s.MustGetPickleResult(pickleID)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickleResults(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
expected := []models.PickleResult{{PickleID: "1"}, {PickleID: "2"}}
|
||||||
|
for _, pr := range expected {
|
||||||
|
s.MustInsertPickleResult(pr)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := s.MustGetPickleResults()
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickleStepResult(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
const pickleID = "1"
|
||||||
|
const stepID = "2"
|
||||||
|
|
||||||
|
expected := models.PickleStepResult{
|
||||||
|
Status: models.Passed,
|
||||||
|
PickleID: pickleID,
|
||||||
|
PickleStepID: stepID,
|
||||||
|
}
|
||||||
|
s.MustInsertPickleStepResult(expected)
|
||||||
|
|
||||||
|
actual := s.MustGetPickleStepResult(stepID)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickleStepResultsByPickleID(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
const pickleID = "p1"
|
||||||
|
|
||||||
|
expected := []models.PickleStepResult{
|
||||||
|
{
|
||||||
|
Status: models.Passed,
|
||||||
|
PickleID: pickleID,
|
||||||
|
PickleStepID: "s1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: models.Passed,
|
||||||
|
PickleID: pickleID,
|
||||||
|
PickleStepID: "s2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, psr := range expected {
|
||||||
|
s.MustInsertPickleStepResult(psr)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := s.MustGetPickleStepResultsByPickleID(pickleID)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetPickleStepResultsByStatus(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
const pickleID = "p1"
|
||||||
|
|
||||||
|
expected := []models.PickleStepResult{
|
||||||
|
{
|
||||||
|
Status: models.Passed,
|
||||||
|
PickleID: pickleID,
|
||||||
|
PickleStepID: "s1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testdata := []models.PickleStepResult{
|
||||||
|
expected[0],
|
||||||
|
{
|
||||||
|
Status: models.Failed,
|
||||||
|
PickleID: pickleID,
|
||||||
|
PickleStepID: "s2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, psr := range testdata {
|
||||||
|
s.MustInsertPickleStepResult(psr)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := s.MustGetPickleStepResultsByStatus(models.Passed)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetFeature(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
const uri = "<uri>"
|
||||||
|
|
||||||
|
expected := &models.Feature{GherkinDocument: &messages.GherkinDocument{Uri: uri}}
|
||||||
|
s.MustInsertFeature(expected)
|
||||||
|
|
||||||
|
actual := s.MustGetFeature(uri)
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MustGetFeatures(t *testing.T) {
|
||||||
|
s := storage.NewStorage()
|
||||||
|
|
||||||
|
expected := []*models.Feature{
|
||||||
|
{GherkinDocument: &messages.GherkinDocument{Uri: "uri1"}},
|
||||||
|
{GherkinDocument: &messages.GherkinDocument{Uri: "uri2"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range expected {
|
||||||
|
s.MustInsertFeature(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := s.MustGetFeatures()
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
60
internal/testutils/utils.go
Обычный файл
60
internal/testutils/utils.go
Обычный файл
|
@ -0,0 +1,60 @@
|
||||||
|
package testutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cucumber/gherkin-go/v11"
|
||||||
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildTestFeature creates a feature for testing purpose.
|
||||||
|
//
|
||||||
|
// The created feature includes:
|
||||||
|
// - a background
|
||||||
|
// - one normal scenario with three steps
|
||||||
|
// - one outline scenario with one example and three steps
|
||||||
|
func BuildTestFeature(t *testing.T) models.Feature {
|
||||||
|
newIDFunc := (&messages.Incrementing{}).NewId
|
||||||
|
|
||||||
|
gherkinDocument, err := gherkin.ParseGherkinDocument(strings.NewReader(featureContent), newIDFunc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
path := t.Name()
|
||||||
|
gherkinDocument.Uri = path
|
||||||
|
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
|
||||||
|
|
||||||
|
ft := models.Feature{GherkinDocument: gherkinDocument, Pickles: pickles, Content: []byte(featureContent)}
|
||||||
|
require.Len(t, ft.Pickles, 2)
|
||||||
|
|
||||||
|
require.Len(t, ft.Pickles[0].AstNodeIds, 1)
|
||||||
|
require.Len(t, ft.Pickles[0].Steps, 3)
|
||||||
|
|
||||||
|
require.Len(t, ft.Pickles[1].AstNodeIds, 2)
|
||||||
|
require.Len(t, ft.Pickles[1].Steps, 3)
|
||||||
|
|
||||||
|
return ft
|
||||||
|
}
|
||||||
|
|
||||||
|
const featureContent = `Feature: eat godogs
|
||||||
|
In order to be happy
|
||||||
|
As a hungry gopher
|
||||||
|
I need to be able to eat godogs
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given there are <begin> godogs
|
||||||
|
|
||||||
|
Scenario: Eat 5 out of 12
|
||||||
|
When I eat 5
|
||||||
|
Then there should be 7 remaining
|
||||||
|
|
||||||
|
Scenario Outline: Eat <dec> out of <beginning>
|
||||||
|
When I eat <dec>
|
||||||
|
Then there should be <remain> remaining
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
| begin | dec | remain |
|
||||||
|
| 12 | 5 | 7 |`
|
21
internal/utils/utils.go
Обычный файл
21
internal/utils/utils.go
Обычный файл
|
@ -0,0 +1,21 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// S repeats a space n times
|
||||||
|
func S(n int) string {
|
||||||
|
if n < 0 {
|
||||||
|
n = 1
|
||||||
|
}
|
||||||
|
return strings.Repeat(" ", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeNowFunc is a utility function to simply testing
|
||||||
|
// by allowing TimeNowFunc to be defined to zero time
|
||||||
|
// to remove the time domain from tests
|
||||||
|
var TimeNowFunc = func() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
}
|
31
parser.go
31
parser.go
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/cucumber/gherkin-go/v11"
|
"github.com/cucumber/gherkin-go/v11"
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
"github.com/cucumber/godog/internal/tags"
|
"github.com/cucumber/godog/internal/tags"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ func extractFeaturePathLine(p string) (string, int) {
|
||||||
return retPath, line
|
return retPath, line
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFeatureFile(path string, newIDFunc func() string) (*feature, error) {
|
func parseFeatureFile(path string, newIDFunc func() string) (*models.Feature, error) {
|
||||||
reader, err := os.Open(path)
|
reader, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -47,12 +48,12 @@ func parseFeatureFile(path string, newIDFunc func() string) (*feature, error) {
|
||||||
gherkinDocument.Uri = path
|
gherkinDocument.Uri = path
|
||||||
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
|
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
|
||||||
|
|
||||||
f := feature{GherkinDocument: gherkinDocument, pickles: pickles, content: buf.Bytes()}
|
f := models.Feature{GherkinDocument: gherkinDocument, Pickles: pickles, Content: buf.Bytes()}
|
||||||
return &f, nil
|
return &f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
func parseFeatureDir(dir string, newIDFunc func() string) ([]*models.Feature, error) {
|
||||||
var features []*feature
|
var features []*models.Feature
|
||||||
return features, filepath.Walk(dir, func(p string, f os.FileInfo, err error) error {
|
return features, filepath.Walk(dir, func(p string, f os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -76,8 +77,8 @@ func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePath(path string) ([]*feature, error) {
|
func parsePath(path string) ([]*models.Feature, error) {
|
||||||
var features []*feature
|
var features []*models.Feature
|
||||||
|
|
||||||
path, line := extractFeaturePathLine(path)
|
path, line := extractFeaturePathLine(path)
|
||||||
|
|
||||||
|
@ -99,23 +100,23 @@ func parsePath(path string) ([]*feature, error) {
|
||||||
|
|
||||||
// filter scenario by line number
|
// filter scenario by line number
|
||||||
var pickles []*messages.Pickle
|
var pickles []*messages.Pickle
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
sc := ft.findScenario(pickle.AstNodeIds[0])
|
sc := ft.FindScenario(pickle.AstNodeIds[0])
|
||||||
|
|
||||||
if line == -1 || uint32(line) == sc.Location.Line {
|
if line == -1 || uint32(line) == sc.Location.Line {
|
||||||
pickles = append(pickles, pickle)
|
pickles = append(pickles, pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ft.pickles = pickles
|
ft.Pickles = pickles
|
||||||
|
|
||||||
return append(features, ft), nil
|
return append(features, ft), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
func parseFeatures(filter string, paths []string) ([]*models.Feature, error) {
|
||||||
var order int
|
var order int
|
||||||
|
|
||||||
featureIdxs := make(map[string]int)
|
featureIdxs := make(map[string]int)
|
||||||
uniqueFeatureURI := make(map[string]*feature)
|
uniqueFeatureURI := make(map[string]*models.Feature)
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
feats, err := parsePath(path)
|
feats, err := parsePath(path)
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var features = make([]*feature, len(uniqueFeatureURI))
|
var features = make([]*models.Feature, len(uniqueFeatureURI))
|
||||||
for uri, feature := range uniqueFeatureURI {
|
for uri, feature := range uniqueFeatureURI {
|
||||||
idx := featureIdxs[uri]
|
idx := featureIdxs[uri]
|
||||||
features[idx] = feature
|
features[idx] = feature
|
||||||
|
@ -151,11 +152,11 @@ func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
||||||
return features, nil
|
return features, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterFeatures(filter string, features []*feature) (result []*feature) {
|
func filterFeatures(filter string, features []*models.Feature) (result []*models.Feature) {
|
||||||
for _, ft := range features {
|
for _, ft := range features {
|
||||||
ft.pickles = tags.ApplyTagFilter(filter, ft.pickles)
|
ft.Pickles = tags.ApplyTagFilter(filter, ft.Pickles)
|
||||||
|
|
||||||
if ft.Feature != nil && len(ft.pickles) > 0 {
|
if ft.Feature != nil && len(ft.Pickles) > 0 {
|
||||||
result = append(result, ft)
|
result = append(result, ft)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
results.go
81
results.go
|
@ -1,81 +0,0 @@
|
||||||
package godog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testRunStarted struct {
|
|
||||||
StartedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type pickleResult struct {
|
|
||||||
PickleID string
|
|
||||||
StartedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type pickleStepResult struct {
|
|
||||||
Status stepResultStatus
|
|
||||||
finishedAt time.Time
|
|
||||||
err error
|
|
||||||
|
|
||||||
PickleID string
|
|
||||||
PickleStepID string
|
|
||||||
|
|
||||||
def *StepDefinition
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStepResult(pickleID, pickleStepID string, match *StepDefinition) pickleStepResult {
|
|
||||||
return pickleStepResult{finishedAt: timeNowFunc(), PickleID: pickleID, PickleStepID: pickleStepID, def: match}
|
|
||||||
}
|
|
||||||
|
|
||||||
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] }
|
|
||||||
|
|
||||||
type stepResultStatus int
|
|
||||||
|
|
||||||
const (
|
|
||||||
passed stepResultStatus = iota
|
|
||||||
failed
|
|
||||||
skipped
|
|
||||||
undefined
|
|
||||||
pending
|
|
||||||
)
|
|
||||||
|
|
||||||
func (st stepResultStatus) clr() colors.ColorFunc {
|
|
||||||
switch st {
|
|
||||||
case passed:
|
|
||||||
return green
|
|
||||||
case failed:
|
|
||||||
return red
|
|
||||||
case skipped:
|
|
||||||
return cyan
|
|
||||||
default:
|
|
||||||
return yellow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st stepResultStatus) String() string {
|
|
||||||
switch st {
|
|
||||||
case passed:
|
|
||||||
return "passed"
|
|
||||||
case failed:
|
|
||||||
return "failed"
|
|
||||||
case skipped:
|
|
||||||
return "skipped"
|
|
||||||
case undefined:
|
|
||||||
return "undefined"
|
|
||||||
case pending:
|
|
||||||
return "pending"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
34
run.go
34
run.go
|
@ -12,8 +12,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
"github.com/cucumber/messages-go/v10"
|
||||||
|
|
||||||
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/storage"
|
||||||
|
"github.com/cucumber/godog/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -29,12 +33,12 @@ type runner struct {
|
||||||
randomSeed int64
|
randomSeed int64
|
||||||
stopOnFailure, strict bool
|
stopOnFailure, strict bool
|
||||||
|
|
||||||
features []*feature
|
features []*models.Feature
|
||||||
|
|
||||||
testSuiteInitializer testSuiteInitializer
|
testSuiteInitializer testSuiteInitializer
|
||||||
scenarioInitializer scenarioInitializer
|
scenarioInitializer scenarioInitializer
|
||||||
|
|
||||||
storage *storage
|
storage *storage.Storage
|
||||||
fmt Formatter
|
fmt Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +46,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
||||||
var copyLock sync.Mutex
|
var copyLock sync.Mutex
|
||||||
|
|
||||||
if fmt, ok := r.fmt.(storageFormatter); ok {
|
if fmt, ok := r.fmt.(storageFormatter); ok {
|
||||||
fmt.setStorage(r.storage)
|
fmt.SetStorage(r.storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
testSuiteContext := TestSuiteContext{}
|
testSuiteContext := TestSuiteContext{}
|
||||||
|
@ -50,8 +54,8 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
||||||
r.testSuiteInitializer(&testSuiteContext)
|
r.testSuiteInitializer(&testSuiteContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
testRunStarted := testRunStarted{StartedAt: timeNowFunc()}
|
testRunStarted := models.TestRunStarted{StartedAt: utils.TimeNowFunc()}
|
||||||
r.storage.mustInsertTestRunStarted(testRunStarted)
|
r.storage.MustInsertTestRunStarted(testRunStarted)
|
||||||
r.fmt.TestRunStarted()
|
r.fmt.TestRunStarted()
|
||||||
|
|
||||||
// run before suite handlers
|
// run before suite handlers
|
||||||
|
@ -61,15 +65,15 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
||||||
|
|
||||||
queue := make(chan int, rate)
|
queue := make(chan int, rate)
|
||||||
for _, ft := range r.features {
|
for _, ft := range r.features {
|
||||||
pickles := make([]*messages.Pickle, len(ft.pickles))
|
pickles := make([]*messages.Pickle, len(ft.Pickles))
|
||||||
if r.randomSeed != 0 {
|
if r.randomSeed != 0 {
|
||||||
r := rand.New(rand.NewSource(r.randomSeed))
|
r := rand.New(rand.NewSource(r.randomSeed))
|
||||||
perm := r.Perm(len(ft.pickles))
|
perm := r.Perm(len(ft.Pickles))
|
||||||
for i, v := range perm {
|
for i, v := range perm {
|
||||||
pickles[v] = ft.pickles[i]
|
pickles[v] = ft.Pickles[i]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
copy(pickles, ft.pickles)
|
copy(pickles, ft.Pickles)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, p := range pickles {
|
for i, p := range pickles {
|
||||||
|
@ -78,7 +82,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
||||||
queue <- i // reserve space in queue
|
queue <- i // reserve space in queue
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
r.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.content)
|
r.fmt.Feature(ft.GherkinDocument, ft.Uri, ft.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func(fail *bool, pickle *messages.Pickle) {
|
go func(fail *bool, pickle *messages.Pickle) {
|
||||||
|
@ -181,12 +185,12 @@ func runWithOptions(suiteName string, runner runner, opt Options) int {
|
||||||
return exitOptionError
|
return exitOptionError
|
||||||
}
|
}
|
||||||
|
|
||||||
runner.storage = newStorage()
|
runner.storage = storage.NewStorage()
|
||||||
for _, feat := range runner.features {
|
for _, feat := range runner.features {
|
||||||
runner.storage.mustInsertFeature(feat)
|
runner.storage.MustInsertFeature(feat)
|
||||||
|
|
||||||
for _, pickle := range feat.pickles {
|
for _, pickle := range feat.Pickles {
|
||||||
runner.storage.mustInsertPickle(pickle)
|
runner.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var basicGherkinFeature = `
|
var basicGherkinFeature = `
|
||||||
|
@ -28,31 +31,31 @@ func Test_ProgressFormatterWhenStepPanics(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w := colors.Uncolored(&buf)
|
w := colors.Uncolored(&buf)
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", w),
|
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^one$`, func() error { return nil })
|
ctx.Step(`^one$`, func() error { return nil })
|
||||||
ctx.Step(`^two$`, func() error { panic("omg") })
|
ctx.Step(`^two$`, func() error { panic("omg") })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
require.True(t, failed)
|
require.True(t, failed)
|
||||||
|
|
||||||
actual := buf.String()
|
actual := buf.String()
|
||||||
assert.Contains(t, actual, "godog/fmt_progress_test.go:41")
|
assert.Contains(t, actual, "godog/run_progress_test.go:44")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_ProgressFormatterWithPanicInMultistep(t *testing.T) {
|
func Test_ProgressFormatterWithPanicInMultistep(t *testing.T) {
|
||||||
|
@ -62,14 +65,14 @@ func Test_ProgressFormatterWithPanicInMultistep(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w := colors.Uncolored(&buf)
|
w := colors.Uncolored(&buf)
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", w),
|
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^sub1$`, func() error { return nil })
|
ctx.Step(`^sub1$`, func() error { return nil })
|
||||||
ctx.Step(`^sub-sub$`, func() error { return nil })
|
ctx.Step(`^sub-sub$`, func() error { return nil })
|
||||||
|
@ -79,10 +82,10 @@ func Test_ProgressFormatterWithPanicInMultistep(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
|
@ -96,14 +99,14 @@ func Test_ProgressFormatterMultistepTemplates(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w := colors.Uncolored(&buf)
|
w := colors.Uncolored(&buf)
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", w),
|
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^sub-sub$`, func() error { return nil })
|
ctx.Step(`^sub-sub$`, func() error { return nil })
|
||||||
ctx.Step(`^substep$`, func() Steps { return Steps{"sub-sub", `unavailable "John" cost 5`, "one", "three"} })
|
ctx.Step(`^substep$`, func() Steps { return Steps{"sub-sub", `unavailable "John" cost 5`, "one", "three"} })
|
||||||
|
@ -112,10 +115,10 @@ func Test_ProgressFormatterMultistepTemplates(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
|
@ -172,24 +175,24 @@ Feature: basic
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w := colors.Uncolored(&buf)
|
w := colors.Uncolored(&buf)
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", w),
|
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^one$`, func() error { return nil })
|
ctx.Step(`^one$`, func() error { return nil })
|
||||||
ctx.Step(`^two:$`, func(doc *messages.PickleStepArgument_PickleDocString) Steps { return Steps{"one"} })
|
ctx.Step(`^two:$`, func(doc *messages.PickleStepArgument_PickleDocString) Steps { return Steps{"one"} })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
|
@ -210,8 +213,8 @@ Feature: basic
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
var subStep = `three:
|
var subStep = `three:
|
||||||
"""
|
"""
|
||||||
|
@ -221,8 +224,8 @@ Feature: basic
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w := colors.Uncolored(&buf)
|
w := colors.Uncolored(&buf)
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", w),
|
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^one$`, func() error { return nil })
|
ctx.Step(`^one$`, func() error { return nil })
|
||||||
ctx.Step(`^two$`, func() Steps { return Steps{subStep} })
|
ctx.Step(`^two$`, func() Steps { return Steps{subStep} })
|
||||||
|
@ -230,10 +233,10 @@ Feature: basic
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
57
run_test.go
57
run_test.go
|
@ -17,6 +17,9 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cucumber/godog/colors"
|
"github.com/cucumber/godog/colors"
|
||||||
|
"github.com/cucumber/godog/internal/formatters"
|
||||||
|
"github.com/cucumber/godog/internal/models"
|
||||||
|
"github.com/cucumber/godog/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func okStep() error {
|
func okStep() error {
|
||||||
|
@ -70,22 +73,22 @@ func Test_FailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", ioutil.Discard),
|
fmt: formatters.ProgressFormatterFunc("progress", ioutil.Discard),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^one$`, func() error { return nil })
|
ctx.Step(`^one$`, func() error { return nil })
|
||||||
ctx.Step(`^two$`, func() error { return ErrPending })
|
ctx.Step(`^two$`, func() error { return ErrPending })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
|
@ -103,22 +106,22 @@ func Test_FailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", ioutil.Discard),
|
fmt: formatters.ProgressFormatterFunc("progress", ioutil.Discard),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^one$`, func() error { return nil })
|
ctx.Step(`^one$`, func() error { return nil })
|
||||||
// two - is undefined
|
// two - is undefined
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
|
@ -136,22 +139,22 @@ func Test_ShouldFailOnError(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
gd.Uri = path
|
gd.Uri = path
|
||||||
ft := feature{GherkinDocument: gd}
|
ft := models.Feature{GherkinDocument: gd}
|
||||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||||
|
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: progressFunc("progress", ioutil.Discard),
|
fmt: formatters.ProgressFormatterFunc("progress", ioutil.Discard),
|
||||||
features: []*feature{&ft},
|
features: []*models.Feature{&ft},
|
||||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^one$`, func() error { return nil })
|
|
||||||
ctx.Step(`^two$`, func() error { return fmt.Errorf("error") })
|
ctx.Step(`^two$`, func() error { return fmt.Errorf("error") })
|
||||||
|
ctx.Step(`^one$`, func() error { return nil })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.storage = newStorage()
|
r.storage = storage.NewStorage()
|
||||||
r.storage.mustInsertFeature(&ft)
|
r.storage.MustInsertFeature(&ft)
|
||||||
for _, pickle := range ft.pickles {
|
for _, pickle := range ft.Pickles {
|
||||||
r.storage.mustInsertPickle(pickle)
|
r.storage.MustInsertPickle(pickle)
|
||||||
}
|
}
|
||||||
|
|
||||||
failed := r.concurrent(1)
|
failed := r.concurrent(1)
|
||||||
|
@ -284,7 +287,7 @@ func Test_RandomizeRun(t *testing.T) {
|
||||||
const createRandomSeedFlag = -1
|
const createRandomSeedFlag = -1
|
||||||
const noConcurrencyFlag = 1
|
const noConcurrencyFlag = 1
|
||||||
const formatter = "pretty"
|
const formatter = "pretty"
|
||||||
const featurePath = "formatter-tests/features/with_few_empty_scenarios.feature"
|
const featurePath = "internal/formatters/formatter-tests/features/with_few_empty_scenarios.feature"
|
||||||
|
|
||||||
fmtOutputScenarioInitializer := func(ctx *ScenarioContext) {
|
fmtOutputScenarioInitializer := func(ctx *ScenarioContext) {
|
||||||
ctx.Step(`^(?:a )?failing step`, failingStepDef)
|
ctx.Step(`^(?:a )?failing step`, failingStepDef)
|
||||||
|
@ -367,7 +370,7 @@ func Test_FormatterConcurrencyRun(t *testing.T) {
|
||||||
"cucumber",
|
"cucumber",
|
||||||
}
|
}
|
||||||
|
|
||||||
featurePaths := []string{"formatter-tests/features"}
|
featurePaths := []string{"internal/formatters/formatter-tests/features"}
|
||||||
|
|
||||||
const concurrency = 100
|
const concurrency = 100
|
||||||
const noRandomFlag = 0
|
const noRandomFlag = 0
|
||||||
|
|
|
@ -24,7 +24,7 @@ func callstack3() *stack {
|
||||||
return &st
|
return &st
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStacktrace(t *testing.T) {
|
func Test_Stacktrace(t *testing.T) {
|
||||||
err := &traceError{
|
err := &traceError{
|
||||||
msg: "err msg",
|
msg: "err msg",
|
||||||
stack: callstack1(),
|
stack: callstack1(),
|
||||||
|
|
106
stepdef_test.go
106
stepdef_test.go
|
@ -1,106 +0,0 @@
|
||||||
package godog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cucumber/messages-go/v10"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestShouldSupportIntTypes(t *testing.T) {
|
|
||||||
fn := func(a int64, b int32, c int16, d int8) error { return nil }
|
|
||||||
|
|
||||||
def := &StepDefinition{
|
|
||||||
Handler: fn,
|
|
||||||
hv: reflect.ValueOf(fn),
|
|
||||||
}
|
|
||||||
|
|
||||||
def.args = []interface{}{"1", "1", "1", "1"}
|
|
||||||
if err := def.run(); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
def.args = []interface{}{"1", "1", "1", strings.Repeat("1", 9)}
|
|
||||||
if err := def.run(); err == nil {
|
|
||||||
t.Fatalf("expected convertion fail for int8, but got none")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldSupportFloatTypes(t *testing.T) {
|
|
||||||
fn := func(a float64, b float32) error { return nil }
|
|
||||||
|
|
||||||
def := &StepDefinition{
|
|
||||||
Handler: fn,
|
|
||||||
hv: reflect.ValueOf(fn),
|
|
||||||
}
|
|
||||||
|
|
||||||
def.args = []interface{}{"1.1", "1.09"}
|
|
||||||
if err := def.run(); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
def.args = []interface{}{"1.08", strings.Repeat("1", 65) + ".67"}
|
|
||||||
if err := def.run(); err == nil {
|
|
||||||
t.Fatalf("expected convertion fail for float32, but got none")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldNotSupportOtherPointerTypesThanGherkin(t *testing.T) {
|
|
||||||
fn1 := func(a *int) error { return nil }
|
|
||||||
fn2 := func(a *messages.PickleStepArgument_PickleDocString) error { return nil }
|
|
||||||
fn3 := func(a *messages.PickleStepArgument_PickleTable) error { return nil }
|
|
||||||
|
|
||||||
def1 := &StepDefinition{Handler: fn1, hv: reflect.ValueOf(fn1), args: []interface{}{(*int)(nil)}}
|
|
||||||
def2 := &StepDefinition{Handler: fn2, hv: reflect.ValueOf(fn2), args: []interface{}{&messages.PickleStepArgument_PickleDocString{}}}
|
|
||||||
def3 := &StepDefinition{Handler: fn3, hv: reflect.ValueOf(fn3), args: []interface{}{(*messages.PickleStepArgument_PickleTable)(nil)}}
|
|
||||||
|
|
||||||
if err := def1.run(); err == nil {
|
|
||||||
t.Fatalf("expected conversion error, but got none")
|
|
||||||
}
|
|
||||||
if err := def2.run(); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if err := def3.run(); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldSupportOnlyByteSlice(t *testing.T) {
|
|
||||||
fn1 := func(a []byte) error { return nil }
|
|
||||||
fn2 := func(a []string) error { return nil }
|
|
||||||
|
|
||||||
def1 := &StepDefinition{Handler: fn1, hv: reflect.ValueOf(fn1), args: []interface{}{"str"}}
|
|
||||||
def2 := &StepDefinition{Handler: fn2, hv: reflect.ValueOf(fn2), args: []interface{}{[]string{}}}
|
|
||||||
|
|
||||||
if err := def1.run(); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if err := def2.run(); err == nil {
|
|
||||||
t.Fatalf("expected conversion error, but got none")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnexpectedArguments(t *testing.T) {
|
|
||||||
fn := func(a, b int) error { return nil }
|
|
||||||
def := &StepDefinition{Handler: fn, hv: reflect.ValueOf(fn)}
|
|
||||||
|
|
||||||
def.args = []interface{}{"1"}
|
|
||||||
if err := def.run(); err == nil {
|
|
||||||
t.Fatalf("expected an error due to wrong number of arguments, but got none")
|
|
||||||
}
|
|
||||||
|
|
||||||
def.args = []interface{}{"one", "two"}
|
|
||||||
if err := def.run(); err == nil {
|
|
||||||
t.Fatalf("expected conversion error, but got none")
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TODO maybe we should support duration
|
|
||||||
// fn2 := func(err time.Duration) error { return nil }
|
|
||||||
// def = &StepDefinition{Handler: fn2, hv: reflect.ValueOf(fn2)}
|
|
||||||
|
|
||||||
// def.args = []interface{}{"1"}
|
|
||||||
// if err := def.run(); err == nil {
|
|
||||||
// t.Fatalf("expected an error due to wrong argument type, but got none")
|
|
||||||
// }
|
|
||||||
}
|
|
Показаны не все изменённые файлы, т.к. их слишком много Показать больше
Загрузка…
Создание таблицы
Сослаться в новой задаче