Files
EscapistsReintroduced/tests/test_archive_game_control.py
jakub cab998fb64 Combine Workshop addon and fix prison startup
Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
2026-09-20 16:42:52 +02:00

71 lines
4.4 KiB
Python

"""Run the real archiver against synthetic sealed startup logs, without engines."""
from pathlib import Path
import json
import shutil
import subprocess
import sys
import tempfile
import unittest
ROOT=Path(__file__).resolve().parents[1]
sys.path.insert(0,str(ROOT/'tools'))
from native_provenance import snapshot,persist,bindings,seal_run
from test_vanilla_game_control import BASE
ORDINARY='''00 SCRIPT : Module: Game; defines: "PLATFORM_WINDOWS"
00 SCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems
00 SCRIPT : Reintroduced [mission]: phase 0 -> 1
00 SCRIPT : ERR ORDINARY: local participant verified project=core phase=prison
'''
class ArchiveControl(unittest.TestCase):
def archive(self,project,result,control=None,cleanup=True,content=None):
tmp=tempfile.TemporaryDirectory(prefix='erri-archive-control-test-');self.addCleanup(tmp.cleanup)
root=Path(tmp.name);(root/'addons/core').mkdir(parents=True)
(root/'addons/core/addon.gproj').write_text('Synthetic fixture source, not a native project')
tools=root/'tools';tools.mkdir()
for name in ('archive_native.py','native_report.py','source_manifest.py','native_provenance.py','headless_game.py','project_schema.py'):
shutil.copyfile(ROOT/'tools'/name,tools/name)
session=root/'session';session.mkdir()
(session/'console.log').write_text(content if content is not None else BASE if project=='vanilla-control' else ORDINARY)
captured=snapshot(root,['synthetic-archive-test-no-engine']);persist(session,captured)
data={**bindings(captured),'started_unix':json.loads(captured[1])['captured_unix'],**seal_run(root,session,captured),'project':project,'result':result,'cleanup_confirmed':cleanup}
if control is not None:data['control_only']=control
(session/'runner.json').write_text(json.dumps(data))
# Deliberately false saved status; actual archiver must recompute sealed log.
(session/'game-startup-report.json').write_text('{"ready":true,"failed":false}')
command=[sys.executable,str(tools/'archive_native.py'),str(session),'control']
done=subprocess.run(command,text=True,capture_output=True)
dest=root/'docs/evidence/control'
self.assertTrue(dest.exists(),done.stderr)
self.assertEqual((dest/'console.log.txt').read_bytes(),(session/'console.log').read_bytes())
self.assertTrue((dest/'report.json').is_file(), done.stderr)
return done,json.loads((dest/'report.json').read_text()),command,dest
def test_clean_control_gets_own_result_and_no_successor_qualification(self):
result,report,command,dest=self.archive('vanilla-control','vanilla-control-started',True)
self.assertEqual(result.returncode,0,result.stderr)
self.assertTrue(report['control_metadata_consistent']);self.assertTrue(report['control_only'])
self.assertFalse(report['normal_mission_ready']);self.assertFalse(report['scenario_header_verified'])
self.assertIn('no successor',report['qualification'])
before=(dest/'report.json').read_bytes()
duplicate=subprocess.run(command,capture_output=True,text=True)
self.assertNotEqual(duplicate.returncode,0);self.assertEqual((dest/'report.json').read_bytes(),before)
def test_control_rejects_ordinary_result_or_inconsistent_flag(self):
for result,flag in [('game-started',True),('vanilla-control-started',None),('vanilla-control-started',False),('vanilla-control-started','true')]:
with self.subTest(result=result,flag=flag):
done,report,_,_=self.archive('vanilla-control',result,flag)
self.assertEqual(done.returncode,1);self.assertTrue(report['ready'])
def test_control_retains_native_failure_despite_saved_success(self):
done,report,_,_=self.archive('vanilla-control','vanilla-control-started',True,content=BASE+"00 GUI (E): Unknown class 'SCR_WidgetExportRuleRoot'")
self.assertEqual(done.returncode,1);self.assertFalse(report['ready']);self.assertTrue(report['engine_errors'])
def test_cleanup_is_still_required(self):
done,_,_,_=self.archive('vanilla-control','vanilla-control-started',True,cleanup=False)
self.assertEqual(done.returncode,1)
def test_ordinary_current_and_legacy_status_remain_strict(self):
for flag in (None,False):
done,report,_,_=self.archive('core','game-started',flag)
self.assertEqual(done.returncode,0,done.stderr);self.assertTrue(report['normal_mission_ready'])
for result,flag in [('vanilla-control-started',False),('game-started',True)]:
done,_,_,_=self.archive('core',result,flag);self.assertEqual(done.returncode,1)
if __name__=='__main__':unittest.main()