""" Test directory structure creation functionality for Issue #138: Explode Markdown file to markdown directory. This test module covers the creation of filesystem directory structures that match the hierarchical organization of markdown documents. """ import pytest import tempfile import shutil from pathlib import Path from unittest.mock import Mock, patch # Import will fail initially (RED phase) until implementation exists try: from markitect.plugins.builtin.markdown_commands import ( create_directory_structure, explode_markdown_file, DirectoryStructureBuilder, MarkdownSection ) except ImportError: # Expected during RED phase - tests should fail initially create_directory_structure = None explode_markdown_file = None DirectoryStructureBuilder = None MarkdownSection = None class TestDirectoryStructureCreation: """Test creation of directory structures from markdown hierarchy.""" def setup_method(self): """Set up temporary directory for each test.""" self.temp_dir = Path(tempfile.mkdtemp()) def teardown_method(self): """Clean up temporary directory after each test.""" if self.temp_dir.exists(): shutil.rmtree(self.temp_dir) def test_create_simple_directory_structure(self): """Test creating a simple directory structure from markdown sections.""" # This should fail initially (RED phase) # Mock sections representing a simple book structure sections = [ Mock(level=1, title="Part 1: Introduction", children=[ Mock(level=2, title="Chapter 1: Getting Started", children=[], content="Content for chapter 1"), Mock(level=2, title="Chapter 2: Basics", children=[], content="Content for chapter 2") ], content="Introduction content"), ] result = create_directory_structure(sections, self.temp_dir) # Verify directory structure part_dir = self.temp_dir / "part_1_introduction" assert part_dir.exists() assert part_dir.is_dir() chapter1_file = part_dir / "chapter_1_getting_started.md" chapter2_file = part_dir / "chapter_2_basics.md" assert chapter1_file.exists() assert chapter2_file.exists() # Verify content was written assert "Content for chapter 1" in chapter1_file.read_text() assert "Content for chapter 2" in chapter2_file.read_text() def test_create_nested_directory_structure(self): """Test creating deeply nested directory structures.""" # This should fail initially (RED phase) sections = [ Mock(level=1, title="Part 1", children=[ Mock(level=2, title="Chapter 1", children=[ Mock(level=3, title="Section 1.1", children=[ Mock(level=4, title="Subsection 1.1.1", children=[], content="Deep content") ], content="Section content") ], content="Chapter content") ], content="Part content") ] result = create_directory_structure(sections, self.temp_dir) # Verify nested structure deep_path = (self.temp_dir / "part_1" / "chapter_1" / "section_1_1" / "subsection_1_1_1.md") # Note: Exact structure depends on implementation decisions # This test defines expected behavior assert any(path.name == "subsection_1_1_1.md" for path in self.temp_dir.rglob("*.md")) def test_create_structure_with_duplicate_names(self): """Test handling duplicate heading names in directory structure.""" # This should fail initially (RED phase) sections = [ Mock(level=1, title="Introduction", children=[], content="First intro"), Mock(level=1, title="Introduction", children=[], content="Second intro") ] result = create_directory_structure(sections, self.temp_dir) # Should create unique directories/files intro1_path = self.temp_dir / "introduction" intro2_path = self.temp_dir / "introduction_2" # One of these patterns should exist assert (intro1_path.exists() or (self.temp_dir / "introduction.md").exists() or (self.temp_dir / "introduction_2.md").exists()) def test_create_structure_handles_existing_directories(self): """Test behavior when target directories already exist.""" # This should fail initially (RED phase) # Pre-create a directory existing_dir = self.temp_dir / "chapter_1" existing_dir.mkdir() sections = [ Mock(level=1, title="Chapter 1", children=[], content="New content") ] # Should handle existing directory gracefully result = create_directory_structure(sections, self.temp_dir) # Should either merge, skip, or create alternative name assert result is not None # Function should complete without error def test_create_structure_with_special_characters(self): """Test directory creation with headings containing special characters.""" # This should fail initially (RED phase) sections = [ Mock(level=1, title="Chapter 1: What's New?", children=[], content="Content with special chars"), Mock(level=1, title="File/Path Issues", children=[], content="Path content") ] result = create_directory_structure(sections, self.temp_dir) # Verify safe directory names were created safe_names = [path.name for path in self.temp_dir.iterdir()] # Should contain sanitized versions assert any("whats_new" in name.lower() for name in safe_names) assert any("file_path" in name.lower() for name in safe_names) def test_create_structure_preserves_markdown_formatting(self): """Test that markdown formatting is preserved in extracted files.""" # This should fail initially (RED phase) markdown_content = """## Chapter Title This content has **bold** and *italic* text. ```python def example(): return "code block" ``` - List item 1 - List item 2 """ sections = [ Mock(level=1, title="Test Chapter", children=[], content=markdown_content) ] result = create_directory_structure(sections, self.temp_dir) # Find the created file md_files = list(self.temp_dir.rglob("*.md")) assert len(md_files) > 0 content = md_files[0].read_text() # Verify markdown formatting is preserved assert "**bold**" in content assert "*italic*" in content assert "```python" in content assert "- List item 1" in content class TestDirectoryStructureBuilder: """Test the DirectoryStructureBuilder class.""" def setup_method(self): """Set up temporary directory for each test.""" self.temp_dir = Path(tempfile.mkdtemp()) def teardown_method(self): """Clean up temporary directory after each test.""" if self.temp_dir.exists(): shutil.rmtree(self.temp_dir) def test_builder_initialization(self): """Test DirectoryStructureBuilder initialization.""" # This should fail initially (RED phase) builder = DirectoryStructureBuilder( output_dir=self.temp_dir, max_depth=3, file_extension=".md" ) assert builder.output_dir == self.temp_dir assert builder.max_depth == 3 assert builder.file_extension == ".md" def test_builder_depth_limiting(self): """Test that builder respects maximum depth settings.""" # This should fail initially (RED phase) builder = DirectoryStructureBuilder( output_dir=self.temp_dir, max_depth=2 ) # Create deep structure that exceeds max depth sections = [ Mock(level=1, title="Level 1", children=[ Mock(level=2, title="Level 2", children=[ Mock(level=3, title="Level 3", children=[ Mock(level=4, title="Level 4", children=[], content="Deep content") ], content="L3 content") ], content="L2 content") ], content="L1 content") ] result = builder.build(sections) # Should flatten or handle deep structures appropriately # Exact behavior depends on implementation assert result is not None class TestMarkdownExplosion: """Test the complete markdown file explosion process.""" def setup_method(self): """Set up temporary directory for each test.""" self.temp_dir = Path(tempfile.mkdtemp()) def teardown_method(self): """Clean up temporary directory after each test.""" if self.temp_dir.exists(): shutil.rmtree(self.temp_dir) def test_explode_simple_markdown_file(self): """Test complete explosion of a simple markdown file.""" # This should fail initially (RED phase) markdown_content = """# Part 1: Introduction This is the introduction to our document. ## Chapter 1: Getting Started Here's how to get started. ### Section 1.1: Installation Installation instructions. ## Chapter 2: Advanced Usage Advanced topics. """ # Create input file input_file = self.temp_dir / "input.md" input_file.write_text(markdown_content) # Create output directory output_dir = self.temp_dir / "exploded" # Explode the file result = explode_markdown_file(input_file, output_dir) # Verify structure was created assert output_dir.exists() assert len(list(output_dir.rglob("*.md"))) > 0 # Verify content distribution md_files = list(output_dir.rglob("*.md")) all_content = "" for md_file in md_files: all_content += md_file.read_text() # Original content should be distributed across files assert "This is the introduction" in all_content assert "Here's how to get started" in all_content assert "Installation instructions" in all_content def test_explode_file_with_front_matter(self): """Test explosion of file with YAML front matter.""" # This should fail initially (RED phase) markdown_content = """--- title: "My Document" author: "Test Author" --- # Chapter 1 Content here. """ input_file = self.temp_dir / "input.md" input_file.write_text(markdown_content) output_dir = self.temp_dir / "exploded" result = explode_markdown_file(input_file, output_dir) # Front matter should be handled appropriately # (preserved in root, copied to sections, or handled per implementation) assert result is not None def test_explode_file_error_handling(self): """Test error handling for invalid inputs.""" # This should fail initially (RED phase) # Non-existent input file with pytest.raises(FileNotFoundError): explode_markdown_file(Path("nonexistent.md"), self.temp_dir) # Invalid output directory with pytest.raises((PermissionError, OSError)): explode_markdown_file(Path("test.md"), Path("/invalid/path"))