"""Test module audio/general metadata extraction functions.""" import subprocess from types import SimpleNamespace from unittest.mock import patch from flexmock import flexmock import pytest from src import config from src import mediainfo_extractor def test_fixture_file_info(): """Extract and format data from real test file.""" wav_filename = 'tests/fixtures/1234567890_1_1.wav' expected_results = { 'bit_rate': 1411200, 'bits_per_sample': 16, 'channels': 2, 'codec': 'pcm', 'container': 'wave', 'duration_ms': 2963, 'file_size_bytes': 522796, 'mime_type': 'audio/vnd.wave', 'sample_rate': 44100 } results = mediainfo_extractor.get_audio_asset_media_info(wav_filename) assert expected_results == results def test_get_media_info(): """Test for successful parsing of info.""" mock_file_path = 'some/file/path.ext' binary_output = SimpleNamespace( stdout=b'{"abc": "xyz"}', stderr=b'' ) (flexmock(subprocess) .should_receive('run') .with_args( config.MEDIAINFO_CMD + [mock_file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) .and_return(binary_output)) result = mediainfo_extractor.get_media_info(mock_file_path) assert result == {'abc': 'xyz'} def test_get_media_info_stderr(): """Test for mediainfo stderr result.""" mock_file_path = 'some/file/path.general' binary_output = SimpleNamespace( stdout=b'', stderr=b'E: something_went_wrong' ) (flexmock(subprocess) .should_receive('run') .with_args( config.MEDIAINFO_CMD + [mock_file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) .and_return(binary_output)) with pytest.raises(Exception) as e: mediainfo_extractor.get_media_info(mock_file_path) assert str(e.value) == 'E: something_went_wrong' @patch('subprocess.run') def test_get_media_info_subprocess_failure(subprocess_mock): """Test get_media_info failure during subprocess call.""" # mocking mock_file_path = '/mock_path' mock_error_message = 'error' subprocess_mock.side_effect = OSError(mock_error_message) # test function call with pytest.raises(OSError) as e: mediainfo_extractor.get_media_info( mock_file_path) # checking subprocess_mock.assert_called_once_with([ config.MEDIAINFO_CMD, mock_file_path]) assert e.value.args[0] == mock_error_message def test_format_media_info(): """Test filter and format mediainfo data.""" raw_output = { 'media': { 'track': [ { '@type': 'Audio', 'Duration': '2.963', 'Channels': '2', 'Format': 'PCM', 'SamplingRate': '44100', 'BitDepth': '24', 'BitRate': '1411200', 'CodecID': '1' }, { '@type': 'General', 'Format': 'Wave', 'InternetMediaType': 'audio/vnd.wave', 'FileSize': '38144932', 'Title': 'SongName' }, { '@type': 'Extra', 'Data': 'xyz' } ] } } expected_output = { 'bit_rate': 1411200, 'bits_per_sample': 24, 'channels': 2, 'codec': 'pcm', 'container': 'wave', 'duration_ms': 2963, 'file_size_bytes': 38144932, 'mime_type': 'audio/vnd.wave', 'sample_rate': 44100 } assert mediainfo_extractor.format_media_info(raw_output) == expected_output def test_format_media_info_missing(): """Test graceful handling of missing data.""" raw_output = { 'media': { 'track': [] } } expected_output = { 'bit_rate': None, 'bits_per_sample': None, 'channels': None, 'codec': None, 'container': None, 'duration_ms': None, 'file_size_bytes': None, 'mime_type': None, 'sample_rate': None } assert mediainfo_extractor.format_media_info(raw_output) == expected_output def test_format_media_info_duration_int(): """Test case of duration math producing non-int.""" raw_output = { 'media': { 'track': [ { '@type': 'Audio', '@typeorder': '1', 'Duration': '129.698', 'Channels': '2', 'Format': 'PCM', 'SamplingRate': '44100', 'BitDepth': '24', 'BitRate': '1411200' }, { '@type': 'General', 'Format': 'Wave', 'InternetMediaType': 'audio/vnd.wave', 'FileSize': '38144932' } ] } } expected_output = { 'bit_rate': 1411200, 'bits_per_sample': 24, 'channels': 2, 'codec': 'pcm', 'container': 'wave', 'duration_ms': 129699, 'file_size_bytes': 38144932, 'mime_type': 'audio/vnd.wave', 'sample_rate': 44100 } assert mediainfo_extractor.format_media_info(raw_output) == expected_output def test_format_media_info_multiple_tracks(): """Test filter and format of mediainfo data with multiple tracks.""" raw_output = { 'media': { 'track': [ { '@type': 'Audio', '@typeorder': '1', 'Duration': '2.963', 'Channels': '2', 'Format': 'PCM', 'SamplingRate': '44100', 'BitDepth': '24', 'BitRate': '1411200' }, { '@type': 'Audio', '@typeorder': '2', 'Duration': '3.963', 'Channels': '3', 'Format': 'PCN', 'SamplingRate': '44101', 'BitDepth': '25', 'BitRate': '1411201' }, { '@type': 'General', 'Format': 'Wave', 'InternetMediaType': 'audio/vnd.wave', 'FileSize': '38144932' } ] } } expected_output = { 'bit_rate': 1411200, 'bits_per_sample': 24, 'channels': 2, 'codec': 'pcm', 'container': 'wave', 'duration_ms': 2963, 'file_size_bytes': 38144932, 'mime_type': 'audio/vnd.wave', 'sample_rate': 44100 } assert mediainfo_extractor.format_media_info(raw_output) == expected_output @pytest.mark.parametrize( 'key, data, expected_output', [ ('bits_per_sample', '', None), ('duration', '2963 / 2742', 2963), ('duration', '123.456', 123.456), ('duration', '123.00', 123), ('blerg', '123', '123') ] ) def test_type_cast(key, data, expected_output): """Test type casting edge cases.""" assert mediainfo_extractor.type_cast(key, data) == expected_output