Files

207 lines
6.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
video_split 单元测试
"""
import os
import json
from pathlib import Path
import pytest
# 确保 src 在 path 中
import sys
sys.path.insert(0, str(Path(__file__).parent.parent))
from doco.video_split import (
hamming_distance,
format_timestamp,
build_b_manuscript,
is_blank_frame,
)
class TestHammingDistance:
def test_identical_strings(self):
assert hamming_distance("abc", "abc") == 0
def test_different_strings(self):
assert hamming_distance("abc", "abd") == 1
def test_different_length(self):
# 长度不同时,返回较长字符串的长度
assert hamming_distance("abc", "ab") == 3
class TestFormatTimestamp:
def test_zero(self):
assert format_timestamp(0) == "0m0s"
def test_seconds_only(self):
assert format_timestamp(30000) == "0m30s" # 30秒
def test_minutes_and_seconds(self):
assert format_timestamp(90000) == "1m30s" # 1分30秒
def test_longer(self):
assert format_timestamp(3723000) == "62m3s" # 62分3秒
class TestBuildBManuscript:
def test_empty_keyframes(self):
lines = build_b_manuscript([])
assert lines == []
def test_single_frame(self):
keyframes = [
{"timestamp_ms": 0, "ocr_text": "测试字幕"}
]
lines = build_b_manuscript(keyframes)
assert len(lines) == 1
assert "[0m0s]" in lines[0]
assert "测试字幕" in lines[0]
def test_duplicate_text_merged(self):
"""相邻同文本应合并"""
keyframes = [
{"timestamp_ms": 0, "ocr_text": "相同"},
{"timestamp_ms": 1000, "ocr_text": "相同"},
{"timestamp_ms": 2000, "ocr_text": "不同"},
]
lines = build_b_manuscript(keyframes)
assert len(lines) == 2
def test_placeholder_skipped(self):
"""OCR占位文本应跳过"""
keyframes = [
{"timestamp_ms": 0, "ocr_text": "[OCR待填充 frame=001.png]"},
{"timestamp_ms": 1000, "ocr_text": "真实字幕"},
]
lines = build_b_manuscript(keyframes)
assert len(lines) == 1
assert "真实字幕" in lines[0]
class TestKeyframesJson:
"""验证 keyframes.json 输出格式"""
def test_keyframe_structure(self, tmp_path):
"""验证单个关键帧的 JSON 结构"""
# 模拟关键帧数据
kf = {
"frame_index": 1,
"timestamp_ms": 1000,
"frame_image_path": str(tmp_path / "frame_0001.png"),
"phash": "ff00aabb12345678",
"ocr_text": "测试",
}
# 验证字段存在
assert "frame_index" in kf
assert "timestamp_ms" in kf
assert "frame_image_path" in kf
assert "phash" in kf
assert "ocr_text" in kf
def test_keyframes_json_output(self, tmp_path):
"""验证完整 keyframes.json 输出"""
frames_dir = tmp_path / "frames"
frames_dir.mkdir()
# 创建一个测试图片
test_img = frames_dir / "frame_0001.png"
test_img.write_bytes(b"fake_png_data")
keyframes_data = {
"video_path": str(tmp_path / "video.mp4"),
"fps_sampled": 1,
"phash_threshold": 8,
"keyframes": [
{
"frame_index": 0,
"timestamp_ms": 0,
"frame_image_path": str(test_img),
"phash": "abcd1234",
"ocr_text": "首帧",
}
]
}
json_path = tmp_path / "keyframes.json"
with open(json_path, "w", encoding="utf-8") as f:
json.dump(keyframes_data, f, ensure_ascii=False, indent=2)
# 验证可读
with open(json_path, "r", encoding="utf-8") as f:
loaded = json.load(f)
assert loaded["fps_sampled"] == 1
assert loaded["phash_threshold"] == 8
assert len(loaded["keyframes"]) == 1
assert loaded["keyframes"][0]["frame_index"] == 0
class TestIsBlankFrame:
"""is_blank_frame 双条件检测单元测试"""
def test_pure_black_frame(self, tmp_path):
"""全 0 纯黑图:max_brightness=0,white_ratio=0,is_blank=True"""
from PIL import Image
img_path = tmp_path / "black.png"
img = Image.new("L", (100, 100), 0) # 全黑
img.save(img_path)
is_blank, white_ratio, max_brightness = is_blank_frame(img_path)
assert is_blank is True
assert max_brightness == 0
assert white_ratio == 0.0
def test_subtitle_frame(self, tmp_path):
"""有少量白像素(亮度255,占~1%)的图:is_blank=False"""
from PIL import Image
import numpy as np
img_path = tmp_path / "subtitle.png"
arr = np.zeros((100, 100), dtype=np.uint8)
# 1% 白像素(亮度255),其余黑(亮度0)
arr[:10, :10] = 255 # 10×10=100/10000=1%
img = Image.fromarray(arr, mode="L")
img.save(img_path)
is_blank, white_ratio, max_brightness = is_blank_frame(img_path)
assert is_blank is False
assert max_brightness == 255
assert 0.005 <= white_ratio <= 0.02 # ~1%
def test_max_brightness_ok_but_ratio_too_low(self, tmp_path):
"""max_brightness>=240 但 white_ratio<0.005 → is_blank=True"""
from PIL import Image
import numpy as np
img_path = tmp_path / "few_pixels.png"
arr = np.zeros((100, 100), dtype=np.uint8)
# 只有 0.1% 白像素(不够 0.5%),但 max_brightness=255
arr[:10, :1] = 255
img = Image.fromarray(arr, mode="L")
img.save(img_path)
is_blank, white_ratio, max_brightness = is_blank_frame(img_path)
assert is_blank is True
assert max_brightness == 255
assert white_ratio < 0.005
def test_ratio_ok_but_max_brightness_too_low(self, tmp_path):
"""max_brightness<240 → 白像素计数全为0 → is_blank=True"""
from PIL import Image
import numpy as np
img_path = tmp_path / "dim_pixels.png"
arr = np.zeros((100, 100), dtype=np.uint8)
# 1% 像素亮度=220(不满足阈值240),其余黑
# is_blank_frame 用 arr > 240 统计白像素,220 全不满足 → white_ratio=0
arr[:10, :10] = 220
img = Image.fromarray(arr, mode="L")
img.save(img_path)
is_blank, white_ratio, max_brightness = is_blank_frame(img_path)
assert is_blank is True
assert max_brightness == 220
assert white_ratio == 0.0