mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
145 lines
4.5 KiB
Python
145 lines
4.5 KiB
Python
"""Tests for link resolution service."""
|
|
|
|
import pytest
|
|
|
|
import pytest_asyncio
|
|
|
|
from basic_memory.schemas.base import Entity as EntitySchema
|
|
from basic_memory.services.link_resolver import LinkResolver
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def test_entities(entity_service, file_service):
|
|
"""Create a set of test entities."""
|
|
|
|
e1, _ = await entity_service.create_or_update_entity(
|
|
EntitySchema(
|
|
title="Core Service",
|
|
entity_type="component",
|
|
folder="components",
|
|
)
|
|
)
|
|
e2, _ = await entity_service.create_or_update_entity(
|
|
EntitySchema(
|
|
title="Service Config",
|
|
entity_type="config",
|
|
folder="config",
|
|
)
|
|
)
|
|
e3, _ = await entity_service.create_or_update_entity(
|
|
EntitySchema(
|
|
title="Auth Service",
|
|
entity_type="component",
|
|
folder="components",
|
|
)
|
|
)
|
|
e4, _ = await entity_service.create_or_update_entity(
|
|
EntitySchema(
|
|
title="Core Features",
|
|
entity_type="specs",
|
|
folder="specs",
|
|
)
|
|
)
|
|
|
|
return [e1, e2, e3, e4]
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def link_resolver(entity_repository, search_service, test_entities):
|
|
"""Create LinkResolver instance with indexed test data."""
|
|
# Index all test entities
|
|
for entity in test_entities:
|
|
await search_service.index_entity(entity)
|
|
|
|
return LinkResolver(entity_repository, search_service)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_exact_permalink_match(link_resolver, test_entities):
|
|
"""Test resolving a link that exactly matches a permalink."""
|
|
entity = await link_resolver.resolve_link("components/core-service")
|
|
assert entity.permalink == "components/core-service"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_exact_title_match(link_resolver, test_entities):
|
|
"""Test resolving a link that matches an entity title."""
|
|
entity = await link_resolver.resolve_link("Core Service")
|
|
assert entity.permalink == "components/core-service"
|
|
|
|
|
|
@pytest.mark.skip(reason="Fuzzy misspelling not yet implemented")
|
|
@pytest.mark.asyncio
|
|
async def test_fuzzy_title_match_misspelling(link_resolver):
|
|
# Test slight misspelling
|
|
result = await link_resolver.resolve_link("Core Servise")
|
|
assert result.permalink == "components/core-service"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_fuzzy_title_partial_match(link_resolver):
|
|
# Test partial match
|
|
result = await link_resolver.resolve_link("Auth Serv")
|
|
assert result.permalink == "components/auth-service"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_fuzzy_title_exact_match(link_resolver):
|
|
# Test partial match
|
|
result = await link_resolver.resolve_link("auth-service")
|
|
assert result.permalink == "components/auth-service"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_link_text_normalization(link_resolver):
|
|
"""Test link text normalization."""
|
|
# Basic normalization
|
|
text, alias = link_resolver._normalize_link_text("[[Core Service]]")
|
|
assert text == "Core Service"
|
|
assert alias is None
|
|
|
|
# With alias
|
|
text, alias = link_resolver._normalize_link_text("[[Core Service|Main Service]]")
|
|
assert text == "Core Service"
|
|
assert alias == "Main Service"
|
|
|
|
# Extra whitespace
|
|
text, alias = link_resolver._normalize_link_text(" [[ Core Service | Main Service ]] ")
|
|
assert text == "Core Service"
|
|
assert alias == "Main Service"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_resolve_none(link_resolver):
|
|
"""Test resolving non-existent entity."""
|
|
# Basic new entity
|
|
assert await link_resolver.resolve_link("New Feature") is None
|
|
|
|
|
|
@pytest.mark.skip("Advanced relevance scoring not yet implemented")
|
|
@pytest.mark.asyncio
|
|
async def test_multiple_matches_resolution(link_resolver):
|
|
"""Test resolution when multiple potential matches exist."""
|
|
# Add some similar entities
|
|
test_cases = [
|
|
{
|
|
"link": "Service", # Ambiguous
|
|
"expected_prefix": "components/", # Should prefer component directory match
|
|
},
|
|
{
|
|
"link": "Core", # Ambiguous
|
|
"expected_prefix": "specs/", # Should prefer specs directory match
|
|
},
|
|
{
|
|
"link": "Service",
|
|
"expected": "components/core-service", # Should pick shortest/highest scored
|
|
},
|
|
]
|
|
|
|
for case in test_cases:
|
|
result = await link_resolver.resolve_link(case["link"])
|
|
if "expected_prefix" in case:
|
|
assert result.startswith(case["expected_prefix"])
|
|
else:
|
|
assert result == case["expected"]
|