run ruff
This commit is contained in:
@@ -10,15 +10,15 @@ Test Coverage:
|
||||
- Integration with code analysis results
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import tempfile
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import sys
|
||||
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'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||
|
||||
from skill_seekers.cli.api_reference_builder import APIReferenceBuilder
|
||||
|
||||
@@ -38,28 +38,34 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
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': []
|
||||
}]
|
||||
"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)
|
||||
@@ -72,31 +78,33 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
|
||||
# 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)
|
||||
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}
|
||||
"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": [],
|
||||
}
|
||||
],
|
||||
'return_type': 'int',
|
||||
'docstring': 'Calculate sum of numbers.',
|
||||
'is_async': False,
|
||||
'is_method': False,
|
||||
'decorators': []
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
@@ -106,32 +114,36 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
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)
|
||||
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'}
|
||||
"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": [],
|
||||
}
|
||||
],
|
||||
'return_type': 'dict',
|
||||
'docstring': 'Create a user object.',
|
||||
'is_async': False,
|
||||
'is_method': False,
|
||||
'decorators': []
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
@@ -141,34 +153,33 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
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)
|
||||
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': []
|
||||
}]
|
||||
}]
|
||||
"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)
|
||||
@@ -179,13 +190,13 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
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)
|
||||
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')
|
||||
classes_pos = content.find("## Classes")
|
||||
functions_pos = content.find("## Functions")
|
||||
|
||||
self.assertNotEqual(classes_pos, -1)
|
||||
self.assertNotEqual(functions_pos, -1)
|
||||
@@ -195,48 +206,50 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
"""Test integration with actual code analyzer output format."""
|
||||
# Simulate real code analyzer output
|
||||
code_analysis = {
|
||||
'files': [
|
||||
"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": "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': []
|
||||
}]
|
||||
}
|
||||
"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": [],
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -248,40 +261,42 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
|
||||
# Verify filenames
|
||||
filenames = [f.name for f in generated.values()]
|
||||
self.assertIn('calculator.md', filenames)
|
||||
self.assertIn('utils.md', filenames)
|
||||
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_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)
|
||||
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_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)
|
||||
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}
|
||||
"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": [],
|
||||
}
|
||||
],
|
||||
'return_type': 'dict',
|
||||
'docstring': 'Fetch data from URL.',
|
||||
'is_async': True,
|
||||
'is_method': False,
|
||||
'decorators': []
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
builder = APIReferenceBuilder(code_analysis)
|
||||
@@ -291,33 +306,30 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
output_file = list(generated.values())[0]
|
||||
content = output_file.read_text()
|
||||
|
||||
self.assertIn('**Async function**', content)
|
||||
self.assertIn('fetch_data', content)
|
||||
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': [
|
||||
"files": [
|
||||
{"file": "empty.py", "language": "Python", "classes": [], "functions": []},
|
||||
{
|
||||
'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": [],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
'file': 'valid.py',
|
||||
'language': 'Python',
|
||||
'classes': [],
|
||||
'functions': [{
|
||||
'name': 'test',
|
||||
'parameters': [],
|
||||
'return_type': None,
|
||||
'docstring': None,
|
||||
'is_async': False,
|
||||
'is_method': False,
|
||||
'decorators': []
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -326,9 +338,9 @@ class TestAPIReferenceBuilder(unittest.TestCase):
|
||||
|
||||
# Only valid.py should be generated
|
||||
self.assertEqual(len(generated), 1)
|
||||
self.assertIn('valid.py', list(generated.keys())[0])
|
||||
self.assertIn("valid.py", list(generated.keys())[0])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
# Run tests with verbose output
|
||||
unittest.main(verbosity=2)
|
||||
|
||||
Reference in New Issue
Block a user