Skip to content

Commit 7b10b42

Browse files
authored
Merge pull request #141 from jstemmer/refactor-report-builder
Refactor report builder to support interleaved events from different packages
2 parents c796dcf + 4d0ed8b commit 7b10b42

File tree

15 files changed

+696
-524
lines changed

15 files changed

+696
-524
lines changed

parser/gotest/event.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package gotest
22

3-
import "time"
3+
import (
4+
"time"
5+
6+
"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/reader"
7+
)
48

59
// Event is a single event in a Go test or benchmark.
610
type Event struct {
711
Type string `json:"type"`
812

913
Name string `json:"name,omitempty"`
14+
Package string `json:"pkg,omitempty"`
1015
Result string `json:"result,omitempty"`
1116
Duration time.Duration `json:"duration,omitempty"`
1217
Data string `json:"data,omitempty"`
@@ -23,3 +28,10 @@ type Event struct {
2328
BytesPerOp int64 `json:"benchmark_bytes_per_op,omitempty"`
2429
AllocsPerOp int64 `json:"benchmark_allocs_per_op,omitempty"`
2530
}
31+
32+
func (e *Event) applyMetadata(m *reader.Metadata) {
33+
if e == nil || m == nil {
34+
return
35+
}
36+
e.Package = m.Package
37+
}

parser/gotest/gotest.go

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,18 @@ func (p *Parser) Parse(r io.Reader) (gtr.Report, error) {
133133
return p.parse(reader.NewLimitedLineReader(r, maxLineSize))
134134
}
135135

136-
func (p *Parser) parse(r *reader.LimitedLineReader) (gtr.Report, error) {
136+
func (p *Parser) parse(r reader.LineReader) (gtr.Report, error) {
137137
p.events = nil
138138
for {
139-
line, err := r.ReadLine()
139+
line, metadata, err := r.ReadLine()
140140
if err == io.EOF {
141141
break
142142
} else if err != nil {
143143
return gtr.Report{}, err
144144
}
145145

146+
var evs []Event
147+
146148
// Lines that exceed bufio.MaxScanTokenSize are not expected to contain
147149
// any relevant test infrastructure output, so instead of parsing them
148150
// we treat them as regular output to increase performance.
@@ -152,9 +154,14 @@ func (p *Parser) parse(r *reader.LimitedLineReader) (gtr.Report, error) {
152154
// turned out to be fine in almost all cases, it seemed an appropriate
153155
// value to use to decide whether or not to attempt parsing this line.
154156
if len(line) > bufio.MaxScanTokenSize {
155-
p.output(line)
157+
evs = p.output(line)
156158
} else {
157-
p.parseLine(line)
159+
evs = p.parseLine(line)
160+
}
161+
162+
for _, ev := range evs {
163+
ev.applyMetadata(metadata)
164+
p.events = append(p.events, ev)
158165
}
159166
}
160167
return p.report(p.events), nil
@@ -181,130 +188,124 @@ func (p *Parser) Events() []Event {
181188
return events
182189
}
183190

184-
func (p *Parser) parseLine(line string) {
191+
func (p *Parser) parseLine(line string) (events []Event) {
185192
if strings.HasPrefix(line, "=== RUN ") {
186-
p.runTest(strings.TrimSpace(line[8:]))
193+
return p.runTest(strings.TrimSpace(line[8:]))
187194
} else if strings.HasPrefix(line, "=== PAUSE ") {
188-
p.pauseTest(strings.TrimSpace(line[10:]))
195+
return p.pauseTest(strings.TrimSpace(line[10:]))
189196
} else if strings.HasPrefix(line, "=== CONT ") {
190-
p.contTest(strings.TrimSpace(line[9:]))
197+
return p.contTest(strings.TrimSpace(line[9:]))
191198
} else if matches := regexEndTest.FindStringSubmatch(line); len(matches) == 5 {
192-
p.endTest(line, matches[1], matches[2], matches[3], matches[4])
199+
return p.endTest(line, matches[1], matches[2], matches[3], matches[4])
193200
} else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 2 {
194-
p.status(matches[1])
201+
return p.status(matches[1])
195202
} else if matches := regexSummary.FindStringSubmatch(line); len(matches) == 8 {
196-
p.summary(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], matches[7])
203+
return p.summary(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], matches[7])
197204
} else if matches := regexCoverage.FindStringSubmatch(line); len(matches) == 3 {
198-
p.coverage(matches[1], matches[2])
205+
return p.coverage(matches[1], matches[2])
199206
} else if matches := regexBenchmark.FindStringSubmatch(line); len(matches) == 2 {
200-
p.runBench(matches[1])
207+
return p.runBench(matches[1])
201208
} else if matches := regexBenchSummary.FindStringSubmatch(line); len(matches) == 7 {
202-
p.benchSummary(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6])
209+
return p.benchSummary(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6])
203210
} else if matches := regexEndBenchmark.FindStringSubmatch(line); len(matches) == 3 {
204-
p.endBench(matches[1], matches[2])
211+
return p.endBench(matches[1], matches[2])
205212
} else if strings.HasPrefix(line, "# ") {
206-
// TODO(jstemmer): this should just be output; we should detect build output when building report
207213
fields := strings.Fields(strings.TrimPrefix(line, "# "))
208214
if len(fields) == 1 || len(fields) == 2 {
209-
p.buildOutput(fields[0])
210-
} else {
211-
p.output(line)
215+
return p.buildOutput(fields[0])
212216
}
213-
} else {
214-
p.output(line)
215217
}
218+
return p.output(line)
216219
}
217220

218-
func (p *Parser) add(event Event) {
219-
p.events = append(p.events, event)
221+
func (p *Parser) runTest(name string) []Event {
222+
return []Event{{Type: "run_test", Name: name}}
220223
}
221224

222-
func (p *Parser) runTest(name string) {
223-
p.add(Event{Type: "run_test", Name: name})
225+
func (p *Parser) pauseTest(name string) []Event {
226+
return []Event{{Type: "pause_test", Name: name}}
224227
}
225228

226-
func (p *Parser) pauseTest(name string) {
227-
p.add(Event{Type: "pause_test", Name: name})
229+
func (p *Parser) contTest(name string) []Event {
230+
return []Event{{Type: "cont_test", Name: name}}
228231
}
229232

230-
func (p *Parser) contTest(name string) {
231-
p.add(Event{Type: "cont_test", Name: name})
232-
}
233-
234-
func (p *Parser) endTest(line, indent, result, name, duration string) {
233+
func (p *Parser) endTest(line, indent, result, name, duration string) []Event {
234+
var events []Event
235235
if idx := strings.Index(line, fmt.Sprintf("%s--- %s:", indent, result)); idx > 0 {
236-
p.output(line[:idx])
236+
events = append(events, p.output(line[:idx])...)
237237
}
238238
_, n := stripIndent(indent)
239-
p.add(Event{
239+
events = append(events, Event{
240240
Type: "end_test",
241241
Name: name,
242242
Result: result,
243243
Indent: n,
244244
Duration: parseSeconds(duration),
245245
})
246+
return events
246247
}
247248

248-
func (p *Parser) status(result string) {
249-
p.add(Event{Type: "status", Result: result})
249+
func (p *Parser) status(result string) []Event {
250+
return []Event{{Type: "status", Result: result}}
250251
}
251252

252-
func (p *Parser) summary(result, name, duration, cached, status, covpct, packages string) {
253-
p.add(Event{
253+
func (p *Parser) summary(result, name, duration, cached, status, covpct, packages string) []Event {
254+
return []Event{{
254255
Type: "summary",
255256
Result: result,
256257
Name: name,
257258
Duration: parseSeconds(duration),
258259
Data: strings.TrimSpace(cached + " " + status),
259260
CovPct: parseFloat(covpct),
260261
CovPackages: parsePackages(packages),
261-
})
262+
}}
262263
}
263264

264-
func (p *Parser) coverage(percent, packages string) {
265-
p.add(Event{
265+
func (p *Parser) coverage(percent, packages string) []Event {
266+
return []Event{{
266267
Type: "coverage",
267268
CovPct: parseFloat(percent),
268269
CovPackages: parsePackages(packages),
269-
})
270+
}}
270271
}
271272

272-
func (p *Parser) runBench(name string) {
273-
p.add(Event{
273+
func (p *Parser) runBench(name string) []Event {
274+
return []Event{{
274275
Type: "run_benchmark",
275276
Name: name,
276-
})
277+
}}
277278
}
278279

279-
func (p *Parser) benchSummary(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp string) {
280-
p.add(Event{
280+
func (p *Parser) benchSummary(name, iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp string) []Event {
281+
return []Event{{
281282
Type: "benchmark",
282283
Name: name,
283284
Iterations: parseInt(iterations),
284285
NsPerOp: parseFloat(nsPerOp),
285286
MBPerSec: parseFloat(mbPerSec),
286287
BytesPerOp: parseInt(bytesPerOp),
287288
AllocsPerOp: parseInt(allocsPerOp),
288-
})
289+
}}
289290
}
290291

291-
func (p *Parser) endBench(result, name string) {
292-
p.add(Event{
292+
func (p *Parser) endBench(result, name string) []Event {
293+
return []Event{{
293294
Type: "end_benchmark",
294295
Name: name,
295296
Result: result,
296-
})
297+
}}
297298
}
298299

299-
func (p *Parser) buildOutput(packageName string) {
300-
p.add(Event{
300+
func (p *Parser) buildOutput(packageName string) []Event {
301+
return []Event{{
301302
Type: "build_output",
302303
Name: packageName,
303-
})
304+
}}
304305
}
305306

306-
func (p *Parser) output(line string) {
307-
p.add(Event{Type: "output", Data: line})
307+
func (p *Parser) output(line string) []Event {
308+
return []Event{{Type: "output", Data: line}}
308309
}
309310

310311
func parseSeconds(s string) time.Duration {

0 commit comments

Comments
 (0)