must be able to customize output for formatters
since it maybe configured by flag values in the future example: - godog -f junit:stdout - godog -f junit:output.xml
Этот коммит содержится в:
родитель
aed77a5b4b
коммит
e71d596404
6 изменённых файлов: 110 добавлений и 80 удалений
33
fmt.go
33
fmt.go
|
@ -3,6 +3,7 @@ package godog
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -43,13 +44,13 @@ type undefinedSnippet struct {
|
||||||
|
|
||||||
type registeredFormatter struct {
|
type registeredFormatter struct {
|
||||||
name string
|
name string
|
||||||
fmt Formatter
|
fmt FormatterFunc
|
||||||
description string
|
description string
|
||||||
}
|
}
|
||||||
|
|
||||||
var formatters []*registeredFormatter
|
var formatters []*registeredFormatter
|
||||||
|
|
||||||
func findFmt(format string) (f Formatter, err error) {
|
func findFmt(format string) (f FormatterFunc, err error) {
|
||||||
var names []string
|
var names []string
|
||||||
for _, el := range formatters {
|
for _, el := range formatters {
|
||||||
if el.name == format {
|
if el.name == format {
|
||||||
|
@ -66,9 +67,10 @@ func findFmt(format string) (f Formatter, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format registers a feature suite output
|
// Format registers a feature suite output
|
||||||
// Formatter as the name and descriptiongiven.
|
// formatter by given name, description and
|
||||||
// Formatter is used to represent suite output
|
// FormatterFunc constructor function, to initialize
|
||||||
func Format(name, description string, f Formatter) {
|
// formatter with the output recorder.
|
||||||
|
func Format(name, description string, f FormatterFunc) {
|
||||||
formatters = append(formatters, ®isteredFormatter{
|
formatters = append(formatters, ®isteredFormatter{
|
||||||
name: name,
|
name: name,
|
||||||
fmt: f,
|
fmt: f,
|
||||||
|
@ -95,6 +97,10 @@ type Formatter interface {
|
||||||
Summary()
|
Summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormatterFunc builds a formatter with given
|
||||||
|
// io.Writer to record output.
|
||||||
|
type FormatterFunc func(io.Writer) Formatter
|
||||||
|
|
||||||
type stepType int
|
type stepType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -149,6 +155,7 @@ func (f stepResult) line() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type basefmt struct {
|
type basefmt struct {
|
||||||
|
out io.Writer
|
||||||
owner interface{}
|
owner interface{}
|
||||||
indent int
|
indent int
|
||||||
|
|
||||||
|
@ -286,23 +293,23 @@ func (f *basefmt) Summary() {
|
||||||
scenarios = append(scenarios, parts...)
|
scenarios = append(scenarios, parts...)
|
||||||
elapsed := time.Since(f.started)
|
elapsed := time.Since(f.started)
|
||||||
|
|
||||||
fmt.Println("")
|
fmt.Fprintln(f.out, "")
|
||||||
if total == 0 {
|
if total == 0 {
|
||||||
fmt.Println("No scenarios")
|
fmt.Fprintln(f.out, "No scenarios")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(fmt.Sprintf("%d scenarios (%s)", total, strings.Join(scenarios, ", ")))
|
fmt.Fprintln(f.out, fmt.Sprintf("%d scenarios (%s)", total, strings.Join(scenarios, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
if nsteps == 0 {
|
if nsteps == 0 {
|
||||||
fmt.Println("No steps")
|
fmt.Fprintln(f.out, "No steps")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(fmt.Sprintf("%d steps (%s)", nsteps, strings.Join(steps, ", ")))
|
fmt.Fprintln(f.out, fmt.Sprintf("%d steps (%s)", nsteps, strings.Join(steps, ", ")))
|
||||||
}
|
}
|
||||||
fmt.Println(elapsed)
|
fmt.Fprintln(f.out, elapsed)
|
||||||
|
|
||||||
if text := f.snippets(); text != "" {
|
if text := f.snippets(); text != "" {
|
||||||
fmt.Println(cl("\nYou can implement step definitions for undefined steps with these snippets:", yellow))
|
fmt.Fprintln(f.out, cl("\nYou can implement step definitions for undefined steps with these snippets:", yellow))
|
||||||
fmt.Println(cl(text, yellow))
|
fmt.Fprintln(f.out, cl(text, yellow))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,26 +5,20 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/cucumber/gherkin-go.v3"
|
"gopkg.in/cucumber/gherkin-go.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const nanoSec = 1000000
|
const nanoSec = 1000000
|
||||||
|
const spec = "0.1.0"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("events", "Produces a JSON event stream.", &events{
|
Format("events", fmt.Sprintf("Produces JSON event stream, based on spec: %s.", spec), eventsFunc)
|
||||||
basefmt: basefmt{
|
|
||||||
started: time.Now(),
|
|
||||||
indent: 2,
|
|
||||||
},
|
|
||||||
runID: sha1RunID(),
|
|
||||||
suite: "main",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sha1RunID() string {
|
func eventsFunc(out io.Writer) Formatter {
|
||||||
data, err := json.Marshal(&struct {
|
data, err := json.Marshal(&struct {
|
||||||
Time int64
|
Time int64
|
||||||
Runner string
|
Runner string
|
||||||
|
@ -36,11 +30,33 @@ func sha1RunID() string {
|
||||||
|
|
||||||
hasher := sha1.New()
|
hasher := sha1.New()
|
||||||
hasher.Write(data)
|
hasher.Write(data)
|
||||||
return hex.EncodeToString(hasher.Sum(nil))
|
|
||||||
|
formatter := &events{
|
||||||
|
basefmt: basefmt{
|
||||||
|
started: time.Now(),
|
||||||
|
indent: 2,
|
||||||
|
out: out,
|
||||||
|
},
|
||||||
|
runID: hex.EncodeToString(hasher.Sum(nil)),
|
||||||
|
suite: "main",
|
||||||
|
}
|
||||||
|
|
||||||
|
formatter.event(&struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
RunID string `json:"run_id"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
}{
|
||||||
|
"TestRunStarted",
|
||||||
|
formatter.runID,
|
||||||
|
spec,
|
||||||
|
time.Now().UnixNano() / nanoSec,
|
||||||
|
})
|
||||||
|
|
||||||
|
return formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
type events struct {
|
type events struct {
|
||||||
sync.Once
|
|
||||||
basefmt
|
basefmt
|
||||||
|
|
||||||
runID string
|
runID string
|
||||||
|
@ -59,26 +75,11 @@ func (f *events) event(ev interface{}) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("failed to marshal stream event: %+v - %v", ev, err))
|
panic(fmt.Sprintf("failed to marshal stream event: %+v - %v", ev, err))
|
||||||
}
|
}
|
||||||
fmt.Println(string(data))
|
fmt.Fprintln(f.out, string(data))
|
||||||
}
|
|
||||||
|
|
||||||
func (f *events) started() {
|
|
||||||
f.event(&struct {
|
|
||||||
Event string `json:"event"`
|
|
||||||
RunID string `json:"run_id"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
Timestamp int64 `json:"timestamp"`
|
|
||||||
}{
|
|
||||||
"TestRunStarted",
|
|
||||||
f.runID,
|
|
||||||
"0.1.0",
|
|
||||||
time.Now().UnixNano() / nanoSec,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *events) Node(n interface{}) {
|
func (f *events) Node(n interface{}) {
|
||||||
f.basefmt.Node(n)
|
f.basefmt.Node(n)
|
||||||
f.Do(f.started)
|
|
||||||
|
|
||||||
switch t := n.(type) {
|
switch t := n.(type) {
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
|
@ -187,8 +188,8 @@ func (f *events) step(res *stepResult) {
|
||||||
line = last.TableBody[len(last.TableBody)-1].Location.Line
|
line = last.TableBody[len(last.TableBody)-1].Location.Line
|
||||||
}
|
}
|
||||||
case *gherkin.Scenario:
|
case *gherkin.Scenario:
|
||||||
line = t.Steps[len(t.Steps)-1].Location.Line
|
line = t.Location.Line
|
||||||
finished = line == res.step.Location.Line
|
finished = t.Steps[len(t.Steps)-1].Location.Line == res.step.Location.Line
|
||||||
}
|
}
|
||||||
|
|
||||||
if finished {
|
if finished {
|
||||||
|
@ -213,7 +214,7 @@ func (f *events) step(res *stepResult) {
|
||||||
func (f *events) Defined(step *gherkin.Step, def *StepDef) {
|
func (f *events) Defined(step *gherkin.Step, def *StepDef) {
|
||||||
if def != nil {
|
if def != nil {
|
||||||
m := def.Expr.FindStringSubmatchIndex(step.Text)[2:]
|
m := def.Expr.FindStringSubmatchIndex(step.Text)[2:]
|
||||||
args := make([][2]int, 0)
|
var args [][2]int
|
||||||
for i := 0; i < len(m)/2; i++ {
|
for i := 0; i < len(m)/2; i++ {
|
||||||
pair := m[i : i*2+2]
|
pair := m[i : i*2+2]
|
||||||
var idxs [2]int
|
var idxs [2]int
|
||||||
|
@ -222,6 +223,10 @@ func (f *events) Defined(step *gherkin.Step, def *StepDef) {
|
||||||
args = append(args, idxs)
|
args = append(args, idxs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(args) == 0 {
|
||||||
|
args = make([][2]int, 0)
|
||||||
|
}
|
||||||
|
|
||||||
f.event(&struct {
|
f.event(&struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
RunID string `json:"run_id"`
|
RunID string `json:"run_id"`
|
||||||
|
|
16
fmt_junit.go
16
fmt_junit.go
|
@ -11,17 +11,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("junit", "Prints junit compatible xml to stdout", &junitFormatter{
|
Format("junit", "Prints junit compatible xml to stdout", junitFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func junitFunc(out io.Writer) Formatter {
|
||||||
|
return &junitFormatter{
|
||||||
suite: &junitPackageSuite{
|
suite: &junitPackageSuite{
|
||||||
Name: "main", // @TODO: it should extract package name
|
Name: "main", // @TODO: it should extract package name
|
||||||
TestSuites: make([]*junitTestSuite, 0),
|
TestSuites: make([]*junitTestSuite, 0),
|
||||||
},
|
},
|
||||||
|
out: out,
|
||||||
started: time.Now(),
|
started: time.Now(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type junitFormatter struct {
|
type junitFormatter struct {
|
||||||
suite *junitPackageSuite
|
suite *junitPackageSuite
|
||||||
|
out io.Writer
|
||||||
|
|
||||||
// timing
|
// timing
|
||||||
started time.Time
|
started time.Time
|
||||||
|
@ -45,7 +51,7 @@ func (j *junitFormatter) Feature(feature *gherkin.Feature, path string, c []byte
|
||||||
j.suite.TestSuites = append(j.suite.TestSuites, testSuite)
|
j.suite.TestSuites = append(j.suite.TestSuites, testSuite)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *junitFormatter) Defined(*gherkin.Step, *StepDef) {
|
func (j *junitFormatter) Defined(*gherkin.Step, *StepDef) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,12 +135,12 @@ func (j *junitFormatter) Pending(step *gherkin.Step, match *StepDef) {
|
||||||
|
|
||||||
func (j *junitFormatter) Summary() {
|
func (j *junitFormatter) Summary() {
|
||||||
j.suite.Time = time.Since(j.started).String()
|
j.suite.Time = time.Since(j.started).String()
|
||||||
io.WriteString(os.Stdout, xml.Header)
|
io.WriteString(j.out, xml.Header)
|
||||||
|
|
||||||
enc := xml.NewEncoder(os.Stdout)
|
enc := xml.NewEncoder(os.Stdout)
|
||||||
enc.Indent("", s(2))
|
enc.Indent("", s(2))
|
||||||
if err := enc.Encode(j.suite); err != nil {
|
if err := enc.Encode(j.suite); err != nil {
|
||||||
fmt.Println("failed to write junit xml:", err)
|
fmt.Fprintln(os.Stderr, "failed to write junit xml:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -12,12 +13,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("pretty", "Prints every feature with runtime statuses.", &pretty{
|
Format("pretty", "Prints every feature with runtime statuses.", prettyFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prettyFunc(out io.Writer) Formatter {
|
||||||
|
return &pretty{
|
||||||
basefmt: basefmt{
|
basefmt: basefmt{
|
||||||
started: time.Now(),
|
started: time.Now(),
|
||||||
indent: 2,
|
indent: 2,
|
||||||
|
out: out,
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>")
|
var outlinePlaceholderRegexp = regexp.MustCompile("<[^>]+>")
|
||||||
|
@ -48,13 +54,13 @@ type pretty struct {
|
||||||
func (f *pretty) Feature(ft *gherkin.Feature, p string, c []byte) {
|
func (f *pretty) Feature(ft *gherkin.Feature, p string, c []byte) {
|
||||||
if len(f.features) != 0 {
|
if len(f.features) != 0 {
|
||||||
// not a first feature, add a newline
|
// not a first feature, add a newline
|
||||||
fmt.Println("")
|
fmt.Fprintln(f.out, "")
|
||||||
}
|
}
|
||||||
f.features = append(f.features, &feature{Path: p, Feature: ft})
|
f.features = append(f.features, &feature{Path: p, Feature: ft})
|
||||||
fmt.Println(bcl(ft.Keyword+": ", white) + ft.Name)
|
fmt.Fprintln(f.out, bcl(ft.Keyword+": ", white)+ft.Name)
|
||||||
if strings.TrimSpace(ft.Description) != "" {
|
if strings.TrimSpace(ft.Description) != "" {
|
||||||
for _, line := range strings.Split(ft.Description, "\n") {
|
for _, line := range strings.Split(ft.Description, "\n") {
|
||||||
fmt.Println(s(f.indent) + strings.TrimSpace(line))
|
fmt.Fprintln(f.out, s(f.indent)+strings.TrimSpace(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +110,7 @@ func (f *pretty) Summary() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(failedScenarios) > 0 {
|
if len(failedScenarios) > 0 {
|
||||||
fmt.Println("\n--- " + cl("Failed scenarios:", red) + "\n")
|
fmt.Fprintln(f.out, "\n--- "+cl("Failed scenarios:", red)+"\n")
|
||||||
var unique []string
|
var unique []string
|
||||||
for _, fail := range failedScenarios {
|
for _, fail := range failedScenarios {
|
||||||
var found bool
|
var found bool
|
||||||
|
@ -120,7 +126,7 @@ func (f *pretty) Summary() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fail := range unique {
|
for _, fail := range unique {
|
||||||
fmt.Println(" " + cl(fail, red))
|
fmt.Fprintln(f.out, " "+cl(fail, red))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.basefmt.Summary()
|
f.basefmt.Summary()
|
||||||
|
@ -173,7 +179,7 @@ func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
||||||
text = cl(ostep.Text, cyan)
|
text = cl(ostep.Text, cyan)
|
||||||
}
|
}
|
||||||
// print the step outline
|
// print the step outline
|
||||||
fmt.Println(s(f.indent*2) + cl(strings.TrimSpace(ostep.Keyword), cyan) + " " + text)
|
fmt.Fprintln(f.out, s(f.indent*2)+cl(strings.TrimSpace(ostep.Keyword), cyan)+" "+text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,13 +187,13 @@ func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
||||||
max := longest(example)
|
max := longest(example)
|
||||||
// an example table header
|
// an example table header
|
||||||
if firstExample {
|
if firstExample {
|
||||||
fmt.Println("")
|
fmt.Fprintln(f.out, "")
|
||||||
fmt.Println(s(f.indent*2) + bcl(example.Keyword+": ", white) + example.Name)
|
fmt.Fprintln(f.out, s(f.indent*2)+bcl(example.Keyword+": ", white)+example.Name)
|
||||||
|
|
||||||
for i, cell := range example.TableHeader.Cells {
|
for i, cell := range example.TableHeader.Cells {
|
||||||
cells[i] = cl(cell.Value, cyan) + s(max[i]-len(cell.Value))
|
cells[i] = cl(cell.Value, cyan) + s(max[i]-len(cell.Value))
|
||||||
}
|
}
|
||||||
fmt.Println(s(f.indent*3) + "| " + strings.Join(cells, " | ") + " |")
|
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cells, " | ")+" |")
|
||||||
}
|
}
|
||||||
|
|
||||||
// an example table row
|
// an example table row
|
||||||
|
@ -195,11 +201,11 @@ func (f *pretty) printOutlineExample(outline *gherkin.ScenarioOutline) {
|
||||||
for i, cell := range row.Cells {
|
for i, cell := range row.Cells {
|
||||||
cells[i] = cl(cell.Value, clr) + s(max[i]-len(cell.Value))
|
cells[i] = cl(cell.Value, clr) + s(max[i]-len(cell.Value))
|
||||||
}
|
}
|
||||||
fmt.Println(s(f.indent*3) + "| " + strings.Join(cells, " | ") + " |")
|
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cells, " | ")+" |")
|
||||||
|
|
||||||
// if there is an error
|
// if there is an error
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
fmt.Println(s(f.indent*4) + bcl(msg, red))
|
fmt.Fprintln(f.out, s(f.indent*4)+bcl(msg, red))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +232,7 @@ func (f *pretty) printStep(step *gherkin.Step, def *StepDef, c color) {
|
||||||
text += cl(step.Text, c)
|
text += cl(step.Text, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(text)
|
fmt.Fprintln(f.out, text)
|
||||||
switch t := step.Argument.(type) {
|
switch t := step.Argument.(type) {
|
||||||
case *gherkin.DataTable:
|
case *gherkin.DataTable:
|
||||||
f.printTable(t, c)
|
f.printTable(t, c)
|
||||||
|
@ -235,11 +241,11 @@ func (f *pretty) printStep(step *gherkin.Step, def *StepDef, c color) {
|
||||||
if len(t.ContentType) > 0 {
|
if len(t.ContentType) > 0 {
|
||||||
ct = " " + cl(t.ContentType, c)
|
ct = " " + cl(t.ContentType, c)
|
||||||
}
|
}
|
||||||
fmt.Println(s(f.indent*3) + cl(t.Delimitter, c) + ct)
|
fmt.Fprintln(f.out, s(f.indent*3)+cl(t.Delimitter, c)+ct)
|
||||||
for _, ln := range strings.Split(t.Content, "\n") {
|
for _, ln := range strings.Split(t.Content, "\n") {
|
||||||
fmt.Println(s(f.indent*3) + cl(ln, c))
|
fmt.Fprintln(f.out, s(f.indent*3)+cl(ln, c))
|
||||||
}
|
}
|
||||||
fmt.Println(s(f.indent*3) + cl(t.Delimitter, c))
|
fmt.Fprintln(f.out, s(f.indent*3)+cl(t.Delimitter, c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +255,7 @@ func (f *pretty) printStepKind(res *stepResult) {
|
||||||
// first background step
|
// first background step
|
||||||
case f.bgSteps > 0 && f.bgSteps == len(f.feature.Background.Steps):
|
case f.bgSteps > 0 && f.bgSteps == len(f.feature.Background.Steps):
|
||||||
f.commentPos = f.longestStep(f.feature.Background.Steps, f.length(f.feature.Background))
|
f.commentPos = f.longestStep(f.feature.Background.Steps, f.length(f.feature.Background))
|
||||||
fmt.Println("\n" + s(f.indent) + bcl(f.feature.Background.Keyword+": "+f.feature.Background.Name, white))
|
fmt.Fprintln(f.out, "\n"+s(f.indent)+bcl(f.feature.Background.Keyword+": "+f.feature.Background.Name, white))
|
||||||
f.bgSteps--
|
f.bgSteps--
|
||||||
// subsequent background steps
|
// subsequent background steps
|
||||||
case f.bgSteps > 0:
|
case f.bgSteps > 0:
|
||||||
|
@ -266,7 +272,7 @@ func (f *pretty) printStepKind(res *stepResult) {
|
||||||
}
|
}
|
||||||
text := s(f.indent) + bcl(f.scenario.Keyword+": ", white) + f.scenario.Name
|
text := s(f.indent) + bcl(f.scenario.Keyword+": ", white) + f.scenario.Name
|
||||||
text += s(f.commentPos-f.length(f.scenario)+1) + f.line(f.scenario.Location)
|
text += s(f.commentPos-f.length(f.scenario)+1) + f.line(f.scenario.Location)
|
||||||
fmt.Println("\n" + text)
|
fmt.Fprintln(f.out, "\n"+text)
|
||||||
f.scenarioKeyword = true
|
f.scenarioKeyword = true
|
||||||
}
|
}
|
||||||
f.steps--
|
f.steps--
|
||||||
|
@ -285,7 +291,7 @@ func (f *pretty) printStepKind(res *stepResult) {
|
||||||
}
|
}
|
||||||
text := s(f.indent) + bcl(f.outline.Keyword+": ", white) + f.outline.Name
|
text := s(f.indent) + bcl(f.outline.Keyword+": ", white) + f.outline.Name
|
||||||
text += s(f.commentPos-f.length(f.outline)+1) + f.line(f.outline.Location)
|
text += s(f.commentPos-f.length(f.outline)+1) + f.line(f.outline.Location)
|
||||||
fmt.Println("\n" + text)
|
fmt.Fprintln(f.out, "\n"+text)
|
||||||
f.scenarioKeyword = true
|
f.scenarioKeyword = true
|
||||||
}
|
}
|
||||||
if len(f.outlineSteps) == len(f.outline.Steps)+f.bgSteps {
|
if len(f.outlineSteps) == len(f.outline.Steps)+f.bgSteps {
|
||||||
|
@ -298,10 +304,10 @@ func (f *pretty) printStepKind(res *stepResult) {
|
||||||
|
|
||||||
f.printStep(res.step, res.def, res.typ.clr())
|
f.printStep(res.step, res.def, res.typ.clr())
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
fmt.Println(s(f.indent*2) + bcl(res.err, red))
|
fmt.Fprintln(f.out, s(f.indent*2)+bcl(res.err, red))
|
||||||
}
|
}
|
||||||
if res.typ == pending {
|
if res.typ == pending {
|
||||||
fmt.Println(s(f.indent*3) + cl("TODO: write pending definition", yellow))
|
fmt.Fprintln(f.out, s(f.indent*3)+cl("TODO: write pending definition", yellow))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +319,7 @@ func (f *pretty) printTable(t *gherkin.DataTable, c color) {
|
||||||
for i, cell := range row.Cells {
|
for i, cell := range row.Cells {
|
||||||
cols[i] = cell.Value + s(l[i]-len(cell.Value))
|
cols[i] = cell.Value + s(l[i]-len(cell.Value))
|
||||||
}
|
}
|
||||||
fmt.Println(s(f.indent*3) + cl("| "+strings.Join(cols, " | ")+" |", c))
|
fmt.Fprintln(f.out, s(f.indent*3)+cl("| "+strings.Join(cols, " | ")+" |", c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,13 +11,18 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Format("progress", "Prints a character per step.", &progress{
|
Format("progress", "Prints a character per step.", progressFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func progressFunc(out io.Writer) Formatter {
|
||||||
|
return &progress{
|
||||||
basefmt: basefmt{
|
basefmt: basefmt{
|
||||||
started: time.Now(),
|
started: time.Now(),
|
||||||
indent: 2,
|
indent: 2,
|
||||||
|
out: out,
|
||||||
},
|
},
|
||||||
stepsPerRow: 70,
|
stepsPerRow: 70,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type progress struct {
|
type progress struct {
|
||||||
|
@ -47,13 +53,13 @@ func (f *progress) Summary() {
|
||||||
fmt.Printf(" %d\n", f.steps)
|
fmt.Printf(" %d\n", f.steps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("")
|
fmt.Fprintln(f.out, "")
|
||||||
|
|
||||||
if len(f.failed) > 0 {
|
if len(f.failed) > 0 {
|
||||||
fmt.Println("\n--- " + cl("Failed steps:", red) + "\n")
|
fmt.Fprintln(f.out, "\n--- "+cl("Failed steps:", red)+"\n")
|
||||||
for _, fail := range f.failed {
|
for _, fail := range f.failed {
|
||||||
fmt.Println(s(4) + cl(fail.step.Keyword+" "+fail.step.Text, red) + cl(" # "+fail.line(), black))
|
fmt.Fprintln(f.out, s(4)+cl(fail.step.Keyword+" "+fail.step.Text, red)+cl(" # "+fail.line(), black))
|
||||||
fmt.Println(s(6) + cl("Error: ", red) + bcl(fail.err, red) + "\n")
|
fmt.Fprintln(f.out, s(6)+cl("Error: ", red)+bcl(fail.err, red)+"\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.basefmt.Summary()
|
f.basefmt.Summary()
|
||||||
|
@ -74,7 +80,7 @@ func (f *progress) step(res *stepResult) {
|
||||||
}
|
}
|
||||||
f.steps++
|
f.steps++
|
||||||
if math.Mod(float64(f.steps), float64(f.stepsPerRow)) == 0 {
|
if math.Mod(float64(f.steps), float64(f.stepsPerRow)) == 0 {
|
||||||
fmt.Printf(" %d\n", f.steps)
|
fmt.Fprintf(f.out, " %d\n", f.steps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
run.go
2
run.go
|
@ -93,7 +93,7 @@ func RunWithOptions(contextInitializer func(suite *Suite), opt Options) int {
|
||||||
fatal(err)
|
fatal(err)
|
||||||
|
|
||||||
r := runner{
|
r := runner{
|
||||||
fmt: formatter,
|
fmt: formatter(os.Stdout),
|
||||||
initializer: contextInitializer,
|
initializer: contextInitializer,
|
||||||
features: features,
|
features: features,
|
||||||
stopOnFailure: opt.StopOnFailure,
|
stopOnFailure: opt.StopOnFailure,
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче