Files
markitect-tool/tests/test_extension_registry.py

115 lines
3.5 KiB
Python

import pytest
from markitect_tool.extension import (
ExtensionDescriptor,
ExtensionRegistry,
ExtensionRegistryError,
OptionalDependency,
ProcessingCapability,
)
def test_extension_descriptor_serializes_contract_metadata():
descriptor = ExtensionDescriptor(
id="query.selector",
kind="query-engine",
summary="Small selector query engine.",
capabilities=[ProcessingCapability(id="ast", kind="read")],
input_contract="Document + selector",
output_contract="QueryMatch[]",
diagnostics_namespace="query",
provenance_prefix="query.selector",
cli={"command": "mkt query"},
docs=["docs/query-extraction.md"],
)
data = descriptor.to_dict()
assert data["id"] == "query.selector"
assert data["kind"] == "query-engine"
assert data["capabilities"][0]["id"] == "ast"
assert data["cli"]["command"] == "mkt query"
def test_extension_registry_lists_by_kind_and_capability():
selector = ExtensionDescriptor(
id="query.selector",
kind="query-engine",
capabilities=[ProcessingCapability(id="ast")],
)
local = ExtensionDescriptor(
id="backend.local-sqlite",
kind="backend",
capabilities=[ProcessingCapability(id="snapshots"), ProcessingCapability(id="fts")],
)
registry = ExtensionRegistry([local, selector])
assert [descriptor.id for descriptor in registry.list()] == [
"backend.local-sqlite",
"query.selector",
]
assert [descriptor.id for descriptor in registry.list(kind="query-engine")] == [
"query.selector"
]
assert [descriptor.id for descriptor in registry.require_capability("fts")] == [
"backend.local-sqlite"
]
assert registry.require_capability("missing") == []
assert registry.list(kind="missing") == []
def test_extension_registry_rejects_duplicate_ids():
descriptor = ExtensionDescriptor(id="query.selector", kind="query-engine")
registry = ExtensionRegistry([descriptor])
with pytest.raises(ExtensionRegistryError, match="Duplicate extension id"):
registry.register(descriptor)
def test_extension_registry_checks_optional_dependencies():
registry = ExtensionRegistry(
[
ExtensionDescriptor(
id="query.jsonpath",
kind="query-engine",
optional_dependencies=[
OptionalDependency(
name="jsonpath_ng",
package="jsonpath-ng",
extra="query",
required=True,
),
OptionalDependency(name="tabulate"),
],
)
]
)
missing = registry.check_dependencies("query.jsonpath", available_modules=set())
available = registry.check_dependencies(
"query.jsonpath",
available_modules={"jsonpath_ng", "tabulate"},
)
assert not missing.compatible
assert missing.missing == ["jsonpath_ng"]
assert missing.optional_missing == ["tabulate"]
assert available.compatible
def test_extension_descriptor_instantiates_factory():
descriptor = ExtensionDescriptor(
id="fake.extension",
kind="test",
factory=lambda: {"ready": True},
)
assert descriptor.instantiate() == {"ready": True}
def test_extension_descriptor_requires_factory_to_instantiate():
descriptor = ExtensionDescriptor(id="fake.extension", kind="test")
with pytest.raises(ExtensionRegistryError, match="has no factory"):
descriptor.instantiate()