chore: import upstream snapshot with attribution
Test Vector Database Adaptors / Test MCP Vector DB Tools (push) Has been cancelled
Tests / Code Quality (Ruff & Mypy) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.12) (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers CLI - Convert documentation to AI skills dockerfile:Dockerfile name:skill-seekers]) (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers MCP Server - 25 tools for AI assistants dockerfile:Dockerfile.mcp name:skill-seekers-mcp]) (push) Has been cancelled
Docker Publish / Test Docker Images (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / Serial / Integration / E2E Tests (push) Has been cancelled
Tests / MCP Server Tests (push) Has been cancelled
Test Vector Database Adaptors / Test chroma Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test faiss Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test qdrant Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test weaviate Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test MCP Vector DB Tools (push) Has been cancelled
Tests / Code Quality (Ruff & Mypy) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.12) (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers CLI - Convert documentation to AI skills dockerfile:Dockerfile name:skill-seekers]) (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers MCP Server - 25 tools for AI assistants dockerfile:Dockerfile.mcp name:skill-seekers-mcp]) (push) Has been cancelled
Docker Publish / Test Docker Images (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / Serial / Integration / E2E Tests (push) Has been cancelled
Tests / MCP Server Tests (push) Has been cancelled
Test Vector Database Adaptors / Test chroma Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test faiss Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test qdrant Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test weaviate Adaptor (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests for api_reference_builder.py - Markdown API documentation generation.
|
||||
|
||||
Test Coverage:
|
||||
- Class formatting
|
||||
- Function formatting
|
||||
- Parameter table generation
|
||||
- Markdown output structure
|
||||
- Integration with code analysis results
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||
|
||||
from skill_seekers.cli.api_reference_builder import APIReferenceBuilder
|
||||
|
||||
|
||||
class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
"""Tests for API reference builder"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test environment"""
|
||||
self.temp_dir = tempfile.mkdtemp()
|
||||
self.output_dir = Path(self.temp_dir) / "api_reference"
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up test environment"""
|
||||
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
||||
|
||||
def test_class_formatting(self):
|
||||
"""Test markdown formatting for class signatures."""
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{
|
||||
"file": "test.py",
|
||||
"language": "Python",
|
||||
"classes": [
|
||||
{
|
||||
"name": "Calculator",
|
||||
"docstring": "A simple calculator class.",
|
||||
"base_classes": ["object"],
|
||||
"methods": [
|
||||
{
|
||||
"name": "add",
|
||||
"parameters": [
|
||||
{"name": "a", "type_hint": "int", "default": None},
|
||||
{"name": "b", "type_hint": "int", "default": None},
|
||||
],
|
||||
"return_type": "int",
|
||||
"docstring": "Add two numbers.",
|
||||
"is_async": False,
|
||||
"is_method": True,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
"functions": [],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Verify file was generated
|
||||
self.assertEqual(len(generated), 1)
|
||||
output_file = list(generated.values())[0]
|
||||
self.assertTrue(output_file.exists())
|
||||
|
||||
# Verify content
|
||||
content = output_file.read_text()
|
||||
self.assertIn("### Calculator", content)
|
||||
self.assertIn("A simple calculator class", content)
|
||||
self.assertIn("**Inherits from**: object", content)
|
||||
self.assertIn("##### add", content)
|
||||
self.assertIn("Add two numbers", content)
|
||||
|
||||
def test_function_formatting(self):
|
||||
"""Test markdown formatting for function signatures."""
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{
|
||||
"file": "utils.py",
|
||||
"language": "Python",
|
||||
"classes": [],
|
||||
"functions": [
|
||||
{
|
||||
"name": "calculate_sum",
|
||||
"parameters": [
|
||||
{"name": "numbers", "type_hint": "list", "default": None}
|
||||
],
|
||||
"return_type": "int",
|
||||
"docstring": "Calculate sum of numbers.",
|
||||
"is_async": False,
|
||||
"is_method": False,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Verify content
|
||||
output_file = list(generated.values())[0]
|
||||
content = output_file.read_text()
|
||||
|
||||
self.assertIn("## Functions", content)
|
||||
self.assertIn("### calculate_sum", content)
|
||||
self.assertIn("Calculate sum of numbers", content)
|
||||
self.assertIn("**Returns**: `int`", content)
|
||||
|
||||
def test_parameter_table_generation(self):
|
||||
"""Test parameter table formatting."""
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{
|
||||
"file": "test.py",
|
||||
"language": "Python",
|
||||
"classes": [],
|
||||
"functions": [
|
||||
{
|
||||
"name": "create_user",
|
||||
"parameters": [
|
||||
{"name": "name", "type_hint": "str", "default": None},
|
||||
{"name": "age", "type_hint": "int", "default": "18"},
|
||||
{"name": "active", "type_hint": "bool", "default": "True"},
|
||||
],
|
||||
"return_type": "dict",
|
||||
"docstring": "Create a user object.",
|
||||
"is_async": False,
|
||||
"is_method": False,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Verify parameter table
|
||||
output_file = list(generated.values())[0]
|
||||
content = output_file.read_text()
|
||||
|
||||
self.assertIn("**Parameters**:", content)
|
||||
self.assertIn("| Name | Type | Default | Description |", content)
|
||||
self.assertIn("| name | str | - |", content) # Parameters with no default show "-"
|
||||
self.assertIn("| age | int | 18 |", content)
|
||||
self.assertIn("| active | bool | True |", content)
|
||||
|
||||
def test_markdown_output_structure(self):
|
||||
"""Test overall markdown document structure."""
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{
|
||||
"file": "module.py",
|
||||
"language": "Python",
|
||||
"classes": [
|
||||
{
|
||||
"name": "TestClass",
|
||||
"docstring": "Test class.",
|
||||
"base_classes": [],
|
||||
"methods": [],
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "test_func",
|
||||
"parameters": [],
|
||||
"return_type": None,
|
||||
"docstring": "Test function.",
|
||||
"is_async": False,
|
||||
"is_method": False,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Verify structure
|
||||
output_file = list(generated.values())[0]
|
||||
content = output_file.read_text()
|
||||
|
||||
# Check header
|
||||
self.assertIn("# API Reference: module.py", content)
|
||||
self.assertIn("**Language**: Python", content)
|
||||
self.assertIn("**Source**: `module.py`", content)
|
||||
|
||||
# Check sections in order
|
||||
classes_pos = content.find("## Classes")
|
||||
functions_pos = content.find("## Functions")
|
||||
|
||||
self.assertNotEqual(classes_pos, -1)
|
||||
self.assertNotEqual(functions_pos, -1)
|
||||
self.assertLess(classes_pos, functions_pos)
|
||||
|
||||
def test_integration_with_code_analyzer(self):
|
||||
"""Test integration with actual code analyzer output format."""
|
||||
# Simulate real code analyzer output
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{
|
||||
"file": "calculator.py",
|
||||
"language": "Python",
|
||||
"classes": [
|
||||
{
|
||||
"name": "Calculator",
|
||||
"base_classes": [],
|
||||
"methods": [
|
||||
{
|
||||
"name": "add",
|
||||
"parameters": [
|
||||
{"name": "a", "type_hint": "float", "default": None},
|
||||
{"name": "b", "type_hint": "float", "default": None},
|
||||
],
|
||||
"return_type": "float",
|
||||
"docstring": "Add two numbers.",
|
||||
"decorators": [],
|
||||
"is_async": False,
|
||||
"is_method": True,
|
||||
}
|
||||
],
|
||||
"docstring": "Calculator class.",
|
||||
"line_number": 1,
|
||||
}
|
||||
],
|
||||
"functions": [],
|
||||
},
|
||||
{
|
||||
"file": "utils.js",
|
||||
"language": "JavaScript",
|
||||
"classes": [],
|
||||
"functions": [
|
||||
{
|
||||
"name": "formatDate",
|
||||
"parameters": [{"name": "date", "type_hint": None, "default": None}],
|
||||
"return_type": None,
|
||||
"docstring": None,
|
||||
"is_async": False,
|
||||
"is_method": False,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Verify multiple files generated
|
||||
self.assertEqual(len(generated), 2)
|
||||
|
||||
# Verify filenames
|
||||
filenames = [f.name for f in generated.values()]
|
||||
self.assertIn("calculator.md", filenames)
|
||||
self.assertIn("utils.md", filenames)
|
||||
|
||||
# Verify Python file content
|
||||
py_file = next(f for f in generated.values() if f.name == "calculator.md")
|
||||
py_content = py_file.read_text()
|
||||
self.assertIn("Calculator class", py_content)
|
||||
self.assertIn("add(a: float, b: float) → float", py_content)
|
||||
|
||||
# Verify JavaScript file content
|
||||
js_file = next(f for f in generated.values() if f.name == "utils.md")
|
||||
js_content = js_file.read_text()
|
||||
self.assertIn("formatDate", js_content)
|
||||
self.assertIn("**Language**: JavaScript", js_content)
|
||||
|
||||
def test_async_function_indicator(self):
|
||||
"""Test that async functions are marked in output."""
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{
|
||||
"file": "async_utils.py",
|
||||
"language": "Python",
|
||||
"classes": [],
|
||||
"functions": [
|
||||
{
|
||||
"name": "fetch_data",
|
||||
"parameters": [{"name": "url", "type_hint": "str", "default": None}],
|
||||
"return_type": "dict",
|
||||
"docstring": "Fetch data from URL.",
|
||||
"is_async": True,
|
||||
"is_method": False,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Verify async indicator
|
||||
output_file = list(generated.values())[0]
|
||||
content = output_file.read_text()
|
||||
|
||||
self.assertIn("**Async function**", content)
|
||||
self.assertIn("fetch_data", content)
|
||||
|
||||
def test_empty_analysis_skipped(self):
|
||||
"""Test that files with no analysis are skipped."""
|
||||
code_analysis = {
|
||||
"files": [
|
||||
{"file": "empty.py", "language": "Python", "classes": [], "functions": []},
|
||||
{
|
||||
"file": "valid.py",
|
||||
"language": "Python",
|
||||
"classes": [],
|
||||
"functions": [
|
||||
{
|
||||
"name": "test",
|
||||
"parameters": [],
|
||||
"return_type": None,
|
||||
"docstring": None,
|
||||
"is_async": False,
|
||||
"is_method": False,
|
||||
"decorators": [],
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
generated = builder.build_reference(self.output_dir)
|
||||
|
||||
# Only valid.py should be generated
|
||||
self.assertEqual(len(generated), 1)
|
||||
self.assertIn("valid.py", list(generated.keys())[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run tests with verbose output
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user