Skip to content

Commit 2c28c16

Browse files
committed
tests: update fixtures search
1 parent 60af988 commit 2c28c16

11 files changed

Lines changed: 150 additions & 138 deletions

File tree

tests/obfuscator/conftest.py

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from __future__ import annotations
44

5+
import builtins
56
import io
7+
import warnings
68
from base64 import b64decode
79
from dataclasses import dataclass, field
810
from pathlib import Path
@@ -58,6 +60,8 @@
5860
)
5961
from pof.utils.tokens import untokenize
6062

63+
from .utils import exec_capture
64+
6165
FIXTURES_DIR = Path(__file__).parent / "fixtures"
6266

6367

@@ -93,15 +97,21 @@ class SkipEntry:
9397
"*",
9498
"Fails: replaces inner function names with globals() lookups (KeyError on nested scope)",
9599
),
100+
# TODO: fix all
96101
SkipEntry(
97102
"IPv6Obfuscator",
98-
"getattr",
99-
"Fails: binascii.Error on odd-length source from getattr fixture",
103+
"*",
104+
"Fails: binascii.Error on odd-length source",
100105
),
101106
SkipEntry(
102107
"UUIDObfuscator",
103-
"getattr",
104-
"Fails: binascii.Error on odd-length source from getattr fixture",
108+
"*",
109+
"Fails: binascii.Error on odd-length source",
110+
),
111+
SkipEntry(
112+
"MACObfuscator",
113+
"*",
114+
"Fails: binascii.Error on odd-length source",
105115
),
106116
]
107117

@@ -212,56 +222,33 @@ class SkipEntry:
212222
ObfuscatorEntry(TokensObfuscator, "TokensObfuscator", "other"),
213223
]
214224

215-
FIXTURES: list[SourceFixture] = [
216-
SourceFixture(
217-
name="simple",
218-
path=str(FIXTURES_DIR / "simple.py"),
219-
expected_output="Hello, world!\n7\nnegative\nzero\npositive\ndone\n",
220-
),
221-
SourceFixture(
222-
name="moderate",
223-
path=str(FIXTURES_DIR / "moderate.py"),
224-
expected_output=(
225-
"[12, 75]\n"
226-
"[('Circle', 75), ('Rectangle', 12)]\n"
227-
"['Circle', 'Rectangle']\n"
228-
"Total shapes: 2\n"
229-
"Rectangle: 12\n"
230-
"Circle: 75\n"
231-
"Sum: 87\n"
232-
"caught division error\n"
233-
"cleanup done\n"
234-
),
235-
),
236-
SourceFixture(
237-
name="complex",
238-
path=str(FIXTURES_DIR / "complex.py"),
239-
expected_output=(
240-
"10\n12\n10\n"
241-
"[0, 1, 4, 9, 16]\n"
242-
"3\n3\n4\n4\n"
243-
"[15, 20, 25, 30]\n"
244-
"105\n"
245-
"2\ndone\n"
246-
"[2, 4, 6, 8]\n"
247-
"stopped at 3\n"
248-
"0:alpha\n1:beta\n2:gamma\n"
249-
"16.4\n"
250-
),
251-
),
252-
SourceFixture(
253-
name="multiline_strings",
254-
path=str(FIXTURES_DIR / "multiline_strings.py"),
255-
expected_output=(
256-
"helloworld\nfoobar\nonetwothree\nhelloworld\nhelloworld\nabc\n"
257-
),
258-
),
259-
SourceFixture(
260-
name="getattr",
261-
path=str(FIXTURES_DIR / "getattr.py"),
262-
expected_output="1\n1\n2\n",
263-
),
264-
]
225+
226+
def discover_fixtures() -> list[SourceFixture]:
227+
"""Scan fixtures directory for .py files, execute each, and capture expected output."""
228+
fixtures: list[SourceFixture] = []
229+
for path in sorted(FIXTURES_DIR.glob("*.py"), key=lambda p: p.stem):
230+
if path.name == "__init__.py":
231+
continue
232+
try:
233+
source = path.read_text()
234+
expected_output = exec_capture(source, {"__builtins__": builtins})
235+
except Exception as exc: # noqa: BLE001
236+
warnings.warn(
237+
f"Skipping fixture {path.name}: {exc}",
238+
stacklevel=1,
239+
)
240+
continue
241+
fixtures.append(
242+
SourceFixture(
243+
name=path.stem,
244+
path=str(path),
245+
expected_output=expected_output,
246+
)
247+
)
248+
return fixtures
249+
250+
251+
FIXTURES: list[SourceFixture] = discover_fixtures()
265252

266253

267254
def get_obfuscator_callable(
Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# Language features: stdlib imports, nested functions, lambdas,
2-
# multi-line strings, generators, all prior features
3-
41
import math
52
import itertools
63

@@ -18,10 +15,6 @@ def multiply(x):
1815
print(double(5))
1916
print(triple(4))
2017

21-
# Lambda
22-
transform = lambda x: x * x + 1
23-
print(transform(3))
24-
2518
# Generator expression
2619
squares_gen = (i * i for i in range(5))
2720
print(list(squares_gen))
@@ -41,53 +34,13 @@ def multiply(x):
4134
print(len(pairs))
4235

4336

44-
# Class with decorator and comprehensions
45-
def validate(func):
46-
def wrapper(*args, **kwargs):
47-
return func(*args, **kwargs)
48-
49-
return wrapper
50-
51-
52-
def validate2(func):
53-
def wrapper(*args, **kwargs):
54-
return func(*args, **kwargs)
55-
56-
return wrapper
57-
58-
59-
@validate2
60-
def validate3(func):
61-
@validate
62-
def wrapper(*args, **kwargs):
63-
return func(*args, **kwargs)
64-
65-
return wrapper
66-
67-
6837
class DataProcessor:
6938
def __init__(self, data):
7039
self.data = data
7140

72-
@validate
7341
def filtered(self, threshold):
7442
return [x for x in self.data if x > threshold]
7543

76-
@validate
77-
@validate2
78-
def two_decorators(self):
79-
return 1
80-
81-
@validate
82-
@staticmethod
83-
@validate2
84-
def three_decorators():
85-
return 1
86-
87-
@validate3
88-
def foo():
89-
pass
90-
9144
def stats(self):
9245
total = sum(self.data)
9346
count = len(self.data)
@@ -124,8 +77,3 @@ def stats(self):
12477
items = ["alpha", "beta", "gamma"]
12578
for idx, item in enumerate(items):
12679
print(f"{idx}:{item}")
127-
128-
foo = 1 + 2
129-
foo += 1.2 + 2.2
130-
foo += 10**1
131-
print(foo)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
def validate(func):
2+
print("validate outer")
3+
def wrapper(*args, **kwargs):
4+
print("validate")
5+
return func(*args, **kwargs)
6+
7+
return wrapper
8+
9+
10+
def validate2(func):
11+
print("validate2 outer")
12+
def wrapper(*args, **kwargs):
13+
print("validate2")
14+
return func(*args, **kwargs)
15+
16+
return wrapper
17+
18+
19+
@validate2
20+
def validate3(func):
21+
print("validate3 outer")
22+
@validate
23+
def wrapper(*args, **kwargs):
24+
print("validate3")
25+
return func(*args, **kwargs)
26+
27+
return wrapper
28+
29+
30+
class DataProcessor:
31+
@validate
32+
def filtered(self):
33+
return "filtered"
34+
35+
@validate
36+
@validate2
37+
def two_decorators(self):
38+
return "two_decorators"
39+
40+
@validate
41+
@staticmethod
42+
@validate2
43+
def three_decorators():
44+
return "three_decorators"
45+
46+
@validate3
47+
def foo(self):
48+
return "foo"
49+
50+
d = DataProcessor()
51+
print(d.filtered())
52+
print(d.two_decorators())
53+
print(DataProcessor.three_decorators())
54+
print(d.foo())

tests/obfuscator/fixtures/getattr.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,22 @@ class Foo:
66
b = getattr(Foo, "bar")
77
print(b)
88

9+
c = Foo.__dict__["bar"]
10+
print(c)
11+
12+
# TODO: enable?
13+
# d = Foo.__dict__.get("bar")
14+
# print(d)
15+
16+
# TODO: enable?
17+
# e = Foo.__dict__.__getitem__("bar")
18+
# print(e)
19+
920
setattr(Foo, "bar", 2)
1021
print(Foo.bar)
22+
23+
delattr(Foo, "bar")
24+
try:
25+
print(Foo.bar)
26+
except AttributeError:
27+
print("AttributeError caught")
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import math
2+
3+
localmath = math
4+
floorval = localmath.floor(3.2)
5+
print(floorval)
6+
7+
def ceil(a):
8+
print("LOCAL CEIL")
9+
10+
print(math.ceil(3.2))
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
transform = lambda x: x * x + 1
2+
print(transform(3))
3+
print(transform(4))
4+
print(transform(5))

tests/obfuscator/fixtures/moderate.py

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
# Language features: classes, inheritance, decorators, comprehensions,
2-
# try/except/finally, .format(), for/while loops
3-
4-
5-
def log_call(func):
6-
def wrapper(*args, **kwargs):
7-
result = func(*args, **kwargs)
8-
return result
9-
10-
return wrapper
11-
12-
131
class Shape:
142
def __init__(self, name):
153
self.name = name
@@ -27,7 +15,6 @@ def __init__(self, width, height):
2715
self.width = width
2816
self.height = height
2917

30-
@log_call
3118
def area(self):
3219
return self.width * self.height
3320

@@ -55,26 +42,12 @@ def area(self):
5542
unique_types = {type(s).__name__ for s in shapes}
5643
print(sorted(unique_types))
5744

58-
# String formatting
59-
msg = "Total shapes: {}".format(len(shapes))
60-
print(msg)
61-
62-
# For loop
6345
for s in shapes:
6446
print("{}: {}".format(s.name, s.area()))
6547

66-
# While loop
6748
count = 0
6849
total = 0
6950
while count < len(areas):
7051
total = total + areas[count]
7152
count = count + 1
7253
print("Sum: {}".format(total))
73-
74-
# Try/except/finally
75-
try:
76-
result = 10 // 0
77-
except ZeroDivisionError:
78-
print("caught division error")
79-
finally:
80-
print("cleanup done")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
print(42 - 2)
2+
3+
print(42 * 120)
4+
5+
print(42 / 2)
6+
7+
print(10**5)
8+
9+
foo = 1 + 2
10+
foo += 1.2 + 2.2
11+
foo += 10**1
12+
print(foo)

tests/obfuscator/fixtures/simple.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
# Language features: functions, string concatenation, arithmetic,
2-
# conditionals, for loop, print statements
3-
4-
51
def greet(name):
62
return "Hello, " + name + "!"
73

tests/obfuscator/fixtures/multiline_strings.py renamed to tests/obfuscator/fixtures/strings.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
# Language features: implicit string concatenation (multi-line and single-line)
1+
print("Hello, world!")
2+
3+
msg = "Hello, {}".format("world!")
4+
print(msg)
5+
6+
# multi-line strings/split strings
27
a = ("hello"
38
"world")
49
print(a)

0 commit comments

Comments
 (0)