<fix>(PRETIFIER): Fix s method to not have errors on negative entry
Context: While trying to create an helper library to manage http rest api testing, I made a system witch allow to pick value from responses, header, cookie, ... and inject then as variables. Issue: Doing this, when the inject variable make the line longer than the longest declared step, godog will failed to render test result under pretty formatting cause it will try to write a comment on a negative index Fix: Fix s methods so it will not goes to fatal when recieving negative number.
Этот коммит содержится в:
родитель
2e1454719a
коммит
eb75d692bd
10 изменённых файлов: 5771 добавлений и 5610 удалений
1
.gitignore
предоставленный
1
.gitignore
предоставленный
|
@ -5,3 +5,4 @@ Gopkg.lock
|
|||
Gopkg.toml
|
||||
|
||||
.DS_Store
|
||||
.idea
|
|
@ -45,6 +45,7 @@ Feature: pretty formatter
|
|||
No steps
|
||||
0s
|
||||
"""
|
||||
|
||||
Scenario: Support of Feature Plus Scenario Outline
|
||||
Given a feature "features/simple.feature" file:
|
||||
"""
|
||||
|
@ -111,6 +112,7 @@ Feature: pretty formatter
|
|||
No steps
|
||||
0s
|
||||
"""
|
||||
|
||||
Scenario: Support of Feature Plus Scenario With Steps
|
||||
Given a feature "features/simple.feature" file:
|
||||
"""
|
||||
|
@ -146,6 +148,7 @@ Feature: pretty formatter
|
|||
2 steps (1 passed, 1 failed)
|
||||
0s
|
||||
"""
|
||||
|
||||
Scenario: Support of Feature Plus Scenario Outline With Steps
|
||||
Given a feature "features/simple.feature" file:
|
||||
"""
|
||||
|
@ -214,6 +217,7 @@ Feature: pretty formatter
|
|||
No steps
|
||||
0s
|
||||
"""
|
||||
|
||||
Scenario: Support of Docstrings
|
||||
Given a feature "features/simple.feature" file:
|
||||
"""
|
||||
|
@ -244,6 +248,7 @@ Feature: pretty formatter
|
|||
1 steps (1 passed)
|
||||
0s
|
||||
"""
|
||||
|
||||
Scenario: Support of Undefined, Pending and Skipped status
|
||||
Given a feature "features/simple.feature" file:
|
||||
"""
|
||||
|
@ -286,3 +291,30 @@ Feature: pretty formatter
|
|||
s.Step(`^undefined$`, undefined)
|
||||
}
|
||||
"""
|
||||
|
||||
# Ensure s will not break when injecting data from BeforeStep
|
||||
Scenario: Support data injection in BeforeStep
|
||||
Given a feature "features/inject.feature" file:
|
||||
"""
|
||||
Feature: inject long value
|
||||
|
||||
Scenario: test scenario
|
||||
Given Ignore I save some value X under key Y
|
||||
When Ignore I use value {{Y}}
|
||||
Then Ignore Godog rendering should not break
|
||||
"""
|
||||
And I allow variable injection
|
||||
When I run feature suite with formatter "pretty"
|
||||
Then the rendered output will be as follows:
|
||||
"""
|
||||
Feature: inject long value
|
||||
|
||||
Scenario: test scenario # features/inject.feature:3
|
||||
Given Ignore I save some value X under key Y # suite_context.go:0 -> SuiteContext.func7
|
||||
When Ignore I use value someverylonginjectionsoweacanbesureitsurpasstheinitiallongeststeplenghtanditwillhelptestsmethodsafety # suite_context.go:0 -> SuiteContext.func7
|
||||
Then Ignore Godog rendering should not break # suite_context.go:0 -> SuiteContext.func7
|
||||
|
||||
1 scenarios (1 passed)
|
||||
3 steps (3 passed)
|
||||
0s
|
||||
"""
|
Различия файлов не показаны, т.к. их слишком много
Показать различия
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites name="succeed" tests="78" skipped="0" failures="0" errors="0" time="0">
|
||||
<testsuites name="succeed" tests="79" skipped="0" failures="0" errors="0" time="0">
|
||||
<testsuite name="JUnit XML formatter" tests="9" skipped="0" failures="0" errors="0" time="0">
|
||||
<testcase name="Support of Feature Plus Scenario Node" status="passed" time="0"></testcase>
|
||||
<testcase name="Support of Feature Plus Scenario Node With Tags" status="passed" time="0"></testcase>
|
||||
|
@ -35,7 +35,7 @@
|
|||
<testcase name="loaded feature should have a number of scenarios #3" status="passed" time="0"></testcase>
|
||||
<testcase name="load a number of feature files" status="passed" time="0"></testcase>
|
||||
</testsuite>
|
||||
<testsuite name="pretty formatter" tests="9" skipped="0" failures="0" errors="0" time="0">
|
||||
<testsuite name="pretty formatter" tests="10" skipped="0" failures="0" errors="0" time="0">
|
||||
<testcase name="Support of Feature Plus Scenario Node" status="passed" time="0"></testcase>
|
||||
<testcase name="Support of Feature Plus Scenario Node With Tags" status="passed" time="0"></testcase>
|
||||
<testcase name="Support of Feature Plus Scenario Outline" status="passed" time="0"></testcase>
|
||||
|
@ -45,6 +45,7 @@
|
|||
<testcase name="Support of Comments" status="passed" time="0"></testcase>
|
||||
<testcase name="Support of Docstrings" status="passed" time="0"></testcase>
|
||||
<testcase name="Support of Undefined, Pending and Skipped status" status="passed" time="0"></testcase>
|
||||
<testcase name="Support data injection in BeforeStep" status="passed" time="0"></testcase>
|
||||
</testsuite>
|
||||
<testsuite name="run background" tests="3" skipped="0" failures="0" errors="0" time="0">
|
||||
<testcase name="should run background steps" status="passed" time="0"></testcase>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
...................................................................... 140
|
||||
...................................................................... 210
|
||||
...................................................................... 280
|
||||
....................... 303
|
||||
........................... 307
|
||||
|
||||
|
||||
78 scenarios (78 passed)
|
||||
303 steps (303 passed)
|
||||
79 scenarios (79 passed)
|
||||
307 steps (307 passed)
|
||||
0s
|
|
@ -124,12 +124,13 @@ func (f *pretty) printUndefinedScenario(sc interface{}) {
|
|||
case *gherkin.Scenario:
|
||||
f.commentPos = f.longestStep(t.Steps, f.length(sc))
|
||||
text := s(f.indent) + keywordAndName(t.Keyword, t.Name)
|
||||
text += s(f.commentPos-f.length(t)+1) + f.line(t.Location)
|
||||
text += s(f.commentPos-f.length(t)) + f.line(t.Location)
|
||||
fmt.Fprintln(f.out, "\n"+text)
|
||||
case *gherkin.ScenarioOutline:
|
||||
f.commentPos = f.longestStep(t.Steps, f.length(sc))
|
||||
text := s(f.indent) + keywordAndName(t.Keyword, t.Name)
|
||||
text += s(f.commentPos-f.length(t)+1) + f.line(t.Location)
|
||||
text += s(f.commentPos-f.length(t)) + f.line(t.Location)
|
||||
|
||||
fmt.Fprintln(f.out, "\n"+text)
|
||||
|
||||
for _, example := range t.Examples {
|
||||
|
@ -248,9 +249,9 @@ func (f *pretty) printExampleRow(row *gherkin.TableRow, max []int, clr colors.Co
|
|||
for i, cell := range row.Cells {
|
||||
val := clr(cell.Value)
|
||||
ln := utf8.RuneCountInString(val)
|
||||
cells[i] = val + s(max[i]-ln)
|
||||
cells[i] = val + s(max[i]-ln+1)
|
||||
}
|
||||
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cells, " | ")+" |")
|
||||
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cells, "| ")+"|")
|
||||
}
|
||||
|
||||
func (f *pretty) printExampleHeader(example *gherkin.Examples, max []int) {
|
||||
|
@ -262,9 +263,9 @@ func (f *pretty) printExampleHeader(example *gherkin.Examples, max []int) {
|
|||
for i, cell := range example.TableHeader.Cells {
|
||||
val := cyan(cell.Value)
|
||||
ln := utf8.RuneCountInString(val)
|
||||
cells[i] = val + s(max[i]-ln)
|
||||
cells[i] = val + s(max[i]-ln+1)
|
||||
}
|
||||
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cells, " | ")+" |")
|
||||
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cells, "| ")+"|")
|
||||
}
|
||||
|
||||
func (f *pretty) printStep(step *gherkin.Step, def *StepDef, c colors.ColorFunc) {
|
||||
|
@ -289,6 +290,7 @@ func (f *pretty) printStep(step *gherkin.Step, def *StepDef, c colors.ColorFunc)
|
|||
text += c(step.Text)
|
||||
}
|
||||
text += s(f.commentPos-f.length(step)+1) + blackb(fmt.Sprintf("# %s", def.definitionID()))
|
||||
|
||||
default:
|
||||
text += c(step.Text)
|
||||
}
|
||||
|
@ -342,6 +344,7 @@ func (f *pretty) printStepKind(res *stepResult) {
|
|||
}
|
||||
text := s(f.indent) + keywordAndName(f.scenario.Keyword, f.scenario.Name)
|
||||
text += s(f.commentPos-f.length(f.scenario)+1) + f.line(f.scenario.Location)
|
||||
|
||||
fmt.Fprintln(f.out, "\n"+text)
|
||||
f.scenarioKeyword = true
|
||||
}
|
||||
|
@ -357,6 +360,7 @@ func (f *pretty) printStepKind(res *stepResult) {
|
|||
}
|
||||
text := s(f.indent) + keywordAndName(f.outline.Keyword, f.outline.Name)
|
||||
text += s(f.commentPos-f.length(f.outline)+1) + f.line(f.outline.Location)
|
||||
|
||||
fmt.Fprintln(f.out, "\n"+text)
|
||||
f.scenarioKeyword = true
|
||||
}
|
||||
|
@ -400,9 +404,9 @@ func (f *pretty) printTable(t *gherkin.DataTable, c colors.ColorFunc) {
|
|||
for i, cell := range row.Cells {
|
||||
val := c(cell.Value)
|
||||
ln := utf8.RuneCountInString(val)
|
||||
cols[i] = val + s(l[i]-ln)
|
||||
cols[i] = val + s(l[i]-ln+1)
|
||||
}
|
||||
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cols, " | ")+" |")
|
||||
fmt.Fprintln(f.out, s(f.indent*3)+"| "+strings.Join(cols, "| ")+"|")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
4
go.mod
4
go.mod
|
@ -3,7 +3,7 @@ module github.com/cucumber/godog
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/DATA-DOG/go-txdb v0.1.3
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/DATA-DOG/go-txdb v0.1.3 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
)
|
||||
|
|
|
@ -251,14 +251,14 @@ func TestSucceedRun(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
expectedOutput, err := ioutil.ReadFile(tc.filename)
|
||||
expectedOutputNoConcurrency, err := ioutil.ReadFile(tc.filename)
|
||||
require.NoError(t, err)
|
||||
|
||||
for concurrency := range make([]int, tc.concurrency) {
|
||||
t.Run(
|
||||
fmt.Sprintf("%s/concurrency/%d", tc.format, concurrency),
|
||||
func(t *testing.T) {
|
||||
testSucceedRun(t, tc.format, concurrency, string(expectedOutput))
|
||||
testSucceedRun(t, tc.format, concurrency, string(expectedOutputNoConcurrency))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ import (
|
|||
"github.com/cucumber/godog/gherkin"
|
||||
)
|
||||
|
||||
var (
|
||||
allowInjection = true
|
||||
)
|
||||
|
||||
// SuiteContext provides steps for godog suite execution and
|
||||
// can be used for meta-testing of godog features/steps themselves.
|
||||
//
|
||||
|
@ -43,6 +47,7 @@ func SuiteContext(s *Suite, additionalContextInitializers ...func(suite *Suite))
|
|||
s.Step(`^I run feature suite$`, c.iRunFeatureSuite)
|
||||
s.Step(`^I run feature suite with tags "([^"]*)"$`, c.iRunFeatureSuiteWithTags)
|
||||
s.Step(`^I run feature suite with formatter "([^"]*)"$`, c.iRunFeatureSuiteWithFormatter)
|
||||
s.Step(`^(?:I )(allow|disable) variable injection`, c.iSetVariableInjectionTo)
|
||||
s.Step(`^(?:a )?feature "([^"]*)"(?: file)?:$`, c.aFeatureFile)
|
||||
s.Step(`^the suite should have (passed|failed)$`, c.theSuiteShouldHave)
|
||||
|
||||
|
@ -97,6 +102,44 @@ func SuiteContext(s *Suite, additionalContextInitializers ...func(suite *Suite))
|
|||
s.Step(`^(?:a )?failing nested multistep$`, func() Steps {
|
||||
return Steps{"passing step", "passing multistep", "failing multistep"}
|
||||
})
|
||||
// Default recovery step
|
||||
s.Step(`Ignore.*`, func() error {
|
||||
return nil
|
||||
})
|
||||
|
||||
s.BeforeStep(func(step *gherkin.Step) {
|
||||
if !allowInjection {
|
||||
return
|
||||
}
|
||||
step.Text = injectAll(step.Text)
|
||||
args := step.Argument
|
||||
if args != nil {
|
||||
switch arg := args.(type) {
|
||||
case *gherkin.DataTable:
|
||||
for i := 0; i < len(arg.Rows); i++ {
|
||||
for n, cell := range arg.Rows[i].Cells {
|
||||
arg.Rows[i].Cells[n].Value = injectAll(cell.Value)
|
||||
}
|
||||
}
|
||||
case *gherkin.DocString:
|
||||
arg.Content = injectAll(arg.Content)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func injectAll(inTo string) string {
|
||||
re := regexp.MustCompile(`{{[^{}]+}}`)
|
||||
return re.ReplaceAllStringFunc(
|
||||
inTo,
|
||||
func(key string) string {
|
||||
injectRegex := regexp.MustCompile(`^{{.+}}$`)
|
||||
if injectRegex.MatchString(key) {
|
||||
return "someverylonginjectionsoweacanbesureitsurpasstheinitiallongeststeplenghtanditwillhelptestsmethodsafety"
|
||||
}
|
||||
return key
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type firedEvent struct {
|
||||
|
@ -123,6 +166,11 @@ func (s *suiteContext) ResetBeforeEachScenario(interface{}) {
|
|||
s.events = []*firedEvent{}
|
||||
}
|
||||
|
||||
func (s *suiteContext) iSetVariableInjectionTo(to string) error {
|
||||
allowInjection = to == "allow"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *suiteContext) iRunFeatureSuiteWithTags(tags string) error {
|
||||
if err := s.parseFeatures(); err != nil {
|
||||
return err
|
||||
|
|
3
utils.go
3
utils.go
|
@ -20,6 +20,9 @@ var (
|
|||
|
||||
// repeats a space n times
|
||||
func s(n int) string {
|
||||
if n <= 0 {
|
||||
n = 1
|
||||
}
|
||||
return strings.Repeat(" ", n)
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче