107 lines
4.7 KiB
Python
Executable File
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()
|