Some checks are pending
Test Dashboard / test-and-dashboard (push) Waiting to run
Named for Milton Waddams, who was relocated to the basement with boxes of legacy documents. He handles the .doc and .xls files from 1997 that nobody else wants to touch. - Rename package from mcp-office-tools to mcwaddams - Update author to Ryan Malloy - Update all imports and references - Add Office Space themed README narrative - All 53 tests passing
157 lines
6.1 KiB
Python
157 lines
6.1 KiB
Python
"""Test suite for MCP Office Tools server with mixin architecture."""
|
|
|
|
import pytest
|
|
import tempfile
|
|
import os
|
|
from pathlib import Path
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
# FastMCP testing - using direct tool access
|
|
|
|
from mcwaddams.server import app
|
|
from mcwaddams.utils import OfficeFileError
|
|
|
|
|
|
class TestServerInitialization:
|
|
"""Test server initialization and basic functionality."""
|
|
|
|
def test_app_creation(self):
|
|
"""Test that FastMCP app is created correctly."""
|
|
assert app is not None
|
|
assert hasattr(app, 'get_tools')
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_all_mixins_tools_registered(self):
|
|
"""Test that all mixin tools are registered correctly."""
|
|
# Get all registered tool names
|
|
tool_names = await app.get_tools()
|
|
tool_names_set = set(tool_names)
|
|
|
|
# Expected tools from all mixins
|
|
expected_universal_tools = {
|
|
"extract_text",
|
|
"extract_images",
|
|
"extract_metadata",
|
|
"detect_office_format",
|
|
"analyze_document_health",
|
|
"get_supported_formats"
|
|
}
|
|
expected_word_tools = {"convert_to_markdown", "extract_word_tables", "analyze_word_structure"}
|
|
expected_excel_tools = {"analyze_excel_data", "extract_excel_formulas", "create_excel_chart_data"}
|
|
|
|
# Verify universal tools are registered
|
|
assert expected_universal_tools.issubset(tool_names_set), f"Missing universal tools: {expected_universal_tools - tool_names_set}"
|
|
|
|
# Verify word tools are registered
|
|
assert expected_word_tools.issubset(tool_names_set), f"Missing word tools: {expected_word_tools - tool_names_set}"
|
|
|
|
# Verify excel tools are registered
|
|
assert expected_excel_tools.issubset(tool_names_set), f"Missing excel tools: {expected_excel_tools - tool_names_set}"
|
|
|
|
# Verify minimum number of tools
|
|
assert len(tool_names) >= 12 # 6 universal + 3 word + 3 excel (+ future PowerPoint tools)
|
|
|
|
def test_mixin_composition_works(self):
|
|
"""Test that mixin composition created the expected server structure."""
|
|
# Import the server module to ensure all mixins are initialized
|
|
import mcwaddams.server as server_module
|
|
|
|
# Verify the mixins were created
|
|
assert hasattr(server_module, 'universal_mixin')
|
|
assert hasattr(server_module, 'word_mixin')
|
|
assert hasattr(server_module, 'excel_mixin')
|
|
assert hasattr(server_module, 'powerpoint_mixin')
|
|
|
|
# Verify mixin instances are correct types
|
|
from mcwaddams.mixins import UniversalMixin, WordMixin, ExcelMixin, PowerPointMixin
|
|
assert isinstance(server_module.universal_mixin, UniversalMixin)
|
|
assert isinstance(server_module.word_mixin, WordMixin)
|
|
assert isinstance(server_module.excel_mixin, ExcelMixin)
|
|
assert isinstance(server_module.powerpoint_mixin, PowerPointMixin)
|
|
|
|
|
|
class TestToolAccess:
|
|
"""Test tool accessibility and metadata."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_tool_metadata(self):
|
|
"""Test getting tool metadata through FastMCP API."""
|
|
# Test that we can get tool metadata
|
|
tool = await app.get_tool("get_supported_formats")
|
|
|
|
assert tool is not None
|
|
assert tool.name == "get_supported_formats"
|
|
assert "Get list of all supported Office document formats" in tool.description
|
|
assert hasattr(tool, 'fn') # Has the actual function
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_all_expected_tools_accessible(self):
|
|
"""Test that all expected tools are accessible via get_tool."""
|
|
expected_tools = [
|
|
# Universal tools
|
|
"extract_text",
|
|
"extract_images",
|
|
"extract_metadata",
|
|
"detect_office_format",
|
|
"analyze_document_health",
|
|
"get_supported_formats",
|
|
# Word tools
|
|
"convert_to_markdown",
|
|
"extract_word_tables",
|
|
"analyze_word_structure",
|
|
# Excel tools
|
|
"analyze_excel_data",
|
|
"extract_excel_formulas",
|
|
"create_excel_chart_data"
|
|
]
|
|
|
|
for tool_name in expected_tools:
|
|
tool = await app.get_tool(tool_name)
|
|
assert tool is not None, f"Tool {tool_name} should be accessible"
|
|
assert tool.name == tool_name
|
|
assert hasattr(tool, 'fn'), f"Tool {tool_name} should have a function"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tool_function_binding(self):
|
|
"""Test that tools are properly bound to mixin instances."""
|
|
# Get a universal tool
|
|
universal_tool = await app.get_tool("get_supported_formats")
|
|
assert 'UniversalMixin' in str(type(universal_tool.fn.__self__))
|
|
|
|
# Get a word tool
|
|
word_tool = await app.get_tool("convert_to_markdown")
|
|
assert 'WordMixin' in str(type(word_tool.fn.__self__))
|
|
|
|
|
|
class TestMixinIntegration:
|
|
"""Test integration between different mixins."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_universal_and_word_tools_coexist(self):
|
|
"""Test that universal and word tools can coexist properly."""
|
|
# Verify both universal and word tools are available
|
|
# This test confirms the mixin composition works correctly
|
|
|
|
# Get tools from both mixins
|
|
universal_tool = await app.get_tool("get_supported_formats")
|
|
word_tool = await app.get_tool("convert_to_markdown")
|
|
|
|
# Verify they're bound to different mixin instances
|
|
assert universal_tool.fn.__self__ != word_tool.fn.__self__
|
|
assert 'UniversalMixin' in str(type(universal_tool.fn.__self__))
|
|
assert 'WordMixin' in str(type(word_tool.fn.__self__))
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_no_tool_name_conflicts(self):
|
|
"""Test that there are no tool name conflicts between mixins."""
|
|
tool_names = await app.get_tools()
|
|
|
|
# Verify no duplicates
|
|
assert len(tool_names) == len(set(tool_names)), "Tool names should be unique"
|
|
|
|
# Verify expected count: 7 universal + 10 word + 3 excel = 20
|
|
assert len(tool_names) == 20, f"Expected 20 tools, got {len(tool_names)}: {list(tool_names.keys())}"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"]) |