#!/usr/bin/env python3 """Metadata diagnostics and dependency inspection without a server or modules.""" from pathlib import Path import subprocess import sys import tempfile binary = str(Path(sys.argv[1]).resolve()) def check(option, path, code, *messages): result = subprocess.run([binary, option, str(path)], capture_output=True, text=True) assert result.returncode == code, (result.returncode, result.stdout, result.stderr) for message in messages: assert message in result.stdout + result.stderr, (message, result.stdout, result.stderr) base = Path("tests/fixtures/project-v10.xtc").read_text() check("--inspect", "tests/fixtures/project-v10.xtc", 0, "Project format 10", "missing/unreadable: 0") with tempfile.TemporaryDirectory(prefix="xtc-inspect-") as directory: root = Path(directory) project = root / "project.xtc" media = root / "media.wav" # Relative paths resolve against the project, independently of the subprocess cwd. audio = base.replace("ASSET -", "ASSET " + b"media.wav".hex()).replace("MIDI 1", "MIDI 0") audio = audio.replace("NOTES 1 1\nNOTE 0 0 0 480 69 100 0", "NOTES 0 0") project.write_text(audio) check("--validate", project, 0, "metadata valid") check("--inspect", project, 2, "Media clip 0", str(media), "missing/unreadable: 1") media.write_text("Deliberately not WAV data") check("--inspect", project, 0, "available", "WAV contents", "not checked") module = root / "module.so" plugin = Path("tests/fixtures/project-plugin-v6.xtc").read_text() plugin = plugin.replace(b"/missing/test.so".hex(), str(module).encode().hex()) project.write_text(plugin) check("--validate", project, 0) check("--inspect", project, 2, "LADSPA node 0 ID 900000 descriptor 0", "xtc_test_gain", str(module)) # Inspection succeeds for readable files without trying dlopen or decoding. module.write_text("Deliberately not an executable module") check("--inspect", project, 0, "no plugin code executed") for text, messages in [ (base.replace("XTC_PROJECT 10", "XTC_PROJECT 999"), ("line 1", "999", "1..10")), ("XTC_PROJECT 10\n", ("line 2", "APP")), (base.replace("TEMPO 120000", "TEMPO 0"), ("line 3", "TEMPO")), (base + "OPTIONAL_FUTURE 1\n", ("Unknown fields",)), (base.replace("APP 0 1 0", "APP 0 1 0 extra"), ("APP",)), ]: project.write_text(text) check("--inspect", project, 1, *messages) with project.open("wb") as stream: stream.truncate(4194305) check("--inspect", project, 1, "SIZE", "4 MiB") check("--inspect", root / "absent.xtc", 1, "OPEN") print("Project inspection availability, diagnostics and strict compatibility passed.")