#!/usr/bin/env python3 """Static nigig compatibility sentinels, not build/runtime tests. Run with Python 3.11+: python3 tools/nigig_compat/check.py [--root CHECKOUT] File moves are allowed for the platform and widget implementations. These checks catch accidentally omitted interfaces; they do not prove semantics. """ import argparse from pathlib import Path import re import tomllib import unittest parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--root', type=Path, default=Path(__file__).resolve().parents[2]) args, rest = parser.parse_known_args() ROOT = args.root.resolve() def read(path): return (ROOT / path).read_text(encoding='utf-8') def rust_under(*directories): return '\n'.join(p.read_text(encoding='utf-8') for directory in directories for p in (ROOT / directory).rglob('*.rs') if 'target' not in p.parts) class NigigCompatibility(unittest.TestCase): def test_optional_sibling_exports(self): cargo = tomllib.loads(read('widgets/Cargo.toml')) source = read('widgets/src/lib.rs') for feature, crate in [('test', 'makepad-test'), ('gltf', 'makepad-gltf'), ('csg', 'makepad-csg')]: with self.subTest(feature=feature): self.assertIn('dep:' + crate, cargo['features'][feature]) self.assertTrue(cargo['dependencies'][crate]['optional']) self.assertIn('pub use ' + crate.replace('-', '_') + ';', source) def test_isolate_host_entry_points(self): source = rust_under('widgets/core/src', 'widgets/src') for symbol in ['enter_isolate', 'leave_isolate']: self.assertRegex(source, r'pub\s+fn\s+' + symbol + r'\s*\(') def test_android_test_mode_forwarding(self): source = rust_under('platform/src/os/linux/android', 'platform/hal/src/backend/android') self.assertIn('makepad.NIGIG_TEST_MODE', source) self.assertIn('"NIGIG_TEST_MODE"', source) def test_startup_and_touch_protocol(self): source = rust_under('platform/studio/src') for symbol in ['BeforeStartup', 'AfterStartup', 'RemoteTouchUpdate', 'RemoteLongPress', 'RemoteTextPaste', 'RemoteIMEComposition']: with self.subTest(symbol=symbol): self.assertTrue(symbol in source, 'Missing nigig protocol symbol: ' + symbol) def test_secondary_dex_and_custom_manifest(self): source = read('tools/cargo_makepad/src/android/compile.rs') self.assertGreaterEqual(source.count('bundle_crate_secondary_dex('), 2, 'secondary dex bundler must be defined and invoked') self.assertIn('resources/android/AndroidManifest.xml.template', source) self.assertIn('generate_android_wrapper_manifest', source) def test_game_packages(self): expected = { 'libs/sim/Cargo.toml': 'makepad-game-sim', 'libs/sim/math/Cargo.toml': 'makepad-game-math', 'libs/game/blocks/Cargo.toml': 'makepad-game-blocks', 'libs/game/render/Cargo.toml': 'makepad-game-render', } for path, name in expected.items(): with self.subTest(package=name): self.assertEqual(tomllib.loads(read(path))['package']['name'], name) def test_quest_packaging_remains_available(self): source = read('tools/cargo_makepad/src/android/mod.rs') enum = re.search(r'pub enum AndroidVariant\s*\{([^}]+)\}', source) self.assertIsNotNone(enum) self.assertRegex(enum.group(1), r'\bQuest\b') def test_cef_widget_remains_available(self): cargo = tomllib.loads(read('widgets/Cargo.toml')) self.assertIn('cef', cargo['features']) self.assertTrue((ROOT / 'widgets/families/cef/Cargo.toml').is_file()) if __name__ == '__main__': unittest.main(argv=['check.py', *rest])