Skip to main content
Glama
test_audio_processor.py10.6 kB
"""Test audio processor domain logic.""" from pathlib import Path from unittest.mock import MagicMock, patch import pytest from mcp_server_whisper.domain.audio_processor import AudioProcessor from mcp_server_whisper.exceptions import AudioCompressionError, AudioConversionError class TestAudioProcessor: """Test suite for AudioProcessor domain logic.""" def test_calculate_compression_needed_below_threshold(self) -> None: """Test that files below threshold don't need compression.""" file_size = 20 * 1024 * 1024 # 20 MB result = AudioProcessor.calculate_compression_needed(file_size, max_mb=25) assert result is False def test_calculate_compression_needed_at_threshold(self) -> None: """Test that files exactly at threshold don't need compression.""" file_size = 25 * 1024 * 1024 # Exactly 25 MB result = AudioProcessor.calculate_compression_needed(file_size, max_mb=25) assert result is False def test_calculate_compression_needed_above_threshold(self) -> None: """Test that files above threshold need compression.""" file_size = 30 * 1024 * 1024 # 30 MB result = AudioProcessor.calculate_compression_needed(file_size, max_mb=25) assert result is True def test_calculate_compression_needed_custom_threshold(self) -> None: """Test compression calculation with custom threshold.""" file_size = 15 * 1024 * 1024 # 15 MB result = AudioProcessor.calculate_compression_needed(file_size, max_mb=10) assert result is True def test_generate_output_path_with_custom_path(self, tmp_path: Path) -> None: """Test generating output path when custom path is provided.""" input_path = tmp_path / "input.mp3" custom_path = tmp_path / "custom_output.mp3" result = AudioProcessor.generate_output_path( input_path=input_path, output_path=custom_path, suffix="compressed", extension=".mp3" ) assert result == custom_path def test_generate_output_path_with_suffix(self, tmp_path: Path) -> None: """Test generating output path with suffix.""" input_path = tmp_path / "audio.mp3" result = AudioProcessor.generate_output_path( input_path=input_path, output_path=None, suffix="compressed", extension=".mp3" ) assert result == tmp_path / "compressed_audio.mp3" def test_generate_output_path_without_suffix(self, tmp_path: Path) -> None: """Test generating output path without suffix (extension change only).""" input_path = tmp_path / "audio.mp3" result = AudioProcessor.generate_output_path( input_path=input_path, output_path=None, suffix="", extension=".wav" ) assert result == tmp_path / "audio.wav" def test_generate_output_path_preserves_parent_directory(self, tmp_path: Path) -> None: """Test that generated path stays in same parent directory.""" parent = tmp_path / "audio_files" parent.mkdir() input_path = parent / "test.mp3" result = AudioProcessor.generate_output_path( input_path=input_path, output_path=None, suffix="converted", extension=".wav" ) assert result.parent == parent assert result == parent / "converted_test.wav" @pytest.mark.anyio async def test_load_audio_from_path_success(self, tmp_path: Path) -> None: """Test successfully loading audio from path.""" test_file = tmp_path / "test.mp3" test_file.write_bytes(b"fake audio data") mock_audio = MagicMock() with patch( "mcp_server_whisper.domain.audio_processor.AudioSegment.from_file", return_value=mock_audio ) as mock_from_file: result = await AudioProcessor.load_audio_from_path(test_file) assert result == mock_audio mock_from_file.assert_called_once() # Check that format was extracted from file extension call_args = mock_from_file.call_args assert call_args[0][0] == str(test_file) assert call_args[1]["format"] == "mp3" @pytest.mark.anyio async def test_load_audio_from_path_failure(self, tmp_path: Path) -> None: """Test error handling when loading audio fails.""" test_file = tmp_path / "invalid.mp3" test_file.write_bytes(b"not audio") with patch( "mcp_server_whisper.domain.audio_processor.AudioSegment.from_file", side_effect=Exception("Invalid audio") ): with pytest.raises(AudioConversionError, match="Failed to load audio file"): await AudioProcessor.load_audio_from_path(test_file) @pytest.mark.anyio async def test_convert_audio_format_success(self, tmp_path: Path) -> None: """Test successfully converting audio format.""" mock_audio = MagicMock() mock_export = MagicMock() mock_audio.export = mock_export output_path = tmp_path / "output.wav" test_data = b"converted audio data" output_path.write_bytes(test_data) result = await AudioProcessor.convert_audio_format(mock_audio, "wav", output_path) assert result == test_data mock_export.assert_called_once() call_args = mock_export.call_args assert call_args[0][0] == str(output_path) assert call_args[1]["format"] == "wav" @pytest.mark.anyio async def test_convert_audio_format_failure(self, tmp_path: Path) -> None: """Test error handling when conversion fails.""" mock_audio = MagicMock() mock_audio.export = MagicMock(side_effect=Exception("Conversion failed")) output_path = tmp_path / "output.mp3" with pytest.raises(AudioConversionError, match="Audio conversion to mp3 failed"): await AudioProcessor.convert_audio_format(mock_audio, "mp3", output_path) @pytest.mark.anyio async def test_compress_mp3_success(self, tmp_path: Path) -> None: """Test successfully compressing MP3.""" mock_audio = MagicMock() mock_audio.frame_rate = 44100 mock_export = MagicMock() mock_audio.export = mock_export output_path = tmp_path / "compressed.mp3" test_data = b"compressed audio" output_path.write_bytes(test_data) result = await AudioProcessor.compress_mp3(mock_audio, output_path, target_sample_rate=22050) assert result == test_data mock_export.assert_called_once() call_args = mock_export.call_args assert call_args[0][0] == str(output_path) assert call_args[1]["format"] == "mp3" assert call_args[1]["parameters"] == ["-ar", "22050"] @pytest.mark.anyio async def test_compress_mp3_failure(self, tmp_path: Path) -> None: """Test error handling when compression fails.""" mock_audio = MagicMock() mock_audio.frame_rate = 44100 mock_audio.export = MagicMock(side_effect=Exception("Compression failed")) output_path = tmp_path / "compressed.mp3" with pytest.raises(AudioCompressionError, match="MP3 compression failed"): await AudioProcessor.compress_mp3(mock_audio, output_path) @pytest.mark.anyio async def test_concatenate_audio_segments_mp3(self) -> None: """Test concatenating multiple MP3 audio segments.""" chunk1 = b"chunk1 data" chunk2 = b"chunk2 data" mock_segment = MagicMock() mock_output = b"concatenated audio" with ( patch("mcp_server_whisper.domain.audio_processor.AudioSegment.from_mp3") as mock_from_mp3, patch("mcp_server_whisper.domain.audio_processor.AudioSegment.empty") as mock_empty, ): # Return same mock for simplicity mock_empty.return_value = mock_segment mock_from_mp3.return_value = mock_segment # Mock += operation mock_segment.__iadd__ = MagicMock(return_value=mock_segment) # Mock the export def mock_export(output, format): output.write(mock_output) return None mock_segment.export = mock_export result = await AudioProcessor.concatenate_audio_segments([chunk1, chunk2], format="mp3") assert result == mock_output assert mock_from_mp3.call_count == 2 @pytest.mark.anyio async def test_concatenate_audio_segments_wav(self) -> None: """Test concatenating WAV audio segments.""" chunks = [b"chunk1", b"chunk2"] mock_segment = MagicMock() mock_output = b"concatenated wav" with ( patch("mcp_server_whisper.domain.audio_processor.AudioSegment.from_wav") as mock_from_wav, patch("mcp_server_whisper.domain.audio_processor.AudioSegment.empty") as mock_empty, ): mock_empty.return_value = mock_segment mock_from_wav.return_value = mock_segment # Mock += operation mock_segment.__iadd__ = MagicMock(return_value=mock_segment) def mock_export(output, format): output.write(mock_output) return None mock_segment.export = mock_export result = await AudioProcessor.concatenate_audio_segments(chunks, format="wav") assert result == mock_output assert mock_from_wav.call_count == 2 @pytest.mark.anyio async def test_concatenate_audio_segments_failure(self) -> None: """Test error handling when concatenation fails.""" chunks = [b"chunk1"] with patch( "mcp_server_whisper.domain.audio_processor.AudioSegment.empty", side_effect=Exception("Concat failed") ): with pytest.raises(AudioConversionError, match="Audio concatenation failed"): await AudioProcessor.concatenate_audio_segments(chunks) @pytest.mark.anyio async def test_concatenate_audio_segments_empty_list(self) -> None: """Test concatenating empty list of chunks.""" mock_combined = MagicMock() mock_output = b"empty" with patch("mcp_server_whisper.domain.audio_processor.AudioSegment.empty") as mock_empty: mock_empty.return_value = mock_combined def mock_export(output, format): output.write(mock_output) return None mock_combined.export = mock_export result = await AudioProcessor.concatenate_audio_segments([]) assert result == mock_output

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arcaputo3/mcp-server-whisper'

If you have feedback or need assistance with the MCP directory API, please join our Discord server