Merge pull request #323 from cucumber/move-formatters-to-internal-pkg
Added internal packages for formatters, storage and models
Этот коммит содержится в:
коммит
783f5e40a3
105 изменённых файлов: 1493 добавлений и 872 удалений
|
@ -36,7 +36,7 @@ commands:
|
|||
go_test:
|
||||
description: "Run go test"
|
||||
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 ./...
|
||||
godog:
|
||||
description: "Run godog"
|
||||
|
|
4
flags.go
4
flags.go
|
@ -10,8 +10,12 @@ import (
|
|||
"time"
|
||||
|
||||
"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" +
|
||||
s(4) + "- dir " + colors.Yellow("(features/)") + "\n" +
|
||||
s(4) + "- feature " + colors.Yellow("(*.feature)") + "\n" +
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cucumber/godog/colors"
|
||||
"github.com/cucumber/godog/internal/formatters"
|
||||
)
|
||||
|
||||
func TestFlagsShouldRandomizeAndGenerateSeed(t *testing.T) {
|
||||
|
@ -61,7 +62,7 @@ func TestFlagsUsageShouldIncludeFormatDescriptons(t *testing.T) {
|
|||
output := colors.Uncolored(&buf)
|
||||
|
||||
// register some custom formatter
|
||||
Format("custom", "custom format description", junitFunc)
|
||||
Format("custom", "custom format description", formatters.JUnitFormatterFunc)
|
||||
|
||||
var opt Options
|
||||
flags := FlagSet(&opt)
|
||||
|
|
65
fmt.go
65
fmt.go
|
@ -6,28 +6,18 @@ import (
|
|||
"strings"
|
||||
"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
|
||||
// and returns FormaterFunc matched by given
|
||||
// format name or nil otherwise
|
||||
func FindFmt(name string) FormatterFunc {
|
||||
for _, el := range formatters {
|
||||
if el.name == name {
|
||||
return el.fmt
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return formatters.FindFmt(name)
|
||||
}
|
||||
|
||||
// Format registers a feature suite output
|
||||
|
@ -35,24 +25,14 @@ func FindFmt(name string) FormatterFunc {
|
|||
// FormatterFunc constructor function, to initialize
|
||||
// formatter with the output recorder.
|
||||
func Format(name, description string, f FormatterFunc) {
|
||||
formatters = append(formatters, ®isteredFormatter{
|
||||
name: name,
|
||||
fmt: f,
|
||||
description: description,
|
||||
})
|
||||
formatters.Format(name, description, f)
|
||||
}
|
||||
|
||||
// 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(formatters))
|
||||
|
||||
for _, f := range formatters {
|
||||
fmts[f.name] = f.description
|
||||
}
|
||||
|
||||
return fmts
|
||||
return formatters.AvailableFormatters()
|
||||
}
|
||||
|
||||
// Formatter is an interface for feature runner
|
||||
|
@ -62,32 +42,17 @@ func AvailableFormatters() map[string]string {
|
|||
// 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, *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 Formatter = formatters.Formatter
|
||||
|
||||
type storageFormatter interface {
|
||||
setStorage(*storage)
|
||||
SetStorage(*storage.Storage)
|
||||
}
|
||||
|
||||
// FormatterFunc builds a formatter with given
|
||||
// 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 {
|
||||
return pickle.Steps[len(pickle.Steps)-1].Id == step.Id
|
||||
}
|
||||
|
||||
func printStepDefinitions(steps []*StepDefinition, w io.Writer) {
|
||||
func printStepDefinitions(steps []*models.StepDefinition, w io.Writer) {
|
||||
var longest int
|
||||
for _, def := range steps {
|
||||
n := utf8.RuneCountInString(def.Expr.String())
|
||||
|
@ -98,9 +63,11 @@ func printStepDefinitions(steps []*StepDefinition, w io.Writer) {
|
|||
|
||||
for _, def := range steps {
|
||||
n := utf8.RuneCountInString(def.Expr.String())
|
||||
location := def.definitionID()
|
||||
location := internal_fmt.DefinitionID(def)
|
||||
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 {
|
||||
|
|
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 (
|
||||
"bytes"
|
||||
|
@ -14,14 +14,20 @@ import (
|
|||
"github.com/cucumber/messages-go/v10"
|
||||
|
||||
"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 {
|
||||
return newBaseFmt(suite, out)
|
||||
// BaseFormatterFunc implements the FormatterFunc for the base formatter
|
||||
func BaseFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||
return NewBaseFmt(suite, out)
|
||||
}
|
||||
|
||||
func newBaseFmt(suite string, out io.Writer) *basefmt {
|
||||
return &basefmt{
|
||||
// NewBaseFmt creates a new base formatter
|
||||
func NewBaseFmt(suite string, out io.Writer) *Basefmt {
|
||||
return &Basefmt{
|
||||
suiteName: suite,
|
||||
indent: 2,
|
||||
out: out,
|
||||
|
@ -29,47 +35,63 @@ func newBaseFmt(suite string, out io.Writer) *basefmt {
|
|||
}
|
||||
}
|
||||
|
||||
type basefmt struct {
|
||||
// Basefmt ...
|
||||
type Basefmt struct {
|
||||
suiteName string
|
||||
out io.Writer
|
||||
indent int
|
||||
|
||||
storage *storage
|
||||
storage *storage.Storage
|
||||
lock *sync.Mutex
|
||||
}
|
||||
|
||||
func (f *basefmt) setStorage(st *storage) {
|
||||
// SetStorage ...
|
||||
func (f *Basefmt) SetStorage(st *storage.Storage) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
f.storage = st
|
||||
}
|
||||
|
||||
func (f *basefmt) TestRunStarted() {}
|
||||
func (f *basefmt) Feature(ft *messages.GherkinDocument, p string, c []byte) {}
|
||||
func (f *basefmt) Pickle(p *messages.Pickle) {}
|
||||
func (f *basefmt) Defined(*messages.Pickle, *messages.Pickle_PickleStep, *StepDefinition) {}
|
||||
func (f *basefmt) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
}
|
||||
func (f *basefmt) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
}
|
||||
func (f *basefmt) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
}
|
||||
func (f *basefmt) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||
}
|
||||
func (f *basefmt) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
// TestRunStarted ...
|
||||
func (f *Basefmt) TestRunStarted() {}
|
||||
|
||||
// Feature ...
|
||||
func (f *Basefmt) Feature(*messages.GherkinDocument, string, []byte) {}
|
||||
|
||||
// Pickle ...
|
||||
func (f *Basefmt) Pickle(*messages.Pickle) {}
|
||||
|
||||
// Defined ...
|
||||
func (f *Basefmt) Defined(*messages.Pickle, *messages.Pickle_PickleStep, *models.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 totalSt, passedSt, failedSt, skippedSt, pendingSt, undefinedSt int
|
||||
|
||||
pickleResults := f.storage.mustGetPickleResults()
|
||||
pickleResults := f.storage.MustGetPickleResults()
|
||||
for _, pr := range pickleResults {
|
||||
var prStatus stepResultStatus
|
||||
var prStatus models.StepResultStatus
|
||||
totalSc++
|
||||
|
||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pr.PickleID)
|
||||
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pr.PickleID)
|
||||
|
||||
if len(pickleStepResults) == 0 {
|
||||
prStatus = undefined
|
||||
|
@ -130,8 +152,8 @@ func (f *basefmt) Summary() {
|
|||
}
|
||||
scenarios = append(scenarios, parts...)
|
||||
|
||||
testRunStartedAt := f.storage.mustGetTestRunStarted().StartedAt
|
||||
elapsed := timeNowFunc().Sub(testRunStartedAt)
|
||||
testRunStartedAt := f.storage.MustGetTestRunStarted().StartedAt
|
||||
elapsed := utils.TimeNowFunc().Sub(testRunStartedAt)
|
||||
|
||||
fmt.Fprintln(f.out, "")
|
||||
|
||||
|
@ -161,15 +183,16 @@ func (f *basefmt) Summary() {
|
|||
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, yellow("You can implement step definitions for undefined steps with these snippets:"))
|
||||
fmt.Fprintln(f.out, yellow(text))
|
||||
}
|
||||
}
|
||||
|
||||
func (f *basefmt) snippets() string {
|
||||
undefinedStepResults := f.storage.mustGetPickleStepResultsByStatus(undefined)
|
||||
// Snippets ...
|
||||
func (f *Basefmt) Snippets() string {
|
||||
undefinedStepResults := f.storage.MustGetPickleStepResultsByStatus(undefined)
|
||||
if len(undefinedStepResults) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
@ -178,12 +201,12 @@ func (f *basefmt) snippets() string {
|
|||
var snips []undefinedSnippet
|
||||
// build snippets
|
||||
for _, u := range undefinedStepResults {
|
||||
pickleStep := f.storage.mustGetPickleStep(u.PickleStepID)
|
||||
pickleStep := f.storage.MustGetPickleStep(u.PickleStepID)
|
||||
|
||||
steps := []string{pickleStep.Text}
|
||||
arg := pickleStep.Argument
|
||||
if u.def != nil {
|
||||
steps = u.def.undefined
|
||||
if u.Def != nil {
|
||||
steps = u.Def.Undefined
|
||||
arg = nil
|
||||
}
|
||||
for _, step := range steps {
|
|
@ -1,4 +1,4 @@
|
|||
package godog_test
|
||||
package formatters_test
|
||||
|
||||
import (
|
||||
"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.
|
||||
|
@ -19,22 +19,26 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/cucumber/messages-go/v10"
|
||||
|
||||
"github.com/cucumber/godog/formatters"
|
||||
"github.com/cucumber/godog/internal/models"
|
||||
)
|
||||
|
||||
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 {
|
||||
return &cukefmt{basefmt: newBaseFmt(suite, out)}
|
||||
// CucumberFormatterFunc implements the FormatterFunc for the cucumber formatter
|
||||
func CucumberFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||
return &cukefmt{Basefmt: NewBaseFmt(suite, out)}
|
||||
}
|
||||
|
||||
type cukefmt struct {
|
||||
*basefmt
|
||||
*Basefmt
|
||||
}
|
||||
|
||||
func (f *cukefmt) Summary() {
|
||||
features := f.storage.mustGetFeatures()
|
||||
features := f.storage.MustGetFeatures()
|
||||
|
||||
res := f.buildCukeFeatures(features)
|
||||
|
||||
|
@ -46,15 +50,15 @@ func (f *cukefmt) Summary() {
|
|||
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))
|
||||
|
||||
res = make([]cukeFeatureJSON, len(features))
|
||||
res = make([]CukeFeatureJSON, len(features))
|
||||
|
||||
for idx, feat := range features {
|
||||
cukeFeature := buildCukeFeature(feat)
|
||||
|
||||
pickles := f.storage.mustGetPickles(feat.Uri)
|
||||
pickles := f.storage.MustGetPickles(feat.Uri)
|
||||
sort.Sort(sortPicklesByID(pickles))
|
||||
|
||||
cukeFeature.Elements = f.buildCukeElements(pickles)
|
||||
|
@ -75,8 +79,8 @@ func (f *cukefmt) buildCukeElements(pickles []*messages.Pickle) (res []cukeEleme
|
|||
res = make([]cukeElement, len(pickles))
|
||||
|
||||
for idx, pickle := range pickles {
|
||||
pickleResult := f.storage.mustGetPickleResult(pickle.Id)
|
||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||
pickleResult := f.storage.MustGetPickleResult(pickle.Id)
|
||||
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||
|
||||
cukeElement := f.buildCukeElement(pickle)
|
||||
|
||||
|
@ -88,12 +92,14 @@ func (f *cukefmt) buildCukeElements(pickles []*messages.Pickle) (res []cukeEleme
|
|||
for jdx, stepResult := range pickleStepResults {
|
||||
cukeStep := f.buildCukeStep(pickle, stepResult)
|
||||
|
||||
stepResultFinishedAt := stepResult.finishedAt
|
||||
stepResultFinishedAt := stepResult.FinishedAt
|
||||
d := int(stepResultFinishedAt.Sub(stepStartedAt).Nanoseconds())
|
||||
stepStartedAt = stepResultFinishedAt
|
||||
|
||||
cukeStep.Result.Duration = &d
|
||||
if stepResult.Status == undefined || stepResult.Status == pending || stepResult.Status == skipped {
|
||||
if stepResult.Status == undefined ||
|
||||
stepResult.Status == pending ||
|
||||
stepResult.Status == skipped {
|
||||
cukeStep.Result.Duration = nil
|
||||
}
|
||||
|
||||
|
@ -157,7 +163,8 @@ type cukeElement struct {
|
|||
Steps []cukeStep `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
type cukeFeatureJSON struct {
|
||||
// CukeFeatureJSON ...
|
||||
type CukeFeatureJSON struct {
|
||||
URI string `json:"uri"`
|
||||
ID string `json:"id"`
|
||||
Keyword string `json:"keyword"`
|
||||
|
@ -169,8 +176,8 @@ type cukeFeatureJSON struct {
|
|||
Elements []cukeElement `json:"elements,omitempty"`
|
||||
}
|
||||
|
||||
func buildCukeFeature(feat *feature) cukeFeatureJSON {
|
||||
cukeFeature := cukeFeatureJSON{
|
||||
func buildCukeFeature(feat *models.Feature) CukeFeatureJSON {
|
||||
cukeFeature := CukeFeatureJSON{
|
||||
URI: feat.Uri,
|
||||
ID: makeCukeID(feat.Feature.Name),
|
||||
Keyword: feat.Feature.Keyword,
|
||||
|
@ -195,8 +202,8 @@ func buildCukeFeature(feat *feature) cukeFeatureJSON {
|
|||
}
|
||||
|
||||
func (f *cukefmt) buildCukeElement(pickle *messages.Pickle) (cukeElement cukeElement) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
scenario := feature.findScenario(pickle.AstNodeIds[0])
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
scenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||
|
||||
cukeElement.Name = pickle.Name
|
||||
cukeElement.Line = int(scenario.Location.Line)
|
||||
|
@ -214,7 +221,7 @@ func (f *cukefmt) buildCukeElement(pickle *messages.Pickle) (cukeElement cukeEle
|
|||
return
|
||||
}
|
||||
|
||||
example, _ := feature.findExample(pickle.AstNodeIds[1])
|
||||
example, _ := feature.FindExample(pickle.AstNodeIds[1])
|
||||
|
||||
for _, tag := range example.Tags {
|
||||
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
|
||||
}
|
||||
|
||||
func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult pickleStepResult) (cukeStep cukeStep) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
pickleStep := f.storage.mustGetPickleStep(stepResult.PickleStepID)
|
||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
||||
func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult models.PickleStepResult) (cukeStep cukeStep) {
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
pickleStep := f.storage.MustGetPickleStep(stepResult.PickleStepID)
|
||||
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||
|
||||
line := step.Location.Line
|
||||
if len(pickle.AstNodeIds) == 2 {
|
||||
_, row := feature.findExample(pickle.AstNodeIds[1])
|
||||
_, row := feature.FindExample(pickle.AstNodeIds[1])
|
||||
line = row.Location.Line
|
||||
}
|
||||
|
||||
|
@ -273,13 +280,13 @@ func (f *cukefmt) buildCukeStep(pickle *messages.Pickle, stepResult pickleStepRe
|
|||
}
|
||||
}
|
||||
|
||||
if stepResult.def != nil {
|
||||
cukeStep.Match.Location = strings.Split(stepResult.def.definitionID(), " ")[0]
|
||||
if stepResult.Def != nil {
|
||||
cukeStep.Match.Location = strings.Split(DefinitionID(stepResult.Def), " ")[0]
|
||||
}
|
||||
|
||||
cukeStep.Result.Status = stepResult.Status.String()
|
||||
if stepResult.err != nil {
|
||||
cukeStep.Result.Error = stepResult.err.Error()
|
||||
if stepResult.Err != nil {
|
||||
cukeStep.Result.Error = stepResult.Err.Error()
|
||||
}
|
||||
|
||||
if stepResult.Status == undefined || stepResult.Status == pending {
|
|
@ -1,4 +1,4 @@
|
|||
package godog
|
||||
package formatters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -6,24 +6,29 @@ import (
|
|||
"io"
|
||||
|
||||
"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 spec = "0.1.0"
|
||||
|
||||
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 {
|
||||
return &events{basefmt: newBaseFmt(suite, out)}
|
||||
// EventsFormatterFunc implements the FormatterFunc for the events formatter
|
||||
func EventsFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||
return &eventsFormatter{Basefmt: NewBaseFmt(suite, out)}
|
||||
}
|
||||
|
||||
type events struct {
|
||||
*basefmt
|
||||
type eventsFormatter struct {
|
||||
*Basefmt
|
||||
}
|
||||
|
||||
func (f *events) event(ev interface{}) {
|
||||
func (f *eventsFormatter) event(ev interface{}) {
|
||||
data, err := json.Marshal(ev)
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
|
||||
func (f *events) Pickle(pickle *messages.Pickle) {
|
||||
f.basefmt.Pickle(pickle)
|
||||
func (f *eventsFormatter) Pickle(pickle *messages.Pickle) {
|
||||
f.Basefmt.Pickle(pickle)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -44,7 +49,7 @@ func (f *events) Pickle(pickle *messages.Pickle) {
|
|||
}{
|
||||
"TestCaseStarted",
|
||||
f.scenarioLocation(pickle),
|
||||
timeNowFunc().UnixNano() / nanoSec,
|
||||
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||
})
|
||||
|
||||
if len(pickle.Steps) == 0 {
|
||||
|
@ -58,14 +63,14 @@ func (f *events) Pickle(pickle *messages.Pickle) {
|
|||
}{
|
||||
"TestCaseFinished",
|
||||
f.scenarioLocation(pickle),
|
||||
timeNowFunc().UnixNano() / nanoSec,
|
||||
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||
"undefined",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (f *events) TestRunStarted() {
|
||||
f.basefmt.TestRunStarted()
|
||||
func (f *eventsFormatter) TestRunStarted() {
|
||||
f.Basefmt.TestRunStarted()
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -78,13 +83,13 @@ func (f *events) TestRunStarted() {
|
|||
}{
|
||||
"TestRunStarted",
|
||||
spec,
|
||||
timeNowFunc().UnixNano() / nanoSec,
|
||||
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||
f.suiteName,
|
||||
})
|
||||
}
|
||||
|
||||
func (f *events) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
||||
f.basefmt.Feature(ft, p, c)
|
||||
func (f *eventsFormatter) Feature(ft *messages.GherkinDocument, p string, c []byte) {
|
||||
f.Basefmt.Feature(ft, p, c)
|
||||
|
||||
f.lock.Lock()
|
||||
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
|
||||
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
|
||||
} else if len(f.storage.mustGetPickleStepResultsByStatus(passed)) == 0 {
|
||||
if len(f.storage.mustGetPickleStepResultsByStatus(undefined)) > len(f.storage.mustGetPickleStepResultsByStatus(pending)) {
|
||||
} else if len(f.storage.MustGetPickleStepResultsByStatus(passed)) == 0 {
|
||||
if len(f.storage.MustGetPickleStepResultsByStatus(undefined)) > len(f.storage.MustGetPickleStepResultsByStatus(pending)) {
|
||||
status = undefined
|
||||
} else {
|
||||
status = pending
|
||||
}
|
||||
}
|
||||
|
||||
snips := f.snippets()
|
||||
snips := f.Snippets()
|
||||
if len(snips) > 0 {
|
||||
snips = "You can implement step definitions for undefined steps with these snippets:\n" + snips
|
||||
}
|
||||
|
@ -130,20 +135,20 @@ func (f *events) Summary() {
|
|||
}{
|
||||
"TestRunFinished",
|
||||
status.String(),
|
||||
timeNowFunc().UnixNano() / nanoSec,
|
||||
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||
snips,
|
||||
"", // @TODO not sure that could be correctly implemented
|
||||
})
|
||||
}
|
||||
|
||||
func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStep.Id)
|
||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
||||
func (f *eventsFormatter) step(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep) {
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
pickleStepResult := f.storage.MustGetPickleStepResult(pickleStep.Id)
|
||||
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||
|
||||
var errMsg string
|
||||
if pickleStepResult.err != nil {
|
||||
errMsg = pickleStepResult.err.Error()
|
||||
if pickleStepResult.Err != nil {
|
||||
errMsg = pickleStepResult.Err.Error()
|
||||
}
|
||||
f.event(&struct {
|
||||
Event string `json:"event"`
|
||||
|
@ -154,7 +159,7 @@ func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_Pickl
|
|||
}{
|
||||
"TestStepFinished",
|
||||
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
||||
timeNowFunc().UnixNano() / nanoSec,
|
||||
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||
pickleStepResult.Status.String(),
|
||||
errMsg,
|
||||
})
|
||||
|
@ -162,17 +167,11 @@ func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_Pickl
|
|||
if isLastStep(pickle, pickleStep) {
|
||||
var status string
|
||||
|
||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||
for _, stepResult := range pickleStepResults {
|
||||
switch stepResult.Status {
|
||||
case passed:
|
||||
status = passed.String()
|
||||
case failed:
|
||||
status = failed.String()
|
||||
case undefined:
|
||||
status = undefined.String()
|
||||
case pending:
|
||||
status = pending.String()
|
||||
case passed, failed, undefined, pending:
|
||||
status = stepResult.Status.String()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,20 +183,20 @@ func (f *events) step(pickle *messages.Pickle, pickleStep *messages.Pickle_Pickl
|
|||
}{
|
||||
"TestCaseFinished",
|
||||
f.scenarioLocation(pickle),
|
||||
timeNowFunc().UnixNano() / nanoSec,
|
||||
utils.TimeNowFunc().UnixNano() / nanoSec,
|
||||
status,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (f *events) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep, def *StepDefinition) {
|
||||
f.basefmt.Defined(pickle, pickleStep, def)
|
||||
func (f *eventsFormatter) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_PickleStep, def *models.StepDefinition) {
|
||||
f.Basefmt.Defined(pickle, pickleStep, def)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
step := feature.findStep(pickleStep.AstNodeIds[0])
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
step := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||
|
||||
if def != nil {
|
||||
m := def.Expr.FindStringSubmatchIndex(pickleStep.Text)[2:]
|
||||
|
@ -222,7 +221,7 @@ func (f *events) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_Pi
|
|||
}{
|
||||
"StepDefinitionFound",
|
||||
fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line),
|
||||
def.definitionID(),
|
||||
DefinitionID(def),
|
||||
args,
|
||||
})
|
||||
}
|
||||
|
@ -234,12 +233,12 @@ func (f *events) Defined(pickle *messages.Pickle, pickleStep *messages.Pickle_Pi
|
|||
}{
|
||||
"TestStepStarted",
|
||||
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) {
|
||||
f.basefmt.Passed(pickle, step, match)
|
||||
func (f *eventsFormatter) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Passed(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -247,8 +246,8 @@ func (f *events) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
|||
f.step(pickle, step)
|
||||
}
|
||||
|
||||
func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Skipped(pickle, step, match)
|
||||
func (f *eventsFormatter) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Skipped(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -256,8 +255,8 @@ func (f *events) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
|||
f.step(pickle, step)
|
||||
}
|
||||
|
||||
func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Undefined(pickle, step, match)
|
||||
func (f *eventsFormatter) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Undefined(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -265,8 +264,8 @@ func (f *events) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
|||
f.step(pickle, step)
|
||||
}
|
||||
|
||||
func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||
f.basefmt.Failed(pickle, step, match, err)
|
||||
func (f *eventsFormatter) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition, err error) {
|
||||
f.Basefmt.Failed(pickle, step, match, err)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -274,8 +273,8 @@ func (f *events) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
|||
f.step(pickle, step)
|
||||
}
|
||||
|
||||
func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Pending(pickle, step, match)
|
||||
func (f *eventsFormatter) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Pending(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -283,15 +282,19 @@ func (f *events) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
|||
f.step(pickle, step)
|
||||
}
|
||||
|
||||
func (f *events) scenarioLocation(pickle *messages.Pickle) string {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
scenario := feature.findScenario(pickle.AstNodeIds[0])
|
||||
func (f *eventsFormatter) scenarioLocation(pickle *messages.Pickle) string {
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
scenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||
|
||||
line := scenario.Location.Line
|
||||
if len(pickle.AstNodeIds) == 2 {
|
||||
_, row := feature.findExample(pickle.AstNodeIds[1])
|
||||
_, row := feature.FindExample(pickle.AstNodeIds[1])
|
||||
line = row.Location.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 (
|
||||
"encoding/xml"
|
||||
|
@ -8,18 +8,22 @@ import (
|
|||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cucumber/godog/formatters"
|
||||
"github.com/cucumber/godog/internal/utils"
|
||||
)
|
||||
|
||||
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 {
|
||||
return &junitFormatter{basefmt: newBaseFmt(suite, out)}
|
||||
// JUnitFormatterFunc implements the FormatterFunc for the junit formatter
|
||||
func JUnitFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||
return &junitFormatter{Basefmt: NewBaseFmt(suite, out)}
|
||||
}
|
||||
|
||||
type junitFormatter struct {
|
||||
*basefmt
|
||||
*Basefmt
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
||||
features := f.storage.mustGetFeatures()
|
||||
func (f *junitFormatter) buildJUNITPackageSuite() JunitPackageSuite {
|
||||
features := f.storage.MustGetFeatures()
|
||||
sort.Sort(sortFeaturesByName(features))
|
||||
|
||||
testRunStartedAt := f.storage.mustGetTestRunStarted().StartedAt
|
||||
testRunStartedAt := f.storage.MustGetTestRunStarted().StartedAt
|
||||
|
||||
suite := junitPackageSuite{
|
||||
suite := JunitPackageSuite{
|
||||
Name: f.suiteName,
|
||||
TestSuites: make([]*junitTestSuite, len(features)),
|
||||
Time: junitTimeDuration(testRunStartedAt, timeNowFunc()),
|
||||
Time: junitTimeDuration(testRunStartedAt, utils.TimeNowFunc()),
|
||||
}
|
||||
|
||||
for idx, feature := range features {
|
||||
pickles := f.storage.mustGetPickles(feature.Uri)
|
||||
pickles := f.storage.MustGetPickles(feature.Uri)
|
||||
sort.Sort(sortPicklesByID(pickles))
|
||||
|
||||
ts := junitTestSuite{
|
||||
|
@ -74,7 +78,7 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
|||
for idx, pickle := range pickles {
|
||||
tc := junitTestCase{}
|
||||
|
||||
pickleResult := f.storage.mustGetPickleResult(pickle.Id)
|
||||
pickleResult := f.storage.MustGetPickleResult(pickle.Id)
|
||||
|
||||
if idx == 0 {
|
||||
firstPickleStartedAt = pickleResult.StartedAt
|
||||
|
@ -84,8 +88,8 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
|||
|
||||
if len(pickle.Steps) > 0 {
|
||||
lastStep := pickle.Steps[len(pickle.Steps)-1]
|
||||
lastPickleStepResult := f.storage.mustGetPickleStepResult(lastStep.Id)
|
||||
lastPickleFinishedAt = lastPickleStepResult.finishedAt
|
||||
lastPickleStepResult := f.storage.MustGetPickleStepResult(lastStep.Id)
|
||||
lastPickleFinishedAt = lastPickleStepResult.FinishedAt
|
||||
}
|
||||
|
||||
tc.Time = junitTimeDuration(pickleResult.StartedAt, lastPickleFinishedAt)
|
||||
|
@ -99,9 +103,9 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
|||
ts.Tests++
|
||||
suite.Tests++
|
||||
|
||||
pickleStepResults := f.storage.mustGetPickleStepResultsByPickleID(pickle.Id)
|
||||
pickleStepResults := f.storage.MustGetPickleStepResultsByPickleID(pickle.Id)
|
||||
for _, stepResult := range pickleStepResults {
|
||||
pickleStep := f.storage.mustGetPickleStep(stepResult.PickleStepID)
|
||||
pickleStep := f.storage.MustGetPickleStep(stepResult.PickleStepID)
|
||||
|
||||
switch stepResult.Status {
|
||||
case passed:
|
||||
|
@ -109,7 +113,7 @@ func (f *junitFormatter) buildJUNITPackageSuite() junitPackageSuite {
|
|||
case failed:
|
||||
tc.Status = failed.String()
|
||||
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:
|
||||
tc.Error = append(tc.Error, &junitError{
|
||||
|
@ -182,7 +186,8 @@ type junitTestSuite struct {
|
|||
TestCases []*junitTestCase
|
||||
}
|
||||
|
||||
type junitPackageSuite struct {
|
||||
// JunitPackageSuite ...
|
||||
type JunitPackageSuite struct {
|
||||
XMLName xml.Name `xml:"testsuites"`
|
||||
Name string `xml:"name,attr"`
|
||||
Tests int `xml:"tests,attr"`
|
|
@ -1,4 +1,4 @@
|
|||
package godog_test
|
||||
package formatters_test
|
||||
|
||||
import (
|
||||
"bytes"
|
|
@ -1,4 +1,4 @@
|
|||
package godog
|
||||
package formatters
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -11,26 +11,29 @@ import (
|
|||
"github.com/cucumber/messages-go/v10"
|
||||
|
||||
"github.com/cucumber/godog/colors"
|
||||
"github.com/cucumber/godog/formatters"
|
||||
"github.com/cucumber/godog/internal/models"
|
||||
)
|
||||
|
||||
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 {
|
||||
return &pretty{basefmt: newBaseFmt(suite, out)}
|
||||
// PrettyFormatterFunc implements the FormatterFunc for the pretty formatter
|
||||
func PrettyFormatterFunc(suite string, out io.Writer) formatters.Formatter {
|
||||
return &pretty{Basefmt: NewBaseFmt(suite, out)}
|
||||
}
|
||||
|
||||
var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>")
|
||||
|
||||
// a built in default pretty formatter
|
||||
type pretty struct {
|
||||
*basefmt
|
||||
*Basefmt
|
||||
firstFeature *bool
|
||||
}
|
||||
|
||||
func (f *pretty) TestRunStarted() {
|
||||
f.basefmt.TestRunStarted()
|
||||
f.Basefmt.TestRunStarted()
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -48,7 +51,7 @@ func (f *pretty) Feature(gd *messages.GherkinDocument, p string, c []byte) {
|
|||
*f.firstFeature = false
|
||||
f.lock.Unlock()
|
||||
|
||||
f.basefmt.Feature(gd, p, c)
|
||||
f.Basefmt.Feature(gd, p, c)
|
||||
|
||||
f.lock.Lock()
|
||||
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
|
||||
func (f *pretty) Pickle(pickle *messages.Pickle) {
|
||||
f.basefmt.Pickle(pickle)
|
||||
f.Basefmt.Pickle(pickle)
|
||||
|
||||
f.lock.Lock()
|
||||
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) {
|
||||
f.basefmt.Passed(pickle, step, match)
|
||||
func (f *pretty) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Passed(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -78,8 +81,8 @@ func (f *pretty) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
|||
f.printStep(pickle, step)
|
||||
}
|
||||
|
||||
func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Skipped(pickle, step, match)
|
||||
func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Skipped(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -87,8 +90,8 @@ func (f *pretty) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleSt
|
|||
f.printStep(pickle, step)
|
||||
}
|
||||
|
||||
func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Undefined(pickle, step, match)
|
||||
func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Undefined(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -96,8 +99,8 @@ func (f *pretty) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
|||
f.printStep(pickle, step)
|
||||
}
|
||||
|
||||
func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||
f.basefmt.Failed(pickle, step, match, err)
|
||||
func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition, err error) {
|
||||
f.Basefmt.Failed(pickle, step, match, err)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -105,8 +108,8 @@ func (f *pretty) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleSte
|
|||
f.printStep(pickle, step)
|
||||
}
|
||||
|
||||
func (f *pretty) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Pending(pickle, step, match)
|
||||
func (f *pretty) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Pending(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
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) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
||||
astBackground := feature.findBackground(pickle.AstNodeIds[0])
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
|
||||
|
||||
scenarioHeaderLength = f.lengthPickle(astScenario.Keyword, astScenario.Name)
|
||||
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) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
text := s(f.indent) + keywordAndName(astScenario.Keyword, astScenario.Name)
|
||||
text += s(spaceFilling) + line(feature.Uri, astScenario.Location)
|
||||
fmt.Fprintln(f.out, "\n"+text)
|
||||
}
|
||||
|
||||
func (f *pretty) printUndefinedPickle(pickle *messages.Pickle) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
||||
astBackground := feature.findBackground(pickle.AstNodeIds[0])
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
func (f *pretty) Summary() {
|
||||
failedStepResults := f.storage.mustGetPickleStepResultsByStatus(failed)
|
||||
failedStepResults := f.storage.MustGetPickleStepResultsByStatus(failed)
|
||||
if len(failedStepResults) > 0 {
|
||||
fmt.Fprintln(f.out, "\n--- "+red("Failed steps:")+"\n")
|
||||
|
||||
sort.Sort(sortPickleStepResultsByPickleStepID(failedStepResults))
|
||||
|
||||
for _, fail := range failedStepResults {
|
||||
pickle := f.storage.mustGetPickle(fail.PickleID)
|
||||
pickleStep := f.storage.mustGetPickleStep(fail.PickleStepID)
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
pickle := f.storage.MustGetPickle(fail.PickleID)
|
||||
pickleStep := f.storage.MustGetPickleStep(fail.PickleStepID)
|
||||
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)
|
||||
|
||||
astStep := feature.findStep(pickleStep.AstNodeIds[0])
|
||||
astStep := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||
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*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) {
|
||||
var errorMsg string
|
||||
var clr = green
|
||||
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||
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
|
||||
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
|
||||
if firstExamplesTable && printExampleHeader && firstExecutedScenarioStep {
|
||||
|
@ -257,10 +260,10 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
|||
// determine example row status
|
||||
switch {
|
||||
case result.Status == failed:
|
||||
errorMsg = result.err.Error()
|
||||
clr = result.Status.clr()
|
||||
errorMsg = result.Err.Error()
|
||||
clr = result.Status.Color()
|
||||
case result.Status == undefined || result.Status == pending:
|
||||
clr = result.Status.clr()
|
||||
clr = result.Status.Color()
|
||||
case result.Status == skipped && clr == nil:
|
||||
clr = cyan
|
||||
}
|
||||
|
@ -268,11 +271,11 @@ func (f *pretty) printOutlineExample(pickle *messages.Pickle, backgroundSteps in
|
|||
if firstExamplesTable && printExampleHeader {
|
||||
// in first example, we need to print steps
|
||||
|
||||
pickleStep := f.storage.mustGetPickleStep(result.PickleStepID)
|
||||
astStep := feature.findStep(pickleStep.AstNodeIds[0])
|
||||
pickleStep := f.storage.MustGetPickleStep(result.PickleStepID)
|
||||
astStep := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||
|
||||
var text = ""
|
||||
if result.def != nil {
|
||||
if result.Def != nil {
|
||||
if m := outlinePlaceholderRegexp.FindAllStringIndex(astStep.Text, -1); len(m) > 0 {
|
||||
var pos int
|
||||
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)
|
||||
|
||||
text += s(maxLength - stepLength)
|
||||
text += " " + blackb("# "+result.def.definitionID())
|
||||
text += " " + blackb("# "+DefinitionID(result.Def))
|
||||
}
|
||||
|
||||
// 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) {
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
astBackground := feature.findBackground(pickle.AstNodeIds[0])
|
||||
astScenario := feature.findScenario(pickle.AstNodeIds[0])
|
||||
astStep := feature.findStep(pickleStep.AstNodeIds[0])
|
||||
feature := f.storage.MustGetFeature(pickle.Uri)
|
||||
astBackground := feature.FindBackground(pickle.AstNodeIds[0])
|
||||
astScenario := feature.FindScenario(pickle.AstNodeIds[0])
|
||||
astStep := feature.FindStep(pickleStep.AstNodeIds[0])
|
||||
|
||||
var astBackgroundStep 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 {
|
||||
return
|
||||
|
@ -383,11 +386,11 @@ func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_
|
|||
f.printScenarioHeader(pickle, astScenario, maxLength-scenarioHeaderLength)
|
||||
}
|
||||
|
||||
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStep.Id)
|
||||
text := s(f.indent*2) + pickleStepResult.Status.clr()(strings.TrimSpace(astStep.Keyword)) + " " + pickleStepResult.Status.clr()(pickleStep.Text)
|
||||
if pickleStepResult.def != nil {
|
||||
pickleStepResult := f.storage.MustGetPickleStepResult(pickleStep.Id)
|
||||
text := s(f.indent*2) + pickleStepResult.Status.Color()(strings.TrimSpace(astStep.Keyword)) + " " + pickleStepResult.Status.Color()(pickleStep.Text)
|
||||
if pickleStepResult.Def != nil {
|
||||
text += s(maxLength - stepLength + 1)
|
||||
text += blackb("# " + pickleStepResult.def.definitionID())
|
||||
text += blackb("# " + DefinitionID(pickleStepResult.Def))
|
||||
}
|
||||
fmt.Fprintln(f.out, text)
|
||||
|
||||
|
@ -399,8 +402,8 @@ func (f *pretty) printStep(pickle *messages.Pickle, pickleStep *messages.Pickle_
|
|||
f.printDocString(docString)
|
||||
}
|
||||
|
||||
if pickleStepResult.err != nil {
|
||||
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", pickleStepResult.err)))
|
||||
if pickleStepResult.Err != nil {
|
||||
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", pickleStepResult.Err)))
|
||||
}
|
||||
|
||||
if pickleStepResult.Status == pending {
|
|
@ -1,4 +1,4 @@
|
|||
package godog
|
||||
package formatters
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -8,23 +8,27 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/cucumber/messages-go/v10"
|
||||
|
||||
"github.com/cucumber/godog/formatters"
|
||||
"github.com/cucumber/godog/internal/models"
|
||||
)
|
||||
|
||||
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
|
||||
return &progress{
|
||||
basefmt: newBaseFmt(suite, out),
|
||||
Basefmt: NewBaseFmt(suite, out),
|
||||
stepsPerRow: 70,
|
||||
steps: &steps,
|
||||
}
|
||||
}
|
||||
|
||||
type progress struct {
|
||||
*basefmt
|
||||
*Basefmt
|
||||
stepsPerRow int
|
||||
steps *int
|
||||
}
|
||||
|
@ -41,20 +45,20 @@ func (f *progress) Summary() {
|
|||
|
||||
var failedStepsOutput []string
|
||||
|
||||
failedSteps := f.storage.mustGetPickleStepResultsByStatus(failed)
|
||||
failedSteps := f.storage.MustGetPickleStepResultsByStatus(failed)
|
||||
sort.Sort(sortPickleStepResultsByPickleStepID(failedSteps))
|
||||
|
||||
for _, sr := range failedSteps {
|
||||
if sr.Status == failed {
|
||||
pickle := f.storage.mustGetPickle(sr.PickleID)
|
||||
pickleStep := f.storage.mustGetPickleStep(sr.PickleStepID)
|
||||
feature := f.storage.mustGetFeature(pickle.Uri)
|
||||
pickle := f.storage.MustGetPickle(sr.PickleID)
|
||||
pickleStep := f.storage.MustGetPickleStep(sr.PickleStepID)
|
||||
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)
|
||||
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
|
||||
stepLine := fmt.Sprintf("%s:%d", pickle.Uri, step.Location.Line)
|
||||
|
||||
|
@ -62,7 +66,7 @@ func (f *progress) Summary() {
|
|||
failedStepsOutput,
|
||||
s(2)+red(scenarioDesc)+blackb(" # "+scenarioLine),
|
||||
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, "")
|
||||
|
||||
f.basefmt.Summary()
|
||||
f.Basefmt.Summary()
|
||||
}
|
||||
|
||||
func (f *progress) step(pickleStepID string) {
|
||||
pickleStepResult := f.storage.mustGetPickleStepResult(pickleStepID)
|
||||
pickleStepResult := f.storage.MustGetPickleStepResult(pickleStepID)
|
||||
|
||||
switch pickleStepResult.Status {
|
||||
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) {
|
||||
f.basefmt.Passed(pickle, step, match)
|
||||
func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Passed(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -109,8 +113,8 @@ func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleS
|
|||
f.step(step.Id)
|
||||
}
|
||||
|
||||
func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Skipped(pickle, step, match)
|
||||
func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Skipped(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -118,8 +122,8 @@ func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_Pickle
|
|||
f.step(step.Id)
|
||||
}
|
||||
|
||||
func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Undefined(pickle, step, match)
|
||||
func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Undefined(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -127,8 +131,8 @@ func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_Pick
|
|||
f.step(step.Id)
|
||||
}
|
||||
|
||||
func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) {
|
||||
f.basefmt.Failed(pickle, step, match, err)
|
||||
func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition, err error) {
|
||||
f.Basefmt.Failed(pickle, step, match, err)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
@ -136,8 +140,8 @@ func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleS
|
|||
f.step(step.Id)
|
||||
}
|
||||
|
||||
func (f *progress) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) {
|
||||
f.basefmt.Pending(pickle, step, match)
|
||||
func (f *progress) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *models.StepDefinition) {
|
||||
f.Basefmt.Pending(pickle, step, match)
|
||||
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
|
@ -1,57 +1,57 @@
|
|||
{"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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"}
|
|
@ -1,16 +1,16 @@
|
|||
{"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":"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":"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":"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":"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":"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"}
|
|
@ -1,7 +1,7 @@
|
|||
{"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":"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":"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"}
|
|
@ -1,28 +1,28 @@
|
|||
{"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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"}
|
|
@ -1,27 +1,27 @@
|
|||
{"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":"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":"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":"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":"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":"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":"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":"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":"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":"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"}
|
|
@ -1,9 +1,9 @@
|
|||
<bold-white>Feature:</bold-white> outline
|
||||
|
||||
<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>When</cyan> <cyan>passing step</cyan> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_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>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/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/internal/formatters_test.oddEvenStepDef</bold-black>
|
||||
|
||||
<bold-white>Examples:</bold-white> tagged
|
||||
| <cyan>odd</cyan> | <cyan>even</cyan> |
|
|
@ -1,12 +1,12 @@
|
|||
<bold-white>Feature:</bold-white> single scenario with background
|
||||
|
||||
<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>And</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/internal/formatters_test.passingStepDef</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>Then</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/internal/formatters_test.passingStepDef</bold-black>
|
||||
|
||||
1 scenarios (<green>1 passed</green>)
|
||||
4 steps (<green>4 passed</green>)
|
|
@ -4,7 +4,7 @@
|
|||
feature
|
||||
|
||||
<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 steps (<green>1 passed</green>)
|
|
@ -1,19 +1,19 @@
|
|||
<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>
|
||||
<green>Given</green> <green>passing step</green> <bold-black># fmt_output_test.go:101 -> github.com/cucumber/godog_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>
|
||||
<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/internal/formatters_test.failingStepDef</bold-black>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
<bold-white>Feature:</bold-white> two scenarios with background fail
|
||||
|
||||
<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>
|
||||
<red>And</red> <red>failing step</red> <bold-black># fmt_output_test.go:117 -> github.com/cucumber/godog_test.failingStepDef</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/internal/formatters_test.failingStepDef</bold-black>
|
||||
<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>
|
||||
<cyan>When</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_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/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>
|
||||
<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>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package godog
|
||||
package formatters
|
||||
|
||||
import (
|
||||
"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 (
|
||||
"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
|
||||
pickles []*messages.Pickle
|
||||
content []byte
|
||||
Pickles []*messages.Pickle
|
||||
Content []byte
|
||||
}
|
||||
|
||||
type sortFeaturesByName []*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] }
|
||||
|
||||
func (f feature) findScenario(astScenarioID string) *messages.GherkinDocument_Feature_Scenario {
|
||||
// FindScenario ...
|
||||
func (f Feature) FindScenario(astScenarioID string) *messages.GherkinDocument_Feature_Scenario {
|
||||
for _, child := range f.GherkinDocument.Feature.Children {
|
||||
if sc := child.GetScenario(); sc != nil && sc.Id == astScenarioID {
|
||||
return sc
|
||||
|
@ -26,7 +24,8 @@ func (f feature) findScenario(astScenarioID string) *messages.GherkinDocument_Fe
|
|||
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
|
||||
|
||||
for _, child := range f.GherkinDocument.Feature.Children {
|
||||
|
@ -42,7 +41,8 @@ func (f feature) findBackground(astScenarioID string) *messages.GherkinDocument_
|
|||
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 {
|
||||
if sc := child.GetScenario(); sc != nil {
|
||||
for _, example := range sc.Examples {
|
||||
|
@ -58,7 +58,8 @@ func (f feature) findExample(exampleAstID string) (*messages.GherkinDocument_Fea
|
|||
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 {
|
||||
if sc := child.GetScenario(); sc != nil {
|
||||
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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cucumber/messages-go/v10"
|
||||
)
|
||||
|
||||
var matchFuncDefRef = regexp.MustCompile(`\(([^\)]+)\)`)
|
||||
|
||||
// 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
|
||||
var typeOfBytes = reflect.TypeOf([]byte(nil))
|
||||
|
||||
// StepDefinition is a registered step definition
|
||||
// contains a StepHandler and regexp which
|
||||
|
@ -40,50 +20,21 @@ type Steps []string
|
|||
// when step is matched and is either failed
|
||||
// or successful
|
||||
type StepDefinition struct {
|
||||
args []interface{}
|
||||
hv reflect.Value
|
||||
Expr *regexp.Regexp
|
||||
Handler interface{}
|
||||
Args []interface{}
|
||||
HandlerValue reflect.Value
|
||||
Expr *regexp.Regexp
|
||||
Handler interface{}
|
||||
|
||||
// multistep related
|
||||
nested bool
|
||||
undefined []string
|
||||
Nested bool
|
||||
Undefined []string
|
||||
}
|
||||
|
||||
func (sd *StepDefinition) definitionID() string {
|
||||
ptr := sd.hv.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)
|
||||
}
|
||||
|
||||
// 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))
|
||||
// Run a step with the matched arguments using reflect
|
||||
func (sd *StepDefinition) Run() interface{} {
|
||||
typ := sd.HandlerValue.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
|
||||
for i := 0; i < typ.NumIn(); i++ {
|
||||
|
@ -166,7 +117,7 @@ func (sd *StepDefinition) run() interface{} {
|
|||
}
|
||||
values = append(values, reflect.ValueOf(float32(v)))
|
||||
case reflect.Ptr:
|
||||
arg := sd.args[i]
|
||||
arg := sd.Args[i]
|
||||
switch param.Elem().String() {
|
||||
case "messages.PickleStepArgument_PickleDocString":
|
||||
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) {
|
||||
arg := sd.args[idx]
|
||||
arg := sd.Args[idx]
|
||||
s, ok := arg.(string)
|
||||
if !ok {
|
||||
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 (
|
||||
"fmt"
|
||||
|
@ -6,6 +6,8 @@ import (
|
|||
|
||||
"github.com/cucumber/messages-go/v10"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
|
||||
"github.com/cucumber/godog/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -31,15 +33,17 @@ const (
|
|||
tablePickleStepResultIndexStatus string = "status"
|
||||
)
|
||||
|
||||
type storage struct {
|
||||
// Storage is a thread safe in-mem storage
|
||||
type Storage struct {
|
||||
db *memdb.MemDB
|
||||
|
||||
testRunStarted testRunStarted
|
||||
lock *sync.Mutex
|
||||
testRunStarted models.TestRunStarted
|
||||
testRunStartedLock *sync.Mutex
|
||||
}
|
||||
|
||||
func newStorage() *storage {
|
||||
// Create the DB schema
|
||||
// NewStorage will create an in-mem storage that
|
||||
// is used across concurrent runners and formatters
|
||||
func NewStorage() *Storage {
|
||||
schema := memdb.DBSchema{
|
||||
Tables: map[string]*memdb.TableSchema{
|
||||
tableFeature: {
|
||||
|
@ -115,10 +119,12 @@ func newStorage() *storage {
|
|||
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)
|
||||
|
||||
if err := txn.Insert(tablePickle, p); err != nil {
|
||||
|
@ -134,12 +140,14 @@ func (s *storage) mustInsertPickle(p *messages.Pickle) {
|
|||
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)
|
||||
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)
|
||||
for v := it.Next(); v != nil; v = it.Next() {
|
||||
ps = append(ps, v.(*messages.Pickle))
|
||||
|
@ -148,89 +156,102 @@ func (s *storage) mustGetPickles(uri string) (ps []*messages.Pickle) {
|
|||
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)
|
||||
return v.(*messages.Pickle_PickleStep)
|
||||
}
|
||||
|
||||
func (s *storage) mustInsertTestRunStarted(trs testRunStarted) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
// MustInsertTestRunStarted will set the test run started event and panic on error.
|
||||
func (s *Storage) MustInsertTestRunStarted(trs models.TestRunStarted) {
|
||||
s.testRunStartedLock.Lock()
|
||||
defer s.testRunStartedLock.Unlock()
|
||||
|
||||
s.testRunStarted = trs
|
||||
}
|
||||
|
||||
func (s *storage) mustGetTestRunStarted() testRunStarted {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
// MustGetTestRunStarted will retrieve the test run started event and panic on error.
|
||||
func (s *Storage) MustGetTestRunStarted() models.TestRunStarted {
|
||||
s.testRunStartedLock.Lock()
|
||||
defer s.testRunStartedLock.Unlock()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
for v := it.Next(); v != nil; v = it.Next() {
|
||||
prs = append(prs, v.(pickleResult))
|
||||
prs = append(prs, v.(models.PickleResult))
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
for v := it.Next(); v != nil; v = it.Next() {
|
||||
psrs = append(psrs, v.(pickleStepResult))
|
||||
psrs = append(psrs, v.(models.PickleStepResult))
|
||||
}
|
||||
|
||||
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)
|
||||
for v := it.Next(); v != nil; v = it.Next() {
|
||||
psrs = append(psrs, v.(pickleStepResult))
|
||||
psrs = append(psrs, v.(models.PickleStepResult))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
for v := it.Next(); v != nil; v = it.Next() {
|
||||
fs = append(fs, v.(*feature))
|
||||
fs = append(fs, v.(*models.Feature))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *storage) mustInsert(table string, obj interface{}) {
|
||||
func (s *Storage) mustInsert(table string, obj interface{}) {
|
||||
txn := s.db.Txn(writeMode)
|
||||
|
||||
if err := txn.Insert(table, obj); err != nil {
|
||||
|
@ -240,7 +261,7 @@ func (s *storage) mustInsert(table string, obj interface{}) {
|
|||
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)
|
||||
defer txn.Abort()
|
||||
|
||||
|
@ -255,7 +276,7 @@ func (s *storage) mustFirst(table, index string, args ...interface{}) interface{
|
|||
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)
|
||||
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/messages-go/v10"
|
||||
|
||||
"github.com/cucumber/godog/internal/models"
|
||||
"github.com/cucumber/godog/internal/tags"
|
||||
)
|
||||
|
||||
|
@ -30,7 +31,7 @@ func extractFeaturePathLine(p string) (string, int) {
|
|||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -47,12 +48,12 @@ func parseFeatureFile(path string, newIDFunc func() string) (*feature, error) {
|
|||
gherkinDocument.Uri = path
|
||||
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
|
||||
}
|
||||
|
||||
func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
||||
var features []*feature
|
||||
func parseFeatureDir(dir string, newIDFunc func() string) ([]*models.Feature, error) {
|
||||
var features []*models.Feature
|
||||
return features, filepath.Walk(dir, func(p string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -76,8 +77,8 @@ func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
|
|||
})
|
||||
}
|
||||
|
||||
func parsePath(path string) ([]*feature, error) {
|
||||
var features []*feature
|
||||
func parsePath(path string) ([]*models.Feature, error) {
|
||||
var features []*models.Feature
|
||||
|
||||
path, line := extractFeaturePathLine(path)
|
||||
|
||||
|
@ -99,23 +100,23 @@ func parsePath(path string) ([]*feature, error) {
|
|||
|
||||
// filter scenario by line number
|
||||
var pickles []*messages.Pickle
|
||||
for _, pickle := range ft.pickles {
|
||||
sc := ft.findScenario(pickle.AstNodeIds[0])
|
||||
for _, pickle := range ft.Pickles {
|
||||
sc := ft.FindScenario(pickle.AstNodeIds[0])
|
||||
|
||||
if line == -1 || uint32(line) == sc.Location.Line {
|
||||
pickles = append(pickles, pickle)
|
||||
}
|
||||
}
|
||||
ft.pickles = pickles
|
||||
ft.Pickles = pickles
|
||||
|
||||
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
|
||||
|
||||
featureIdxs := make(map[string]int)
|
||||
uniqueFeatureURI := make(map[string]*feature)
|
||||
uniqueFeatureURI := make(map[string]*models.Feature)
|
||||
for _, path := range paths {
|
||||
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 {
|
||||
idx := featureIdxs[uri]
|
||||
features[idx] = feature
|
||||
|
@ -151,11 +152,11 @@ func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
|||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
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"
|
||||
"sync"
|
||||
|
||||
"github.com/cucumber/godog/colors"
|
||||
"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 (
|
||||
|
@ -29,12 +33,12 @@ type runner struct {
|
|||
randomSeed int64
|
||||
stopOnFailure, strict bool
|
||||
|
||||
features []*feature
|
||||
features []*models.Feature
|
||||
|
||||
testSuiteInitializer testSuiteInitializer
|
||||
scenarioInitializer scenarioInitializer
|
||||
|
||||
storage *storage
|
||||
storage *storage.Storage
|
||||
fmt Formatter
|
||||
}
|
||||
|
||||
|
@ -42,7 +46,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
|||
var copyLock sync.Mutex
|
||||
|
||||
if fmt, ok := r.fmt.(storageFormatter); ok {
|
||||
fmt.setStorage(r.storage)
|
||||
fmt.SetStorage(r.storage)
|
||||
}
|
||||
|
||||
testSuiteContext := TestSuiteContext{}
|
||||
|
@ -50,8 +54,8 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
|||
r.testSuiteInitializer(&testSuiteContext)
|
||||
}
|
||||
|
||||
testRunStarted := testRunStarted{StartedAt: timeNowFunc()}
|
||||
r.storage.mustInsertTestRunStarted(testRunStarted)
|
||||
testRunStarted := models.TestRunStarted{StartedAt: utils.TimeNowFunc()}
|
||||
r.storage.MustInsertTestRunStarted(testRunStarted)
|
||||
r.fmt.TestRunStarted()
|
||||
|
||||
// run before suite handlers
|
||||
|
@ -61,15 +65,15 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
|||
|
||||
queue := make(chan int, rate)
|
||||
for _, ft := range r.features {
|
||||
pickles := make([]*messages.Pickle, len(ft.pickles))
|
||||
pickles := make([]*messages.Pickle, len(ft.Pickles))
|
||||
if r.randomSeed != 0 {
|
||||
r := rand.New(rand.NewSource(r.randomSeed))
|
||||
perm := r.Perm(len(ft.pickles))
|
||||
perm := r.Perm(len(ft.Pickles))
|
||||
for i, v := range perm {
|
||||
pickles[v] = ft.pickles[i]
|
||||
pickles[v] = ft.Pickles[i]
|
||||
}
|
||||
} else {
|
||||
copy(pickles, ft.pickles)
|
||||
copy(pickles, ft.Pickles)
|
||||
}
|
||||
|
||||
for i, p := range pickles {
|
||||
|
@ -78,7 +82,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
|
|||
queue <- i // reserve space in queue
|
||||
|
||||
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) {
|
||||
|
@ -181,12 +185,12 @@ func runWithOptions(suiteName string, runner runner, opt Options) int {
|
|||
return exitOptionError
|
||||
}
|
||||
|
||||
runner.storage = newStorage()
|
||||
runner.storage = storage.NewStorage()
|
||||
for _, feat := range runner.features {
|
||||
runner.storage.mustInsertFeature(feat)
|
||||
runner.storage.MustInsertFeature(feat)
|
||||
|
||||
for _, pickle := range feat.pickles {
|
||||
runner.storage.mustInsertPickle(pickle)
|
||||
for _, pickle := range feat.Pickles {
|
||||
runner.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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 = `
|
||||
|
@ -28,31 +31,31 @@ func Test_ProgressFormatterWhenStepPanics(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := colors.Uncolored(&buf)
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", w),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
ctx.Step(`^two$`, func() error { panic("omg") })
|
||||
},
|
||||
}
|
||||
|
||||
r.storage = newStorage()
|
||||
r.storage.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
require.True(t, failed)
|
||||
|
||||
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) {
|
||||
|
@ -62,14 +65,14 @@ func Test_ProgressFormatterWithPanicInMultistep(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := colors.Uncolored(&buf)
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", w),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^sub1$`, 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.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
|
@ -96,14 +99,14 @@ func Test_ProgressFormatterMultistepTemplates(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := colors.Uncolored(&buf)
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", w),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^sub-sub$`, func() error { return nil })
|
||||
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.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
|
@ -172,24 +175,24 @@ Feature: basic
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := colors.Uncolored(&buf)
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", w),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
ctx.Step(`^two:$`, func(doc *messages.PickleStepArgument_PickleDocString) Steps { return Steps{"one"} })
|
||||
},
|
||||
}
|
||||
|
||||
r.storage = newStorage()
|
||||
r.storage.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
|
@ -210,8 +213,8 @@ Feature: basic
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
var subStep = `three:
|
||||
"""
|
||||
|
@ -221,8 +224,8 @@ Feature: basic
|
|||
var buf bytes.Buffer
|
||||
w := colors.Uncolored(&buf)
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", w),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", w),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
ctx.Step(`^two$`, func() Steps { return Steps{subStep} })
|
||||
|
@ -230,10 +233,10 @@ Feature: basic
|
|||
},
|
||||
}
|
||||
|
||||
r.storage = newStorage()
|
||||
r.storage.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
57
run_test.go
57
run_test.go
|
@ -17,6 +17,9 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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 {
|
||||
|
@ -70,22 +73,22 @@ func Test_FailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", ioutil.Discard),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", ioutil.Discard),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
ctx.Step(`^two$`, func() error { return ErrPending })
|
||||
},
|
||||
}
|
||||
|
||||
r.storage = newStorage()
|
||||
r.storage.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
|
@ -103,22 +106,22 @@ func Test_FailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", ioutil.Discard),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", ioutil.Discard),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
// two - is undefined
|
||||
},
|
||||
}
|
||||
|
||||
r.storage = newStorage()
|
||||
r.storage.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
|
@ -136,22 +139,22 @@ func Test_ShouldFailOnError(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
gd.Uri = path
|
||||
ft := feature{GherkinDocument: gd}
|
||||
ft.pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
ft := models.Feature{GherkinDocument: gd}
|
||||
ft.Pickles = gherkin.Pickles(*gd, path, (&messages.Incrementing{}).NewId)
|
||||
|
||||
r := runner{
|
||||
fmt: progressFunc("progress", ioutil.Discard),
|
||||
features: []*feature{&ft},
|
||||
fmt: formatters.ProgressFormatterFunc("progress", ioutil.Discard),
|
||||
features: []*models.Feature{&ft},
|
||||
scenarioInitializer: func(ctx *ScenarioContext) {
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
ctx.Step(`^two$`, func() error { return fmt.Errorf("error") })
|
||||
ctx.Step(`^one$`, func() error { return nil })
|
||||
},
|
||||
}
|
||||
|
||||
r.storage = newStorage()
|
||||
r.storage.mustInsertFeature(&ft)
|
||||
for _, pickle := range ft.pickles {
|
||||
r.storage.mustInsertPickle(pickle)
|
||||
r.storage = storage.NewStorage()
|
||||
r.storage.MustInsertFeature(&ft)
|
||||
for _, pickle := range ft.Pickles {
|
||||
r.storage.MustInsertPickle(pickle)
|
||||
}
|
||||
|
||||
failed := r.concurrent(1)
|
||||
|
@ -284,7 +287,7 @@ func Test_RandomizeRun(t *testing.T) {
|
|||
const createRandomSeedFlag = -1
|
||||
const noConcurrencyFlag = 1
|
||||
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) {
|
||||
ctx.Step(`^(?:a )?failing step`, failingStepDef)
|
||||
|
@ -367,7 +370,7 @@ func Test_FormatterConcurrencyRun(t *testing.T) {
|
|||
"cucumber",
|
||||
}
|
||||
|
||||
featurePaths := []string{"formatter-tests/features"}
|
||||
featurePaths := []string{"internal/formatters/formatter-tests/features"}
|
||||
|
||||
const concurrency = 100
|
||||
const noRandomFlag = 0
|
||||
|
|
|
@ -24,7 +24,7 @@ func callstack3() *stack {
|
|||
return &st
|
||||
}
|
||||
|
||||
func TestStacktrace(t *testing.T) {
|
||||
func Test_Stacktrace(t *testing.T) {
|
||||
err := &traceError{
|
||||
msg: "err msg",
|
||||
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")
|
||||
// }
|
||||
}
|
Показаны не все изменённые файлы, т.к. их слишком много Показать больше
Загрузка…
Создание таблицы
Сослаться в новой задаче