Skip to content

Commit 5575b73

Browse files
committed
chore: add regression tests based on github issues
1 parent 4ca2910 commit 5575b73

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

tests/techniques/test_variable_renamer.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ def test_does_not_collect_builtin_names(self) -> None:
3131
assert "print" not in renameable
3232
assert "len" not in renameable
3333

34+
def test_does_not_collect_builtin_names_used_only_in_calls(self) -> None:
35+
"""Regression #10: ``int(…)``, ``str(…)``, etc. use Load context, not Store."""
36+
renameable = _collect(
37+
textwrap.dedent(
38+
"""\
39+
class A:
40+
def __init__(self):
41+
self.fps = int(25)
42+
self.tag = str(99)
43+
"""
44+
)
45+
)
46+
assert "int" not in renameable
47+
assert "str" not in renameable
48+
3449
def test_does_not_collect_imported_name(self) -> None:
3550
renameable = _collect("import os\npath = os.getcwd()")
3651
assert "os" not in renameable
@@ -107,6 +122,36 @@ def test_builtin_names_not_renamed(self) -> None:
107122
result = _apply(source)
108123
assert "len" in result
109124

125+
def test_builtin_type_converters_in_calls_not_renamed(self) -> None:
126+
"""Regression #10: call sites like ``int(25)`` must stay as builtins.
127+
128+
Only bound names are renamed; ``int`` / ``str`` in call position are
129+
:class:`ast.Load`, not collected, and must not become random ids.
130+
"""
131+
source = textwrap.dedent(
132+
"""\
133+
class A:
134+
def __init__(self):
135+
self.fps = int(25)
136+
self.tag = str(99)
137+
"""
138+
)
139+
result = _apply(source)
140+
assert "int(25)" in result
141+
assert "str(99)" in result
142+
tree = ast.parse(result)
143+
class_def = tree.body[0]
144+
assert isinstance(class_def, ast.ClassDef)
145+
init = class_def.body[0]
146+
assert isinstance(init, ast.FunctionDef)
147+
for stmt in init.body:
148+
assert isinstance(stmt, ast.Assign)
149+
call = stmt.value
150+
assert isinstance(call, ast.Call)
151+
func = call.func
152+
assert isinstance(func, ast.Name)
153+
assert func.id in ("int", "str")
154+
110155
def test_import_name_not_renamed(self) -> None:
111156
source = "import os\npath = os.getcwd()"
112157
result = _apply(source)
@@ -117,6 +162,55 @@ def test_dunder_not_renamed(self) -> None:
117162
result = _apply(source)
118163
assert "__name__" in result
119164

165+
def test_string_literal_unchanged_when_it_contains_renamed_identifier(self) -> None:
166+
"""Only :class:`ast.Name` nodes rename; string contents must not be touched.
167+
168+
A naive textual substitution could turn ``'my name is evil'`` into
169+
``'my <obfuscated> is evil'`` when the variable ``name`` is renamed.
170+
"""
171+
source = "name = 'my name is evil'\n"
172+
result = _apply(source)
173+
tree = ast.parse(result)
174+
assign = tree.body[0]
175+
assert isinstance(assign, ast.Assign)
176+
assert isinstance(assign.targets[0], ast.Name)
177+
assert assign.targets[0].id != "name"
178+
val = assign.value
179+
assert isinstance(val, ast.Constant)
180+
assert val.value == "my name is evil"
181+
182+
def test_name_main_guard_with_imports_preserves_name_dunder(self) -> None:
183+
"""Regression: __name__ in `if __name__ == '__main__'` must stay intact.
184+
185+
It is only ever loaded here, is excluded as a dunder/builtin from the
186+
rename map, and must not become a random identifier (would break the
187+
main guard).
188+
"""
189+
source = textwrap.dedent(
190+
"""\
191+
from file1 import f1
192+
from file2 import f2
193+
194+
if __name__ == "__main__":
195+
f1()
196+
f2()
197+
print("f3")
198+
"""
199+
)
200+
result = _apply(source)
201+
assert "__name__" in result
202+
assert "__main__" in result
203+
# Imported symbols are not renamed; calls must still match imports.
204+
assert "f1()" in result
205+
assert "f2()" in result
206+
tree = ast.parse(result)
207+
if_node = tree.body[2]
208+
assert isinstance(if_node, ast.If)
209+
test = if_node.test
210+
assert isinstance(test, ast.Compare)
211+
assert isinstance(test.left, ast.Name)
212+
assert test.left.id == "__name__"
213+
120214
def test_function_name_is_renamed(self) -> None:
121215
source = "def compute(): return 42"
122216
result = _apply(source)

0 commit comments

Comments
 (0)