"""Backward Compatibility Tests Tests to ensure that configuration changes don't break existing functionality: - Rule-based segmentation (SemanticSegmenter) works unchanged (CONFIG-02) - AnalyzeProcessor is not affected by SRTProcessor config changes (CONFIG-03) - Existing API calls remain compatible """ import pytest from unittest.mock import Mock, patch, MagicMock from pathlib import Path from kb_workflow.srt.parser import Segment from kb_workflow.srt.segmenter import SemanticSegmenter # ============================================================================= # Test Fixtures # ============================================================================= @pytest.fixture def sample_segments(): """Sample subtitle segments for testing""" return [ Segment(1, 0.0, 5.0, "第一句内容"), Segment(2, 5.0, 10.0, "第二句内容"), Segment(3, 10.0, 15.0, "第三句内容"), ] @pytest.fixture def long_text_segments(): """Segments with long text that triggers length-based splitting""" text = "这是一段很长的文本内容" * 50 # ~500 characters return [ Segment(1, 0.0, 5.0, text[:250]), Segment(2, 5.0, 10.0, text[:250]), Segment(3, 10.0, 15.0, text[:250]), ] @pytest.fixture def gap_segments(): """Segments with time gaps > 3 seconds""" return [ Segment(1, 0.0, 5.0, "第一段落内容"), Segment(2, 10.0, 15.0, "第二段落内容"), # 5 second gap Segment(3, 15.0, 20.0, "继续第二段落"), ] # ============================================================================= # Task 1: Rule-based Segmentation Backward Compatibility (CONFIG-02) # ============================================================================= class TestBackwardCompatibility: """Test backward compatibility for rule-based segmentation (CONFIG-02)""" def test_rule_based_segmentation_unchanged(self, sample_segments): """Test 1: enable_semantic_segmentation=False 使用规则分段器""" from kb_workflow.pipeline.processors.srt import SRTProcessor from kb_workflow.srt.semantic_engine import SemanticSegmentationEngine # Create SRTProcessor with semantic segmentation disabled processor = SRTProcessor( state_manager=None, enable_semantic_segmentation=False ) # Verify it uses SemanticSegmenter (rule-based) assert isinstance(processor.segmenter, SemanticSegmenter), \ "Should use SemanticSegmenter when enable_semantic_segmentation=False" # Verify it does NOT use SemanticSegmentationEngine assert not isinstance(processor.segmenter, SemanticSegmentationEngine), \ "Should NOT use SemanticSegmentationEngine when enable_semantic_segmentation=False" # Verify segment() returns plain text list (not VideoSegment objects) result = processor.segmenter.segment(sample_segments) assert isinstance(result, list), "segment() should return a list" assert len(result) > 0, "Should have at least one paragraph" assert all(isinstance(para, str) for para in result), \ "Rule-based segmenter should return plain text strings, not VideoSegment objects" def test_rule_based_no_llm_calls(self, sample_segments): """Test 2: 规则分段不调用 LLM,无网络开销""" from kb_workflow.pipeline.processors.srt import SRTProcessor # Mock SimpleAIClient to detect any LLM calls with patch('kb_workflow.deep_analyzer.SimpleAIClient') as mock_client: # Create processor with rule-based segmentation processor = SRTProcessor( state_manager=None, enable_semantic_segmentation=False ) # Call segment method result = processor.segmenter.segment(sample_segments) # Verify SimpleAIClient was NOT called # (rule-based segmentation should not initialize AI client) assert not mock_client.called, \ "Rule-based segmentation should NOT call SimpleAIClient" # Verify we still get results without LLM assert len(result) > 0, "Should have results without LLM" def test_rule_based_thresholds_unchanged(self, gap_segments, long_text_segments): """Test 3: 规则分段的分段逻辑(时间/长度阈值)未改变""" segmenter = SemanticSegmenter( gap_threshold=3.0, # Phase 12 default max_paragraph_chars=500 # Phase 12 default ) # Test 1: Time gap threshold (3 seconds) result = segmenter.segment(gap_segments) # Should split into 2 paragraphs due to 5-second gap assert len(result) == 2, \ f"Should split into 2 paragraphs due to time gap, got {len(result)}" assert "第一段落内容" in result[0] assert "第二段落内容" in result[1] # Test 2: Character length threshold (500 chars) result = segmenter.segment(long_text_segments) # Each segment is ~250 chars, so with 3 segments we should get splits # First segment: 250 chars (no split) # Second segment: 250 + 250 = 500 chars (might split depending on exact count) assert len(result) >= 1, "Should have at least one paragraph" assert all(isinstance(para, str) for para in result), \ "All results should be plain text strings" @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 3") def test_existing_api_compatibility(self): """Test 4: 不传 enable_semantic_segmentation 参数时使用配置默认值""" # This test will be implemented in Task 3 pass @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 3") def test_explicit_false_overrides_config(self): """Test 5: 显式传 False 时覆盖配置,使用规则分段""" # This test will be implemented in Task 3 pass @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 3") def test_migration_path(self): """Test 6: 验证用户可以通过两种方式启用语义分段""" # This test will be implemented in Task 3 pass @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 2") def test_analyze_processor_unaffected(self): """Test 7: AnalyzeProcessor 不受 KBSettings.enable_semantic_segmentation 影响""" # This test will be implemented in Task 2 pass # ============================================================================= # Task 2: AnalyzeProcessor Independence (CONFIG-03) # ============================================================================= class TestAnalyzeProcessorIndependence: """Test that AnalyzeProcessor is independent of SRTProcessor configuration""" @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 2") def test_analyze_processor_unaffected_by_config(self): """Test: AnalyzeProcessor 不受 KBSettings.enable_semantic_segmentation 影响""" # This test will be implemented in Task 2 pass @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 2") def test_analyze_processor_normal_initialization(self): """Test: AnalyzeProcessor 正常初始化和处理""" # This test will be implemented in Task 2 pass @pytest.mark.skipif(True, reason="Not implemented yet - will implement in Task 2") def test_analyze_processor_output_unchanged(self): """Test: AnalyzeProcessor 输出格式未改变""" # This test will be implemented in Task 2 pass