Spaces:
Sleeping
Sleeping
File size: 5,451 Bytes
3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 3da2703 b3fce51 | 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 | """
Unit tests for Node 4: Clip Signal Extractor
(src/envs/subenv2/node4_clip_extractor.py)
OpenCV VideoCapture and FaceLandmarker initialization are mocked so no real
video files or model assets are required.
"""
from __future__ import annotations
import json
import types
from pathlib import Path
from unittest.mock import MagicMock, patch
import numpy as np
import pytest
from src.schemas.subenv2 import ClipSignalObservation
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
_RNG = np.random.default_rng(42)
def _random_frame(height: int = 72, width: int = 128) -> np.ndarray:
return _RNG.integers(0, 256, (height, width, 3), dtype=np.uint8)
def mock_capture(frame_count: int, height: int = 72, width: int = 128) -> MagicMock:
frames = [_random_frame(height, width) for _ in range(frame_count)]
read_returns = [(True, f) for f in frames] + [(False, None)]
read_iter = iter(read_returns)
cap = MagicMock()
cap.isOpened.return_value = True
cap.read.side_effect = lambda: next(read_iter)
cap.release.return_value = None
return cap
def _make_landmarker_mock() -> MagicMock:
lm = types.SimpleNamespace(x=0.5, y=0.5, z=0.0)
landmarks = [lm] * 478
detect_result = types.SimpleNamespace(face_landmarks=[landmarks])
landmarker = MagicMock()
landmarker.detect.return_value = detect_result
landmarker.close.return_value = None
return landmarker
def _full_patch(cap_mock: MagicMock, landmarker: MagicMock):
from contextlib import ExitStack
stack = ExitStack()
stack.enter_context(patch("cv2.VideoCapture", return_value=cap_mock))
stack.enter_context(
patch(
"src.envs.subenv2.node4_clip_extractor._create_face_landmarker",
return_value=landmarker,
)
)
return stack
_EMPTY_CTX: dict = {
"current_phoneme_coverage": {},
"current_pose_distribution": {},
"clips_audited_so_far": 0,
"similar_clips_accepted": 0,
}
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
def test_raises_on_short_clip(tmp_path):
dummy = tmp_path / "dummy.mp4"
dummy.touch()
cap = mock_capture(10)
with patch("cv2.VideoCapture", return_value=cap):
with pytest.raises(ValueError, match="24"):
from src.envs.subenv2.node4_clip_extractor import extract_clip_signals
extract_clip_signals(dummy, {})
def test_blur_score_in_range(tmp_path):
dummy = tmp_path / "dummy.mp4"
dummy.touch()
cap30 = mock_capture(30)
landmarker = _make_landmarker_mock()
with _full_patch(cap30, landmarker):
from src.envs.subenv2.node4_clip_extractor import extract_clip_signals
result = extract_clip_signals(dummy, _EMPTY_CTX)
assert isinstance(result, ClipSignalObservation)
assert 0.0 <= result.blur_score <= 1.0
def test_phoneme_coverage_new_empty_dataset(tmp_path):
dummy = tmp_path / "dummy.mp4"
dummy.touch()
aligner_data = {"phonemes": ["AH", "EE", "OW"]}
aligner_json = tmp_path / "align.json"
aligner_json.write_text(json.dumps(aligner_data))
cap30 = mock_capture(30)
landmarker = _make_landmarker_mock()
ctx = {**_EMPTY_CTX, "current_phoneme_coverage": {}}
with _full_patch(cap30, landmarker):
from src.envs.subenv2.node4_clip_extractor import extract_clip_signals
result = extract_clip_signals(
dummy,
ctx,
aligner_output=json.loads(aligner_json.read_text()),
)
assert result.phoneme_coverage_new == 1.0
def test_phoneme_coverage_new_partial(tmp_path):
dummy = tmp_path / "dummy.mp4"
dummy.touch()
aligner_data = {"phonemes": ["AH", "EE", "OW"]}
aligner_json = tmp_path / "align.json"
aligner_json.write_text(json.dumps(aligner_data))
cap30 = mock_capture(30)
landmarker = _make_landmarker_mock()
ctx = {**_EMPTY_CTX, "current_phoneme_coverage": {"AH": 3}}
with _full_patch(cap30, landmarker):
from src.envs.subenv2.node4_clip_extractor import extract_clip_signals
result = extract_clip_signals(
dummy,
ctx,
aligner_output=json.loads(aligner_json.read_text()),
)
assert abs(result.phoneme_coverage_new - 2 / 3) < 1e-6
def test_no_forced_align_path(tmp_path):
dummy = tmp_path / "dummy.mp4"
dummy.touch()
cap30 = mock_capture(30)
landmarker = _make_landmarker_mock()
with _full_patch(cap30, landmarker):
from src.envs.subenv2.node4_clip_extractor import extract_clip_signals
result = extract_clip_signals(dummy, _EMPTY_CTX, aligner_output=None)
assert result.phoneme_sequence == []
assert result.lip_sync_confidence == 0.0
def test_raises_when_landmarker_unavailable(tmp_path):
dummy = tmp_path / "dummy.mp4"
dummy.touch()
cap30 = mock_capture(30)
with patch("cv2.VideoCapture", return_value=cap30), patch(
"src.envs.subenv2.node4_clip_extractor._create_face_landmarker",
return_value=None,
):
with pytest.raises(ValueError, match="FaceLandmarker model file"):
from src.envs.subenv2.node4_clip_extractor import extract_clip_signals
extract_clip_signals(dummy, _EMPTY_CTX)
|