Add 34 tests across 3 test modules: - test_parse_tools.py: 11 tests for README/CLAUDE.md parsing - test_validation_tools.py: 11 tests for compatibility and agent validation - test_report_tools.py: 12 tests for report generation and filtering Coverage: parse_tools 79%, validation_tools 96%, report_tools 89% Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
194 lines
5.4 KiB
Python
194 lines
5.4 KiB
Python
"""
|
|
Unit tests for parse tools.
|
|
"""
|
|
import pytest
|
|
from pathlib import Path
|
|
|
|
|
|
@pytest.fixture
|
|
def parse_tools():
|
|
"""Create ParseTools instance"""
|
|
from mcp_server.parse_tools import ParseTools
|
|
return ParseTools()
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_readme(tmp_path):
|
|
"""Create a sample README.md for testing"""
|
|
readme = tmp_path / "README.md"
|
|
readme.write_text("""# Test Plugin
|
|
|
|
A test plugin for validation.
|
|
|
|
## Features
|
|
|
|
- **Feature One**: Does something
|
|
- **Feature Two**: Does something else
|
|
|
|
## Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `/test-cmd` | Test command |
|
|
| `/another-cmd` | Another test command |
|
|
|
|
## Agents
|
|
|
|
| Agent | Description |
|
|
|-------|-------------|
|
|
| `test-agent` | A test agent |
|
|
|
|
## Tools Summary
|
|
|
|
### Category A (3 tools)
|
|
`tool_a`, `tool_b`, `tool_c`
|
|
|
|
### Category B (2 tools)
|
|
`tool_d`, `tool_e`
|
|
""")
|
|
return str(tmp_path)
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_claude_md(tmp_path):
|
|
"""Create a sample CLAUDE.md for testing"""
|
|
claude_md = tmp_path / "CLAUDE.md"
|
|
claude_md.write_text("""# CLAUDE.md
|
|
|
|
## Project Overview
|
|
|
|
### Four-Agent Model (test)
|
|
|
|
| Agent | Personality | Responsibilities |
|
|
|-------|-------------|------------------|
|
|
| **Planner** | Thoughtful | Planning via `create_issue`, `search_lessons` |
|
|
| **Executor** | Focused | Implementation via `write`, `edit` |
|
|
|
|
## Workflow
|
|
|
|
1. Planner creates issues
|
|
2. Executor implements code
|
|
""")
|
|
return str(claude_md)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_basic(parse_tools, sample_readme):
|
|
"""Test basic plugin interface parsing"""
|
|
result = await parse_tools.parse_plugin_interface(sample_readme)
|
|
|
|
assert "error" not in result
|
|
# Plugin name extraction strips "Plugin" suffix
|
|
assert result["plugin_name"] == "Test"
|
|
assert "A test plugin" in result["description"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_commands(parse_tools, sample_readme):
|
|
"""Test command extraction from README"""
|
|
result = await parse_tools.parse_plugin_interface(sample_readme)
|
|
|
|
commands = result["commands"]
|
|
assert len(commands) == 2
|
|
assert commands[0]["name"] == "/test-cmd"
|
|
assert commands[1]["name"] == "/another-cmd"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_agents(parse_tools, sample_readme):
|
|
"""Test agent extraction from README"""
|
|
result = await parse_tools.parse_plugin_interface(sample_readme)
|
|
|
|
agents = result["agents"]
|
|
assert len(agents) == 1
|
|
assert agents[0]["name"] == "test-agent"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_tools(parse_tools, sample_readme):
|
|
"""Test tool extraction from README"""
|
|
result = await parse_tools.parse_plugin_interface(sample_readme)
|
|
|
|
tools = result["tools"]
|
|
tool_names = [t["name"] for t in tools]
|
|
assert "tool_a" in tool_names
|
|
assert "tool_b" in tool_names
|
|
assert "tool_e" in tool_names
|
|
assert len(tools) >= 5
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_categories(parse_tools, sample_readme):
|
|
"""Test tool category extraction"""
|
|
result = await parse_tools.parse_plugin_interface(sample_readme)
|
|
|
|
categories = result["tool_categories"]
|
|
assert "Category A" in categories
|
|
assert "Category B" in categories
|
|
assert "tool_a" in categories["Category A"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_features(parse_tools, sample_readme):
|
|
"""Test feature extraction"""
|
|
result = await parse_tools.parse_plugin_interface(sample_readme)
|
|
|
|
features = result["features"]
|
|
assert "Feature One" in features
|
|
assert "Feature Two" in features
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_interface_not_found(parse_tools, tmp_path):
|
|
"""Test error when README not found"""
|
|
result = await parse_tools.parse_plugin_interface(str(tmp_path / "nonexistent"))
|
|
|
|
assert "error" in result
|
|
assert "not found" in result["error"].lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_claude_md_agents(parse_tools, sample_claude_md):
|
|
"""Test agent extraction from CLAUDE.md"""
|
|
result = await parse_tools.parse_claude_md_agents(sample_claude_md)
|
|
|
|
assert "error" not in result
|
|
assert result["agent_count"] == 2
|
|
|
|
agents = result["agents"]
|
|
agent_names = [a["name"] for a in agents]
|
|
assert "Planner" in agent_names
|
|
assert "Executor" in agent_names
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_claude_md_tool_refs(parse_tools, sample_claude_md):
|
|
"""Test tool reference extraction from agents"""
|
|
result = await parse_tools.parse_claude_md_agents(sample_claude_md)
|
|
|
|
agents = {a["name"]: a for a in result["agents"]}
|
|
planner = agents["Planner"]
|
|
|
|
assert "create_issue" in planner["tool_refs"]
|
|
assert "search_lessons" in planner["tool_refs"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_claude_md_not_found(parse_tools, tmp_path):
|
|
"""Test error when CLAUDE.md not found"""
|
|
result = await parse_tools.parse_claude_md_agents(str(tmp_path / "CLAUDE.md"))
|
|
|
|
assert "error" in result
|
|
assert "not found" in result["error"].lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_parse_plugin_with_direct_file(parse_tools, sample_readme):
|
|
"""Test parsing with direct file path instead of directory"""
|
|
readme_path = Path(sample_readme) / "README.md"
|
|
result = await parse_tools.parse_plugin_interface(str(readme_path))
|
|
|
|
assert "error" not in result
|
|
# Plugin name extraction strips "Plugin" suffix
|
|
assert result["plugin_name"] == "Test"
|