"""Unit tests for core interfaces and protocols.""" import pytest from typing import List from tagging_system.core.interfaces import ( FileDiscovery, ContentAnalyzer, TagGenerator, FrontmatterManager, BaseFileDiscovery, BaseContentAnalyzer, BaseTagGenerator, BaseFrontmatterManager ) from tagging_system.core.models import ( FileInfo, ContentAnalysis, TagStructure, FrontmatterData, ValidationResult, ContentType, LanguageInfo ) class MockFileDiscovery(BaseFileDiscovery): """Mock implementation of FileDiscovery for testing.""" def scan_directory(self, path: str) -> List[FileInfo]: """Mock directory scanning.""" from datetime import datetime return [ FileInfo( path=f"{path}/test.md", name="test.md", directory=path, extension=".md", size=100, created=datetime.now(), modified=datetime.now() ) ] def filter_by_type(self, files: List[FileInfo], types: List[str]) -> List[FileInfo]: """Mock file filtering.""" return [f for f in files if f.extension in types] def exclude_sensitive(self, files: List[FileInfo]) -> List[FileInfo]: """Mock sensitive file exclusion.""" return [f for f in files if "sensitive" not in f.path] class MockContentAnalyzer(BaseContentAnalyzer): """Mock implementation of ContentAnalyzer for testing.""" def analyze_content(self, content: str) -> ContentAnalysis: """Mock content analysis.""" return ContentAnalysis( language=LanguageInfo.ENGLISH, content_type=ContentType.NOTE, topics=["test"], mentions={'tools': [], 'technologies': [], 'people': [], 'organizations': []} ) def detect_language(self, content: str) -> str: """Mock language detection.""" return "en" def extract_topics(self, content: str) -> List[str]: """Mock topic extraction.""" return ["test", "mock"] def classify_content_type(self, content: str, filename: str) -> str: """Mock content type classification.""" return "note" class MockTagGenerator(BaseTagGenerator): """Mock implementation of TagGenerator for testing.""" def generate_directory_tags(self, filepath: str) -> List[str]: """Mock directory tag generation.""" if "100-project" in filepath: return ["project"] return ["unknown"] def generate_content_tags(self, analysis: ContentAnalysis) -> List[str]: """Mock content tag generation.""" return analysis.topics def generate_hierarchical_tags(self, topics: List[str]) -> List[str]: """Mock hierarchical tag generation.""" return [f"topic/{topic}" for topic in topics] def consolidate_tags(self, tags: List[str]) -> List[str]: """Mock tag consolidation.""" return list(set(tags)) # Remove duplicates class MockFrontmatterManager(BaseFrontmatterManager): """Mock implementation of FrontmatterManager for testing.""" def parse_frontmatter(self, content: str) -> FrontmatterData: """Mock frontmatter parsing.""" return FrontmatterData( title="Test", tags=["test"], created="2024-01-01" ) def update_frontmatter(self, content: str, updates: FrontmatterData) -> str: """Mock frontmatter updating.""" return f"---\ntitle: {updates.title}\ntags: {updates.tags}\n---\n{content}" def validate_frontmatter(self, data: FrontmatterData) -> ValidationResult: """Mock frontmatter validation.""" result = ValidationResult(is_valid=True) if not data.title: result.add_error("Title is required") return result class TestProtocolCompliance: """Test that mock implementations comply with protocols.""" def test_file_discovery_protocol_compliance(self): """Test that MockFileDiscovery implements FileDiscovery protocol.""" mock = MockFileDiscovery() assert isinstance(mock, FileDiscovery) # Test method calls files = mock.scan_directory("test") assert len(files) == 1 assert files[0].name == "test.md" filtered = mock.filter_by_type(files, [".md"]) assert len(filtered) == 1 non_sensitive = mock.exclude_sensitive(files) assert len(non_sensitive) == 1 def test_content_analyzer_protocol_compliance(self): """Test that MockContentAnalyzer implements ContentAnalyzer protocol.""" mock = MockContentAnalyzer() assert isinstance(mock, ContentAnalyzer) # Test method calls analysis = mock.analyze_content("test content") assert analysis.language == LanguageInfo.ENGLISH assert analysis.content_type == ContentType.NOTE language = mock.detect_language("test content") assert language == "en" topics = mock.extract_topics("test content") assert "test" in topics content_type = mock.classify_content_type("test content", "test.md") assert content_type == "note" def test_tag_generator_protocol_compliance(self): """Test that MockTagGenerator implements TagGenerator protocol.""" mock = MockTagGenerator() assert isinstance(mock, TagGenerator) # Test method calls dir_tags = mock.generate_directory_tags("100-project/test.md") assert "project" in dir_tags analysis = ContentAnalysis( language=LanguageInfo.ENGLISH, content_type=ContentType.NOTE, topics=["ai", "ml"] ) content_tags = mock.generate_content_tags(analysis) assert "ai" in content_tags hierarchical = mock.generate_hierarchical_tags(["ai", "ml"]) assert "topic/ai" in hierarchical consolidated = mock.consolidate_tags(["tag1", "tag1", "tag2"]) assert len(consolidated) == 2 def test_frontmatter_manager_protocol_compliance(self): """Test that MockFrontmatterManager implements FrontmatterManager protocol.""" mock = MockFrontmatterManager() assert isinstance(mock, FrontmatterManager) # Test method calls frontmatter = mock.parse_frontmatter("---\ntitle: Test\n---\nContent") assert frontmatter.title == "Test" updated = mock.update_frontmatter("Content", frontmatter) assert "title: Test" in updated validation = mock.validate_frontmatter(frontmatter) assert validation.is_valid is True class TestAbstractBaseClasses: """Test abstract base class behavior.""" def test_base_classes_cannot_be_instantiated(self): """Test that abstract base classes cannot be instantiated directly.""" with pytest.raises(TypeError): BaseFileDiscovery() with pytest.raises(TypeError): BaseContentAnalyzer() with pytest.raises(TypeError): BaseTagGenerator() with pytest.raises(TypeError): BaseFrontmatterManager() def test_concrete_implementations_work(self): """Test that concrete implementations of base classes work.""" file_discovery = MockFileDiscovery() content_analyzer = MockContentAnalyzer() tag_generator = MockTagGenerator() frontmatter_manager = MockFrontmatterManager() # All should be instances of their respective base classes assert isinstance(file_discovery, BaseFileDiscovery) assert isinstance(content_analyzer, BaseContentAnalyzer) assert isinstance(tag_generator, BaseTagGenerator) assert isinstance(frontmatter_manager, BaseFrontmatterManager)