#!/usr/bin/env python3 import sys import unittest from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[1] SDK_SRC = PROJECT_ROOT / "packages" / "jwebot-sdk" / "src" KERNEL_SRC = PROJECT_ROOT / "packages" / "jwebot-kernel" / "src" sys.path[:0] = [str(SDK_SRC), str(KERNEL_SRC)] from jwebot_kernel import ( # noqa: E402 CatalogError, ExtensionCatalog, parse_manifest, ) def manifest(plugin_id: str, command: str): module_name = plugin_id.replace("-", "_") return parse_manifest( { "id": plugin_id, "author": "tester", "description": f"Handle {command}", "help": [command], "version": "1.0.0", "api_version": "1", "entrypoint": f"{module_name}:plugin", "type": "command", "capabilities": { "commands": [command], "storage": False, "network_profiles": [], }, } ) class ExtensionCatalogTests(unittest.TestCase): def test_registration_is_open_then_frozen(self): catalog = ExtensionCatalog() catalog.register(manifest("hello-command", "/hello")) self.assertFalse(catalog.frozen) catalog.freeze() self.assertTrue(catalog.frozen) with self.assertRaisesRegex(CatalogError, "frozen"): catalog.register(manifest("weather-command", "/weather")) def test_duplicate_plugin_id_is_rejected(self): catalog = ExtensionCatalog() catalog.register(manifest("hello-command", "/hello")) with self.assertRaisesRegex(CatalogError, "duplicate plugin id"): catalog.register(manifest("hello-command", "/hello2")) def test_command_collision_is_rejected_case_insensitively(self): catalog = ExtensionCatalog() catalog.register(manifest("hello-command", "/Hello")) with self.assertRaisesRegex(CatalogError, "already belongs"): catalog.register(manifest("other-command", "/hello")) def test_routing_requires_a_frozen_catalog(self): catalog = ExtensionCatalog() with self.assertRaisesRegex(CatalogError, "must be frozen"): catalog.resolve_command("/hello") def test_frozen_catalog_resolves_arguments(self): catalog = ExtensionCatalog() catalog.register(manifest("hello-command", "/hello")) catalog.freeze() match = catalog.resolve_command("/hello world") self.assertIsNotNone(match) assert match is not None self.assertEqual(match.plugin_id, "hello-command") self.assertEqual(match.command, "/hello") self.assertEqual(match.arguments, "world") def test_command_name_does_not_match_a_longer_token(self): catalog = ExtensionCatalog() catalog.register(manifest("hello-command", "/hello")) catalog.freeze() self.assertIsNone(catalog.resolve_command("/hello-world")) def test_catalog_views_are_read_only(self): catalog = ExtensionCatalog() catalog.register(manifest("hello-command", "/hello")) with self.assertRaises(TypeError): catalog.commands["/other"] = "other-command" # type: ignore[index] if __name__ == "__main__": unittest.main()