Files
bikini-patchwork/tests/test_obfuscator.py
T
2026-06-04 04:46:22 -05:00

81 lines
3.3 KiB
Python

from __future__ import annotations
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
from patchwork import Obfuscator
EXAMPLES = ROOT / 'examples'
EXAMPLE_NAMES = ['hello', 'fizzbuzz', 'classes', 'stress', 'modern', 'future_annotations', 'literals']
SEEDS = [1, 7, 42, 1234, 999999]
def run(path: Path) -> str:
res = subprocess.run([sys.executable, str(path)], capture_output=True, text=True, timeout=20)
if res.returncode != 0:
raise RuntimeError(f'{path} exited {res.returncode}\nstderr:\n{res.stderr}')
return res.stdout
def check_one(name: str, seed: int) -> None:
src_path = EXAMPLES / f'{name}.py'
expected = run(src_path)
obf_src = Obfuscator(seed=seed).obfuscate(src_path.read_text(encoding='utf-8'))
obf_path = EXAMPLES / f'{name}_test_{seed}.py'
obf_path.write_text(obf_src, encoding='utf-8')
try:
actual = run(obf_path)
finally:
obf_path.unlink(missing_ok=True)
if actual != expected:
raise AssertionError(f'{name} seed={seed}: output mismatch\n--- expected ---\n{expected}--- actual ---\n{actual}')
def main() -> int:
fails = 0
for name in EXAMPLE_NAMES:
for seed in SEEDS:
try:
check_one(name, seed)
print(f'ok: {name:10s} seed={seed}')
except Exception as e:
fails += 1
print(f'FAIL: {name:10s} seed={seed}: {e}')
src = (EXAMPLES / 'hello.py').read_text(encoding='utf-8')
a = Obfuscator(seed=1).obfuscate(src)
b = Obfuscator(seed=2).obfuscate(src)
c = Obfuscator(seed=1).obfuscate(src)
if a == b:
print('FAIL: polymorphism (seed=1 vs seed=2 produced identical output)')
fails += 1
else:
print('ok: polymorphism (seeds 1 vs 2 differ)')
if a != c:
print('FAIL: reproducibility (same seed gave different output)')
fails += 1
else:
print('ok: reproducibility (seed=1 stable)')
literals_src = (EXAMPLES / 'literals.py').read_text(encoding='utf-8')
literals_obf = Obfuscator(seed=2026).obfuscate(literals_src)
if 'PATCHWORK_LITERAL_MARKER_9f8b6b7d' in literals_obf or 'PATCHWORK_BYTES_MARKER' in literals_obf:
print('FAIL: literal markers were present in obfuscated output')
fails += 1
else:
print('ok: literal markers absent from obfuscated output')
future_src = (EXAMPLES / 'future_annotations.py').read_text(encoding='utf-8')
for kwargs in ({'encrypt_strings': False}, {'opaque_predicates': False, 'junk_branches': False}):
try:
obf = Obfuscator(seed=77, **kwargs).obfuscate(future_src)
obf_path = EXAMPLES / f'future_annotations_options_{len(kwargs)}.py'
obf_path.write_text(obf, encoding='utf-8')
try:
if run(obf_path) != run(EXAMPLES / 'future_annotations.py'):
raise AssertionError('output mismatch')
finally:
obf_path.unlink(missing_ok=True)
print(f'ok: future annotations options {kwargs}')
except Exception as e:
fails += 1
print(f'FAIL: future annotations options {kwargs}: {e}')
print(f'\n{fails} failures' if fails else '\nall good')
return 1 if fails else 0
if __name__ == '__main__':
raise SystemExit(main())