diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 1053602c8..fc1798445 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -13,6 +13,7 @@ # included in all copies or substantial portions of the Software. import codecs +from typing import ClassVar from unittest.mock import patch from beets.dbcore.query import TrueQuery @@ -20,8 +21,9 @@ from beets.library import Item from beets.test import _common from beets.test.helper import ( AutotagStub, + BeetsTestCase, ImportTestCase, - PluginTestCase, + PluginMixin, TerminalImportMixin, control_stdin, ) @@ -72,7 +74,7 @@ class ModifyFileMocker: f.write(contents) -class EditMixin(PluginTestCase): +class EditMixin(PluginMixin): """Helper containing some common functionality used for the Edit tests.""" plugin = "edit" @@ -116,7 +118,7 @@ class EditMixin(PluginTestCase): @_common.slow_test() @patch("beets.library.Item.write") -class EditCommandTest(EditMixin): +class EditCommandTest(EditMixin, BeetsTestCase): """Black box tests for `beetsplug.edit`. Command line interaction is simulated using `test.helper.control_stdin()`, and yaml editing via an external editor is simulated using `ModifyFileMocker`. @@ -327,11 +329,13 @@ class EditDuringImporterTestCase( """TODO""" IGNORED = ["added", "album_id", "id", "mtime", "path"] + singletons: ClassVar[bool] def setUp(self): super().setUp() # Create some mediafiles, and store them for comparison. self.prepare_album_for_import() + self._setup_import_session(singletons=self.singletons) self.items_orig = [Item.from_path(f.path) for f in self.import_media] self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.GOOD @@ -342,11 +346,15 @@ class EditDuringImporterTestCase( super().tearDown() self.matcher.restore() + +@_common.slow_test() +class EditDuringImporterNonSingletonTest(EditDuringImporterTestCase): + singletons = False + def test_edit_apply_asis(self): """Edit the album field for all items in the library, apply changes, using the original item tags. """ - self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, @@ -377,7 +385,6 @@ class EditDuringImporterTestCase( """Edit the album field for all items in the library, discard changes, using the original item tags. """ - self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, @@ -401,7 +408,6 @@ class EditDuringImporterTestCase( """Edit the album field for all items in the library, apply changes, using a candidate. """ - self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Applied Track": "Edited Track"}}, @@ -423,7 +429,6 @@ class EditDuringImporterTestCase( """Import the album using a candidate, then retag and edit and apply changes. """ - self._setup_import_session() self.run_mocked_interpreter( {}, # 1, Apply changes. @@ -454,7 +459,6 @@ class EditDuringImporterTestCase( """Edit the album field for all items in the library, discard changes, using a candidate. """ - self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Applied Track": "Edited Track"}}, @@ -472,11 +476,33 @@ class EditDuringImporterTestCase( # Ensure album is fetched from a candidate. self.assertIn("albumid", self.lib.albums()[0].mb_albumid) + def test_edit_apply_candidate_singleton(self): + """Edit the album field for all items in the library, apply changes, + using a candidate and singleton mode. + """ + # Edit track titles. + self.run_mocked_interpreter( + {"replacements": {"Applied Track": "Edited Track"}}, + # edit Candidates, 1, Apply changes, aBort. + ["c", "1", "a", "b"], + ) + + # Check that 'title' field is modified, and other fields come from + # the candidate. + self.assertTrue( + all("Edited Track " in i.title for i in self.lib.items()) + ) + self.assertTrue(all("match " in i.mb_trackid for i in self.lib.items())) + + +@_common.slow_test() +class EditDuringImporterSingletonTest(EditDuringImporterTestCase): + singletons = True + def test_edit_apply_asis_singleton(self): """Edit the album field for all items in the library, apply changes, using the original item tags and singleton mode. """ - self._setup_import_session(singletons=True) # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, @@ -494,22 +520,3 @@ class EditDuringImporterTestCase( self.assertTrue( all("Edited Track" in i.title for i in self.lib.items()) ) - - def test_edit_apply_candidate_singleton(self): - """Edit the album field for all items in the library, apply changes, - using a candidate and singleton mode. - """ - self._setup_import_session() - # Edit track titles. - self.run_mocked_interpreter( - {"replacements": {"Applied Track": "Edited Track"}}, - # edit Candidates, 1, Apply changes, aBort. - ["c", "1", "a", "b"], - ) - - # Check that 'title' field is modified, and other fields come from - # the candidate. - self.assertTrue( - all("Edited Track " in i.title for i in self.lib.items()) - ) - self.assertTrue(all("match " in i.mb_trackid for i in self.lib.items())) diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index f8ee3191b..79aedb53e 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -18,6 +18,7 @@ import os import shutil +from typing import ClassVar from mediafile import MediaFile @@ -28,13 +29,24 @@ from beets.util import bytestring_path, displayable_path, syspath from beetsplug.filefilter import FileFilterPlugin -class FileFilterPluginTest(ImportTestCase): +class FileFilterPluginMixin(ImportTestCase): + singletons: ClassVar[bool] + def setUp(self): super().setUp() self.__create_import_dir(2) self._setup_import_session() config["import"]["pretend"] = True + import_files = [self.import_dir] + self._setup_import_session(singletons=self.singletons) + self.importer.paths = import_files + + def tearDown(self): + self.unload_plugins() + FileFilterPlugin.listeners = None + super().tearDown() + def __copy_file(self, dest_path, metadata): # Copy files resource_path = os.path.join(_common.RSRC, b"full.mp3") @@ -89,25 +101,22 @@ class FileFilterPluginTest(ImportTestCase): self.__copy_file(dest_path, metadata) self.misc_paths.append(dest_path) - def __run(self, expected_lines, singletons=False): + def _run(self, expected_lines): self.load_plugins("filefilter") - - import_files = [self.import_dir] - self._setup_import_session(singletons=singletons) - self.importer.paths = import_files - with capture_log() as logs: self.importer.run() - self.unload_plugins() - FileFilterPlugin.listeners = None logs = [line for line in logs if not line.startswith("Sending event:")] self.assertEqual(logs, expected_lines) + +class FileFilterPluginNonSingletonTest(FileFilterPluginMixin): + singletons = False + def test_import_default(self): """The default configuration should import everything.""" - self.__run( + self._run( [ "Album: %s" % displayable_path(self.artist_path), " %s" % displayable_path(self.artist_paths[0]), @@ -123,14 +132,14 @@ class FileFilterPluginTest(ImportTestCase): def test_import_nothing(self): config["filefilter"]["path"] = "not_there" - self.__run( + self._run( ["No files imported from %s" % displayable_path(self.import_dir)] ) # Global options def test_import_global(self): config["filefilter"]["path"] = ".*track_1.*\\.mp3" - self.__run( + self._run( [ "Album: %s" % displayable_path(self.artist_path), " %s" % displayable_path(self.artist_paths[0]), @@ -138,18 +147,10 @@ class FileFilterPluginTest(ImportTestCase): " %s" % displayable_path(self.misc_paths[0]), ] ) - self.__run( - [ - "Singleton: %s" % displayable_path(self.artist_paths[0]), - "Singleton: %s" % displayable_path(self.misc_paths[0]), - ], - singletons=True, - ) - # Album options def test_import_album(self): config["filefilter"]["album_path"] = ".*track_1.*\\.mp3" - self.__run( + self._run( [ "Album: %s" % displayable_path(self.artist_path), " %s" % displayable_path(self.artist_paths[0]), @@ -157,29 +158,10 @@ class FileFilterPluginTest(ImportTestCase): " %s" % displayable_path(self.misc_paths[0]), ] ) - self.__run( - [ - "Singleton: %s" % displayable_path(self.artist_paths[0]), - "Singleton: %s" % displayable_path(self.artist_paths[1]), - "Singleton: %s" % displayable_path(self.album_paths[0]), - "Singleton: %s" % displayable_path(self.album_paths[1]), - "Singleton: %s" % displayable_path(self.misc_paths[0]), - "Singleton: %s" % displayable_path(self.misc_paths[1]), - ], - singletons=True, - ) - # Singleton options def test_import_singleton(self): config["filefilter"]["singleton_path"] = ".*track_1.*\\.mp3" - self.__run( - [ - "Singleton: %s" % displayable_path(self.artist_paths[0]), - "Singleton: %s" % displayable_path(self.misc_paths[0]), - ], - singletons=True, - ) - self.__run( + self._run( [ "Album: %s" % displayable_path(self.artist_path), " %s" % displayable_path(self.artist_paths[0]), @@ -196,8 +178,7 @@ class FileFilterPluginTest(ImportTestCase): # Album and singleton options def test_import_both(self): config["filefilter"]["album_path"] = ".*track_1.*\\.mp3" - config["filefilter"]["singleton_path"] = ".*track_2.*\\.mp3" - self.__run( + self._run( [ "Album: %s" % displayable_path(self.artist_path), " %s" % displayable_path(self.artist_paths[0]), @@ -205,10 +186,50 @@ class FileFilterPluginTest(ImportTestCase): " %s" % displayable_path(self.misc_paths[0]), ] ) - self.__run( + + +class FileFilterPluginSingletonTest(FileFilterPluginMixin): + singletons = True + + def test_import_global(self): + config["filefilter"]["path"] = ".*track_1.*\\.mp3" + self._run( + [ + "Singleton: %s" % displayable_path(self.artist_paths[0]), + "Singleton: %s" % displayable_path(self.misc_paths[0]), + ] + ) + + # Album options + def test_import_album(self): + config["filefilter"]["album_path"] = ".*track_1.*\\.mp3" + self._run( + [ + "Singleton: %s" % displayable_path(self.artist_paths[0]), + "Singleton: %s" % displayable_path(self.artist_paths[1]), + "Singleton: %s" % displayable_path(self.album_paths[0]), + "Singleton: %s" % displayable_path(self.album_paths[1]), + "Singleton: %s" % displayable_path(self.misc_paths[0]), + "Singleton: %s" % displayable_path(self.misc_paths[1]), + ] + ) + + # Singleton options + def test_import_singleton(self): + config["filefilter"]["singleton_path"] = ".*track_1.*\\.mp3" + self._run( + [ + "Singleton: %s" % displayable_path(self.artist_paths[0]), + "Singleton: %s" % displayable_path(self.misc_paths[0]), + ] + ) + + # Album and singleton options + def test_import_both(self): + config["filefilter"]["singleton_path"] = ".*track_2.*\\.mp3" + self._run( [ "Singleton: %s" % displayable_path(self.artist_paths[1]), "Singleton: %s" % displayable_path(self.misc_paths[1]), - ], - singletons=True, + ] )