# backend/tests/test_common_fixes_extended.py """Tests for common_fixes module — all 18 fixes.""" import pytest def _subs_from_lines(lines: list[str], fmt="srt"): """Helper: create an in-memory pysubs2 SSAFile from text lines.""" import pysubs2 subs = pysubs2.SSAFile() for i, line in enumerate(lines): event = pysubs2.SSAEvent( start=i * 3000, end=i * 3000 + 2000, text=line, ) subs.events.append(event) return subs def test_watermark_removed(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["Downloaded from opensubtitles.org", "Hello world"]) changes = apply_common_fixes(subs, {"watermark_removal": True}) removed = [c for c in changes if c.modified_text == ""] assert len(removed) == 1 assert "opensubtitles" in removed[0].original_text def test_watermark_not_removed_when_disabled(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["Downloaded from opensubtitles.org"]) changes = apply_common_fixes(subs, {"watermark_removal": False}) assert not changes def test_em_dash_correction(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["Wait--I didn't know"]) changes = apply_common_fixes(subs, {"em_dash_correction": True}) assert changes assert "\u2014" in subs.events[0].text # em dash U+2014 assert "--" not in subs.events[0].text def test_quote_normalization(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["\u201cHello\u201d"]) # curly quotes changes = apply_common_fixes(subs, {"quote_normalization": True}) assert changes assert subs.events[0].text == '"Hello"' def test_crocodile_brackets_removed(): from common_fixes import apply_common_fixes subs = _subs_from_lines([">> Previously on..."]) changes = apply_common_fixes(subs, {"crocodile_brackets": True}) assert changes assert ">>" not in subs.events[0].text def test_multiple_spaces_collapsed(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["Hello world"]) changes = apply_common_fixes(subs, {"multiple_spaces": True}) assert changes assert subs.events[0].text == "Hello world" def test_apostrophe_normalization(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["He said ''hello''"]) changes = apply_common_fixes(subs, {"apostrophe_normalization": True}) assert changes assert "''" not in subs.events[0].text def test_fix_uppercase_detects_all_caps_file(): from common_fixes import apply_common_fixes lines = ["HELLO WORLD", "HOW ARE YOU", "I AM FINE", "YES REALLY"] subs = _subs_from_lines(lines) changes = apply_common_fixes(subs, {"fix_uppercase": True}) assert changes # conversion happened # Sentence case applied — "HELLO WORLD" → "Hello world" assert subs.events[0].text == "Hello world" def test_interpunction_spacing_removes_space_before_comma(): from common_fixes import apply_common_fixes subs = _subs_from_lines(["Wait , I need to think"]) changes = apply_common_fixes(subs, {"interpunction_spacing": True}) assert changes assert "Wait," in subs.events[0].text assert "Wait ," not in subs.events[0].text def test_long_line_wrap_splits_long_line(): import pysubs2 from common_fixes import apply_common_fixes long_text = ( "This is a very long subtitle line that should be wrapped at the configured character limit" ) subs = _subs_from_lines([long_text]) changes = apply_common_fixes(subs, {"long_line_wrap": True, "wrap_chars": 42}) # After wrapping the event text should be shorter per line lines = subs.events[0].text.split("\\N") # ASS linebreak or \n if len(lines) == 1: lines = subs.events[0].text.split("\n") assert len(lines) >= 2 or changes # either wrapped or recorded a change def test_short_line_merge_combines_adjacent_short_events(): import pysubs2 from common_fixes import apply_common_fixes subs = pysubs2.SSAFile() # Two very short adjacent events within 500ms of each other subs.events.append(pysubs2.SSAEvent(start=0, end=1000, text="Yes,")) subs.events.append(pysubs2.SSAEvent(start=1100, end=2000, text="right.")) changes = apply_common_fixes(subs, {"short_line_merge": True}) # Either merged into one event or no change if implementation skips — just must not crash assert isinstance(changes, list) def test_fix_uppercase_skips_mixed_case_file(): from common_fixes import apply_common_fixes lines = ["Hello world", "How are you", "I AM FINE"] subs = _subs_from_lines(lines) changes = apply_common_fixes(subs, {"fix_uppercase": True}) assert not changes # <60% uppercase — skip def test_overlap_fix_adjusts_end_time(): import pysubs2 from common_fixes import apply_common_fixes subs = pysubs2.SSAFile() # Event A ends at 2500ms, Event B starts at 2000ms — overlap subs.events.append(pysubs2.SSAEvent(start=0, end=2500, text="First")) subs.events.append(pysubs2.SSAEvent(start=2000, end=4000, text="Second")) changes = apply_common_fixes(subs, {"overlap_fix": True}) assert changes assert subs.events[0].end == 1999 # adjusted to start_of_next - 1ms def test_min_display_time_extends_short_event(): import pysubs2 from common_fixes import apply_common_fixes subs = pysubs2.SSAFile() # 300ms duration — below default 800ms minimum subs.events.append(pysubs2.SSAEvent(start=0, end=300, text="Hi")) changes = apply_common_fixes(subs, {"min_display_time": True, "min_ms": 800}) assert changes assert subs.events[0].end >= 800 def _overlapping_subs(): import pysubs2 subs = pysubs2.SSAFile() # Two karaoke syllables sharing a start, then a line that begins before they end. subs.events.append(pysubs2.SSAEvent(start=1000, end=4000, text="{\\k30}ko")) subs.events.append(pysubs2.SSAEvent(start=1000, end=4000, text="{\\k30}e")) subs.events.append(pysubs2.SSAEvent(start=2000, end=5000, text="Dialogue")) return subs @pytest.mark.parametrize("fmt", ["ass", "ssa"]) def test_overlap_fix_leaves_ass_timing_alone(fmt): """Overlaps in ASS are deliberate (karaoke, layered signs). Prod 2026-10-03: the overlap fix collapsed 4487 of 5557 events of a typeset release to zero duration — 515 sidecars in the library were hit. """ from common_fixes import apply_common_fixes subs = _overlapping_subs() apply_common_fixes(subs, {"overlap_fix": True}, fmt=fmt) assert [(e.start, e.end) for e in subs.events] == [(1000, 4000), (1000, 4000), (2000, 5000)] def test_overlap_fix_still_applies_to_srt(): from common_fixes import apply_common_fixes subs = _overlapping_subs() apply_common_fixes(subs, {"overlap_fix": True}, fmt="srt") assert subs.events[1].end == 1999