From 24cb17a35ebaf5829cefa943c5a528d4accd7dfc Mon Sep 17 00:00:00 2001 From: historia Date: Wed, 19 Aug 2026 02:44:04 -0400 Subject: feat: --debug flag --- tests/test_converter.py | 107 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test_converter.py b/tests/test_converter.py index 48dc162..707688e 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -3,7 +3,7 @@ import tempfile import unittest from pathlib import Path -from unittest.mock import patch +from unittest.mock import MagicMock, patch from converter import config from converter.converter import AudiobookConverter, find_existing_outputs, prompt_overwrite @@ -144,6 +144,110 @@ class NarratorTagTests(unittest.TestCase): "narrator") +class ChapterDebugDirTests(unittest.TestCase): + """Per-chapter debug subfolder naming (chunk numbering restarts per chapter).""" + + def test_none_when_not_debugging(self): + self.assertIsNone(AudiobookConverter._chapter_debug_dir(None, 3, "The Trial")) + + def test_chapter_subfolder_named_by_index_and_title(self): + book_dir = Path("debug") / "dune_Vivian" + chapter_dir = AudiobookConverter._chapter_debug_dir(book_dir, 3, "The Trial") + self.assertEqual(chapter_dir, book_dir / "03_The Trial") + + def test_untitled_chapter_uses_fallback(self): + chapter_dir = AudiobookConverter._chapter_debug_dir(Path("d"), 1, "") + self.assertEqual(chapter_dir, Path("d") / "01_chapter") + + +class DebugDumpTests(unittest.TestCase): + """--debug: per-chunk text/audio dumps and request/response logging.""" + + def setUp(self): + self._tmp = tempfile.TemporaryDirectory() + self._debug_folder = patch.object(config, "DEBUG_FOLDER", Path(self._tmp.name)) + self._debug_folder.start() + self.debug_root = Path(self._tmp.name) + self.converter = AudiobookConverter.__new__(AudiobookConverter) + self.converter.tts = MagicMock() + + def tearDown(self): + self._debug_folder.stop() + self._tmp.cleanup() + + def _chunk_source(self, name, body=b"audio"): + path = self.debug_root / "sources" / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(body) + return path + + def test_successful_chunk_dumps_text_and_audio(self): + audio = self._chunk_source("chunk_0001.wav") + self.converter.tts.process_chunk_with_retry.return_value = audio + results = self.converter._synthesize_chunks(["Hello world."], + debug_dir=self.debug_root / "book") + self.assertEqual(results, {1: audio}) + debug_dir = self.debug_root / "book" + self.assertEqual((debug_dir / "chunk_0001.txt").read_text(encoding="utf-8"), + "Hello world.") + self.assertEqual((debug_dir / "chunk_0001.wav").read_bytes(), b"audio") + + def test_failed_chunk_dumps_text_but_no_audio(self): + self.converter.tts.process_chunk_with_retry.return_value = None + results = self.converter._synthesize_chunks(["Hello again."], + debug_dir=self.debug_root / "book") + self.assertEqual(results, {1: None}) + debug_dir = self.debug_root / "book" + self.assertEqual([path.name for path in sorted(debug_dir.iterdir())], + ["chunk_0001.txt"]) + + def test_text_dumped_even_when_request_raises(self): + self.converter.tts.process_chunk_with_retry.side_effect = RuntimeError("boom") + results = self.converter._synthesize_chunks(["Crash text."], + debug_dir=self.debug_root / "book") + self.assertEqual(results, {1: None}) + self.assertEqual((self.debug_root / "book" / "chunk_0001.txt").read_text( + encoding="utf-8"), "Crash text.") + + def test_audio_suffix_preserved_and_nested_dirs_created(self): + audio = self._chunk_source("generated.mp3") + self.converter.tts.process_chunk_with_retry.return_value = audio + self.converter._synthesize_chunks(["Hello."], + debug_dir=self.debug_root / "nested" / "book") + self.assertTrue((self.debug_root / "nested" / "book" / "chunk_0001.mp3").exists()) + + def test_no_debug_dir_writes_nothing(self): + audio = self._chunk_source("chunk_0001.wav") + self.converter.tts.process_chunk_with_retry.return_value = audio + results = self.converter._synthesize_chunks(["Hello world."]) + self.assertEqual(results, {1: audio}) + self.assertEqual([path.name for path in self.debug_root.iterdir()], ["sources"]) + + def test_request_and_response_are_logged(self): + audio = self._chunk_source("chunk_0001.wav") + self.converter.tts.process_chunk_with_retry.return_value = audio + with self.assertLogs("converter.converter", level="DEBUG") as logs: + self.converter._synthesize_chunks(["Hello world."], + debug_dir=self.debug_root / "book") + joined = "\n".join(logs.output) + self.assertIn("Chunk 1/1 request text: Hello world.", joined) + self.assertIn("Chunk 1/1 response in", joined) + self.assertIn("chunk_0001.wav", joined) + + def test_debug_write_failure_does_not_abort_conversion(self): + blocker = self.debug_root / "blocker" + blocker.write_bytes(b"") + audio = self._chunk_source("chunk_0001.wav") + self.converter.tts.process_chunk_with_retry.return_value = audio + results = self.converter._synthesize_chunks(["Hello."], debug_dir=blocker / "book") + self.assertEqual(results, {1: audio}) + + def test_debug_flag_wiring(self): + with patch("converter.converter.QwenTTSClient"): + self.assertFalse(AudiobookConverter().debug) + self.assertTrue(AudiobookConverter(debug=True).debug) + + class PromptOverwriteTests(unittest.TestCase): def test_single_file_yes(self): with patch("builtins.input", return_value="y"): @@ -197,6 +301,7 @@ class RunOverwritePromptTests(unittest.TestCase): self.converter.single_file = False self.converter.output_format = "mp3" self.converter.language = "English" + self.converter.debug = False self.converted = [] self.converter.convert_book = ( lambda file_path, output_name=None: -- cgit v1.2.3