Files
ios/tools/validate_project.py

45 lines
2.6 KiB
Python

"""Cross-platform structural checks only; this does not compile or test Swift."""
import hashlib
import json
import pathlib
import plistlib
import re
import subprocess
import sys
import xml.etree.ElementTree as ET
root = pathlib.Path(__file__).resolve().parents[1]
generated = [root / "MusicBridge.xcodeproj/project.pbxproj",
root / "MusicBridge.xcodeproj/xcshareddata/xcschemes/MusicBridge.xcscheme",
root / "MusicBridge/Info.plist", root / "MusicBridgeWidgets/Info.plist",
root / "MusicBridgeRemote/Info.plist", root / "MusicBridge/App.entitlements", root / "MusicBridgeRemote/Remote.entitlements"]
before = [p.read_bytes() for p in generated]
subprocess.run([sys.executable, str(root / "tools/generate_project.py")], check=True)
assert before == [p.read_bytes() for p in generated], "Generated project is stale; review and commit regeneration."
project = generated[0].read_text(encoding="utf-8")
for folder in ("MusicBridge", "MusicBridgeTests", "Shared", "MusicBridgeWidgets", "RemoteShared", "MusicBridgeRemote"):
for source in (root / folder).glob("*.swift"):
key = hashlib.sha256(source.relative_to(root).as_posix().encode()).hexdigest()[:24].upper()
assert key in project, f"Missing source: {source.name}"
defined = set(re.findall(r'"([A-F0-9]{24})" = \{', project))
referenced = set(re.findall(r'"([A-F0-9]{24})"', project))
assert defined == referenced, "Project has dangling object references."
info = plistlib.loads(generated[2].read_bytes())
assert info["NSLocalNetworkUsageDescription"]
assert info["NSCameraUsageDescription"]
assert info["NSSupportsLiveActivities"] is True
assert plistlib.loads(generated[3].read_bytes())["NSExtension"]["NSExtensionPointIdentifier"] == "com.apple.widgetkit-extension"
assert info["NSBonjourServices"] == ["_musicbridge._tcp"]
assert info["CFBundleURLTypes"][0]["CFBundleURLSchemes"] == ["musicbridge"]
assert info["NSAppTransportSecurity"] == {
"NSAllowsLocalNetworking": True,
"NSExceptionDomains": {network: {"NSExceptionAllowsInsecureHTTPLoads": True}
for network in ("10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16")},
}
ET.parse(generated[1])
fixture = json.loads((root / "MusicBridgeTests/state-v1.json").read_text(encoding="utf-8"))
assert fixture["protocolVersion"] == 1 and fixture["positionSeconds"] == 42.5
assert set(fixture["capabilities"]) == {"play", "pause", "toggle", "next", "previous", "seek"}
print("PASS: deterministic project, source membership, object references, plist, scheme XML, protocol fixture.")
print("Swift compilation and XCTest must run on macOS/Xcode.")