183 lines
6.6 KiB
Python
183 lines
6.6 KiB
Python
|
|
"""Unit tests for resolution strategies."""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from markitect.prompts.resolver.strategy import (
|
||
|
|
ResolutionConfig,
|
||
|
|
MultiSpaceResolutionStrategy,
|
||
|
|
SingleSpaceResolutionStrategy,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestResolutionConfig:
|
||
|
|
"""Tests for ResolutionConfig."""
|
||
|
|
|
||
|
|
def test_create_minimal_config(self):
|
||
|
|
"""Test creating config with only required fields."""
|
||
|
|
config = ResolutionConfig(space_id="space-1")
|
||
|
|
assert config.space_id == "space-1"
|
||
|
|
assert config.included_spaces == []
|
||
|
|
assert config.default_space_id is None
|
||
|
|
assert config.shared_space_id is None
|
||
|
|
assert config.max_generation_depth == 3
|
||
|
|
|
||
|
|
def test_create_full_config(self):
|
||
|
|
"""Test creating config with all fields."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
included_spaces=["space-2", "space-3"],
|
||
|
|
default_space_id="default-space",
|
||
|
|
shared_space_id="shared-space",
|
||
|
|
max_generation_depth=5,
|
||
|
|
)
|
||
|
|
assert config.space_id == "space-1"
|
||
|
|
assert config.included_spaces == ["space-2", "space-3"]
|
||
|
|
assert config.default_space_id == "default-space"
|
||
|
|
assert config.shared_space_id == "shared-space"
|
||
|
|
assert config.max_generation_depth == 5
|
||
|
|
|
||
|
|
def test_config_to_dict(self):
|
||
|
|
"""Test serialization."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
included_spaces=["space-2"],
|
||
|
|
)
|
||
|
|
data = config.to_dict()
|
||
|
|
assert data["space_id"] == "space-1"
|
||
|
|
assert data["included_spaces"] == ["space-2"]
|
||
|
|
assert "max_generation_depth" in data
|
||
|
|
|
||
|
|
def test_config_from_dict(self):
|
||
|
|
"""Test deserialization."""
|
||
|
|
data = {
|
||
|
|
"space_id": "space-1",
|
||
|
|
"included_spaces": ["space-2", "space-3"],
|
||
|
|
"default_space_id": "default",
|
||
|
|
"shared_space_id": "shared",
|
||
|
|
"max_generation_depth": 4,
|
||
|
|
}
|
||
|
|
config = ResolutionConfig.from_dict(data)
|
||
|
|
assert config.space_id == "space-1"
|
||
|
|
assert config.included_spaces == ["space-2", "space-3"]
|
||
|
|
assert config.default_space_id == "default"
|
||
|
|
assert config.shared_space_id == "shared"
|
||
|
|
assert config.max_generation_depth == 4
|
||
|
|
|
||
|
|
|
||
|
|
class TestMultiSpaceResolutionStrategy:
|
||
|
|
"""Tests for MultiSpaceResolutionStrategy."""
|
||
|
|
|
||
|
|
def setup_method(self):
|
||
|
|
"""Setup strategy for each test."""
|
||
|
|
self.strategy = MultiSpaceResolutionStrategy()
|
||
|
|
|
||
|
|
def test_search_order_local_only(self):
|
||
|
|
"""Test search order with only local space."""
|
||
|
|
config = ResolutionConfig(space_id="space-1")
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
assert order == ["space-1"]
|
||
|
|
|
||
|
|
def test_search_order_with_included(self):
|
||
|
|
"""Test search order with included spaces."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
included_spaces=["space-2", "space-3"],
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
assert order == ["space-1", "space-2", "space-3"]
|
||
|
|
|
||
|
|
def test_search_order_with_default(self):
|
||
|
|
"""Test search order with default space."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
default_space_id="default-space",
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
assert order == ["space-1", "default-space"]
|
||
|
|
|
||
|
|
def test_search_order_with_shared(self):
|
||
|
|
"""Test search order with shared space."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
shared_space_id="shared-space",
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
assert order == ["space-1", "shared-space"]
|
||
|
|
|
||
|
|
def test_search_order_full_config(self):
|
||
|
|
"""Test full resolution order (FR-3.1)."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="local",
|
||
|
|
included_spaces=["included-1", "included-2"],
|
||
|
|
default_space_id="default",
|
||
|
|
shared_space_id="shared",
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
# FR-3.1: Local, Included, Default, Shared
|
||
|
|
assert order == ["local", "included-1", "included-2", "default", "shared"]
|
||
|
|
|
||
|
|
def test_search_order_removes_duplicates(self):
|
||
|
|
"""Test that duplicates are removed."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
included_spaces=["space-2", "space-1", "space-3"], # space-1 duplicate
|
||
|
|
default_space_id="space-2", # space-2 duplicate
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
# Should have each space only once, preserving first occurrence
|
||
|
|
assert order == ["space-1", "space-2", "space-3"]
|
||
|
|
assert len(order) == 3
|
||
|
|
|
||
|
|
def test_search_order_preserves_included_order(self):
|
||
|
|
"""Test that included spaces order is preserved."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
included_spaces=["space-a", "space-b", "space-c"],
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
# Included spaces should appear in specified order
|
||
|
|
assert order.index("space-a") < order.index("space-b")
|
||
|
|
assert order.index("space-b") < order.index("space-c")
|
||
|
|
|
||
|
|
def test_search_order_priority(self):
|
||
|
|
"""Test search order priority."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="local",
|
||
|
|
included_spaces=["included"],
|
||
|
|
default_space_id="default",
|
||
|
|
shared_space_id="shared",
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
# Local has highest priority (index 0)
|
||
|
|
assert order[0] == "local"
|
||
|
|
# Shared has lowest priority (last index)
|
||
|
|
assert order[-1] == "shared"
|
||
|
|
|
||
|
|
|
||
|
|
class TestSingleSpaceResolutionStrategy:
|
||
|
|
"""Tests for SingleSpaceResolutionStrategy."""
|
||
|
|
|
||
|
|
def setup_method(self):
|
||
|
|
"""Setup strategy for each test."""
|
||
|
|
self.strategy = SingleSpaceResolutionStrategy()
|
||
|
|
|
||
|
|
def test_search_order_only_local(self):
|
||
|
|
"""Test that only local space is returned."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="space-1",
|
||
|
|
included_spaces=["space-2", "space-3"],
|
||
|
|
default_space_id="default",
|
||
|
|
shared_space_id="shared",
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
assert order == ["space-1"]
|
||
|
|
|
||
|
|
def test_search_order_ignores_other_spaces(self):
|
||
|
|
"""Test that other configured spaces are ignored."""
|
||
|
|
config = ResolutionConfig(
|
||
|
|
space_id="my-space",
|
||
|
|
included_spaces=["ignored-1", "ignored-2"],
|
||
|
|
)
|
||
|
|
order = self.strategy.get_search_order(config)
|
||
|
|
assert len(order) == 1
|
||
|
|
assert order[0] == "my-space"
|