Files
kam-mobile/open_questions/tests/test_probe.py
T
2026-09-11 18:19:50 +05:00

107 lines
4.7 KiB
Python
Executable File

import importlib.util
import json
import tempfile
import unittest
from pathlib import Path
HERE = Path(__file__).resolve().parents[1]
PROJECT = HERE.parent
def load_probe_module():
p = HERE / 'tools/decision_probe.py'
spec = importlib.util.spec_from_file_location('decision_probe_testmod', p)
mod = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(mod)
return mod
class ProbeTests(unittest.TestCase):
def test_question_count_and_unique(self):
q = json.loads((HERE/'config/questions.json').read_text(encoding='utf-8'))['questions']
ids = [x['id'] for x in q]
self.assertEqual(18, len(ids))
self.assertEqual(len(ids), len(set(ids)))
def test_every_question_has_test(self):
q = json.loads((HERE/'config/questions.json').read_text(encoding='utf-8'))['questions']
self.assertTrue(all(x['tests'] for x in q))
def test_fixed_manifest_is_minimal_and_exact(self):
m = json.loads((HERE/'config/fixture_manifest.json').read_text(encoding='utf-8'))
self.assertEqual('exact-whitelist-no-recursive-discovery', m['selection_policy'])
self.assertEqual([
'Maps/Town Defence/Town Defence.dat',
'Maps/Town Defence/Town Defence.map',
'data/sprites/Tileset.rxx',
], [x['path'] for x in m['primary']])
self.assertEqual(1, len(m['conditional_fallbacks']))
self.assertFalse(m['conditional_fallbacks'][0]['enabled_by_default'])
self.assertEqual([
'Maps/The Barbarian King/TBK01/TBK01.dat',
'Maps/The Barbarian King/TBK01/TBK01.map',
], [x['path'] for x in m['conditional_fallbacks'][0]['files']])
def test_binary_selection_ignores_decoys_and_fallback_is_opt_in(self):
mod = load_probe_module()
with tempfile.TemporaryDirectory() as td:
root = Path(td)
assets = root/'private-assets'
(assets/'a').mkdir(parents=True)
(assets/'decoys').mkdir(parents=True)
(assets/'a/one.dat').write_bytes(b'abc')
(assets/'a/two.map').write_bytes(b'defg')
(assets/'a/three.rxx').write_bytes(b'hijkl')
(assets/'a/fallback.map').write_bytes(b'mnopqr')
(assets/'decoys/should-never-be-read.map').write_bytes(b'X'*100)
manifest = root/'manifest.json'
manifest.write_text(json.dumps({
'selection_policy':'exact-whitelist-no-recursive-discovery',
'primary':[
{'id':'d','role':'dat','path':'a/one.dat','expected_size':3},
{'id':'m','role':'map','path':'a/two.map','expected_size':4},
{'id':'r','role':'rxx','path':'a/three.rxx','expected_size':5},
],
'conditional_fallbacks':[
{'id':'layer-map','enabled_by_default':False,'files':[
{'id':'fm','role':'map','path':'a/fallback.map','expected_size':6}
]}
]
}), encoding='utf-8')
mod.ASSETS = assets
mod.MANIFEST = manifest
mod.INCLUDE_FALLBACKS = set()
primary = [p.relative_to(assets).as_posix() for _,p in mod.selected_files({'.dat','.map','.rxx'})]
self.assertEqual(['a/one.dat','a/two.map','a/three.rxx'], primary)
self.assertNotIn('decoys/should-never-be-read.map', primary)
mod.INCLUDE_FALLBACKS = {'layer-map'}
with_fallback = [p.relative_to(assets).as_posix() for _,p in mod.selected_files({'.dat','.map','.rxx'})]
self.assertEqual(['a/one.dat','a/two.map','a/three.rxx','a/fallback.map'], with_fallback)
def test_independent_inspector_does_not_import_kam(self):
s = (HERE/'tools/decision_probe.py').read_text(encoding='utf-8')
self.assertNotIn('import KM_', s)
self.assertNotIn('from KM_', s)
def test_no_recursive_binary_asset_scan_in_probe(self):
s = (HERE/'tools/decision_probe.py').read_text(encoding='utf-8')
self.assertNotIn('ASSETS.rglob', s)
self.assertNotIn('ASSETS.glob', s)
self.assertNotIn("rglob('*')", s)
self.assertNotIn("glob('**", s)
def test_integrated_paths_do_not_replace_old_runner(self):
self.assertTrue((PROJECT/'run-open-question-tests.sh').is_file())
compatibility = (HERE/'COMPATIBILITY.md').read_text(encoding='utf-8')
self.assertIn('build-android.sh', compatibility)
self.assertIn('does not overwrite', compatibility)
def test_no_production_claim(self):
s = (HERE/'README.md').read_text(encoding='utf-8')
self.assertIn('does not replace', s)
if __name__ == '__main__':
unittest.main()