Ctrl K
ComunidadGuías…

backend/tests/test_ffsubsync_shift_parser.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""One ffsubsync shift parser, and no silent 0 ms on unparseable output.

The legacy wrapper (``services.video_sync``) and the engine class
(``services.sync_engines.ffsubsync_engine``) each had their own parser with
different patterns, and both returned 0 when no offset line was found. A run
whose output carried no offset then "succeeded" with no shift: the sidecar
was rewritten unchanged and booked as synced.
"""

from unittest.mock import MagicMock, patch

import pytest

from services.sync_engines.ffsubsync_output import parse_ffsubsync_shift

REAL_LINE = "[13:51:53] INFO     offset seconds: 22.960                      ffsubsync.py:189"


class TestParser:
    @pytest.mark.parametrize(
        ("output", "expected"),
        [
            ("INFO     offset seconds: 22.960", 22960),
            (REAL_LINE, 22960),
            ("           INFO     offset seconds: -0.990    ffsubsync.py:189", -990),
            ("offset seconds: 0.000", 0),
            ("offset: 1.234 s applied", 1234),
            ("Offset: -0.5 s", -500),
            ("estimated shift: 0.42s", 420),
            ("offset -1.2s detected", -1200),
            ("offset seconds: 1.001", 1001),
        ],
    )
    def test_known_formats(self, output, expected):
        assert parse_ffsubsync_shift(output) == expected

    @pytest.mark.parametrize(
        "output",
        ["", "no offset info", "INFO     extracting speech segments...", "max_offset_seconds: 60"],
    )
    def test_no_offset_line_is_none_not_zero(self, output):
        assert parse_ffsubsync_shift(output) is None

    def test_both_modules_use_the_shared_parser(self):
        from services import video_sync
        from services.sync_engines import ffsubsync_engine

        assert video_sync._parse_ffsubsync_shift is parse_ffsubsync_shift
        assert ffsubsync_engine._parse_ffsubsync_shift is parse_ffsubsync_shift


ORIGINAL = "1\n00:00:01,000 --> 00:00:02,000\nHello\n"


def test_legacy_wrapper_fails_without_an_offset_line(tmp_path):
    from services.video_sync import sync_with_ffsubsync

    sub = tmp_path / "ep.srt"
    sub.write_text(ORIGINAL)
    fake = MagicMock(returncode=0, stderr="INFO     computing alignments...", stdout="")
    with (
        patch("services.video_sync.shutil.which", return_value="/usr/bin/ffsubsync"),
        patch("services.video_sync.subprocess.run", return_value=fake),
        patch("config.get_settings", return_value=MagicMock(sync_sanity_threshold_ms=45_000)),
        pytest.raises(RuntimeError, match="no offset"),
    ):
        sync_with_ffsubsync(str(sub), "/video.mkv")
    assert sub.read_text() == ORIGINAL


def test_legacy_wrapper_keeps_a_real_zero_offset(tmp_path):
    from services.video_sync import sync_with_ffsubsync

    sub = tmp_path / "ep.srt"
    sub.write_text(ORIGINAL)
    fake = MagicMock(returncode=0, stderr="INFO     offset seconds: 0.000", stdout="")
    with (
        patch("services.video_sync.shutil.which", return_value="/usr/bin/ffsubsync"),
        patch("services.video_sync.subprocess.run", return_value=fake),
        patch("config.get_settings", return_value=MagicMock(sync_sanity_threshold_ms=45_000)),
    ):
        result = sync_with_ffsubsync(str(sub), "/video.mkv")
    assert result["shift_ms"] == 0


def test_engine_reports_failure_without_an_offset_line(tmp_path):
    from services.sync_engines.ffsubsync_engine import FfsubsyncEngine

    sub = tmp_path / "ep.srt"
    sub.write_text(ORIGINAL)
    fake = MagicMock(returncode=0, stderr="INFO     computing alignments...", stdout="")
    with (
        patch("services.sync_engines.ffsubsync_engine.shutil.which", return_value="ffsubsync"),
        patch("services.sync_engines.ffsubsync_engine.subprocess.run", return_value=fake),
        patch("services.sync_engines.ffsubsync_engine._fire_after_sync_trigger") as trigger,
    ):
        result = FfsubsyncEngine().sync(str(sub), "/v.mkv")
    assert result.ok is False
    assert "no offset" in result.reason
    assert sub.read_text() == ORIGINAL
    trigger.assert_not_called()


def test_preview_fails_without_an_offset_line(tmp_path):
    from services import sync_preview

    sub = tmp_path / "ep.srt"
    sub.write_text(ORIGINAL)
    fake = MagicMock(returncode=0, stderr="nothing useful", stdout="")
    with (
        patch("services.sync_preview.shutil.which", return_value="/usr/bin/ffsubsync"),
        patch.object(sync_preview, "_locked_subprocess", return_value=fake),
        pytest.raises(RuntimeError, match="no offset"),
    ):
        sync_preview._run_ffsubsync_preview(str(sub), "/v.mkv")