Files
EscapistsReintroduced/tests/test_project_schema.py
T

114 lines
5.7 KiB
Python

#!/usr/bin/env python3
"""Strict Core menu project extension in both source and packed validators."""
from pathlib import Path
import re
import sys
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT/'tools'))
import headless_game as packed
import source_bundle as bundle
from project_schema import parse_project
CURRENT = (ROOT/'addons/core/addon.gproj').read_text()
MENU = CURRENT[CURRENT.index(' Configurations {'):CURRENT.rindex('}')]
MINIMAL = CURRENT[:CURRENT.index(' Configurations {')]+'}\n'
CORE_PROJECT = 'addons/core/addon.gproj'
MENU_FILE = 'addons/core/Configs/ERR/AdminMenus.conf'
class ProjectSchemaTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.payload = {name: (ROOT/name).read_bytes() for name in bundle.inventory(ROOT)}
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix='erri-project-schema-')
self.addCleanup(self.temp.cleanup)
self.candidate = Path(self.temp.name)
(self.candidate/'data.pak').write_bytes(b'SYNTHETIC PACKAGE')
(self.candidate/'resourceDatabase.rdb').write_bytes(b'SYNTHETIC DATABASE')
def packed(self, text, project='core'):
(self.candidate/'addon.gproj').write_text(text)
return packed.packed_inventory(self.candidate, project)
def source(self, text):
payload = dict(self.payload)
payload[CORE_PROJECT] = text.encode()
return bundle.validate(payload, ROOT)
def test_old_minimal_and_exact_owned_menu_extension_are_accepted(self):
for text in (MINIMAL, CURRENT, re.sub(r'\s+', ' ', CURRENT)):
with self.subTest(text=text):
match = parse_project(text, allow_core_menu=True)
self.assertIsNotNone(match)
self.assertEqual(match.group(1, 2), ('ERR_Core', packed.PACKED_GUID))
self.assertEqual(set(self.packed(text)), packed.PACKED_FILES)
self.assertEqual(self.source(text)['core']['dependencies'], [packed.PACKED_BASE])
self.assertIsNotNone(parse_project(MINIMAL))
self.assertIsNone(parse_project(CURRENT))
def test_menu_extension_cannot_redirect_override_or_add_unreviewed_settings(self):
mutations = (
CURRENT.replace('B48C7FA12692DE03', 'FFFFFFFFFFFFFFFF'),
CURRENT.replace('50C890C996B0A6FC', 'FFFFFFFFFFFFFFFF'),
CURRENT.replace('Configs/ERR/AdminMenus.conf', 'Configs/Foreign/Menu.conf'),
CURRENT.replace('MenuConfigs {', 'MenuConfigs +{'),
CURRENT.replace('MenuConfigs {', 'MenuConfigs -{'),
CURRENT.replace('C747AFB6B750CE9A', 'FFFFFFFFFFFFFFFF'),
CURRENT.replace('Configs/System/chimeraMenus.conf', 'Configs/Foreign/Menu.conf'),
CURRENT.replace('"{C747AFB6B750CE9A}Configs/System/chimeraMenus.conf"', ''),
CURRENT.replace('GameProjectConfig PC', 'GameProjectConfig HEADLESS'),
CURRENT.replace('GameProjectConfig PC', 'GameProjectConfig XBOX_SERIES'),
CURRENT.replace('GameProjectConfig PC', 'UnknownConfig PC'),
CURRENT.replace('MenuManagerSettings MenuManagerSettings', 'MenuManagerSettings OtherSettings'),
CURRENT.replace(' MenuConfigs', ' UnknownSetting 1\n MenuConfigs'),
CURRENT.replace('"{B48C7FA12692DE03}Configs/ERR/AdminMenus.conf"', '"{B48C7FA12692DE03}Configs/ERR/AdminMenus.conf" "{FFFFFFFFFFFFFFFF}Extra.conf"'),
CURRENT.replace(MENU, MENU+MENU),
CURRENT+'GameProject {}\n',
)
for text in mutations:
with self.subTest(text=text):
self.assertIsNone(parse_project(text, allow_core_menu=True))
with self.assertRaises(ValueError): self.packed(text)
with self.assertRaisesRegex(ValueError, 'identity/dependency'): self.source(text)
def test_identity_and_exact_dependencies_remain_required_with_extension(self):
for text in (
CURRENT.replace('ERR_Core', 'ERR_Chat'),
CURRENT.replace(packed.PACKED_GUID, 'FFFFFFFFFFFFFFFF'),
CURRENT.replace(packed.PACKED_BASE, '5F16D7E4A1CBE075'),
CURRENT.replace('Dependencies {', 'Dependencies { "58D0FB3206B6F859"'),
CURRENT.replace('Dependencies {', 'Dependencies { "5192138CB9D5B911"'),
):
with self.subTest(text=text):
with self.assertRaises(ValueError): self.packed(text)
with self.assertRaisesRegex(ValueError, 'identity/dependency'): self.source(text)
def test_extension_is_core_only(self):
for name, (identity, guid, deps) in packed.PACKED_PROJECTS.items():
if name == 'core': continue
text = (ROOT/'addons'/name/'addon.gproj').read_text()
text = text[:text.rindex('}')]+MENU+'}\n'
with self.subTest(project=name):
with self.assertRaises(ValueError): self.packed(text, name)
payload = dict(self.payload)
payload['addons/'+name+'/addon.gproj'] = text.encode()
with self.assertRaisesRegex(ValueError, 'identity/dependency'): bundle.validate(payload, ROOT)
def test_source_menu_reference_must_resolve_to_its_owned_resource(self):
payload = dict(self.payload)
payload.pop(MENU_FILE)
payload.pop(MENU_FILE+'.meta')
with self.assertRaisesRegex(ValueError, 'unresolved or nonvanilla'): bundle.validate(payload, ROOT)
payload = dict(self.payload)
payload[MENU_FILE+'.meta'] = payload[MENU_FILE+'.meta'].replace(b'B48C7FA12692DE03', b'FFFFFFFFFFFFFFFF')
with self.assertRaisesRegex(ValueError, 'unresolved or nonvanilla'): bundle.validate(payload, ROOT)
if __name__ == '__main__':
unittest.main()