93
93
private import InlineExpectationsTestPrivate
94
94
95
95
/**
96
- * Base class for tests with inline expectations. The test extends this class to provide the actual
96
+ * The base class for tests with inline expectations. The test extends this class to provide the actual
97
97
* results of the query, which are then compared with the expected results in comments to produce a
98
98
* list of failure messages that point out where the actual results differ from the expected
99
99
* results.
@@ -121,11 +121,17 @@ abstract class InlineExpectationsTest extends string {
121
121
* - `value` - The value of the result, which will be matched against the value associated with
122
122
* `tag` in any expected result comment on that line.
123
123
*/
124
- abstract predicate hasActualResult ( string file , int line , string element , string tag , string value ) ;
124
+ abstract predicate hasActualResult ( Location location , string element , string tag , string value ) ;
125
125
126
- predicate hasActualResult ( Location location , string element , string tag , string value ) {
127
- this .hasActualResult ( location .getFile ( ) .getAbsolutePath ( ) , location .getStartLine ( ) , element ,
128
- tag , value )
126
+ /**
127
+ * Holds if there is an optional result on the specified location.
128
+ *
129
+ * This is similar to `hasActualResult`, but returns results that do not require a matching annotation.
130
+ * A failure will still arise if there is an annotation that does not match any results, but not vice versa.
131
+ * Override this predicate to specify optional results.
132
+ */
133
+ predicate hasOptionalResult ( Location location , string element , string tag , string value ) {
134
+ none ( )
129
135
}
130
136
131
137
final predicate hasFailureMessage ( FailureLocatable element , string message ) {
@@ -139,13 +145,14 @@ abstract class InlineExpectationsTest extends string {
139
145
)
140
146
or
141
147
not exists ( ValidExpectation expectation | expectation .matchesActualResult ( actualResult ) ) and
142
- message = "Unexpected result: " + actualResult .getExpectationText ( )
148
+ message = "Unexpected result: " + actualResult .getExpectationText ( ) and
149
+ not actualResult .isOptional ( )
143
150
)
144
151
)
145
152
or
146
153
exists ( ValidExpectation expectation |
147
154
not exists ( ActualResult actualResult | expectation .matchesActualResult ( actualResult ) ) and
148
- expectation .getTag ( ) = this . getARelevantTag ( ) and
155
+ expectation .getTag ( ) = getARelevantTag ( ) and
149
156
element = expectation and
150
157
(
151
158
expectation instanceof GoodExpectation and
@@ -174,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)(
174
181
/**
175
182
* The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first
176
183
* column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a
177
- * column containing expected results preceeded by the string `name:`.
184
+ * column containing expected results preceded by the string `name:`.
178
185
*/
179
186
private newtype TColumn =
180
187
TDefaultColumn ( ) or
@@ -248,9 +255,13 @@ private string expectationPattern() {
248
255
249
256
private newtype TFailureLocatable =
250
257
TActualResult (
251
- InlineExpectationsTest test , Location location , string element , string tag , string value
258
+ InlineExpectationsTest test , Location location , string element , string tag , string value ,
259
+ boolean optional
252
260
) {
253
- test .hasActualResult ( location , element , tag , value )
261
+ test .hasActualResult ( location , element , tag , value ) and
262
+ optional = false
263
+ or
264
+ test .hasOptionalResult ( location , element , tag , value ) and optional = true
254
265
} or
255
266
TValidExpectation ( ExpectationComment comment , string tag , string value , string knownFailure ) {
256
267
exists ( TColumn column , string tags |
@@ -269,7 +280,7 @@ class FailureLocatable extends TFailureLocatable {
269
280
270
281
Location getLocation ( ) { none ( ) }
271
282
272
- final string getExpectationText ( ) { result = this . getTag ( ) + "=" + this . getValue ( ) }
283
+ final string getExpectationText ( ) { result = getTag ( ) + "=" + getValue ( ) }
273
284
274
285
string getTag ( ) { none ( ) }
275
286
@@ -282,8 +293,9 @@ class ActualResult extends FailureLocatable, TActualResult {
282
293
string element ;
283
294
string tag ;
284
295
string value ;
296
+ boolean optional ;
285
297
286
- ActualResult ( ) { this = TActualResult ( test , location , element , tag , value ) }
298
+ ActualResult ( ) { this = TActualResult ( test , location , element , tag , value , optional ) }
287
299
288
300
override string toString ( ) { result = element }
289
301
@@ -294,6 +306,8 @@ class ActualResult extends FailureLocatable, TActualResult {
294
306
override string getTag ( ) { result = tag }
295
307
296
308
override string getValue ( ) { result = value }
309
+
310
+ predicate isOptional ( ) { optional = true }
297
311
}
298
312
299
313
abstract private class Expectation extends FailureLocatable {
@@ -318,24 +332,24 @@ private class ValidExpectation extends Expectation, TValidExpectation {
318
332
string getKnownFailure ( ) { result = knownFailure }
319
333
320
334
predicate matchesActualResult ( ActualResult actualResult ) {
321
- this . getLocation ( ) .getStartLine ( ) = actualResult .getLocation ( ) .getStartLine ( ) and
322
- this . getLocation ( ) .getFile ( ) = actualResult .getLocation ( ) .getFile ( ) and
323
- this . getTag ( ) = actualResult .getTag ( ) and
324
- this . getValue ( ) = actualResult .getValue ( )
335
+ getLocation ( ) .getStartLine ( ) = actualResult .getLocation ( ) .getStartLine ( ) and
336
+ getLocation ( ) .getFile ( ) = actualResult .getLocation ( ) .getFile ( ) and
337
+ getTag ( ) = actualResult .getTag ( ) and
338
+ getValue ( ) = actualResult .getValue ( )
325
339
}
326
340
}
327
341
328
342
/* Note: These next three classes correspond to all the possible values of type `TColumn`. */
329
343
class GoodExpectation extends ValidExpectation {
330
- GoodExpectation ( ) { this . getKnownFailure ( ) = "" }
344
+ GoodExpectation ( ) { getKnownFailure ( ) = "" }
331
345
}
332
346
333
347
class FalsePositiveExpectation extends ValidExpectation {
334
- FalsePositiveExpectation ( ) { this . getKnownFailure ( ) = "SPURIOUS" }
348
+ FalsePositiveExpectation ( ) { getKnownFailure ( ) = "SPURIOUS" }
335
349
}
336
350
337
351
class FalseNegativeExpectation extends ValidExpectation {
338
- FalseNegativeExpectation ( ) { this . getKnownFailure ( ) = "MISSING" }
352
+ FalseNegativeExpectation ( ) { getKnownFailure ( ) = "MISSING" }
339
353
}
340
354
341
355
class InvalidExpectation extends Expectation , TInvalidExpectation {
0 commit comments