""" Test directory structure analysis functionality for Issue #139: Implode directory to a markdown file. This test module covers the analysis of directory structures to identify hierarchical organization and markdown files for the implosion process. """ 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 ( analyze_directory_structure, scan_markdown_files, detect_hierarchy_from_structure, DirectoryNode, identify_index_files ) except ImportError: # Expected during RED phase - tests should fail initially analyze_directory_structure = None scan_markdown_files = None detect_hierarchy_from_structure = None DirectoryNode = None identify_index_files = None class TestDirectoryStructureAnalysis: """Test analysis of directory structures for implosion.""" 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_scan_simple_markdown_files(self): """Test scanning directory for markdown files.""" # This should fail initially (RED phase) # Create test structure (self.temp_dir / "chapter_1.md").write_text("# Chapter 1\nContent here.") (self.temp_dir / "chapter_2.md").write_text("# Chapter 2\nMore content.") (self.temp_dir / "not_markdown.txt").write_text("Not a markdown file.") markdown_files = scan_markdown_files(self.temp_dir) # Should find only markdown files assert len(markdown_files) == 2 file_names = [f.name for f in markdown_files] assert "chapter_1.md" in file_names assert "chapter_2.md" in file_names assert "not_markdown.txt" not in file_names def test_scan_nested_directory_structure(self): """Test scanning nested directories for markdown files.""" # This should fail initially (RED phase) # Create nested structure part_dir = self.temp_dir / "part_1_introduction" part_dir.mkdir() (part_dir / "index.md").write_text("# Part 1: Introduction\nIntro content.") chapter_dir = part_dir / "chapter_1_getting_started" chapter_dir.mkdir() (chapter_dir / "index.md").write_text("## Chapter 1: Getting Started\nChapter content.") (chapter_dir / "section_1_1_installation.md").write_text("### Section 1.1: Installation\nInstall info.") markdown_files = scan_markdown_files(self.temp_dir, recursive=True) # Should find all markdown files in nested structure assert len(markdown_files) >= 3 file_paths = [str(f) for f in markdown_files] assert any("part_1_introduction/index.md" in path for path in file_paths) assert any("chapter_1_getting_started/index.md" in path for path in file_paths) assert any("section_1_1_installation.md" in path for path in file_paths) def test_detect_hierarchy_from_directory_depth(self): """Test detecting hierarchy levels based on directory depth.""" # This should fail initially (RED phase) # Create structure with different depths (self.temp_dir / "root_file.md").write_text("# Root Level") level1_dir = self.temp_dir / "level_1" level1_dir.mkdir() (level1_dir / "file.md").write_text("## Level 1") level2_dir = level1_dir / "level_2" level2_dir.mkdir() (level2_dir / "file.md").write_text("### Level 2") hierarchy = detect_hierarchy_from_structure(self.temp_dir) # Should detect proper hierarchy levels assert hierarchy is not None assert len(hierarchy) > 0 # Root level should be detected root_items = [item for item in hierarchy if item.depth == 0] assert len(root_items) >= 1 # Nested levels should be detected nested_items = [item for item in hierarchy if item.depth > 0] assert len(nested_items) > 0 def test_identify_index_files_vs_content_files(self): """Test identification of index.md files vs regular content files.""" # This should fail initially (RED phase) # Create mixed structure section_dir = self.temp_dir / "section_1" section_dir.mkdir() (section_dir / "index.md").write_text("# Section 1\nSection intro.") (section_dir / "subsection_a.md").write_text("## Subsection A\nContent A.") (section_dir / "subsection_b.md").write_text("## Subsection B\nContent B.") analysis = identify_index_files(section_dir) # Should distinguish index files from content files assert analysis.index_file is not None assert analysis.index_file.name == "index.md" assert len(analysis.content_files) == 2 content_names = [f.name for f in analysis.content_files] assert "subsection_a.md" in content_names assert "subsection_b.md" in content_names def test_analyze_complex_directory_structure(self): """Test analysis of a complex directory structure like md-explode output.""" # This should fail initially (RED phase) # Create structure similar to md-explode output part1_dir = self.temp_dir / "part_1_introduction" part1_dir.mkdir() (part1_dir / "index.md").write_text("# Part 1: Introduction\nPart content.") chapter1_dir = part1_dir / "chapter_1_getting_started" chapter1_dir.mkdir() (chapter1_dir / "index.md").write_text("## Chapter 1: Getting Started\nChapter content.") (chapter1_dir / "section_1_1_setup.md").write_text("### Section 1.1: Setup\nSetup content.") (chapter1_dir / "section_1_2_config.md").write_text("### Section 1.2: Config\nConfig content.") part2_dir = self.temp_dir / "part_2_advanced" part2_dir.mkdir() (part2_dir / "chapter_2_1_algorithms.md").write_text("## Chapter 2.1: Algorithms\nAlgo content.") structure = analyze_directory_structure(self.temp_dir) # Should create comprehensive structure analysis assert structure is not None assert len(structure.root_nodes) >= 2 # Two parts # Should identify different hierarchy levels parts = [node for node in structure.root_nodes if node.depth == 1] # Parts chapters = [node for node in structure.all_nodes if node.depth == 2] # Chapters sections = [node for node in structure.all_nodes if node.depth == 3] # Sections assert len(parts) >= 2 assert len(chapters) >= 2 assert len(sections) >= 2 class TestDirectoryNode: """Test the DirectoryNode data model.""" def test_directory_node_creation(self): """Test creating DirectoryNode objects.""" # This should fail initially (RED phase) path = Path("/test/path") node = DirectoryNode( path=path, name="test_name", depth=2, is_directory=True ) assert node.path == path assert node.name == "test_name" assert node.depth == 2 assert node.is_directory == True assert node.children == [] assert node.markdown_files == [] def test_directory_node_add_child(self): """Test adding child nodes to directory nodes.""" # This should fail initially (RED phase) parent = DirectoryNode(Path("/parent"), "parent", 1, True) child = DirectoryNode(Path("/parent/child"), "child", 2, True) parent.add_child(child) assert len(parent.children) == 1 assert parent.children[0] == child assert child.parent == parent def test_directory_node_add_markdown_file(self): """Test adding markdown files to directory nodes.""" # This should fail initially (RED phase) node = DirectoryNode(Path("/test"), "test", 1, True) md_file = Path("/test/file.md") node.add_markdown_file(md_file) assert len(node.markdown_files) == 1 assert node.markdown_files[0] == md_file def test_directory_node_hierarchy_validation(self): """Test that directory node hierarchy is validated.""" # This should fail initially (RED phase) parent = DirectoryNode(Path("/parent"), "parent", 1, True) invalid_child = DirectoryNode(Path("/parent/child"), "child", 3, True) # Skip level 2 # Should validate hierarchy (or at least not break) parent.add_child(invalid_child) # Basic structure should still work assert len(parent.children) == 1 class TestDirectoryStructureBuilder: """Test building comprehensive directory structure representations.""" 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_structure_builder_processes_flat_directory(self): """Test building structure from flat directory with markdown files.""" # This should fail initially (RED phase) (self.temp_dir / "intro.md").write_text("# Introduction\nIntro content.") (self.temp_dir / "chapter_1.md").write_text("# Chapter 1\nChapter content.") (self.temp_dir / "conclusion.md").write_text("# Conclusion\nConclusion content.") structure = analyze_directory_structure(self.temp_dir) # Should process flat structure assert structure is not None assert len(structure.root_nodes) >= 3 # All files should be at root level (depth 0) for node in structure.root_nodes: assert node.depth == 0 def test_structure_builder_handles_empty_directories(self): """Test handling of empty directories in structure.""" # This should fail initially (RED phase) empty_dir = self.temp_dir / "empty_section" empty_dir.mkdir() structure = analyze_directory_structure(self.temp_dir) # Should handle empty directories gracefully assert structure is not None # Empty directories might be included or excluded depending on implementation def test_structure_builder_sorts_items_correctly(self): """Test that structure builder sorts items in logical order.""" # This should fail initially (RED phase) # Create files that should be sorted (self.temp_dir / "03_chapter_3.md").write_text("# Chapter 3") (self.temp_dir / "01_chapter_1.md").write_text("# Chapter 1") (self.temp_dir / "02_chapter_2.md").write_text("# Chapter 2") structure = analyze_directory_structure(self.temp_dir) # Should sort items logically (numeric or alphabetic) assert structure is not None assert len(structure.root_nodes) == 3 # Files should be in some logical order first_file = structure.root_nodes[0] last_file = structure.root_nodes[-1] # Should have some ordering (exact order depends on implementation) assert first_file.name != last_file.name