Skip to content

Commit 4742481

Browse files
committed
Python: Consolidate "mutable default" tests
Moves the existing tests into the `ModificationOfParameterWithDefault` subdirectory which already contained a bunch more tests. In the process, I also removed some duplicated test cases.
1 parent 7e1dd38 commit 4742481

File tree

5 files changed

+93
-108
lines changed

5 files changed

+93
-108
lines changed

python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ edges
2828
| test.py:131:23:131:23 | ControlFlowNode for l | test.py:135:9:135:9 | ControlFlowNode for l |
2929
| test.py:138:15:138:15 | ControlFlowNode for l | test.py:140:9:140:9 | ControlFlowNode for l |
3030
| test.py:145:23:145:23 | ControlFlowNode for l | test.py:147:9:147:9 | ControlFlowNode for l |
31+
| test.py:153:25:153:25 | ControlFlowNode for x | test.py:154:5:154:5 | ControlFlowNode for x |
32+
| test.py:156:21:156:21 | ControlFlowNode for x | test.py:157:5:157:5 | ControlFlowNode for x |
33+
| test.py:159:27:159:27 | ControlFlowNode for y | test.py:160:25:160:25 | ControlFlowNode for y |
34+
| test.py:159:27:159:27 | ControlFlowNode for y | test.py:161:21:161:21 | ControlFlowNode for y |
35+
| test.py:160:25:160:25 | ControlFlowNode for y | test.py:153:25:153:25 | ControlFlowNode for x |
36+
| test.py:161:21:161:21 | ControlFlowNode for y | test.py:156:21:156:21 | ControlFlowNode for x |
37+
| test.py:181:28:181:28 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x |
38+
| test.py:181:28:181:28 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x |
39+
| test.py:194:18:194:18 | ControlFlowNode for x | test.py:195:28:195:28 | ControlFlowNode for x |
40+
| test.py:195:28:195:28 | ControlFlowNode for x | test.py:181:28:181:28 | ControlFlowNode for x |
41+
| test.py:197:18:197:18 | ControlFlowNode for x | test.py:198:28:198:28 | ControlFlowNode for x |
42+
| test.py:198:28:198:28 | ControlFlowNode for x | test.py:181:28:181:28 | ControlFlowNode for x |
3143
nodes
3244
| test.py:2:12:2:12 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
3345
| test.py:3:5:3:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
@@ -81,6 +93,20 @@ nodes
8193
| test.py:140:9:140:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
8294
| test.py:145:23:145:23 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
8395
| test.py:147:9:147:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
96+
| test.py:153:25:153:25 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
97+
| test.py:154:5:154:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
98+
| test.py:156:21:156:21 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
99+
| test.py:157:5:157:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
100+
| test.py:159:27:159:27 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
101+
| test.py:160:25:160:25 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
102+
| test.py:161:21:161:21 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
103+
| test.py:181:28:181:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
104+
| test.py:185:9:185:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
105+
| test.py:187:9:187:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
106+
| test.py:194:18:194:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
107+
| test.py:195:28:195:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
108+
| test.py:197:18:197:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
109+
| test.py:198:28:198:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
84110
subpaths
85111
#select
86112
| test.py:3:5:3:5 | ControlFlowNode for l | test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:2:12:2:12 | ControlFlowNode for l | default value |
@@ -106,3 +132,9 @@ subpaths
106132
| test.py:135:9:135:9 | ControlFlowNode for l | test.py:131:23:131:23 | ControlFlowNode for l | test.py:135:9:135:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:131:23:131:23 | ControlFlowNode for l | default value |
107133
| test.py:140:9:140:9 | ControlFlowNode for l | test.py:138:15:138:15 | ControlFlowNode for l | test.py:140:9:140:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:138:15:138:15 | ControlFlowNode for l | default value |
108134
| test.py:147:9:147:9 | ControlFlowNode for l | test.py:145:23:145:23 | ControlFlowNode for l | test.py:147:9:147:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:145:23:145:23 | ControlFlowNode for l | default value |
135+
| test.py:154:5:154:5 | ControlFlowNode for x | test.py:159:27:159:27 | ControlFlowNode for y | test.py:154:5:154:5 | ControlFlowNode for x | This expression mutates a $@. | test.py:159:27:159:27 | ControlFlowNode for y | default value |
136+
| test.py:157:5:157:5 | ControlFlowNode for x | test.py:159:27:159:27 | ControlFlowNode for y | test.py:157:5:157:5 | ControlFlowNode for x | This expression mutates a $@. | test.py:159:27:159:27 | ControlFlowNode for y | default value |
137+
| test.py:185:9:185:9 | ControlFlowNode for x | test.py:194:18:194:18 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:194:18:194:18 | ControlFlowNode for x | default value |
138+
| test.py:185:9:185:9 | ControlFlowNode for x | test.py:197:18:197:18 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:197:18:197:18 | ControlFlowNode for x | default value |
139+
| test.py:187:9:187:9 | ControlFlowNode for x | test.py:194:18:194:18 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:194:18:194:18 | ControlFlowNode for x | default value |
140+
| test.py:187:9:187:9 | ControlFlowNode for x | test.py:197:18:197:18 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:197:18:197:18 | ControlFlowNode for x | default value |

python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,59 @@ def sanitizer_negated(l = [1]):
148148
else:
149149
l.append(1)
150150
return l
151+
152+
# indirect modification of parameter with default
153+
def aug_assign_argument(x):
154+
x += ['x'] #$ modification=x
155+
156+
def mutate_argument(x):
157+
x.append('x') #$ modification=x
158+
159+
def indirect_modification(y = []):
160+
aug_assign_argument(y)
161+
mutate_argument(y)
162+
163+
def guarded_modification(z=[]):
164+
if z:
165+
z.append(0)
166+
return z
167+
168+
# This function causes a discrepancy between the
169+
# Python 2 and 3 versions of the analysis.
170+
# We comment it out until we have resoved the issue.
171+
#
172+
# def issue1143(expr, param=[]):
173+
# if not param:
174+
# return result
175+
# for i in param:
176+
# param.remove(i) # Mutation here
177+
178+
179+
# Type guarding of modification of parameter with default:
180+
181+
def do_stuff_based_on_type(x):
182+
if isinstance(x, str):
183+
x = x.split()
184+
elif isinstance(x, dict):
185+
x.setdefault('foo', 'bar') #$ modification=x
186+
elif isinstance(x, list):
187+
x.append(5) #$ modification=x
188+
elif isinstance(x, tuple):
189+
x = x.unknown_method()
190+
191+
def str_default(x="hello world"):
192+
do_stuff_based_on_type(x)
193+
194+
def dict_default(x={'baz':'quux'}):
195+
do_stuff_based_on_type(x)
196+
197+
def list_default(x=[1,2,3,4]):
198+
do_stuff_based_on_type(x)
199+
200+
def tuple_default(x=(1,2)):
201+
do_stuff_based_on_type(x)
202+
203+
# Modification of parameter with default (safe method)
204+
205+
def safe_method(x=[]):
206+
return x.count(42)

python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected

Lines changed: 0 additions & 44 deletions
This file was deleted.

python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.qlref

Lines changed: 0 additions & 1 deletion
This file was deleted.

python/ql/test/query-tests/Functions/general/functions_test.py

Lines changed: 5 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def ok3(x):
3636
def ok4(x = []):
3737
return len(x)
3838

39-
def mpd(x = []):
40-
x.append("x")
39+
40+
4141

4242

4343
def use_implicit_return_value(arg):
@@ -128,10 +128,10 @@ def mutli_return(arg):
128128
else:
129129
return do_nothing()
130130

131-
#Modification of parameter with default
132131

133-
def augassign(x = []):
134-
x += ["x"]
132+
133+
134+
135135

136136

137137
#ODASA 3658
@@ -144,61 +144,3 @@ def ok5():
144144
except ValueError as e:
145145
print(e)
146146
exit(EXIT_ERROR)
147-
148-
149-
150-
# indirect modification of parameter with default
151-
def aug_assign_argument(x):
152-
x += ['x']
153-
154-
def mutate_argument(x):
155-
x.append('x')
156-
157-
def indirect_modification(y = []):
158-
aug_assign_argument(y)
159-
mutate_argument(y)
160-
161-
def guarded_modification(z=[]):
162-
if z:
163-
z.append(0)
164-
return z
165-
166-
# This function causes a discrepancy between the
167-
# Python 2 and 3 versions of the analysis.
168-
# We comment it out until we have resoved the issue.
169-
#
170-
# def issue1143(expr, param=[]):
171-
# if not param:
172-
# return result
173-
# for i in param:
174-
# param.remove(i) # Mutation here
175-
176-
177-
# Type guarding of modification of parameter with default:
178-
179-
def do_stuff_based_on_type(x):
180-
if isinstance(x, str):
181-
x = x.split()
182-
elif isinstance(x, dict):
183-
x.setdefault('foo', 'bar')
184-
elif isinstance(x, list):
185-
x.append(5)
186-
elif isinstance(x, tuple):
187-
x = x.unknown_method()
188-
189-
def str_default(x="hello world"):
190-
do_stuff_based_on_type(x)
191-
192-
def dict_default(x={'baz':'quux'}):
193-
do_stuff_based_on_type(x)
194-
195-
def list_default(x=[1,2,3,4]):
196-
do_stuff_based_on_type(x)
197-
198-
def tuple_default(x=(1,2)):
199-
do_stuff_based_on_type(x)
200-
201-
# Modification of parameter with default (safe method)
202-
203-
def safe_method(x=[]):
204-
return x.count(42)

0 commit comments

Comments
 (0)