Spaces:
Sleeping
Sleeping
| """ | |
| 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) | |