"""media_validation 媒体文件校验单测.""" import pytest from domain.media_validation import ( MIN_AUDIO_FILE_SIZE, MIN_IMAGE_FILE_SIZE, MIN_VIDEO_FILE_SIZE, SUPPORTED_VIDEO_CODECS, is_valid_media, safe_parse_fps, ) # ── 常量测试 ───────────────────────────────────────────────────────────────── class TestConstants: """模块常量""" def test_min_sizes(self): assert MIN_VIDEO_FILE_SIZE == 1024 assert MIN_AUDIO_FILE_SIZE == 100 assert MIN_IMAGE_FILE_SIZE == 100 def test_supported_codecs_is_frozenset(self): assert isinstance(SUPPORTED_VIDEO_CODECS, frozenset) def test_supported_codecs_includes_common(self): assert "h264" in SUPPORTED_VIDEO_CODECS assert "hevc" in SUPPORTED_VIDEO_CODECS assert "vp9" in SUPPORTED_VIDEO_CODECS assert "av1" in SUPPORTED_VIDEO_CODECS assert "mpeg4" in SUPPORTED_VIDEO_CODECS assert "prores" in SUPPORTED_VIDEO_CODECS def test_supported_codecs_count(self): assert len(SUPPORTED_VIDEO_CODECS) >= 20 # ── safe_parse_fps ─────────────────────────────────────────────────────────── class TestSafeParseFps: """safe_parse_fps 函数""" def test_simple_decimal(self): assert safe_parse_fps("30.0") == 30.0 def test_integer_string(self): assert safe_parse_fps("24") == 24.0 def test_fraction_format(self): assert abs(safe_parse_fps("30000/1001") - 29.97) < 0.01 def test_simple_fraction(self): assert safe_parse_fps("30/1") == 30.0 def test_24fps_fraction(self): assert safe_parse_fps("24/1") == 24.0 def test_60fps_fraction(self): assert safe_parse_fps("60000/1001") == pytest.approx(59.94, abs=0.01) def test_zero_denominator_returns_zero(self): assert safe_parse_fps("30/0") == 0.0 def test_empty_string_returns_zero(self): assert safe_parse_fps("") == 0.0 def test_invalid_string_returns_zero(self): assert safe_parse_fps("invalid") == 0.0 def test_none_numerator_fraction(self): assert safe_parse_fps("abc/1001") == 0.0 def test_negative_fps(self): assert safe_parse_fps("-30") == -30.0 def test_very_high_fps(self): assert safe_parse_fps("240/1") == 240.0 def test_multiple_slashes(self): # 只按第一个 / 分割 # "30/1/2" → num="30", den="1/2" → float("1/2") 抛异常 → 返回 0 assert safe_parse_fps("30/1/2") == 0.0 def test_float_fraction(self): result = safe_parse_fps("29.97/1") assert result == pytest.approx(29.97) def test_zero_fps(self): assert safe_parse_fps("0") == 0.0 def test_zero_numerator(self): assert safe_parse_fps("0/1000") == 0.0 # ── is_valid_media - video ─────────────────────────────────────────────────── class TestIsValidMediaVideo: """is_valid_media 视频校验""" def test_valid_video(self): metadata = { "size_bytes": 1024 * 1024, # 1MB "duration": 10.0, "codec": "h264", "width": 1920, "height": 1080, } assert is_valid_media(metadata, "video") is True def test_small_file_invalid(self): metadata = {"size_bytes": 100, "duration": 10.0} assert is_valid_media(metadata, "video") is False def test_exact_min_size_valid(self): metadata = {"size_bytes": MIN_VIDEO_FILE_SIZE, "duration": 1.0} assert is_valid_media(metadata, "video") is True def test_zero_duration_invalid(self): metadata = {"size_bytes": 1024 * 1024, "duration": 0} assert is_valid_media(metadata, "video") is False def test_negative_duration_invalid(self): metadata = {"size_bytes": 1024 * 1024, "duration": -1.0} assert is_valid_media(metadata, "video") is False def test_unsupported_codec_still_valid(self): # 非白名单编码仍允许通过(不做严格拦截) metadata = { "size_bytes": 1024 * 1024, "duration": 10.0, "codec": "unknown_codec_xyz", } assert is_valid_media(metadata, "video") is True def test_empty_codec_valid(self): metadata = {"size_bytes": 1024 * 1024, "duration": 10.0, "codec": ""} assert is_valid_media(metadata, "video") is True def test_no_codec_valid(self): metadata = {"size_bytes": 1024 * 1024, "duration": 10.0} assert is_valid_media(metadata, "video") is True def test_hevc_codec_valid(self): metadata = { "size_bytes": 1024 * 1024, "duration": 10.0, "codec": "hevc", } assert is_valid_media(metadata, "video") is True def test_codec_case_insensitive(self): metadata = { "size_bytes": 1024 * 1024, "duration": 10.0, "codec": "H264", } assert is_valid_media(metadata, "video") is True def test_missing_size_invalid(self): metadata = {"duration": 10.0} assert is_valid_media(metadata, "video") is False def test_missing_duration_invalid(self): metadata = {"size_bytes": 1024 * 1024} assert is_valid_media(metadata, "video") is False def test_empty_metadata_invalid(self): assert is_valid_media({}, "video") is False # ── is_valid_media - audio ─────────────────────────────────────────────────── class TestIsValidMediaAudio: """is_valid_media 音频校验""" def test_valid_audio(self): metadata = {"size_bytes": 1024, "duration": 30.0, "codec": "aac"} assert is_valid_media(metadata, "audio") is True def test_small_audio_invalid(self): metadata = {"size_bytes": 50, "duration": 30.0} assert is_valid_media(metadata, "audio") is False def test_exact_min_size_valid(self): metadata = {"size_bytes": MIN_AUDIO_FILE_SIZE, "duration": 1.0} assert is_valid_media(metadata, "audio") is True def test_zero_duration_invalid(self): metadata = {"size_bytes": 1024, "duration": 0} assert is_valid_media(metadata, "audio") is False def test_negative_duration_invalid(self): metadata = {"size_bytes": 1024, "duration": -5.0} assert is_valid_media(metadata, "audio") is False def test_empty_metadata_invalid(self): assert is_valid_media({}, "audio") is False def test_very_short_audio_valid(self): metadata = {"size_bytes": 200, "duration": 0.5} assert is_valid_media(metadata, "audio") is True # ── is_valid_media - image ─────────────────────────────────────────────────── class TestIsValidMediaImage: """is_valid_media 图片校验""" def test_valid_image(self): metadata = {"size_bytes": 1024, "width": 1920, "height": 1080} assert is_valid_media(metadata, "image") is True def test_small_image_invalid(self): metadata = {"size_bytes": 50, "width": 1920, "height": 1080} assert is_valid_media(metadata, "image") is False def test_exact_min_size_valid(self): metadata = { "size_bytes": MIN_IMAGE_FILE_SIZE, "width": 100, "height": 100, } assert is_valid_media(metadata, "image") is True def test_zero_width_invalid(self): metadata = {"size_bytes": 1024, "width": 0, "height": 1080} assert is_valid_media(metadata, "image") is False def test_zero_height_invalid(self): metadata = {"size_bytes": 1024, "width": 1920, "height": 0} assert is_valid_media(metadata, "image") is False def test_negative_width_invalid(self): metadata = {"size_bytes": 1024, "width": -1, "height": 1080} assert is_valid_media(metadata, "image") is False def test_small_image_valid(self): metadata = {"size_bytes": 200, "width": 10, "height": 10} assert is_valid_media(metadata, "image") is True def test_missing_width_invalid(self): metadata = {"size_bytes": 1024, "height": 1080} assert is_valid_media(metadata, "image") is False def test_missing_height_invalid(self): metadata = {"size_bytes": 1024, "width": 1920} assert is_valid_media(metadata, "image") is False def test_empty_metadata_invalid(self): assert is_valid_media({}, "image") is False # ── is_valid_media - edge cases ───────────────────────────────────────────── class TestIsValidMediaEdgeCases: """is_valid_media 边界情况""" def test_invalid_media_type(self): metadata = {"size_bytes": 1024, "duration": 10.0} assert is_valid_media(metadata, "document") is False def test_empty_media_type(self): metadata = {"size_bytes": 1024} assert is_valid_media(metadata, "") is False def test_string_size_converted(self): metadata = {"size_bytes": "2048", "duration": "5.0"} assert is_valid_media(metadata, "video") is True def test_video_size_as_string(self): metadata = {"size_bytes": "1000000", "duration": "30"} assert is_valid_media(metadata, "video") is True def test_invalid_size_string_raises(self): # int("abc") 会抛 ValueError metadata = {"size_bytes": "abc", "duration": 10.0} with pytest.raises(ValueError): is_valid_media(metadata, "video") def test_none_size_raises(self): # int(None) 会抛 TypeError metadata = {"size_bytes": None, "duration": 10.0} with pytest.raises(TypeError): is_valid_media(metadata, "video")