From 9d4d7ef806c17387af9778725cd65a5e7ed10e39 Mon Sep 17 00:00:00 2001 From: historia Date: Wed, 19 Aug 2026 04:45:28 -0400 Subject: fix: limit chunk size to 250 --- tests/test_audio.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'tests/test_audio.py') diff --git a/tests/test_audio.py b/tests/test_audio.py index fb448f8..c043766 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -1,9 +1,11 @@ """Tests for audio helpers: speed parameters, chunk cleanup, encoding, -command construction, and duration verification.""" +command construction, duration verification, and audio concatenation.""" import tempfile import unittest +import wave from pathlib import Path +from unittest.mock import patch from converter import audio from converter import config @@ -17,6 +19,7 @@ from converter.audio import ( build_ffmetadata, build_m4b_chapters_command, cleanup_chunks, + concat_audio_files, speed_export_params, verify_output_duration, ) @@ -422,5 +425,67 @@ class BuildM4bChaptersCommandMetaTests(unittest.TestCase): self.assertNotIn("-metadata", cmd) +class ConcatAudioFilesTests(unittest.TestCase): + """Concatenation of sub-request audio into one chunk file.""" + + @staticmethod + def _write_wav(path: Path, frames: bytes, framerate: int = 24000) -> Path: + with wave.open(str(path), "wb") as wav_file: + wav_file.setnchannels(1) + wav_file.setsampwidth(2) + wav_file.setframerate(framerate) + wav_file.writeframes(frames) + return path + + def test_wav_files_are_merged_in_order(self): + with tempfile.TemporaryDirectory() as tmp: + first = self._write_wav(Path(tmp) / "a.wav", b"\x01\x00" * 10) + second = self._write_wav(Path(tmp) / "b.wav", b"\x02\x00" * 20) + destination = Path(tmp) / "out.wav" + concat_audio_files([first, second], destination) + with wave.open(str(destination), "rb") as wav_file: + self.assertEqual(wav_file.getframerate(), 24000) + self.assertEqual(wav_file.getnchannels(), 1) + self.assertEqual(wav_file.getsampwidth(), 2) + frames = wav_file.readframes(wav_file.getnframes()) + self.assertEqual(frames, b"\x01\x00" * 10 + b"\x02\x00" * 20) + + def test_single_wav_file_is_copied(self): + with tempfile.TemporaryDirectory() as tmp: + source = self._write_wav(Path(tmp) / "a.wav", b"\x03\x00" * 15) + destination = Path(tmp) / "out.wav" + concat_audio_files([source], destination) + with wave.open(str(destination), "rb") as wav_file: + self.assertEqual(wav_file.readframes(wav_file.getnframes()), + b"\x03\x00" * 15) + + def test_empty_source_list_raises(self): + with tempfile.TemporaryDirectory() as tmp: + with self.assertRaises(ValueError): + concat_audio_files([], Path(tmp) / "out.wav") + + def test_mismatched_wav_parameters_fall_back_to_ffmpeg(self): + with tempfile.TemporaryDirectory() as tmp: + first = self._write_wav(Path(tmp) / "a.wav", b"\x01\x00" * 10, framerate=24000) + second = self._write_wav(Path(tmp) / "b.wav", b"\x02\x00" * 10, framerate=16000) + destination = Path(tmp) / "out.wav" + with patch("converter.audio.shutil.which", return_value=None), \ + self.assertRaises(RuntimeError) as ctx: + concat_audio_files([first, second], destination) + self.assertIn("ffmpeg", str(ctx.exception)) + # The wave-module path must not have written a partial output. + self.assertFalse(destination.exists()) + + def test_non_wav_input_falls_back_to_ffmpeg(self): + with tempfile.TemporaryDirectory() as tmp: + source = Path(tmp) / "part.mp3" + source.write_bytes(b"not a wav file") + destination = Path(tmp) / "out.wav" + with patch("converter.audio.shutil.which", return_value=None), \ + self.assertRaises(RuntimeError) as ctx: + concat_audio_files([source], destination) + self.assertIn("ffmpeg", str(ctx.exception)) + + if __name__ == "__main__": unittest.main() -- cgit v1.2.3