""" 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", ]