43
43
* There is no need to write a `select` clause or query predicate. All of the differences between
44
44
* expected results and actual results will be reported in the `failures()` query predicate.
45
45
*
46
- * To annotate the test source code with an expected result, place a comment on the
46
+ * To annotate the test source code with an expected result, place a comment starting with a `$` on the
47
47
* same line as the expected result, with text of the following format as the body of the comment:
48
48
*
49
- * `$ tag=expected-value`
49
+ * `tag=expected-value`
50
50
*
51
51
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
52
52
* the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
53
53
* omitted, in which case `expected-value` is treated as the empty string. Multiple expectations may
54
- * be placed in the same comment, as long as each is prefixed by a `$` . Any actual result that
54
+ * be placed in the same comment. Any actual result that
55
55
* appears on a line that does not contain a matching expected result comment will be reported with
56
56
* a message of the form "Unexpected result: tag=value". Any expected result comment for which there
57
57
* is no matching actual result will be reported with a message of the form
60
60
* Example:
61
61
* ```cpp
62
62
* int i = x + 5; // $const=5
63
- * int j = y + (7 - 3) // $const=7 $ const=3 $ const=4 // The result of the subtraction is a constant.
63
+ * int j = y + (7 - 3) // $const=7 const=3 const=4 // The result of the subtraction is a constant.
64
64
* ```
65
65
*
66
- * For tests that contain known false positives and false negatives , it is possible to further
67
- * annotate that a particular expected result is known to be a false positive , or that a particular
68
- * missing result is known to be a false negative :
66
+ * For tests that contain known missing and spurious results , it is possible to further
67
+ * annotate that a particular expected result is known to be spurious , or that a particular
68
+ * missing result is known to be missing :
69
69
*
70
- * `$f+: tag=expected-value` // False positive
71
- * `$f-: tag=expected-value` // False negative
70
+ * `$ SPURIOUS: tag=expected-value` // Spurious result
71
+ * `$ MISSING: tag=expected-value` // Missing result
72
72
*
73
- * A false positive expectation is treated as any other expected result, except that if there is no
74
- * matching actual result, the message will be of the form "Fixed false positive : tag=value". A
75
- * false negative expectation is treated as if there were no expected result, except that if a
73
+ * A spurious expectation is treated as any other expected result, except that if there is no
74
+ * matching actual result, the message will be of the form "Fixed spurious result : tag=value". A
75
+ * missing expectation is treated as if there were no expected result, except that if a
76
76
* matching expected result is found, the message will be of the form
77
- * "Fixed false negative: tag=value".
77
+ * "Fixed missing result: tag=value".
78
+ *
79
+ * A single line can contain all the expected, spurious and missing results of that line. For instance:
80
+ * `$ tag1=value1 SPURIOUS: tag2=value2 MISSING: tag3=value3`.
78
81
*
79
82
* If the same result value is expected for two or more tags on the same line, there is a shorthand
80
83
* notation available:
81
84
*
82
- * `$ tag1,tag2=expected-value`
85
+ * `tag1,tag2=expected-value`
83
86
*
84
87
* is equivalent to:
85
88
*
86
- * `$ tag1=expected-value $ tag2=expected-value`
89
+ * `tag1=expected-value tag2=expected-value`
87
90
*/
88
91
89
92
private import InlineExpectationsTestPrivate
@@ -126,7 +129,7 @@ abstract class InlineExpectationsTest extends string {
126
129
(
127
130
exists ( FalseNegativeExpectation falseNegative |
128
131
falseNegative .matchesActualResult ( actualResult ) and
129
- message = "Fixed false negative :" + falseNegative .getExpectationText ( )
132
+ message = "Fixed missing result :" + falseNegative .getExpectationText ( )
130
133
)
131
134
or
132
135
not exists ( ValidExpectation expectation | expectation .matchesActualResult ( actualResult ) ) and
@@ -143,7 +146,7 @@ abstract class InlineExpectationsTest extends string {
143
146
message = "Missing result:" + expectation .getExpectationText ( )
144
147
or
145
148
expectation instanceof FalsePositiveExpectation and
146
- message = "Fixed false positive :" + expectation .getExpectationText ( )
149
+ message = "Fixed spurious result :" + expectation .getExpectationText ( )
147
150
)
148
151
)
149
152
or
@@ -160,20 +163,79 @@ abstract class InlineExpectationsTest extends string {
160
163
* is treated as part of the expected results, except that the comment may contain a `//` sequence
161
164
* to treat the remainder of the line as a regular (non-interpreted) comment.
162
165
*/
163
- private string expectationCommentPattern ( ) { result = "\\s*( \\$(?:[^/]|/[^/])*)(?://.*)?" }
166
+ private string expectationCommentPattern ( ) { result = "\\s*\\$( (?:[^/]|/[^/])*)(?://.*)?" }
164
167
165
168
/**
166
- * RegEx pattern to match a single expected result, not including the leading `$`. It starts with an
167
- * optional `f+:` or `f-:`, followed by one or more comma-separated tags containing only letters,
168
- * `-`, and `_`, optionally followed by `=` and the expected value .
169
+ * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first
170
+ * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a
171
+ * column containing expected results preceeded by the string `name:` .
169
172
*/
170
- private string expectationPattern ( ) {
171
- result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
173
+ private newtype TColumn =
174
+ TDefaultColumn ( ) or
175
+ TNamedColumn ( string name ) { name = [ "MISSING" , "SPURIOUS" ] }
176
+
177
+ bindingset [ start, content]
178
+ private int getEndOfColumnPosition ( int start , string content ) {
179
+ result =
180
+ min ( string name , int cand |
181
+ exists ( TNamedColumn ( name ) ) and
182
+ cand = content .indexOf ( name + ":" ) and
183
+ cand > start
184
+ |
185
+ cand
186
+ )
187
+ or
188
+ not exists ( string name |
189
+ exists ( TNamedColumn ( name ) ) and
190
+ content .indexOf ( name + ":" ) > start
191
+ ) and
192
+ result = content .length ( )
193
+ }
194
+
195
+ private predicate getAnExpectation (
196
+ LineComment comment , TColumn column , string expectation , string tags , string value
197
+ ) {
198
+ exists ( string content |
199
+ content = comment .getContents ( ) .regexpCapture ( expectationCommentPattern ( ) , 1 ) and
200
+ (
201
+ column = TDefaultColumn ( ) and
202
+ exists ( int end |
203
+ end = getEndOfColumnPosition ( 0 , content ) and
204
+ expectation = content .prefix ( end ) .regexpFind ( expectationPattern ( ) , _, _) .trim ( )
205
+ )
206
+ or
207
+ exists ( string name , int start , int end |
208
+ column = TNamedColumn ( name ) and
209
+ start = content .indexOf ( name + ":" ) + name .length ( ) + 1 and
210
+ end = getEndOfColumnPosition ( start , content ) and
211
+ expectation = content .substring ( start , end ) .regexpFind ( expectationPattern ( ) , _, _) .trim ( )
212
+ )
213
+ )
214
+ ) and
215
+ tags = expectation .regexpCapture ( expectationPattern ( ) , 1 ) and
216
+ if exists ( expectation .regexpCapture ( expectationPattern ( ) , 2 ) )
217
+ then value = expectation .regexpCapture ( expectationPattern ( ) , 2 )
218
+ else value = ""
172
219
}
173
220
174
- private string getAnExpectation ( LineComment comment ) {
175
- result = comment .getContents ( ) .regexpCapture ( expectationCommentPattern ( ) , 1 ) .splitAt ( "$" ) .trim ( ) and
176
- result != ""
221
+ private string getColumnString ( TColumn column ) {
222
+ column = TDefaultColumn ( ) and result = ""
223
+ or
224
+ column = TNamedColumn ( result )
225
+ }
226
+
227
+ /**
228
+ * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or
229
+ * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character
230
+ * must not be a digit), optionally followed by `=` and the expected value.
231
+ */
232
+ private string expectationPattern ( ) {
233
+ exists ( string tag , string tags , string value |
234
+ tag = "[A-Za-z-_][A-Za-z-_0-9]*" and
235
+ tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and
236
+ value = "((?:\"[^\"]*\"|'[^']*'|\\S+)*)" and
237
+ result = tags + "(?:=" + value + ")?"
238
+ )
177
239
}
178
240
179
241
private newtype TFailureLocatable =
@@ -183,24 +245,14 @@ private newtype TFailureLocatable =
183
245
test .hasActualResult ( ___location , element , tag , value )
184
246
} or
185
247
TValidExpectation ( LineComment comment , string tag , string value , string knownFailure ) {
186
- exists ( string expectation |
187
- expectation = getAnExpectation ( comment ) and
188
- expectation .regexpMatch ( expectationPattern ( ) ) and
189
- tag = expectation .regexpCapture ( expectationPattern ( ) , 2 ) .splitAt ( "," ) .trim ( ) and
190
- (
191
- if exists ( expectation .regexpCapture ( expectationPattern ( ) , 3 ) )
192
- then value = expectation .regexpCapture ( expectationPattern ( ) , 3 )
193
- else value = ""
194
- ) and
195
- (
196
- if exists ( expectation .regexpCapture ( expectationPattern ( ) , 1 ) )
197
- then knownFailure = expectation .regexpCapture ( expectationPattern ( ) , 1 )
198
- else knownFailure = ""
199
- )
248
+ exists ( TColumn column , string tags |
249
+ getAnExpectation ( comment , column , _, tags , value ) and
250
+ tag = tags .splitAt ( "," ) and
251
+ knownFailure = getColumnString ( column )
200
252
)
201
253
} or
202
254
TInvalidExpectation ( LineComment comment , string expectation ) {
203
- expectation = getAnExpectation ( comment ) and
255
+ getAnExpectation ( comment , _ , expectation , _ , _ ) and
204
256
not expectation .regexpMatch ( expectationPattern ( ) )
205
257
}
206
258
@@ -265,16 +317,17 @@ private class ValidExpectation extends Expectation, TValidExpectation {
265
317
}
266
318
}
267
319
320
+ /* Note: These next three classes correspond to all the possible values of type `TColumn`. */
268
321
class GoodExpectation extends ValidExpectation {
269
322
GoodExpectation ( ) { getKnownFailure ( ) = "" }
270
323
}
271
324
272
325
class FalsePositiveExpectation extends ValidExpectation {
273
- FalsePositiveExpectation ( ) { getKnownFailure ( ) = "f+ " }
326
+ FalsePositiveExpectation ( ) { getKnownFailure ( ) = "SPURIOUS " }
274
327
}
275
328
276
329
class FalseNegativeExpectation extends ValidExpectation {
277
- FalseNegativeExpectation ( ) { getKnownFailure ( ) = "f- " }
330
+ FalseNegativeExpectation ( ) { getKnownFailure ( ) = "MISSING " }
278
331
}
279
332
280
333
class InvalidExpectation extends Expectation , TInvalidExpectation {
0 commit comments