4343 * There is no need to write a `select` clause or query predicate. All of the differences between
4444 * expected results and actual results will be reported in the `failures()` query predicate.
4545 *
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
4747 * same line as the expected result, with text of the following format as the body of the comment:
4848 *
49- * `$ tag=expected-value`
49+ * `tag=expected-value`
5050 *
5151 * Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
5252 * the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
5353 * 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
5555 * appears on a line that does not contain a matching expected result comment will be reported with
5656 * a message of the form "Unexpected result: tag=value". Any expected result comment for which there
5757 * is no matching actual result will be reported with a message of the form
6060 * Example:
6161 * ```cpp
6262 * 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.
6464 * ```
6565 *
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 :
6969 *
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
7272 *
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
7676 * 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`.
7881 *
7982 * If the same result value is expected for two or more tags on the same line, there is a shorthand
8083 * notation available:
8184 *
82- * `$ tag1,tag2=expected-value`
85+ * `tag1,tag2=expected-value`
8386 *
8487 * is equivalent to:
8588 *
86- * `$ tag1=expected-value $ tag2=expected-value`
89+ * `tag1=expected-value tag2=expected-value`
8790 */
8891
8992private import InlineExpectationsTestPrivate
@@ -126,7 +129,7 @@ abstract class InlineExpectationsTest extends string {
126129 (
127130 exists ( FalseNegativeExpectation falseNegative |
128131 falseNegative .matchesActualResult ( actualResult ) and
129- message = "Fixed false negative :" + falseNegative .getExpectationText ( )
132+ message = "Fixed missing result :" + falseNegative .getExpectationText ( )
130133 )
131134 or
132135 not exists ( ValidExpectation expectation | expectation .matchesActualResult ( actualResult ) ) and
@@ -143,7 +146,7 @@ abstract class InlineExpectationsTest extends string {
143146 message = "Missing result:" + expectation .getExpectationText ( )
144147 or
145148 expectation instanceof FalsePositiveExpectation and
146- message = "Fixed false positive :" + expectation .getExpectationText ( )
149+ message = "Fixed spurious result :" + expectation .getExpectationText ( )
147150 )
148151 )
149152 or
@@ -160,20 +163,79 @@ abstract class InlineExpectationsTest extends string {
160163 * is treated as part of the expected results, except that the comment may contain a `//` sequence
161164 * to treat the remainder of the line as a regular (non-interpreted) comment.
162165 */
163- private string expectationCommentPattern ( ) { result = "\\s*( \\$(?:[^/]|/[^/])*)(?://.*)?" }
166+ private string expectationCommentPattern ( ) { result = "\\s*\\$( (?:[^/]|/[^/])*)(?://.*)?" }
164167
165168/**
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:` .
169172 */
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 = ""
172219}
173220
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+ )
177239}
178240
179241private newtype TFailureLocatable =
@@ -183,24 +245,14 @@ private newtype TFailureLocatable =
183245 test .hasActualResult ( location , element , tag , value )
184246 } or
185247 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 )
200252 )
201253 } or
202254 TInvalidExpectation ( LineComment comment , string expectation ) {
203- expectation = getAnExpectation ( comment ) and
255+ getAnExpectation ( comment , _ , expectation , _ , _ ) and
204256 not expectation .regexpMatch ( expectationPattern ( ) )
205257 }
206258
@@ -265,16 +317,17 @@ private class ValidExpectation extends Expectation, TValidExpectation {
265317 }
266318}
267319
320+ /* Note: These next three classes correspond to all the possible values of type `TColumn`. */
268321class GoodExpectation extends ValidExpectation {
269322 GoodExpectation ( ) { getKnownFailure ( ) = "" }
270323}
271324
272325class FalsePositiveExpectation extends ValidExpectation {
273- FalsePositiveExpectation ( ) { getKnownFailure ( ) = "f+ " }
326+ FalsePositiveExpectation ( ) { getKnownFailure ( ) = "SPURIOUS " }
274327}
275328
276329class FalseNegativeExpectation extends ValidExpectation {
277- FalseNegativeExpectation ( ) { getKnownFailure ( ) = "f- " }
330+ FalseNegativeExpectation ( ) { getKnownFailure ( ) = "MISSING " }
278331}
279332
280333class InvalidExpectation extends Expectation , TInvalidExpectation {
0 commit comments