Skip to content

Commit 1277881

Browse files
author
Dave Bartolomeo
committed
C++: Document InlineExpectationsTest
1 parent 60a0eff commit 1277881

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

cpp/ql/test/TestUtilities/InlineExpectationsTest.qll

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,116 @@
1+
/**
2+
* Provides a library for writing QL tests whose success or failure is based on expected results
3+
* embedded in the test source code as comments, rather than a `.expected` file.
4+
*
5+
* To create a new inline expectations test:
6+
* - Declare a class that extends `InlineExpectationsTest`. In the characteristic predicate of the
7+
* new class, bind `this` to a unique string (usually the name of the test).
8+
* - Override the `hasActualResult()` predicate to produce the actual results of the query. For each
9+
* result, specify a `Location`, a text description of the element for which the result was
10+
* reported, a short string to serve as the tag to identify expected results for this test, and the
11+
* expected value of the result.
12+
* - Override `getARelevantTag()` to return the set of tags that can be produced by
13+
* `hasActualResult()`. Often this is just a single tag.
14+
*
15+
* Example:
16+
* ```
17+
* class ConstantValueTest extends InlineExpectationsTest {
18+
* ConstantValueTest() { this = "ConstantValueTest" }
19+
*
20+
* override string getARelevantTag() {
21+
* // We only use one tag for this test.
22+
* result = "const"
23+
* }
24+
*
25+
* override predicate hasActualResult(
26+
* Location location, string element, string tag, string valuesasas
27+
* ) {
28+
* exists(Expr e |
29+
* tag = "const" and // The tag for this test.
30+
* valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions.
31+
* location = e.getLocation() and // The location of the result to be reported.
32+
* element = e.toString() // The display text for the result.
33+
* )
34+
* }
35+
* }
36+
* ```
37+
*
38+
* There is no need to write a `select` clause or query predicate. All of the differences between
39+
* expected results and actual results will be reported in the `failures()` query predicate.
40+
*
41+
* To annotate the test source code with an expected result, place a C++-style (`//`) comment on the
42+
* same line as the expected result, with text of the following format as the body of the comment:
43+
*
44+
* `// $tag=expected-value`
45+
*
46+
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
47+
* the value of the `value` parameter from `hasActualResult()`. Multiple expectations may be placed
48+
* in the same comment, as long as each is prefixed by a `$`. Any actual result that appears on a
49+
* line that does not contain a matching expected result comment will be reported with a message of
50+
* the form "Unexpected result: tag=value". Any expected result comment for which there is no
51+
* matching actual result will be reported with a message of the form
52+
* "Missing result: tag=expected-value".
53+
*
54+
* Example:
55+
* ```
56+
* int i = x + 5; // $const=5
57+
* int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant.
58+
* ```
59+
*
60+
* For tests that contain known false positives and false negatives, it is possible to further
61+
* annotate that a particular expected result is known to be a false positive, or that a particular
62+
* missing result is known to be a false negative:
63+
*
64+
* `// $f+:tag=expected-value` // False positive
65+
* `// $f-:tag=expected-value` // False negative
66+
*
67+
* A false positive expectation is treated as any other expected result, except that if there is no
68+
* matching actual result, the message will be of the form "Fixed false positive: tag=value". A
69+
* false negative expectation is treated as if there were no expected result, except that if a
70+
* matching expected result is found, the message will be of the form
71+
* "Fixed false negative: tag=value".
72+
*
73+
* If the same result value is expected for two or more tags on the same line, there is a shorthand
74+
* notation available:
75+
*
76+
* `// $tag1,tag2=expected-value`
77+
*
78+
* is equivalent to:
79+
*
80+
* `// $tag1=expected-value $tag2=expected-value`
81+
*/
82+
183
import cpp
284

85+
/**
86+
* Base class for tests with inline expectations. The test extends this class to provide the actual
87+
* results of the query, which are then compared with the expected results in comments to produce a
88+
* list of failure messages that point out where the actual results differ from the expected
89+
* results.
90+
*/
391
abstract class InlineExpectationsTest extends string {
492
bindingset[this]
593
InlineExpectationsTest() { any() }
694

95+
/**
96+
* Returns all tags that can be generated by this test. Most tests will only ever produce a single
97+
* tag. Any expected result comments for a tag that is not returned by the `getARelevantTag()`
98+
* predicate for an active test will be ignored. This makes it possible to write multiple tests in
99+
* different `.ql` files that all query the same source code.
100+
*/
7101
abstract string getARelevantTag();
8102

103+
/**
104+
* Returns the actual results of the query that is being tested. Each result consist of the
105+
* following values:
106+
* - `location` - The source code location of the result. Any expected result comment must appear
107+
* on the start line of this location.
108+
* - `element` - Display text for the element on which the result is reported.
109+
* - `tag` - The tag that marks this result as coming from this test. This must be one of the tags
110+
* returned by `getARelevantTag()`.
111+
* - `value` - The value of the result, which will be matched against the value associated with
112+
* `tag` in any expected result comment on that line.
113+
*/
9114
abstract predicate hasActualResult(Location location, string element, string tag, string value);
10115

11116
final predicate hasFailureMessage(FailureLocatable element, string message) {

0 commit comments

Comments
 (0)