"""Duplication 查重记录领域实体单测.""" import pytest from packages.domain.duplication import DuplicateSegment, DuplicationRecord class TestDuplicateSegmentCreate: def test_create_normal(self): seg = DuplicateSegment.create( source_start=10.0, source_end=20.0, matched_video_id="vid123", matched_video_name="测试视频", matched_start=5.0, matched_end=15.0, similarity=85.5, ) assert seg.id assert seg.source_start == 10.0 assert seg.source_end == 20.0 assert seg.matched_video_id == "vid123" assert seg.matched_video_name == "测试视频" assert seg.matched_start == 5.0 assert seg.matched_end == 15.0 assert seg.similarity == 85.5 def test_create_negative_source_start_raises(self): with pytest.raises(ValueError, match="invalid source segment range"): DuplicateSegment.create( source_start=-1.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=10.0, similarity=50.0, ) def test_create_zero_duration_source_raises(self): with pytest.raises(ValueError, match="invalid source segment range"): DuplicateSegment.create( source_start=10.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=10.0, similarity=50.0, ) def test_create_reversed_source_range_raises(self): with pytest.raises(ValueError, match="invalid source segment range"): DuplicateSegment.create( source_start=20.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=10.0, similarity=50.0, ) def test_create_negative_matched_start_raises(self): with pytest.raises(ValueError, match="invalid matched segment range"): DuplicateSegment.create( source_start=0.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=-1.0, matched_end=10.0, similarity=50.0, ) def test_create_zero_duration_matched_raises(self): with pytest.raises(ValueError, match="invalid matched segment range"): DuplicateSegment.create( source_start=0.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=5.0, matched_end=5.0, similarity=50.0, ) def test_create_similarity_negative_raises(self): with pytest.raises(ValueError, match="similarity must be between 0 and 100"): DuplicateSegment.create( source_start=0.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=10.0, similarity=-1.0, ) def test_create_similarity_over_100_raises(self): with pytest.raises(ValueError, match="similarity must be between 0 and 100"): DuplicateSegment.create( source_start=0.0, source_end=10.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=10.0, similarity=101.0, ) def test_create_similarity_boundary_values(self): # 0 和 100 都是合法的 seg0 = DuplicateSegment.create( source_start=0.0, source_end=1.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=1.0, similarity=0.0, ) assert seg0.similarity == 0.0 seg100 = DuplicateSegment.create( source_start=0.0, source_end=1.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=1.0, similarity=100.0, ) assert seg100.similarity == 100.0 def test_create_unique_ids(self): seg1 = DuplicateSegment.create( source_start=0.0, source_end=1.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=1.0, similarity=50.0, ) seg2 = DuplicateSegment.create( source_start=0.0, source_end=1.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=1.0, similarity=50.0, ) assert seg1.id != seg2.id class TestDuplicationRecordCreate: def test_create_normal(self): record = DuplicationRecord.create( user_id="user1", filename="test.mp4", file_size=1024000, storage_key="videos/test.mp4", duration_seconds=30.5, ) assert record.id assert record.user_id == "user1" assert record.filename == "test.mp4" assert record.file_size == 1024000 assert record.storage_key == "videos/test.mp4" assert record.duration_seconds == 30.5 assert record.status == "pending" assert record.duplicate_rate is None assert record.duplicate_count == 0 assert record.segments == [] assert record.error_message == "" def test_create_strips_whitespace(self): record = DuplicationRecord.create( user_id=" user1 ", filename=" test.mp4 ", file_size=100, storage_key="key1", ) assert record.user_id == "user1" assert record.filename == "test.mp4" def test_create_empty_user_id_raises(self): with pytest.raises(ValueError, match="user_id cannot be empty"): DuplicationRecord.create( user_id="", filename="test.mp4", file_size=100, storage_key="key1", ) def test_create_empty_filename_raises(self): with pytest.raises(ValueError, match="filename cannot be empty"): DuplicationRecord.create( user_id="u1", filename="", file_size=100, storage_key="key1", ) def test_create_zero_file_size_raises(self): with pytest.raises(ValueError, match="file_size must be positive"): DuplicationRecord.create( user_id="u1", filename="test.mp4", file_size=0, storage_key="key1", ) def test_create_negative_file_size_raises(self): with pytest.raises(ValueError, match="file_size must be positive"): DuplicationRecord.create( user_id="u1", filename="test.mp4", file_size=-100, storage_key="key1", ) class TestDuplicationRecordStatus: def test_mark_processing(self): record = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") record.mark_processing() assert record.status == "processing" def test_mark_completed(self): record = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") seg = DuplicateSegment.create( source_start=0.0, source_end=5.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=5.0, similarity=90.0, ) record.mark_completed(duplicate_rate=25.5, duplicate_count=3, segments=[seg]) assert record.status == "completed" assert record.duplicate_rate == 25.5 assert record.duplicate_count == 3 assert len(record.segments) == 1 def test_mark_completed_invalid_rate_raises(self): record = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") with pytest.raises(ValueError, match="duplicate_rate must be between 0 and 100"): record.mark_completed(duplicate_rate=-1, duplicate_count=0, segments=[]) with pytest.raises(ValueError, match="duplicate_rate must be between 0 and 100"): record.mark_completed(duplicate_rate=101, duplicate_count=0, segments=[]) def test_mark_failed(self): record = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") record.mark_failed("网络超时") assert record.status == "failed" assert record.error_message == "网络超时" def test_can_retry_only_failed(self): record = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") assert record.can_retry() is False # pending record.mark_processing() assert record.can_retry() is False # processing record.mark_failed("error") assert record.can_retry() is True # failed seg = DuplicateSegment.create( source_start=0.0, source_end=1.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=1.0, similarity=50.0, ) record2 = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") record2.mark_completed(10.0, 1, [seg]) assert record2.can_retry() is False # completed def test_reset_for_retry(self): record = DuplicationRecord.create(user_id="u1", filename="t.mp4", file_size=100, storage_key="k1") seg = DuplicateSegment.create( source_start=0.0, source_end=1.0, matched_video_id="v1", matched_video_name="v", matched_start=0.0, matched_end=1.0, similarity=50.0, ) record.mark_completed(50.0, 2, [seg]) record.video_fingerprint = {"hash": "abc"} record.reset_for_retry() assert record.status == "pending" assert record.duplicate_rate is None assert record.duplicate_count == 0 assert record.error_message == "" assert record.segments == [] assert record.video_fingerprint is None