From f09088df4355888641189f7019091a4d74b17bf7 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Wed, 1 May 2019 17:53:03 +0100 Subject: [PATCH] replaygain: Handle invalid XML output from bs1770gain --- beetsplug/replaygain.py | 9 +++++- test/test_replaygain.py | 62 ++++++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/beetsplug/replaygain.py b/beetsplug/replaygain.py index 4168c61b99..4a0ea064f1 100644 --- a/beetsplug/replaygain.py +++ b/beetsplug/replaygain.py @@ -251,7 +251,14 @@ def end_element_handler(name): state['gain'] = state['peak'] = None parser.StartElementHandler = start_element_handler parser.EndElementHandler = end_element_handler - parser.Parse(text, True) + + try: + parser.Parse(text, True) + except xml.parsers.expat.ExpatError: + raise ReplayGainError( + u'The bs1770gain tool produced malformed XML. ' + 'Using version >=0.4.10 may solve this problem.' + ) if len(per_file_gain) != len(path_list): raise ReplayGainError( diff --git a/test/test_replaygain.py b/test/test_replaygain.py index 6ddee54dac..f750f3012f 100644 --- a/test/test_replaygain.py +++ b/test/test_replaygain.py @@ -19,7 +19,8 @@ import unittest import six -from test.helper import TestHelper, has_program +from mock import patch +from test.helper import TestHelper, capture_log, has_program from beets import config from beets.mediafile import MediaFile @@ -44,6 +45,15 @@ LOUDNESS_PROG_AVAILABLE = False +def reset_replaygain(item): + item['rg_track_peak'] = None + item['rg_track_gain'] = None + item['rg_album_gain'] = None + item['rg_album_gain'] = None + item.write() + item.store() + + class ReplayGainCliTestBase(TestHelper): def setUp(self): @@ -68,20 +78,12 @@ def setUp(self): album = self.add_album_fixture(2) for item in album.items(): - self._reset_replaygain(item) + reset_replaygain(item) def tearDown(self): self.teardown_beets() self.unload_plugins() - def _reset_replaygain(self, item): - item['rg_track_peak'] = None - item['rg_track_gain'] = None - item['rg_album_gain'] = None - item['rg_album_gain'] = None - item.write() - item.store() - def test_cli_saves_track_gain(self): for item in self.lib.items(): self.assertIsNone(item.rg_track_peak) @@ -166,6 +168,46 @@ class ReplayGainLdnsCliTest(ReplayGainCliTestBase, unittest.TestCase): backend = u'bs1770gain' +class ReplayGainLdnsCliMalformedTest(TestHelper, unittest.TestCase): + + @patch('beetsplug.replaygain.call') + def setUp(self, call_patch): + self.setup_beets() + self.config['replaygain']['backend'] = 'bs1770gain' + + # Patch call to return nothing, bypassing the bs1770gain installation + # check. + call_patch.return_value = None + self.load_plugins('replaygain') + + for item in self.add_album_fixture(2).items(): + reset_replaygain(item) + + @patch('beetsplug.replaygain.call') + def test_malformed_output(self, call_patch): + # Return malformed XML (the ampersand should be &) + call_patch.return_value = """ + + + + + + + """ + + with capture_log('beets.replaygain') as logs: + self.run_command('replaygain') + + # Count how many lines match the expected error. + matching = [line for line in logs if + line == 'replaygain: ReplayGain error: bs1770gain ' + 'returned malformed XML - this is a bug in ' + 'versions prior to v0.4.10, please ensure that ' + 'your version is up to date'] + + self.assertEqual(len(matching), 2) + + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)