diff --git a/.tests/unit/test_generators.py b/.tests/unit/test_generators.py new file mode 100644 index 0000000..e482784 --- /dev/null +++ b/.tests/unit/test_generators.py @@ -0,0 +1,218 @@ +"""Unit tests for generators.""" + +import pytest +from code_doc_cli.generators.markdown_generator import MarkdownGenerator +from code_doc_cli.generators.templates import DocumentationTemplate, SyntaxHighlighter +from code_doc_cli.parsers.base import DocElement, ElementType, Parameter + + +class TestMarkdownGenerator: + """Tests for Markdown generator.""" + + @pytest.fixture + def sample_elements(self): + """Create sample documentation elements.""" + elements = [] + + module_elem = DocElement( + name="sample_module", + element_type=ElementType.MODULE, + description="This is a sample module for testing.", + full_docstring="This is a sample module for testing.", + source_file="sample.py", + line_number=1, + ) + elements.append(module_elem) + + func_elem = DocElement( + name="add", + element_type=ElementType.FUNCTION, + description="Add two numbers together.", + full_docstring="Add two numbers together.\n\nArgs:\n a: First number\n b: Second number", + parameters=[ + Parameter(name="a", type_hint="int", description="First number"), + Parameter(name="b", type_hint="int", description="Second number"), + ], + return_type="int", + return_description="The sum of a and b", + source_file="sample.py", + line_number=10, + visibility="public", + ) + elements.append(func_elem) + + class_elem = DocElement( + name="Calculator", + element_type=ElementType.CLASS, + description="A simple calculator class.", + full_docstring="A simple calculator class.", + attributes=[ + ("memory", "int", "Current stored value in memory"), + ], + source_file="sample.py", + line_number=20, + visibility="public", + decorators=["@dataclass"], + ) + elements.append(class_elem) + + return elements + + def test_generate_markdown(self, sample_elements): + """Test Markdown generation.""" + generator = MarkdownGenerator() + output = generator.generate(elements=sample_elements) + + assert "# API Documentation" in output + assert "sample_module" in output + assert "add" in output + assert "Calculator" in output + + def test_generate_function_markdown(self, sample_elements): + """Test function documentation in Markdown.""" + generator = MarkdownGenerator() + output = generator.generate(elements=sample_elements) + + assert "### add" in output + assert "int" in output + assert "First number" in output + + def test_generate_class_markdown(self, sample_elements): + """Test class documentation in Markdown.""" + generator = MarkdownGenerator() + output = generator.generate(elements=sample_elements) + + assert "## Calculator" in output + assert "memory" in output + + def test_generate_json(self, sample_elements): + """Test JSON generation.""" + generator = MarkdownGenerator() + output = generator.generate_json(elements=sample_elements) + + assert '"name": "add"' in output + assert '"type": "function"' in output + assert '"parameters"' in output + + def test_generate_json_structure(self, sample_elements): + """Test JSON output structure.""" + generator = MarkdownGenerator() + output = generator.generate_json(elements=sample_elements) + + import json + data = json.loads(output) + + assert "generated_at" in data + assert "elements" in data + assert len(data["elements"]) == 3 + + def test_custom_title(self, sample_elements): + """Test custom documentation title.""" + generator = MarkdownGenerator() + output = generator.generate(elements=sample_elements, title="Custom Title") + + assert "# Custom Title" in output + + def test_no_metadata(self, sample_elements): + """Test generation without metadata.""" + generator = MarkdownGenerator() + output = generator.generate(elements=sample_elements, include_metadata=False) + + assert "Generated on" not in output + + def test_empty_elements(self): + """Test generation with no elements.""" + generator = MarkdownGenerator() + output = generator.generate(elements=[]) + + assert "# API Documentation" in output + + +class TestDocumentationTemplate: + """Tests for documentation template.""" + + def test_format_function(self): + """Test function template formatting.""" + template = DocumentationTemplate() + params = [("a", "int", None, "First number"), ("b", "int", None, "Second number")] + output = template.format_function( + name="add", + description="Add two numbers.", + parameters=params, + return_type="int", + return_description="The sum", + raises=[("ValueError", "If inputs are invalid")], + examples=["add(1, 2) # Returns 3"], + source_file="test.py", + line_number=10, + decorators=[], + ) + + assert "### add" in output + assert "Add two numbers" in output + assert "| a |" in output + assert "| b |" in output + assert "Returns:" in output + assert "Raises:" in output + + def test_format_class(self): + """Test class template formatting.""" + template = DocumentationTemplate() + output = template.format_class( + name="Calculator", + description="A calculator class.", + attributes=[("value", "int", "Stored value")], + methods=["add", "subtract"], + parameters=[("BaseClass", "Some description")], + decorators=["@dataclass"], + source_file="test.py", + line_number=5, + ) + + assert "## Calculator" in output + assert "A calculator class" in output + assert "Attributes:" in output + assert "value" in output + assert "Methods:" in output + + def test_format_module(self): + """Test module template formatting.""" + template = DocumentationTemplate() + output = template.format_module( + name="my_module", + description="This is my module.", + imports=["os", "sys"], + elements_count={"functions": 5, "classes": 2, "constants": 3}, + ) + + assert "# my_module" in output + assert "This is my module" in output + assert "os" in output + assert "functions" in output + + +class TestSyntaxHighlighter: + """Tests for syntax highlighter.""" + + def test_highlight_python(self): + """Test Python syntax highlighting.""" + highlighter = SyntaxHighlighter() + code = "def hello():\n print('world')" + output = highlighter.highlight(code, "python") + + assert output + assert "
" in output or "code" in output.lower()
+
+    def test_highlight_with_theme(self):
+        """Test different themes."""
+        for theme in ["default", "dark", "light"]:
+            highlighter = SyntaxHighlighter(theme=theme)
+            assert highlighter.theme is not None
+
+    def test_get_css(self):
+        """Test CSS generation."""
+        highlighter = SyntaxHighlighter()
+        css = highlighter.get_css()
+
+        assert css
+        assert "pre" in css or "code" in css