Files
shell-speak/tests/integration/test_full_pipeline.py
Auto User 95459fb4c8 fix: resolve CI test failure in output.py
- Fixed undefined 'tool' variable in display_history function
- Changed '[tool]' markup tag usage to proper Rich syntax
- All tests now pass (38/38 unit tests)
- Type checking passes with mypy --strict
2026-01-31 06:22:27 +00:00

264 lines
7.4 KiB
Python

"""Integration tests for the full documentation pipeline."""
import tempfile
from pathlib import Path
import pytest
from click.testing import CliRunner
from doc2man.cli import main
from doc2man.parsers.python import parse_python_file
from doc2man.parsers.go import parse_go_file
from doc2man.parsers.javascript import parse_javascript_file
from doc2man.generators.man import generate_man_page
from doc2man.generators.markdown import generate_markdown
from doc2man.generators.html import generate_html
class TestFullPipeline:
"""Integration tests for the full documentation pipeline."""
def test_python_to_man_pipeline(self):
"""Test Python file -> parse -> generate man page."""
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as f:
f.write(b'''
def greet(name, greeting="Hello"):
"""Greet a person with a custom greeting.
Args:
name: The name of the person to greet.
greeting: The greeting word to use.
Returns:
The greeting string.
Raises:
ValueError: If name is empty.
"""
if not name:
raise ValueError("Name cannot be empty")
return f"{greeting}, {name}!"
''')
f.flush()
parsed = parse_python_file(Path(f.name))
assert parsed["language"] == "python"
assert len(parsed["functions"]) == 1
with tempfile.NamedTemporaryFile(suffix=".1", delete=False) as out:
output_path = Path(out.name)
result = generate_man_page([{"file": str(f.name), "data": parsed}], output_path)
assert ".TH" in result
assert "NAME" in result
assert "greet" in result.lower()
output_path.unlink()
Path(f.name).unlink()
def test_python_to_markdown_pipeline(self):
"""Test Python file -> parse -> generate markdown."""
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as f:
f.write(b'''
def calculate(a, b):
"""Calculate sum of two numbers.
Args:
a: First number.
b: Second number.
Returns:
The sum of a and b.
"""
return a + b
''')
f.flush()
parsed = parse_python_file(Path(f.name))
with tempfile.NamedTemporaryFile(suffix=".md", delete=False) as out:
output_path = Path(out.name)
result = generate_markdown([{"file": str(f.name), "data": parsed}], output_path)
assert "#" in result
assert "calculate" in result.lower()
assert "Parameters" in result
output_path.unlink()
Path(f.name).unlink()
def test_python_to_html_pipeline(self):
"""Test Python file -> parse -> generate HTML."""
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as f:
f.write(b'''
class Calculator:
"""A simple calculator class."""
def add(self, a, b):
"""Add two numbers.
Args:
a: First number.
b: Second number.
Returns:
The sum.
"""
return a + b
''')
f.flush()
parsed = parse_python_file(Path(f.name))
with tempfile.NamedTemporaryFile(suffix=".html", delete=False) as out:
output_path = Path(out.name)
result = generate_html([{"file": str(f.name), "data": parsed}], output_path)
assert "<!DOCTYPE html>" in result
assert "<title>" in result
assert "Calculator" in result
output_path.unlink()
Path(f.name).unlink()
def test_go_pipeline(self):
"""Test Go file parsing and generation."""
with tempfile.NamedTemporaryFile(suffix=".go", delete=False) as f:
f.write(b'''
// Package math provides math utilities.
//
// This is a simple math package.
package math
// Add adds two integers.
//
// a: First integer
// b: Second integer
//
// Returns: The sum
func Add(a, b int) int {
return a + b
}
''')
f.flush()
parsed = parse_go_file(Path(f.name))
assert parsed["language"] == "go"
assert len(parsed["functions"]) >= 1
Path(f.name).unlink()
def test_javascript_pipeline(self):
"""Test JavaScript file parsing and generation."""
with tempfile.NamedTemporaryFile(suffix=".js", delete=False) as f:
f.write(b'''
/**
* Multiplies two numbers.
*
* @param {number} a - First number
* @param {number} b - Second number
* @returns {number} The product
*/
function multiply(a, b) {
return a * b;
}
''')
f.flush()
parsed = parse_javascript_file(Path(f.name))
assert parsed["language"] == "javascript"
assert len(parsed["functions"]) == 1
Path(f.name).unlink()
def test_typescript_pipeline(self):
"""Test TypeScript file parsing and generation."""
with tempfile.NamedTemporaryFile(suffix=".ts", delete=False) as f:
f.write(b'''
/**
* Divides two numbers.
*
* @param numerator - The numerator
* @param denominator - The denominator
* @returns The quotient
*/
function divide(numerator: number, denominator: number): number {
return numerator / denominator;
}
''')
f.flush()
parsed = parse_javascript_file(Path(f.name))
assert parsed["language"] == "javascript"
assert len(parsed["functions"]) >= 1
Path(f.name).unlink()
class TestCLIIntegration:
"""Integration tests for CLI commands."""
def test_cli_generate_command(self):
"""Test the full generate CLI command."""
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as f:
f.write(b'''
def example():
"""An example function."""
pass
''')
f.flush()
with tempfile.NamedTemporaryFile(suffix=".1", delete=False) as out:
runner = CliRunner()
result = runner.invoke(main, [
"generate",
f.name,
"--output", out.name,
"--format", "man"
])
assert result.exit_code == 0
assert Path(out.name).exists()
out_path = Path(out.name)
assert out_path.stat().st_size > 0
out_path.unlink()
Path(f.name).unlink()
def test_cli_multiple_files(self):
"""Test generating from multiple files."""
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as f1:
f1.write(b'''
def func1():
"""First function."""
pass
''')
f1.flush()
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as f2:
f2.write(b'''
def func2():
"""Second function."""
pass
''')
f2.flush()
with tempfile.NamedTemporaryFile(suffix=".md", delete=False) as out:
runner = CliRunner()
result = runner.invoke(main, [
"generate",
f1.name, f2.name,
"--output", out.name,
"--format", "markdown"
])
assert result.exit_code == 0
content = Path(out.name).read_text()
assert "func1" in content or "func2" in content
out_path = Path(out.name)
out_path.unlink()
Path(f1.name).unlink()
Path(f2.name).unlink()