@@ -3,205 +3,183 @@ package godog
3
3
import (
4
4
"encoding/xml"
5
5
"fmt"
6
+ "io"
6
7
"os"
7
8
"time"
8
9
9
10
"gopkg.in/cucumber/gherkin-go.v3"
10
11
)
11
12
12
13
func init () {
13
- Format ("junit" , "Prints out in junit compatible xml format" , & junitFormatter {
14
- suites : make ([]* junitTestSuites , 0 ),
14
+ Format ("junit" , "Prints junit compatible xml to stdout" , & junitFormatter {
15
+ suite : & junitPackageSuite {
16
+ Name : "main" , // @TODO: it should extract package name
17
+ TestSuites : make ([]* junitTestSuite , 0 ),
18
+ },
19
+ started : time .Now (),
15
20
})
16
21
}
17
22
18
23
type junitFormatter struct {
19
- suites []* junitTestSuites
24
+ suite * junitPackageSuite
25
+
26
+ // timing
27
+ started time.Time
28
+ caseStarted time.Time
29
+ featStarted time.Time
30
+
31
+ outline * gherkin.ScenarioOutline
32
+ outlineExample int
20
33
}
21
34
22
35
func (j * junitFormatter ) Feature (feature * gherkin.Feature , path string ) {
23
- testSuites := & junitTestSuites {
24
- Name : feature . Name ,
25
- TestSuites : make ([] * junitTestSuite , 0 ) ,
36
+ testSuite := & junitTestSuite {
37
+ TestCases : make ([] * TestCase , 0 ) ,
38
+ Name : feature . Name ,
26
39
}
27
40
28
- j .suites = append (j .suites , testSuites )
41
+ if len (j .suite .TestSuites ) > 0 {
42
+ j .current ().Time = time .Since (j .featStarted ).String ()
43
+ }
44
+ j .featStarted = time .Now ()
45
+ j .suite .TestSuites = append (j .suite .TestSuites , testSuite )
29
46
}
30
47
31
48
func (j * junitFormatter ) Node (node interface {}) {
32
- testSuite := & junitTestSuite {
33
- TestCases : make ([]* TestCase , 0 ),
34
- Timestamp : time .Now (),
35
- }
49
+ suite := j .current ()
50
+ tcase := & TestCase {}
36
51
37
52
switch t := node .(type ) {
38
53
case * gherkin.ScenarioOutline :
39
- testSuite .Name = t .Name
54
+ j .outline = t
55
+ return
40
56
case * gherkin.Scenario :
41
- testSuite .Name = t .Name
42
- case * gherkin.Background :
43
- testSuite .Name = "Background"
57
+ tcase .Name = t .Name
58
+ suite .Tests ++
59
+ j .suite .Tests ++
60
+ case * gherkin.Examples :
61
+ j .outlineExample = 0
62
+ return
63
+ case * gherkin.TableRow :
64
+ j .outlineExample ++
65
+ tcase .Name = fmt .Sprintf ("%s #%d" , j .outline .Name , j .outlineExample )
66
+ suite .Tests ++
67
+ j .suite .Tests ++
68
+ default :
69
+ return
44
70
}
45
-
46
- currentSuites := j .currentSuites ()
47
- currentSuites .TestSuites = append (currentSuites .TestSuites , testSuite )
71
+ if len (suite .TestCases ) > 0 {
72
+ suite .current ().Time = time .Since (j .caseStarted ).String ()
73
+ }
74
+ j .caseStarted = time .Now ()
75
+ suite .TestCases = append (suite .TestCases , tcase )
48
76
}
49
77
50
78
func (j * junitFormatter ) Failed (step * gherkin.Step , match * StepDef , err error ) {
51
- testCase := & TestCase {
52
- Name : step .Text ,
79
+ suite := j .current ()
80
+ suite .Failures ++
81
+ j .suite .Failures ++
82
+
83
+ tcase := suite .current ()
84
+ tcase .Status = "failed"
85
+ tcase .Failure = & junitFailure {
86
+ Message : fmt .Sprintf ("%s %s: %s" , step .Type , step .Text , err .Error ()),
53
87
}
54
-
55
- testCase .Failure = & junitFailure {
56
- Contents : err .Error (),
57
- }
58
-
59
- currentSuites := j .currentSuites ()
60
- currentSuites .Failures ++
61
- currentSuite := currentSuites .currentSuite ()
62
- currentSuite .Failures ++
63
- currentSuite .TestCases = append (currentSuite .TestCases , testCase )
64
88
}
65
89
66
90
func (j * junitFormatter ) Passed (step * gherkin.Step , match * StepDef ) {
67
- testCase := & TestCase {
68
- Name : step .Text ,
69
- }
91
+ suite := j .current ()
70
92
71
- currentSuites := j .currentSuites ()
72
- currentSuites .Tests ++
73
- currentSuite := currentSuites .currentSuite ()
74
- currentSuite .Tests ++
75
- currentSuite .TestCases = append (currentSuite .TestCases , testCase )
93
+ tcase := suite .current ()
94
+ tcase .Status = "passed"
76
95
}
77
96
78
97
func (j * junitFormatter ) Skipped (step * gherkin.Step ) {
79
- testCase := & TestCase {
80
- Name : step .Text ,
81
- }
82
-
83
- currentSuites := j .currentSuites ()
84
- currentSuite := currentSuites .currentSuite ()
85
- currentSuite .Skipped ++
86
- currentSuite .TestCases = append (currentSuite .TestCases , testCase )
87
98
}
88
99
89
100
func (j * junitFormatter ) Undefined (step * gherkin.Step ) {
90
- testCase := & TestCase {
91
- Name : step .Text ,
92
- }
93
-
94
- currentSuites := j .currentSuites ()
95
- currentSuites .Disabled ++
96
- currentSuite := currentSuites .currentSuite ()
97
- currentSuite .Disabled ++
98
- currentSuite .TestCases = append (currentSuite .TestCases , testCase )
101
+ suite := j .current ()
102
+ suite .Errors ++
103
+ j .suite .Errors ++
104
+
105
+ tcase := suite .current ()
106
+ tcase .Status = "undefined"
107
+ tcase .Error = append (tcase .Error , & junitError {
108
+ Type : "undefined" ,
109
+ Message : fmt .Sprintf ("%s %s" , step .Type , step .Text ),
110
+ })
99
111
}
100
112
101
113
func (j * junitFormatter ) Pending (step * gherkin.Step , match * StepDef ) {
102
- testCase := & TestCase {
103
- Name : step .Text ,
104
- }
105
-
106
- testCase .Skipped = & junitSkipped {
107
- Contents : step .Text ,
108
- }
109
-
110
- currentSuites := j .currentSuites ()
111
- currentSuite := currentSuites .currentSuite ()
112
- currentSuite .Skipped ++
113
- currentSuite .TestCases = append (currentSuite .TestCases , testCase )
114
+ suite := j .current ()
115
+ suite .Errors ++
116
+ j .suite .Errors ++
117
+
118
+ tcase := suite .current ()
119
+ tcase .Status = "pending"
120
+ tcase .Error = append (tcase .Error , & junitError {
121
+ Type : "pending" ,
122
+ Message : fmt .Sprintf ("%s %s: TODO: write pending definition" , step .Type , step .Text ),
123
+ })
114
124
}
115
125
116
126
func (j * junitFormatter ) Summary () {
127
+ j .suite .Time = time .Since (j .started ).String ()
128
+ io .WriteString (os .Stdout , xml .Header )
129
+
117
130
enc := xml .NewEncoder (os .Stdout )
118
- enc .Indent (" " , " " )
119
- if err := enc .Encode (j .suites ); err != nil {
120
- fmt .Printf ( "error: %v \n " , err )
131
+ enc .Indent ("" , s ( 2 ) )
132
+ if err := enc .Encode (j .suite ); err != nil {
133
+ fmt .Println ( "failed to write junit xml: " , err )
121
134
}
122
135
}
123
136
124
137
type junitFailure struct {
125
- Message string `xml:"message,attr"`
126
- Type string `xml:"type,attr"`
127
- Contents string `xml:",chardata"`
138
+ Message string `xml:"message,attr"`
139
+ Type string `xml:"type,attr,omitempty"`
128
140
}
129
141
130
142
type junitError struct {
131
- Message string `xml:"message,attr"`
132
- Type string `xml:"type,attr"`
133
- Contents string `xml:",chardata"`
134
- }
135
-
136
- type junitProperty struct {
137
- Name string `xml:"name,attr"`
138
- Value string `xml:"value,attr"`
139
- }
140
-
141
- type junitSkipped struct {
142
- Contents string `xml:",chardata"`
143
- }
144
-
145
- type SystemErr struct {
146
- Contents string `xml:",chardata"`
147
- }
148
-
149
- type SystemOut struct {
150
- Contents string `xml:",chardata"`
143
+ XMLName xml.Name `xml:"error,omitempty"`
144
+ Message string `xml:"message,attr"`
145
+ Type string `xml:"type,attr"`
151
146
}
152
147
153
148
type TestCase struct {
154
- XMLName xml.Name `xml:"testcase"`
155
- Name string `xml:"name,attr"`
156
- Classname string `xml:"classname,attr"`
157
- Assertions string `xml:"assertions,attr"`
158
- Status string `xml:"status,attr"`
159
- Time string `xml:"time,attr"`
160
- Skipped * junitSkipped `xml:"skipped,omitempty"`
161
- Failure * junitFailure `xml:"failure,omitempty"`
162
- Error * junitError `xml:"error,omitempty"`
163
- SystemOut * SystemOut `xml:"system-out,omitempty"`
164
- SystemErr * SystemErr `xml:"system-err,omitempty"`
149
+ XMLName xml.Name `xml:"testcase"`
150
+ Name string `xml:"name,attr"`
151
+ Status string `xml:"status,attr"`
152
+ Time string `xml:"time,attr"`
153
+ Failure * junitFailure `xml:"failure,omitempty"`
154
+ Error []* junitError
165
155
}
166
156
167
157
type junitTestSuite struct {
168
- XMLName xml.Name `xml:"testsuite"`
169
- Name string `xml:"name,attr"`
170
- Tests int `xml:"tests,attr"`
171
- Failures int `xml:"failures,attr"`
172
- Errors int `xml:"errors,attr"`
173
- Disabled int `xml:"disabled,attr"`
174
- Skipped int `xml:"skipped,attr"`
175
- Time string `xml:"time,attr"`
176
- Hostname string `xml:"hostname,attr"`
177
- ID string `xml:"id,attr"`
178
- Package string `xml:"package,attr"`
179
- Timestamp time.Time `xml:"timestamp,attr"`
180
- SystemOut * SystemOut `xml:"system-out,omitempty"`
181
- SystemErr * SystemErr `xml:"system-err,omitempty"`
182
- Properties []* junitProperty `xml:"properties>property,omitempty"`
183
- TestCases []* TestCase
184
- }
185
-
186
- func (ts * junitTestSuite ) currentCase () * TestCase {
158
+ XMLName xml.Name `xml:"testsuite"`
159
+ Name string `xml:"name,attr"`
160
+ Tests int `xml:"tests,attr"`
161
+ Skipped int `xml:"skipped,attr"`
162
+ Failures int `xml:"failures,attr"`
163
+ Errors int `xml:"errors,attr"`
164
+ Time string `xml:"time,attr"`
165
+ TestCases []* TestCase
166
+ }
167
+
168
+ func (ts * junitTestSuite ) current () * TestCase {
187
169
return ts .TestCases [len (ts .TestCases )- 1 ]
188
170
}
189
171
190
- type junitTestSuites struct {
172
+ type junitPackageSuite struct {
191
173
XMLName xml.Name `xml:"testsuites"`
192
174
Name string `xml:"name,attr"`
193
175
Tests int `xml:"tests,attr"`
176
+ Skipped int `xml:"skipped,attr"`
194
177
Failures int `xml:"failures,attr"`
195
178
Errors int `xml:"errors,attr"`
196
- Disabled int `xml:"disabled,attr"`
197
179
Time string `xml:"time,attr"`
198
180
TestSuites []* junitTestSuite
199
181
}
200
182
201
- func (ts * junitTestSuites ) currentSuite () * junitTestSuite {
202
- return ts .TestSuites [len (ts .TestSuites )- 1 ]
203
- }
204
-
205
- func (j * junitFormatter ) currentSuites () * junitTestSuites {
206
- return j .suites [len (j .suites )- 1 ]
183
+ func (j * junitFormatter ) current () * junitTestSuite {
184
+ return j .suite .TestSuites [len (j .suite .TestSuites )- 1 ]
207
185
}
0 commit comments