assistance-engine/scratches/pseco/synthetic_dataset/mbap_tester.py

229 lines
8.4 KiB
Python

#!/usr/bin/env python3
"""
Simple MBAP test harness.
- Loads `data/raw/code/mbap.json`
- For each entry with `code` and `test_list`, runs a heuristic mock AVAP executor
- Compares returned `result` against each test's expected value and prints a summary
Note: This is a heuristic mock executor — it supports many common AVAP idioms but
is not a full AVAP interpreter. It aims to be useful for quick verification.
"""
import json
import re
import sys
import hashlib
import random
import string
from pathlib import Path
MBAP_PATH = Path(__file__).resolve().parents[1] / "data" / "raw" / "code" / "mbap.json"
def load_mbap(path: Path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
def transform_avap_to_python(code: str) -> str:
lines = code.splitlines()
out_lines = []
for raw in lines:
line = raw.strip()
if not line:
continue
# remove addParam(...) calls
if re.match(r'addParam\(', line):
continue
# getListLen(var, lenvar) -> lenvar = len(var)
m = re.match(r'getListLen\(([^,]+),\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append(f"{m.group(2).strip()} = len({m.group(1).strip()})")
continue
# itemFromList(list, idx, var) -> var = list[idx]
m = re.match(r'itemFromList\(([^,]+),\s*([^,]+),\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append(f"{m.group(3).strip()} = {m.group(1).strip()}[{m.group(2).strip()}]")
continue
# AddVariableToJSON(idx, value, result) -> result.append(value)
m = re.match(r'AddVariableToJSON\(([^,]+),\s*([^,]+),\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append(f"{m.group(3).strip()}.append({m.group(2).strip()})")
continue
# startLoop(i, s, e) -> for i in range(s, e+1):
m = re.match(r'startLoop\(([^,]+),\s*([^,]+),\s*([^,]+)\)', line)
if m:
out_lines.append(f"for {m.group(1).strip()} in range({m.group(2).strip()}, {m.group(3).strip()}+1):")
continue
# simple else/end tokens
if line.startswith('else()'):
out_lines.append('else:')
continue
if line.startswith('endLoop') or line == 'end()':
continue
# if(a, b, "op")
m = re.match(r'if\(([^,]*),\s*([^,]*),\s*"([^"]+)"\)', line)
if m:
a = m.group(1).strip()
b = m.group(2).strip()
op = m.group(3).strip()
if op in ('==', '!=', '>', '<', '>=', '<='):
out_lines.append(f"if {a} {op} {b}:")
else:
# treat as raw expression
out_lines.append(f"if {op}:")
continue
# addResult(x) -> output = x
m = re.match(r'addResult\(([^)]+)\)', line)
if m:
out_lines.append(f"output = {m.group(1).strip()}")
continue
# encodeSHA256(src, dst)
m = re.match(r'encodeSHA256\(([^,]+),\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append("import hashlib")
out_lines.append(f"{m.group(2)} = hashlib.sha256(str({m.group(1)}).encode()).hexdigest()")
continue
# encodeMD5
m = re.match(r'encodeMD5\(([^,]+),\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append("import hashlib")
out_lines.append(f"{m.group(2)} = hashlib.md5(str({m.group(1)}).encode()).hexdigest()")
continue
# randomString(len, token)
m = re.match(r'randomString\(([^,]+),\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append(f"{m.group(2)} = ''.join(__random.choice(__letters) for _ in range(int({m.group(1)})))")
continue
# getRegex(text, pattern, matches) -> use python re.findall
m = re.match(r'getRegex\(([^,]+),\s*"([^"]+)",\s*([A-Za-z_][A-Za-z0-9_]*)\)', line)
if m:
out_lines.append(f"{m.group(3)} = re.findall(r'{m.group(2)}', str({m.group(1)}))")
continue
# RequestGet/Post -> mock
if line.startswith('RequestGet(') or line.startswith('RequestPost('):
out_lines.append("response = {'_mock': 'response'}")
out_lines.append("output = response")
continue
# function foo(...) { -> def foo(...):
m = re.match(r'function\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)\s*\{', line)
if m:
args = m.group(2).strip()
out_lines.append(f"def {m.group(1)}({args}):")
continue
# return(...) -> return ...
m = re.match(r'return\(([^)]+)\)', line)
if m:
out_lines.append(f"return {m.group(1).strip()}")
continue
# simple replacements to make many lines valid python-ish
line = line.replace('&&', 'and').replace('||', 'or')
# remove trailing semicolons if any
if line.endswith(';'):
line = line[:-1]
out_lines.append(line)
# Ensure we always expose 'output' variable at the end if not set
py = '\n'.join(out_lines)
guard = "\nif 'output' not in locals():\n output = locals().get('result', None)\n"
return py + guard
def mock_execute(code: str, inputs: dict):
"""Heuristic mock executor:
- Creates a restricted locals dict with provided `inputs`
- Transforms AVAP-ish code into Python-ish code
- Executes it and returns {'result': output} or {'error': msg}
"""
# prepare locals
globs = {"__builtins__": {}}
locals_: dict = {}
# expose helpers
locals_['re'] = re
locals_['hashlib'] = hashlib
locals_['__random'] = random
locals_['__letters'] = string.ascii_letters + string.digits
# copy input params into locals
if isinstance(inputs, dict):
for k, v in inputs.items():
locals_[k] = v
# transform
py = transform_avap_to_python(code)
try:
exec(py, globs, locals_)
output = locals_.get('output', None)
return {'result': output}
except Exception as e:
return {'error': str(e), 'transformed': py}
def canonical_expected(test_item):
"""Try to extract expected value from a test item.
Accepts several common shapes: {'input':..., 'expected':...},
{'in':..., 'out':...}, or simple dicts.
"""
if isinstance(test_item, dict):
if 'expected' in test_item:
return test_item['expected']
if 'output' in test_item:
return test_item['output']
if 'result' in test_item:
return test_item['result']
# some datasets embed expected as the last item
if 'expected_result' in test_item:
return test_item['expected_result']
return None
def canonical_input(test_item):
if isinstance(test_item, dict):
if 'input' in test_item:
return test_item['input']
if 'in' in test_item:
return test_item['in']
# if dict and contains params keys other than expected, assume it's the input itself
# heuristics: if contains keys other than 'expected'/'output' treat as params
keys = set(test_item.keys())
if not keys.intersection({'expected','output','result','description'}):
return test_item
return {}
def run_all(path: Path):
data = load_mbap(path)
total = 0
passed = 0
for entry in data:
task_id = entry.get('task_id')
code = entry.get('code')
tests = entry.get('test_list') or []
if not code:
continue
print(f"Task {task_id}: processing {len(tests)} tests")
for ti, test_item in enumerate(tests):
total += 1
inp = canonical_input(test_item)
expected = canonical_expected(test_item)
res = mock_execute(code, inp)
if 'error' in res:
print(f" test #{ti+1}: ERROR -> {res['error']}")
# optionally show transformed code for debugging
# print(res.get('transformed'))
continue
got = res.get('result')
ok = (expected is None) or (got == expected)
if ok:
passed += 1
status = 'PASS'
else:
status = 'FAIL'
print(f" test #{ti+1}: {status} | expected={expected!r} got={got!r}")
print(f"\nSummary: passed {passed}/{total} tests")
if __name__ == '__main__':
p = MBAP_PATH
if not p.exists():
print(f"mbap.json not found at {p}")
sys.exit(1)
run_all(p)