Repository navigation
Expand file tree
/
Copy pathtest_tsg_parser.py
More file actions
122 lines (109 loc) · 4.67 KB
/
Copy pathtest_tsg_parser.py
File metadata and controls
122 lines (109 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import unittest
import unittest.mock
import json
from semmle.logging import format_message
from semmle.python.parser.tsg_parser import Node, evaluate_string, read_tsg_python_output
class JsonOutputTest(unittest.TestCase):
def test_decodes_nodes_edges_and_attribute_values(self):
output = json.dumps(
[
{
"id": 0,
"edges": [
{
"sink": 1,
"attrs": {"body": {"type": "int", "int": 0}},
}
],
"attrs": {
"_kind": {"type": "string", "string": "Module"},
"_location": {
"type": "list",
"values": [
{"type": "int", "int": 0},
{"type": "int", "int": 0},
{"type": "int", "int": 1},
{"type": "int", "int": 0},
],
},
},
},
{
"id": 1,
"edges": [],
"attrs": {
"_kind": {"type": "string", "string": "Name"},
"variable": {
"type": "string",
"string": "caf\u00e9 \u26a0\ufe0f \U0001f4be",
},
"s": {
"type": "string",
"string": '"\u26a0\ufe0f problem %s: %s"',
},
"is_async": {"type": "bool", "bool": True},
"optional": {"type": "null"},
"_skip_to": {"type": "graphNode", "id": 0},
},
},
]
).encode("utf-8")
process = unittest.mock.Mock()
process.communicate.return_value = (output, None)
process.returncode = 0
with unittest.mock.patch(
"semmle.python.parser.tsg_parser.subprocess.Popen", return_value=process
):
node_attr, edge_attr = read_tsg_python_output(
"test.py", unittest.mock.Mock()
)
self.assertEqual(node_attr[1]["variable"], "caf\u00e9 \u26a0\ufe0f \U0001f4be")
self.assertEqual(node_attr[1]["s"], "\u26a0\ufe0f problem %s: %s")
self.assertIs(node_attr[1]["is_async"], True)
self.assertIsNone(node_attr[1]["optional"])
self.assertIsInstance(node_attr[1]["_skip_to"], Node)
self.assertEqual(node_attr[1]["_skip_to"].id, 0)
self.assertEqual(edge_attr, {0: {"body": [(0, 1)]}})
def test_evaluate_string_on_reported_value(self):
value = '"\u26a0\ufe0f problem %s: %s"'
self.assertEqual(evaluate_string(value), "\u26a0\ufe0f problem %s: %s")
def test_syntax_error_node_raises(self):
output = json.dumps(
[
{
"id": 0,
"edges": [],
"attrs": {
"_kind": {"type": "string", "string": "SyntaxErrorNode"},
"_location": {
"type": "list",
"values": [
{"type": "int", "int": 4},
{"type": "int", "int": 5},
{"type": "int", "int": 4},
{"type": "int", "int": 6},
],
},
"source": {"type": "string", "string": "!"},
},
}
]
).encode("utf-8")
process = unittest.mock.Mock()
process.communicate.return_value = (output, None)
process.returncode = 0
with unittest.mock.patch(
"semmle.python.parser.tsg_parser.subprocess.Popen", return_value=process
):
with self.assertRaises(SyntaxError) as raised:
read_tsg_python_output("test.py", unittest.mock.Mock())
self.assertEqual(raised.exception.lineno, 5)
self.assertEqual(raised.exception.offset, 5)
class FormatMessageTest(unittest.TestCase):
"""A pre-formatted log message may contain `%` directives coming from the analysed source, and
must not be `%`-formatted again."""
def test_no_arguments(self):
message = "Error while parsing value '%s: %s'"
self.assertEqual(format_message(message, ()), message)
def test_with_arguments(self):
self.assertEqual(format_message("%s and %s", ("a", "b")), "a and b")