from pathlib import Path
import json, os, tempfile, runpy, contextlib, io, inspect, struct, time
from lupa.luajit21 import LuaRuntime
R=Path(__file__).resolve().parents[1]
def to_lua(L,v):
 if isinstance(v,dict):return L.table_from({k:to_lua(L,x) for k,x in v.items()})
 if isinstance(v,list):return L.table_from([to_lua(L,x) for x in v])
 return v
L=LuaRuntime(unpack_returned_tuples=True)
L.globals().LIVE_API=to_lua(L,json.loads((R/'tests/live-api-t1-failure.json').read_text())['api_functions'])
L.globals().SOURCE=str(R/'src');L.globals().FIXTURE=to_lua(L,json.loads((R/'tests/three-mechs-identities.json').read_text()))
with tempfile.TemporaryDirectory() as tmp:
 os.environ['APPDATA']=tmp
 result=L.execute((R/'tests/test_spatial.lua').read_text())
report=dict(result.items());report['actual_export_inventory_used']=True;report['vector_components_api']='Vector3.to_elements'
# Test real arms.lua roster validation over typed sparse-memory fixtures.
with contextlib.redirect_stdout(io.StringIO()):old=runpy.run_path(str(R/'tests/test_hud.py'))
gl=old['arm_env'].__globals__.copy()
source=inspect.getsource(old['arm_env']).replace('return A,mech,model','return A,mech,model,m,N')
exec(source,gl)
MECH,ARM=old['MECH'],old['ARM']
A,mech,model,m,N=gl['arm_env']([(MECH,1,77),(MECH,4,78),(MECH,7,79),(ARM,2,5),(ARM,3,6),(ARM,5,7),(ARM,6,8),(ARM,8,10),(ARM,9,11)])
_,link,meta=A[b'discover'](mech,model)
assert link==b'AMBIGUOUS' and meta[b'mechs']==3 and meta[b'candidates']==6
assert A[b'verify'](meta)
original=m.read(0x60000000,8);m.put(0x60000000,struct.pack('<II',99,0));assert not A[b'verify'](meta);m.put(0x60000000,original);assert A[b'verify'](meta)
original=m.read(0x61000000,8);m.put(0x61000000,struct.pack('<Q',0x63000000));assert not A[b'verify'](meta);m.put(0x61000000,original)
original=m.read(0x30001030,20);m.put(0x30001030,struct.pack('<QIII',0x60000000,32,0xffffffff,1));assert not A[b'verify'](meta);m.put(0x30001030,original)
start=time.perf_counter()
for _ in range(200):
 _,_,meta=A[b'discover'](mech,model);assert A[b'verify'](meta)
report['roster_mutation_tests']=True
report['synthetic_discovery_and_verify_mean_ms']=(time.perf_counter()-start)*1000/200
report['discovery_bytes']=meta[b'bytes'];report['discovery_calls']=meta[b'calls']
report['live_performance_measured']=False
(R/'validation/spatial-tests.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report,indent=2))
