126 lines
9.2 KiB
Python
126 lines
9.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Native gate record contracts and negative cases, without input or engine use."""
|
|
import copy
|
|
from pathlib import Path
|
|
import sys
|
|
import unittest
|
|
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'tools'))
|
|
from ordinary_gate_evidence import parse_gate_record,parse_gate_records,join_gate_snapshots,validate_gate_geometry
|
|
|
|
NONCE='gateTrial123'
|
|
|
|
def fixture():
|
|
lines=[f'SCRIPT : ERR INPUT OBSERVE: run={NONCE} sample=0 real=1000 world=10000 QUEUED']
|
|
for i in range(1,31):
|
|
t=1000+i*110;w=10000+i*110
|
|
lines.append(f'SCRIPT : ERR INPUT OBSERVE: run={NONCE} sample={i} real={t} world={w} SAMPLE origin=<6088.5,211.389,7158.5> forward=0 input=<0,0,0> velocity=<0,0,0> inventory=0')
|
|
if i==1:
|
|
lines.append(f'SCRIPT : ERR LOOK OBSERVE: run={NONCE} sample={i} real={t} BASIS native-player-camera-world-transform')
|
|
lines.append(f'SCRIPT : ERR LOOK OBSERVE: run={NONCE} sample={i} real={t} SAMPLE direction=<0,0,1> camera=<6088.58,213.019,7158.56> body=<6088.5,211.389,7158.5> bodyForward=<0,0,1> turn=<0,0,0>')
|
|
if i==1:
|
|
lines.append(f'SCRIPT : ERR GATE OBSERVE: run={NONCE} sample={i} real={t} BASIS registered-prison-lock-native-interaction')
|
|
lines.append(f'SCRIPT : ERR GATE OBSERVE: run={NONCE} sample={i} real={t} SAMPLE phase=1 selected=0 context=0 cachedPerformable=0 progressBound=0 performing=0 progress=0 duration=4 pressed=0')
|
|
lines.append(f'SCRIPT : ERR GATE OBSERVE: run={NONCE} sample={i} real={t} GEOMETRY body=<6088.5,211.389,7158.5> context=<6092.77,213.226,7154> radius=2 doorState=0 doorControl=0 prison=<6090,211.444,7160> gate=<6090,211.344,7154> gateForward=<0,0,1>')
|
|
if i==19:
|
|
lines.append(f'SCRIPT : ERR INPUT OBSERVE: run={NONCE} sample={i} real={t+1} world={w} READY')
|
|
lines.append(f'SCRIPT : ERR GATE OBSERVE: run={NONCE} sample=31 real=4410 CANCELLED native-player-or-prison-context-lost')
|
|
lines.append(f'SCRIPT : ERR LOOK OBSERVE: run={NONCE} sample=31 real=4410 CANCELLED menu-opened')
|
|
return '\n'.join(lines)+'\n'
|
|
|
|
def matching(raw,text):
|
|
return next(line for line in raw.splitlines() if text in line)
|
|
|
|
class GateEvidenceTests(unittest.TestCase):
|
|
def reject(self,raw,start=20,end=25):
|
|
result=validate_gate_geometry(raw,NONCE,start,end)
|
|
self.assertFalse(result['verified'],result);self.assertTrue(result['errors'])
|
|
def test_native_shape_parse_join_and_geometry_only(self):
|
|
raw=fixture();parsed=parse_gate_records(raw,NONCE);joined=join_gate_snapshots(raw,NONCE)
|
|
self.assertEqual(len(parsed['snapshots']),30)
|
|
self.assertEqual(len(parsed['records']),62)
|
|
self.assertEqual(joined['snapshots'][20]['input']['real_ms'],3200)
|
|
self.assertEqual(joined['snapshots'][20]['look']['body'],joined['snapshots'][20]['geometry']['body'])
|
|
result=validate_gate_geometry(raw,NONCE,20,25)
|
|
self.assertTrue(result['verified'],result)
|
|
self.assertEqual(result['snapshot_count'],6)
|
|
self.assertFalse(result['approach_verified']);self.assertFalse(result['held_action_verified'])
|
|
self.assertEqual(result['radius'],2)
|
|
self.assertEqual(result['prison'],[6090,211.444,7160])
|
|
self.assertTrue(validate_gate_geometry(raw,NONCE)['verified'])
|
|
self.assertIsNone(parse_gate_record('irrelevant native log line',NONCE))
|
|
def test_no_success_inferred_from_native_selected_or_full_progress(self):
|
|
raw=fixture().replace('selected=0 context=0 cachedPerformable=0 progressBound=0 performing=0 progress=0 duration=4 pressed=0',
|
|
'selected=1 context=1 cachedPerformable=1 progressBound=1 performing=1 progress=4 duration=4 pressed=1')
|
|
result=validate_gate_geometry(raw,NONCE,20,25)
|
|
self.assertTrue(result['verified'],result)
|
|
self.assertFalse(result['held_action_verified']);self.assertFalse(result['approach_verified'])
|
|
def test_malformed_foreign_unknown_and_numeric_records_rejected(self):
|
|
raw=fixture()
|
|
record=matching(raw,'ERR GATE OBSERVE: run='+NONCE+' sample=20 real=3200 SAMPLE')
|
|
for old,new in (('run='+NONCE,'run=foreign'),('phase=1','phase=3'),('selected=0','selected=2'),
|
|
('duration=4','duration=5'),('progress=0','progress=nan'),('progress=0','progress=1e999'),
|
|
('pressed=0','pressed=-1'),('progressBound=0','progressBound=1'),('performing=0','performing=1'),
|
|
('cachedPerformable=0','cachedPerformable=1'),('SAMPLE phase','UNKNOWN phase'),
|
|
('OBSERVE: ','OBSERVE:')):
|
|
with self.subTest(new=new):self.reject(raw.replace(record,record.replace(old,new)))
|
|
geometry=matching(raw,'sample=20 real=3200 GEOMETRY')
|
|
for old,new in (('radius=2','radius=0'),('radius=2','radius=11'),('doorState=0','doorState=2'),
|
|
('gateForward=<0,0,1>','gateForward=<0,0,0>'),('gateForward=<0,0,1>','gateForward=<0,0,2>'),
|
|
('gateForward=<0,0,1>','gateForward=<0,1,0>'),('body=<6088.5,211.389,7158.5>','body=<nan,0,1>')):
|
|
self.reject(raw.replace(geometry,geometry.replace(old,new)))
|
|
def test_pair_order_duplicates_gaps_and_missing_ack_refused(self):
|
|
raw=fixture();sample=matching(raw,'sample=20 real=3200 SAMPLE phase');geometry=matching(raw,'sample=20 real=3200 GEOMETRY')
|
|
for changed in (raw.replace(sample+'\n',''),raw.replace(geometry+'\n',''),raw.replace(sample,sample+'\n'+sample),
|
|
raw.replace(sample+'\n'+geometry,geometry+'\n'+sample),
|
|
raw.replace(geometry,geometry.replace('real=3200','real=3201')),
|
|
raw.replace(geometry,geometry.replace('sample=20','sample=19')),
|
|
'\n'.join(line for line in raw.splitlines() if 'BASIS registered-prison' not in line)):
|
|
self.reject(changed)
|
|
def test_native_three_centimetre_cross_api_difference_is_bounded(self):
|
|
raw=fixture();pose=matching(raw,'ERR LOOK OBSERVE: run='+NONCE+' sample=22 real=3420 SAMPLE')
|
|
accepted=raw.replace(pose,pose.replace('body=<6088.5,211.389,7158.5>','body=<6088.5,211.389,7158.47>'))
|
|
self.assertTrue(validate_gate_geometry(accepted,NONCE,20,25)['verified'])
|
|
self.reject(raw.replace(pose,pose.replace('body=<6088.5,211.389,7158.5>','body=<6088.5,211.389,7158.44>')))
|
|
geometry=matching(raw,'sample=22 real=3420 GEOMETRY')
|
|
self.reject(raw.replace(geometry,geometry.replace('body=<6088.5,211.389,7158.5>','body=<6088.5,211.389,7158.52>')))
|
|
def test_geometry_drift_and_clock_mismatch_refused(self):
|
|
raw=fixture();geometry=matching(raw,'sample=22 real=3420 GEOMETRY')
|
|
for old,new in (('context=<6092.77,213.226,7154>','context=<6092.80,213.226,7154>'),
|
|
('prison=<6090,211.444,7160>','prison=<6090.02,211.444,7160>'),
|
|
('gate=<6090,211.344,7154>','gate=<6090,211.344,7154.02>'),('radius=2','radius=2.01'),
|
|
('doorState=0','doorState=0.01'),('doorControl=0','doorControl=0.01'),
|
|
('gateForward=<0,0,1>','gateForward=<0.01,0,0.99995>')):
|
|
self.reject(raw.replace(geometry,geometry.replace(old,new)))
|
|
self.reject(raw.replace('sample=22 real=3420 SAMPLE phase','sample=22 real=3421 SAMPLE phase').replace('sample=22 real=3420 GEOMETRY','sample=22 real=3421 GEOMETRY'))
|
|
def test_phase_menu_and_cancellation_span(self):
|
|
raw=fixture();sample=matching(raw,'sample=22 real=3420 SAMPLE phase')
|
|
phase2=raw.replace(sample,sample.replace('phase=1','phase=2'))
|
|
self.reject(phase2)
|
|
self.assertTrue(validate_gate_geometry(phase2,NONCE,23,25)['verified'])
|
|
inp=matching(raw,'sample=22 real=3420 world=12420 SAMPLE origin')
|
|
self.reject(raw.replace(inp,inp.replace('inventory=0','inventory=1')))
|
|
self.reject(raw.replace('sample=31 real=4410 CANCELLED native-player-or-prison-context-lost','sample=24 real=3640 CANCELLED native-player-or-prison-context-lost'))
|
|
self.reject(raw+'SCRIPT : ERR GATE OBSERVE: run='+NONCE+' sample=31 real=4410 CANCELLED explicit-scope-lost\n')
|
|
def test_invalid_span_types_and_unknown_nonce(self):
|
|
raw=fixture()
|
|
for start,end in ((True,25),(20,False),(20,20),(25,20),(18,25),(20,451),(20,31),('20',25)):
|
|
result=validate_gate_geometry(raw,NONCE,start,end);self.assertFalse(result['verified'],result)
|
|
for nonce in (None,'','../unsafe','a'*33):
|
|
self.assertFalse(validate_gate_geometry(raw,nonce,20,25)['verified'])
|
|
def test_readonly_body_approach_not_credited_as_success(self):
|
|
raw=fixture()
|
|
for index in range(20,31):
|
|
real=1000+index*110;body=f'<6088.5,211.389,{7158.5-(index-19)*.1}>'
|
|
lines=[]
|
|
for line in raw.splitlines():
|
|
if f'sample={index} real={real} ' in line:
|
|
line=line.replace('<6088.5,211.389,7158.5>',body)
|
|
lines.append(line)
|
|
raw='\n'.join(lines)+'\n'
|
|
result=validate_gate_geometry(raw,NONCE,20,25)
|
|
self.assertTrue(result['verified'],result)
|
|
self.assertLess(result['final_context_distance_metres'],result['initial_context_distance_metres'])
|
|
self.assertFalse(result['approach_verified']);self.assertFalse(result['held_action_verified'])
|
|
|
|
if __name__=='__main__':unittest.main()
|