Files
libretro/tests/test_schema_semantic_gate.py
T
Abdessamad Derraz 7143d20ef8 fix: check the event schema under the given root
validate_schemas.py read install-events.schema.json from the real tree while a test pointed ROOT at a scratch one, and test_schema_semantic_gate.py called unittest.main() before its last class.
2026-10-23 19:23:59 +02:00

125 lines
4.4 KiB
Python

"""Schema-invalid synthetic manifests must not crash semantic validation."""
from __future__ import annotations
import io
import json
import sys
import tempfile
import unittest
from contextlib import redirect_stdout
from pathlib import Path
from unittest import mock
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
try:
import validate_schemas
except ImportError as exc:
validate_schemas = None
IMPORT_ERROR = str(exc)
else:
IMPORT_ERROR = ""
@unittest.skipIf(validate_schemas is None, f"validate_schemas unavailable: {IMPORT_ERROR}")
class SemanticManifestValidation(unittest.TestCase):
def test_invalid_synthetic_manifest_reports_schema_errors_without_crashing(self):
with tempfile.TemporaryDirectory(dir=REPO_ROOT) as directory:
root = Path(directory)
(root / "emulators").mkdir()
platforms = root / "platforms"
platforms.mkdir()
(platforms / "_data_dirs.yml").write_text(
"data_directories: {}\n", encoding="utf-8"
)
(root / "database.json").write_text(
json.dumps({"files": None}), encoding="utf-8"
)
install = root / "install"
install.mkdir()
(install / "synthetic.json").write_text(
json.dumps({"files": None}), encoding="utf-8"
)
api = root / "website" / "public" / "api" / "v1"
api.mkdir(parents=True)
(api / "catalog.json").write_text(
json.dumps({"count": 1, "items": None}), encoding="utf-8"
)
output = io.StringIO()
with mock.patch.object(validate_schemas, "ROOT", root), mock.patch.object(
sys, "argv", ["validate_schemas.py"]
), redirect_stdout(output):
result = validate_schemas.main()
self.assertEqual(result, 1)
text = output.getvalue().replace("\\", "/")
self.assertIn("database.json", text)
self.assertIn("install/synthetic.json", text)
self.assertIn("website/public/api/v1/catalog.json", text)
self.assertIn("files", text)
self.assertIn("items", text)
self.assertNotIn("Traceback", text)
def test_valid_synthetic_manifest_still_runs_semantic_checks(self):
manifest = {
"manifest_version": 2,
"source": "full",
"regions": [],
"platform": "synthetic",
"display_name": "Synthetic",
"version": "test",
"generated": "2026-10-21T00:00:00Z",
"base_destination": "",
"detect": [],
"standalone_copies": [],
"total_files": 1,
"total_size": 0,
"total_omitted": 0,
"omitted_files": [],
"files": [],
}
with tempfile.TemporaryDirectory(dir=REPO_ROOT) as directory:
path = Path(directory) / "synthetic.json"
path.write_text(json.dumps(manifest), encoding="utf-8")
errors = validate_schemas._validate_json_files(
[path],
"install-manifest.schema.json",
validate_schemas._semantic_install_checks,
)
self.assertEqual(len(errors), 1)
self.assertIn("total_files does not equal len(files)", errors[0])
try:
import jsonschema
except ImportError:
jsonschema = None
@unittest.skipIf(jsonschema is None, "jsonschema unavailable")
class DataRootIsKeyedBySystem(unittest.TestCase):
"""AetherSX2 gave Android/data/xyz.aethersx2.android only in its notes:
the site could not print the folder, nor which OS tabs apply."""
def _errors(self, value):
schema = json.loads((REPO_ROOT / "schemas/emulator.schema.json").read_text(encoding="utf-8"))
validator = jsonschema.Draft202012Validator(schema["properties"]["data_root"])
return list(validator.iter_errors(value))
def test_a_system_with_its_path_and_reference(self):
self.assertEqual(self._errors({"android": {
"path": "Android/data/xyz.aethersx2.android/files", "source_ref": "a.kt:1"}}), [])
def test_an_unknown_system_or_a_path_without_reference(self):
self.assertTrue(self._errors({"amiga": {"path": "x", "source_ref": "y"}}))
self.assertTrue(self._errors({"windows": {"path": "%APPDATA%/X"}}))
self.assertTrue(self._errors({}))
if __name__ == "__main__":
unittest.main()