"""Tests for PlatformAdapter base class This module tests the interface contracts for the PlatformAdapter abstract base class: 1. PlatformAdapter is an abstract class and cannot be instantiated directly 2. Subclasses must implement all abstract methods """ import pytest from abc import ABC from typing import Dict, Any from kb_pipeline.platforms.base import PlatformAdapter class TestPlatformAdapterInterface: """Test the PlatformAdapter interface contracts""" def test_platform_adapter_is_abstract(self): """Test 1: PlatformAdapter is an abstract class and cannot be instantiated directly""" # Verify it's an ABC subclass assert issubclass(PlatformAdapter, ABC) # Verify it cannot be instantiated directly with pytest.raises(TypeError) as exc_info: PlatformAdapter() # Error should mention abstract methods assert "abstract" in str(exc_info.value).lower() def test_subclass_must_implement_all_methods(self): """Test 2: Subclass must implement all abstract methods""" # Create an incomplete implementation class IncompleteAdapter(PlatformAdapter): def get_content_type(self, url: str) -> str: return "video" # Missing: fetch_metadata, fetch_content, get_output_filename # This should fail to instantiate with pytest.raises(TypeError) as exc_info: IncompleteAdapter() # Verify error mentions missing methods error_msg = str(exc_info.value).lower() assert "abstract" in error_msg or "implement" in error_msg def test_complete_implementation_can_be_instantiated(self): """Test that a complete implementation can be instantiated""" class CompleteAdapter(PlatformAdapter): def get_content_type(self, url: str) -> str: return "video" async def fetch_metadata(self, content_id: str, content_type: str) -> Dict[str, Any]: return {"title": "test"} async def fetch_content(self, content_id: str, content_type: str) -> str: return "# Test Content" def get_output_filename(self, content_id: str, content_type: str, suffix: str) -> str: return f"test_{content_id}_{suffix}" # Should instantiate without error adapter = CompleteAdapter() assert adapter is not None assert adapter.get_content_type("https://example.com/video/123") == "video" class TestPlatformAdapterMethods: """Test the abstract method signatures""" def test_get_content_type_signature(self): """Test get_content_type method signature""" class TestAdapter(PlatformAdapter): def get_content_type(self, url: str) -> str: return "video" async def fetch_metadata(self, content_id: str, content_type: str) -> Dict[str, Any]: return {} async def fetch_content(self, content_id: str, content_type: str) -> str: return "" def get_output_filename(self, content_id: str, content_type: str, suffix: str) -> str: return "" adapter = TestAdapter() # Method should accept URL string and return content type string result = adapter.get_content_type("https://www.bilibili.com/video/BV1test") assert isinstance(result, str) def test_fetch_metadata_is_async(self): """Test fetch_metadata is an async method""" import inspect assert inspect.iscoroutinefunction(PlatformAdapter.fetch_metadata) def test_fetch_content_is_async(self): """Test fetch_content is an async method""" import inspect assert inspect.iscoroutinefunction(PlatformAdapter.fetch_content) def test_get_output_filename_signature(self): """Test get_output_filename method signature""" class TestAdapter(PlatformAdapter): def get_content_type(self, url: str) -> str: return "" async def fetch_metadata(self, content_id: str, content_type: str) -> Dict[str, Any]: return {} async def fetch_content(self, content_id: str, content_type: str) -> str: return "" def get_output_filename(self, content_id: str, content_type: str, suffix: str) -> str: return f"{content_type}_{content_id}_{suffix}" adapter = TestAdapter() # Method should accept content_id, content_type, suffix and return filename string result = adapter.get_output_filename("BV1test", "video", "metadata.json") assert isinstance(result, str) assert "BV1test" in result assert "video" in result assert "metadata.json" in result