263 lines
8.7 KiB
Python
263 lines
8.7 KiB
Python
"""
|
|
Tests for mcp-server/server.py
|
|
|
|
These are pure unit tests that don't require any external dependencies.
|
|
They test:
|
|
- The strip_local_prefix() function directly (no network)
|
|
- MCP server tool definitions and structure
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
class TestStripLocalPrefix:
|
|
"""Tests for the strip_local_prefix() function."""
|
|
|
|
def test_strips_prefix_from_full_id(self):
|
|
"""Should strip /local/ prefix from full library ID."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = "/local/foundryvtt"
|
|
expected_output = "foundryvtt"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == expected_output
|
|
|
|
def test_preserves_id_without_prefix(self):
|
|
"""Should preserve ID that doesn't have /local/ prefix."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = "foundryvtt"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == input_id # Should be unchanged
|
|
|
|
def test_strips_from_multiple_local_prefixes(self):
|
|
"""Should handle edge case of multiple prefixes."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = "/local//local/foundryvtt"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
# Should only strip first occurrence
|
|
assert result == "/local/foundryvtt"
|
|
|
|
def test_empty_string(self):
|
|
"""Empty string should remain empty."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = ""
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == input_id # Should be unchanged
|
|
|
|
def test_whitespace_only(self):
|
|
"""Whitespace only should remain whitespace (no /local/ to strip)."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = " \t\n"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == input_id
|
|
|
|
def test_case_sensitive_prefix(self):
|
|
"""Prefix matching is case-sensitive."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
# Lowercase - should strip
|
|
result1 = strip_local_prefix("/local/test")
|
|
assert result1 == "test"
|
|
|
|
# Uppercase - should NOT strip (not a match)
|
|
result2 = strip_local_prefix("/LOCAL/test")
|
|
assert result2 == "/LOCAL/test" # Unchanged
|
|
|
|
def test_partial_match_does_not_strip(self):
|
|
"""Only exact /local/ prefix is stripped, not partial matches."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
# Partial match - should NOT strip
|
|
input_id = "/local-docs/test"
|
|
result = strip_local_prefix(input_id)
|
|
assert result == input_id # Unchanged
|
|
|
|
# Different separator - should NOT strip
|
|
input_id2 = "/localdocs/test"
|
|
result2 = strip_local_prefix(input_id2)
|
|
assert result2 == input_id2
|
|
|
|
def test_prefix_with_trailing_slash(self):
|
|
"""Should handle trailing slash in ID."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = "/local/foundryvtt/"
|
|
expected_output = "foundryvtt/"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == expected_output
|
|
|
|
|
|
class TestMcpServerStructure:
|
|
"""Tests for MCP server tool structure (without starting the server)."""
|
|
|
|
def test_import_fastmcp(self):
|
|
"""Should be able to import FastMCP."""
|
|
try:
|
|
from fastmcp import FastMCP
|
|
# Import successful
|
|
except ImportError as e:
|
|
pytest.skip(f"fastmcp not installed: {e}")
|
|
|
|
|
|
class TestMcpServerToolsExistence:
|
|
"""Tests to verify MCP server has expected tools defined."""
|
|
|
|
def test_mcp_instance_created(self):
|
|
"""MCP instance should be created with tools."""
|
|
from mcp_server.server import mcp
|
|
|
|
assert mcp is not None
|
|
|
|
def test_resolve_library_id_tool_exists(self):
|
|
"""resolve-library-id tool should be registered."""
|
|
from mcp_server.server import mcp
|
|
|
|
# Check if the tool exists by trying to access it
|
|
if hasattr(mcp, 'tools'):
|
|
tool_names = [t.name for t in mcp.tools]
|
|
assert "resolve_library_id" in tool_names
|
|
|
|
def test_get_library_docs_tool_exists(self):
|
|
"""get-library-docs tool should be registered."""
|
|
from mcp_server.server import mcp
|
|
|
|
if hasattr(mcp, 'tools'):
|
|
tool_names = [t.name for t in mcp.tools]
|
|
assert "get_library_docs" in tool_names
|
|
|
|
def test_list_libraries_tool_exists(self):
|
|
"""list-libraries tool should be registered."""
|
|
from mcp_server.server import mcp
|
|
|
|
if hasattr(mcp, 'tools'):
|
|
tool_names = [t.name for t in mcp.tools]
|
|
assert "list_libraries" in tool_names
|
|
|
|
def test_search_docs_tool_exists(self):
|
|
"""search-docs tool should be registered."""
|
|
from mcp_server.server import mcp
|
|
|
|
if hasattr(mcp, 'tools'):
|
|
tool_names = [t.name for t in mcp.tools]
|
|
assert "search_docs" in tool_names
|
|
|
|
def test_refresh_library_tool_exists(self):
|
|
"""refresh-library tool should be registered."""
|
|
from mcp_server.server import mcp
|
|
|
|
if hasattr(mcp, 'tools'):
|
|
tool_names = [t.name for t in mcp.tools]
|
|
assert "refresh_library" in tool_names
|
|
|
|
def test_sync_sources_tool_exists(self):
|
|
"""sync-sources tool should be registered."""
|
|
from mcp_server.server import mcp
|
|
|
|
if hasattr(mcp, 'tools'):
|
|
tool_names = [t.name for t in mcp.tools]
|
|
assert "sync_sources" in tool_names
|
|
|
|
|
|
class TestMcpServerStripPrefixIntegration:
|
|
"""Integration tests for strip_prefix usage in MCP server functions."""
|
|
|
|
def test_resolve_library_id_calls_strip_prefix(self):
|
|
"""resolve_library_id should handle /local/ prefix in responses."""
|
|
# This test verifies that the tool is available and uses the prefix correctly
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
# Verify the function exists and works
|
|
assert callable(strip_local_prefix)
|
|
|
|
# Test with sample IDs
|
|
test_ids = [
|
|
"/local/foundryvtt",
|
|
"/local/pytest",
|
|
"/local/mydocs/reference",
|
|
]
|
|
|
|
for lib_id in test_ids:
|
|
stripped = strip_local_prefix(lib_id)
|
|
assert not stripped.startswith("/local/")
|
|
|
|
|
|
class TestMcpServerPrefixHandlingVariations:
|
|
"""Additional tests for prefix handling variations."""
|
|
|
|
def test_long_library_id(self):
|
|
"""Should handle long library IDs with /local/ prefix."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = "/local/very-long-library-id-with-many-chars-in-name"
|
|
expected_output = "very-long-library-id-with-many-chars-in-name"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == expected_output
|
|
|
|
def test_special_characters_in_id(self):
|
|
"""Should handle special characters in library ID."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
# IDs can have underscores, dashes, numbers
|
|
input_id = "/local/my-doc_v2-3_test"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == "my-doc_v2-3_test"
|
|
|
|
def test_unicode_in_stripped_name(self):
|
|
"""Stripped name should preserve unicode characters."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
# Library IDs sometimes have unicode in them
|
|
input_id = "/local/世界文档" # Chinese characters
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == "世界文档"
|
|
|
|
def test_mixed_case_stripped_name(self):
|
|
"""Stripped name can have mixed case."""
|
|
from mcp_server.server import strip_local_prefix
|
|
|
|
input_id = "/local/FoundryVTT"
|
|
|
|
result = strip_local_prefix(input_id)
|
|
assert result == "FoundryVTT"
|
|
|
|
|
|
# =============================================================================
|
|
# FIXTURES
|
|
# =============================================================================
|
|
|
|
@pytest.fixture
|
|
def sample_library_ids():
|
|
"""Sample library IDs for testing prefix stripping."""
|
|
return [
|
|
"/local/foundryvtt",
|
|
"/local/pytest",
|
|
"/local/mydocs/reference/guide.md",
|
|
"/local/my-app",
|
|
"/local/documentation/tutorial/getting-started",
|
|
]
|
|
|
|
|
|
@pytest.fixture
|
|
def expected_stripped_ids(sample_library_ids):
|
|
"""Expected stripped versions of sample library IDs."""
|
|
return [
|
|
"foundryvtt",
|
|
"pytest",
|
|
"mydocs/reference/guide.md",
|
|
"my-app",
|
|
"documentation/tutorial/getting-started",
|
|
]
|