#!/usr/bin/env python3 import contextlib import importlib.util import io import pathlib import tempfile import unittest from unittest import mock _SCRIPT_PATH = pathlib.Path(__file__).with_name("offset-fixer.py") _SPEC = importlib.util.spec_from_file_location("offset_fixer", _SCRIPT_PATH) mod = importlib.util.module_from_spec(_SPEC) assert _SPEC and _SPEC.loader _SPEC.loader.exec_module(mod) class OffsetFixerTest(unittest.TestCase): def test_format_time_string(self) -> None: entry = mod.SubtitleEntry(1, "hello\n", "01:02:03,250", "01:02:04,500") self.assertEqual( "01:02:03,250 --> 01:02:04,500", entry.formatTimeString(), ) def test_shift_updates_start_and_end(self) -> None: entry = mod.SubtitleEntry(1, "hello\n", "00:00:10,000", "00:00:12,500") entry.shift(1.25) self.assertEqual( "00:00:11,250 --> 00:00:13,750", entry.formatTimeString(), ) def test_main_writes_shifted_output(self) -> None: srt = ( "1\n" "00:00:01,000 --> 00:00:02,000\n" "Hello\n" "\n" "2\n" "00:00:03,500 --> 00:00:04,250\n" "Bye\n" "\n" ) with tempfile.TemporaryDirectory() as td: in_path = pathlib.Path(td) / "input.srt" out_path = pathlib.Path(td) / "output.srt" in_path.write_text(srt, encoding="utf-8") argv = [ "offset-fixer.py", "--seconds", "1.5", "--file", str(in_path), "--outfile", str(out_path), ] with mock.patch("sys.argv", argv), contextlib.redirect_stdout(io.StringIO()): mod.main() output = out_path.read_text(encoding="utf-8") self.assertIn("00:00:02,500 --> 00:00:03,500", output) self.assertIn("00:00:05,000 --> 00:00:05,750", output) self.assertIn("Hello", output) self.assertIn("Bye", output) def test_main_strip_first_and_last(self) -> None: srt = ( "1\n" "00:00:01,000 --> 00:00:02,000\n" "First subtitle\n" "\n" "2\n" "00:00:03,000 --> 00:00:04,000\n" "Last subtitle\n" "\n" ) with tempfile.TemporaryDirectory() as td: in_path = pathlib.Path(td) / "input.srt" out_path = pathlib.Path(td) / "output.srt" in_path.write_text(srt, encoding="utf-8") argv = [ "offset-fixer.py", "--seconds", "0", "--file", str(in_path), "--outfile", str(out_path), "--strip-first", "--strip-last", ] with mock.patch("sys.argv", argv), contextlib.redirect_stdout(io.StringIO()): mod.main() output = out_path.read_text(encoding="utf-8") self.assertNotIn("First subtitle", output) self.assertNotIn("Last subtitle", output) self.assertIn("00:00:01,000 --> 00:00:02,000", output) self.assertIn("00:00:03,000 --> 00:00:04,000", output) def test_main_inplace_creates_backup_and_updates_source(self) -> None: srt = ( "1\n" "00:00:01,000 --> 00:00:02,000\n" "Keep me\n" "\n" ) with tempfile.TemporaryDirectory() as td: in_path = pathlib.Path(td) / "input.srt" in_path.write_text(srt, encoding="utf-8") argv = [ "offset-fixer.py", "--seconds", "0.5", "--file", str(in_path), "--inplace", ] with mock.patch("sys.argv", argv), contextlib.redirect_stdout(io.StringIO()): mod.main() backup_text = (pathlib.Path(str(in_path) + ".backup")).read_text(encoding="utf-8") updated_text = in_path.read_text(encoding="utf-8") self.assertIn("00:00:01,000 --> 00:00:02,000", backup_text) self.assertIn("00:00:01,500 --> 00:00:02,500", updated_text) self.assertIn("Keep me", updated_text) def test_main_inplace_rejects_outfile(self) -> None: srt = ( "1\n" "00:00:01,000 --> 00:00:02,000\n" "Hello\n" "\n" ) with tempfile.TemporaryDirectory() as td: in_path = pathlib.Path(td) / "input.srt" out_path = pathlib.Path(td) / "output.srt" in_path.write_text(srt, encoding="utf-8") argv = [ "offset-fixer.py", "--seconds", "1", "--file", str(in_path), "--inplace", "--outfile", str(out_path), ] with mock.patch("sys.argv", argv), contextlib.redirect_stdout(io.StringIO()): with self.assertRaises(SystemExit) as exc: mod.main() self.assertEqual(1, exc.exception.code) if __name__ == "__main__": unittest.main()