"""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 "" in result
assert "
" 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()