Files
EscapistsReintroduced/tests/test_relative_look_runner.py
T

75 lines
5.2 KiB
Python

"""Optional mouse-proof launch and evidence boundaries; never launch a display."""
import copy
import json
from pathlib import Path
import sys
import tempfile
from types import SimpleNamespace, ModuleType
import unittest
from unittest.mock import patch
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'tools'))
import headless_game as r
import test_headless_input_exercise_runner as fixtures
from test_headless_input_exercise_runner import NONCE
class LookRunner(unittest.TestCase):
def test_optin_requires_all_existing_input_guards_before_side_effects(self):
valid=dict(exercise_relative_look=True,exercise_player_input=True,observe_player_input=True,inspect_headless_display=True,project='chat',settle=50)
r.validate_input_exercise(SimpleNamespace(**valid))
for field,value in [('exercise_player_input',False),('observe_player_input',False),('inspect_headless_display',False),('project',r.CONTROL),('settle',49),('packed_core',Path('/packed'))]:
args=SimpleNamespace(**{**valid,field:value})
with self.subTest(field=field),patch.object(r,'assert_no_game',side_effect=AssertionError('must refuse before process access')):
with self.assertRaises(ValueError):r.run(args)
r.validate_input_exercise(SimpleNamespace())
def test_native_flag_is_explicit_bound_and_default_has_no_look(self):
base=['gamescope','--backend','headless','--','/proton','run','/game']
ordinary=r.input_observer_command(base,'chat',None,NONCE)
self.assertNotIn('-errOrdinaryLookObserve',ordinary)
look=r.input_observer_command(base,'chat',None,NONCE,True)
self.assertEqual(look[-2:],['-errOrdinaryLookObserve',NONCE]);self.assertEqual(look[:-2],ordinary)
for command,flag in [(base,1),(look,True),(base+['-errOrdinaryLookObserve','foreign'],False)]:
with self.assertRaises(ValueError):r.input_observer_command(command,'chat',None,NONCE,flag)
def test_helper_optin_requires_exact_matching_native_nonce_and_keeps_private_boundary(self):
with tempfile.TemporaryDirectory() as folder:
root=Path(folder);(root/'tools').mkdir();profile=root/'profile';profile.mkdir()
for name in ('headless_input_proof.py','headless_display_probe.py'):(root/'tools'/name).write_text('# fake')
base=['gamescope','--backend','headless','--','/proton','run','/game','-errOrdinaryInputObserve',NONCE]
for native,flag,valid in [(base,False,True),(base,True,False),(base+['-errOrdinaryLookObserve',NONCE],True,True),(base+['-errOrdinaryLookObserve','foreign'],True,False),(base+['-errOrdinaryLookObserve',NONCE],False,False),(base+['-errOrdinaryLookObserve'],True,False),(base+['-errOrdinaryLookObserve',NONCE,'-errOrdinaryLookObserve',NONCE],True,False)]:
wrapped,display=r.display_probe_command(native,root,Path('/compat'),profile,Path('/game'),NONCE,':0')
if not valid:
with self.assertRaises(ValueError):r.input_exercise_command(wrapped,root,Path('/compat'),profile,Path('/game'),NONCE,':0',display,flag)
continue
command,context=r.input_exercise_command(wrapped,root,Path('/compat'),profile,Path('/game'),NONCE,':0',display,flag)
self.assertEqual(command[:4],base[:4]);self.assertEqual(command[-len(native[4:]):],native[4:])
self.assertEqual('--enable-private-look-proof' in command,flag);self.assertEqual(context.get('look_requested',False),flag)
def test_final_evidence_is_independent_and_earlier_failures_survive(self):
for verified,prior in [(True,'game-started'),(False,'game-started'),(True,'game-failed'),(False,'cleanup-failed')]:
with tempfile.TemporaryDirectory() as folder:
session,context,report,observation=fixtures.ExerciseTests.make_proof(self,Path(folder))
context['look_requested']=True;report['look_requested']=True;report['look_proof']={'requested':True,'completed':True}
raw='native sealed console bytes';(session/'console.log').write_text(raw);Path(context['report']).write_text(json.dumps(report))
module=ModuleType('ordinary_look_evidence');calls=[]
def validate(*args):calls.append(args);return {'verified':verified,'errors':[] if verified else ['native turn missing']}
module.validate_look_evidence=validate
with patch.dict(sys.modules,{'ordinary_look_evidence':module}):
result,proof=r.input_exercise_result(prior,context,session,observation,{'verified':True})
self.assertEqual(calls,[(raw,NONCE,report['look_proof'],report['events'])])
self.assertEqual(proof['verified'],verified)
self.assertEqual(result,'input-exercise-incomplete' if not verified and prior=='game-started' else prior)
self.assertEqual((session/'input-proof.json').read_bytes(),Path(context['report']).read_bytes())
def test_unrequested_or_mismatched_mouse_claim_cannot_qualify(self):
for request,reported,payload in [(False,True,{}),(True,False,None),(False,False,{}),(False,1,None)]:
with tempfile.TemporaryDirectory() as folder:
session,context,report,observation=fixtures.ExerciseTests.make_proof(self,Path(folder))
context['look_requested']=request;report['look_requested']=reported
if payload is not None:report['look_proof']=payload
Path(context['report']).write_text(json.dumps(report))
result,proof=r.input_exercise_result('game-started',context,session,observation,{'verified':True})
self.assertFalse(proof['verified']);self.assertEqual(result,'input-exercise-incomplete')
if __name__=='__main__':unittest.main()