4251970b49
CI/CD Pipeline / Check if frontend-only change (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
539 lines
19 KiB
Python
Executable File
539 lines
19 KiB
Python
Executable File
"""CoverGenerator 纯逻辑单测 — 时间钳制 + 智能选帧算法.
|
|
|
|
通过 mock run_ffmpeg 和 probe_video_info 验证纯逻辑部分,
|
|
不实际执行 FFmpeg,确保测试轻量快速。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from video_processing.cover_generator import (
|
|
DEFAULT_COVER_HEIGHT,
|
|
DEFAULT_COVER_QUALITY,
|
|
DEFAULT_COVER_TIME,
|
|
DEFAULT_COVER_WIDTH,
|
|
SMART_COVER_FRAME_COUNT,
|
|
CoverGenerator,
|
|
)
|
|
|
|
|
|
class TestCoverGeneratorConstants:
|
|
"""常量默认值测试."""
|
|
|
|
def test_default_cover_time(self):
|
|
"""默认抽帧时间为 1.0 秒."""
|
|
assert DEFAULT_COVER_TIME == 1.0
|
|
|
|
def test_default_dimensions(self):
|
|
"""默认封面尺寸 1080x1920 (竖屏)."""
|
|
assert DEFAULT_COVER_WIDTH == 1080
|
|
assert DEFAULT_COVER_HEIGHT == 1920
|
|
|
|
def test_default_quality(self):
|
|
"""默认质量为 5 (JPEG q:v, 越小越好)."""
|
|
assert DEFAULT_COVER_QUALITY == 5
|
|
|
|
def test_smart_cover_frame_count(self):
|
|
"""智能封面默认抽 3 帧."""
|
|
assert SMART_COVER_FRAME_COUNT == 3
|
|
|
|
|
|
class TestExtractFrameCommand:
|
|
"""extract_frame 命令构建测试."""
|
|
|
|
def _probe_video_info_mock(self, duration=10.0):
|
|
"""创建 probe_video_info 的 mock."""
|
|
return {"duration": duration, "width": 1920, "height": 1080, "fps": 25.0}
|
|
|
|
def test_default_params_command(self, tmp_path):
|
|
"""默认参数下 FFmpeg 命令正确."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
# 让 output_path 在 run_ffmpeg 后存在
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
result = CoverGenerator.extract_frame(str(video_file), str(output_file))
|
|
|
|
assert result == Path(output_file)
|
|
mock_run.assert_called_once()
|
|
cmd = mock_run.call_args[0][0]
|
|
|
|
# 基本结构
|
|
assert cmd[0].endswith("ffmpeg") or "ffmpeg" in cmd[0]
|
|
assert "-y" in cmd
|
|
assert "-vframes" in cmd
|
|
assert cmd[cmd.index("-vframes") + 1] == "1"
|
|
assert "-f" in cmd
|
|
assert "mjpeg" in cmd[cmd.index("-f") + 1]
|
|
|
|
# 时间点
|
|
ss_idx = cmd.index("-ss")
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(DEFAULT_COVER_TIME, abs=0.001)
|
|
|
|
# 输入文件
|
|
i_idx = cmd.index("-i")
|
|
assert cmd[i_idx + 1] == str(video_file)
|
|
|
|
# 输出文件
|
|
assert cmd[-1] == str(output_file)
|
|
|
|
# scale + crop 滤镜
|
|
vf_idx = cmd.index("-vf")
|
|
vf_value = cmd[vf_idx + 1]
|
|
assert "scale=" in vf_value
|
|
assert "crop=" in vf_value
|
|
assert "force_original_aspect_ratio=increase" in vf_value
|
|
|
|
def test_custom_time(self, tmp_path):
|
|
"""自定义抽帧时间点."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(duration=30.0),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), time_sec=5.5)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
ss_idx = cmd.index("-ss")
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(5.5, abs=0.001)
|
|
|
|
def test_custom_dimensions(self, tmp_path):
|
|
"""自定义输出尺寸."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), width=1920, height=1080)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
vf_idx = cmd.index("-vf")
|
|
vf_value = cmd[vf_idx + 1]
|
|
assert "scale=1920:1080:" in vf_value
|
|
assert "crop=1920:1080" in vf_value
|
|
|
|
def test_custom_quality(self, tmp_path):
|
|
"""自定义 JPEG 质量."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), quality=2)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
q_idx = cmd.index("-q:v")
|
|
assert cmd[q_idx + 1] == "2"
|
|
|
|
def test_time_exceeds_duration_clamps_to_midpoint(self, tmp_path):
|
|
"""抽帧时间超过视频时长时,钳制到中间帧."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(duration=5.0),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), time_sec=10.0)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
ss_idx = cmd.index("-ss")
|
|
# 钳制到 duration/2 = 2.5
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(2.5, abs=0.001)
|
|
|
|
def test_negative_time_clamps_to_zero(self, tmp_path):
|
|
"""负时间钳制到 0."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(duration=10.0),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), time_sec=-2.0)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
ss_idx = cmd.index("-ss")
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(0.0, abs=0.001)
|
|
|
|
def test_time_equals_duration_clamps_to_midpoint(self, tmp_path):
|
|
"""时间点等于时长时钳制到中间帧."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(duration=10.0),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), time_sec=10.0)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
ss_idx = cmd.index("-ss")
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(5.0, abs=0.001)
|
|
|
|
def test_zero_duration_video(self, tmp_path):
|
|
"""视频时长为 0 时的行为(不钳制,用原始时间)."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(duration=0.0),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file), time_sec=0.5)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
ss_idx = cmd.index("-ss")
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(0.5, abs=0.001)
|
|
|
|
def test_video_not_found_raises(self, tmp_path):
|
|
"""视频文件不存在时抛出 FileNotFoundError."""
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with pytest.raises(FileNotFoundError):
|
|
CoverGenerator.extract_frame(str(tmp_path / "nonexistent.mp4"), str(output_file))
|
|
|
|
def test_output_creates_parent_dir(self, tmp_path):
|
|
"""输出目录不存在时自动创建."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
out_dir = tmp_path / "deep" / "nested"
|
|
output_file = out_dir / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(),
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file))
|
|
|
|
assert out_dir.exists()
|
|
assert out_dir.is_dir()
|
|
|
|
def test_ffmpeg_failure_propagates(self, tmp_path):
|
|
"""FFmpeg 失败时异常向上传递."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value=self._probe_video_info_mock(),
|
|
),
|
|
patch(
|
|
"video_processing.cover_generator.run_ffmpeg",
|
|
side_effect=RuntimeError("FFmpeg error"),
|
|
),
|
|
):
|
|
with pytest.raises(RuntimeError, match="FFmpeg error"):
|
|
CoverGenerator.extract_frame(str(video_file), str(output_file))
|
|
|
|
|
|
class TestSmartCoverTimePoints:
|
|
"""智能封面时间点计算测试."""
|
|
|
|
def test_single_frame_falls_back_to_default(self, tmp_path):
|
|
"""只有 1 帧时退化为普通抽帧(取 DEFAULT_COVER_TIME 和 midpoint 中较小值)."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value={"duration": 20.0},
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
# frame_count=1 时退化为普通抽帧
|
|
CoverGenerator.extract_smart_cover(str(video_file), str(output_file), frame_count=1)
|
|
|
|
# 只调用一次(退化路径)
|
|
assert mock_run.call_count == 1
|
|
cmd = mock_run.call_args[0][0]
|
|
ss_idx = cmd.index("-ss")
|
|
# min(DEFAULT_COVER_TIME=1.0, duration/2=10.0) = 1.0
|
|
assert float(cmd[ss_idx + 1]) == pytest.approx(1.0, abs=0.001)
|
|
|
|
def test_zero_duration_falls_back(self, tmp_path):
|
|
"""视频时长为 0 时退化为普通抽帧."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value={"duration": 0.0},
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_smart_cover(str(video_file), str(output_file))
|
|
|
|
# 只调用一次(退化路径)
|
|
assert mock_run.call_count == 1
|
|
|
|
def test_three_frames_uniform_distribution(self, tmp_path):
|
|
"""3 帧均匀分布在 5%~95% 区间."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
call_times = []
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value={"duration": 100.0},
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
# 记录抽帧时间
|
|
ss_idx = cmd.index("-ss")
|
|
call_times.append(float(cmd[ss_idx + 1]))
|
|
# 在输出路径写文件
|
|
output_arg = cmd[-1]
|
|
Path(output_arg).parent.mkdir(parents=True, exist_ok=True)
|
|
# 不同文件大小,让第三帧"最清晰"
|
|
idx = len(call_times) - 1
|
|
size = 1000 * (idx + 1) # 递增的文件大小
|
|
Path(output_arg).write_bytes(b"x" * size)
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_smart_cover(str(video_file), str(output_file))
|
|
|
|
# 3 帧:5%、50%、95%
|
|
assert len(call_times) == 3
|
|
assert call_times[0] == pytest.approx(5.0, abs=0.1) # 5%
|
|
assert call_times[1] == pytest.approx(50.0, abs=0.1) # 50%
|
|
assert call_times[2] == pytest.approx(95.0, abs=0.1) # 95%
|
|
|
|
def test_five_frames_distribution(self, tmp_path):
|
|
"""5 帧均匀分布."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
call_times = []
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value={"duration": 100.0},
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
|
|
def fake_run(cmd):
|
|
ss_idx = cmd.index("-ss")
|
|
call_times.append(float(cmd[ss_idx + 1]))
|
|
output_arg = cmd[-1]
|
|
Path(output_arg).parent.mkdir(parents=True, exist_ok=True)
|
|
idx = len(call_times) - 1
|
|
Path(output_arg).write_bytes(b"x" * (1000 * (idx + 1)))
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.extract_smart_cover(str(video_file), str(output_file), frame_count=5)
|
|
|
|
assert len(call_times) == 5
|
|
# step = (95-5) / (5-1) = 22.5
|
|
# times: 5, 27.5, 50, 72.5, 95
|
|
assert call_times[0] == pytest.approx(5.0, abs=0.1)
|
|
assert call_times[1] == pytest.approx(27.5, abs=0.1)
|
|
assert call_times[2] == pytest.approx(50.0, abs=0.1)
|
|
assert call_times[3] == pytest.approx(72.5, abs=0.1)
|
|
assert call_times[4] == pytest.approx(95.0, abs=0.1)
|
|
|
|
def test_selects_largest_file_as_best(self, tmp_path):
|
|
"""选择文件最大的帧作为最佳封面(清晰度近似)."""
|
|
video_file = tmp_path / "test.mp4"
|
|
video_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
sizes = [5000, 15000, 8000] # 第二帧最大
|
|
|
|
with (
|
|
patch(
|
|
"video_processing.cover_generator.probe_video_info",
|
|
return_value={"duration": 100.0},
|
|
),
|
|
patch("video_processing.cover_generator.run_ffmpeg") as mock_run,
|
|
):
|
|
call_idx = [0]
|
|
|
|
def fake_run(cmd):
|
|
output_arg = cmd[-1]
|
|
Path(output_arg).parent.mkdir(parents=True, exist_ok=True)
|
|
idx = call_idx[0]
|
|
Path(output_arg).write_bytes(b"x" * sizes[idx])
|
|
call_idx[0] += 1
|
|
|
|
mock_run.side_effect = fake_run
|
|
result = CoverGenerator.extract_smart_cover(str(video_file), str(output_file))
|
|
|
|
# 第二帧(索引1)应该是最佳
|
|
assert result == output_file
|
|
# 输出文件大小应等于第二帧大小
|
|
assert output_file.stat().st_size == 15000
|
|
|
|
|
|
class TestProcessCustomCover:
|
|
"""自定义封面处理测试."""
|
|
|
|
def test_custom_cover_resize_command(self, tmp_path):
|
|
"""自定义封面调整尺寸命令正确."""
|
|
input_file = tmp_path / "upload.jpg"
|
|
input_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with patch("video_processing.cover_generator.run_ffmpeg") as mock_run:
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.process_custom_cover(str(input_file), str(output_file))
|
|
|
|
mock_run.assert_called_once()
|
|
cmd = mock_run.call_args[0][0]
|
|
|
|
assert "-i" in cmd
|
|
assert cmd[cmd.index("-i") + 1] == str(input_file)
|
|
assert cmd[-1] == str(output_file)
|
|
|
|
# scale + crop
|
|
vf_idx = cmd.index("-vf")
|
|
vf_value = cmd[vf_idx + 1]
|
|
assert "scale=" in vf_value
|
|
assert "crop=" in vf_value
|
|
|
|
def test_custom_cover_not_found_raises(self, tmp_path):
|
|
"""自定义封面文件不存在时抛出 FileNotFoundError."""
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with pytest.raises(FileNotFoundError):
|
|
CoverGenerator.process_custom_cover(str(tmp_path / "nonexistent.jpg"), str(output_file))
|
|
|
|
def test_custom_cover_custom_dimensions(self, tmp_path):
|
|
"""自定义封面自定义输出尺寸."""
|
|
input_file = tmp_path / "upload.jpg"
|
|
input_file.write_bytes(b"fake")
|
|
output_file = tmp_path / "cover.jpg"
|
|
|
|
with patch("video_processing.cover_generator.run_ffmpeg") as mock_run:
|
|
|
|
def fake_run(cmd):
|
|
output_file.write_bytes(b"fake jpg")
|
|
|
|
mock_run.side_effect = fake_run
|
|
CoverGenerator.process_custom_cover(str(input_file), str(output_file), width=800, height=600)
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
vf_idx = cmd.index("-vf")
|
|
vf_value = cmd[vf_idx + 1]
|
|
assert "scale=800:600:" in vf_value
|
|
assert "crop=800:600" in vf_value
|