"""Exercise capture completeness, native defaults, and provenance merging.""" import hashlib import json import pathlib import subprocess import sys import tempfile import unittest class SceneMetadataExportTests(unittest.TestCase): def test_capture_validation_and_merge(self): script = pathlib.Path(__file__).with_name("export_scene_metadata.py") with tempfile.TemporaryDirectory() as directory: root = pathlib.Path(directory) assembly, log, output = root / "assembly", root / "capture.log", root / "output.json" assembly.write_bytes(b"test assembly identity") previous = { "client_version": "test-revision", "source": { "assembly_sha256": hashlib.sha256(assembly.read_bytes()).hexdigest(), "capture_sha256": "previous-capture", "entry_saved_values_policy": {"town": "preserve this policy"}, }, "floors": {"30": {"saved_values": {"Existing": 7}}}, } output.write_text(json.dumps(previous), encoding="utf-8") rows = [{"Name": "DebugFlag", "DefaultValue": 0, "MinValue": 0, "MaxValue": 1, "AllowedValues": [0, 1]}] capture = ( "[GAC_SCENE_META] FLOOR 10 20 startGroup=0 anchor=1 count=1\n" "[GAC_SCENE_META] GROUP 20 1 side=Server: 1 hoyo=true deleted=false\n" "[GAC_SCENE_PLACEMENT] ANCHOR 20 1 pos=1,2,3 rot=90\n" "[GAC_SCENE_PLACEMENT] END 20\n" "[GAC_SCENE_META] END 20\n" "[GAC_SCENE_PROPS] END 20\n" ) args = [sys.executable, str(script), str(log), "--assembly", str(assembly), "--client-version", "test-revision", "--output", str(output), "--merge", "--dimension-index", "0", "--omit-start-anchor"] for invalid in (capture, capture + '[GAC_SCENE_SAVED] DIMENSION 20 0 [{"Name":"DebugFlag","DefaultValue":2,"MinValue":0,"MaxValue":1}]\n', capture + "[GAC_SCENE_SAVED] DIMENSION 20 0 " + json.dumps(rows) + "\n", capture.replace("[GAC_SCENE_PROPS] END 20\n", "")): log.write_text(invalid, encoding="utf-8") result = subprocess.run(args, capture_output=True, text=True) self.assertNotEqual(result.returncode, 0, result.stdout) self.assertEqual(json.loads(output.read_text()), previous, "invalid captures must not alter existing output") log.write_text(capture + "[GAC_SCENE_SAVED] DIMENSION 20 0 " + json.dumps(rows) + "\n" + "[GAC_SCENE_DIMENSION] GROUPS 20 0 7 [1]\n", encoding="utf-8") result = subprocess.run(args, capture_output=True, text=True) self.assertEqual(result.returncode, 0, result.stderr) merged = json.loads(output.read_text()) self.assertEqual(merged["floors"]["20"]["saved_values"]["DebugFlag"], 0) self.assertNotIn("start_anchor", merged["floors"]["20"]) self.assertEqual(merged["floors"]["20"]["floor_default_anchor"]["pos"], {"x": 1000, "y": 2000, "z": 3000}) self.assertEqual(merged["floors"]["20"]["dimension_id"], 7) self.assertEqual(merged["floors"]["20"]["dimension_groups"], {"7": [1]}) self.assertEqual(merged["floors"]["30"], previous["floors"]["30"]) self.assertEqual(merged["source"]["entry_saved_values_policy"], previous["source"]["entry_saved_values_policy"]) if __name__ == "__main__": unittest.main()