Python: Sync identical file

This commit is contained in:
Mathias Vorreiter Pedersen
2020-10-29 19:07:10 +01:00
parent 4be02a9463
commit acf6ffb990

View File

@@ -43,15 +43,15 @@
* There is no need to write a `select` clause or query predicate. All of the differences between
* expected results and actual results will be reported in the `failures()` query predicate.
*
* To annotate the test source code with an expected result, place a comment on the
* To annotate the test source code with an expected result, place a comment starting with a `$` on the
* same line as the expected result, with text of the following format as the body of the comment:
*
* `$tag=expected-value`
* `tag=expected-value`
*
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
* the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
* omitted, in which case `expected-value` is treated as the empty string. Multiple expectations may
* be placed in the same comment, as long as each is prefixed by a `$`. Any actual result that
* be placed in the same comment. Any actual result that
* appears on a line that does not contain a matching expected result comment will be reported with
* a message of the form "Unexpected result: tag=value". Any expected result comment for which there
* is no matching actual result will be reported with a message of the form
@@ -60,30 +60,33 @@
* Example:
* ```cpp
* int i = x + 5; // $const=5
* int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant.
* int j = y + (7 - 3) // $const=7 const=3 const=4 // The result of the subtraction is a constant.
* ```
*
* For tests that contain known false positives and false negatives, it is possible to further
* annotate that a particular expected result is known to be a false positive, or that a particular
* missing result is known to be a false negative:
* For tests that contain known missing and spurious results, it is possible to further
* annotate that a particular expected result is known to be spurious, or that a particular
* missing result is known to be missing:
*
* `$f+:tag=expected-value` // False positive
* `$f-:tag=expected-value` // False negative
* `$ SPURIOUS: tag=expected-value` // Spurious result
* `$ MISSING: tag=expected-value` // Missing result
*
* A false positive expectation is treated as any other expected result, except that if there is no
* matching actual result, the message will be of the form "Fixed false positive: tag=value". A
* false negative expectation is treated as if there were no expected result, except that if a
* A spurious expectation is treated as any other expected result, except that if there is no
* matching actual result, the message will be of the form "Fixed spurious result: tag=value". A
* missing expectation is treated as if there were no expected result, except that if a
* matching expected result is found, the message will be of the form
* "Fixed false negative: tag=value".
* "Fixed missing result: tag=value".
*
* A single line can contain all the expected, spurious and missing results of that line. For instance:
* `$ tag1=value1 SPURIOUS: tag2=value2 MISSING: tag3=value3`.
*
* If the same result value is expected for two or more tags on the same line, there is a shorthand
* notation available:
*
* `$tag1,tag2=expected-value`
* `tag1,tag2=expected-value`
*
* is equivalent to:
*
* `$tag1=expected-value $tag2=expected-value`
* `tag1=expected-value tag2=expected-value`
*/
private import InlineExpectationsTestPrivate
@@ -126,7 +129,7 @@ abstract class InlineExpectationsTest extends string {
(
exists(FalseNegativeExpectation falseNegative |
falseNegative.matchesActualResult(actualResult) and
message = "Fixed false negative:" + falseNegative.getExpectationText()
message = "Fixed missing result:" + falseNegative.getExpectationText()
)
or
not exists(ValidExpectation expectation | expectation.matchesActualResult(actualResult)) and
@@ -143,7 +146,7 @@ abstract class InlineExpectationsTest extends string {
message = "Missing result:" + expectation.getExpectationText()
or
expectation instanceof FalsePositiveExpectation and
message = "Fixed false positive:" + expectation.getExpectationText()
message = "Fixed spurious result:" + expectation.getExpectationText()
)
)
or
@@ -160,20 +163,84 @@ abstract class InlineExpectationsTest extends string {
* is treated as part of the expected results, except that the comment may contain a `//` sequence
* to treat the remainder of the line as a regular (non-interpreted) comment.
*/
private string expectationCommentPattern() { result = "\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)(?://.*)?" }
/**
* RegEx pattern to match a single expected result, not including the leading `$`. It starts with an
* optional `f+:` or `f-:`, followed by one or more comma-separated tags containing only letters,
* `-`, and `_`, optionally followed by `=` and the expected value.
* The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first
* column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a
* column containing expected results preceeded by the string `name:`.
*/
private string expectationPattern() {
result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
private newtype TColumn =
TDefaultColumn() or
TNamedColumn(string name) { name = ["MISSING", "SPURIOUS"] }
bindingset[start, content]
private int getEndOfColumnPosition(int start, string content) {
result =
min(string name, int cand |
exists(TNamedColumn(name)) and
cand = content.indexOf(name + ":") and
cand > start
|
cand
)
or
not exists(string name |
exists(TNamedColumn(name)) and
content.indexOf(name + ":") > start
) and
result = content.length()
}
private string getAnExpectation(LineComment comment) {
result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and
result != ""
private string getAnExpectation(LineComment comment, TColumn column) {
exists(string content |
content = comment.getContents().regexpCapture(expectationCommentPattern(), 1) and
(
column = TDefaultColumn() and
exists(int end |
end = getEndOfColumnPosition(0, content) and
result = content.prefix(end).splitAt(" ").trim()
)
or
exists(string name, int start, int end |
column = TNamedColumn(name) and
start = content.indexOf(name + ":") + name.length() + 1 and
end = getEndOfColumnPosition(start, content) and
result = content.substring(start, end).splitAt(" ").trim()
)
) and
result != ""
)
}
bindingset[expectation]
private string getATag(string expectation) {
(
result = expectation.prefix(expectation.indexOf("=")).splitAt(",").trim()
or
not exists(expectation.indexOf("=")) and
result = expectation.splitAt(",").trim()
)
}
bindingset[expectation]
private string getValueForTag(string expectation) {
result = expectation.suffix(expectation.indexOf("=") + 1)
}
private string getColumnString(TColumn column) {
column = TDefaultColumn() and result = ""
or
column = TNamedColumn(result)
}
/**
* RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or
* more comma-separated tags containing only letters, `-`, and `_`, optionally followed by `=` and the
* expected value.
*/
private string expectationPattern() {
result = "((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
}
private newtype TFailureLocatable =
@@ -183,24 +250,19 @@ private newtype TFailureLocatable =
test.hasActualResult(location, element, tag, value)
} or
TValidExpectation(LineComment comment, string tag, string value, string knownFailure) {
exists(string expectation |
expectation = getAnExpectation(comment) and
expectation.regexpMatch(expectationPattern()) and
tag = expectation.regexpCapture(expectationPattern(), 2).splitAt(",").trim() and
exists(string expectation, TColumn column |
expectation = getAnExpectation(comment, column) and
tag = getATag(expectation) and
(
if exists(expectation.regexpCapture(expectationPattern(), 3))
then value = expectation.regexpCapture(expectationPattern(), 3)
if exists(getValueForTag(expectation))
then value = getValueForTag(expectation)
else value = ""
) and
(
if exists(expectation.regexpCapture(expectationPattern(), 1))
then knownFailure = expectation.regexpCapture(expectationPattern(), 1)
else knownFailure = ""
)
knownFailure = getColumnString(column)
)
} or
TInvalidExpectation(LineComment comment, string expectation) {
expectation = getAnExpectation(comment) and
expectation = getAnExpectation(comment, _) and
not expectation.regexpMatch(expectationPattern())
}
@@ -265,16 +327,17 @@ private class ValidExpectation extends Expectation, TValidExpectation {
}
}
/* Note: These next three classes correspond to all the possible values of type `TColumn`. */
class GoodExpectation extends ValidExpectation {
GoodExpectation() { getKnownFailure() = "" }
}
class FalsePositiveExpectation extends ValidExpectation {
FalsePositiveExpectation() { getKnownFailure() = "f+" }
FalsePositiveExpectation() { getKnownFailure() = "SPURIOUS" }
}
class FalseNegativeExpectation extends ValidExpectation {
FalseNegativeExpectation() { getKnownFailure() = "f-" }
FalseNegativeExpectation() { getKnownFailure() = "MISSING" }
}
class InvalidExpectation extends Expectation, TInvalidExpectation {