release: public alpha 0.6.0 baseline
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import tempfile
|
||||
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
|
||||
ManifestError,
|
||||
PluginType,
|
||||
load_manifest,
|
||||
parse_manifest,
|
||||
)
|
||||
from jwebot_kernel import manifest as manifest_module # noqa: E402
|
||||
|
||||
|
||||
class ManifestTests(unittest.TestCase):
|
||||
def manifest(self, **overrides):
|
||||
value = {
|
||||
"id": "hello-command",
|
||||
"author": "jwebot",
|
||||
"description": "Say hello",
|
||||
"help": ["/hello [name]"],
|
||||
"version": "1.0.0",
|
||||
"api_version": "1",
|
||||
"entrypoint": "hello_command:plugin",
|
||||
"type": "command",
|
||||
"capabilities": {
|
||||
"commands": ["/hello"],
|
||||
"storage": False,
|
||||
"network_profiles": [],
|
||||
"service_profiles": [],
|
||||
},
|
||||
}
|
||||
value.update(overrides)
|
||||
return value
|
||||
|
||||
def test_command_manifest_is_parsed(self):
|
||||
manifest = parse_manifest(self.manifest())
|
||||
self.assertEqual(manifest.plugin_id, "hello-command")
|
||||
self.assertEqual(manifest.author, "jwebot")
|
||||
self.assertEqual(manifest.description, "Say hello")
|
||||
self.assertEqual(manifest.help_entries, ("/hello [name]",))
|
||||
self.assertEqual(manifest.plugin_type, PluginType.COMMAND)
|
||||
self.assertEqual(manifest.capabilities.commands, ("/hello",))
|
||||
|
||||
def test_author_is_required_and_bounded(self):
|
||||
value = self.manifest()
|
||||
del value["author"]
|
||||
with self.assertRaisesRegex(ManifestError, "author must"):
|
||||
parse_manifest(value)
|
||||
with self.assertRaisesRegex(ManifestError, "author has an invalid format"):
|
||||
parse_manifest(self.manifest(author="../Alice"))
|
||||
|
||||
def test_unknown_capability_is_rejected(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["shell"] = True
|
||||
with self.assertRaisesRegex(ManifestError, "unknown capabilities"):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_description_and_help_are_declared_together(self):
|
||||
value = self.manifest()
|
||||
del value["help"]
|
||||
with self.assertRaisesRegex(
|
||||
ManifestError,
|
||||
"declared together",
|
||||
):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_command_manifest_requires_visible_help_metadata(self):
|
||||
value = self.manifest()
|
||||
del value["description"]
|
||||
del value["help"]
|
||||
with self.assertRaisesRegex(
|
||||
ManifestError,
|
||||
"must declare description",
|
||||
):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_help_entries_are_bounded_command_usage(self):
|
||||
with self.assertRaisesRegex(ManifestError, "invalid display"):
|
||||
parse_manifest(self.manifest(help=["plain prose"]))
|
||||
with self.assertRaisesRegex(ManifestError, "display boundary"):
|
||||
parse_manifest(self.manifest(description="x" * 121))
|
||||
|
||||
def test_command_extension_requires_a_namespace(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["commands"] = []
|
||||
with self.assertRaisesRegex(ManifestError, "at least one command"):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_non_command_extension_cannot_claim_a_command(self):
|
||||
with self.assertRaisesRegex(ManifestError, "only command extensions"):
|
||||
parse_manifest(self.manifest(type="enrichment"))
|
||||
|
||||
def test_unsupported_api_version_is_rejected(self):
|
||||
with self.assertRaisesRegex(ManifestError, "unsupported api_version"):
|
||||
parse_manifest(self.manifest(api_version="2"))
|
||||
|
||||
def test_entrypoint_must_use_plugin_namespace(self):
|
||||
with self.assertRaisesRegex(ManifestError, "plugin module namespace"):
|
||||
parse_manifest(self.manifest(entrypoint="json:plugin"))
|
||||
|
||||
def test_service_profiles_are_bounded_and_parsed(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["service_profiles"] = ["coin"]
|
||||
self.assertEqual(
|
||||
parse_manifest(value).capabilities.service_profiles,
|
||||
("coin",),
|
||||
)
|
||||
|
||||
def test_duplicate_commands_are_rejected(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["commands"] = ["/hello", "/hello"]
|
||||
with self.assertRaisesRegex(ManifestError, "duplicates"):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_case_insensitive_duplicate_commands_are_rejected(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["commands"] = ["/Hello", "/hello"]
|
||||
with self.assertRaisesRegex(ManifestError, "case-insensitive duplicates"):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_command_rejects_manifest_breaking_characters(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["commands"] = ['/"quoted']
|
||||
with self.assertRaisesRegex(ManifestError, "invalid value"):
|
||||
parse_manifest(value)
|
||||
|
||||
def test_command_accepts_chinese_names(self):
|
||||
value = self.manifest()
|
||||
value["capabilities"]["commands"] = ["/天气"]
|
||||
self.assertEqual(
|
||||
parse_manifest(value).capabilities.commands,
|
||||
("/天气",),
|
||||
)
|
||||
|
||||
def test_load_manifest_reads_toml(self):
|
||||
if manifest_module.tomllib is None:
|
||||
self.skipTest("tomli is not installed under local Python")
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = Path(directory) / "plugin.toml"
|
||||
path.write_text(
|
||||
"\n".join(
|
||||
(
|
||||
'id = "hello-command"',
|
||||
'author = "Alice"',
|
||||
'description = "Say hello"',
|
||||
'help = ["/hello"]',
|
||||
'version = "1.0.0"',
|
||||
'api_version = "1"',
|
||||
'entrypoint = "hello_command:plugin"',
|
||||
'type = "command"',
|
||||
"",
|
||||
"[capabilities]",
|
||||
'commands = ["/hello"]',
|
||||
"storage = false",
|
||||
"network_profiles = []",
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
self.assertEqual(load_manifest(path).plugin_id, "hello-command")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user