mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-24 12:49:03 -05:00
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.
125 lines
4.4 KiB
Python
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()
|