mirror of
https://github.com/bikini/patchwork
synced 2026-06-27 08:08:41 +00:00
81 lines
3.3 KiB
Python
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())
|