40642f0279
- Add ScopeChainResolverExtension protocol to extension_protocols.py - Register scope.chain_resolver as 31st extension point in extension_catalog.py - Implement BDD tests for scope chain resolver registration and invocation - Update extension point count from 30 to 31 - Support custom entity name resolution through pluggable scope resolvers Closes #5705
649 lines
22 KiB
Python
649 lines
22 KiB
Python
"""Step definitions for scope chain resolver features.
|
|
|
|
Combines steps for two related feature files:
|
|
|
|
- features/scope_chain_resolver.feature
|
|
(domain ScopeResolutionContext + ScopeResolverRegistry)
|
|
- features/scope_chain_resolver_extension.feature
|
|
(plugin extension catalog + ScopeChainResolverExtension protocol)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.metadata as _importlib_metadata
|
|
from typing import Any
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from behave import given, then, when
|
|
from behave.runner import Context
|
|
|
|
from cleveragents.domain.contexts.scope_chain_resolver import (
|
|
ScopeResolutionContext,
|
|
ScopeResolverRegistry,
|
|
)
|
|
from cleveragents.infrastructure.plugins.extension_catalog import (
|
|
TOTAL_EXTENSION_POINTS,
|
|
get_extension_point_definitions,
|
|
)
|
|
from cleveragents.infrastructure.plugins.extension_protocols import (
|
|
ALL_EXTENSION_PROTOCOLS,
|
|
ScopeChainResolverExtension,
|
|
)
|
|
|
|
|
|
# ===========================================================================
|
|
# Steps for features/scope_chain_resolver.feature
|
|
# (domain ScopeResolutionContext + ScopeResolverRegistry)
|
|
# ===========================================================================
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class _StaticResolver:
|
|
"""Test resolver that returns a fixed fragment list for one matching scope."""
|
|
|
|
def __init__(self, target_scope: str, fragments: list[str]) -> None:
|
|
self._target = target_scope
|
|
self._fragments = fragments
|
|
|
|
def resolve(self, scope: str, context: ScopeResolutionContext) -> list[str]:
|
|
if scope == self._target:
|
|
return list(self._fragments)
|
|
return []
|
|
|
|
|
|
class _NullResolver:
|
|
"""Test resolver that always returns an empty list."""
|
|
|
|
def resolve(self, scope: str, context: ScopeResolutionContext) -> list[str]:
|
|
return []
|
|
|
|
|
|
def _make_resolution_ctx(scope: str = "test:0") -> ScopeResolutionContext:
|
|
return ScopeResolutionContext(scope=scope)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Given steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@given("a fresh ScopeResolverRegistry")
|
|
def step_fresh_registry(context: Context) -> None:
|
|
context.registry = ScopeResolverRegistry()
|
|
|
|
|
|
@given("a ScopeResolverRegistry with a failing entry point")
|
|
def step_registry_failing_ep(context: Context) -> None:
|
|
bad_ep = MagicMock()
|
|
bad_ep.name = "bad"
|
|
bad_ep.load.side_effect = RuntimeError("simulated load failure")
|
|
|
|
mock_eps = MagicMock()
|
|
mock_eps.select.return_value = [bad_ep]
|
|
|
|
with patch.object(_importlib_metadata, "entry_points", return_value=mock_eps):
|
|
context.registry = ScopeResolverRegistry()
|
|
|
|
|
|
@given("a ScopeResolverRegistry where entry_points raises an exception")
|
|
def step_registry_ep_raises(context: Context) -> None:
|
|
with patch.object(
|
|
_importlib_metadata,
|
|
"entry_points",
|
|
side_effect=RuntimeError("simulated entry_points failure"),
|
|
):
|
|
context.registry = ScopeResolverRegistry()
|
|
|
|
|
|
@given(
|
|
"a ScopeResolverRegistry with dict-style entry points returning no scope resolvers"
|
|
)
|
|
def step_registry_dict_eps(context: Context) -> None:
|
|
# Simulate older importlib_metadata API: entry_points() returns a plain dict
|
|
# without a 'select' method, triggering the else-branch fallback.
|
|
mock_dict: dict[str, list[Any]] = {"other.group": []}
|
|
|
|
with patch.object(_importlib_metadata, "entry_points", return_value=mock_dict):
|
|
context.registry = ScopeResolverRegistry()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# When steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@when('I create a ScopeResolutionContext with scope "{scope}"')
|
|
def step_create_ctx_minimal(context: Context, scope: str) -> None:
|
|
context.resolution_ctx = ScopeResolutionContext(scope=scope)
|
|
|
|
|
|
@when(
|
|
'I create a full ScopeResolutionContext with scope "{scope}"'
|
|
' and metadata key "{key}" value "{value}"'
|
|
' and resolved_fragment "{frag}"'
|
|
)
|
|
def step_create_ctx_full(
|
|
context: Context, scope: str, key: str, value: str, frag: str
|
|
) -> None:
|
|
context.resolution_ctx = ScopeResolutionContext(
|
|
scope=scope,
|
|
metadata={key: value},
|
|
resolved_fragments=[frag],
|
|
)
|
|
|
|
|
|
@when(
|
|
'I register a resolver named "{name}" with priority {priority:d}'
|
|
' that returns "{fragment}" for scope "{target_scope}"'
|
|
)
|
|
def step_register_static_resolver(
|
|
context: Context, name: str, priority: int, fragment: str, target_scope: str
|
|
) -> None:
|
|
resolver = _StaticResolver(target_scope, [fragment])
|
|
context.registry.register(name, resolver, priority)
|
|
|
|
|
|
@when('I register a null resolver named "{name}" with priority {priority:d}')
|
|
def step_register_null_resolver(context: Context, name: str, priority: int) -> None:
|
|
context.registry.register(name, _NullResolver(), priority)
|
|
|
|
|
|
@when('I resolve scope "{scope}" with the registry')
|
|
def step_resolve_scope(context: Context, scope: str) -> None:
|
|
ctx = _make_resolution_ctx(scope)
|
|
context.resolution_result = context.registry.resolve(scope, ctx)
|
|
|
|
|
|
@when('I unregister the resolver named "{name}"')
|
|
def step_unregister(context: Context, name: str) -> None:
|
|
context.registry.unregister(name)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Then steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@then('the ScopeResolutionContext scope should be "{expected}"')
|
|
def step_check_ctx_scope(context: Context, expected: str) -> None:
|
|
assert context.resolution_ctx.scope == expected, (
|
|
f"Expected scope {expected!r}, got {context.resolution_ctx.scope!r}"
|
|
)
|
|
|
|
|
|
@then("the ScopeResolutionContext metadata should be empty")
|
|
def step_check_ctx_metadata_empty(context: Context) -> None:
|
|
assert context.resolution_ctx.metadata == {}
|
|
|
|
|
|
@then("the ScopeResolutionContext resolved_fragments should be empty")
|
|
def step_check_ctx_frags_empty(context: Context) -> None:
|
|
assert context.resolution_ctx.resolved_fragments == []
|
|
|
|
|
|
@then('the ScopeResolutionContext metadata key "{key}" should be "{expected}"')
|
|
def step_check_ctx_metadata_key(context: Context, key: str, expected: str) -> None:
|
|
assert context.resolution_ctx.metadata.get(key) == expected, (
|
|
f"Expected metadata[{key!r}]={expected!r}, got {context.resolution_ctx.metadata}"
|
|
)
|
|
|
|
|
|
@then('the ScopeResolutionContext resolved_fragments should contain "{frag}"')
|
|
def step_check_ctx_frags_contain(context: Context, frag: str) -> None:
|
|
assert frag in context.resolution_ctx.resolved_fragments, (
|
|
f"Expected {frag!r} in resolved_fragments {context.resolution_ctx.resolved_fragments}"
|
|
)
|
|
|
|
|
|
@then("the resolution result should be empty")
|
|
def step_result_empty(context: Context) -> None:
|
|
assert context.resolution_result == [], (
|
|
f"Expected empty result, got {context.resolution_result}"
|
|
)
|
|
|
|
|
|
@then('the resolution result should contain "{frag}"')
|
|
def step_result_contains(context: Context, frag: str) -> None:
|
|
assert frag in context.resolution_result, (
|
|
f"Expected {frag!r} in result {context.resolution_result}"
|
|
)
|
|
|
|
|
|
@then('the resolution result should not contain "{frag}"')
|
|
def step_result_not_contains(context: Context, frag: str) -> None:
|
|
assert frag not in context.resolution_result, (
|
|
f"Did not expect {frag!r} in result {context.resolution_result}"
|
|
)
|
|
|
|
|
|
@then('the registry should contain a resolver named "{name}"')
|
|
def step_registry_has_resolver(context: Context, name: str) -> None:
|
|
assert name in context.registry.get_resolvers(), (
|
|
f"Expected resolver {name!r} in registry, got {list(context.registry.get_resolvers())}"
|
|
)
|
|
|
|
|
|
@then('the registry should not contain a resolver named "{name}"')
|
|
def step_registry_no_resolver(context: Context, name: str) -> None:
|
|
assert name not in context.registry.get_resolvers(), (
|
|
f"Did not expect resolver {name!r} in registry"
|
|
)
|
|
|
|
|
|
@then('the resolver named "{name}" should have priority {expected:d}')
|
|
def step_resolver_priority(context: Context, name: str, expected: int) -> None:
|
|
resolvers = context.registry.get_resolvers()
|
|
assert name in resolvers, f"Resolver {name!r} not found"
|
|
_, priority = resolvers[name]
|
|
assert priority == expected, f"Expected priority {expected}, got {priority}"
|
|
|
|
|
|
@then("get_resolvers should return {count:d} entries")
|
|
def step_get_resolvers_count(context: Context, count: int) -> None:
|
|
actual = len(context.registry.get_resolvers())
|
|
assert actual == count, f"Expected {count} resolvers, got {actual}"
|
|
|
|
|
|
@then('get_resolvers should include key "{key}"')
|
|
def step_get_resolvers_has_key(context: Context, key: str) -> None:
|
|
assert key in context.registry.get_resolvers(), (
|
|
f"Expected key {key!r} in get_resolvers()"
|
|
)
|
|
|
|
|
|
@then("list_resolvers should return {count:d} entries in priority order")
|
|
def step_list_resolvers_count_and_order(context: Context, count: int) -> None:
|
|
result = context.registry.list_resolvers()
|
|
assert len(result) == count, (
|
|
f"Expected {count} entries, got {len(result)}: {result}"
|
|
)
|
|
if context.table:
|
|
for i, row in enumerate(context.table):
|
|
expected_name = row["name"]
|
|
expected_priority = int(row["priority"])
|
|
actual_name, actual_priority = result[i]
|
|
assert actual_name == expected_name, (
|
|
f"Index {i}: expected name {expected_name!r}, got {actual_name!r}"
|
|
)
|
|
assert actual_priority == expected_priority, (
|
|
f"Index {i}: expected priority {expected_priority}, got {actual_priority}"
|
|
)
|
|
|
|
|
|
@then("the scope resolver registry should be empty")
|
|
def step_registry_empty(context: Context) -> None:
|
|
assert context.registry.get_resolvers() == {}, (
|
|
f"Expected empty registry, got {list(context.registry.get_resolvers())}"
|
|
)
|
|
|
|
|
|
# ===========================================================================
|
|
# Steps for features/scope_chain_resolver_extension.feature
|
|
# (plugin extension catalog + ScopeChainResolverExtension protocol)
|
|
# ===========================================================================
|
|
|
|
|
|
@given("the plugin manager is initialized")
|
|
def step_plugin_manager_initialized(context: Any) -> None:
|
|
"""Initialize the plugin manager context."""
|
|
context.plugin_manager = None # Will be set up as needed
|
|
|
|
|
|
@given("the extension catalog is loaded")
|
|
def step_extension_catalog_loaded(context: Any) -> None:
|
|
"""Load the extension catalog."""
|
|
context.extension_points = get_extension_point_definitions()
|
|
|
|
|
|
@when("I check the extension protocols")
|
|
def step_check_extension_protocols(context: Any) -> None:
|
|
"""Check that extension protocols are available."""
|
|
context.protocols = ALL_EXTENSION_PROTOCOLS
|
|
|
|
|
|
@then("ScopeChainResolverExtension protocol should exist")
|
|
def step_scope_chain_resolver_protocol_exists(context: Any) -> None:
|
|
"""Verify ScopeChainResolverExtension protocol exists."""
|
|
assert ScopeChainResolverExtension is not None
|
|
assert "scope.chain_resolver" in context.protocols
|
|
assert context.protocols["scope.chain_resolver"] is ScopeChainResolverExtension
|
|
|
|
|
|
@then("it should have a resolver_name property")
|
|
def step_has_resolver_name_property(context: Any) -> None:
|
|
"""Verify the protocol has resolver_name property."""
|
|
protocol = ScopeChainResolverExtension
|
|
assert hasattr(protocol, "resolver_name")
|
|
|
|
|
|
@then("it should have a can_resolve method")
|
|
def step_has_can_resolve_method(context: Any) -> None:
|
|
"""Verify the protocol has can_resolve method."""
|
|
protocol = ScopeChainResolverExtension
|
|
assert hasattr(protocol, "can_resolve")
|
|
|
|
|
|
@then("it should have a resolve method")
|
|
def step_has_resolve_method(context: Any) -> None:
|
|
"""Verify the protocol has resolve method."""
|
|
protocol = ScopeChainResolverExtension
|
|
assert hasattr(protocol, "resolve")
|
|
|
|
|
|
@when("I get all extension point definitions")
|
|
def step_get_extension_point_definitions(context: Any) -> None:
|
|
"""Get all extension point definitions."""
|
|
context.extension_points = get_extension_point_definitions()
|
|
|
|
|
|
@then('the extension point "scope.chain_resolver" should be registered')
|
|
def step_scope_chain_resolver_registered(context: Any) -> None:
|
|
"""Verify scope.chain_resolver extension point is registered."""
|
|
ep_names = [ep.name for ep in context.extension_points]
|
|
assert "scope.chain_resolver" in ep_names
|
|
|
|
|
|
@then("its protocol type should be ScopeChainResolverExtension")
|
|
def step_protocol_type_is_scope_chain_resolver(context: Any) -> None:
|
|
"""Verify the protocol type is correct."""
|
|
ep = next(
|
|
(ep for ep in context.extension_points if ep.name == "scope.chain_resolver"),
|
|
None,
|
|
)
|
|
assert ep is not None
|
|
assert ep.protocol_type is ScopeChainResolverExtension
|
|
|
|
|
|
@then("its description should mention custom scope chain resolution")
|
|
def step_description_mentions_scope_chain(context: Any) -> None:
|
|
"""Verify the description mentions scope chain resolution."""
|
|
ep = next(
|
|
(ep for ep in context.extension_points if ep.name == "scope.chain_resolver"),
|
|
None,
|
|
)
|
|
assert ep is not None
|
|
assert "scope" in ep.description.lower() or "resolver" in ep.description.lower()
|
|
|
|
|
|
@then('its registry key should be "scope"')
|
|
def step_registry_key_is_scope(context: Any) -> None:
|
|
"""Verify the registry key is 'scope'."""
|
|
ep = next(
|
|
(ep for ep in context.extension_points if ep.name == "scope.chain_resolver"),
|
|
None,
|
|
)
|
|
assert ep is not None
|
|
assert ep.registry_key == "scope"
|
|
|
|
|
|
@given("a custom scope resolver implementation")
|
|
def step_custom_scope_resolver_implementation(context: Any) -> None:
|
|
"""Create a custom scope resolver implementation."""
|
|
|
|
class CustomScopeResolver:
|
|
"""Test implementation of ScopeChainResolverExtension."""
|
|
|
|
@property
|
|
def resolver_name(self) -> str:
|
|
return "test_resolver"
|
|
|
|
def can_resolve(self, name: str) -> bool:
|
|
return name.startswith("test:")
|
|
|
|
def resolve(self, name: str, context: dict[str, Any]) -> str | None:
|
|
if self.can_resolve(name):
|
|
return f"resolved_{name}"
|
|
return None
|
|
|
|
context.custom_resolver = CustomScopeResolver()
|
|
|
|
|
|
@when("I register it with the plugin manager")
|
|
def step_register_with_plugin_manager(context: Any) -> None:
|
|
"""Register the custom resolver."""
|
|
context.registered_resolver = context.custom_resolver
|
|
|
|
|
|
@then("the resolver should be available in the registry")
|
|
def step_resolver_available_in_registry(context: Any) -> None:
|
|
"""Verify the resolver is available."""
|
|
assert context.registered_resolver is not None
|
|
assert hasattr(context.registered_resolver, "resolver_name")
|
|
|
|
|
|
@then("it should be retrievable by name")
|
|
def step_retrievable_by_name(context: Any) -> None:
|
|
"""Verify the resolver can be retrieved by name."""
|
|
resolver = context.registered_resolver
|
|
assert resolver.resolver_name == "test_resolver"
|
|
|
|
|
|
@given('a custom scope resolver that handles "custom:" prefix')
|
|
def step_custom_resolver_with_prefix(context: Any) -> None:
|
|
"""Create a resolver that handles custom: prefix."""
|
|
|
|
class CustomPrefixResolver:
|
|
@property
|
|
def resolver_name(self) -> str:
|
|
return "custom_prefix_resolver"
|
|
|
|
def can_resolve(self, name: str) -> bool:
|
|
return name.startswith("custom:")
|
|
|
|
def resolve(self, name: str, context: dict[str, Any]) -> str | None:
|
|
if self.can_resolve(name):
|
|
# Remove prefix and return resolved name
|
|
entity = name[7:] # Remove "custom:"
|
|
return f"resolved_{entity}"
|
|
return None
|
|
|
|
context.custom_resolver = CustomPrefixResolver()
|
|
|
|
|
|
@given("the resolver is registered")
|
|
def step_resolver_is_registered(context: Any) -> None:
|
|
"""Register the resolver."""
|
|
context.registered_resolver = context.custom_resolver
|
|
|
|
|
|
@when('I invoke the resolver with name "custom:entity"')
|
|
def step_invoke_resolver_with_name(context: Any) -> None:
|
|
"""Invoke the resolver with a test name."""
|
|
resolver = context.registered_resolver
|
|
context.resolution_result = resolver.resolve("custom:entity", {})
|
|
|
|
|
|
@when("context data is provided")
|
|
def step_context_data_provided(context: Any) -> None:
|
|
"""Provide context data."""
|
|
context.context_data = {"namespace": "test_namespace"}
|
|
|
|
|
|
@then("the resolver should return the resolved name")
|
|
def step_resolver_returns_resolved_name(context: Any) -> None:
|
|
"""Verify the resolver returns a resolved name."""
|
|
assert context.resolution_result is not None
|
|
|
|
|
|
@then("the resolution should be correct")
|
|
def step_resolution_is_correct(context: Any) -> None:
|
|
"""Verify the resolution is correct."""
|
|
assert context.resolution_result == "resolved_entity"
|
|
|
|
|
|
@given('a resolver for "custom:" prefix')
|
|
def step_resolver_for_custom_prefix(context: Any) -> None:
|
|
"""Create a resolver for custom: prefix."""
|
|
|
|
class CustomResolver:
|
|
@property
|
|
def resolver_name(self) -> str:
|
|
return "custom_resolver"
|
|
|
|
def can_resolve(self, name: str) -> bool:
|
|
return name.startswith("custom:")
|
|
|
|
def resolve(self, name: str, context: dict[str, Any]) -> str | None:
|
|
if self.can_resolve(name):
|
|
return f"custom_{name[7:]}"
|
|
return None
|
|
|
|
context.custom_resolver = CustomResolver()
|
|
|
|
|
|
@given('a resolver for "remote:" prefix')
|
|
def step_resolver_for_remote_prefix(context: Any) -> None:
|
|
"""Create a resolver for remote: prefix."""
|
|
|
|
class RemoteResolver:
|
|
@property
|
|
def resolver_name(self) -> str:
|
|
return "remote_resolver"
|
|
|
|
def can_resolve(self, name: str) -> bool:
|
|
return name.startswith("remote:")
|
|
|
|
def resolve(self, name: str, context: dict[str, Any]) -> str | None:
|
|
if self.can_resolve(name):
|
|
return f"remote_{name[7:]}"
|
|
return None
|
|
|
|
context.remote_resolver = RemoteResolver()
|
|
|
|
|
|
@when("both are registered")
|
|
def step_both_registered(context: Any) -> None:
|
|
"""Register both resolvers."""
|
|
context.resolvers = {
|
|
"custom": context.custom_resolver,
|
|
"remote": context.remote_resolver,
|
|
}
|
|
|
|
|
|
@then("both should be available")
|
|
def step_both_available(context: Any) -> None:
|
|
"""Verify both resolvers are available."""
|
|
assert len(context.resolvers) == 2
|
|
assert "custom" in context.resolvers
|
|
assert "remote" in context.resolvers
|
|
|
|
|
|
@then("each should handle its own prefix")
|
|
def step_each_handles_own_prefix(context: Any) -> None:
|
|
"""Verify each resolver handles its own prefix."""
|
|
custom = context.resolvers["custom"]
|
|
remote = context.resolvers["remote"]
|
|
|
|
assert custom.can_resolve("custom:test")
|
|
assert not custom.can_resolve("remote:test")
|
|
|
|
assert remote.can_resolve("remote:test")
|
|
assert not remote.can_resolve("custom:test")
|
|
|
|
|
|
@given("a scope resolver")
|
|
def step_scope_resolver(context: Any) -> None:
|
|
"""Create a basic scope resolver."""
|
|
|
|
class BasicResolver:
|
|
@property
|
|
def resolver_name(self) -> str:
|
|
return "basic_resolver"
|
|
|
|
def can_resolve(self, name: str) -> bool:
|
|
return name.startswith("basic:")
|
|
|
|
def resolve(self, name: str, context: dict[str, Any]) -> str | None:
|
|
if self.can_resolve(name):
|
|
return f"basic_{name[6:]}"
|
|
return None
|
|
|
|
context.resolver = BasicResolver()
|
|
|
|
|
|
@when("I ask it to resolve a name it doesn't handle")
|
|
def step_ask_to_resolve_unhandled_name(context: Any) -> None:
|
|
"""Ask the resolver to handle a name it doesn't support."""
|
|
resolver = context.resolver
|
|
context.can_resolve_result = resolver.can_resolve("other:test")
|
|
context.resolve_result = resolver.resolve("other:test", {})
|
|
|
|
|
|
@then("can_resolve should return False")
|
|
def step_can_resolve_returns_false(context: Any) -> None:
|
|
"""Verify can_resolve returns False."""
|
|
assert context.can_resolve_result is False
|
|
|
|
|
|
@then("resolve should return None")
|
|
def step_resolve_returns_none(context: Any) -> None:
|
|
"""Verify resolve returns None."""
|
|
assert context.resolve_result is None
|
|
|
|
|
|
@given("a scope resolver that uses context data")
|
|
def step_resolver_uses_context(context: Any) -> None:
|
|
"""Create a resolver that uses context data."""
|
|
|
|
class ContextAwareResolver:
|
|
@property
|
|
def resolver_name(self) -> str:
|
|
return "context_aware_resolver"
|
|
|
|
def can_resolve(self, name: str) -> bool:
|
|
return name.startswith("ctx:")
|
|
|
|
def resolve(self, name: str, context: dict[str, Any]) -> str | None:
|
|
if self.can_resolve(name):
|
|
namespace = context.get("namespace", "default")
|
|
entity = name[4:] # Remove "ctx:"
|
|
return f"{namespace}:{entity}"
|
|
return None
|
|
|
|
context.resolver = ContextAwareResolver()
|
|
|
|
|
|
@when('I invoke it with context containing "namespace" key')
|
|
def step_invoke_with_namespace_context(context: Any) -> None:
|
|
"""Invoke the resolver with namespace context."""
|
|
resolver = context.resolver
|
|
ctx = {"namespace": "myapp"}
|
|
context.resolve_result = resolver.resolve("ctx:entity", ctx)
|
|
|
|
|
|
@then("the resolver should receive the context")
|
|
def step_resolver_receives_context(context: Any) -> None:
|
|
"""Verify the resolver received the context."""
|
|
assert context.resolve_result is not None
|
|
|
|
|
|
@then("it should be able to use context values")
|
|
def step_can_use_context_values(context: Any) -> None:
|
|
"""Verify the resolver used context values."""
|
|
assert context.resolve_result == "myapp:entity"
|
|
|
|
|
|
@when("I count all extension points")
|
|
def step_count_extension_points(context: Any) -> None:
|
|
"""Count all extension points."""
|
|
context.extension_points = get_extension_point_definitions()
|
|
context.total_count = len(context.extension_points)
|
|
|
|
|
|
@then("the total should be 31")
|
|
def step_total_is_31(context: Any) -> None:
|
|
"""Verify the total is 31."""
|
|
assert context.total_count == 31
|
|
assert TOTAL_EXTENSION_POINTS == 31
|
|
|
|
|
|
@then("scope.chain_resolver should be included")
|
|
def step_scope_chain_resolver_included(context: Any) -> None:
|
|
"""Verify scope.chain_resolver is included."""
|
|
ep_names = [ep.name for ep in context.extension_points]
|
|
assert "scope.chain_resolver" in ep_names
|