From 9820f49ceb004a2beca1ef7d4ff2442055102b78 Mon Sep 17 00:00:00 2001 From: "Stettler, Robert" Date: Fri, 17 Feb 2017 12:36:07 -0500 Subject: [PATCH] Added examples logic. --- fmt_cucumber.go | 181 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 121 insertions(+), 60 deletions(-) diff --git a/fmt_cucumber.go b/fmt_cucumber.go index 47d077a..7069a0a 100644 --- a/fmt_cucumber.go +++ b/fmt_cucumber.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/DATA-DOG/godog/gherkin" "encoding/json" + "strconv" ) const cukeurl = "https://www.relishapp.com/cucumber/cucumber/docs/formatters/json-output-formatter" @@ -29,7 +30,7 @@ func cucumberFunc(suite string, out io.Writer) Formatter { // Replace spaces with - func makeId(name string) string { - return strings.Replace(strings.ToLower(name)," ","-",-1) + return strings.Replace(strings.ToLower(name), " ", "-", -1) } type cukeTag struct { @@ -38,104 +39,159 @@ type cukeTag struct { } type cukeResult struct { - Status string `json:"status"` + Status string `json:"status"` Duration int `json:"duration"` - Error string `json:"error_message,omitempty"` + Error string `json:"error_message,omitempty"` } type cukeMatch struct { Location string `json:"location"` } -type cukeStep struct { - Keyword string `json:"keyword"` - Name string `json:"name"` - Line int `json:"line"` - Match cukeMatch `json:"match"` - Result cukeResult `json:"result"` +type cukeExample struct { + Keyword string `json:"keyword"` + Id string `json:"id"` + Name string `json:"name"` + Line int `json:"line"` + Description string `json:"description"` + Rows []cukeRow `json:"rows"` } +type cukeRow struct { + Cells []string `json:"cells"` + Id string `json:"id"` + Line int `json:"line"` +} + +type cukeStep struct { + Keyword string `json:"keyword"` + Name string `json:"name"` + Line int `json:"line"` + Match cukeMatch `json:"match"` + Result cukeResult `json:"result"` +} type cukeElement struct { - Keyword string `json:"keyword"` - Id string `json:"id"` - Name string `json:"name"` - Line int `json:"line"` + Keyword string `json:"keyword"` + Id string `json:"id"` + Name string `json:"name"` + Line int `json:"line"` Description string `json:"description"` - Tags []cukeTag `json:"tags"` - Type string `json:type` - Steps []cukeStep `json:steps` - + Tags []cukeTag `json:"tags"` + Type string `json:type` + Steps []cukeStep `json:steps` + Examples []cukeExample `json:examples,omitempty` } type cukeFeatureJson struct { - Uri string `json:"uri"` - Id string `json:"id"` - Keyword string `json:"keyword"` - Name string `json:"name"` - Line int `json:"line"` + Uri string `json:"uri"` + Id string `json:"id"` + Keyword string `json:"keyword"` + Name string `json:"name"` + Line int `json:"line"` Description string `json:"description"` - Tags []cukeTag `json:"tags"` - Elements []cukeElement `json:"elements"` - + Tags []cukeTag `json:"tags"` + Elements []cukeElement `json:"elements"` } type cukefmt struct { basefmt - // currently running feature path, to be part of id. - // this is sadly not passed by gherkin nodes. - // it restricts this formatter to run only in synchronous single - // threaded execution. Unless running a copy of formatter for each feature + // currently running feature path, to be part of id. + // this is sadly not passed by gherkin nodes. + // it restricts this formatter to run only in synchronous single + // threaded execution. Unless running a copy of formatter for each feature path string - stat stepType // last step status, before skipped - outlineSteps int // number of current outline scenario steps - id string // current test id. + stat stepType // last step status, before skipped + outlineSteps int // number of current outline scenario steps + id string // current test id. results []cukeFeatureJson // structure that represent cuke results - curStep *cukeStep // track the current step - curElement *cukeElement // track the current element - curFeature *cukeFeatureJson // track the current feature - + curStep *cukeStep // track the current step + curElement *cukeElement // track the current element + curFeature *cukeFeatureJson // track the current feature } - func (f *cukefmt) Node(n interface{}) { f.basefmt.Node(n) switch t := n.(type) { + case *gherkin.Examples: + ex := cukeExample{} + ex.Description = t.Description + ex.Id = f.curElement.Id + ";" + makeId(t.Name) + ex.Line = t.Location.Line + ex.Name = t.Name + ex.Keyword = t.Keyword + ex.Rows = make([]cukeRow,len(t.TableBody)+1) + + // first row is the header + ex.Rows[0].Line = t.TableHeader.Location.Line + ex.Rows[0].Cells = make([]string,len(t.TableHeader.Cells)) + ex.Rows[0].Id = ex.Id + ";1" + for idx, val := range t.TableHeader.Cells { + ex.Rows[0].Cells[idx] = val.Value + } + + // The other example are in the body + for i, row := range t.TableBody { + ex.Rows[1+i].Line = row.Location.Line + ex.Rows[1+i].Cells = make([]string,len(row.Cells)) + ex.Rows[1+i].Id = ex.Id + ";"+strconv.Itoa(i+2) + for idx, val := range row.Cells { + ex.Rows[1+i].Cells[idx] = val.Value + } + } + + f.curElement.Examples = append(f.curElement.Examples,ex) + case *gherkin.ScenarioOutline: - case *gherkin.Scenario: - f.curFeature.Elements = append(f.curFeature.Elements,cukeElement{}) - f.curElement = &f.curFeature.Elements[len(f.curFeature.Elements)-1] + f.curFeature.Elements = append(f.curFeature.Elements, cukeElement{}) + f.curElement = &f.curFeature.Elements[len(f.curFeature.Elements) - 1] f.curElement.Name = t.Name f.curElement.Line = t.Location.Line f.curElement.Description = t.Description f.curElement.Keyword = t.Keyword - f.curElement.Id = f.curFeature.Id+";"+makeId(t.Name) + f.curElement.Id = f.curFeature.Id + ";" + makeId(t.Name) f.curElement.Type = t.Type - f.curElement.Tags = make([]cukeTag,len(t.Tags)) - for idx,element := range t.Tags { + f.curElement.Tags = make([]cukeTag, len(t.Tags)) + for idx, element := range t.Tags { + f.curElement.Tags[idx].Line = element.Location.Line + f.curElement.Tags[idx].Name = element.Name + } + + case *gherkin.Scenario: + f.curFeature.Elements = append(f.curFeature.Elements, cukeElement{}) + f.curElement = &f.curFeature.Elements[len(f.curFeature.Elements) - 1] + + f.curElement.Name = t.Name + f.curElement.Line = t.Location.Line + f.curElement.Description = t.Description + f.curElement.Keyword = t.Keyword + f.curElement.Id = f.curFeature.Id + ";" + makeId(t.Name) + f.curElement.Type = t.Type + f.curElement.Tags = make([]cukeTag, len(t.Tags)) + for idx, element := range t.Tags { f.curElement.Tags[idx].Line = element.Location.Line f.curElement.Tags[idx].Name = element.Name } case *gherkin.TableRow: - fmt.Fprintf(f.out,"Entering Node TableRow: %s:%d\n",f.path, t.Location.Line) + + fmt.Fprintf(f.out, "Entering Node TableRow: %s:%d\n", f.path, t.Location.Line) } } func (f *cukefmt) Feature(ft *gherkin.Feature, p string, c []byte) { - f.basefmt.Feature(ft, p, c) f.path = p f.id = makeId(ft.Name) - f.results = append(f.results,cukeFeatureJson{}) + f.results = append(f.results, cukeFeatureJson{}) - f.curFeature = &f.results[len(f.results)-1] + f.curFeature = &f.results[len(f.results) - 1] f.curFeature.Uri = p f.curFeature.Name = ft.Name f.curFeature.Keyword = ft.Keyword @@ -144,7 +200,7 @@ func (f *cukefmt) Feature(ft *gherkin.Feature, p string, c []byte) { f.curFeature.Id = f.id f.curFeature.Tags = make([]cukeTag, len(ft.Tags)) - for idx,element := range ft.Tags { + for idx, element := range ft.Tags { f.curFeature.Tags[idx].Line = element.Location.Line f.curFeature.Tags[idx].Name = element.Name } @@ -156,12 +212,11 @@ func (f *cukefmt) Summary() { if err != nil { panic(err) } - fmt.Fprintf(f.out,"%s\n",string(dat)) + fmt.Fprintf(f.out, "%s\n", string(dat)) } func (f *cukefmt) step(res *stepResult) { - // determine if test case has finished var finished bool var line int @@ -169,7 +224,7 @@ func (f *cukefmt) step(res *stepResult) { case *gherkin.TableRow: line = t.Location.Line finished = f.isLastStep(res.step) - fmt.Fprintf(f.out,"step: TableRow: line:%v finished:%v\n",line, finished) + fmt.Fprintf(f.out, "step: TableRow: line:%v finished:%v\n", line, finished) case *gherkin.Scenario: f.curStep.Result.Status = res.typ.String() if res.err != nil { @@ -179,45 +234,51 @@ func (f *cukefmt) step(res *stepResult) { } func (f *cukefmt) Defined(step *gherkin.Step, def *StepDef) { - fmt.Fprintf(f.out,"Defined: step:%v stepDef:%v\n",step,def) + fmt.Fprintf(f.out, "Defined: step:%v stepDef:%v\n", step, def) - f.curElement.Steps = append(f.curElement.Steps,cukeStep{}) - f.curStep = &f.curElement.Steps[len(f.curElement.Steps)-1] + f.curElement.Steps = append(f.curElement.Steps, cukeStep{}) + f.curStep = &f.curElement.Steps[len(f.curElement.Steps) - 1] + + if def != nil { + if def.args != nil { + fmt.Fprintf(f.out, "Argument: %v\n", def.args) + } + } f.curStep.Name = step.Text f.curStep.Line = step.Location.Line f.curStep.Keyword = step.Keyword if def != nil { - f.curStep.Match.Location = strings.Split(def.definitionID()," ")[0] + f.curStep.Match.Location = strings.Split(def.definitionID(), " ")[0] } } func (f *cukefmt) Passed(step *gherkin.Step, match *StepDef) { f.basefmt.Passed(step, match) f.stat = passed - f.step(f.passed[len(f.passed)-1]) + f.step(f.passed[len(f.passed) - 1]) } func (f *cukefmt) Skipped(step *gherkin.Step) { f.basefmt.Skipped(step) - f.step(f.skipped[len(f.skipped)-1]) + f.step(f.skipped[len(f.skipped) - 1]) } func (f *cukefmt) Undefined(step *gherkin.Step) { f.basefmt.Undefined(step) f.stat = undefined - f.step(f.undefined[len(f.undefined)-1]) + f.step(f.undefined[len(f.undefined) - 1]) } func (f *cukefmt) Failed(step *gherkin.Step, match *StepDef, err error) { f.basefmt.Failed(step, match, err) f.stat = failed - f.step(f.failed[len(f.failed)-1]) + f.step(f.failed[len(f.failed) - 1]) } func (f *cukefmt) Pending(step *gherkin.Step, match *StepDef) { f.stat = pending f.basefmt.Pending(step, match) - f.step(f.pending[len(f.pending)-1]) + f.step(f.pending[len(f.pending) - 1]) }