""" Test suite for Issue #149 - Phase 2: Implement Explode-Implode Variants Tests all three variant implementations (flat, hierarchical, semantic) with comprehensive explode-implode operations, roundtrip validation, and CLI integration. """ import pytest import tempfile from pathlib import Path from markitect.explode_variants import ( ExplodeVariant, ExplodeOptions, ImplodeOptions, FlatVariant, HierarchicalVariant, SemanticVariant, VariantFactory, get_variant_factory, create_variant ) class TestFlatVariant: """Test the FlatVariant implementation.""" def test_flat_variant_initialization(self): """Test FlatVariant initialization.""" variant = FlatVariant() assert variant.variant_type == ExplodeVariant.FLAT assert variant.name == "Flat Structure" assert "directories based on h1 headings" in variant.description def test_flat_variant_explode_basic(self): """Test basic explosion with flat variant.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create test markdown file test_content = """# Introduction This is the introduction. ## Overview Some overview content. # Chapter 1 First chapter content. ## Section 1.1 Section content here. # Conclusion Final thoughts. """ input_file = temp_path / "test.md" input_file.write_text(test_content, encoding='utf-8') variant = FlatVariant() options = ExplodeOptions( variant=ExplodeVariant.FLAT, create_manifest=True ) result = variant.explode(input_file, options) assert result.success assert result.variant_used == ExplodeVariant.FLAT assert result.output_directory.exists() assert result.manifest_path is not None assert result.manifest_path.exists() assert len(result.files_created) > 0 def test_flat_variant_can_handle_directory(self): """Test flat variant directory detection.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create flat structure (temp_path / "introduction").mkdir() (temp_path / "introduction" / "index.md").write_text("# Introduction") (temp_path / "chapter_1").mkdir() (temp_path / "chapter_1" / "index.md").write_text("# Chapter 1") variant = FlatVariant() assert variant.can_handle_directory(temp_path) def test_flat_variant_detection_patterns(self): """Test flat variant detection patterns.""" variant = FlatVariant() patterns = variant.get_detection_patterns() assert patterns["manifest_type"] == "flat" assert "numbered_directory_ratio" in patterns assert "fallback_score" in patterns class TestHierarchicalVariant: """Test the HierarchicalVariant implementation.""" def test_hierarchical_variant_initialization(self): """Test HierarchicalVariant initialization.""" variant = HierarchicalVariant() assert variant.variant_type == ExplodeVariant.HIERARCHICAL assert variant.name == "Hierarchical Structure" assert "numbered directory structures" in variant.description def test_hierarchical_variant_explode_basic(self): """Test basic explosion with hierarchical variant.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create test markdown file test_content = """# Getting Started Introduction to the system. ## Installation How to install. ## Configuration How to configure. # Advanced Topics Advanced material. ## Performance Performance considerations. # Conclusion Final notes. """ input_file = temp_path / "guide.md" input_file.write_text(test_content, encoding='utf-8') variant = HierarchicalVariant() options = ExplodeOptions( variant=ExplodeVariant.HIERARCHICAL, create_manifest=True ) result = variant.explode(input_file, options) assert result.success assert result.variant_used == ExplodeVariant.HIERARCHICAL assert result.output_directory.exists() assert result.manifest_path is not None # Check for numbered directories subdirs = [d for d in result.output_directory.iterdir() if d.is_dir()] numbered_dirs = [d for d in subdirs if d.name.startswith(('01_', '02_', '03_'))] assert len(numbered_dirs) > 0 def test_hierarchical_variant_can_handle_directory(self): """Test hierarchical variant directory detection.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create hierarchical structure (temp_path / "01_introduction").mkdir() (temp_path / "01_introduction" / "index.md").write_text("# Introduction") (temp_path / "02_chapter_one").mkdir() (temp_path / "02_chapter_one" / "index.md").write_text("# Chapter One") variant = HierarchicalVariant() assert variant.can_handle_directory(temp_path) def test_hierarchical_variant_detection_patterns(self): """Test hierarchical variant detection patterns.""" variant = HierarchicalVariant() patterns = variant.get_detection_patterns() assert patterns["manifest_type"] == "hierarchical" assert "numbered_directory_ratio" in patterns assert patterns["numbered_directory_ratio"]["min"] == 0.6 class TestSemanticVariant: """Test the SemanticVariant implementation.""" def test_semantic_variant_initialization(self): """Test SemanticVariant initialization.""" variant = SemanticVariant() assert variant.variant_type == ExplodeVariant.SEMANTIC assert variant.name == "Semantic Structure" assert "content-based directory groupings" in variant.description def test_semantic_variant_explode_basic(self): """Test basic explosion with semantic variant.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create test markdown file with semantic content test_content = """# Introduction Welcome to this comprehensive guide. # Tutorial: Getting Started This tutorial will walk you through the basics. ## Step 1: Installation Install the software. ## Step 2: Configuration Configure your environment. # Reference: API Documentation Complete API reference. ## Function Listing List of all functions. # Appendix A: Troubleshooting Common issues and solutions. # Conclusion Final thoughts and summary. """ input_file = temp_path / "manual.md" input_file.write_text(test_content, encoding='utf-8') variant = SemanticVariant() options = ExplodeOptions( variant=ExplodeVariant.SEMANTIC, create_manifest=True ) result = variant.explode(input_file, options) assert result.success assert result.variant_used == ExplodeVariant.SEMANTIC assert result.output_directory.exists() assert result.manifest_path is not None # Check for semantic directories subdirs = [d.name for d in result.output_directory.iterdir() if d.is_dir()] semantic_dirs = [d for d in subdirs if d in ['introduction', 'tutorials', 'reference', 'appendices', 'conclusion']] assert len(semantic_dirs) > 0 def test_semantic_variant_can_handle_directory(self): """Test semantic variant directory detection.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create semantic structure (temp_path / "introduction").mkdir() (temp_path / "introduction" / "overview.md").write_text("# Overview") (temp_path / "chapters").mkdir() (temp_path / "chapters" / "basics.md").write_text("# Basics") (temp_path / "appendices").mkdir() (temp_path / "appendices" / "glossary.md").write_text("# Glossary") variant = SemanticVariant() assert variant.can_handle_directory(temp_path) def test_semantic_variant_detection_patterns(self): """Test semantic variant detection patterns.""" variant = SemanticVariant() patterns = variant.get_detection_patterns() assert patterns["manifest_type"] == "semantic" assert "semantic_directory_ratio" in patterns assert patterns["semantic_directory_ratio"]["min"] == 0.4 class TestVariantFactory: """Test the VariantFactory functionality.""" def test_variant_factory_initialization(self): """Test VariantFactory initialization.""" factory = VariantFactory() assert factory is not None # Test that all built-in variants are registered stats = factory.get_variant_statistics() assert stats['total_variants'] >= 3 assert ExplodeVariant.FLAT in stats['variant_types'] assert ExplodeVariant.HIERARCHICAL in stats['variant_types'] assert ExplodeVariant.SEMANTIC in stats['variant_types'] def test_variant_factory_create_variant(self): """Test creating variants through factory.""" factory = VariantFactory() flat_variant = factory.create_variant(ExplodeVariant.FLAT) assert isinstance(flat_variant, FlatVariant) hierarchical_variant = factory.create_variant(ExplodeVariant.HIERARCHICAL) assert isinstance(hierarchical_variant, HierarchicalVariant) semantic_variant = factory.create_variant(ExplodeVariant.SEMANTIC) assert isinstance(semantic_variant, SemanticVariant) def test_variant_factory_detect_variant(self): """Test variant detection through factory.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create a numbered directory structure (temp_path / "01_intro").mkdir() (temp_path / "02_main").mkdir() (temp_path / "03_end").mkdir() factory = VariantFactory() result = factory.detect_variant(temp_path) assert result.variant is not None # Should detect hierarchical due to numbered directories assert result.variant in [ExplodeVariant.HIERARCHICAL, ExplodeVariant.FLAT] def test_variant_factory_convenience_functions(self): """Test convenience functions.""" # Test global factory factory = get_variant_factory() assert isinstance(factory, VariantFactory) # Test create_variant convenience function variant = create_variant(ExplodeVariant.FLAT) assert isinstance(variant, FlatVariant) def test_variant_factory_list_available_variants(self): """Test listing available variants.""" factory = VariantFactory() variants_info = factory.list_available_variants() assert len(variants_info) >= 3 # Check that required fields are present for info in variants_info: assert 'type' in info assert 'name' in info assert 'description' in info assert 'detection_patterns' in info def test_variant_factory_get_best_variant_for_content(self): """Test content-based variant recommendation.""" factory = VariantFactory() # Content with numbered sections (should suggest hierarchical) numbered_content = """# 1. Introduction # 2. Main Content # 3. Conclusion""" result = factory.get_best_variant_for_content(numbered_content) assert result in [ExplodeVariant.HIERARCHICAL, ExplodeVariant.FLAT] # Content with semantic keywords (should suggest semantic) semantic_content = """# Introduction # Tutorial: Getting Started # Reference Manual # Appendix A""" result = factory.get_best_variant_for_content(semantic_content) assert result in [ExplodeVariant.SEMANTIC, ExplodeVariant.FLAT] class TestVariantIntegration: """Test integration between variants and CLI commands.""" def test_explode_options_validation(self): """Test ExplodeOptions validation.""" # Valid options options = ExplodeOptions(variant=ExplodeVariant.FLAT) assert options.variant == ExplodeVariant.FLAT assert options.create_manifest is True # default # Custom options custom_options = ExplodeOptions( variant=ExplodeVariant.HIERARCHICAL, max_depth=5, create_manifest=False, dry_run=True ) assert custom_options.max_depth == 5 assert custom_options.create_manifest is False assert custom_options.dry_run is True def test_implode_options_validation(self): """Test ImplodeOptions validation.""" # Default options options = ImplodeOptions() assert options.preserve_front_matter is True # default assert options.section_spacing == 2 # default # Custom options custom_options = ImplodeOptions( output_file=Path("/tmp/output.md"), section_spacing=3, dry_run=True ) assert custom_options.output_file == Path("/tmp/output.md") assert custom_options.section_spacing == 3 assert custom_options.dry_run is True def test_error_handling(self): """Test error handling in variants.""" variant = FlatVariant() # Test with non-existent file options = ExplodeOptions(variant=ExplodeVariant.FLAT) result = variant.explode(Path("/nonexistent/file.md"), options) assert not result.success assert len(result.errors) > 0 assert "does not exist" in result.errors[0].lower() def test_manifest_integration(self): """Test manifest creation and reading integration.""" with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create test file test_content = "# Test\n\nContent here." input_file = temp_path / "test.md" input_file.write_text(test_content, encoding='utf-8') # Test each variant creates a manifest for variant_type in [ExplodeVariant.FLAT, ExplodeVariant.HIERARCHICAL, ExplodeVariant.SEMANTIC]: variant = create_variant(variant_type) options = ExplodeOptions( variant=variant_type, output_dir=temp_path / f"test_{variant_type.value}", create_manifest=True ) result = variant.explode(input_file, options) assert result.success assert result.manifest_path is not None assert result.manifest_path.exists() # Verify manifest contains correct variant type manifest_content = result.manifest_path.read_text(encoding='utf-8') assert f"explosion_type: {variant_type.value}" in manifest_content if __name__ == '__main__': pytest.main([__file__, "-v"])