backend/tests/test_common_fixes_extended.py
Rama master · réplica de lectura del repositorio original.
# 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