Skip to content

Commit 823ed44

Browse files
committed
Python: Add new-style tests
should perhaps move `LocalFlowStepTest` and `MaximalFlowStep` into where they are referenced (they did not seem too reusable after all). Should also add argument tests in the same way.
1 parent 26286e5 commit 823ed44

File tree

14 files changed

+176
-82
lines changed

14 files changed

+176
-82
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import TestUtilities.InlineExpectationsTest
4+
5+
abstract class FlowTest extends InlineExpectationsTest {
6+
bindingset[this]
7+
FlowTest() { any() }
8+
9+
abstract string flowTag();
10+
11+
abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode);
12+
13+
override string getARelevantTag() { result = this.flowTag() }
14+
15+
override predicate hasActualResult(Location location, string element, string tag, string value) {
16+
exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) |
17+
location = toNode.getLocation() and
18+
tag = this.flowTag() and
19+
value =
20+
"\"" + fromNode.toString() + lineStr(fromNode, toNode) + " -> " + toNode.toString() + "\"" and
21+
element = toNode.toString()
22+
)
23+
}
24+
25+
pragma[inline]
26+
private string lineStr(DataFlow::Node fromNode, DataFlow::Node toNode) {
27+
if fromNode.getLocation().getStartLine() = toNode.getLocation().getStartLine()
28+
then result = ""
29+
else result = ", l:" + fromNode.getLocation().getStartLine()
30+
}
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import FlowTest
4+
5+
class LocalFlowStepTest extends FlowTest {
6+
LocalFlowStepTest() { this = "LocalFlowStepTest" }
7+
8+
override string flowTag() { result = "step" }
9+
10+
override predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) {
11+
DataFlow::localFlowStep(fromNode, toNode)
12+
}
13+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import FlowTest
4+
5+
class MaximalFlowTest extends FlowTest {
6+
MaximalFlowTest() { this = "MaximalFlowTest" }
7+
8+
override string flowTag() { result = "flow" }
9+
10+
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
11+
source != sink and
12+
exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink))
13+
}
14+
}
15+
16+
/**
17+
* A configuration to find all "maximal" flows.
18+
* To be used on small programs.
19+
*/
20+
class MaximalFlowsConfig extends DataFlow::Configuration {
21+
MaximalFlowsConfig() { this = "MaximalFlowsConfig" }
22+
23+
override predicate isSource(DataFlow::Node node) {
24+
not node.asCfgNode() instanceof CallNode and
25+
not node.asCfgNode().getNode() instanceof Return and
26+
not node instanceof DataFlow::ParameterNode and
27+
not exists(DataFlow::Node pred | DataFlow::localFlowStep(pred, node))
28+
}
29+
30+
override predicate isSink(DataFlow::Node node) {
31+
not any(CallNode c).getArg(_) = node.asCfgNode() and
32+
not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ))
33+
}
34+
}

python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import experimental.dataflow.FlowTestUtil.LocalFlowStepTest

python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import experimental.dataflow.FlowTestUtil.MaximalFlowTest
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
def obfuscated_id(x):
2-
y = x
3-
z = y
4-
return z
1+
def obfuscated_id(x): #$ step="ControlFlowNode for FunctionExpr -> GSSA Variable obfuscated_id"
2+
y = x #$ step="ControlFlowNode for x -> SSA variable y" step="SSA variable x, l:1 -> ControlFlowNode for x"
3+
z = y #$ step="ControlFlowNode for y -> SSA variable z" step="SSA variable y, l:2 -> ControlFlowNode for y"
4+
return z #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> ControlFlowNode for z" step="SSA variable z, l:3 -> ControlFlowNode for z"
55

6-
a = 42
7-
b = obfuscated_id(a)
6+
a = 42 #$ step="ControlFlowNode for IntegerLiteral -> GSSA Variable a"
7+
b = obfuscated_id(a) #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> GSSA Variable b" flow="ControlFlowNode for FunctionExpr, l:1 -> ControlFlowNode for obfuscated_id" step="ControlFlowNode for obfuscated_id() -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> ControlFlowNode for obfuscated_id" step="GSSA Variable a, l:6 -> ControlFlowNode for a"

python/ql/test/experimental/dataflow/coverage/dataflowTest.expected

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import python
2+
import experimental.dataflow.FlowTestUtil.FlowTest
3+
import experimental.dataflow.testConfig
4+
5+
class DataFlowTest extends FlowTest {
6+
DataFlowTest() { this = "DataFlowTest" }
7+
8+
override string flowTag() { result = "flow" }
9+
10+
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
11+
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
12+
}
13+
}

0 commit comments

Comments
 (0)