-
Notifications
You must be signed in to change notification settings - Fork 77
/
Copy pathdata_parser.go
138 lines (112 loc) · 5.11 KB
/
data_parser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package oscmd
import (
"regexp"
"github.com/openshift/image-registry/tools/junitreport/pkg/api"
"github.com/openshift/image-registry/tools/junitreport/pkg/parser/stack"
)
func newTestDataParser() stack.TestDataParser {
return &testDataParser{
// testStartPattern matches the test beginning bookend
testStartPattern: regexp.MustCompile(`=== BEGIN TEST CASE ===`),
// testDeclarationPattern matches the test declaration line, the full match is the name of the test being run
// as we're starting the test declaration line with a Unix path, misprinting a leading newline will cause this
// pattern to match the entire misprinted line
testDeclarationPattern: regexp.MustCompile(`.+:[0-9]+: executing '.+' expecting .+`),
// testConclusionPattern matches the test conclusion line, and contains the following submatches:
// - 1: test result
// - 2: test duration
// - 3: test name
// - 5: test result message
// In order to make this regex sane, we *require* a end-line anchor and therefore make us a little more fragile
// in the face of broken input
testConclusionPattern: regexp.MustCompile(`(SUCCESS|FAILURE) after ([0-9]+\.[0-9]+s): (.+:[0-9]+: executing '.*' expecting .*?)(: (.*))?$`),
// testEndPattern matches the test end bookend
testEndPattern: regexp.MustCompile(`=== END TEST CASE ===`),
}
}
type testDataParser struct {
testStartPattern *regexp.Regexp
testDeclarationPattern *regexp.Regexp
testConclusionPattern *regexp.Regexp
testEndPattern *regexp.Regexp
}
// MarksBeginning determines if the line marks the beginning of a test case
func (p *testDataParser) MarksBeginning(line string) bool {
return p.testStartPattern.MatchString(line)
}
// ExtractName extracts the name of the test case from test output lines
func (p *testDataParser) ExtractName(line string) (string, bool) {
// The test declaration pattern is technically a subset of the test conclusion pattern, and will therefore
// match anything the test declaration pattern matches. The match from the test conclusion pattern is more
// correct, if it exists, so we check the conclusion pattern first and return if we have a name candidate.
if matches := p.testConclusionPattern.FindStringSubmatch(line); len(matches) > 3 && len(matches[3]) > 0 {
return matches[3], true
}
if matches := p.testDeclarationPattern.FindStringSubmatch(line); len(matches) > 0 && len(matches[0]) > 0 {
return matches[0], true
}
return "", false
}
// ExtractResult extracts the test result from a test output line
func (p *testDataParser) ExtractResult(line string) (api.TestResult, bool) {
if matches := p.testConclusionPattern.FindStringSubmatch(line); len(matches) > 1 && len(matches[1]) > 0 {
switch matches[1] {
case "SUCCESS":
return api.TestResultPass, true
case "FAILURE":
return api.TestResultFail, true
}
}
return "", false
}
// ExtractDuration extracts the test duration from a test output line
func (p *testDataParser) ExtractDuration(line string) (string, bool) {
if matches := p.testConclusionPattern.FindStringSubmatch(line); len(matches) > 2 && len(matches[2]) > 0 {
return matches[2], true
}
return "", false
}
// ExtractMessage extracts a message (e.g. for signalling why a failure or skip occurred) from a test output line
func (p *testDataParser) ExtractMessage(line string) (string, bool) {
if matches := p.testConclusionPattern.FindStringSubmatch(line); len(matches) > 5 && len(matches[5]) > 0 {
return matches[5], true
}
return "", false
}
// MarksCompletion determines if the line marks the completion of a test case
func (p *testDataParser) MarksCompletion(line string) bool {
return p.testEndPattern.MatchString(line)
}
func newTestSuiteDataParser() stack.TestSuiteDataParser {
return &testSuiteDataParser{
// suiteDeclarationPattern matches the suite declaration line and has the following submatches:
// - 1: suite name
suiteDeclarationPattern: regexp.MustCompile(`=== BEGIN TEST SUITE (.*) ===`),
// suiteConclusionPattern matches the suite conclusion line
suiteConclusionPattern: regexp.MustCompile(`=== END TEST SUITE ===`),
}
}
type testSuiteDataParser struct {
suiteDeclarationPattern *regexp.Regexp
suiteConclusionPattern *regexp.Regexp
}
// MarksBeginning determines if the line marks the beginning of a test suite
func (p *testSuiteDataParser) MarksBeginning(line string) bool {
return p.suiteDeclarationPattern.MatchString(line)
}
// ExtractName extracts the name of the test suite from a test output line
func (p *testSuiteDataParser) ExtractName(line string) (string, bool) {
if matches := p.suiteDeclarationPattern.FindStringSubmatch(line); len(matches) > 1 && len(matches[1]) > 0 {
return matches[1], true
}
return "", false
}
// ExtractProperties extracts any metadata properties of the test suite from a test output line
func (p *testSuiteDataParser) ExtractProperties(line string) (map[string]string, bool) {
// `os::cmd` suites cannot expose properties
return map[string]string{}, false
}
// MarksCompletion determines if the line marks the completion of a test suite
func (p *testSuiteDataParser) MarksCompletion(line string) bool {
return p.suiteConclusionPattern.MatchString(line)
}