diff options
| -rw-r--r-- | tests/test_audio.py | 58 | ||||
| -rw-r--r-- | tests/test_converter.py | 14 |
2 files changed, 72 insertions, 0 deletions
diff --git a/tests/test_audio.py b/tests/test_audio.py index f36ed54..7e782cc 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -8,6 +8,7 @@ from pathlib import Path from converter import audio from converter import config from converter.audio import ( + _collect_chunk_files, _encode_args, build_concat_command, build_ffmetadata, @@ -142,6 +143,43 @@ class BuildConcatCommandTests(unittest.TestCase): self.assertIn("pcm_s16le", cmd) self.assertNotIn("-movflags", cmd) + def test_speed_without_speed_path_rejected(self): + with self.assertRaises(ValueError): + build_concat_command(Path("list.txt"), Path("out.mp3"), "mp3", speed=1.5) + + +class CollectChunkFilesTests(unittest.TestCase): + def test_uses_recorded_paths_exactly(self): + with tempfile.TemporaryDirectory() as tmp: + present = Path(tmp) / "chunk_0001.wav" + present.write_bytes(b"audio") + chunk_results = { + 1: present, + 2: None, # failed chunk + 3: Path(tmp) / "chunk_0003.wav", # recorded but deleted + } + files, missing = _collect_chunk_files(3, chunk_results) + + self.assertEqual(files, [present]) + self.assertEqual(missing, [2, 3]) + + def test_glob_fallback_without_results(self): + with tempfile.TemporaryDirectory() as tmp: + chunks_dir = Path(tmp) + (chunks_dir / "chunk_0002.wav").write_bytes(b"audio") + (chunks_dir / "chunk_0001.wav").write_bytes(b"audio") + + original = config.CHUNKS_FOLDER + config.CHUNKS_FOLDER = chunks_dir + try: + files, missing = _collect_chunk_files(3) + finally: + config.CHUNKS_FOLDER = original + + self.assertEqual(files, [chunks_dir / "chunk_0001.wav", + chunks_dir / "chunk_0002.wav"]) + self.assertEqual(missing, [3]) + class BuildM4bChaptersCommandTests(unittest.TestCase): def setUp(self): @@ -222,6 +260,26 @@ class BuildFFMetadataTests(unittest.TestCase): self.assertIn("START=1200", content) self.assertIn("title=Two", content) + def test_escapes_special_characters(self): + # ffmpeg's FFMETADATA format treats = ; # and \ as structural. + chapters = [(0, 1000, "A = B; C# D\\E")] + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "meta.txt" + build_ffmetadata(chapters, path) + content = path.read_text(encoding="utf-8") + + self.assertIn(r"title=A \= B\; C\# D\\E", content) + + def test_collapses_newlines_in_titles(self): + chapters = [(0, 1000, "Two\nLines")] + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "meta.txt" + build_ffmetadata(chapters, path) + content = path.read_text(encoding="utf-8") + + self.assertIn("title=Two Lines\n", content) + self.assertNotIn("title=Two\n", content) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_converter.py b/tests/test_converter.py index 1235dda..9c03e30 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -17,5 +17,19 @@ class SanitizeFilenameTests(unittest.TestCase): self.assertEqual(AudiobookConverter._sanitize_filename("///"), "chapter") +class ConfigurationValidationTests(unittest.TestCase): + def test_invalid_voice_mode_rejected(self): + with self.assertRaises(ValueError): + AudiobookConverter(voice_mode="custon_voice") + + def test_nonpositive_speed_rejected(self): + with self.assertRaises(ValueError): + AudiobookConverter(speed=0) + + def test_unknown_format_rejected(self): + with self.assertRaises(ValueError): + AudiobookConverter(output_format="ogg") + + if __name__ == "__main__": unittest.main() |
