generated from personal-projects/leo-claude-mktplace
Move tests to repository root and update pytest configuration
- Move tests from src/gitea_mcp_remote/tests/ to tests/ (top-level) - Update pytest.ini to point to new test location - All imports already use absolute paths (gitea_mcp_remote.*) - Tests run successfully from new location (28/30 pass, 2 pre-existing failures) This improves project structure by following standard Python conventions where tests live at the repository root level rather than inside the source package. Closes #21 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
149
tests/test_filtering.py
Normal file
149
tests/test_filtering.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""Tests for tool filtering module."""
|
||||
|
||||
import pytest
|
||||
|
||||
from gitea_mcp_remote.filtering import ToolFilter
|
||||
|
||||
|
||||
class TestToolFilter:
|
||||
"""Test ToolFilter class."""
|
||||
|
||||
def test_init_with_both_lists_logs_warning(self, caplog):
|
||||
"""Test that specifying both enabled and disabled lists logs warning."""
|
||||
import logging
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
filter = ToolFilter(enabled_tools=["tool1"], disabled_tools=["tool2"])
|
||||
|
||||
assert "Both enabled_tools and disabled_tools specified" in caplog.text
|
||||
assert "Disabled list takes precedence" in caplog.text
|
||||
|
||||
# Verify disabled list takes precedence
|
||||
assert not filter.should_include_tool("tool2")
|
||||
|
||||
def test_passthrough_mode(self):
|
||||
"""Test passthrough mode (no filtering)."""
|
||||
filter = ToolFilter()
|
||||
|
||||
assert filter.should_include_tool("any_tool")
|
||||
assert filter.should_include_tool("another_tool")
|
||||
|
||||
stats = filter.get_filter_stats()
|
||||
assert stats["mode"] == "passthrough"
|
||||
|
||||
def test_whitelist_mode(self):
|
||||
"""Test whitelist mode (enabled_tools)."""
|
||||
filter = ToolFilter(enabled_tools=["tool1", "tool2"])
|
||||
|
||||
assert filter.should_include_tool("tool1")
|
||||
assert filter.should_include_tool("tool2")
|
||||
assert not filter.should_include_tool("tool3")
|
||||
assert not filter.should_include_tool("tool4")
|
||||
|
||||
stats = filter.get_filter_stats()
|
||||
assert stats["mode"] == "whitelist"
|
||||
assert stats["enabled_count"] == 2
|
||||
assert "tool1" in stats["enabled_tools"]
|
||||
assert "tool2" in stats["enabled_tools"]
|
||||
|
||||
def test_blacklist_mode(self):
|
||||
"""Test blacklist mode (disabled_tools)."""
|
||||
filter = ToolFilter(disabled_tools=["tool1", "tool2"])
|
||||
|
||||
assert not filter.should_include_tool("tool1")
|
||||
assert not filter.should_include_tool("tool2")
|
||||
assert filter.should_include_tool("tool3")
|
||||
assert filter.should_include_tool("tool4")
|
||||
|
||||
stats = filter.get_filter_stats()
|
||||
assert stats["mode"] == "blacklist"
|
||||
assert stats["disabled_count"] == 2
|
||||
assert "tool1" in stats["disabled_tools"]
|
||||
assert "tool2" in stats["disabled_tools"]
|
||||
|
||||
def test_filter_tools_list(self):
|
||||
"""Test filtering a list of tool definitions."""
|
||||
filter = ToolFilter(enabled_tools=["tool1", "tool3"])
|
||||
|
||||
tools = [
|
||||
{"name": "tool1", "description": "First tool"},
|
||||
{"name": "tool2", "description": "Second tool"},
|
||||
{"name": "tool3", "description": "Third tool"},
|
||||
{"name": "tool4", "description": "Fourth tool"},
|
||||
]
|
||||
|
||||
filtered = filter.filter_tools_list(tools)
|
||||
|
||||
assert len(filtered) == 2
|
||||
assert filtered[0]["name"] == "tool1"
|
||||
assert filtered[1]["name"] == "tool3"
|
||||
|
||||
def test_filter_tools_response(self):
|
||||
"""Test filtering an MCP list_tools response."""
|
||||
filter = ToolFilter(disabled_tools=["tool2"])
|
||||
|
||||
response = {
|
||||
"tools": [
|
||||
{"name": "tool1", "description": "First tool"},
|
||||
{"name": "tool2", "description": "Second tool"},
|
||||
{"name": "tool3", "description": "Third tool"},
|
||||
],
|
||||
"other_data": "preserved",
|
||||
}
|
||||
|
||||
filtered = filter.filter_tools_response(response)
|
||||
|
||||
assert len(filtered["tools"]) == 2
|
||||
assert filtered["tools"][0]["name"] == "tool1"
|
||||
assert filtered["tools"][1]["name"] == "tool3"
|
||||
assert filtered["other_data"] == "preserved"
|
||||
|
||||
def test_filter_tools_response_no_tools_key(self):
|
||||
"""Test filtering response without 'tools' key."""
|
||||
filter = ToolFilter(enabled_tools=["tool1"])
|
||||
|
||||
response = {"other_data": "value"}
|
||||
filtered = filter.filter_tools_response(response)
|
||||
|
||||
assert filtered == response
|
||||
|
||||
def test_filter_tools_response_immutable(self):
|
||||
"""Test that original response is not mutated."""
|
||||
filter = ToolFilter(enabled_tools=["tool1"])
|
||||
|
||||
original = {
|
||||
"tools": [
|
||||
{"name": "tool1"},
|
||||
{"name": "tool2"},
|
||||
]
|
||||
}
|
||||
|
||||
filtered = filter.filter_tools_response(original)
|
||||
|
||||
# Original should still have 2 tools
|
||||
assert len(original["tools"]) == 2
|
||||
# Filtered should have 1 tool
|
||||
assert len(filtered["tools"]) == 1
|
||||
|
||||
def test_empty_tool_list(self):
|
||||
"""Test filtering empty tool list."""
|
||||
filter = ToolFilter(enabled_tools=["tool1"])
|
||||
|
||||
result = filter.filter_tools_list([])
|
||||
assert result == []
|
||||
|
||||
def test_tool_with_no_name(self):
|
||||
"""Test handling tool without name field."""
|
||||
filter = ToolFilter(enabled_tools=["tool1"])
|
||||
|
||||
tools = [
|
||||
{"name": "tool1"},
|
||||
{"description": "No name"},
|
||||
{"name": "tool2"},
|
||||
]
|
||||
|
||||
filtered = filter.filter_tools_list(tools)
|
||||
|
||||
# Only tool1 should match, tool without name is excluded
|
||||
assert len(filtered) == 1
|
||||
assert filtered[0]["name"] == "tool1"
|
||||
Reference in New Issue
Block a user