aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test_converter.py107
1 files changed, 106 insertions, 1 deletions
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: