Spaces:
Sleeping
Sleeping
File size: 7,897 Bytes
2d74db3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | """
Tests for agent_optimizer.py
Covers:
- Layout style β render_mode routing logic (Blurred Stack vs AI Smart Crop)
- Slug sanitisation logic used for output filenames
- run_autonomous_editing_pipeline returns False when no highlights found
- run_autonomous_editing_pipeline iterates and calls generate_vertical_reel_clip per highlight
All Gemini API calls and FFmpeg calls are fully mocked.
"""
import os
import sys
import pytest
from unittest.mock import patch, MagicMock, call
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../app")))
from models import (
StructuredTranscript,
AudioSegment,
WordTimestamp,
ChronologicalVisualTimeline,
VideoFrameMoment,
)
# βββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _make_transcript():
return StructuredTranscript(
segments=[
AudioSegment(
start_time=0.0,
end_time=10.0,
text="Hello world",
words=[WordTimestamp(word="Hello", start=0.0, end=0.5)],
)
]
)
def _make_timeline():
return ChronologicalVisualTimeline(
timeline=[VideoFrameMoment(timestamp_seconds=5.0, visual_description="Slide visible")]
)
def _make_highlight(title="Great Hook", start=10.0, end=30.0, position="center"):
"""Return a mock ProductionHighlight object."""
h = MagicMock()
h.hook_title = title
h.start_time = start
h.end_time = end
h.speaker_position = position
return h
# βββ Slug sanitisation (inline logic extracted for testing) βββββββββββββββββββ
def _sanitise_slug(title: str) -> str:
"""Mirrors the slug logic inside run_autonomous_editing_pipeline."""
return (
"".join(c for c in title if c.isalnum() or c in (" ", "_"))
.rstrip()
.replace(" ", "_")
.lower()
)
class TestSlugSanitisation:
def test_spaces_become_underscores(self):
assert _sanitise_slug("Hello World") == "hello_world"
def test_special_chars_removed(self):
assert _sanitise_slug("Top 5 Tips! #viral") == "top_5_tips_viral"
def test_already_clean_title(self):
assert _sanitise_slug("clean_title") == "clean_title"
def test_empty_title(self):
assert _sanitise_slug("") == ""
def test_only_special_chars_becomes_empty(self):
assert _sanitise_slug("!!!") == ""
# βββ Layout style β render mode routing ββββββββββββββββββββββββββββββββββββββ
def _resolve_render_mode(layout_style: str, speaker_position: str) -> str:
"""Mirrors the if/else in run_autonomous_editing_pipeline."""
if "Blurred Stack" in layout_style:
return "blurred"
return speaker_position
class TestRenderModeRouting:
def test_blurred_stack_overrides_speaker_position(self):
assert _resolve_render_mode("Blurred Stack Mode (Presentation/Code)", "left") == "blurred"
def test_ai_smart_crop_uses_speaker_position_center(self):
assert _resolve_render_mode("AI Smart Face Crop (Podcast/Vlog)", "center") == "center"
def test_ai_smart_crop_uses_speaker_position_left(self):
assert _resolve_render_mode("AI Smart Face Crop (Podcast/Vlog)", "left") == "left"
def test_ai_smart_crop_uses_speaker_position_right(self):
assert _resolve_render_mode("AI Smart Face Crop (Podcast/Vlog)", "right") == "right"
def test_blurred_partial_match_still_resolves(self):
# Ensures substring matching works as coded
assert _resolve_render_mode("Blurred Stack", "right") == "blurred"
# βββ run_autonomous_editing_pipeline βββββββββββββββββββββββββββββββββββββββββ
class TestRunAutonomousEditingPipeline:
@patch("agent_optimizer.generate_vertical_reel_clip")
@patch("agent_optimizer.discover_highlights_autonomously", return_value=[])
def test_returns_false_when_no_highlights(self, mock_discover, mock_render):
from agent_optimizer import run_autonomous_editing_pipeline
result = run_autonomous_editing_pipeline(
video_path="fake.mp4",
audio_transcript=_make_transcript(),
visual_breakdown=_make_timeline(),
layout_style="AI Smart Face Crop",
)
assert result is False
mock_render.assert_not_called()
@patch("agent_optimizer.os.makedirs")
@patch("agent_optimizer.generate_vertical_reel_clip")
@patch("agent_optimizer.discover_highlights_autonomously")
def test_returns_true_when_highlights_found(self, mock_discover, mock_render, mock_makedirs):
mock_discover.return_value = [_make_highlight("Good Clip", 5.0, 25.0, "center")]
from agent_optimizer import run_autonomous_editing_pipeline
result = run_autonomous_editing_pipeline(
video_path="fake.mp4",
audio_transcript=_make_transcript(),
visual_breakdown=_make_timeline(),
layout_style="AI Smart Face Crop",
)
assert result is True
@patch("agent_optimizer.os.makedirs")
@patch("agent_optimizer.generate_vertical_reel_clip")
@patch("agent_optimizer.discover_highlights_autonomously")
def test_calls_render_once_per_highlight(self, mock_discover, mock_render, mock_makedirs):
highlights = [
_make_highlight("Clip One", 5.0, 25.0, "center"),
_make_highlight("Clip Two", 40.0, 60.0, "left"),
]
mock_discover.return_value = highlights
from agent_optimizer import run_autonomous_editing_pipeline
run_autonomous_editing_pipeline(
video_path="fake.mp4",
audio_transcript=_make_transcript(),
visual_breakdown=_make_timeline(),
layout_style="AI Smart Face Crop",
)
assert mock_render.call_count == 2
@patch("agent_optimizer.os.makedirs")
@patch("agent_optimizer.generate_vertical_reel_clip")
@patch("agent_optimizer.discover_highlights_autonomously")
def test_blurred_mode_overrides_render_mode(self, mock_discover, mock_render, mock_makedirs):
mock_discover.return_value = [_make_highlight("Demo", 0.0, 20.0, "right")]
from agent_optimizer import run_autonomous_editing_pipeline
run_autonomous_editing_pipeline(
video_path="fake.mp4",
audio_transcript=_make_transcript(),
visual_breakdown=_make_timeline(),
layout_style="Blurred Stack Mode",
)
_, kwargs = mock_render.call_args
assert kwargs["render_mode"] == "blurred"
@patch("agent_optimizer.os.makedirs")
@patch("agent_optimizer.generate_vertical_reel_clip")
@patch("agent_optimizer.discover_highlights_autonomously")
def test_ffmpeg_error_does_not_crash_pipeline(self, mock_discover, mock_render, mock_makedirs):
"""A single clip render failure should not stop remaining clips."""
mock_discover.return_value = [
_make_highlight("Bad Clip", 0.0, 20.0, "center"),
_make_highlight("Good Clip", 30.0, 50.0, "center"),
]
mock_render.side_effect = [Exception("ffmpeg failed"), None]
from agent_optimizer import run_autonomous_editing_pipeline
# Should not raise β the exception is caught internally
result = run_autonomous_editing_pipeline(
video_path="fake.mp4",
audio_transcript=_make_transcript(),
visual_breakdown=_make_timeline(),
layout_style="AI Smart Face Crop",
)
assert result is True
assert mock_render.call_count == 2
|