From 74fee8d886a7fe01577a2958987212c105beae26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Tue, 2 Jul 2024 21:28:18 +0100 Subject: [PATCH 01/29] Remove unused classes and constant --- beets/test/_common.py | 66 ++++--------------------------------------- 1 file changed, 6 insertions(+), 60 deletions(-) diff --git a/beets/test/_common.py b/beets/test/_common.py index 746fa1a564..2be33de95e 100644 --- a/beets/test/_common.py +++ b/beets/test/_common.py @@ -18,19 +18,17 @@ import shutil import sys import tempfile -import time import unittest from contextlib import contextmanager -import beets # noqa: E402 -import beets.library # noqa: E402 +import beets +import beets.library # Make sure the development versions of the plugins are used -import beetsplug # noqa: E402 -from beets import util # noqa: E402 -from beets import importer, logging # noqa: E402 -from beets.ui import commands # noqa: E402 -from beets.util import bytestring_path, syspath # noqa: E402 +import beetsplug +from beets import importer, logging, util +from beets.ui import commands +from beets.util import syspath beetsplug.__path__ = [ os.path.abspath( @@ -121,9 +119,6 @@ def item(lib=None): return i -_album_ident = 0 - - def album(lib=None): global _item_ident _item_ident += 1 @@ -254,36 +249,6 @@ def tearDown(self): super().tearDown() -# Mock timing. - - -class Timecop: - """Mocks the timing system (namely time() and sleep()) for testing. - Inspired by the Ruby timecop library. - """ - - def __init__(self): - self.now = time.time() - - def time(self): - return self.now - - def sleep(self, amount): - self.now += amount - - def install(self): - self.orig = { - "time": time.time, - "sleep": time.sleep, - } - time.time = self.time - time.sleep = self.sleep - - def restore(self): - time.time = self.orig["time"] - time.sleep = self.orig["sleep"] - - # Mock I/O. @@ -388,25 +353,6 @@ def __getattr__(self, key): return self.fields.get(key) -# Convenience methods for setting up a temporary sandbox directory for tests -# that need to interact with the filesystem. - - -class TempDirMixin: - """Text mixin for creating and deleting a temporary directory.""" - - def create_temp_dir(self): - """Create a temporary directory and assign it into `self.temp_dir`. - Call `remove_temp_dir` later to delete it. - """ - self.temp_dir = bytestring_path(tempfile.mkdtemp()) - - def remove_temp_dir(self): - """Delete the temporary directory created by `create_temp_dir`.""" - if os.path.isdir(syspath(self.temp_dir)): - shutil.rmtree(syspath(self.temp_dir)) - - # Platform mocking. From 2566e227446804b9821c72c6c42a2a91bb25f78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Wed, 3 Jul 2024 11:56:15 +0100 Subject: [PATCH 02/29] Incorporate _common.Assertions into helper.TestHelper --- beets/test/helper.py | 2 +- test/test_importer.py | 12 ++++-------- test/test_ui.py | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index c9b30f619f..bd01c0e3a3 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -142,7 +142,7 @@ def has_program(cmd, args=["--version"]): return True -class TestHelper: +class TestHelper(_common.Assertions): """Helper mixin for high-level cli and plugin tests. This mixin provides methods to isolate beets' global state provide diff --git a/test/test_importer.py b/test/test_importer.py index fe41ad2f55..87af62a713 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -271,7 +271,7 @@ def create_archive(session): return path -class RmTempTest(unittest.TestCase, ImportHelper, _common.Assertions): +class RmTempTest(unittest.TestCase, ImportHelper): """Tests that temporarily extracted archives are properly removed after usage. """ @@ -1170,9 +1170,7 @@ def match_album_mock(*args, **kwargs): @patch("beets.autotag.mb.match_album", Mock(side_effect=match_album_mock)) -class ImportDuplicateAlbumTest( - unittest.TestCase, TestHelper, _common.Assertions -): +class ImportDuplicateAlbumTest(unittest.TestCase, TestHelper): def setUp(self): self.setup_beets() @@ -1294,9 +1292,7 @@ def match_track_mock(*args, **kwargs): @patch("beets.autotag.mb.match_track", Mock(side_effect=match_track_mock)) -class ImportDuplicateSingletonTest( - unittest.TestCase, TestHelper, _common.Assertions -): +class ImportDuplicateSingletonTest(unittest.TestCase, TestHelper): def setUp(self): self.setup_beets() @@ -1650,7 +1646,7 @@ def test_coalesce_multiple_unicode(self): self.assertEqual(len(items), 3) -class ReimportTest(unittest.TestCase, ImportHelper, _common.Assertions): +class ReimportTest(unittest.TestCase, ImportHelper): """Test "re-imports", in which the autotagging machinery is used for music that's already in the library. diff --git a/test/test_ui.py b/test/test_ui.py index f7494bafb3..4b37c73df0 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -844,7 +844,7 @@ def test_parse_paths_from_logfile(self): @_common.slow_test() -class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions): +class ConfigTest(unittest.TestCase, TestHelper): def setUp(self): self.setup_beets() From 3e278159ed07eed4f44bee4fa20d17b8e9d12d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 13 Jul 2024 17:32:18 +0100 Subject: [PATCH 03/29] Dedupe TestHelper and _common.TestCase setup --- beets/test/_common.py | 65 -------------------------- beets/test/helper.py | 59 ++++++++++++++++++++--- test/plugins/test_art.py | 15 ++++-- test/plugins/test_beatport.py | 6 +-- test/plugins/test_convert.py | 16 ++++--- test/plugins/test_discogs.py | 5 +- test/plugins/test_embedart.py | 1 - test/plugins/test_hook.py | 5 +- test/plugins/test_plugin_mediafield.py | 3 +- test/plugins/test_smartplaylist.py | 7 ++- test/plugins/test_spotify.py | 4 +- test/plugins/test_subsonicupdate.py | 5 +- test/plugins/test_the.py | 4 +- test/plugins/test_web.py | 3 +- test/test_art_resize.py | 4 +- test/test_autotag.py | 16 +++---- test/test_datequery.py | 8 ++-- test/test_files.py | 23 ++++----- test/test_importer.py | 31 ++++++------ test/test_library.py | 42 ++++++++--------- test/test_logging.py | 6 +-- test/test_mb.py | 8 ++-- test/test_metasync.py | 4 +- test/test_query.py | 13 +++--- test/test_sort.py | 5 +- test/test_ui.py | 25 +++++----- test/test_ui_commands.py | 5 +- test/test_ui_init.py | 8 ++-- test/test_util.py | 5 +- test/test_vfs.py | 3 +- 30 files changed, 197 insertions(+), 207 deletions(-) diff --git a/beets/test/_common.py b/beets/test/_common.py index 2be33de95e..790ea9422b 100644 --- a/beets/test/_common.py +++ b/beets/test/_common.py @@ -15,7 +15,6 @@ """Some common functionality for beets' test cases.""" import os -import shutil import sys import tempfile import unittest @@ -185,70 +184,6 @@ def assert_equal_path(self, a, b): ) -# A test harness for all beets tests. -# Provides temporary, isolated configuration. -class TestCase(unittest.TestCase, Assertions): - """A unittest.TestCase subclass that saves and restores beets' - global configuration. This allows tests to make temporary - modifications that will then be automatically removed when the test - completes. Also provides some additional assertion methods, a - temporary directory, and a DummyIO. - """ - - def setUp(self): - # A "clean" source list including only the defaults. - beets.config.sources = [] - beets.config.read(user=False, defaults=True) - - # Direct paths to a temporary directory. Tests can also use this - # temporary directory. - self.temp_dir = util.bytestring_path(tempfile.mkdtemp()) - - beets.config["statefile"] = os.fsdecode( - os.path.join(self.temp_dir, b"state.pickle") - ) - beets.config["library"] = os.fsdecode( - os.path.join(self.temp_dir, b"library.db") - ) - beets.config["directory"] = os.fsdecode( - os.path.join(self.temp_dir, b"libdir") - ) - - # Set $HOME, which is used by Confuse to create directories. - self._old_home = os.environ.get("HOME") - os.environ["HOME"] = os.fsdecode(self.temp_dir) - - # Initialize, but don't install, a DummyIO. - self.io = DummyIO() - - def tearDown(self): - if os.path.isdir(syspath(self.temp_dir)): - shutil.rmtree(syspath(self.temp_dir)) - if self._old_home is None: - del os.environ["HOME"] - else: - os.environ["HOME"] = self._old_home - self.io.restore() - - beets.config.clear() - beets.config._materialized = False - - -class LibTestCase(TestCase): - """A test case that includes an in-memory library object (`lib`) and - an item added to the library (`i`). - """ - - def setUp(self): - super().setUp() - self.lib = beets.library.Library(":memory:") - self.i = item(self.lib) - - def tearDown(self): - self.lib._connection().close() - super().tearDown() - - # Mock I/O. diff --git a/beets/test/helper.py b/beets/test/helper.py index bd01c0e3a3..6cb45e828f 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -36,11 +36,13 @@ import shutil import subprocess import sys +import unittest from contextlib import contextmanager from enum import Enum from io import StringIO from tempfile import mkdtemp, mkstemp from typing import ClassVar +from unittest.mock import patch import responses from mediafile import Image, MediaFile @@ -174,11 +176,19 @@ def setup_beets(self, disk=False): Make sure you call ``teardown_beets()`` afterwards. """ self.create_temp_dir() - os.environ["BEETSDIR"] = os.fsdecode(self.temp_dir) + temp_dir_str = os.fsdecode(self.temp_dir) + self.env_patcher = patch.dict( + "os.environ", + { + "BEETSDIR": temp_dir_str, + "HOME": temp_dir_str, # used by Confuse to create directories. + }, + ) + self.env_patcher.start() self.config = beets.config - self.config.clear() - self.config.read() + self.config.sources = [] + self.config.read(user=False, defaults=True) self.config["plugins"] = [] self.config["verbose"] = 1 @@ -195,13 +205,16 @@ def setup_beets(self, disk=False): dbpath = ":memory:" self.lib = Library(dbpath, self.libdir) + # Initialize, but don't install, a DummyIO. + self.io = _common.DummyIO() + def teardown_beets(self): + self.env_patcher.stop() + self.io.restore() self.lib._close() - if "BEETSDIR" in os.environ: - del os.environ["BEETSDIR"] self.remove_temp_dir() - self.config.clear() - beets.config.read(user=False, defaults=True) + beets.config.clear() + beets.config._materialized = False def load_plugins(self, *plugins): """Load and initialize plugins by names. @@ -490,6 +503,38 @@ def touch(self, path, dir=None, content=""): return path +# A test harness for all beets tests. +# Provides temporary, isolated configuration. +class BeetsTestCase(unittest.TestCase, TestHelper): + """A unittest.TestCase subclass that saves and restores beets' + global configuration. This allows tests to make temporary + modifications that will then be automatically removed when the test + completes. Also provides some additional assertion methods, a + temporary directory, and a DummyIO. + """ + + def setUp(self): + self.setup_beets() + + def tearDown(self): + self.teardown_beets() + + +class LibTestCase(BeetsTestCase): + """A test case that includes an in-memory library object (`lib`) and + an item added to the library (`i`). + """ + + def setUp(self): + super().setUp() + self.lib = beets.library.Library(":memory:") + self.i = _common.item(self.lib) + + def tearDown(self): + self.lib._connection().close() + super().tearDown() + + class ImportHelper(TestHelper): """Provides tools to setup a library, a directory containing files that are to be imported and an import session. The class also provides stubs for the diff --git a/test/plugins/test_art.py b/test/plugins/test_art.py index 8a2aa5870a..4d631aa38a 100644 --- a/test/plugins/test_art.py +++ b/test/plugins/test_art.py @@ -26,7 +26,12 @@ from beets import config, importer, library, logging, util from beets.autotag import AlbumInfo, AlbumMatch from beets.test import _common -from beets.test.helper import CleanupModulesMixin, FetchImageHelper, capture_log +from beets.test.helper import ( + BeetsTestCase, + CleanupModulesMixin, + FetchImageHelper, + capture_log, +) from beets.util import syspath from beets.util.artresizer import ArtResizer from beetsplug import fetchart @@ -44,7 +49,7 @@ def __init__(self, **kwargs): setattr(self, k, v) -class UseThePlugin(CleanupModulesMixin, _common.TestCase): +class UseThePlugin(CleanupModulesMixin, BeetsTestCase): modules = (fetchart.__name__, ArtResizer.__module__) def setUp(self): @@ -977,14 +982,14 @@ def test_deinterlace_and_resize(self): self._assert_image_operated(self.IMG_348x348, self.RESIZE_OP, True) -class DeprecatedConfigTest(_common.TestCase): +class DeprecatedConfigTest(BeetsTestCase): """While refactoring the plugin, the remote_priority option was deprecated, and a new codepath should translate its effect. Check that it actually does so. """ # If we subclassed UseThePlugin, the configuration change would either be - # overwritten by _common.TestCase or be set after constructing the + # overwritten by BeetsTestCase or be set after constructing the # plugin object def setUp(self): super().setUp() @@ -995,7 +1000,7 @@ def test_moves_filesystem_to_end(self): self.assertEqual(type(self.plugin.sources[-1]), fetchart.FileSystem) -class EnforceRatioConfigTest(_common.TestCase): +class EnforceRatioConfigTest(BeetsTestCase): """Throw some data at the regexes.""" def _load_with_config(self, values, should_raise): diff --git a/test/plugins/test_beatport.py b/test/plugins/test_beatport.py index fd75f21542..9b07ebb0df 100644 --- a/test/plugins/test_beatport.py +++ b/test/plugins/test_beatport.py @@ -20,11 +20,11 @@ from beets import library from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import beatport -class BeatportTest(_common.TestCase, TestHelper): +class BeatportTest(BeetsTestCase): def _make_release_response(self): """Returns a dict that mimics a response from the beatport API. @@ -601,7 +601,7 @@ def test_genre_applied(self): self.assertEqual(track.genre, test_track.genre) -class BeatportResponseEmptyTest(_common.TestCase, TestHelper): +class BeatportResponseEmptyTest(BeetsTestCase): def _make_tracks_response(self): results = [ { diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index bc13b6fecb..12b72bf852 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -22,8 +22,8 @@ from mediafile import MediaFile from beets import util -from beets.test import _common, helper -from beets.test.helper import capture_log, control_stdin +from beets.test import _common +from beets.test.helper import BeetsTestCase, capture_log, control_stdin from beets.util import bytestring_path, displayable_path @@ -33,7 +33,7 @@ def shell_quote(text): return shlex.quote(text) -class TestHelper(helper.TestHelper): +class ConvertMixin: def tagged_copy_cmd(self, tag): """Return a conversion command that copies files and appends `tag` to the copy. @@ -84,8 +84,12 @@ def assertNoFileTag(self, path, tag): # noqa ) +class ConvertTestCase(BeetsTestCase, ConvertMixin): + pass + + @_common.slow_test() -class ImportConvertTest(_common.TestCase, TestHelper): +class ImportConvertTest(ConvertTestCase): def setUp(self): self.setup_beets(disk=True) # Converter is threaded self.importer = self.create_importer() @@ -163,7 +167,7 @@ def run_convert(self, *args): @_common.slow_test() -class ConvertCliTest(_common.TestCase, TestHelper, ConvertCommand): +class ConvertCliTest(ConvertTestCase, ConvertCommand): def setUp(self): self.setup_beets(disk=True) # Converter is threaded self.album = self.add_album_fixture(ext="ogg") @@ -310,7 +314,7 @@ def test_playlist_pretend(self): @_common.slow_test() -class NeverConvertLossyFilesTest(_common.TestCase, TestHelper, ConvertCommand): +class NeverConvertLossyFilesTest(ConvertTestCase, ConvertCommand): """Test the effect of the `never_convert_lossy_files` option.""" def setUp(self): diff --git a/test/plugins/test_discogs.py b/test/plugins/test_discogs.py index 6ee57dcd9c..203a8a3763 100644 --- a/test/plugins/test_discogs.py +++ b/test/plugins/test_discogs.py @@ -18,14 +18,13 @@ import unittest from beets import config -from beets.test import _common from beets.test._common import Bag -from beets.test.helper import capture_log +from beets.test.helper import BeetsTestCase, capture_log from beets.util.id_extractors import extract_discogs_id_regex from beetsplug.discogs import DiscogsPlugin -class DGAlbumInfoTest(_common.TestCase): +class DGAlbumInfoTest(BeetsTestCase): def _make_release(self, tracks=None): """Returns a Bag that mimics a discogs_client.Release. The list of elements on the returned Bag is incomplete, including just diff --git a/test/plugins/test_embedart.py b/test/plugins/test_embedart.py index 48a110295b..d280fefd9b 100644 --- a/test/plugins/test_embedart.py +++ b/test/plugins/test_embedart.py @@ -47,7 +47,6 @@ class EmbedartCliTest(TestHelper, FetchImageHelper): abbey_differentpath = os.path.join(_common.RSRC, b"abbey-different.jpg") def setUp(self): - self.io = _common.DummyIO() self.io.install() self.setup_beets() # Converter is threaded self.load_plugins("embedart") diff --git a/test/plugins/test_hook.py b/test/plugins/test_hook.py index 1364028f6c..ee79b35992 100644 --- a/test/plugins/test_hook.py +++ b/test/plugins/test_hook.py @@ -19,8 +19,7 @@ import unittest from beets import config, plugins -from beets.test import _common -from beets.test.helper import TestHelper, capture_log +from beets.test.helper import BeetsTestCase, capture_log def get_temporary_path(): @@ -30,7 +29,7 @@ def get_temporary_path(): return os.path.join(temporary_directory, temporary_name) -class HookTest(_common.TestCase, TestHelper): +class HookTest(BeetsTestCase): TEST_HOOK_COUNT = 5 def setUp(self): diff --git a/test/plugins/test_plugin_mediafield.py b/test/plugins/test_plugin_mediafield.py index 0e03886cf8..938f1244bf 100644 --- a/test/plugins/test_plugin_mediafield.py +++ b/test/plugins/test_plugin_mediafield.py @@ -24,6 +24,7 @@ from beets.library import Item from beets.plugins import BeetsPlugin from beets.test import _common +from beets.test.helper import BeetsTestCase from beets.util import bytestring_path, syspath field_extension = mediafile.MediaField( @@ -41,7 +42,7 @@ ) -class ExtendedFieldTestMixin(_common.TestCase): +class ExtendedFieldTestMixin(BeetsTestCase): def _mediafile_fixture(self, name, extension="mp3"): name = bytestring_path(name + "." + extension) src = os.path.join(_common.RSRC, name) diff --git a/test/plugins/test_smartplaylist.py b/test/plugins/test_smartplaylist.py index 68c11c9105..9655f3f90d 100644 --- a/test/plugins/test_smartplaylist.py +++ b/test/plugins/test_smartplaylist.py @@ -23,14 +23,13 @@ from beets.dbcore import OrQuery from beets.dbcore.query import FixedFieldSort, MultipleSort, NullSort from beets.library import Album, Item, parse_query_string -from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.ui import UserError from beets.util import CHAR_REPLACE, bytestring_path, syspath from beetsplug.smartplaylist import SmartPlaylistPlugin -class SmartPlaylistTest(_common.TestCase): +class SmartPlaylistTest(BeetsTestCase): def test_build_queries(self): spl = SmartPlaylistPlugin() self.assertIsNone(spl._matched_playlists) @@ -339,7 +338,7 @@ def test_playlist_update_uri_format(self): self.assertEqual(content, b"http://beets:8337/item/3/file\n") -class SmartPlaylistCLITest(_common.TestCase, TestHelper): +class SmartPlaylistCLITest(BeetsTestCase): def setUp(self): self.setup_beets() diff --git a/test/plugins/test_spotify.py b/test/plugins/test_spotify.py index ae5ce5228a..c2fcc0722f 100644 --- a/test/plugins/test_spotify.py +++ b/test/plugins/test_spotify.py @@ -9,7 +9,7 @@ from beets import config from beets.library import Item from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import spotify @@ -25,7 +25,7 @@ def _params(url): return parse_qs(urlparse(url).query) -class SpotifyPluginTest(_common.TestCase, TestHelper): +class SpotifyPluginTest(BeetsTestCase): @responses.activate def setUp(self): config.clear() diff --git a/test/plugins/test_subsonicupdate.py b/test/plugins/test_subsonicupdate.py index 3f84d848f5..be7f979ac3 100644 --- a/test/plugins/test_subsonicupdate.py +++ b/test/plugins/test_subsonicupdate.py @@ -6,8 +6,7 @@ import responses from beets import config -from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import subsonicupdate @@ -26,7 +25,7 @@ def _params(url): return parse_qs(urlparse(url).query) -class SubsonicPluginTest(_common.TestCase, TestHelper): +class SubsonicPluginTest(BeetsTestCase): """Test class for subsonicupdate.""" @responses.activate diff --git a/test/plugins/test_the.py b/test/plugins/test_the.py index e6d5107741..4f23d6f133 100644 --- a/test/plugins/test_the.py +++ b/test/plugins/test_the.py @@ -3,11 +3,11 @@ import unittest from beets import config -from beets.test import _common +from beets.test.helper import BeetsTestCase from beetsplug.the import FORMAT, PATTERN_A, PATTERN_THE, ThePlugin -class ThePluginTest(_common.TestCase): +class ThePluginTest(BeetsTestCase): def test_unthe_with_default_patterns(self): self.assertEqual(ThePlugin().unthe("", PATTERN_THE), "") self.assertEqual( diff --git a/test/plugins/test_web.py b/test/plugins/test_web.py index afd1ed706c..c34de05d28 100644 --- a/test/plugins/test_web.py +++ b/test/plugins/test_web.py @@ -9,10 +9,11 @@ from beets import logging from beets.library import Album, Item from beets.test import _common +from beets.test.helper import LibTestCase from beetsplug import web -class WebPluginTest(_common.LibTestCase): +class WebPluginTest(LibTestCase): def setUp(self): super().setUp() self.log = logging.getLogger("beets.web") diff --git a/test/test_art_resize.py b/test/test_art_resize.py index ac9463cba4..e7bee02dc4 100644 --- a/test/test_art_resize.py +++ b/test/test_art_resize.py @@ -20,7 +20,7 @@ from unittest.mock import patch from beets.test import _common -from beets.test.helper import CleanupModulesMixin, TestHelper +from beets.test.helper import BeetsTestCase, CleanupModulesMixin from beets.util import command_output, syspath from beets.util.artresizer import IMBackend, PILBackend @@ -48,7 +48,7 @@ def __init__(self): pass -class ArtResizerFileSizeTest(CleanupModulesMixin, _common.TestCase, TestHelper): +class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): """Unittest test case for Art Resizer to a specific filesize.""" modules = (IMBackend.__module__,) diff --git a/test/test_autotag.py b/test/test_autotag.py index e9b44458c8..8ff613cfff 100644 --- a/test/test_autotag.py +++ b/test/test_autotag.py @@ -22,11 +22,11 @@ from beets.autotag import AlbumInfo, TrackInfo, match from beets.autotag.hooks import Distance, string_dist from beets.library import Item -from beets.test import _common +from beets.test.helper import BeetsTestCase from beets.util import plurality -class PluralityTest(_common.TestCase): +class PluralityTest(BeetsTestCase): def test_plurality_consensus(self): objs = [1, 1, 1, 1] obj, freq = plurality(objs) @@ -146,7 +146,7 @@ def _clear_weights(): Distance.__dict__["_weights"].cache = {} -class DistanceTest(_common.TestCase): +class DistanceTest(BeetsTestCase): def tearDown(self): super().tearDown() _clear_weights() @@ -330,7 +330,7 @@ def test_update(self): ) -class TrackDistanceTest(_common.TestCase): +class TrackDistanceTest(BeetsTestCase): def test_identical_tracks(self): item = _make_item("one", 1) info = _make_trackinfo()[0] @@ -358,7 +358,7 @@ def test_various_artists_tolerated(self): self.assertEqual(dist, 0.0) -class AlbumDistanceTest(_common.TestCase): +class AlbumDistanceTest(BeetsTestCase): def _mapping(self, items, info): out = {} for i, t in zip(items, info.tracks): @@ -664,7 +664,7 @@ def _apply(self, info=None, per_disc_numbering=False, artist_credit=False): autotag.apply_metadata(info, mapping) -class ApplyTest(_common.TestCase, ApplyTestUtil): +class ApplyTest(BeetsTestCase, ApplyTestUtil): def setUp(self): super().setUp() @@ -925,7 +925,7 @@ def test_data_source_applied(self): self.assertEqual(self.items[0].data_source, "MusicBrainz") -class ApplyCompilationTest(_common.TestCase, ApplyTestUtil): +class ApplyCompilationTest(BeetsTestCase, ApplyTestUtil): def setUp(self): super().setUp() @@ -1073,7 +1073,7 @@ def test_accented_characters(self): self.assertEqual(dist, 0.0) -class EnumTest(_common.TestCase): +class EnumTest(BeetsTestCase): """ Test Enum Subclasses defined in beets.util.enumeration """ diff --git a/test/test_datequery.py b/test/test_datequery.py index 2b666f0d13..56c85e05da 100644 --- a/test/test_datequery.py +++ b/test/test_datequery.py @@ -25,7 +25,7 @@ InvalidQueryArgumentValueError, _parse_periods, ) -from beets.test import _common +from beets.test.helper import LibTestCase def _date(string): @@ -152,7 +152,7 @@ def _parsetime(s): return time.mktime(datetime.strptime(s, "%Y-%m-%d %H:%M").timetuple()) -class DateQueryTest(_common.LibTestCase): +class DateQueryTest(LibTestCase): def setUp(self): super().setUp() self.i.added = _parsetime("2013-03-30 22:21") @@ -187,7 +187,7 @@ def test_single_day_nonmatch_fast(self): self.assertEqual(len(matched), 0) -class DateQueryTestRelative(_common.LibTestCase): +class DateQueryTestRelative(LibTestCase): def setUp(self): super().setUp() @@ -233,7 +233,7 @@ def test_single_day_nonmatch_fast(self): self.assertEqual(len(matched), 0) -class DateQueryTestRelativeMore(_common.LibTestCase): +class DateQueryTestRelativeMore(LibTestCase): def setUp(self): super().setUp() self.i.added = _parsetime(datetime.now().strftime("%Y-%m-%d %H:%M")) diff --git a/test/test_files.py b/test/test_files.py index 46aebe54fa..68971cd854 100644 --- a/test/test_files.py +++ b/test/test_files.py @@ -25,10 +25,11 @@ from beets import util from beets.test import _common from beets.test._common import item, touch +from beets.test.helper import BeetsTestCase from beets.util import MoveOperation, bytestring_path, syspath -class MoveTest(_common.TestCase): +class MoveTest(BeetsTestCase): def setUp(self): super().setUp() @@ -207,7 +208,7 @@ def test_hardlink_changes_path(self): self.assertEqual(self.i.path, util.normpath(self.dest)) -class HelperTest(_common.TestCase): +class HelperTest(BeetsTestCase): def test_ancestry_works_on_file(self): p = "/a/b/c" a = ["/", "/a", "/a/b"] @@ -244,7 +245,7 @@ def test_forward_slash(self): self.assertEqual(util.path_as_posix(p), a) -class AlbumFileTest(_common.TestCase): +class AlbumFileTest(BeetsTestCase): def setUp(self): super().setUp() @@ -311,7 +312,7 @@ def test_albuminfo_move_to_custom_dir(self): self.assertIn(b"testotherdir", self.i.path) -class ArtFileTest(_common.TestCase): +class ArtFileTest(BeetsTestCase): def setUp(self): super().setUp() @@ -485,7 +486,7 @@ def test_move_not_last_file_does_not_move_albumart(self): self.assertExists(oldartpath) -class RemoveTest(_common.TestCase): +class RemoveTest(BeetsTestCase): def setUp(self): super().setUp() @@ -546,7 +547,7 @@ def test_removing_last_item_in_album_with_albumart_prunes_dir(self): # Tests that we can "delete" nonexistent files. -class SoftRemoveTest(_common.TestCase): +class SoftRemoveTest(BeetsTestCase): def setUp(self): super().setUp() @@ -564,7 +565,7 @@ def test_soft_remove_silent_on_no_file(self): self.fail("OSError when removing path") -class SafeMoveCopyTest(_common.TestCase): +class SafeMoveCopyTest(BeetsTestCase): def setUp(self): super().setUp() @@ -612,7 +613,7 @@ def test_self_copy(self): self.assertExists(self.path) -class PruneTest(_common.TestCase): +class PruneTest(BeetsTestCase): def setUp(self): super().setUp() @@ -632,7 +633,7 @@ def test_prune_nonexistent_directory(self): self.assertNotExists(self.sub) -class WalkTest(_common.TestCase): +class WalkTest(BeetsTestCase): def setUp(self): super().setUp() @@ -666,7 +667,7 @@ def test_ignore_everything(self): self.assertEqual(res[0], (self.base, [], [])) -class UniquePathTest(_common.TestCase): +class UniquePathTest(BeetsTestCase): def setUp(self): super().setUp() @@ -694,7 +695,7 @@ def test_conflicting_file_with_number_increases_number(self): self.assertEqual(path, os.path.join(self.base, b"x.3.mp3")) -class MkDirAllTest(_common.TestCase): +class MkDirAllTest(BeetsTestCase): def test_parent_exists(self): path = os.path.join(self.temp_dir, b"foo", b"bar", b"baz", b"qux.mp3") util.mkdirall(path) diff --git a/test/test_importer.py b/test/test_importer.py index 87af62a713..8c2b474e07 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -36,6 +36,7 @@ from beets.test import _common from beets.test.helper import ( AutotagStub, + BeetsTestCase, ImportHelper, TestHelper, capture_log, @@ -44,7 +45,7 @@ from beets.util import bytestring_path, displayable_path, syspath -class ScrubbedImportTest(_common.TestCase, ImportHelper): +class ScrubbedImportTest(BeetsTestCase, ImportHelper): def setUp(self): self.setup_beets(disk=True) self.load_plugins("scrub") @@ -99,7 +100,7 @@ def test_tags_not_restored(self): @_common.slow_test() -class NonAutotaggedImportTest(_common.TestCase, ImportHelper): +class NonAutotaggedImportTest(BeetsTestCase, ImportHelper): def setUp(self): self.setup_beets(disk=True) self._create_import_dir(2) @@ -344,7 +345,7 @@ def create_archive(self): return os.path.join(_common.RSRC, b"password.rar") -class ImportSingletonTest(_common.TestCase, ImportHelper): +class ImportSingletonTest(BeetsTestCase, ImportHelper): """Test ``APPLY`` and ``ASIS`` choices for an import session with singletons config set to True. """ @@ -467,7 +468,7 @@ def test_set_fields(self): self.assertEqual(item.title, "Applied Title 1 - formatted") -class ImportTest(_common.TestCase, ImportHelper): +class ImportTest(BeetsTestCase, ImportHelper): """Test APPLY, ASIS and SKIP choices.""" def setUp(self): @@ -681,7 +682,7 @@ def test_set_fields(self): ) -class ImportTracksTest(_common.TestCase, ImportHelper): +class ImportTracksTest(BeetsTestCase, ImportHelper): """Test TRACKS and APPLY choice.""" def setUp(self): @@ -715,7 +716,7 @@ def test_apply_tracks_adds_singleton_path(self): self.assert_file_in_lib(b"singletons", b"Applied Title 1.mp3") -class ImportCompilationTest(_common.TestCase, ImportHelper): +class ImportCompilationTest(BeetsTestCase, ImportHelper): """Test ASIS import of a folder containing tracks with different artists.""" def setUp(self): @@ -834,7 +835,7 @@ def test_asis_albumartists_tag_sets_multi_albumartists(self): self.assertTrue(asserted_multi_artists_0 and asserted_multi_artists_1) -class ImportExistingTest(_common.TestCase, ImportHelper): +class ImportExistingTest(BeetsTestCase, ImportHelper): """Test importing files that are already in the library directory.""" def setUp(self): @@ -959,7 +960,7 @@ def test_outside_file_is_moved(self): self.assertNotExists(self.import_media[0].path) -class GroupAlbumsImportTest(_common.TestCase, ImportHelper): +class GroupAlbumsImportTest(BeetsTestCase, ImportHelper): def setUp(self): self.setup_beets() self._create_import_dir(3) @@ -1031,7 +1032,7 @@ def setUp(self): config["import"]["group_albums"] = True -class ChooseCandidateTest(_common.TestCase, ImportHelper): +class ChooseCandidateTest(BeetsTestCase, ImportHelper): def setUp(self): self.setup_beets() self._create_import_dir(1) @@ -1054,7 +1055,7 @@ def test_choose_second_candidate(self): self.assertEqual(self.lib.albums().get().album, "Applied Album MM") -class InferAlbumDataTest(_common.TestCase): +class InferAlbumDataTest(BeetsTestCase): def setUp(self): super().setUp() @@ -1365,7 +1366,7 @@ def add_item_fixture(self, **kwargs): return item -class TagLogTest(_common.TestCase): +class TagLogTest(BeetsTestCase): def test_tag_log_line(self): sio = StringIO() handler = logging.StreamHandler(sio) @@ -1484,7 +1485,7 @@ def _mkmp3(path): ) -class AlbumsInDirTest(_common.TestCase): +class AlbumsInDirTest(BeetsTestCase): def setUp(self): super().setUp() @@ -1526,7 +1527,7 @@ def test_finds_multiple_songs(self): self.assertEqual(len(album), 1) -class MultiDiscAlbumsInDirTest(_common.TestCase): +class MultiDiscAlbumsInDirTest(BeetsTestCase): def create_music(self, files=True, ascii=True): """Create some music in multiple album directories. @@ -1751,7 +1752,7 @@ def test_reimported_album_not_preserves_flexattr(self): self.assertEqual(self._album().data_source, "match_source") -class ImportPretendTest(_common.TestCase, ImportHelper): +class ImportPretendTest(BeetsTestCase, ImportHelper): """Test the pretend commandline option""" def __init__(self, method_name="runTest"): @@ -1944,7 +1945,7 @@ def mocked_get_recording_by_id( "musicbrainzngs.get_release_by_id", Mock(side_effect=mocked_get_release_by_id), ) -class ImportMusicBrainzIdTest(_common.TestCase, ImportHelper): +class ImportMusicBrainzIdTest(BeetsTestCase, ImportHelper): """Test the --musicbrainzid argument.""" MB_RELEASE_PREFIX = "https://musicbrainz.org/release/" diff --git a/test/test_library.py b/test/test_library.py index c9d0440b51..179927dc95 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -32,14 +32,14 @@ from beets import config, plugins, util from beets.test import _common from beets.test._common import item -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase, LibTestCase, TestHelper from beets.util import bytestring_path, syspath # Shortcut to path normalization. np = util.normpath -class LoadTest(_common.LibTestCase): +class LoadTest(LibTestCase): def test_load_restores_data_from_db(self): original_title = self.i.title self.i.title = "something" @@ -53,7 +53,7 @@ def test_load_clears_dirty_flags(self): self.assertNotIn("artist", self.i._dirty) -class StoreTest(_common.LibTestCase): +class StoreTest(LibTestCase): def test_store_changes_database_value(self): self.i.year = 1987 self.i.store() @@ -94,7 +94,7 @@ def test_store_album_cascades_flex_deletes(self): self.assertNotIn("flex1", album.items()[0]) -class AddTest(_common.TestCase): +class AddTest(BeetsTestCase): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -126,14 +126,14 @@ def test_library_add_path_inserts_row(self): self.assertEqual(new_grouping, self.i.grouping) -class RemoveTest(_common.LibTestCase): +class RemoveTest(LibTestCase): def test_remove_deletes_from_db(self): self.i.remove() c = self.lib._connection().execute("select * from items") self.assertIsNone(c.fetchone()) -class GetSetTest(_common.TestCase): +class GetSetTest(BeetsTestCase): def setUp(self): super().setUp() self.i = item() @@ -169,7 +169,7 @@ def test_album_fallback(self): self.assertIsNone(i.get("flexx")) -class DestinationTest(_common.TestCase): +class DestinationTest(BeetsTestCase): def setUp(self): super().setUp() # default directory is ~/Music and the only reason why it was switched @@ -182,10 +182,6 @@ def tearDown(self): super().tearDown() self.lib._connection().close() - # Reset config if it was changed in test cases - config.clear() - config.read(user=False, defaults=True) - def test_directory_works_with_trailing_slash(self): self.lib.directory = b"one/" self.lib.path_formats = [("default", "two")] @@ -551,7 +547,7 @@ def test_album_field_in_template(self): self.assertEqual(self.i.destination(), np("one/foo/two")) -class ItemFormattedMappingTest(_common.LibTestCase): +class ItemFormattedMappingTest(LibTestCase): def test_formatted_item_value(self): formatted = self.i.formatted() self.assertEqual(formatted["artist"], "the artist") @@ -624,7 +620,7 @@ def _assert_dest(self, dest, i=None): self.assertEqual(actual, dest) -class DestinationFunctionTest(_common.TestCase, PathFormattingMixin): +class DestinationFunctionTest(BeetsTestCase, PathFormattingMixin): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -733,7 +729,7 @@ def test_first_different_sep(self): self._assert_dest(b"/base/Alice & Bob") -class DisambiguationTest(_common.TestCase, PathFormattingMixin): +class DisambiguationTest(BeetsTestCase, PathFormattingMixin): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -822,7 +818,7 @@ def test_key_flexible_attribute(self): self._assert_dest(b"/base/foo/the title", self.i1) -class SingletonDisambiguationTest(_common.TestCase, PathFormattingMixin): +class SingletonDisambiguationTest(BeetsTestCase, PathFormattingMixin): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -907,7 +903,7 @@ def test_key_flexible_attribute(self): self._assert_dest(b"/base/foo/the title", self.i1) -class PluginDestinationTest(_common.TestCase): +class PluginDestinationTest(BeetsTestCase): def setUp(self): super().setUp() @@ -959,7 +955,7 @@ def test_plugin_value_sanitized(self): self._assert_dest(b"the artist bar_baz") -class AlbumInfoTest(_common.TestCase): +class AlbumInfoTest(BeetsTestCase): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -1064,7 +1060,7 @@ def test_noop_albuminfo_changes_affect_items(self): self.assertEqual(i.album, ai.album) -class ArtDestinationTest(_common.TestCase): +class ArtDestinationTest(BeetsTestCase): def setUp(self): super().setUp() config["art_filename"] = "artimage" @@ -1092,7 +1088,7 @@ def test_art_path_sanitized(self): self.assertIn(b"artYimage", art) -class PathStringTest(_common.TestCase): +class PathStringTest(BeetsTestCase): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -1178,7 +1174,7 @@ def test_unicode_artpath_in_database_decoded(self): self.assertTrue(isinstance(alb.artpath, bytes)) -class MtimeTest(_common.TestCase): +class MtimeTest(BeetsTestCase): def setUp(self): super().setUp() self.ipath = os.path.join(self.temp_dir, b"testfile.mp3") @@ -1216,7 +1212,7 @@ def test_mtime_up_to_date_after_read(self): self.assertGreaterEqual(self.i.mtime, self._mtime()) -class ImportTimeTest(_common.TestCase): +class ImportTimeTest(BeetsTestCase): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -1232,7 +1228,7 @@ def test_atime_for_singleton(self): self.assertGreater(self.singleton.added, 0) -class TemplateTest(_common.LibTestCase): +class TemplateTest(LibTestCase): def test_year_formatted_in_template(self): self.i.year = 123 self.i.store() @@ -1262,7 +1258,7 @@ def test_album_and_item_format(self): self.assertEqual(f"{item:$tagada}", "togodo") -class UnicodePathTest(_common.LibTestCase): +class UnicodePathTest(LibTestCase): def test_unicode_path(self): self.i.path = os.path.join(_common.RSRC, "unicode\u2019d.mp3".encode()) # If there are any problems with unicode paths, we will raise diff --git a/test/test_logging.py b/test/test_logging.py index 58be799e0a..db7f33bfd6 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -10,10 +10,10 @@ import beetsplug from beets import plugins, ui from beets.test import _common, helper -from beets.test._common import TestCase +from beets.test.helper import BeetsTestCase -class LoggingTest(TestCase): +class LoggingTest(BeetsTestCase): def test_logging_management(self): l1 = log.getLogger("foo123") l2 = blog.getLogger("foo123") @@ -162,7 +162,7 @@ def test_import_stage_level2(self): @_common.slow_test() -class ConcurrentEventsTest(TestCase, helper.TestHelper): +class ConcurrentEventsTest(BeetsTestCase): """Similar to LoggingLevelTest but lower-level and focused on multiple events interaction. Since this is a bit heavy we don't do it in LoggingLevelTest. diff --git a/test/test_mb.py b/test/test_mb.py index efd620522f..9922cbfa04 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -20,10 +20,10 @@ from beets import config from beets.autotag import mb -from beets.test import _common +from beets.test.helper import BeetsTestCase -class MBAlbumInfoTest(_common.TestCase): +class MBAlbumInfoTest(BeetsTestCase): def _make_release( self, date_str="2009", @@ -662,7 +662,7 @@ def test_track_disambiguation(self): self.assertEqual(t[1].trackdisambig, "SECOND TRACK") -class ParseIDTest(_common.TestCase): +class ParseIDTest(BeetsTestCase): def test_parse_id_correct(self): id_string = "28e32c71-1450-463e-92bf-e0a46446fc11" out = mb._parse_id(id_string) @@ -680,7 +680,7 @@ def test_parse_id_url_finds_id(self): self.assertEqual(out, id_string) -class ArtistFlatteningTest(_common.TestCase): +class ArtistFlatteningTest(BeetsTestCase): def _credit_dict(self, suffix=""): return { "artist": { diff --git a/test/test_metasync.py b/test/test_metasync.py index 9dae099af7..a3bc3acb23 100644 --- a/test/test_metasync.py +++ b/test/test_metasync.py @@ -21,7 +21,7 @@ from beets.library import Item from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase def _parsetime(s): @@ -32,7 +32,7 @@ def _is_windows(): return platform.system() == "Windows" -class MetaSyncTest(_common.TestCase, TestHelper): +class MetaSyncTest(BeetsTestCase): itunes_library_unix = os.path.join(_common.RSRC, b"itunes_library_unix.xml") itunes_library_windows = os.path.join( _common.RSRC, b"itunes_library_windows.xml" diff --git a/test/test_query.py b/test/test_query.py index 69277cfcd1..897b247dc5 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -31,6 +31,7 @@ ) from beets.library import Item, Library from beets.test import _common, helper +from beets.test.helper import BeetsTestCase, LibTestCase from beets.util import syspath # Because the absolute path begins with something like C:, we @@ -48,7 +49,7 @@ def assertNotInResult(self, item, results): # noqa self.assertNotIn(item.id, result_ids) -class AnyFieldQueryTest(_common.LibTestCase): +class AnyFieldQueryTest(LibTestCase): def test_no_restriction(self): q = dbcore.query.AnyFieldQuery( "title", @@ -92,7 +93,7 @@ def assert_albums_matched(self, results, albums): # A test case class providing a library with some dummy data and some # assertions involving that data. -class DummyDataTestCase(_common.TestCase, AssertsMixin): +class DummyDataTestCase(BeetsTestCase, AssertsMixin): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -418,7 +419,7 @@ def test_invalid_query(self): self.assertIsInstance(raised.exception, ParsingError) -class MatchTest(_common.TestCase): +class MatchTest(BeetsTestCase): def setUp(self): super().setUp() self.item = _common.item() @@ -487,7 +488,7 @@ def test_eq(self): self.assertNotEqual(q3, q4) -class PathQueryTest(_common.LibTestCase, TestHelper, AssertsMixin): +class PathQueryTest(LibTestCase, TestHelper, AssertsMixin): def setUp(self): super().setUp() @@ -871,7 +872,7 @@ def test_match_slow_after_set_none(self): self.assertInResult(item, matched) -class NotQueryMatchTest(_common.TestCase): +class NotQueryMatchTest(BeetsTestCase): """Test `query.NotQuery` matching against a single item, using the same cases and assertions as on `MatchTest`, plus assertion on the negated queries (ie. assertTrue(q) -> assertFalse(NotQuery(q))). @@ -1129,7 +1130,7 @@ def test_fast_vs_slow(self): pass -class RelatedQueriesTest(_common.TestCase, AssertsMixin): +class RelatedQueriesTest(BeetsTestCase, AssertsMixin): """Test album-level queries with track-level filters and vice-versa.""" def setUp(self): diff --git a/test/test_sort.py b/test/test_sort.py index 52fa026005..b222c93f92 100644 --- a/test/test_sort.py +++ b/test/test_sort.py @@ -20,11 +20,12 @@ import beets.library from beets import config, dbcore from beets.test import _common +from beets.test.helper import BeetsTestCase # A test case class providing a library with some dummy data and some # assertions involving that data. -class DummyDataTestCase(_common.TestCase): +class DummyDataTestCase(BeetsTestCase): def setUp(self): super().setUp() self.lib = beets.library.Library(":memory:") @@ -373,7 +374,7 @@ def test_config_opposite_sort_album(self): self.assertGreater(results[0].albumartist, results[1].albumartist) -class CaseSensitivityTest(DummyDataTestCase, _common.TestCase): +class CaseSensitivityTest(DummyDataTestCase, BeetsTestCase): """If case_insensitive is false, lower-case values should be placed after all upper-case values. E.g., `Foo Qux bar` """ diff --git a/test/test_ui.py b/test/test_ui.py index 4b37c73df0..9ca68992ad 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -31,6 +31,7 @@ from beets.autotag.match import distance from beets.test import _common from beets.test.helper import ( + BeetsTestCase, TestHelper, capture_stdout, control_stdin, @@ -108,7 +109,7 @@ def test_list_album_format(self): self.assertNotIn("the album", stdout.getvalue()) -class RemoveTest(_common.TestCase, TestHelper): +class RemoveTest(BeetsTestCase): def setUp(self): super().setUp() @@ -454,7 +455,7 @@ def test_write_metadata_field(self): self.assertIn(f"{old_title} -> new title", output) -class MoveTest(_common.TestCase): +class MoveTest(BeetsTestCase): def setUp(self): super().setUp() @@ -562,7 +563,7 @@ def test_pretend_export_item(self): self.assertNotExists(self.otherdir) -class UpdateTest(_common.TestCase): +class UpdateTest(BeetsTestCase): def setUp(self): super().setUp() @@ -763,7 +764,7 @@ def test_modified_metadata_excluded(self): self.assertNotEqual(item.lyrics, "new lyrics") -class PrintTest(_common.TestCase): +class PrintTest(BeetsTestCase): def setUp(self): super().setUp() self.io.install() @@ -802,7 +803,7 @@ def test_print_with_invalid_locale(self): del os.environ["LC_CTYPE"] -class ImportTest(_common.TestCase): +class ImportTest(BeetsTestCase): def test_quiet_timid_disallowed(self): config["import"]["quiet"] = True config["import"]["timid"] = True @@ -1145,7 +1146,7 @@ def test_beetsdir_config_paths_resolve_relative_to_beetsdir(self): ) -class ShowModelChangeTest(_common.TestCase): +class ShowModelChangeTest(BeetsTestCase): def setUp(self): super().setUp() self.io.install() @@ -1197,7 +1198,7 @@ def test_both_values_shown(self): self.assertIn("bar", out) -class ShowChangeTest(_common.TestCase): +class ShowChangeTest(BeetsTestCase): def setUp(self): super().setUp() self.io.install() @@ -1358,7 +1359,7 @@ def test_item_data_change_wrap_newline(self): @patch("beets.library.Item.try_filesize", Mock(return_value=987)) -class SummarizeItemsTest(_common.TestCase): +class SummarizeItemsTest(BeetsTestCase): def setUp(self): super().setUp() item = library.Item() @@ -1395,7 +1396,7 @@ def test_summarize_items(self): self.assertEqual(summary, "3 items, G 2, F 1, 4kbps, 32:42, 2.9 KiB") -class PathFormatTest(_common.TestCase): +class PathFormatTest(BeetsTestCase): def test_custom_paths_prepend(self): default_formats = ui.get_path_formats() @@ -1408,7 +1409,7 @@ def test_custom_paths_prepend(self): @_common.slow_test() -class PluginTest(_common.TestCase, TestHelper): +class PluginTest(BeetsTestCase): def test_plugin_command_from_pluginpath(self): config["pluginpath"] = [_common.PLUGINPATH] config["plugins"] = ["test"] @@ -1416,7 +1417,7 @@ def test_plugin_command_from_pluginpath(self): @_common.slow_test() -class CompletionTest(_common.TestCase, TestHelper): +class CompletionTest(BeetsTestCase): def test_completion(self): # Load plugin commands config["pluginpath"] = [_common.PLUGINPATH] @@ -1652,7 +1653,7 @@ def test_add_all_common_options(self): ) -class EncodingTest(_common.TestCase): +class EncodingTest(BeetsTestCase): """Tests for the `terminal_encoding` config option and our `_in_encoding` and `_out_encoding` utility functions. """ diff --git a/test/test_ui_commands.py b/test/test_ui_commands.py index f371a1ab11..dfd8ffad00 100644 --- a/test/test_ui_commands.py +++ b/test/test_ui_commands.py @@ -22,11 +22,12 @@ from beets import library, ui from beets.test import _common +from beets.test.helper import BeetsTestCase, LibTestCase from beets.ui import commands from beets.util import syspath -class QueryTest(_common.TestCase): +class QueryTest(BeetsTestCase): def setUp(self): super().setUp() @@ -87,7 +88,7 @@ def test_query_album(self): self.check_do_query(0, 2, album=True, also_items=False) -class FieldsTest(_common.LibTestCase): +class FieldsTest(LibTestCase): def setUp(self): super().setUp() diff --git a/test/test_ui_init.py b/test/test_ui_init.py index 77c9c784b5..df1f36b97e 100644 --- a/test/test_ui_init.py +++ b/test/test_ui_init.py @@ -23,10 +23,10 @@ from beets import config, ui from beets.test import _common -from beets.test.helper import control_stdin +from beets.test.helper import BeetsTestCase, LibTestCase, control_stdin -class InputMethodsTest(_common.TestCase): +class InputMethodsTest(BeetsTestCase): def setUp(self): super().setUp() self.io.install() @@ -90,7 +90,7 @@ def test_input_select_objects(self): self.assertEqual(items, ["1", "3"]) -class InitTest(_common.LibTestCase): +class InitTest(LibTestCase): def setUp(self): super().setUp() @@ -129,7 +129,7 @@ def test_human_seconds(self): self.assertEqual(h, ui.human_seconds(i)) -class ParentalDirCreation(_common.TestCase): +class ParentalDirCreation(BeetsTestCase): def test_create_yes(self): non_exist_path = _common.os.fsdecode( os.path.join(self.temp_dir, b"nonexist", str(random()).encode()) diff --git a/test/test_util.py b/test/test_util.py index d2a7caea09..63de482ffb 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -24,6 +24,7 @@ from beets import util from beets.test import _common +from beets.test.helper import BeetsTestCase class UtilTest(unittest.TestCase): @@ -157,7 +158,7 @@ def test_case_sensitive_detects_insensitive(self): pass -class PathConversionTest(_common.TestCase): +class PathConversionTest(BeetsTestCase): def test_syspath_windows_format(self): with _common.platform_windows(): path = os.path.join("a", "b", "c") @@ -200,7 +201,7 @@ def test_bytesting_path_windows_removes_magic_prefix(self): self.assertEqual(outpath, "C:\\caf\xe9".encode()) -class PathTruncationTest(_common.TestCase): +class PathTruncationTest(BeetsTestCase): def test_truncate_bytestring(self): with _common.platform_posix(): p = util.truncate_path(b"abcde/fgh", 4) diff --git a/test/test_vfs.py b/test/test_vfs.py index 789356157f..939d44f73b 100644 --- a/test/test_vfs.py +++ b/test/test_vfs.py @@ -18,9 +18,10 @@ from beets import library, vfs from beets.test import _common +from beets.test.helper import BeetsTestCase -class VFSTest(_common.TestCase): +class VFSTest(BeetsTestCase): def setUp(self): super().setUp() self.lib = library.Library( From 6c1e26acc9383fa22956becb72d5c09298b7ffd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sun, 7 Jul 2024 18:02:51 +0100 Subject: [PATCH 04/29] Replace unittest.TestCase, TestHelper by BeetsTestCase --- test/plugins/test_advancedrewrite.py | 4 ++-- test/plugins/test_albumtypes.py | 5 ++--- test/plugins/test_bareasc.py | 4 ++-- test/plugins/test_bucket.py | 4 ++-- test/plugins/test_edit.py | 10 +++------- test/plugins/test_embedart.py | 4 ++-- test/plugins/test_embyupdate.py | 4 ++-- test/plugins/test_export.py | 4 ++-- test/plugins/test_fetchart.py | 4 ++-- test/plugins/test_ftintitle.py | 4 ++-- test/plugins/test_info.py | 4 ++-- test/plugins/test_ipfs.py | 4 ++-- test/plugins/test_keyfinder.py | 4 ++-- test/plugins/test_lastgenre.py | 4 ++-- test/plugins/test_limit.py | 4 ++-- test/plugins/test_mbsubmit.py | 4 ++-- test/plugins/test_mbsync.py | 4 ++-- test/plugins/test_mpdstats.py | 4 ++-- test/plugins/test_parentwork.py | 6 +++--- test/plugins/test_permissions.py | 4 ++-- test/plugins/test_play.py | 4 ++-- test/plugins/test_player.py | 4 ++-- test/plugins/test_playlist.py | 19 +++++++++--------- test/plugins/test_plexupdate.py | 4 ++-- test/plugins/test_random.py | 5 +---- test/plugins/test_thumbnails.py | 4 ++-- test/plugins/test_types_plugin.py | 4 ++-- test/plugins/test_zero.py | 4 ++-- test/test_config_command.py | 4 ++-- test/test_importer.py | 9 ++++----- test/test_library.py | 6 +++--- test/test_logging.py | 2 +- test/test_plugins.py | 4 ++-- test/test_query.py | 30 +++++++++++++++------------- test/test_ui.py | 11 +++++----- 35 files changed, 98 insertions(+), 105 deletions(-) diff --git a/test/plugins/test_advancedrewrite.py b/test/plugins/test_advancedrewrite.py index 71f92c4dd1..0d491f8a75 100644 --- a/test/plugins/test_advancedrewrite.py +++ b/test/plugins/test_advancedrewrite.py @@ -17,13 +17,13 @@ import unittest -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.ui import UserError PLUGIN_NAME = "advancedrewrite" -class AdvancedRewritePluginTest(unittest.TestCase, TestHelper): +class AdvancedRewritePluginTest(BeetsTestCase): def setUp(self): self.setup_beets() diff --git a/test/plugins/test_albumtypes.py b/test/plugins/test_albumtypes.py index 6b3b48d10b..4a32db3821 100644 --- a/test/plugins/test_albumtypes.py +++ b/test/plugins/test_albumtypes.py @@ -15,15 +15,14 @@ """Tests for the 'albumtypes' plugin.""" -import unittest from typing import Sequence, Tuple from beets.autotag.mb import VARIOUS_ARTISTS_ID -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug.albumtypes import AlbumTypesPlugin -class AlbumTypesPluginTest(unittest.TestCase, TestHelper): +class AlbumTypesPluginTest(BeetsTestCase): """Tests for albumtypes plugin.""" def setUp(self): diff --git a/test/plugins/test_bareasc.py b/test/plugins/test_bareasc.py index feb99953c1..02af15f8dd 100644 --- a/test/plugins/test_bareasc.py +++ b/test/plugins/test_bareasc.py @@ -6,10 +6,10 @@ import unittest from beets import logging -from beets.test.helper import TestHelper, capture_stdout +from beets.test.helper import BeetsTestCase, capture_stdout -class BareascPluginTest(unittest.TestCase, TestHelper): +class BareascPluginTest(BeetsTestCase): """Test bare ASCII query matching.""" def setUp(self): diff --git a/test/plugins/test_bucket.py b/test/plugins/test_bucket.py index 4f43f5ef5b..adae967b2e 100644 --- a/test/plugins/test_bucket.py +++ b/test/plugins/test_bucket.py @@ -18,11 +18,11 @@ import unittest from beets import config, ui -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import bucket -class BucketPluginTest(unittest.TestCase, TestHelper): +class BucketPluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.plugin = bucket.BucketPlugin() diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 7c1fcf0b30..32095748f6 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -21,9 +21,9 @@ from beets.test import _common from beets.test.helper import ( AutotagStub, + BeetsTestCase, ImportHelper, TerminalImportSessionSetup, - TestHelper, control_stdin, ) from beetsplug.edit import EditPlugin @@ -115,7 +115,7 @@ def run_mocked_command(self, modify_file_args={}, stdin=[], args=[]): @_common.slow_test() @patch("beets.library.Item.write") -class EditCommandTest(unittest.TestCase, TestHelper, EditMixin): +class EditCommandTest(BeetsTestCase, EditMixin): """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`. @@ -323,11 +323,7 @@ def test_invalid_yaml(self, mock_write): @_common.slow_test() class EditDuringImporterTest( - TerminalImportSessionSetup, - unittest.TestCase, - ImportHelper, - TestHelper, - EditMixin, + TerminalImportSessionSetup, BeetsTestCase, ImportHelper, EditMixin ): """TODO""" diff --git a/test/plugins/test_embedart.py b/test/plugins/test_embedart.py index d280fefd9b..4d78582b53 100644 --- a/test/plugins/test_embedart.py +++ b/test/plugins/test_embedart.py @@ -24,7 +24,7 @@ from beets import art, config, logging, ui from beets.test import _common -from beets.test.helper import FetchImageHelper, TestHelper +from beets.test.helper import BeetsTestCase, FetchImageHelper from beets.util import bytestring_path, displayable_path, syspath from beets.util.artresizer import ArtResizer @@ -40,7 +40,7 @@ def wrapper(*args, **kwargs): return wrapper -class EmbedartCliTest(TestHelper, FetchImageHelper): +class EmbedartCliTest(FetchImageHelper, BeetsTestCase): small_artpath = os.path.join(_common.RSRC, b"image-2x3.jpg") abbey_artpath = os.path.join(_common.RSRC, b"abbey.jpg") abbey_similarpath = os.path.join(_common.RSRC, b"abbey-similar.jpg") diff --git a/test/plugins/test_embyupdate.py b/test/plugins/test_embyupdate.py index 57859f5acf..a2d527c21d 100644 --- a/test/plugins/test_embyupdate.py +++ b/test/plugins/test_embyupdate.py @@ -2,11 +2,11 @@ import responses -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import embyupdate -class EmbyUpdateTest(unittest.TestCase, TestHelper): +class EmbyUpdateTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("embyupdate") diff --git a/test/plugins/test_export.py b/test/plugins/test_export.py index b949fe4f8c..746293130c 100644 --- a/test/plugins/test_export.py +++ b/test/plugins/test_export.py @@ -22,10 +22,10 @@ from xml.etree import ElementTree from xml.etree.ElementTree import Element -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase -class ExportPluginTest(unittest.TestCase, TestHelper): +class ExportPluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("export") diff --git a/test/plugins/test_fetchart.py b/test/plugins/test_fetchart.py index b3307472a8..61075c7929 100644 --- a/test/plugins/test_fetchart.py +++ b/test/plugins/test_fetchart.py @@ -19,10 +19,10 @@ import unittest from beets import util -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase -class FetchartCliTest(unittest.TestCase, TestHelper): +class FetchartCliTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("fetchart") diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index 60dd3668e4..923bf14efd 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -17,11 +17,11 @@ import unittest -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import ftintitle -class FtInTitlePluginFunctional(unittest.TestCase, TestHelper): +class FtInTitlePluginFunctional(BeetsTestCase): def setUp(self): """Set up configuration""" self.setup_beets() diff --git a/test/plugins/test_info.py b/test/plugins/test_info.py index bfba739c5a..bb8f97cf0a 100644 --- a/test/plugins/test_info.py +++ b/test/plugins/test_info.py @@ -17,11 +17,11 @@ from mediafile import MediaFile -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.util import displayable_path -class InfoTest(unittest.TestCase, TestHelper): +class InfoTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("info") diff --git a/test/plugins/test_ipfs.py b/test/plugins/test_ipfs.py index 65b7131016..dcea852886 100644 --- a/test/plugins/test_ipfs.py +++ b/test/plugins/test_ipfs.py @@ -18,13 +18,13 @@ from beets import library from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.util import _fsencoding, bytestring_path from beetsplug.ipfs import IPFSPlugin @patch("beets.util.command_output", Mock()) -class IPFSPluginTest(unittest.TestCase, TestHelper): +class IPFSPluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("ipfs") diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index 8509fe3571..329733b476 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -18,11 +18,11 @@ from beets import util from beets.library import Item -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase @patch("beets.util.command_output") -class KeyFinderTest(unittest.TestCase, TestHelper): +class KeyFinderTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("keyfinder") diff --git a/test/plugins/test_lastgenre.py b/test/plugins/test_lastgenre.py index 6f250c3ba4..bf36039df2 100644 --- a/test/plugins/test_lastgenre.py +++ b/test/plugins/test_lastgenre.py @@ -20,11 +20,11 @@ from beets import config from beets.test import _common -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import lastgenre -class LastGenrePluginTest(unittest.TestCase, TestHelper): +class LastGenrePluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.plugin = lastgenre.LastGenrePlugin() diff --git a/test/plugins/test_limit.py b/test/plugins/test_limit.py index 0ed6c92020..1ea57894c3 100644 --- a/test/plugins/test_limit.py +++ b/test/plugins/test_limit.py @@ -15,10 +15,10 @@ import unittest -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase -class LimitPluginTest(unittest.TestCase, TestHelper): +class LimitPluginTest(BeetsTestCase): """Unit tests for LimitPlugin Note: query prefix tests do not work correctly with `run_with_output`. diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index 40024bc714..e0821557b0 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -17,16 +17,16 @@ from beets.test.helper import ( AutotagStub, + BeetsTestCase, ImportHelper, TerminalImportSessionSetup, - TestHelper, capture_stdout, control_stdin, ) class MBSubmitPluginTest( - TerminalImportSessionSetup, unittest.TestCase, ImportHelper, TestHelper + TerminalImportSessionSetup, BeetsTestCase, ImportHelper ): def setUp(self): self.setup_beets() diff --git a/test/plugins/test_mbsync.py b/test/plugins/test_mbsync.py index bc41b34648..cc6837c519 100644 --- a/test/plugins/test_mbsync.py +++ b/test/plugins/test_mbsync.py @@ -19,14 +19,14 @@ from beets import config from beets.library import Item from beets.test.helper import ( - TestHelper, + BeetsTestCase, capture_log, generate_album_info, generate_track_info, ) -class MbsyncCliTest(unittest.TestCase, TestHelper): +class MbsyncCliTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("mbsync") diff --git a/test/plugins/test_mpdstats.py b/test/plugins/test_mpdstats.py index 40804fabb9..1dc9b3a6e2 100644 --- a/test/plugins/test_mpdstats.py +++ b/test/plugins/test_mpdstats.py @@ -18,11 +18,11 @@ from beets import util from beets.library import Item -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug.mpdstats import MPDStats -class MPDStatsTest(unittest.TestCase, TestHelper): +class MPDStatsTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("mpdstats") diff --git a/test/plugins/test_parentwork.py b/test/plugins/test_parentwork.py index 3777849830..372c1ed2f7 100644 --- a/test/plugins/test_parentwork.py +++ b/test/plugins/test_parentwork.py @@ -20,7 +20,7 @@ from unittest.mock import patch from beets.library import Item -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug import parentwork work = { @@ -85,7 +85,7 @@ def mock_workid_response(mbid, includes): return p_work -class ParentWorkIntegrationTest(unittest.TestCase, TestHelper): +class ParentWorkIntegrationTest(BeetsTestCase): def setUp(self): """Set up configuration""" self.setup_beets() @@ -180,7 +180,7 @@ def test_direct_parent_work_real(self): ) -class ParentWorkTest(unittest.TestCase, TestHelper): +class ParentWorkTest(BeetsTestCase): def setUp(self): """Set up configuration""" self.setup_beets() diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index d10a873cd5..82fb3c4435 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -7,7 +7,7 @@ from unittest.mock import Mock, patch from beets.test._common import touch -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.util import displayable_path from beetsplug.permissions import ( check_permissions, @@ -16,7 +16,7 @@ ) -class PermissionsPluginTest(unittest.TestCase, TestHelper): +class PermissionsPluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("permissions") diff --git a/test/plugins/test_play.py b/test/plugins/test_play.py index ac60e8281e..8dcf9d0445 100644 --- a/test/plugins/test_play.py +++ b/test/plugins/test_play.py @@ -20,14 +20,14 @@ import unittest from unittest.mock import ANY, patch -from beets.test.helper import CleanupModulesMixin, TestHelper, control_stdin +from beets.test.helper import BeetsTestCase, CleanupModulesMixin, control_stdin from beets.ui import UserError from beets.util import open_anything from beetsplug.play import PlayPlugin @patch("beetsplug.play.util.interactive_open") -class PlayPluginTest(CleanupModulesMixin, unittest.TestCase, TestHelper): +class PlayPluginTest(CleanupModulesMixin, BeetsTestCase): modules = (PlayPlugin.__module__,) def setUp(self): diff --git a/test/plugins/test_player.py b/test/plugins/test_player.py index f7c9c892d8..486808d33e 100644 --- a/test/plugins/test_player.py +++ b/test/plugins/test_player.py @@ -32,7 +32,7 @@ import confuse import yaml -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.util import bluelet from beetsplug import bpd @@ -277,7 +277,7 @@ def listener_wrap(host, port): beets.ui.main(args) -class BPDTestHelper(unittest.TestCase, TestHelper): +class BPDTestHelper(BeetsTestCase): def setUp(self): self.setup_beets(disk=True) self.load_plugins("bpd") diff --git a/test/plugins/test_playlist.py b/test/plugins/test_playlist.py index a4e6a91f93..63018ef680 100644 --- a/test/plugins/test_playlist.py +++ b/test/plugins/test_playlist.py @@ -18,10 +18,11 @@ from shlex import quote import beets -from beets.test import _common, helper +from beets.test import _common +from beets.test.helper import BeetsTestCase -class PlaylistTestHelper(helper.TestHelper): +class PlaylistTestCase(BeetsTestCase): def setUp(self): self.setup_beets() self.lib = beets.library.Library(":memory:") @@ -88,7 +89,7 @@ def tearDown(self): self.teardown_beets() -class PlaylistQueryTestHelper(PlaylistTestHelper): +class PlaylistQueryTest: def test_name_query_with_absolute_paths_in_playlist(self): q = "playlist:absolute" results = self.lib.items(q) @@ -166,7 +167,7 @@ def test_path_query_with_nonexisting_playlist(self): self.assertEqual(set(results), set()) -class PlaylistTestRelativeToLib(PlaylistQueryTestHelper, unittest.TestCase): +class PlaylistTestRelativeToLib(PlaylistQueryTest, PlaylistTestCase): def setup_test(self): with open(os.path.join(self.playlist_dir, "absolute.m3u"), "w") as f: f.write( @@ -187,7 +188,7 @@ def setup_test(self): self.config["playlist"]["relative_to"] = "library" -class PlaylistTestRelativeToDir(PlaylistQueryTestHelper, unittest.TestCase): +class PlaylistTestRelativeToDir(PlaylistQueryTest, PlaylistTestCase): def setup_test(self): with open(os.path.join(self.playlist_dir, "absolute.m3u"), "w") as f: f.write( @@ -208,7 +209,7 @@ def setup_test(self): self.config["playlist"]["relative_to"] = self.music_dir -class PlaylistTestRelativeToPls(PlaylistQueryTestHelper, unittest.TestCase): +class PlaylistTestRelativeToPls(PlaylistQueryTest, PlaylistTestCase): def setup_test(self): with open(os.path.join(self.playlist_dir, "absolute.m3u"), "w") as f: f.write( @@ -251,7 +252,7 @@ def setup_test(self): self.config["playlist"]["playlist_dir"] = self.playlist_dir -class PlaylistUpdateTestHelper(PlaylistTestHelper): +class PlaylistUpdateTest: def setup_test(self): with open(os.path.join(self.playlist_dir, "absolute.m3u"), "w") as f: f.write( @@ -273,7 +274,7 @@ def setup_test(self): self.config["playlist"]["relative_to"] = "library" -class PlaylistTestItemMoved(PlaylistUpdateTestHelper, unittest.TestCase): +class PlaylistTestItemMoved(PlaylistUpdateTest, PlaylistTestCase): def test_item_moved(self): # Emit item_moved event for an item that is in a playlist results = self.lib.items( @@ -339,7 +340,7 @@ def test_item_moved(self): ) -class PlaylistTestItemRemoved(PlaylistUpdateTestHelper, unittest.TestCase): +class PlaylistTestItemRemoved(PlaylistUpdateTest, PlaylistTestCase): def test_item_removed(self): # Emit item_removed event for an item that is in a playlist results = self.lib.items( diff --git a/test/plugins/test_plexupdate.py b/test/plugins/test_plexupdate.py index f45ea9d8f9..e8e7b83b43 100644 --- a/test/plugins/test_plexupdate.py +++ b/test/plugins/test_plexupdate.py @@ -2,11 +2,11 @@ import responses -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beetsplug.plexupdate import get_music_section, update_plex -class PlexUpdateTest(unittest.TestCase, TestHelper): +class PlexUpdateTest(BeetsTestCase): def add_response_get_music_section(self, section_name="Music"): """Create response for mocking the get_music_section function.""" diff --git a/test/plugins/test_random.py b/test/plugins/test_random.py index b371fa8323..842e018ebd 100644 --- a/test/plugins/test_random.py +++ b/test/plugins/test_random.py @@ -24,7 +24,7 @@ from beets.test.helper import TestHelper -class RandomTest(unittest.TestCase, TestHelper): +class RandomTest(TestHelper, unittest.TestCase): def setUp(self): self.lib = None self.artist1 = "Artist 1" @@ -37,9 +37,6 @@ def setUp(self): self.random_gen = Random() self.random_gen.seed(12345) - def tearDown(self): - pass - def _stats(self, data): mean = sum(data) / len(data) stdev = math.sqrt(sum((p - mean) ** 2 for p in data) / (len(data) - 1)) diff --git a/test/plugins/test_thumbnails.py b/test/plugins/test_thumbnails.py index 951fc6e8ce..942b91db0d 100644 --- a/test/plugins/test_thumbnails.py +++ b/test/plugins/test_thumbnails.py @@ -19,7 +19,7 @@ from tempfile import mkdtemp from unittest.mock import Mock, call, patch -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase from beets.util import bytestring_path, syspath from beetsplug.thumbnails import ( LARGE_DIR, @@ -30,7 +30,7 @@ ) -class ThumbnailsTest(unittest.TestCase, TestHelper): +class ThumbnailsTest(BeetsTestCase): def setUp(self): self.setup_beets() diff --git a/test/plugins/test_types_plugin.py b/test/plugins/test_types_plugin.py index 8225c33025..54766e7aa7 100644 --- a/test/plugins/test_types_plugin.py +++ b/test/plugins/test_types_plugin.py @@ -19,10 +19,10 @@ from confuse import ConfigValueError -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase -class TypesPluginTest(unittest.TestCase, TestHelper): +class TypesPluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.load_plugins("types") diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index 378e419d50..1925bd464d 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -5,12 +5,12 @@ from mediafile import MediaFile from beets.library import Item -from beets.test.helper import TestHelper, control_stdin +from beets.test.helper import BeetsTestCase, control_stdin from beets.util import syspath from beetsplug.zero import ZeroPlugin -class ZeroPluginTest(unittest.TestCase, TestHelper): +class ZeroPluginTest(BeetsTestCase): def setUp(self): self.setup_beets() self.config["zero"] = { diff --git a/test/test_config_command.py b/test/test_config_command.py index 0b122cf1cf..72a0affd9c 100644 --- a/test/test_config_command.py +++ b/test/test_config_command.py @@ -5,10 +5,10 @@ import yaml from beets import config, ui -from beets.test.helper import TestHelper +from beets.test.helper import BeetsTestCase -class ConfigCommandTest(unittest.TestCase, TestHelper): +class ConfigCommandTest(BeetsTestCase): def setUp(self): self.setup_beets() for k in ("VISUAL", "EDITOR"): diff --git a/test/test_importer.py b/test/test_importer.py index 8c2b474e07..f3a255e4e4 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -38,7 +38,6 @@ AutotagStub, BeetsTestCase, ImportHelper, - TestHelper, capture_log, has_program, ) @@ -1171,7 +1170,7 @@ def match_album_mock(*args, **kwargs): @patch("beets.autotag.mb.match_album", Mock(side_effect=match_album_mock)) -class ImportDuplicateAlbumTest(unittest.TestCase, TestHelper): +class ImportDuplicateAlbumTest(BeetsTestCase): def setUp(self): self.setup_beets() @@ -1293,7 +1292,7 @@ def match_track_mock(*args, **kwargs): @patch("beets.autotag.mb.match_track", Mock(side_effect=match_track_mock)) -class ImportDuplicateSingletonTest(unittest.TestCase, TestHelper): +class ImportDuplicateSingletonTest(BeetsTestCase): def setUp(self): self.setup_beets() @@ -1382,7 +1381,7 @@ def test_tag_log_unicode(self): self.assertIn("status caf\xe9", sio.getvalue()) -class ResumeImportTest(unittest.TestCase, TestHelper): +class ResumeImportTest(BeetsTestCase): def setUp(self): self.setup_beets() @@ -1433,7 +1432,7 @@ def raise_exception(event, **kwargs): self.assertIsNotNone(self.lib.items("title:track 1").get()) -class IncrementalImportTest(unittest.TestCase, TestHelper): +class IncrementalImportTest(BeetsTestCase): def setUp(self): self.setup_beets() self.config["import"]["incremental"] = True diff --git a/test/test_library.py b/test/test_library.py index 179927dc95..7d27604d6e 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -32,7 +32,7 @@ from beets import config, plugins, util from beets.test import _common from beets.test._common import item -from beets.test.helper import BeetsTestCase, LibTestCase, TestHelper +from beets.test.helper import BeetsTestCase, LibTestCase from beets.util import bytestring_path, syspath # Shortcut to path normalization. @@ -1267,7 +1267,7 @@ def test_unicode_path(self): self.i.write() -class WriteTest(unittest.TestCase, TestHelper): +class WriteTest(BeetsTestCase): def setUp(self): self.setup_beets() @@ -1355,7 +1355,7 @@ def test_nonexistent_raise_read_error(self): item.read("/thisfiledoesnotexist") -class FilesizeTest(unittest.TestCase, TestHelper): +class FilesizeTest(BeetsTestCase): def setUp(self): self.setup_beets() diff --git a/test/test_logging.py b/test/test_logging.py index db7f33bfd6..0cd3d48210 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -47,7 +47,7 @@ def test_str_format_logging(self): self.assertTrue(stream.getvalue(), "foo oof baz") -class LoggingLevelTest(unittest.TestCase, helper.TestHelper): +class LoggingLevelTest(BeetsTestCase): class DummyModule: class DummyPlugin(plugins.BeetsPlugin): def __init__(self): diff --git a/test/test_plugins.py b/test/test_plugins.py index 707c7db31a..284cee041e 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -35,9 +35,9 @@ from beets.test._common import RSRC from beets.test.helper import ( AutotagStub, + BeetsTestCase, ImportHelper, TerminalImportSessionSetup, - TestHelper, ) from beets.util import bytestring_path, displayable_path, syspath from beets.util.id_extractors import ( @@ -47,7 +47,7 @@ ) -class PluginLoaderTestCase(unittest.TestCase, TestHelper): +class PluginLoaderTestCase(BeetsTestCase): def setup_plugin_loader(self): # FIXME the mocking code is horrific, but this is the lowest and # earliest level of the plugin mechanism we can hook into. diff --git a/test/test_query.py b/test/test_query.py index 897b247dc5..a5a2091bf8 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -30,7 +30,7 @@ ParsingError, ) from beets.library import Item, Library -from beets.test import _common, helper +from beets.test import _common from beets.test.helper import BeetsTestCase, LibTestCase from beets.util import syspath @@ -39,7 +39,13 @@ WIN32_NO_IMPLICIT_PATHS = "Implicit paths are not supported on Windows" -class TestHelper(helper.TestHelper): +class AssertsMixin: + def assert_items_matched(self, results, titles): + self.assertEqual({i.title for i in results}, set(titles)) + + def assert_albums_matched(self, results, albums): + self.assertEqual({a.album for a in results}, set(albums)) + def assertInResult(self, item, results): # noqa result_ids = [i.id for i in results] self.assertIn(item.id, result_ids) @@ -83,14 +89,6 @@ def test_eq(self): self.assertNotEqual(q1, q2) -class AssertsMixin: - def assert_items_matched(self, results, titles): - self.assertEqual({i.title for i in results}, set(titles)) - - def assert_albums_matched(self, results, albums): - self.assertEqual({a.album for a in results}, set(albums)) - - # A test case class providing a library with some dummy data and some # assertions involving that data. class DummyDataTestCase(BeetsTestCase, AssertsMixin): @@ -488,7 +486,7 @@ def test_eq(self): self.assertNotEqual(q3, q4) -class PathQueryTest(LibTestCase, TestHelper, AssertsMixin): +class PathQueryTest(LibTestCase, AssertsMixin): def setUp(self): super().setUp() @@ -726,11 +724,12 @@ def test_detect_relative_path(self): os.chdir(cur_dir) -class IntQueryTest(unittest.TestCase, TestHelper): +class IntQueryTest(BeetsTestCase): def setUp(self): self.lib = Library(":memory:") def tearDown(self): + super().tearDown() Item._types = {} def test_exact_value_match(self): @@ -764,12 +763,14 @@ def test_no_substring_match(self): self.assertIsNone(matched) -class BoolQueryTest(unittest.TestCase, TestHelper): +class BoolQueryTest(BeetsTestCase, AssertsMixin): def setUp(self): + super().setUp() self.lib = Library(":memory:") Item._types = {"flexbool": types.Boolean()} def tearDown(self): + super().tearDown() Item._types = {} def test_parse_true(self): @@ -834,8 +835,9 @@ def test_items_does_not_match_year(self): self.assert_items_matched(items, []) -class NoneQueryTest(unittest.TestCase, TestHelper): +class NoneQueryTest(BeetsTestCase, AssertsMixin): def setUp(self): + super().setUp() self.lib = Library(":memory:") def test_match_singletons(self): diff --git a/test/test_ui.py b/test/test_ui.py index 9ca68992ad..8b3ef7276f 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -32,7 +32,6 @@ from beets.test import _common from beets.test.helper import ( BeetsTestCase, - TestHelper, capture_stdout, control_stdin, has_program, @@ -190,7 +189,7 @@ def test_remove_albums_select_with_delete(self): self.assertEqual(num_existing, 1) -class ModifyTest(unittest.TestCase, TestHelper): +class ModifyTest(BeetsTestCase): def setUp(self): self.setup_beets() self.album = self.add_album_fixture() @@ -404,7 +403,7 @@ def test_arg_parsing_equals_in_value(self): self.assertEqual(mods, {"title": "newTitle"}) -class WriteTest(unittest.TestCase, TestHelper): +class WriteTest(BeetsTestCase): def setUp(self): self.setup_beets() @@ -845,7 +844,7 @@ def test_parse_paths_from_logfile(self): @_common.slow_test() -class ConfigTest(unittest.TestCase, TestHelper): +class ConfigTest(BeetsTestCase): def setUp(self): self.setup_beets() @@ -1469,7 +1468,7 @@ def test_completion(self): ) -class CommonOptionsParserCliTest(unittest.TestCase, TestHelper): +class CommonOptionsParserCliTest(BeetsTestCase): """Test CommonOptionsParser and formatting LibModel formatting on 'list' command. """ @@ -1552,7 +1551,7 @@ def test_version(self): # self.assertIn('plugins: ', l) -class CommonOptionsParserTest(unittest.TestCase, TestHelper): +class CommonOptionsParserTest(BeetsTestCase): def setUp(self): self.setup_beets() From 0b5b94460a7bb8cf8b8a74eee26ae95d208b701a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Wed, 3 Jul 2024 12:01:41 +0100 Subject: [PATCH 05/29] Replace unittest.TestCase, ImportHelper by ImportTestCase --- beets/test/helper.py | 6 +++++- test/plugins/test_edit.py | 4 ++-- test/plugins/test_filefilter.py | 4 ++-- test/plugins/test_importadded.py | 4 ++-- test/plugins/test_mbsubmit.py | 7 ++----- test/test_importer.py | 30 +++++++++++++++--------------- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 6cb45e828f..24659d1d7e 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -535,7 +535,7 @@ def tearDown(self): super().tearDown() -class ImportHelper(TestHelper): +class ImportHelper: """Provides tools to setup a library, a directory containing files that are to be imported and an import session. The class also provides stubs for the autotagging library and several assertions for the library. @@ -644,6 +644,10 @@ def assert_lib_dir_empty(self): self.assertEqual(len(os.listdir(syspath(self.libdir))), 0) +class ImportTestCase(ImportHelper, BeetsTestCase): + pass + + class ImportSessionFixture(importer.ImportSession): """ImportSession that can be controlled programaticaly. diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 32095748f6..7e06e7a1c2 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -22,7 +22,7 @@ from beets.test.helper import ( AutotagStub, BeetsTestCase, - ImportHelper, + ImportTestCase, TerminalImportSessionSetup, control_stdin, ) @@ -323,7 +323,7 @@ def test_invalid_yaml(self, mock_write): @_common.slow_test() class EditDuringImporterTest( - TerminalImportSessionSetup, BeetsTestCase, ImportHelper, EditMixin + TerminalImportSessionSetup, ImportTestCase, EditMixin ): """TODO""" diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index 10eed77c4b..a97fc5f325 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -24,12 +24,12 @@ from beets import config from beets.test import _common -from beets.test.helper import ImportHelper, capture_log +from beets.test.helper import ImportTestCase, capture_log from beets.util import bytestring_path, displayable_path, syspath from beetsplug.filefilter import FileFilterPlugin -class FileFilterPluginTest(unittest.TestCase, ImportHelper): +class FileFilterPluginTest(ImportTestCase): def setUp(self): self.setup_beets() self.__create_import_dir(2) diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index 647892e1d7..baa9f880b0 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -19,7 +19,7 @@ import unittest from beets import importer -from beets.test.helper import AutotagStub, ImportHelper +from beets.test.helper import AutotagStub, ImportTestCase from beets.util import displayable_path, syspath from beetsplug.importadded import ImportAddedPlugin @@ -40,7 +40,7 @@ def modify_mtimes(paths, offset=-60000): os.utime(syspath(path), (mstat.st_atime, mstat.st_mtime + offset * i)) -class ImportAddedTest(unittest.TestCase, ImportHelper): +class ImportAddedTest(ImportTestCase): # The minimum mtime of the files to be imported min_mtime = None diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index e0821557b0..f97e389c57 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -17,17 +17,14 @@ from beets.test.helper import ( AutotagStub, - BeetsTestCase, - ImportHelper, + ImportTestCase, TerminalImportSessionSetup, capture_stdout, control_stdin, ) -class MBSubmitPluginTest( - TerminalImportSessionSetup, BeetsTestCase, ImportHelper -): +class MBSubmitPluginTest(TerminalImportSessionSetup, ImportTestCase): def setUp(self): self.setup_beets() self.load_plugins("mbsubmit") diff --git a/test/test_importer.py b/test/test_importer.py index f3a255e4e4..95e8fd933a 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -37,14 +37,14 @@ from beets.test.helper import ( AutotagStub, BeetsTestCase, - ImportHelper, + ImportTestCase, capture_log, has_program, ) from beets.util import bytestring_path, displayable_path, syspath -class ScrubbedImportTest(BeetsTestCase, ImportHelper): +class ScrubbedImportTest(ImportTestCase): def setUp(self): self.setup_beets(disk=True) self.load_plugins("scrub") @@ -99,7 +99,7 @@ def test_tags_not_restored(self): @_common.slow_test() -class NonAutotaggedImportTest(BeetsTestCase, ImportHelper): +class NonAutotaggedImportTest(ImportTestCase): def setUp(self): self.setup_beets(disk=True) self._create_import_dir(2) @@ -271,7 +271,7 @@ def create_archive(session): return path -class RmTempTest(unittest.TestCase, ImportHelper): +class RmTempTest(ImportTestCase): """Tests that temporarily extracted archives are properly removed after usage. """ @@ -296,7 +296,7 @@ def test_rm(self): self.assertNotExists(tmp_path) -class ImportZipTest(unittest.TestCase, ImportHelper): +class ImportZipTest(ImportTestCase): def setUp(self): self.setup_beets() @@ -344,7 +344,7 @@ def create_archive(self): return os.path.join(_common.RSRC, b"password.rar") -class ImportSingletonTest(BeetsTestCase, ImportHelper): +class ImportSingletonTest(ImportTestCase): """Test ``APPLY`` and ``ASIS`` choices for an import session with singletons config set to True. """ @@ -467,7 +467,7 @@ def test_set_fields(self): self.assertEqual(item.title, "Applied Title 1 - formatted") -class ImportTest(BeetsTestCase, ImportHelper): +class ImportTest(ImportTestCase): """Test APPLY, ASIS and SKIP choices.""" def setUp(self): @@ -681,7 +681,7 @@ def test_set_fields(self): ) -class ImportTracksTest(BeetsTestCase, ImportHelper): +class ImportTracksTest(ImportTestCase): """Test TRACKS and APPLY choice.""" def setUp(self): @@ -715,7 +715,7 @@ def test_apply_tracks_adds_singleton_path(self): self.assert_file_in_lib(b"singletons", b"Applied Title 1.mp3") -class ImportCompilationTest(BeetsTestCase, ImportHelper): +class ImportCompilationTest(ImportTestCase): """Test ASIS import of a folder containing tracks with different artists.""" def setUp(self): @@ -834,7 +834,7 @@ def test_asis_albumartists_tag_sets_multi_albumartists(self): self.assertTrue(asserted_multi_artists_0 and asserted_multi_artists_1) -class ImportExistingTest(BeetsTestCase, ImportHelper): +class ImportExistingTest(ImportTestCase): """Test importing files that are already in the library directory.""" def setUp(self): @@ -959,7 +959,7 @@ def test_outside_file_is_moved(self): self.assertNotExists(self.import_media[0].path) -class GroupAlbumsImportTest(BeetsTestCase, ImportHelper): +class GroupAlbumsImportTest(ImportTestCase): def setUp(self): self.setup_beets() self._create_import_dir(3) @@ -1031,7 +1031,7 @@ def setUp(self): config["import"]["group_albums"] = True -class ChooseCandidateTest(BeetsTestCase, ImportHelper): +class ChooseCandidateTest(ImportTestCase): def setUp(self): self.setup_beets() self._create_import_dir(1) @@ -1646,7 +1646,7 @@ def test_coalesce_multiple_unicode(self): self.assertEqual(len(items), 3) -class ReimportTest(unittest.TestCase, ImportHelper): +class ReimportTest(ImportTestCase): """Test "re-imports", in which the autotagging machinery is used for music that's already in the library. @@ -1751,7 +1751,7 @@ def test_reimported_album_not_preserves_flexattr(self): self.assertEqual(self._album().data_source, "match_source") -class ImportPretendTest(BeetsTestCase, ImportHelper): +class ImportPretendTest(ImportTestCase): """Test the pretend commandline option""" def __init__(self, method_name="runTest"): @@ -1944,7 +1944,7 @@ def mocked_get_recording_by_id( "musicbrainzngs.get_release_by_id", Mock(side_effect=mocked_get_release_by_id), ) -class ImportMusicBrainzIdTest(BeetsTestCase, ImportHelper): +class ImportMusicBrainzIdTest(ImportTestCase): """Test the --musicbrainzid argument.""" MB_RELEASE_PREFIX = "https://musicbrainz.org/release/" From 8373181e020bacdbbdefa84554c1fb15faa55363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Wed, 3 Jul 2024 12:26:56 +0100 Subject: [PATCH 06/29] Create PluginImportTestCase in test_plugins This involves making EventsTest use _create_import_dir from TestHelper. --- test/test_plugins.py | 69 +++++++++++++------------------------------- 1 file changed, 20 insertions(+), 49 deletions(-) diff --git a/test/test_plugins.py b/test/test_plugins.py index 284cee041e..acf703e46c 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -15,7 +15,6 @@ import itertools import os -import shutil import unittest from unittest.mock import ANY, Mock, patch @@ -32,14 +31,13 @@ from beets.library import Item from beets.plugins import MetadataSourcePlugin from beets.test import helper -from beets.test._common import RSRC from beets.test.helper import ( AutotagStub, BeetsTestCase, ImportHelper, TerminalImportSessionSetup, ) -from beets.util import bytestring_path, displayable_path, syspath +from beets.util import displayable_path, syspath from beets.util.id_extractors import ( beatport_id_regex, deezer_id_regex, @@ -77,6 +75,12 @@ def tearDown(self): self.teardown_beets() +class PluginImportTestCase(ImportHelper, PluginLoaderTestCase): + def setUp(self): + super().setUp() + self._create_import_dir(2) + + class ItemTypesTest(PluginLoaderTestCase): def test_flex_field_type(self): class RatingPlugin(plugins.BeetsPlugin): @@ -158,47 +162,11 @@ class AdventListenerPlugin(plugins.BeetsPlugin): self.assertIsNotNone(plugins.types(Item)) -class EventsTest(ImportHelper, PluginLoaderTestCase): +class EventsTest(PluginImportTestCase): def setUp(self): super().setUp() - self.__create_import_dir(2) config["import"]["pretend"] = True - def __copy_file(self, dest_path, metadata): - # Copy files - resource_path = os.path.join(RSRC, b"full.mp3") - shutil.copy(syspath(resource_path), syspath(dest_path)) - medium = MediaFile(dest_path) - # Set metadata - for attr in metadata: - setattr(medium, attr, metadata[attr]) - medium.save() - - def __create_import_dir(self, count): - self.import_dir = os.path.join(self.temp_dir, b"testsrcdir") - if os.path.isdir(syspath(self.import_dir)): - shutil.rmtree(syspath(self.import_dir)) - - self.album_path = os.path.join(self.import_dir, b"album") - os.makedirs(self.album_path) - - metadata = { - "artist": "Tag Artist", - "album": "Tag Album", - "albumartist": None, - "mb_trackid": None, - "mb_albumid": None, - "comp": None, - } - self.file_paths = [] - for i in range(count): - metadata["track"] = i + 1 - metadata["title"] = "Tag Title Album %d" % (i + 1) - track_file = bytestring_path("%02d - track.mp3" % (i + 1)) - dest_path = os.path.join(self.album_path, track_file) - self.__copy_file(dest_path, metadata) - self.file_paths.append(dest_path) - def test_import_task_created(self): import_files = [self.import_dir] self._setup_import_session(singletons=False) @@ -217,10 +185,12 @@ def test_import_task_created(self): logs, [ "Album: {}".format( - displayable_path(os.path.join(self.import_dir, b"album")) + displayable_path( + os.path.join(self.import_dir, b"the_album") + ) ), - " {}".format(displayable_path(self.file_paths[0])), - " {}".format(displayable_path(self.file_paths[1])), + " {}".format(displayable_path(self.media_files[0].path)), + " {}".format(displayable_path(self.media_files[1].path)), ], ) @@ -266,8 +236,12 @@ def import_task_created_event(self, session, task): self.assertEqual( logs, [ - "Singleton: {}".format(displayable_path(self.file_paths[0])), - "Singleton: {}".format(displayable_path(self.file_paths[1])), + "Singleton: {}".format( + displayable_path(self.media_files[0].path) + ), + "Singleton: {}".format( + displayable_path(self.media_files[1].path) + ), ], ) @@ -403,12 +377,9 @@ def dummy9(self, **kwargs): plugins.send("event9", foo=5) -class PromptChoicesTest( - TerminalImportSessionSetup, ImportHelper, PluginLoaderTestCase -): +class PromptChoicesTest(TerminalImportSessionSetup, PluginImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(3) self._setup_import_session() self.matcher = AutotagStub().install() # keep track of ui.input_option() calls From 6ccf33d79e4a021a0e6e64148b4ce98bbe420e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Wed, 3 Jul 2024 16:32:48 +0100 Subject: [PATCH 07/29] test_replaygain: restructure tests to share setup --- test/plugins/test_replaygain.py | 93 +++++++++++++++------------------ 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index 92e3e5f650..d8082b0afd 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -14,11 +14,12 @@ import unittest +from typing import ClassVar from mediafile import MediaFile from beets import config -from beets.test.helper import TestHelper, has_program +from beets.test.helper import BeetsTestCase, has_program from beetsplug.replaygain import ( FatalGstreamerPluginReplayGainError, GStreamerBackend, @@ -51,6 +52,34 @@ def reset_replaygain(item): item.store() +class ReplayGainTestCase(BeetsTestCase): + backend: ClassVar[str] + + def setUp(self): + # Implemented by Mixins, see above. This may decide to skip the test. + self.test_backend() + + self.setup_beets(disk=True) + self.config["replaygain"]["backend"] = self.backend + + try: + self.load_plugins("replaygain") + except Exception: + self.tearDown() + + self.importer = self.create_importer() + + def tearDown(self): + self.unload_plugins() + super().tearDown() + + +class ThreadedImportMixin: + def setUp(self): + super().setUp() + self.config["threaded"] = True + + class GstBackendMixin: backend = "gstreamer" has_r128_support = True @@ -85,22 +114,9 @@ def test_backend(self): pass -class ReplayGainCliTestBase(TestHelper): +class ReplayGainCliTest: FNAME: str - def setUp(self): - # Implemented by Mixins, see above. This may decide to skip the test. - self.test_backend() - - self.setup_beets(disk=True) - self.config["replaygain"]["backend"] = self.backend - - try: - self.load_plugins("replaygain") - except Exception: - self.teardown_beets() - self.unload_plugins() - def _add_album(self, *args, **kwargs): # Use a file with non-zero volume (most test assets are total silence) album = self.add_album_fixture(*args, fname=self.FNAME, **kwargs) @@ -109,10 +125,6 @@ def _add_album(self, *args, **kwargs): return album - def tearDown(self): - self.teardown_beets() - self.unload_plugins() - def test_cli_saves_track_gain(self): self._add_album(2) @@ -320,55 +332,33 @@ def test_per_disc(self): @unittest.skipIf(not GST_AVAILABLE, "gstreamer cannot be found") class ReplayGainGstCliTest( - ReplayGainCliTestBase, unittest.TestCase, GstBackendMixin + ReplayGainCliTest, ReplayGainTestCase, GstBackendMixin ): FNAME = "full" # file contains only silence @unittest.skipIf(not GAIN_PROG_AVAILABLE, "no *gain command found") class ReplayGainCmdCliTest( - ReplayGainCliTestBase, unittest.TestCase, CmdBackendMixin + ReplayGainCliTest, ReplayGainTestCase, CmdBackendMixin ): FNAME = "full" # file contains only silence @unittest.skipIf(not FFMPEG_AVAILABLE, "ffmpeg cannot be found") class ReplayGainFfmpegCliTest( - ReplayGainCliTestBase, unittest.TestCase, FfmpegBackendMixin + ReplayGainCliTest, ReplayGainTestCase, FfmpegBackendMixin ): FNAME = "full" # file contains only silence @unittest.skipIf(not FFMPEG_AVAILABLE, "ffmpeg cannot be found") class ReplayGainFfmpegNoiseCliTest( - ReplayGainCliTestBase, unittest.TestCase, FfmpegBackendMixin + ReplayGainCliTest, ReplayGainTestCase, FfmpegBackendMixin ): FNAME = "whitenoise" -class ImportTest(TestHelper): - threaded = False - - def setUp(self): - # Implemented by Mixins, see above. This may decide to skip the test. - self.test_backend() - - self.setup_beets(disk=True) - self.config["threaded"] = self.threaded - self.config["replaygain"]["backend"] = self.backend - - try: - self.load_plugins("replaygain") - except Exception: - self.teardown_beets() - self.unload_plugins() - - self.importer = self.create_importer() - - def tearDown(self): - self.unload_plugins() - self.teardown_beets() - +class ImportTest: def test_import_converted(self): self.importer.run() for item in self.lib.items(): @@ -380,27 +370,27 @@ def test_import_converted(self): @unittest.skipIf(not GST_AVAILABLE, "gstreamer cannot be found") -class ReplayGainGstImportTest(ImportTest, unittest.TestCase, GstBackendMixin): +class ReplayGainGstImportTest(ImportTest, ReplayGainTestCase, GstBackendMixin): pass @unittest.skipIf(not GAIN_PROG_AVAILABLE, "no *gain command found") -class ReplayGainCmdImportTest(ImportTest, unittest.TestCase, CmdBackendMixin): +class ReplayGainCmdImportTest(ImportTest, ReplayGainTestCase, CmdBackendMixin): pass @unittest.skipIf(not FFMPEG_AVAILABLE, "ffmpeg cannot be found") class ReplayGainFfmpegImportTest( - ImportTest, unittest.TestCase, FfmpegBackendMixin + ImportTest, ReplayGainTestCase, FfmpegBackendMixin ): pass @unittest.skipIf(not FFMPEG_AVAILABLE, "ffmpeg cannot be found") class ReplayGainFfmpegThreadedImportTest( - ImportTest, unittest.TestCase, FfmpegBackendMixin + ThreadedImportMixin, ImportTest, ReplayGainTestCase, FfmpegBackendMixin ): - threaded = True + pass def suite(): @@ -409,3 +399,4 @@ def suite(): if __name__ == "__main__": unittest.main(defaultTest="suite") + unittest.main(defaultTest="suite") From 91099d362e5eb7976732559556ce7c2c84e99cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 29 Jun 2024 18:18:26 +0100 Subject: [PATCH 08/29] Deduplicate TerminalImportHelper and rename to TerminalImportMixin --- beets/test/helper.py | 58 ++++++++++++----------------------- test/plugins/test_edit.py | 6 ++-- test/plugins/test_mbsubmit.py | 4 +-- test/test_plugins.py | 4 +-- test/test_ui_importer.py | 24 ++++++--------- 5 files changed, 36 insertions(+), 60 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 24659d1d7e..1499bd1257 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -541,6 +541,8 @@ class ImportHelper: autotagging library and several assertions for the library. """ + importer: importer.ImportSession + def setup_beets(self, disk=False): super().setup_beets(disk) self.lib.path_formats = [ @@ -598,35 +600,33 @@ def _create_import_dir(self, count=3): self.media_files.append(medium) self.import_media = self.media_files + def _get_import_session(self, import_dir: str) -> None: + self.importer = ImportSessionFixture( + self.lib, + loghandler=None, + query=None, + paths=[import_dir], + ) + def _setup_import_session( self, import_dir=None, - delete=False, - threaded=False, - copy=True, singletons=False, move=False, autotag=True, - link=False, - hardlink=False, ): - config["import"]["copy"] = copy - config["import"]["delete"] = delete + config["import"]["copy"] = True + config["import"]["delete"] = False config["import"]["timid"] = True config["threaded"] = False config["import"]["singletons"] = singletons config["import"]["move"] = move config["import"]["autotag"] = autotag config["import"]["resume"] = False - config["import"]["link"] = link - config["import"]["hardlink"] = hardlink + config["import"]["link"] = False + config["import"]["hardlink"] = False - self.importer = ImportSessionFixture( - self.lib, - loghandler=None, - query=None, - paths=[import_dir or self.import_dir], - ) + self._get_import_session(import_dir or self.import_dir) def assert_file_in_lib(self, *segments): """Join the ``segments`` and assert that this path exists in the @@ -759,37 +759,17 @@ def _add_choice_input(self): raise Exception("Unknown choice %s" % choice) -class TerminalImportSessionSetup: - """Overwrites ImportHelper._setup_import_session to provide a terminal importer""" - - def _setup_import_session( - self, - import_dir=None, - delete=False, - threaded=False, - copy=True, - singletons=False, - move=False, - autotag=True, - ): - config["import"]["copy"] = copy - config["import"]["delete"] = delete - config["import"]["timid"] = True - config["threaded"] = False - config["import"]["singletons"] = singletons - config["import"]["move"] = move - config["import"]["autotag"] = autotag - config["import"]["resume"] = False +class TerminalImportMixin(ImportHelper): + """Provides_a terminal importer for the import session.""" - if not hasattr(self, "io"): - self.io = _common.DummyIO() + def _get_import_session(self, import_dir: str) -> None: self.io.install() self.importer = TerminalImportSessionFixture( self.lib, loghandler=None, query=None, io=self.io, - paths=[import_dir or self.import_dir], + paths=[import_dir], ) diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 7e06e7a1c2..2e6ae07455 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -23,7 +23,7 @@ AutotagStub, BeetsTestCase, ImportTestCase, - TerminalImportSessionSetup, + TerminalImportMixin, control_stdin, ) from beetsplug.edit import EditPlugin @@ -322,8 +322,8 @@ def test_invalid_yaml(self, mock_write): @_common.slow_test() -class EditDuringImporterTest( - TerminalImportSessionSetup, ImportTestCase, EditMixin +class EditDuringImporterTestCase( + EditMixin, TerminalImportMixin, ImportTestCase ): """TODO""" diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index f97e389c57..83cfb1b923 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -18,13 +18,13 @@ from beets.test.helper import ( AutotagStub, ImportTestCase, - TerminalImportSessionSetup, + TerminalImportMixin, capture_stdout, control_stdin, ) -class MBSubmitPluginTest(TerminalImportSessionSetup, ImportTestCase): +class MBSubmitPluginTest(TerminalImportMixin, ImportTestCase): def setUp(self): self.setup_beets() self.load_plugins("mbsubmit") diff --git a/test/test_plugins.py b/test/test_plugins.py index acf703e46c..2ea24b02cb 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -35,7 +35,7 @@ AutotagStub, BeetsTestCase, ImportHelper, - TerminalImportSessionSetup, + TerminalImportMixin, ) from beets.util import displayable_path, syspath from beets.util.id_extractors import ( @@ -377,7 +377,7 @@ def dummy9(self, **kwargs): plugins.send("event9", foo=5) -class PromptChoicesTest(TerminalImportSessionSetup, PluginImportTestCase): +class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase): def setUp(self): super().setUp() self._setup_import_session() diff --git a/test/test_ui_importer.py b/test/test_ui_importer.py index 3991376ac9..7dfcc205ef 100644 --- a/test/test_ui_importer.py +++ b/test/test_ui_importer.py @@ -21,57 +21,53 @@ import unittest from test import test_importer -from beets.test.helper import TerminalImportSessionSetup +from beets.test.helper import TerminalImportMixin class NonAutotaggedImportTest( - TerminalImportSessionSetup, test_importer.NonAutotaggedImportTest + TerminalImportMixin, test_importer.NonAutotaggedImportTest ): pass -class ImportTest(TerminalImportSessionSetup, test_importer.ImportTest): +class ImportTest(TerminalImportMixin, test_importer.ImportTest): pass class ImportSingletonTest( - TerminalImportSessionSetup, test_importer.ImportSingletonTest + TerminalImportMixin, test_importer.ImportSingletonTest ): pass -class ImportTracksTest( - TerminalImportSessionSetup, test_importer.ImportTracksTest -): +class ImportTracksTest(TerminalImportMixin, test_importer.ImportTracksTest): pass class ImportCompilationTest( - TerminalImportSessionSetup, test_importer.ImportCompilationTest + TerminalImportMixin, test_importer.ImportCompilationTest ): pass -class ImportExistingTest( - TerminalImportSessionSetup, test_importer.ImportExistingTest -): +class ImportExistingTest(TerminalImportMixin, test_importer.ImportExistingTest): pass class ChooseCandidateTest( - TerminalImportSessionSetup, test_importer.ChooseCandidateTest + TerminalImportMixin, test_importer.ChooseCandidateTest ): pass class GroupAlbumsImportTest( - TerminalImportSessionSetup, test_importer.GroupAlbumsImportTest + TerminalImportMixin, test_importer.GroupAlbumsImportTest ): pass class GlobalGroupAlbumsImportTest( - TerminalImportSessionSetup, test_importer.GlobalGroupAlbumsImportTest + TerminalImportMixin, test_importer.GlobalGroupAlbumsImportTest ): pass From b64eaeda0a7111ded1b28f77a244d09a5cfa2940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 13 Jul 2024 03:22:37 +0100 Subject: [PATCH 09/29] Rename LibTestCase to ItemInDBTestCase --- beets/test/helper.py | 8 ++------ test/plugins/test_web.py | 4 ++-- test/test_datequery.py | 8 ++++---- test/test_library.py | 14 +++++++------- test/test_query.py | 6 +++--- test/test_ui_commands.py | 4 ++-- test/test_ui_init.py | 4 ++-- 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 1499bd1257..359ce0485f 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -520,20 +520,15 @@ def tearDown(self): self.teardown_beets() -class LibTestCase(BeetsTestCase): +class ItemInDBTestCase(BeetsTestCase): """A test case that includes an in-memory library object (`lib`) and an item added to the library (`i`). """ def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.i = _common.item(self.lib) - def tearDown(self): - self.lib._connection().close() - super().tearDown() - class ImportHelper: """Provides tools to setup a library, a directory containing files that are @@ -985,3 +980,4 @@ def tearDownClass(cls) -> None: """Remove files created by the plugin.""" for module in cls.modules: clean_module_tempdir(module) + self.lib = beets.library.Library(":memory:") diff --git a/test/plugins/test_web.py b/test/plugins/test_web.py index c34de05d28..d2eb3f190d 100644 --- a/test/plugins/test_web.py +++ b/test/plugins/test_web.py @@ -9,11 +9,11 @@ from beets import logging from beets.library import Album, Item from beets.test import _common -from beets.test.helper import LibTestCase +from beets.test.helper import ItemInDBTestCase from beetsplug import web -class WebPluginTest(LibTestCase): +class WebPluginTest(ItemInDBTestCase): def setUp(self): super().setUp() self.log = logging.getLogger("beets.web") diff --git a/test/test_datequery.py b/test/test_datequery.py index 56c85e05da..48740420ce 100644 --- a/test/test_datequery.py +++ b/test/test_datequery.py @@ -25,7 +25,7 @@ InvalidQueryArgumentValueError, _parse_periods, ) -from beets.test.helper import LibTestCase +from beets.test.helper import ItemInDBTestCase def _date(string): @@ -152,7 +152,7 @@ def _parsetime(s): return time.mktime(datetime.strptime(s, "%Y-%m-%d %H:%M").timetuple()) -class DateQueryTest(LibTestCase): +class DateQueryTest(ItemInDBTestCase): def setUp(self): super().setUp() self.i.added = _parsetime("2013-03-30 22:21") @@ -187,7 +187,7 @@ def test_single_day_nonmatch_fast(self): self.assertEqual(len(matched), 0) -class DateQueryTestRelative(LibTestCase): +class DateQueryTestRelative(ItemInDBTestCase): def setUp(self): super().setUp() @@ -233,7 +233,7 @@ def test_single_day_nonmatch_fast(self): self.assertEqual(len(matched), 0) -class DateQueryTestRelativeMore(LibTestCase): +class DateQueryTestRelativeMore(ItemInDBTestCase): def setUp(self): super().setUp() self.i.added = _parsetime(datetime.now().strftime("%Y-%m-%d %H:%M")) diff --git a/test/test_library.py b/test/test_library.py index 7d27604d6e..d224f055c3 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -32,14 +32,14 @@ from beets import config, plugins, util from beets.test import _common from beets.test._common import item -from beets.test.helper import BeetsTestCase, LibTestCase +from beets.test.helper import BeetsTestCase, ItemInDBTestCase from beets.util import bytestring_path, syspath # Shortcut to path normalization. np = util.normpath -class LoadTest(LibTestCase): +class LoadTest(ItemInDBTestCase): def test_load_restores_data_from_db(self): original_title = self.i.title self.i.title = "something" @@ -53,7 +53,7 @@ def test_load_clears_dirty_flags(self): self.assertNotIn("artist", self.i._dirty) -class StoreTest(LibTestCase): +class StoreTest(ItemInDBTestCase): def test_store_changes_database_value(self): self.i.year = 1987 self.i.store() @@ -126,7 +126,7 @@ def test_library_add_path_inserts_row(self): self.assertEqual(new_grouping, self.i.grouping) -class RemoveTest(LibTestCase): +class RemoveTest(ItemInDBTestCase): def test_remove_deletes_from_db(self): self.i.remove() c = self.lib._connection().execute("select * from items") @@ -547,7 +547,7 @@ def test_album_field_in_template(self): self.assertEqual(self.i.destination(), np("one/foo/two")) -class ItemFormattedMappingTest(LibTestCase): +class ItemFormattedMappingTest(ItemInDBTestCase): def test_formatted_item_value(self): formatted = self.i.formatted() self.assertEqual(formatted["artist"], "the artist") @@ -1228,7 +1228,7 @@ def test_atime_for_singleton(self): self.assertGreater(self.singleton.added, 0) -class TemplateTest(LibTestCase): +class TemplateTest(ItemInDBTestCase): def test_year_formatted_in_template(self): self.i.year = 123 self.i.store() @@ -1258,7 +1258,7 @@ def test_album_and_item_format(self): self.assertEqual(f"{item:$tagada}", "togodo") -class UnicodePathTest(LibTestCase): +class UnicodePathTest(ItemInDBTestCase): def test_unicode_path(self): self.i.path = os.path.join(_common.RSRC, "unicode\u2019d.mp3".encode()) # If there are any problems with unicode paths, we will raise diff --git a/test/test_query.py b/test/test_query.py index a5a2091bf8..5657195014 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -31,7 +31,7 @@ ) from beets.library import Item, Library from beets.test import _common -from beets.test.helper import BeetsTestCase, LibTestCase +from beets.test.helper import BeetsTestCase, ItemInDBTestCase from beets.util import syspath # Because the absolute path begins with something like C:, we @@ -55,7 +55,7 @@ def assertNotInResult(self, item, results): # noqa self.assertNotIn(item.id, result_ids) -class AnyFieldQueryTest(LibTestCase): +class AnyFieldQueryTest(ItemInDBTestCase): def test_no_restriction(self): q = dbcore.query.AnyFieldQuery( "title", @@ -486,7 +486,7 @@ def test_eq(self): self.assertNotEqual(q3, q4) -class PathQueryTest(LibTestCase, AssertsMixin): +class PathQueryTest(ItemInDBTestCase, AssertsMixin): def setUp(self): super().setUp() diff --git a/test/test_ui_commands.py b/test/test_ui_commands.py index dfd8ffad00..a064fcf714 100644 --- a/test/test_ui_commands.py +++ b/test/test_ui_commands.py @@ -22,7 +22,7 @@ from beets import library, ui from beets.test import _common -from beets.test.helper import BeetsTestCase, LibTestCase +from beets.test.helper import BeetsTestCase, ItemInDBTestCase from beets.ui import commands from beets.util import syspath @@ -88,7 +88,7 @@ def test_query_album(self): self.check_do_query(0, 2, album=True, also_items=False) -class FieldsTest(LibTestCase): +class FieldsTest(ItemInDBTestCase): def setUp(self): super().setUp() diff --git a/test/test_ui_init.py b/test/test_ui_init.py index df1f36b97e..9febd397c7 100644 --- a/test/test_ui_init.py +++ b/test/test_ui_init.py @@ -23,7 +23,7 @@ from beets import config, ui from beets.test import _common -from beets.test.helper import BeetsTestCase, LibTestCase, control_stdin +from beets.test.helper import BeetsTestCase, ItemInDBTestCase, control_stdin class InputMethodsTest(BeetsTestCase): @@ -90,7 +90,7 @@ def test_input_select_objects(self): self.assertEqual(items, ["1", "3"]) -class InitTest(LibTestCase): +class InitTest(ItemInDBTestCase): def setUp(self): super().setUp() From 2d5fd907c3fac608e19d9779ccffa0c00b192d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Thu, 4 Jul 2024 05:23:58 +0100 Subject: [PATCH 10/29] Remove redundant setup_beets and teardown_beets instructions --- test/plugins/test_advancedrewrite.py | 5 +- test/plugins/test_albumtypes.py | 4 +- test/plugins/test_bareasc.py | 5 +- test/plugins/test_beatport.py | 8 +-- test/plugins/test_bucket.py | 5 +- test/plugins/test_convert.py | 6 +-- test/plugins/test_edit.py | 8 +-- test/plugins/test_embedart.py | 4 +- test/plugins/test_embyupdate.py | 4 +- test/plugins/test_export.py | 4 +- test/plugins/test_fetchart.py | 4 +- test/plugins/test_filefilter.py | 5 +- test/plugins/test_ftintitle.py | 4 +- test/plugins/test_hook.py | 5 +- test/plugins/test_importadded.py | 4 +- test/plugins/test_info.py | 4 +- test/plugins/test_ipfs.py | 4 +- test/plugins/test_keyfinder.py | 4 +- test/plugins/test_lastgenre.py | 5 +- test/plugins/test_limit.py | 4 +- test/plugins/test_mbsubmit.py | 4 +- test/plugins/test_mbsync.py | 4 +- test/plugins/test_mpdstats.py | 4 +- test/plugins/test_parentwork.py | 8 +-- test/plugins/test_permissions.py | 4 +- test/plugins/test_play.py | 4 +- test/plugins/test_player.py | 2 +- test/plugins/test_playlist.py | 4 +- test/plugins/test_plexupdate.py | 4 +- test/plugins/test_smartplaylist.py | 4 +- test/plugins/test_spotify.py | 7 +-- test/plugins/test_subsonicupdate.py | 7 +-- test/plugins/test_thumbnails.py | 6 --- test/plugins/test_types_plugin.py | 4 +- test/plugins/test_zero.py | 4 +- test/test_art_resize.py | 8 --- test/test_config_command.py | 5 +- test/test_importer.py | 79 +++++++++------------------- test/test_library.py | 12 ----- test/test_logging.py | 7 +-- test/test_metasync.py | 4 +- test/test_plugins.py | 4 +- test/test_ui.py | 25 ++------- test/test_ui_init.py | 3 -- 44 files changed, 102 insertions(+), 211 deletions(-) diff --git a/test/plugins/test_advancedrewrite.py b/test/plugins/test_advancedrewrite.py index 0d491f8a75..491e76127b 100644 --- a/test/plugins/test_advancedrewrite.py +++ b/test/plugins/test_advancedrewrite.py @@ -24,12 +24,9 @@ class AdvancedRewritePluginTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_simple_rewrite_example(self): self.config[PLUGIN_NAME] = [ diff --git a/test/plugins/test_albumtypes.py b/test/plugins/test_albumtypes.py index 4a32db3821..e436f5aae4 100644 --- a/test/plugins/test_albumtypes.py +++ b/test/plugins/test_albumtypes.py @@ -27,13 +27,13 @@ class AlbumTypesPluginTest(BeetsTestCase): def setUp(self): """Set up tests.""" - self.setup_beets() + super().setUp() self.load_plugins("albumtypes") def tearDown(self): """Tear down tests.""" self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_renames_types(self): """Tests if the plugin correctly renames the specified types.""" diff --git a/test/plugins/test_bareasc.py b/test/plugins/test_bareasc.py index 02af15f8dd..b3833df3db 100644 --- a/test/plugins/test_bareasc.py +++ b/test/plugins/test_bareasc.py @@ -14,7 +14,7 @@ class BareascPluginTest(BeetsTestCase): def setUp(self): """Set up test environment for bare ASCII query matching.""" - self.setup_beets() + super().setUp() self.log = logging.getLogger("beets.web") self.config["bareasc"]["prefix"] = "#" self.load_plugins("bareasc") @@ -27,9 +27,6 @@ def setUp(self): self.add_item(title="without umlaut or e", artist="Bruggen") self.add_item(title="without umlaut with e", artist="Brueggen") - def tearDown(self): - self.teardown_beets() - def test_bareasc_search(self): test_cases = [ ( diff --git a/test/plugins/test_beatport.py b/test/plugins/test_beatport.py index 9b07ebb0df..98807e9c81 100644 --- a/test/plugins/test_beatport.py +++ b/test/plugins/test_beatport.py @@ -450,7 +450,7 @@ def _make_tracks_response(self): return results def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("beatport") self.lib = library.Library(":memory:") @@ -470,7 +470,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def mk_test_album(self): items = [_common.item() for _ in range(6)] @@ -628,7 +628,7 @@ def _make_tracks_response(self): return results def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("beatport") self.lib = library.Library(":memory:") @@ -641,7 +641,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_response_tracks_empty(self): response_tracks = [] diff --git a/test/plugins/test_bucket.py b/test/plugins/test_bucket.py index adae967b2e..9220621103 100644 --- a/test/plugins/test_bucket.py +++ b/test/plugins/test_bucket.py @@ -24,12 +24,9 @@ class BucketPluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.plugin = bucket.BucketPlugin() - def tearDown(self): - self.teardown_beets() - def _setup_config( self, bucket_year=[], diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index 12b72bf852..9aa98f4c1b 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -106,7 +106,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_import_converted(self): self.importer.run() @@ -193,7 +193,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_convert(self): with control_stdin("y"): @@ -334,7 +334,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_transcode_from_lossless(self): [item] = self.add_item_fixtures(ext="flac") diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 2e6ae07455..c9bd854666 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -125,7 +125,7 @@ class EditCommandTest(BeetsTestCase, EditMixin): TRACK_COUNT = 10 def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("edit") # Add an album, storing the original fields for comparison. self.album = self.add_album_fixture(track_count=self.TRACK_COUNT) @@ -136,7 +136,7 @@ def setUp(self): def tearDown(self): EditPlugin.listeners = None - self.teardown_beets() + super().tearDown() self.unload_plugins() def assertCounts( # noqa @@ -330,7 +330,7 @@ class EditDuringImporterTestCase( IGNORED = ["added", "album_id", "id", "mtime", "path"] def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("edit") # Create some mediafiles, and store them for comparison. self._create_import_dir(3) @@ -342,7 +342,7 @@ def setUp(self): def tearDown(self): EditPlugin.listeners = None self.unload_plugins() - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_edit_apply_asis(self): diff --git a/test/plugins/test_embedart.py b/test/plugins/test_embedart.py index 4d78582b53..c696ae85d3 100644 --- a/test/plugins/test_embedart.py +++ b/test/plugins/test_embedart.py @@ -47,8 +47,8 @@ class EmbedartCliTest(FetchImageHelper, BeetsTestCase): abbey_differentpath = os.path.join(_common.RSRC, b"abbey-different.jpg") def setUp(self): + super().setUp() # Converter is threaded self.io.install() - self.setup_beets() # Converter is threaded self.load_plugins("embedart") def _setup_data(self, artpath=None): @@ -59,7 +59,7 @@ def _setup_data(self, artpath=None): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_embed_art_from_file_with_yes_input(self): self._setup_data() diff --git a/test/plugins/test_embyupdate.py b/test/plugins/test_embyupdate.py index a2d527c21d..d79c01a653 100644 --- a/test/plugins/test_embyupdate.py +++ b/test/plugins/test_embyupdate.py @@ -8,7 +8,7 @@ class EmbyUpdateTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("embyupdate") self.config["emby"] = { @@ -19,7 +19,7 @@ def setUp(self): } def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() def test_api_url_only_name(self): diff --git a/test/plugins/test_export.py b/test/plugins/test_export.py index 746293130c..acf76d48ba 100644 --- a/test/plugins/test_export.py +++ b/test/plugins/test_export.py @@ -27,13 +27,13 @@ class ExportPluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("export") self.test_values = {"title": "xtitle", "album": "xalbum"} def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def execute_command(self, format_type, artist): query = ",".join(self.test_values.keys()) diff --git a/test/plugins/test_fetchart.py b/test/plugins/test_fetchart.py index 61075c7929..ae1fcb96aa 100644 --- a/test/plugins/test_fetchart.py +++ b/test/plugins/test_fetchart.py @@ -24,7 +24,7 @@ class FetchartCliTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("fetchart") self.config["fetchart"]["cover_names"] = "c\xc3\xb6ver.jpg" self.config["art_filename"] = "mycover" @@ -33,7 +33,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def check_cover_is_stored(self): self.assertEqual(self.album["artpath"], self.cover_path) diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index a97fc5f325..f55aedbac3 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -31,14 +31,11 @@ class FileFilterPluginTest(ImportTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.__create_import_dir(2) self._setup_import_session() config["import"]["pretend"] = True - def tearDown(self): - self.teardown_beets() - def __copy_file(self, dest_path, metadata): # Copy files resource_path = os.path.join(_common.RSRC, b"full.mp3") diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index 923bf14efd..32c8e0e02b 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -24,12 +24,12 @@ class FtInTitlePluginFunctional(BeetsTestCase): def setUp(self): """Set up configuration""" - self.setup_beets() + super().setUp() self.load_plugins("ftintitle") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def _ft_add_item(self, path, artist, title, aartist): return self.add_item( diff --git a/test/plugins/test_hook.py b/test/plugins/test_hook.py index ee79b35992..ef26fd1a68 100644 --- a/test/plugins/test_hook.py +++ b/test/plugins/test_hook.py @@ -32,12 +32,9 @@ def get_temporary_path(): class HookTest(BeetsTestCase): TEST_HOOK_COUNT = 5 - def setUp(self): - self.setup_beets() - def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def _add_hook(self, event, command): hook = {"event": event, "command": command} diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index baa9f880b0..b41b91eeea 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -46,7 +46,7 @@ class ImportAddedTest(ImportTestCase): def setUp(self): preserve_plugin_listeners() - self.setup_beets() + super().setUp() self.load_plugins("importadded") self._create_import_dir(2) # Different mtimes on the files to be imported in order to test the @@ -62,7 +62,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() self.matcher.restore() def find_media_file(self, item): diff --git a/test/plugins/test_info.py b/test/plugins/test_info.py index bb8f97cf0a..4ab8aa70c2 100644 --- a/test/plugins/test_info.py +++ b/test/plugins/test_info.py @@ -23,12 +23,12 @@ class InfoTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("info") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_path(self): path = self.create_mediafile_fixture() diff --git a/test/plugins/test_ipfs.py b/test/plugins/test_ipfs.py index dcea852886..cd23b65ad8 100644 --- a/test/plugins/test_ipfs.py +++ b/test/plugins/test_ipfs.py @@ -26,13 +26,13 @@ @patch("beets.util.command_output", Mock()) class IPFSPluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("ipfs") self.lib = library.Library(":memory:") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_stored_hashes(self): test_album = self.mk_test_album() diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index 329733b476..dfd35f61f8 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -24,11 +24,11 @@ @patch("beets.util.command_output") class KeyFinderTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("keyfinder") def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() def test_add_key(self, command_output): diff --git a/test/plugins/test_lastgenre.py b/test/plugins/test_lastgenre.py index bf36039df2..249ecb5fd3 100644 --- a/test/plugins/test_lastgenre.py +++ b/test/plugins/test_lastgenre.py @@ -26,12 +26,9 @@ class LastGenrePluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.plugin = lastgenre.LastGenrePlugin() - def tearDown(self): - self.teardown_beets() - def _setup_config( self, whitelist=False, canonical=False, count=1, prefer_specific=False ): diff --git a/test/plugins/test_limit.py b/test/plugins/test_limit.py index 1ea57894c3..2c01dca76d 100644 --- a/test/plugins/test_limit.py +++ b/test/plugins/test_limit.py @@ -25,7 +25,7 @@ class LimitPluginTest(BeetsTestCase): """ def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("limit") # we'll create an even number of tracks in the library @@ -48,7 +48,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_no_limit(self): """Returns all when there is no limit or filter.""" diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index 83cfb1b923..f82f8c851a 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -26,7 +26,7 @@ class MBSubmitPluginTest(TerminalImportMixin, ImportTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("mbsubmit") self._create_import_dir(2) self._setup_import_session() @@ -34,7 +34,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_print_tracks_output(self): diff --git a/test/plugins/test_mbsync.py b/test/plugins/test_mbsync.py index cc6837c519..62c08f685d 100644 --- a/test/plugins/test_mbsync.py +++ b/test/plugins/test_mbsync.py @@ -28,12 +28,12 @@ class MbsyncCliTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("mbsync") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() @patch("beets.autotag.mb.album_for_id") @patch("beets.autotag.mb.track_for_id") diff --git a/test/plugins/test_mpdstats.py b/test/plugins/test_mpdstats.py index 1dc9b3a6e2..e60a32f4f9 100644 --- a/test/plugins/test_mpdstats.py +++ b/test/plugins/test_mpdstats.py @@ -24,11 +24,11 @@ class MPDStatsTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("mpdstats") def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() def test_update_rating(self): diff --git a/test/plugins/test_parentwork.py b/test/plugins/test_parentwork.py index 372c1ed2f7..fedcc6ceb7 100644 --- a/test/plugins/test_parentwork.py +++ b/test/plugins/test_parentwork.py @@ -88,12 +88,12 @@ def mock_workid_response(mbid, includes): class ParentWorkIntegrationTest(BeetsTestCase): def setUp(self): """Set up configuration""" - self.setup_beets() + super().setUp() self.load_plugins("parentwork") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() # test how it works with real musicbrainz data @unittest.skipUnless( @@ -183,7 +183,7 @@ def test_direct_parent_work_real(self): class ParentWorkTest(BeetsTestCase): def setUp(self): """Set up configuration""" - self.setup_beets() + super().setUp() self.load_plugins("parentwork") self.patcher = patch( "musicbrainzngs.get_work_by_id", side_effect=mock_workid_response @@ -192,7 +192,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() self.patcher.stop() def test_normal_case(self): diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index 82fb3c4435..14ac77cfcf 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -18,13 +18,13 @@ class PermissionsPluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("permissions") self.config["permissions"] = {"file": "777", "dir": "777"} def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() def test_permissions_on_album_imported(self): diff --git a/test/plugins/test_play.py b/test/plugins/test_play.py index 8dcf9d0445..563cb7f3ae 100644 --- a/test/plugins/test_play.py +++ b/test/plugins/test_play.py @@ -31,14 +31,14 @@ class PlayPluginTest(CleanupModulesMixin, BeetsTestCase): modules = (PlayPlugin.__module__,) def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("play") self.item = self.add_item(album="a nice älbum", title="aNiceTitle") self.lib.add_album([self.item]) self.config["play"]["command"] = "echo" def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() def run_and_assert( diff --git a/test/plugins/test_player.py b/test/plugins/test_player.py index 486808d33e..b7735ff10e 100644 --- a/test/plugins/test_player.py +++ b/test/plugins/test_player.py @@ -296,7 +296,7 @@ def setUp(self): self.lib.add_album([self.item1, self.item2]) def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() @contextmanager diff --git a/test/plugins/test_playlist.py b/test/plugins/test_playlist.py index 63018ef680..c7a2caa966 100644 --- a/test/plugins/test_playlist.py +++ b/test/plugins/test_playlist.py @@ -24,7 +24,7 @@ class PlaylistTestCase(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.lib = beets.library.Library(":memory:") self.music_dir = os.path.expanduser(os.path.join("~", "Music")) @@ -86,7 +86,7 @@ def setup_test(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() class PlaylistQueryTest: diff --git a/test/plugins/test_plexupdate.py b/test/plugins/test_plexupdate.py index e8e7b83b43..ba4890dbee 100644 --- a/test/plugins/test_plexupdate.py +++ b/test/plugins/test_plexupdate.py @@ -73,13 +73,13 @@ def add_response_update_plex(self): ) def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("plexupdate") self.config["plex"] = {"host": "localhost", "port": 32400} def tearDown(self): - self.teardown_beets() + super().tearDown() self.unload_plugins() @responses.activate diff --git a/test/plugins/test_smartplaylist.py b/test/plugins/test_smartplaylist.py index 9655f3f90d..f2aa5e1ab4 100644 --- a/test/plugins/test_smartplaylist.py +++ b/test/plugins/test_smartplaylist.py @@ -340,7 +340,7 @@ def test_playlist_update_uri_format(self): class SmartPlaylistCLITest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.item = self.add_item() config["smartplaylist"]["playlists"].set( @@ -354,7 +354,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_splupdate(self): with self.assertRaises(UserError): diff --git a/test/plugins/test_spotify.py b/test/plugins/test_spotify.py index c2fcc0722f..2a385195bd 100644 --- a/test/plugins/test_spotify.py +++ b/test/plugins/test_spotify.py @@ -6,7 +6,6 @@ import responses -from beets import config from beets.library import Item from beets.test import _common from beets.test.helper import BeetsTestCase @@ -28,8 +27,7 @@ def _params(url): class SpotifyPluginTest(BeetsTestCase): @responses.activate def setUp(self): - config.clear() - self.setup_beets() + super().setUp() responses.add( responses.POST, spotify.SpotifyPlugin.oauth_token_url, @@ -46,9 +44,6 @@ def setUp(self): opts = ArgumentsMock("list", False) self.spotify._parse_opts(opts) - def tearDown(self): - self.teardown_beets() - def test_args(self): opts = ArgumentsMock("fail", True) self.assertFalse(self.spotify._parse_opts(opts)) diff --git a/test/plugins/test_subsonicupdate.py b/test/plugins/test_subsonicupdate.py index be7f979ac3..9cfcef47e1 100644 --- a/test/plugins/test_subsonicupdate.py +++ b/test/plugins/test_subsonicupdate.py @@ -31,8 +31,7 @@ class SubsonicPluginTest(BeetsTestCase): @responses.activate def setUp(self): """Sets up config and plugin for test.""" - config.clear() - self.setup_beets() + super().setUp() config["subsonic"]["user"] = "admin" config["subsonic"]["pass"] = "admin" @@ -89,10 +88,6 @@ def setUp(self): } """ - def tearDown(self): - """Tears down tests.""" - self.teardown_beets() - @responses.activate def test_start_scan(self): """Tests success path based on best case scenario.""" diff --git a/test/plugins/test_thumbnails.py b/test/plugins/test_thumbnails.py index 942b91db0d..c2c22bed25 100644 --- a/test/plugins/test_thumbnails.py +++ b/test/plugins/test_thumbnails.py @@ -31,12 +31,6 @@ class ThumbnailsTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - @patch("beetsplug.thumbnails.ArtResizer") @patch("beetsplug.thumbnails.ThumbnailsPlugin._check_local_ok") @patch("beetsplug.thumbnails.os.stat") diff --git a/test/plugins/test_types_plugin.py b/test/plugins/test_types_plugin.py index 54766e7aa7..2f00ec4252 100644 --- a/test/plugins/test_types_plugin.py +++ b/test/plugins/test_types_plugin.py @@ -24,12 +24,12 @@ class TypesPluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("types") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_integer_modify_and_query(self): self.config["types"] = {"myint": "int"} diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index 1925bd464d..8be71b686f 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -12,7 +12,7 @@ class ZeroPluginTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.config["zero"] = { "fields": [], "keep_fields": [], @@ -21,7 +21,7 @@ def setUp(self): def tearDown(self): ZeroPlugin.listeners = None - self.teardown_beets() + super().tearDown() self.unload_plugins() def test_no_patterns(self): diff --git a/test/test_art_resize.py b/test/test_art_resize.py index e7bee02dc4..f5ec88f32f 100644 --- a/test/test_art_resize.py +++ b/test/test_art_resize.py @@ -56,14 +56,6 @@ class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): IMG_225x225 = os.path.join(_common.RSRC, b"abbey.jpg") IMG_225x225_SIZE = os.stat(syspath(IMG_225x225)).st_size - def setUp(self): - """Called before each test, setting up beets.""" - self.setup_beets() - - def tearDown(self): - """Called after each test, unloading all plugins.""" - self.teardown_beets() - def _test_img_resize(self, backend): """Test resizing based on file size, given a resize_func.""" # Check quality setting unaffected by new parameter diff --git a/test/test_config_command.py b/test/test_config_command.py index 72a0affd9c..4383f66645 100644 --- a/test/test_config_command.py +++ b/test/test_config_command.py @@ -10,7 +10,7 @@ class ConfigCommandTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() for k in ("VISUAL", "EDITOR"): if k in os.environ: del os.environ[k] @@ -31,9 +31,6 @@ def setUp(self): config["password"].redact = True config._materialized = False - def tearDown(self): - self.teardown_beets() - def _run_with_yaml_output(self, *args): output = self.run_with_output(*args) return yaml.safe_load(output) diff --git a/test/test_importer.py b/test/test_importer.py index 95e8fd933a..f510b81ac6 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -53,7 +53,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_tags_not_scrubbed(self): config["plugins"] = ["scrub"] @@ -105,9 +105,6 @@ def setUp(self): self._create_import_dir(2) self._setup_import_session(autotag=False) - def tearDown(self): - self.teardown_beets() - def test_album_created_with_track_artist(self): self.importer.run() albums = self.lib.albums() @@ -277,14 +274,11 @@ class RmTempTest(ImportTestCase): """ def setUp(self): - self.setup_beets() + super().setUp() self.want_resume = False self.config["incremental"] = False self._old_home = None - def tearDown(self): - self.teardown_beets() - def test_rm(self): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) @@ -297,12 +291,6 @@ def test_rm(self): class ImportZipTest(ImportTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - def test_import_zip(self): zip_path = create_archive(self) self.assertEqual(len(self.lib.items()), 0) @@ -350,14 +338,14 @@ class ImportSingletonTest(ImportTestCase): """ def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(1) self._setup_import_session() config["import"]["singletons"] = True self.matcher = AutotagStub().install() def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_apply_asis_adds_track(self): @@ -471,14 +459,14 @@ class ImportTest(ImportTestCase): """Test APPLY, ASIS and SKIP choices.""" def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(1) self._setup_import_session() self.matcher = AutotagStub().install() self.matcher.macthin = AutotagStub.GOOD def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_apply_asis_adds_album(self): @@ -685,13 +673,13 @@ class ImportTracksTest(ImportTestCase): """Test TRACKS and APPLY choice.""" def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(1) self._setup_import_session() self.matcher = AutotagStub().install() def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_apply_tracks_adds_singleton_track(self): @@ -719,13 +707,13 @@ class ImportCompilationTest(ImportTestCase): """Test ASIS import of a folder containing tracks with different artists.""" def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(3) self._setup_import_session() self.matcher = AutotagStub().install() def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_asis_homogenous_sets_albumartist(self): @@ -838,7 +826,7 @@ class ImportExistingTest(ImportTestCase): """Test importing files that are already in the library directory.""" def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(1) self.matcher = AutotagStub().install() @@ -849,7 +837,7 @@ def setUp(self): self._setup_import_session(import_dir=self.libdir) def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_does_not_duplicate_item(self): @@ -961,7 +949,7 @@ def test_outside_file_is_moved(self): class GroupAlbumsImportTest(ImportTestCase): def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(3) self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.NONE @@ -973,7 +961,7 @@ def setUp(self): self.importer.add_choice(importer.action.ASIS) def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_add_album_for_different_artist_and_different_album(self): @@ -1033,14 +1021,14 @@ def setUp(self): class ChooseCandidateTest(ImportTestCase): def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(1) self._setup_import_session() self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.BAD def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def test_choose_first_candidate(self): @@ -1172,7 +1160,7 @@ def match_album_mock(*args, **kwargs): @patch("beets.autotag.mb.match_album", Mock(side_effect=match_album_mock)) class ImportDuplicateAlbumTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() # Original album self.add_album_fixture(albumartist="artist", album="album") @@ -1182,9 +1170,6 @@ def setUp(self): config["import"]["autotag"] = True config["import"]["duplicate_keys"]["album"] = "albumartist album" - def tearDown(self): - self.teardown_beets() - def test_remove_duplicate_album(self): item = self.lib.items().get() self.assertEqual(item.title, "t\xeftle 0") @@ -1294,7 +1279,7 @@ def match_track_mock(*args, **kwargs): @patch("beets.autotag.mb.match_track", Mock(side_effect=match_track_mock)) class ImportDuplicateSingletonTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() # Original file in library self.add_item_fixture( @@ -1307,9 +1292,6 @@ def setUp(self): config["import"]["singletons"] = True config["import"]["duplicate_keys"]["item"] = "artist title" - def tearDown(self): - self.teardown_beets() - def test_remove_duplicate(self): item = self.lib.items().get() self.assertEqual(item.mb_trackid, "old trackid") @@ -1382,12 +1364,6 @@ def test_tag_log_unicode(self): class ResumeImportTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - @patch("beets.plugins.send") def test_resume_album(self, plugins_send): self.importer = self.create_importer(album_count=2) @@ -1434,12 +1410,9 @@ def raise_exception(event, **kwargs): class IncrementalImportTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.config["import"]["incremental"] = True - def tearDown(self): - self.teardown_beets() - def test_incremental_album(self): importer = self.create_importer(album_count=1) importer.run() @@ -1656,7 +1629,7 @@ class ReimportTest(ImportTestCase): """ def setUp(self): - self.setup_beets() + super().setUp() # The existing album. album = self.add_album_fixture() @@ -1674,7 +1647,7 @@ def setUp(self): self.matcher.matching = AutotagStub.GOOD def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def _setup_session(self, singletons=False): @@ -1759,8 +1732,7 @@ def __init__(self, method_name="runTest"): self.matcher = None def setUp(self): - self.io = _common.DummyIO() - self.setup_beets() + super().setUp() self.__create_import_dir() self.__create_empty_import_dir() self._setup_import_session() @@ -1769,7 +1741,7 @@ def setUp(self): self.io.install() def tearDown(self): - self.teardown_beets() + super().tearDown() self.matcher.restore() def __create_import_dir(self): @@ -1955,12 +1927,9 @@ class ImportMusicBrainzIdTest(ImportTestCase): ID_RECORDING_1 = "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" def setUp(self): - self.setup_beets() + super().setUp() self._create_import_dir(1) - def tearDown(self): - self.teardown_beets() - def test_one_mbid_one_album(self): self.config["import"]["search_ids"] = [ self.MB_RELEASE_PREFIX + self.ID_RELEASE_0 diff --git a/test/test_library.py b/test/test_library.py index d224f055c3..bce4dbb660 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -1268,12 +1268,6 @@ def test_unicode_path(self): class WriteTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - def test_write_nonexistant(self): item = self.create_item() item.path = b"/path/does/not/exist" @@ -1356,12 +1350,6 @@ def test_nonexistent_raise_read_error(self): class FilesizeTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - def test_filesize(self): item = self.add_item_fixture() self.assertNotEqual(item.filesize, 0) diff --git a/test/test_logging.py b/test/test_logging.py index 0cd3d48210..ad53461867 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -74,12 +74,12 @@ def listener(self): def setUp(self): sys.modules["beetsplug.dummy"] = self.DummyModule beetsplug.dummy = self.DummyModule - self.setup_beets() + super().setUp() self.load_plugins("dummy") def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() del beetsplug.dummy sys.modules.pop("beetsplug.dummy") self.DummyModule.DummyPlugin.listeners = None @@ -207,9 +207,6 @@ def listener2(self): def setUp(self): self.setup_beets(disk=True) - def tearDown(self): - self.teardown_beets() - def test_concurrent_events(self): dp = self.DummyPlugin(self) diff --git a/test/test_metasync.py b/test/test_metasync.py index a3bc3acb23..f320d4a5e6 100644 --- a/test/test_metasync.py +++ b/test/test_metasync.py @@ -39,7 +39,7 @@ class MetaSyncTest(BeetsTestCase): ) def setUp(self): - self.setup_beets() + super().setUp() self.load_plugins("metasync") self.config["metasync"]["source"] = "itunes" @@ -85,7 +85,7 @@ def _set_up_data(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_load_item_types(self): # This test also verifies that the MetaSources have loaded correctly diff --git a/test/test_plugins.py b/test/test_plugins.py index 2ea24b02cb..bda12c2d21 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -58,7 +58,7 @@ def myload(names=()): plugins._classes.update(self._plugin_classes) load_plugins.side_effect = myload - self.setup_beets() + super().setUp() def teardown_plugin_loader(self): self._plugin_loader_patch.stop() @@ -72,7 +72,7 @@ def setUp(self): def tearDown(self): self.teardown_plugin_loader() - self.teardown_beets() + super().tearDown() class PluginImportTestCase(ImportHelper, PluginLoaderTestCase): diff --git a/test/test_ui.py b/test/test_ui.py index 8b3ef7276f..890a033f8e 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -191,13 +191,10 @@ def test_remove_albums_select_with_delete(self): class ModifyTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() self.album = self.add_album_fixture() [self.item] = self.album.items() - def tearDown(self): - self.teardown_beets() - def modify_inp(self, inp, *args): with control_stdin(inp): self.run_command("modify", *args) @@ -404,12 +401,6 @@ def test_arg_parsing_equals_in_value(self): class WriteTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - def write_cmd(self, *args): return self.run_with_output("write", *args) @@ -846,7 +837,7 @@ def test_parse_paths_from_logfile(self): @_common.slow_test() class ConfigTest(BeetsTestCase): def setUp(self): - self.setup_beets() + super().setUp() # Don't use the BEETSDIR from `helper`. Instead, we point the home # directory there. Some tests will set `BEETSDIR` themselves. @@ -895,7 +886,7 @@ def tearDown(self): else: os.environ["APPDATA"] = self._old_appdata self.unload_plugins() - self.teardown_beets() + super().tearDown() def _make_test_cmd(self): test_cmd = ui.Subcommand("test", help="test") @@ -1474,7 +1465,7 @@ class CommonOptionsParserCliTest(BeetsTestCase): """ def setUp(self): - self.setup_beets() + super().setUp() self.item = _common.item() self.item.path = b"xxx/yyy" self.lib.add(self.item) @@ -1483,7 +1474,7 @@ def setUp(self): def tearDown(self): self.unload_plugins() - self.teardown_beets() + super().tearDown() def test_base(self): l = self.run_with_output("ls") @@ -1552,12 +1543,6 @@ def test_version(self): class CommonOptionsParserTest(BeetsTestCase): - def setUp(self): - self.setup_beets() - - def tearDown(self): - self.teardown_beets() - def test_album_option(self): parser = ui.CommonOptionsParser() self.assertFalse(parser._album_flags) diff --git a/test/test_ui_init.py b/test/test_ui_init.py index 9febd397c7..813ef2dca8 100644 --- a/test/test_ui_init.py +++ b/test/test_ui_init.py @@ -91,9 +91,6 @@ def test_input_select_objects(self): class InitTest(ItemInDBTestCase): - def setUp(self): - super().setUp() - def test_human_bytes(self): tests = [ (0, "0.0 B"), From 7d7f16395c5b92a7398ca6ec8962e459ce03db2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Fri, 5 Jul 2024 11:22:26 +0100 Subject: [PATCH 11/29] Remove redundant library setUp instructions --- beets/test/helper.py | 5 ++-- test/plugins/test_art.py | 7 +---- test/plugins/test_beatport.py | 3 -- test/plugins/test_importfeeds.py | 16 ++++------- test/plugins/test_ipfs.py | 2 -- test/plugins/test_playlist.py | 1 - test/test_files.py | 13 --------- test/test_library.py | 47 ++++++-------------------------- test/test_query.py | 12 +------- test/test_sort.py | 1 - test/test_ui.py | 23 ++++------------ test/test_ui_commands.py | 12 -------- test/test_vfs.py | 13 ++++----- 13 files changed, 29 insertions(+), 126 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 359ce0485f..4f62055e7e 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -470,11 +470,11 @@ def run_with_output(self, *args): # Safe file operations - def create_temp_dir(self): + def create_temp_dir(self, **kwargs): """Create a temporary directory and assign it into `self.temp_dir`. Call `remove_temp_dir` later to delete it. """ - temp_dir = mkdtemp() + temp_dir = mkdtemp(**kwargs) self.temp_dir = util.bytestring_path(temp_dir) def remove_temp_dir(self): @@ -980,4 +980,3 @@ def tearDownClass(cls) -> None: """Remove files created by the plugin.""" for module in cls.modules: clean_module_tempdir(module) - self.lib = beets.library.Library(":memory:") diff --git a/test/plugins/test_art.py b/test/plugins/test_art.py index 4d631aa38a..3e9f016dad 100644 --- a/test/plugins/test_art.py +++ b/test/plugins/test_art.py @@ -23,7 +23,7 @@ import confuse import responses -from beets import config, importer, library, logging, util +from beets import config, importer, logging, util from beets.autotag import AlbumInfo, AlbumMatch from beets.test import _common from beets.test.helper import ( @@ -736,16 +736,12 @@ def art_for_album(i, p, local_only=False): self.plugin.art_for_album = art_for_album # Test library. - self.libpath = os.path.join(self.temp_dir, b"tmplib.blb") - self.libdir = os.path.join(self.temp_dir, b"tmplib") - os.mkdir(syspath(self.libdir)) os.mkdir(syspath(os.path.join(self.libdir, b"album"))) itempath = os.path.join(self.libdir, b"album", b"test.mp3") shutil.copyfile( syspath(os.path.join(_common.RSRC, b"full.mp3")), syspath(itempath), ) - self.lib = library.Library(self.libpath) self.i = _common.item() self.i.path = itempath self.album = self.lib.add_album([self.i]) @@ -768,7 +764,6 @@ def art_for_album(i, p, local_only=False): self.task.set_choice(AlbumMatch(0, info, {}, set(), set())) def tearDown(self): - self.lib._connection().close() super().tearDown() self.plugin.art_for_album = self.old_afa diff --git a/test/plugins/test_beatport.py b/test/plugins/test_beatport.py index 98807e9c81..6a4cc52168 100644 --- a/test/plugins/test_beatport.py +++ b/test/plugins/test_beatport.py @@ -18,7 +18,6 @@ import unittest from datetime import timedelta -from beets import library from beets.test import _common from beets.test.helper import BeetsTestCase from beetsplug import beatport @@ -452,7 +451,6 @@ def _make_tracks_response(self): def setUp(self): super().setUp() self.load_plugins("beatport") - self.lib = library.Library(":memory:") # Set up 'album'. response_release = self._make_release_response() @@ -630,7 +628,6 @@ def _make_tracks_response(self): def setUp(self): super().setUp() self.load_plugins("beatport") - self.lib = library.Library(":memory:") # Set up 'tracks'. self.response_tracks = self._make_tracks_response() diff --git a/test/plugins/test_importfeeds.py b/test/plugins/test_importfeeds.py index 7d95a150b4..a8985d0bff 100644 --- a/test/plugins/test_importfeeds.py +++ b/test/plugins/test_importfeeds.py @@ -1,27 +1,21 @@ import datetime import os import os.path -import shutil -import tempfile import unittest from beets import config -from beets.library import Album, Item, Library +from beets.library import Album, Item +from beets.test.helper import BeetsTestCase from beetsplug.importfeeds import ImportFeedsPlugin -class ImportfeedsTestTest(unittest.TestCase): +class ImportfeedsTestTest(BeetsTestCase): def setUp(self): - config.clear() - config.read(user=False) + super().setUp() self.importfeeds = ImportFeedsPlugin() - self.lib = Library(":memory:") - self.feeds_dir = tempfile.mkdtemp() + self.feeds_dir = os.path.join(os.fsdecode(self.temp_dir), "importfeeds") config["importfeeds"]["dir"] = self.feeds_dir - def tearDown(self): - shutil.rmtree(self.feeds_dir) - def test_multi_format_album_playlist(self): config["importfeeds"]["formats"] = "m3u_multi" album = Album(album="album/name", id=1) diff --git a/test/plugins/test_ipfs.py b/test/plugins/test_ipfs.py index cd23b65ad8..928b193f3c 100644 --- a/test/plugins/test_ipfs.py +++ b/test/plugins/test_ipfs.py @@ -16,7 +16,6 @@ import unittest from unittest.mock import Mock, patch -from beets import library from beets.test import _common from beets.test.helper import BeetsTestCase from beets.util import _fsencoding, bytestring_path @@ -28,7 +27,6 @@ class IPFSPluginTest(BeetsTestCase): def setUp(self): super().setUp() self.load_plugins("ipfs") - self.lib = library.Library(":memory:") def tearDown(self): self.unload_plugins() diff --git a/test/plugins/test_playlist.py b/test/plugins/test_playlist.py index c7a2caa966..74befd71f6 100644 --- a/test/plugins/test_playlist.py +++ b/test/plugins/test_playlist.py @@ -25,7 +25,6 @@ class PlaylistTestCase(BeetsTestCase): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.music_dir = os.path.expanduser(os.path.join("~", "Music")) diff --git a/test/test_files.py b/test/test_files.py index 68971cd854..acece24d0f 100644 --- a/test/test_files.py +++ b/test/test_files.py @@ -41,14 +41,10 @@ def setUp(self): ) # add it to a temporary library - self.lib = beets.library.Library(":memory:") self.i = beets.library.Item.from_path(self.path) self.lib.add(self.i) # set up the destination - self.libdir = join(self.temp_dir, b"testlibdir") - os.mkdir(syspath(self.libdir)) - self.lib.directory = self.libdir self.lib.path_formats = [ ("default", join("$artist", "$album", "$title")) ] @@ -250,12 +246,9 @@ def setUp(self): super().setUp() # Make library and item. - self.lib = beets.library.Library(":memory:") self.lib.path_formats = [ ("default", join("$albumartist", "$album", "$title")) ] - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - self.lib.directory = self.libdir self.i = item(self.lib) # Make a file for the item. self.i.path = self.i.destination() @@ -317,9 +310,6 @@ def setUp(self): super().setUp() # Make library and item. - self.lib = beets.library.Library(":memory:") - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - self.lib.directory = self.libdir self.i = item(self.lib) self.i.path = self.i.destination() # Make a music file. @@ -491,9 +481,6 @@ def setUp(self): super().setUp() # Make library and item. - self.lib = beets.library.Library(":memory:") - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - self.lib.directory = self.libdir self.i = item(self.lib) self.i.path = self.i.destination() # Make a music file. diff --git a/test/test_library.py b/test/test_library.py index bce4dbb660..e0ded46bab 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -97,7 +97,6 @@ def test_store_album_cascades_flex_deletes(self): class AddTest(BeetsTestCase): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.i = item() def test_item_add_inserts_row(self): @@ -155,9 +154,8 @@ def test_invalid_field_raises_attributeerror(self): def test_album_fallback(self): # integration test of item-album fallback - lib = beets.library.Library(":memory:") - i = item(lib) - album = lib.add_album([i]) + i = item(self.lib) + album = self.lib.add_album([i]) album["flex"] = "foo" album.store() @@ -170,18 +168,16 @@ def test_album_fallback(self): class DestinationTest(BeetsTestCase): + """Confirm tests handle temporary directory path containing '.'""" + + def create_temp_dir(self, **kwargs): + kwargs["prefix"] = "." + super().create_temp_dir(**kwargs) + def setUp(self): super().setUp() - # default directory is ~/Music and the only reason why it was switched - # to ~/.Music is to confirm that tests works well when path to - # temporary directory contains . - self.lib = beets.library.Library(":memory:", "~/.Music") self.i = item(self.lib) - def tearDown(self): - super().tearDown() - self.lib._connection().close() - def test_directory_works_with_trailing_slash(self): self.lib.directory = b"one/" self.lib.path_formats = [("default", "two")] @@ -623,15 +619,10 @@ def _assert_dest(self, dest, i=None): class DestinationFunctionTest(BeetsTestCase, PathFormattingMixin): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.lib.directory = b"/base" self.lib.path_formats = [("default", "path")] self.i = item(self.lib) - def tearDown(self): - super().tearDown() - self.lib._connection().close() - def test_upper_case_literal(self): self._setf("%upper{foo}") self._assert_dest(b"/base/FOO") @@ -732,7 +723,6 @@ def test_first_different_sep(self): class DisambiguationTest(BeetsTestCase, PathFormattingMixin): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.lib.directory = b"/base" self.lib.path_formats = [("default", "path")] @@ -746,10 +736,6 @@ def setUp(self): self._setf("foo%aunique{albumartist album,year}/$title") - def tearDown(self): - super().tearDown() - self.lib._connection().close() - def test_unique_expands_to_disambiguating_year(self): self._assert_dest(b"/base/foo [2001]/the title", self.i1) @@ -821,7 +807,6 @@ def test_key_flexible_attribute(self): class SingletonDisambiguationTest(BeetsTestCase, PathFormattingMixin): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.lib.directory = b"/base" self.lib.path_formats = [("default", "path")] @@ -835,10 +820,6 @@ def setUp(self): self._setf("foo/$title%sunique{artist title,year}") - def tearDown(self): - super().tearDown() - self.lib._connection().close() - def test_sunique_expands_to_disambiguating_year(self): self._assert_dest(b"/base/foo/the title [2001]", self.i1) @@ -919,7 +900,6 @@ def field_getters(): self.old_field_getters = plugins.item_field_getters plugins.item_field_getters = field_getters - self.lib = beets.library.Library(":memory:") self.lib.directory = b"/base" self.lib.path_formats = [("default", "$artist $foo")] self.i = item(self.lib) @@ -958,7 +938,6 @@ def test_plugin_value_sanitized(self): class AlbumInfoTest(BeetsTestCase): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.i = item() self.lib.add_album((self.i,)) @@ -1065,9 +1044,7 @@ def setUp(self): super().setUp() config["art_filename"] = "artimage" config["replace"] = {"X": "Y"} - self.lib = beets.library.Library( - ":memory:", replacements=[(re.compile("X"), "Y")] - ) + self.lib.replacements = [(re.compile("X"), "Y")] self.i = item(self.lib) self.i.path = self.i.destination() self.ai = self.lib.add_album((self.i,)) @@ -1091,7 +1068,6 @@ def test_art_path_sanitized(self): class PathStringTest(BeetsTestCase): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") self.i = item(self.lib) def test_item_path_is_bytestring(self): @@ -1183,7 +1159,6 @@ def setUp(self): syspath(self.ipath), ) self.i = beets.library.Item.from_path(self.ipath) - self.lib = beets.library.Library(":memory:") self.lib.add(self.i) def tearDown(self): @@ -1213,10 +1188,6 @@ def test_mtime_up_to_date_after_read(self): class ImportTimeTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.lib = beets.library.Library(":memory:") - def added(self): self.track = item() self.album = self.lib.add_album((self.track,)) diff --git a/test/test_query.py b/test/test_query.py index 5657195014..02cdc16737 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -29,7 +29,7 @@ NoneQuery, ParsingError, ) -from beets.library import Item, Library +from beets.library import Item from beets.test import _common from beets.test.helper import BeetsTestCase, ItemInDBTestCase from beets.util import syspath @@ -94,7 +94,6 @@ def test_eq(self): class DummyDataTestCase(BeetsTestCase, AssertsMixin): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") items = [_common.item() for _ in range(3)] items[0].title = "foo bar" items[0].artist = "one" @@ -725,9 +724,6 @@ def test_detect_relative_path(self): class IntQueryTest(BeetsTestCase): - def setUp(self): - self.lib = Library(":memory:") - def tearDown(self): super().tearDown() Item._types = {} @@ -766,7 +762,6 @@ def test_no_substring_match(self): class BoolQueryTest(BeetsTestCase, AssertsMixin): def setUp(self): super().setUp() - self.lib = Library(":memory:") Item._types = {"flexbool": types.Boolean()} def tearDown(self): @@ -836,10 +831,6 @@ def test_items_does_not_match_year(self): class NoneQueryTest(BeetsTestCase, AssertsMixin): - def setUp(self): - super().setUp() - self.lib = Library(":memory:") - def test_match_singletons(self): singleton = self.add_item() album_item = self.add_album().items().get() @@ -1137,7 +1128,6 @@ class RelatedQueriesTest(BeetsTestCase, AssertsMixin): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") albums = [] for album_idx in range(1, 3): diff --git a/test/test_sort.py b/test/test_sort.py index b222c93f92..3d092e5511 100644 --- a/test/test_sort.py +++ b/test/test_sort.py @@ -28,7 +28,6 @@ class DummyDataTestCase(BeetsTestCase): def setUp(self): super().setUp() - self.lib = beets.library.Library(":memory:") albums = [_common.album() for _ in range(3)] albums[0].album = "Album A" diff --git a/test/test_ui.py b/test/test_ui.py index 890a033f8e..d35a900f91 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -40,9 +40,9 @@ from beets.util import MoveOperation, syspath -class ListTest(unittest.TestCase): +class ListTest(BeetsTestCase): def setUp(self): - self.lib = library.Library(":memory:") + super().setUp() self.item = _common.item() self.item.path = "xxx/yyy" self.lib.add(self.item) @@ -114,11 +114,7 @@ def setUp(self): self.io.install() - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - os.mkdir(syspath(self.libdir)) - # Copy a file into the library. - self.lib = library.Library(":memory:", self.libdir) self.item_path = os.path.join(_common.RSRC, b"full.mp3") self.i = library.Item.from_path(self.item_path) self.lib.add(self.i) @@ -451,9 +447,6 @@ def setUp(self): self.io.install() - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - os.mkdir(syspath(self.libdir)) - self.itempath = os.path.join(self.libdir, b"srcfile") shutil.copy( syspath(os.path.join(_common.RSRC, b"full.mp3")), @@ -461,7 +454,6 @@ def setUp(self): ) # Add a file to the library but don't copy it in yet. - self.lib = library.Library(":memory:", self.libdir) self.i = library.Item.from_path(self.itempath) self.lib.add(self.i) self.album = self.lib.add_album([self.i]) @@ -485,28 +477,28 @@ def _move( def test_move_item(self): self._move() self.i.load() - self.assertIn(b"testlibdir", self.i.path) + self.assertIn(b"libdir", self.i.path) self.assertExists(self.i.path) self.assertNotExists(self.itempath) def test_copy_item(self): self._move(copy=True) self.i.load() - self.assertIn(b"testlibdir", self.i.path) + self.assertIn(b"libdir", self.i.path) self.assertExists(self.i.path) self.assertExists(self.itempath) def test_move_album(self): self._move(album=True) self.i.load() - self.assertIn(b"testlibdir", self.i.path) + self.assertIn(b"libdir", self.i.path) self.assertExists(self.i.path) self.assertNotExists(self.itempath) def test_copy_album(self): self._move(copy=True, album=True) self.i.load() - self.assertIn(b"testlibdir", self.i.path) + self.assertIn(b"libdir", self.i.path) self.assertExists(self.i.path) self.assertExists(self.itempath) @@ -559,10 +551,7 @@ def setUp(self): self.io.install() - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - # Copy a file into the library. - self.lib = library.Library(":memory:", self.libdir) item_path = os.path.join(_common.RSRC, b"full.mp3") item_path_two = os.path.join(_common.RSRC, b"full.flac") self.i = library.Item.from_path(item_path) diff --git a/test/test_ui_commands.py b/test/test_ui_commands.py index a064fcf714..735d0c393c 100644 --- a/test/test_ui_commands.py +++ b/test/test_ui_commands.py @@ -28,18 +28,6 @@ class QueryTest(BeetsTestCase): - def setUp(self): - super().setUp() - - self.libdir = os.path.join(self.temp_dir, b"testlibdir") - os.mkdir(syspath(self.libdir)) - - # Add a file to the library but don't copy it in yet. - self.lib = library.Library(":memory:", self.libdir) - - # Alternate destination directory. - # self.otherdir = os.path.join(self.temp_dir, b"testotherdir") - def add_item(self, filename=b"srcfile", templatefile=b"full.mp3"): itempath = os.path.join(self.libdir, filename) shutil.copy( diff --git a/test/test_vfs.py b/test/test_vfs.py index 939d44f73b..34a5f5d308 100644 --- a/test/test_vfs.py +++ b/test/test_vfs.py @@ -16,7 +16,7 @@ import unittest -from beets import library, vfs +from beets import vfs from beets.test import _common from beets.test.helper import BeetsTestCase @@ -24,13 +24,10 @@ class VFSTest(BeetsTestCase): def setUp(self): super().setUp() - self.lib = library.Library( - ":memory:", - path_formats=[ - ("default", "albums/$album/$title"), - ("singleton:true", "tracks/$artist/$title"), - ], - ) + self.lib.path_formats = [ + ("default", "albums/$album/$title"), + ("singleton:true", "tracks/$artist/$title"), + ] self.lib.add(_common.item()) self.lib.add_album([_common.item()]) self.tree = vfs.libtree(self.lib) From 16cf8dd937b9a135201123ac31b979cd56bc5a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 6 Jul 2024 20:14:56 +0100 Subject: [PATCH 12/29] Centralize db setup on disk --- beets/test/helper.py | 10 ++++++---- test/plugins/test_convert.py | 8 ++++---- test/plugins/test_player.py | 4 +++- test/plugins/test_replaygain.py | 3 ++- test/test_importer.py | 8 ++++++-- test/test_logging.py | 5 ++--- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 4f62055e7e..241213ce4a 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -151,9 +151,11 @@ class TestHelper(_common.Assertions): fixtures. """ + db_on_disk: ClassVar[bool] = False + # TODO automate teardown through hook registration - def setup_beets(self, disk=False): + def setup_beets(self): """Setup pristine global configuration and library for testing. Sets ``beets.config`` so we can safely use any functionality @@ -199,7 +201,7 @@ def setup_beets(self, disk=False): os.mkdir(syspath(self.libdir)) self.config["directory"] = os.fsdecode(self.libdir) - if disk: + if self.db_on_disk: dbpath = util.bytestring_path(self.config["library"].as_filename()) else: dbpath = ":memory:" @@ -538,8 +540,8 @@ class ImportHelper: importer: importer.ImportSession - def setup_beets(self, disk=False): - super().setup_beets(disk) + def setup_beets(self): + super().setup_beets() self.lib.path_formats = [ ("default", os.path.join("$artist", "$album", "$title")), ("singleton:true", os.path.join("singletons", "$title")), diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index 9aa98f4c1b..c15462a5b7 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -85,13 +85,13 @@ def assertNoFileTag(self, path, tag): # noqa class ConvertTestCase(BeetsTestCase, ConvertMixin): - pass + db_on_disk = True @_common.slow_test() class ImportConvertTest(ConvertTestCase): def setUp(self): - self.setup_beets(disk=True) # Converter is threaded + super().setUp() self.importer = self.create_importer() self.load_plugins("convert") @@ -169,7 +169,7 @@ def run_convert(self, *args): @_common.slow_test() class ConvertCliTest(ConvertTestCase, ConvertCommand): def setUp(self): - self.setup_beets(disk=True) # Converter is threaded + super().setUp() self.album = self.add_album_fixture(ext="ogg") self.item = self.album.items()[0] self.load_plugins("convert") @@ -318,7 +318,7 @@ class NeverConvertLossyFilesTest(ConvertTestCase, ConvertCommand): """Test the effect of the `never_convert_lossy_files` option.""" def setUp(self): - self.setup_beets(disk=True) # Converter is threaded + super().setUp() self.load_plugins("convert") self.convert_dest = os.path.join(self.temp_dir, b"convert_dest") diff --git a/test/plugins/test_player.py b/test/plugins/test_player.py index b7735ff10e..f0a3f3b664 100644 --- a/test/plugins/test_player.py +++ b/test/plugins/test_player.py @@ -278,8 +278,10 @@ def listener_wrap(host, port): class BPDTestHelper(BeetsTestCase): + db_on_disk = True + def setUp(self): - self.setup_beets(disk=True) + super().setUp() self.load_plugins("bpd") self.item1 = self.add_item( title="Track One Title", diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index d8082b0afd..94846c9689 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -53,13 +53,14 @@ def reset_replaygain(item): class ReplayGainTestCase(BeetsTestCase): + db_on_disk = True backend: ClassVar[str] def setUp(self): # Implemented by Mixins, see above. This may decide to skip the test. self.test_backend() - self.setup_beets(disk=True) + super().setUp() self.config["replaygain"]["backend"] = self.backend try: diff --git a/test/test_importer.py b/test/test_importer.py index f510b81ac6..9800604885 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -45,8 +45,10 @@ class ScrubbedImportTest(ImportTestCase): + db_on_disk = True + def setUp(self): - self.setup_beets(disk=True) + super().setUp() self.load_plugins("scrub") self._create_import_dir(2) self._setup_import_session(autotag=False) @@ -100,8 +102,10 @@ def test_tags_not_restored(self): @_common.slow_test() class NonAutotaggedImportTest(ImportTestCase): + db_on_disk = True + def setUp(self): - self.setup_beets(disk=True) + super().setUp() self._create_import_dir(2) self._setup_import_session(autotag=False) diff --git a/test/test_logging.py b/test/test_logging.py index ad53461867..97786ec18b 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -168,6 +168,8 @@ class ConcurrentEventsTest(BeetsTestCase): LoggingLevelTest. """ + db_on_disk = True + class DummyPlugin(plugins.BeetsPlugin): def __init__(self, test_case): plugins.BeetsPlugin.__init__(self, "dummy") @@ -204,9 +206,6 @@ def listener2(self): except Exception as e: self.exc = e - def setUp(self): - self.setup_beets(disk=True) - def test_concurrent_events(self): dp = self.DummyPlugin(self) From 432da560e4fb4578830b5ae29a4134764f6f3efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 6 Jul 2024 21:47:30 +0100 Subject: [PATCH 13/29] Create PluginTestCase to dedupe plugin setup --- beets/test/helper.py | 19 ++++++++++++++++++- test/plugins/test_albumtypes.py | 15 +++------------ test/plugins/test_bareasc.py | 6 +++--- test/plugins/test_beatport.py | 10 ---------- test/plugins/test_convert.py | 20 +++----------------- test/plugins/test_edit.py | 12 +++++------- test/plugins/test_embedart.py | 10 +++------- test/plugins/test_embyupdate.py | 11 ++++------- test/plugins/test_export.py | 11 ++++------- test/plugins/test_fetchart.py | 11 ++++------- test/plugins/test_ftintitle.py | 13 +++---------- test/plugins/test_importadded.py | 7 +++---- test/plugins/test_info.py | 12 +++--------- test/plugins/test_ipfs.py | 12 +++--------- test/plugins/test_keyfinder.py | 12 +++--------- test/plugins/test_limit.py | 11 ++++------- test/plugins/test_mbsubmit.py | 7 ++++--- test/plugins/test_mbsync.py | 12 +++--------- test/plugins/test_mpdstats.py | 12 +++--------- test/plugins/test_parentwork.py | 19 ++++++------------- test/plugins/test_permissions.py | 11 ++++------- test/plugins/test_play.py | 10 +++------- test/plugins/test_player.py | 10 +++------- test/plugins/test_plexupdate.py | 11 ++++------- test/plugins/test_smartplaylist.py | 11 ++++------- test/plugins/test_types_plugin.py | 12 +++--------- test/test_importer.py | 9 +++------ test/test_logging.py | 7 +++---- test/test_metasync.py | 10 +++------- test/test_plugins.py | 17 +++++------------ 30 files changed, 117 insertions(+), 233 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 241213ce4a..c649981749 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -225,6 +225,7 @@ def load_plugins(self, *plugins): sure you call ``unload_plugins()`` afterwards. """ # FIXME this should eventually be handled by a plugin manager + plugins = (self.plugin,) if hasattr(self, "plugin") else plugins beets.config["plugins"] = plugins beets.plugins.load_plugins(plugins) beets.plugins.find_plugins() @@ -242,7 +243,7 @@ def load_plugins(self, *plugins): Album._queries.update(beets.plugins.named_queries(Album)) def unload_plugins(self): - """Unload all plugins and remove the from the configuration.""" + """Unload all plugins and remove them from the configuration.""" # FIXME this should eventually be handled by a plugin manager beets.config["plugins"] = [] beets.plugins._classes = set() @@ -532,6 +533,22 @@ def setUp(self): self.i = _common.item(self.lib) +class PluginMixin: + plugin: ClassVar[str] + + def setUp(self): + super().setUp() + self.load_plugins() + + def tearDown(self): + super().tearDown() + self.unload_plugins() + + +class PluginTestCase(PluginMixin, BeetsTestCase): + pass + + class ImportHelper: """Provides tools to setup a library, a directory containing files that are to be imported and an import session. The class also provides stubs for the diff --git a/test/plugins/test_albumtypes.py b/test/plugins/test_albumtypes.py index e436f5aae4..a6dfafe65c 100644 --- a/test/plugins/test_albumtypes.py +++ b/test/plugins/test_albumtypes.py @@ -18,22 +18,13 @@ from typing import Sequence, Tuple from beets.autotag.mb import VARIOUS_ARTISTS_ID -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beetsplug.albumtypes import AlbumTypesPlugin -class AlbumTypesPluginTest(BeetsTestCase): +class AlbumTypesPluginTest(PluginTestCase): """Tests for albumtypes plugin.""" - - def setUp(self): - """Set up tests.""" - super().setUp() - self.load_plugins("albumtypes") - - def tearDown(self): - """Tear down tests.""" - self.unload_plugins() - super().tearDown() + plugin = "albumtypes" def test_renames_types(self): """Tests if the plugin correctly renames the specified types.""" diff --git a/test/plugins/test_bareasc.py b/test/plugins/test_bareasc.py index b3833df3db..61c600bad3 100644 --- a/test/plugins/test_bareasc.py +++ b/test/plugins/test_bareasc.py @@ -6,18 +6,18 @@ import unittest from beets import logging -from beets.test.helper import BeetsTestCase, capture_stdout +from beets.test.helper import PluginTestCase, capture_stdout -class BareascPluginTest(BeetsTestCase): +class BareascPluginTest(PluginTestCase): """Test bare ASCII query matching.""" + plugin = "bareasc" def setUp(self): """Set up test environment for bare ASCII query matching.""" super().setUp() self.log = logging.getLogger("beets.web") self.config["bareasc"]["prefix"] = "#" - self.load_plugins("bareasc") # Add library elements. Note that self.lib.add overrides any "id=" # and assigns the next free id number. diff --git a/test/plugins/test_beatport.py b/test/plugins/test_beatport.py index 6a4cc52168..5e5130a5de 100644 --- a/test/plugins/test_beatport.py +++ b/test/plugins/test_beatport.py @@ -450,7 +450,6 @@ def _make_tracks_response(self): def setUp(self): super().setUp() - self.load_plugins("beatport") # Set up 'album'. response_release = self._make_release_response() @@ -466,10 +465,6 @@ def setUp(self): # Set up 'test_tracks' self.test_tracks = self.test_album.items() - def tearDown(self): - self.unload_plugins() - super().tearDown() - def mk_test_album(self): items = [_common.item() for _ in range(6)] for item in items: @@ -627,7 +622,6 @@ def _make_tracks_response(self): def setUp(self): super().setUp() - self.load_plugins("beatport") # Set up 'tracks'. self.response_tracks = self._make_tracks_response() @@ -636,10 +630,6 @@ def setUp(self): # Make alias to be congruent with class `BeatportTest`. self.test_tracks = self.response_tracks - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_response_tracks_empty(self): response_tracks = [] tracks = [beatport.BeatportTrack(t) for t in response_tracks] diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index c15462a5b7..1b864499aa 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -23,7 +23,7 @@ from beets import util from beets.test import _common -from beets.test.helper import BeetsTestCase, capture_log, control_stdin +from beets.test.helper import PluginTestCase, capture_log, control_stdin from beets.util import bytestring_path, displayable_path @@ -84,8 +84,9 @@ def assertNoFileTag(self, path, tag): # noqa ) -class ConvertTestCase(BeetsTestCase, ConvertMixin): +class ConvertTestCase(ConvertMixin, PluginTestCase): db_on_disk = True + plugin = "convert" @_common.slow_test() @@ -93,7 +94,6 @@ class ImportConvertTest(ConvertTestCase): def setUp(self): super().setUp() self.importer = self.create_importer() - self.load_plugins("convert") self.config["convert"] = { "dest": os.path.join(self.temp_dir, b"convert"), @@ -104,10 +104,6 @@ def setUp(self): "quiet": False, } - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_import_converted(self): self.importer.run() item = self.lib.items().get() @@ -172,7 +168,6 @@ def setUp(self): super().setUp() self.album = self.add_album_fixture(ext="ogg") self.item = self.album.items()[0] - self.load_plugins("convert") self.convert_dest = bytestring_path( os.path.join(self.temp_dir, b"convert_dest") @@ -191,10 +186,6 @@ def setUp(self): }, } - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_convert(self): with control_stdin("y"): self.run_convert() @@ -319,7 +310,6 @@ class NeverConvertLossyFilesTest(ConvertTestCase, ConvertCommand): def setUp(self): super().setUp() - self.load_plugins("convert") self.convert_dest = os.path.join(self.temp_dir, b"convert_dest") self.config["convert"] = { @@ -332,10 +322,6 @@ def setUp(self): }, } - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_transcode_from_lossless(self): [item] = self.add_item_fixtures(ext="flac") with control_stdin("y"): diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index c9bd854666..8244704d09 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -21,8 +21,8 @@ from beets.test import _common from beets.test.helper import ( AutotagStub, - BeetsTestCase, ImportTestCase, + PluginTestCase, TerminalImportMixin, control_stdin, ) @@ -73,9 +73,11 @@ def replace_contents(self, filename, log): f.write(contents) -class EditMixin: +class EditMixin(PluginTestCase): """Helper containing some common functionality used for the Edit tests.""" + plugin = "edit" + def assertItemFieldsModified( # noqa self, library_items, items, fields=[], allowed=["path"] ): @@ -115,7 +117,7 @@ def run_mocked_command(self, modify_file_args={}, stdin=[], args=[]): @_common.slow_test() @patch("beets.library.Item.write") -class EditCommandTest(BeetsTestCase, EditMixin): +class EditCommandTest(EditMixin): """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`. @@ -126,7 +128,6 @@ class EditCommandTest(BeetsTestCase, EditMixin): def setUp(self): super().setUp() - self.load_plugins("edit") # Add an album, storing the original fields for comparison. self.album = self.add_album_fixture(track_count=self.TRACK_COUNT) self.album_orig = {f: self.album[f] for f in self.album._fields} @@ -137,7 +138,6 @@ def setUp(self): def tearDown(self): EditPlugin.listeners = None super().tearDown() - self.unload_plugins() def assertCounts( # noqa self, @@ -331,7 +331,6 @@ class EditDuringImporterTestCase( def setUp(self): super().setUp() - self.load_plugins("edit") # Create some mediafiles, and store them for comparison. self._create_import_dir(3) self.items_orig = [Item.from_path(f.path) for f in self.media_files] @@ -341,7 +340,6 @@ def setUp(self): def tearDown(self): EditPlugin.listeners = None - self.unload_plugins() super().tearDown() self.matcher.restore() diff --git a/test/plugins/test_embedart.py b/test/plugins/test_embedart.py index c696ae85d3..a58cd2f289 100644 --- a/test/plugins/test_embedart.py +++ b/test/plugins/test_embedart.py @@ -24,7 +24,7 @@ from beets import art, config, logging, ui from beets.test import _common -from beets.test.helper import BeetsTestCase, FetchImageHelper +from beets.test.helper import BeetsTestCase, FetchImageHelper, PluginMixin from beets.util import bytestring_path, displayable_path, syspath from beets.util.artresizer import ArtResizer @@ -40,7 +40,8 @@ def wrapper(*args, **kwargs): return wrapper -class EmbedartCliTest(FetchImageHelper, BeetsTestCase): +class EmbedartCliTest(PluginMixin, FetchImageHelper, BeetsTestCase): + plugin = "embedart" small_artpath = os.path.join(_common.RSRC, b"image-2x3.jpg") abbey_artpath = os.path.join(_common.RSRC, b"abbey.jpg") abbey_similarpath = os.path.join(_common.RSRC, b"abbey-similar.jpg") @@ -49,7 +50,6 @@ class EmbedartCliTest(FetchImageHelper, BeetsTestCase): def setUp(self): super().setUp() # Converter is threaded self.io.install() - self.load_plugins("embedart") def _setup_data(self, artpath=None): if not artpath: @@ -57,10 +57,6 @@ def _setup_data(self, artpath=None): with open(syspath(artpath), "rb") as f: self.image_data = f.read() - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_embed_art_from_file_with_yes_input(self): self._setup_data() album = self.add_album_fixture() diff --git a/test/plugins/test_embyupdate.py b/test/plugins/test_embyupdate.py index d79c01a653..fe5fc6a817 100644 --- a/test/plugins/test_embyupdate.py +++ b/test/plugins/test_embyupdate.py @@ -2,14 +2,15 @@ import responses -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beetsplug import embyupdate -class EmbyUpdateTest(BeetsTestCase): +class EmbyUpdateTest(PluginTestCase): + plugin = "embyupdate" + def setUp(self): super().setUp() - self.load_plugins("embyupdate") self.config["emby"] = { "host": "localhost", @@ -18,10 +19,6 @@ def setUp(self): "password": "password", } - def tearDown(self): - super().tearDown() - self.unload_plugins() - def test_api_url_only_name(self): self.assertEqual( embyupdate.api_url( diff --git a/test/plugins/test_export.py b/test/plugins/test_export.py index acf76d48ba..32d51a512c 100644 --- a/test/plugins/test_export.py +++ b/test/plugins/test_export.py @@ -22,19 +22,16 @@ from xml.etree import ElementTree from xml.etree.ElementTree import Element -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase -class ExportPluginTest(BeetsTestCase): +class ExportPluginTest(PluginTestCase): + plugin = "export" + def setUp(self): super().setUp() - self.load_plugins("export") self.test_values = {"title": "xtitle", "album": "xalbum"} - def tearDown(self): - self.unload_plugins() - super().tearDown() - def execute_command(self, format_type, artist): query = ",".join(self.test_values.keys()) out = self.run_with_output( diff --git a/test/plugins/test_fetchart.py b/test/plugins/test_fetchart.py index ae1fcb96aa..c64c6f63c8 100644 --- a/test/plugins/test_fetchart.py +++ b/test/plugins/test_fetchart.py @@ -19,22 +19,19 @@ import unittest from beets import util -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase -class FetchartCliTest(BeetsTestCase): +class FetchartCliTest(PluginTestCase): + plugin = "fetchart" + def setUp(self): super().setUp() - self.load_plugins("fetchart") self.config["fetchart"]["cover_names"] = "c\xc3\xb6ver.jpg" self.config["art_filename"] = "mycover" self.album = self.add_album() self.cover_path = os.path.join(self.album.path, b"mycover.jpg") - def tearDown(self): - self.unload_plugins() - super().tearDown() - def check_cover_is_stored(self): self.assertEqual(self.album["artpath"], self.cover_path) with open(util.syspath(self.cover_path)) as f: diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index 32c8e0e02b..56a880b0be 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -17,19 +17,12 @@ import unittest -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beetsplug import ftintitle -class FtInTitlePluginFunctional(BeetsTestCase): - def setUp(self): - """Set up configuration""" - super().setUp() - self.load_plugins("ftintitle") - - def tearDown(self): - self.unload_plugins() - super().tearDown() +class FtInTitlePluginFunctional(PluginTestCase): + plugin = "ftintitle" def _ft_add_item(self, path, artist, title, aartist): return self.add_item( diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index b41b91eeea..ea50e87cde 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -19,7 +19,7 @@ import unittest from beets import importer -from beets.test.helper import AutotagStub, ImportTestCase +from beets.test.helper import AutotagStub, ImportTestCase, PluginMixin from beets.util import displayable_path, syspath from beetsplug.importadded import ImportAddedPlugin @@ -40,14 +40,14 @@ def modify_mtimes(paths, offset=-60000): os.utime(syspath(path), (mstat.st_atime, mstat.st_mtime + offset * i)) -class ImportAddedTest(ImportTestCase): +class ImportAddedTest(PluginMixin, ImportTestCase): # The minimum mtime of the files to be imported + plugin = "importadded" min_mtime = None def setUp(self): preserve_plugin_listeners() super().setUp() - self.load_plugins("importadded") self._create_import_dir(2) # Different mtimes on the files to be imported in order to test the # plugin @@ -61,7 +61,6 @@ def setUp(self): self.importer.add_choice(importer.action.APPLY) def tearDown(self): - self.unload_plugins() super().tearDown() self.matcher.restore() diff --git a/test/plugins/test_info.py b/test/plugins/test_info.py index 4ab8aa70c2..7b2969264d 100644 --- a/test/plugins/test_info.py +++ b/test/plugins/test_info.py @@ -17,18 +17,12 @@ from mediafile import MediaFile -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beets.util import displayable_path -class InfoTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.load_plugins("info") - - def tearDown(self): - self.unload_plugins() - super().tearDown() +class InfoTest(PluginTestCase): + plugin = "info" def test_path(self): path = self.create_mediafile_fixture() diff --git a/test/plugins/test_ipfs.py b/test/plugins/test_ipfs.py index 928b193f3c..5924c19231 100644 --- a/test/plugins/test_ipfs.py +++ b/test/plugins/test_ipfs.py @@ -17,20 +17,14 @@ from unittest.mock import Mock, patch from beets.test import _common -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beets.util import _fsencoding, bytestring_path from beetsplug.ipfs import IPFSPlugin @patch("beets.util.command_output", Mock()) -class IPFSPluginTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.load_plugins("ipfs") - - def tearDown(self): - self.unload_plugins() - super().tearDown() +class IPFSPluginTest(PluginTestCase): + plugin = "ipfs" def test_stored_hashes(self): test_album = self.mk_test_album() diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index dfd35f61f8..9afafe8227 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -18,18 +18,12 @@ from beets import util from beets.library import Item -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase @patch("beets.util.command_output") -class KeyFinderTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.load_plugins("keyfinder") - - def tearDown(self): - super().tearDown() - self.unload_plugins() +class KeyFinderTest(PluginTestCase): + plugin = "keyfinder" def test_add_key(self, command_output): item = Item(path="/file") diff --git a/test/plugins/test_limit.py b/test/plugins/test_limit.py index 2c01dca76d..f656075861 100644 --- a/test/plugins/test_limit.py +++ b/test/plugins/test_limit.py @@ -15,18 +15,19 @@ import unittest -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase -class LimitPluginTest(BeetsTestCase): +class LimitPluginTest(PluginTestCase): """Unit tests for LimitPlugin Note: query prefix tests do not work correctly with `run_with_output`. """ + plugin = "limit" + def setUp(self): super().setUp() - self.load_plugins("limit") # we'll create an even number of tracks in the library self.num_test_items = 10 @@ -46,10 +47,6 @@ def setUp(self): self.track_head_range = "track:.." + str(self.num_limit) self.track_tail_range = "track:" + str(self.num_limit + 1) + ".." - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_no_limit(self): """Returns all when there is no limit or filter.""" result = self.run_with_output("lslimit") diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index f82f8c851a..e8774d610e 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -18,22 +18,23 @@ from beets.test.helper import ( AutotagStub, ImportTestCase, + PluginMixin, TerminalImportMixin, capture_stdout, control_stdin, ) -class MBSubmitPluginTest(TerminalImportMixin, ImportTestCase): +class MBSubmitPluginTest(PluginMixin, TerminalImportMixin, ImportTestCase): + plugin = "mbsubmit" + def setUp(self): super().setUp() - self.load_plugins("mbsubmit") self._create_import_dir(2) self._setup_import_session() self.matcher = AutotagStub().install() def tearDown(self): - self.unload_plugins() super().tearDown() self.matcher.restore() diff --git a/test/plugins/test_mbsync.py b/test/plugins/test_mbsync.py index 62c08f685d..538c372f61 100644 --- a/test/plugins/test_mbsync.py +++ b/test/plugins/test_mbsync.py @@ -19,21 +19,15 @@ from beets import config from beets.library import Item from beets.test.helper import ( - BeetsTestCase, + PluginTestCase, capture_log, generate_album_info, generate_track_info, ) -class MbsyncCliTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.load_plugins("mbsync") - - def tearDown(self): - self.unload_plugins() - super().tearDown() +class MbsyncCliTest(PluginTestCase): + plugin = "mbsync" @patch("beets.autotag.mb.album_for_id") @patch("beets.autotag.mb.track_for_id") diff --git a/test/plugins/test_mpdstats.py b/test/plugins/test_mpdstats.py index e60a32f4f9..a0e00325de 100644 --- a/test/plugins/test_mpdstats.py +++ b/test/plugins/test_mpdstats.py @@ -18,18 +18,12 @@ from beets import util from beets.library import Item -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beetsplug.mpdstats import MPDStats -class MPDStatsTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.load_plugins("mpdstats") - - def tearDown(self): - super().tearDown() - self.unload_plugins() +class MPDStatsTest(PluginTestCase): + plugin = "mpdstats" def test_update_rating(self): item = Item(title="title", path="", id=1) diff --git a/test/plugins/test_parentwork.py b/test/plugins/test_parentwork.py index fedcc6ceb7..b1fd7e6692 100644 --- a/test/plugins/test_parentwork.py +++ b/test/plugins/test_parentwork.py @@ -20,7 +20,7 @@ from unittest.mock import patch from beets.library import Item -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beetsplug import parentwork work = { @@ -85,15 +85,8 @@ def mock_workid_response(mbid, includes): return p_work -class ParentWorkIntegrationTest(BeetsTestCase): - def setUp(self): - """Set up configuration""" - super().setUp() - self.load_plugins("parentwork") - - def tearDown(self): - self.unload_plugins() - super().tearDown() +class ParentWorkIntegrationTest(PluginTestCase): + plugin = "parentwork" # test how it works with real musicbrainz data @unittest.skipUnless( @@ -180,18 +173,18 @@ def test_direct_parent_work_real(self): ) -class ParentWorkTest(BeetsTestCase): +class ParentWorkTest(PluginTestCase): + plugin = "parentwork" + def setUp(self): """Set up configuration""" super().setUp() - self.load_plugins("parentwork") self.patcher = patch( "musicbrainzngs.get_work_by_id", side_effect=mock_workid_response ) self.patcher.start() def tearDown(self): - self.unload_plugins() super().tearDown() self.patcher.stop() diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index 14ac77cfcf..c1655ca112 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -7,7 +7,7 @@ from unittest.mock import Mock, patch from beets.test._common import touch -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beets.util import displayable_path from beetsplug.permissions import ( check_permissions, @@ -16,17 +16,14 @@ ) -class PermissionsPluginTest(BeetsTestCase): +class PermissionsPluginTest(PluginTestCase): + plugin = "permissions" + def setUp(self): super().setUp() - self.load_plugins("permissions") self.config["permissions"] = {"file": "777", "dir": "777"} - def tearDown(self): - super().tearDown() - self.unload_plugins() - def test_permissions_on_album_imported(self): self.do_thing(True) diff --git a/test/plugins/test_play.py b/test/plugins/test_play.py index 563cb7f3ae..9c15e85507 100644 --- a/test/plugins/test_play.py +++ b/test/plugins/test_play.py @@ -20,27 +20,23 @@ import unittest from unittest.mock import ANY, patch -from beets.test.helper import BeetsTestCase, CleanupModulesMixin, control_stdin +from beets.test.helper import CleanupModulesMixin, PluginTestCase, control_stdin from beets.ui import UserError from beets.util import open_anything from beetsplug.play import PlayPlugin @patch("beetsplug.play.util.interactive_open") -class PlayPluginTest(CleanupModulesMixin, BeetsTestCase): +class PlayPluginTest(CleanupModulesMixin, PluginTestCase): modules = (PlayPlugin.__module__,) + plugin = "play" def setUp(self): super().setUp() - self.load_plugins("play") self.item = self.add_item(album="a nice älbum", title="aNiceTitle") self.lib.add_album([self.item]) self.config["play"]["command"] = "echo" - def tearDown(self): - super().tearDown() - self.unload_plugins() - def run_and_assert( self, open_mock, diff --git a/test/plugins/test_player.py b/test/plugins/test_player.py index f0a3f3b664..4b77d1f5b3 100644 --- a/test/plugins/test_player.py +++ b/test/plugins/test_player.py @@ -32,7 +32,7 @@ import confuse import yaml -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beets.util import bluelet from beetsplug import bpd @@ -277,12 +277,12 @@ def listener_wrap(host, port): beets.ui.main(args) -class BPDTestHelper(BeetsTestCase): +class BPDTestHelper(PluginTestCase): db_on_disk = True + plugin = "bpd" def setUp(self): super().setUp() - self.load_plugins("bpd") self.item1 = self.add_item( title="Track One Title", track=1, @@ -297,10 +297,6 @@ def setUp(self): ) self.lib.add_album([self.item1, self.item2]) - def tearDown(self): - super().tearDown() - self.unload_plugins() - @contextmanager def run_bpd( self, diff --git a/test/plugins/test_plexupdate.py b/test/plugins/test_plexupdate.py index ba4890dbee..c27ff7fc34 100644 --- a/test/plugins/test_plexupdate.py +++ b/test/plugins/test_plexupdate.py @@ -2,11 +2,13 @@ import responses -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase from beetsplug.plexupdate import get_music_section, update_plex -class PlexUpdateTest(BeetsTestCase): +class PlexUpdateTest(PluginTestCase): + plugin = "plexupdate" + def add_response_get_music_section(self, section_name="Music"): """Create response for mocking the get_music_section function.""" @@ -74,14 +76,9 @@ def add_response_update_plex(self): def setUp(self): super().setUp() - self.load_plugins("plexupdate") self.config["plex"] = {"host": "localhost", "port": 32400} - def tearDown(self): - super().tearDown() - self.unload_plugins() - @responses.activate def test_get_music_section(self): # Adding response. diff --git a/test/plugins/test_smartplaylist.py b/test/plugins/test_smartplaylist.py index f2aa5e1ab4..0c37f1bd16 100644 --- a/test/plugins/test_smartplaylist.py +++ b/test/plugins/test_smartplaylist.py @@ -23,7 +23,7 @@ from beets.dbcore import OrQuery from beets.dbcore.query import FixedFieldSort, MultipleSort, NullSort from beets.library import Album, Item, parse_query_string -from beets.test.helper import BeetsTestCase +from beets.test.helper import BeetsTestCase, PluginTestCase from beets.ui import UserError from beets.util import CHAR_REPLACE, bytestring_path, syspath from beetsplug.smartplaylist import SmartPlaylistPlugin @@ -338,7 +338,9 @@ def test_playlist_update_uri_format(self): self.assertEqual(content, b"http://beets:8337/item/3/file\n") -class SmartPlaylistCLITest(BeetsTestCase): +class SmartPlaylistCLITest(PluginTestCase): + plugin = "smartplaylist" + def setUp(self): super().setUp() @@ -350,11 +352,6 @@ def setUp(self): ] ) config["smartplaylist"]["playlist_dir"].set(fsdecode(self.temp_dir)) - self.load_plugins("smartplaylist") - - def tearDown(self): - self.unload_plugins() - super().tearDown() def test_splupdate(self): with self.assertRaises(UserError): diff --git a/test/plugins/test_types_plugin.py b/test/plugins/test_types_plugin.py index 2f00ec4252..13f1669326 100644 --- a/test/plugins/test_types_plugin.py +++ b/test/plugins/test_types_plugin.py @@ -19,17 +19,11 @@ from confuse import ConfigValueError -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase -class TypesPluginTest(BeetsTestCase): - def setUp(self): - super().setUp() - self.load_plugins("types") - - def tearDown(self): - self.unload_plugins() - super().tearDown() +class TypesPluginTest(PluginTestCase): + plugin = "types" def test_integer_modify_and_query(self): self.config["types"] = {"myint": "int"} diff --git a/test/test_importer.py b/test/test_importer.py index 9800604885..609887ceda 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -38,25 +38,22 @@ AutotagStub, BeetsTestCase, ImportTestCase, + PluginMixin, capture_log, has_program, ) from beets.util import bytestring_path, displayable_path, syspath -class ScrubbedImportTest(ImportTestCase): +class ScrubbedImportTest(PluginMixin, ImportTestCase): db_on_disk = True + plugin = "scrub" def setUp(self): super().setUp() - self.load_plugins("scrub") self._create_import_dir(2) self._setup_import_session(autotag=False) - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_tags_not_scrubbed(self): config["plugins"] = ["scrub"] config["scrub"]["auto"] = False diff --git a/test/test_logging.py b/test/test_logging.py index 97786ec18b..e7a4a6cad4 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -10,7 +10,7 @@ import beetsplug from beets import plugins, ui from beets.test import _common, helper -from beets.test.helper import BeetsTestCase +from beets.test.helper import BeetsTestCase, PluginTestCase class LoggingTest(BeetsTestCase): @@ -47,7 +47,8 @@ def test_str_format_logging(self): self.assertTrue(stream.getvalue(), "foo oof baz") -class LoggingLevelTest(BeetsTestCase): +class LoggingLevelTest(PluginTestCase): + plugin = "dummy" class DummyModule: class DummyPlugin(plugins.BeetsPlugin): def __init__(self): @@ -75,10 +76,8 @@ def setUp(self): sys.modules["beetsplug.dummy"] = self.DummyModule beetsplug.dummy = self.DummyModule super().setUp() - self.load_plugins("dummy") def tearDown(self): - self.unload_plugins() super().tearDown() del beetsplug.dummy sys.modules.pop("beetsplug.dummy") diff --git a/test/test_metasync.py b/test/test_metasync.py index f320d4a5e6..146d899436 100644 --- a/test/test_metasync.py +++ b/test/test_metasync.py @@ -21,7 +21,7 @@ from beets.library import Item from beets.test import _common -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase def _parsetime(s): @@ -32,7 +32,8 @@ def _is_windows(): return platform.system() == "Windows" -class MetaSyncTest(BeetsTestCase): +class MetaSyncTest(PluginTestCase): + plugin = "metasync" itunes_library_unix = os.path.join(_common.RSRC, b"itunes_library_unix.xml") itunes_library_windows = os.path.join( _common.RSRC, b"itunes_library_windows.xml" @@ -40,7 +41,6 @@ class MetaSyncTest(BeetsTestCase): def setUp(self): super().setUp() - self.load_plugins("metasync") self.config["metasync"]["source"] = "itunes" @@ -83,10 +83,6 @@ def _set_up_data(self): for item in items: self.lib.add(item) - def tearDown(self): - self.unload_plugins() - super().tearDown() - def test_load_item_types(self): # This test also verifies that the MetaSources have loaded correctly self.assertIn("amarok_score", Item._types) diff --git a/test/test_plugins.py b/test/test_plugins.py index bda12c2d21..abc6a69681 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -31,12 +31,9 @@ from beets.library import Item from beets.plugins import MetadataSourcePlugin from beets.test import helper -from beets.test.helper import ( - AutotagStub, - BeetsTestCase, - ImportHelper, - TerminalImportMixin, -) +from beets.test.helper import AutotagStub, ImportHelper +from beets.test.helper import PluginTestCase as BasePluginTestCase +from beets.test.helper import TerminalImportMixin from beets.util import displayable_path, syspath from beets.util.id_extractors import ( beatport_id_regex, @@ -45,11 +42,10 @@ ) -class PluginLoaderTestCase(BeetsTestCase): +class PluginLoaderTestCase(BasePluginTestCase): def setup_plugin_loader(self): # FIXME the mocking code is horrific, but this is the lowest and # earliest level of the plugin mechanism we can hook into. - self.load_plugins() self._plugin_loader_patch = patch("beets.plugins.load_plugins") self._plugin_classes = set() load_plugins = self._plugin_loader_patch.start() @@ -58,17 +54,16 @@ def myload(names=()): plugins._classes.update(self._plugin_classes) load_plugins.side_effect = myload - super().setUp() def teardown_plugin_loader(self): self._plugin_loader_patch.stop() - self.unload_plugins() def register_plugin(self, plugin_class): self._plugin_classes.add(plugin_class) def setUp(self): self.setup_plugin_loader() + super().setUp() def tearDown(self): self.teardown_plugin_loader() @@ -174,7 +169,6 @@ def test_import_task_created(self): with helper.capture_log() as logs: self.importer.run() - self.unload_plugins() # Exactly one event should have been imported (for the album). # Sentinels do not get emitted. @@ -226,7 +220,6 @@ def import_task_created_event(self, session, task): with helper.capture_log() as logs: self.importer.run() - self.unload_plugins() # Exactly one event should have been imported (for the album). # Sentinels do not get emitted. From fcff5d72afefaa299e21b7b894420ffe3a5d3bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sun, 7 Jul 2024 17:48:08 +0100 Subject: [PATCH 14/29] Remove def suite TestLoader definitions --- test/plugins/test_acousticbrainz.py | 8 -------- test/plugins/test_advancedrewrite.py | 9 --------- test/plugins/test_albumtypes.py | 1 + test/plugins/test_art.py | 9 --------- test/plugins/test_bareasc.py | 11 +---------- test/plugins/test_beatport.py | 9 --------- test/plugins/test_bucket.py | 10 ---------- test/plugins/test_convert.py | 8 -------- test/plugins/test_discogs.py | 9 --------- test/plugins/test_edit.py | 9 --------- test/plugins/test_embedart.py | 8 -------- test/plugins/test_embyupdate.py | 10 ---------- test/plugins/test_export.py | 9 --------- test/plugins/test_fetchart.py | 9 --------- test/plugins/test_filefilter.py | 9 --------- test/plugins/test_ftintitle.py | 8 -------- test/plugins/test_hook.py | 8 -------- test/plugins/test_ihate.py | 8 -------- test/plugins/test_importadded.py | 9 --------- test/plugins/test_importfeeds.py | 9 --------- test/plugins/test_info.py | 10 ---------- test/plugins/test_ipfs.py | 9 --------- test/plugins/test_keyfinder.py | 9 --------- test/plugins/test_lastgenre.py | 9 --------- test/plugins/test_limit.py | 9 --------- test/plugins/test_lyrics.py | 8 -------- test/plugins/test_mbsubmit.py | 10 ---------- test/plugins/test_mbsync.py | 9 --------- test/plugins/test_mpdstats.py | 9 --------- test/plugins/test_parentwork.py | 8 -------- test/plugins/test_permissions.py | 9 --------- test/plugins/test_play.py | 8 -------- test/plugins/test_player.py | 8 -------- test/plugins/test_playlist.py | 9 --------- test/plugins/test_plexupdate.py | 10 ---------- test/plugins/test_plugin_mediafield.py | 9 --------- test/plugins/test_random.py | 8 -------- test/plugins/test_replaygain.py | 9 --------- test/plugins/test_smartplaylist.py | 9 --------- test/plugins/test_spotify.py | 9 --------- test/plugins/test_subsonicupdate.py | 10 ---------- test/plugins/test_the.py | 10 ---------- test/plugins/test_thumbnails.py | 9 --------- test/plugins/test_types_plugin.py | 9 --------- test/plugins/test_web.py | 9 --------- test/plugins/test_zero.py | 10 ---------- test/test_art_resize.py | 9 --------- test/test_autotag.py | 8 -------- test/test_config_command.py | 9 --------- test/test_datequery.py | 8 -------- test/test_dbcore.py | 8 -------- test/test_files.py | 8 -------- test/test_hidden.py | 8 -------- test/test_importer.py | 8 -------- test/test_library.py | 8 -------- test/test_logging.py | 10 +--------- test/test_m3ufile.py | 9 --------- test/test_mb.py | 8 -------- test/test_metasync.py | 9 --------- test/test_pipeline.py | 8 -------- test/test_plugins.py | 8 -------- test/test_query.py | 8 -------- test/test_sort.py | 9 --------- test/test_template.py | 8 -------- test/test_ui.py | 8 -------- test/test_ui_commands.py | 9 --------- test/test_ui_importer.py | 9 --------- test/test_ui_init.py | 9 --------- test/test_util.py | 8 -------- test/test_vfs.py | 9 --------- test/testall.py | 18 ------------------ 71 files changed, 3 insertions(+), 623 deletions(-) diff --git a/test/plugins/test_acousticbrainz.py b/test/plugins/test_acousticbrainz.py index fbf83def00..0182e57079 100644 --- a/test/plugins/test_acousticbrainz.py +++ b/test/plugins/test_acousticbrainz.py @@ -99,11 +99,3 @@ def test_realistic(self): ("timbre", "bright"), } self.assertEqual(mapping, expected) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_advancedrewrite.py b/test/plugins/test_advancedrewrite.py index 491e76127b..782b779e82 100644 --- a/test/plugins/test_advancedrewrite.py +++ b/test/plugins/test_advancedrewrite.py @@ -15,7 +15,6 @@ """Test the advancedrewrite plugin for various configurations. """ -import unittest from beets.test.helper import BeetsTestCase from beets.ui import UserError @@ -154,11 +153,3 @@ def test_combined_rewrite_example(self): album="C", ) self.assertEqual(item.artist, "D") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_albumtypes.py b/test/plugins/test_albumtypes.py index a6dfafe65c..3dd63e9de5 100644 --- a/test/plugins/test_albumtypes.py +++ b/test/plugins/test_albumtypes.py @@ -24,6 +24,7 @@ class AlbumTypesPluginTest(PluginTestCase): """Tests for albumtypes plugin.""" + plugin = "albumtypes" def test_renames_types(self): diff --git a/test/plugins/test_art.py b/test/plugins/test_art.py index 3e9f016dad..ce86b257f4 100644 --- a/test/plugins/test_art.py +++ b/test/plugins/test_art.py @@ -17,7 +17,6 @@ import os import shutil -import unittest from unittest.mock import patch import confuse @@ -1016,11 +1015,3 @@ def test_px(self): def test_percent(self): self._load_with_config("0% 0.00% 5.1% 5% 100%".split(), False) self._load_with_config("00% 1.234% foo5% 100.1%".split(), True) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_bareasc.py b/test/plugins/test_bareasc.py index 61c600bad3..393d686c89 100644 --- a/test/plugins/test_bareasc.py +++ b/test/plugins/test_bareasc.py @@ -3,7 +3,6 @@ """Tests for the 'bareasc' plugin.""" -import unittest from beets import logging from beets.test.helper import PluginTestCase, capture_stdout @@ -11,6 +10,7 @@ class BareascPluginTest(PluginTestCase): """Test bare ASCII query matching.""" + plugin = "bareasc" def setUp(self): @@ -81,12 +81,3 @@ def test_bareasc_format_output(self): ) self.assertEqual("Antonin Dvorak:: with accents\n", output.getvalue()) - - -def suite(): - """loader.""" - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_beatport.py b/test/plugins/test_beatport.py index 5e5130a5de..e988c9b4c4 100644 --- a/test/plugins/test_beatport.py +++ b/test/plugins/test_beatport.py @@ -15,7 +15,6 @@ """Tests for the 'beatport' plugin. """ -import unittest from datetime import timedelta from beets.test import _common @@ -656,11 +655,3 @@ def test_genre_empty(self): self.assertEqual( tracks[0].genre, self.test_tracks[0]["subGenres"][0]["name"] ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_bucket.py b/test/plugins/test_bucket.py index 9220621103..4a16fd9949 100644 --- a/test/plugins/test_bucket.py +++ b/test/plugins/test_bucket.py @@ -15,8 +15,6 @@ """Tests for the 'bucket' plugin.""" -import unittest - from beets import config, ui from beets.test.helper import BeetsTestCase from beetsplug import bucket @@ -165,11 +163,3 @@ def test_span_from_str(self): self.check_span_from_str("1980 00", 1980, 2000) self.check_span_from_str("1930 00", 1930, 2000) self.check_span_from_str("1930 50", 1930, 1950) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index 1b864499aa..b82592d640 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -343,11 +343,3 @@ def test_transcode_from_lossy_prevented(self): self.run_convert_path(item.path) converted = os.path.join(self.convert_dest, b"converted.ogg") self.assertNoFileTag(converted, "mp3") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_discogs.py b/test/plugins/test_discogs.py index 203a8a3763..416ca02767 100644 --- a/test/plugins/test_discogs.py +++ b/test/plugins/test_discogs.py @@ -15,7 +15,6 @@ """Tests for discogs plugin. """ -import unittest from beets import config from beets.test._common import Bag @@ -424,11 +423,3 @@ def test_append_style_to_genre_no_style(self): d = DiscogsPlugin().get_album_info(release) self.assertEqual(d.genre, "GENRE1, GENRE2") self.assertEqual(d.style, None) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 8244704d09..927376a721 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -13,7 +13,6 @@ # included in all copies or substantial portions of the Software. import codecs -import unittest from unittest.mock import patch from beets.dbcore.query import TrueQuery @@ -514,11 +513,3 @@ def test_edit_apply_candidate_singleton(self): all("Edited Title " in i.title for i in self.lib.items()) ) self.assertTrue(all("match " in i.mb_trackid for i in self.lib.items())) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_embedart.py b/test/plugins/test_embedart.py index a58cd2f289..57a5b303a3 100644 --- a/test/plugins/test_embedart.py +++ b/test/plugins/test_embedart.py @@ -339,11 +339,3 @@ def test_compare_parsing_error_and_failure( def test_convert_failure(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, convert_status=1) self.assertIsNone(self._similarity(20)) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_embyupdate.py b/test/plugins/test_embyupdate.py index fe5fc6a817..5d9d37af48 100644 --- a/test/plugins/test_embyupdate.py +++ b/test/plugins/test_embyupdate.py @@ -1,5 +1,3 @@ -import unittest - import responses from beets.test.helper import PluginTestCase @@ -235,11 +233,3 @@ def test_get_user(self): self.assertEqual(response[0]["Id"], "2ec276a2642e54a19b612b9418a8bd3b") self.assertEqual(response[0]["Name"], "username") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_export.py b/test/plugins/test_export.py index 32d51a512c..f9f28f8de8 100644 --- a/test/plugins/test_export.py +++ b/test/plugins/test_export.py @@ -18,7 +18,6 @@ import json import re # used to test csv format -import unittest from xml.etree import ElementTree from xml.etree.ElementTree import Element @@ -85,11 +84,3 @@ def test_xml_output(self): txt = details.text self.assertIn(tag, self.test_values, msg=tag) self.assertEqual(self.test_values[tag], txt, msg=txt) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_fetchart.py b/test/plugins/test_fetchart.py index c64c6f63c8..86696df2d1 100644 --- a/test/plugins/test_fetchart.py +++ b/test/plugins/test_fetchart.py @@ -16,7 +16,6 @@ import ctypes import os import sys -import unittest from beets import util from beets.test.helper import PluginTestCase @@ -99,11 +98,3 @@ def test_filesystem_picks_up_hidden_file(self): self.run_command("fetchart") self.album.load() self.check_cover_is_stored() - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index f55aedbac3..4af0a4be72 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -18,7 +18,6 @@ import os import shutil -import unittest from mediafile import MediaFile @@ -217,11 +216,3 @@ def test_import_both(self): ], singletons=True, ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index 56a880b0be..da426e5083 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -169,11 +169,3 @@ def test_contains_feat(self): self.assertTrue(ftintitle.contains_feat("Alice With Bob")) self.assertFalse(ftintitle.contains_feat("Alice defeat Bob")) self.assertFalse(ftintitle.contains_feat("Aliceft.Bob")) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_hook.py b/test/plugins/test_hook.py index ef26fd1a68..8d44423181 100644 --- a/test/plugins/test_hook.py +++ b/test/plugins/test_hook.py @@ -160,11 +160,3 @@ def test_hook_bytes_interpolation(self): for path in temporary_paths: self.assertTrue(os.path.isfile(path)) os.remove(path) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_ihate.py b/test/plugins/test_ihate.py index fdd656703c..92855d4166 100644 --- a/test/plugins/test_ihate.py +++ b/test/plugins/test_ihate.py @@ -43,11 +43,3 @@ def test_hate(self): "artist:testartist album:notthis", ] self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern)) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index ea50e87cde..f1a7746b16 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -16,7 +16,6 @@ """Tests for the `importadded` plugin.""" import os -import unittest from beets import importer from beets.test.helper import AutotagStub, ImportTestCase, PluginMixin @@ -167,11 +166,3 @@ def test_reimported_singletons_skipped(self): "reimport modified Item.added for " + displayable_path(item_path), ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_importfeeds.py b/test/plugins/test_importfeeds.py index a8985d0bff..2b640ca377 100644 --- a/test/plugins/test_importfeeds.py +++ b/test/plugins/test_importfeeds.py @@ -1,7 +1,6 @@ import datetime import os import os.path -import unittest from beets import config from beets.library import Album, Item @@ -67,11 +66,3 @@ def test_playlist_per_session(self): self.assertTrue(os.path.isfile(playlist)) with open(playlist) as playlist_contents: self.assertIn(item_path, playlist_contents.read()) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_info.py b/test/plugins/test_info.py index 7b2969264d..102aceb83a 100644 --- a/test/plugins/test_info.py +++ b/test/plugins/test_info.py @@ -13,8 +13,6 @@ # included in all copies or substantial portions of the Software. -import unittest - from mediafile import MediaFile from beets.test.helper import PluginTestCase @@ -118,11 +116,3 @@ def test_custom_format(self): "$track. $title - $artist ($length)", ) self.assertEqual("02. tïtle 0 - the artist (0:01)\n", out) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_ipfs.py b/test/plugins/test_ipfs.py index 5924c19231..2640ef98fb 100644 --- a/test/plugins/test_ipfs.py +++ b/test/plugins/test_ipfs.py @@ -13,7 +13,6 @@ import os -import unittest from unittest.mock import Mock, patch from beets.test import _common @@ -79,11 +78,3 @@ def mk_test_album(self): album.store(inherit=False) return album - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index 9afafe8227..fbf0ae0f67 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -13,7 +13,6 @@ # included in all copies or substantial portions of the Software. -import unittest from unittest.mock import patch from beets import util @@ -77,11 +76,3 @@ def test_no_key(self, command_output): item.load() self.assertIsNone(item["initial_key"]) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_lastgenre.py b/test/plugins/test_lastgenre.py index 249ecb5fd3..9efcf5fc41 100644 --- a/test/plugins/test_lastgenre.py +++ b/test/plugins/test_lastgenre.py @@ -15,7 +15,6 @@ """Tests for the 'lastgenre' plugin.""" -import unittest from unittest.mock import Mock from beets import config @@ -230,11 +229,3 @@ def test_sort_by_depth(self): tags = ("electronic", "ambient", "chillout") res = self.plugin._sort_by_depth(tags) self.assertEqual(res, ["ambient", "electronic"]) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_limit.py b/test/plugins/test_limit.py index f656075861..5377cd43b8 100644 --- a/test/plugins/test_limit.py +++ b/test/plugins/test_limit.py @@ -13,7 +13,6 @@ """Tests for the 'limit' plugin.""" -import unittest from beets.test.helper import PluginTestCase @@ -94,11 +93,3 @@ def test_prefix_when_incorrectly_ordred(self): incorrect_order = self.num_limit_prefix + " " + self.track_tail_range result = self.lib.items(incorrect_order) self.assertEqual(len(result), 0) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_lyrics.py b/test/plugins/test_lyrics.py index 39fb19a24e..0066235352 100644 --- a/test/plugins/test_lyrics.py +++ b/test/plugins/test_lyrics.py @@ -816,11 +816,3 @@ def test_slug(self): dashes = ["\u200D", "\u2010"] for dash1, dash2 in itertools.combinations(dashes, 2): self.assertEqual(lyrics.slug(dash1), lyrics.slug(dash2)) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index e8774d610e..29c8a687a8 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -13,8 +13,6 @@ # included in all copies or substantial portions of the Software. -import unittest - from beets.test.helper import ( AutotagStub, ImportTestCase, @@ -69,11 +67,3 @@ def test_print_tracks_output_as_tracks(self): "Open files with Picard? " "02. Tag Title 2 - Tag Artist (0:01)" ) self.assertIn(tracklist, output.getvalue()) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_mbsync.py b/test/plugins/test_mbsync.py index 538c372f61..759a4a2b49 100644 --- a/test/plugins/test_mbsync.py +++ b/test/plugins/test_mbsync.py @@ -13,7 +13,6 @@ # included in all copies or substantial portions of the Software. -import unittest from unittest.mock import patch from beets import config @@ -188,11 +187,3 @@ def test_message_when_invalid(self): self.run_command("mbsync", "-f", "'$title'") e = "mbsync: Skipping singleton with invalid mb_trackid: 'old title'" self.assertEqual(e, logs[0]) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_mpdstats.py b/test/plugins/test_mpdstats.py index a0e00325de..325fd5cd32 100644 --- a/test/plugins/test_mpdstats.py +++ b/test/plugins/test_mpdstats.py @@ -13,7 +13,6 @@ # included in all copies or substantial portions of the Software. -import unittest from unittest.mock import ANY, Mock, call, patch from beets import util @@ -82,11 +81,3 @@ def test_run_mpdstats(self, mpd_mock): log.info.assert_has_calls( [call("pause"), call("playing {0}", ANY), call("stop")] ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_parentwork.py b/test/plugins/test_parentwork.py index b1fd7e6692..3ee0e1fb8c 100644 --- a/test/plugins/test_parentwork.py +++ b/test/plugins/test_parentwork.py @@ -232,11 +232,3 @@ def test_no_force(self): def test_direct_parent_work(self): self.assertEqual("2", parentwork.direct_parent_id("1")[0]) self.assertEqual("3", parentwork.work_parent_id("1")[0]) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index c1655ca112..e5db878d05 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -3,7 +3,6 @@ import os import platform -import unittest from unittest.mock import Mock, patch from beets.test._common import touch @@ -103,11 +102,3 @@ def do_set_art(self, expect_success): self.assertEqual( expect_success, check_permissions(album.artpath, 0o777) ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_play.py b/test/plugins/test_play.py index 9c15e85507..45e87a3286 100644 --- a/test/plugins/test_play.py +++ b/test/plugins/test_play.py @@ -141,11 +141,3 @@ def test_command_failed(self, open_mock): with self.assertRaises(UserError): self.run_command("play", "title:aNiceTitle") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_player.py b/test/plugins/test_player.py index 4b77d1f5b3..627b486612 100644 --- a/test/plugins/test_player.py +++ b/test/plugins/test_player.py @@ -1193,11 +1193,3 @@ class BPDPeersTest(BPDTestHelper): }, expectedFailure=True, ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_playlist.py b/test/plugins/test_playlist.py index 74befd71f6..8a8ef85a77 100644 --- a/test/plugins/test_playlist.py +++ b/test/plugins/test_playlist.py @@ -14,7 +14,6 @@ import os -import unittest from shlex import quote import beets @@ -387,11 +386,3 @@ def test_item_removed(self): "nonexisting.mp3", ], ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_plexupdate.py b/test/plugins/test_plexupdate.py index c27ff7fc34..e84e798cf1 100644 --- a/test/plugins/test_plexupdate.py +++ b/test/plugins/test_plexupdate.py @@ -1,5 +1,3 @@ -import unittest - import responses from beets.test.helper import PluginTestCase @@ -132,11 +130,3 @@ def test_update_plex(self): ).status_code, 200, ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_plugin_mediafield.py b/test/plugins/test_plugin_mediafield.py index 938f1244bf..6f933c54cb 100644 --- a/test/plugins/test_plugin_mediafield.py +++ b/test/plugins/test_plugin_mediafield.py @@ -17,7 +17,6 @@ import os import shutil -import unittest import mediafile @@ -124,11 +123,3 @@ def test_overwrite_property(self): with self.assertRaises(ValueError) as cm: mediafile.MediaFile.add_field("artist", mediafile.MediaField()) self.assertIn('property "artist" already exists', str(cm.exception)) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_random.py b/test/plugins/test_random.py index 842e018ebd..84edb4bc6a 100644 --- a/test/plugins/test_random.py +++ b/test/plugins/test_random.py @@ -77,11 +77,3 @@ def experiment(field, histogram=False): self.assertAlmostEqual(0, median1, delta=1) self.assertAlmostEqual(len(self.items) // 2, median2, delta=1) self.assertGreater(stdev2, stdev1) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index 94846c9689..65b27d1bce 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -392,12 +392,3 @@ class ReplayGainFfmpegThreadedImportTest( ThreadedImportMixin, ImportTest, ReplayGainTestCase, FfmpegBackendMixin ): pass - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_smartplaylist.py b/test/plugins/test_smartplaylist.py index 0c37f1bd16..4959c5c8fd 100644 --- a/test/plugins/test_smartplaylist.py +++ b/test/plugins/test_smartplaylist.py @@ -13,7 +13,6 @@ # included in all copies or substantial portions of the Software. -import unittest from os import fsdecode, path, remove from shutil import rmtree from tempfile import mkdtemp @@ -373,11 +372,3 @@ def test_splupdate(self): for name in (b"my_playlist.m3u", b"all.m3u"): with open(path.join(self.temp_dir, name), "rb") as f: self.assertEqual(f.read(), self.item.path + b"\n") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_spotify.py b/test/plugins/test_spotify.py index 2a385195bd..d61c3e85a2 100644 --- a/test/plugins/test_spotify.py +++ b/test/plugins/test_spotify.py @@ -1,7 +1,6 @@ """Tests for the 'spotify' plugin""" import os -import unittest from urllib.parse import parse_qs, urlparse import responses @@ -177,11 +176,3 @@ def test_track_for_id(self): results = self.spotify._match_library_tracks(self.lib, "Happy") self.assertEqual(1, len(results)) self.assertEqual("6NPVjNh8Jhru9xOmyQigds", results[0]["id"]) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_subsonicupdate.py b/test/plugins/test_subsonicupdate.py index 9cfcef47e1..891f75cb78 100644 --- a/test/plugins/test_subsonicupdate.py +++ b/test/plugins/test_subsonicupdate.py @@ -1,6 +1,5 @@ """Tests for the 'subsonic' plugin.""" -import unittest from urllib.parse import parse_qs, urlparse import responses @@ -183,12 +182,3 @@ def test_url_with_missing_schema(self): ) self.subsonicupdate.start_scan() - - -def suite(): - """Default test suite.""" - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_the.py b/test/plugins/test_the.py index 4f23d6f133..3a48092df0 100644 --- a/test/plugins/test_the.py +++ b/test/plugins/test_the.py @@ -1,7 +1,5 @@ """Tests for the 'the' plugin""" -import unittest - from beets import config from beets.test.helper import BeetsTestCase from beetsplug.the import FORMAT, PATTERN_A, PATTERN_THE, ThePlugin @@ -61,11 +59,3 @@ def test_custom_format(self): config["the"]["patterns"] = [PATTERN_THE, PATTERN_A] config["the"]["format"] = "{1} ({0})" self.assertEqual(ThePlugin().the_template_func("The A"), "The (A)") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_thumbnails.py b/test/plugins/test_thumbnails.py index c2c22bed25..14e0de8cf5 100644 --- a/test/plugins/test_thumbnails.py +++ b/test/plugins/test_thumbnails.py @@ -14,7 +14,6 @@ import os.path -import unittest from shutil import rmtree from tempfile import mkdtemp from unittest.mock import Mock, call, patch @@ -281,11 +280,3 @@ def test_uri(self): # test it won't break if we pass it bytes for a path test_uri.uri(b"/") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_types_plugin.py b/test/plugins/test_types_plugin.py index 13f1669326..4ee3b4b34e 100644 --- a/test/plugins/test_types_plugin.py +++ b/test/plugins/test_types_plugin.py @@ -14,7 +14,6 @@ import time -import unittest from datetime import datetime from confuse import ConfigValueError @@ -193,11 +192,3 @@ def list_album(self, query, fmt="$albumartist - $album - $title"): def mktime(*args): return time.mktime(datetime(*args).timetuple()) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_web.py b/test/plugins/test_web.py index d2eb3f190d..6c703af5f6 100644 --- a/test/plugins/test_web.py +++ b/test/plugins/test_web.py @@ -4,7 +4,6 @@ import os.path import platform import shutil -import unittest from beets import logging from beets.library import Album, Item @@ -677,11 +676,3 @@ def test_get_item_file(self): response = self.client.get("/item/" + str(item_id) + "/file") self.assertEqual(response.status_code, 200) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index 8be71b686f..8b6427ae16 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -1,7 +1,5 @@ """Tests for the 'zero' plugin""" -import unittest - from mediafile import MediaFile from beets.library import Item @@ -292,11 +290,3 @@ def test_empty_query_n_response_no_changes(self): self.assertEqual(mf.year, 2016) self.assertEqual(mf.comments, "test comment") self.assertEqual(item["comments"], "test comment") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_art_resize.py b/test/test_art_resize.py index f5ec88f32f..3a2d5cc83a 100644 --- a/test/test_art_resize.py +++ b/test/test_art_resize.py @@ -154,12 +154,3 @@ def test_write_metadata_im(self, mock_util): except AssertionError: command = im.convert_cmd + "foo -set b B -set a A foo".split() mock_util.command_output.assert_called_once_with(command) - - -def suite(): - """Run this suite of tests.""" - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_autotag.py b/test/test_autotag.py index 8ff613cfff..eefa360231 100644 --- a/test/test_autotag.py +++ b/test/test_autotag.py @@ -1088,11 +1088,3 @@ def test_ordered_enum(self): self.assertGreater(OrderedEnumClass.b, OrderedEnumClass.a) self.assertGreater(OrderedEnumClass.c, OrderedEnumClass.a) self.assertGreater(OrderedEnumClass.c, OrderedEnumClass.b) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_config_command.py b/test/test_config_command.py index 4383f66645..980ef93a24 100644 --- a/test/test_config_command.py +++ b/test/test_config_command.py @@ -1,5 +1,4 @@ import os -import unittest from unittest.mock import patch import yaml @@ -128,11 +127,3 @@ def test_edit_invalid_config_file(self): with patch("os.execlp") as execlp: self.run_command("config", "-e") execlp.assert_called_once_with("myeditor", "myeditor", self.config_path) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_datequery.py b/test/test_datequery.py index 48740420ce..55fdf619ba 100644 --- a/test/test_datequery.py +++ b/test/test_datequery.py @@ -318,11 +318,3 @@ def test_datetime_space_separator(self): def test_datetime_invalid_separator(self): with self.assertRaises(InvalidQueryArgumentValueError): DateQuery("added", "2000-01-01x12") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_dbcore.py b/test/test_dbcore.py index 763601b7f1..803612d44c 100644 --- a/test/test_dbcore.py +++ b/test/test_dbcore.py @@ -762,11 +762,3 @@ def test_no_results(self): self.assertIsNone( self.db._fetch(ModelFixture1, dbcore.query.FalseQuery()).get() ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_files.py b/test/test_files.py index acece24d0f..99e790fe4b 100644 --- a/test/test_files.py +++ b/test/test_files.py @@ -692,11 +692,3 @@ def test_child_does_not_exist(self): path = os.path.join(self.temp_dir, b"foo", b"bar", b"baz", b"qux.mp3") util.mkdirall(path) self.assertNotExists(path) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_hidden.py b/test/test_hidden.py index f60f1f6e94..290bbe74b3 100644 --- a/test/test_hidden.py +++ b/test/test_hidden.py @@ -74,11 +74,3 @@ def test_other_hidden(self): with tempfile.NamedTemporaryFile(prefix=".tmp") as f: fn = util.bytestring_path(f.name) self.assertTrue(hidden.is_hidden(fn)) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_importer.py b/test/test_importer.py index 609887ceda..4d150acc32 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -2008,11 +2008,3 @@ def test_candidates_singleton(self): {"VALID_RECORDING_0", "VALID_RECORDING_1"}, {c.info.title for c in task.candidates}, ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_library.py b/test/test_library.py index e0ded46bab..3e35a44a02 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -1392,11 +1392,3 @@ def test_durationtype(self): beets.config["format_raw_length"] = True self.assertEqual(61.23, t.format(61.23)) self.assertEqual(3601.23, t.format(3601.23)) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_logging.py b/test/test_logging.py index e7a4a6cad4..fbc6a5f336 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -3,7 +3,6 @@ import logging as log import sys import threading -import unittest from io import StringIO import beets.logging as blog @@ -49,6 +48,7 @@ def test_str_format_logging(self): class LoggingLevelTest(PluginTestCase): plugin = "dummy" + class DummyModule: class DummyPlugin(plugins.BeetsPlugin): def __init__(self): @@ -281,11 +281,3 @@ def test_root_logger_levels(self): importer = self.create_importer() importer.run() self.assertIn("Sending event: database_change", logs) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_m3ufile.py b/test/test_m3ufile.py index 2db5cac06f..22a4105bca 100644 --- a/test/test_m3ufile.py +++ b/test/test_m3ufile.py @@ -148,12 +148,3 @@ def test_playlist_load_non_extm3u(self): m3ufile = M3UFile(the_playlist_file) m3ufile.load() self.assertFalse(m3ufile.extm3u) - - -def suite(): - """This testsuite's main function.""" - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_mb.py b/test/test_mb.py index 9922cbfa04..4b7d2806a2 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -1077,11 +1077,3 @@ def test_pseudo_releases_with_unsupported_links(self): gp.side_effect = side_effect album = mb.album_for_id("d2a6f856-b553-40a0-ac54-a321e8e2da02") self.assertIsNone(album.country) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_metasync.py b/test/test_metasync.py index 146d899436..4b97bf7d83 100644 --- a/test/test_metasync.py +++ b/test/test_metasync.py @@ -16,7 +16,6 @@ import os import platform import time -import unittest from datetime import datetime from beets.library import Item @@ -128,11 +127,3 @@ def test_sync_from_itunes(self): _parsetime("2014-04-24 09:28:38"), ) self.assertFalse(hasattr(self.lib.items()[1], "itunes_lastskipped")) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_pipeline.py b/test/test_pipeline.py index f5d4cebf33..a1fa203f32 100644 --- a/test/test_pipeline.py +++ b/test/test_pipeline.py @@ -230,11 +230,3 @@ def setkey(key, item): self.assertEqual( list(pl.pull()), [{"x": True}, {"a": False, "x": True}] ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_plugins.py b/test/test_plugins.py index abc6a69681..dd4db6aa28 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -632,11 +632,3 @@ def test_parse_id_url_finds_id(self): id_url = "https://www.beatport.com/release/album-name/%s" % id_string out = MetadataSourcePlugin._get_id("album", id_url, beatport_id_regex) self.assertEqual(out, id_string) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_query.py b/test/test_query.py index 02cdc16737..cdfcc7eedb 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -1161,11 +1161,3 @@ def test_filter_by_common_field(self): q = "catalognum:ABC Album1" results = self.lib.albums(q) self.assert_albums_matched(results, ["Album1"]) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_sort.py b/test/test_sort.py index 3d092e5511..d602c6cbac 100644 --- a/test/test_sort.py +++ b/test/test_sort.py @@ -15,7 +15,6 @@ """Various tests for querying the library database. """ -import unittest import beets.library from beets import config, dbcore @@ -531,11 +530,3 @@ def test_negation_interaction(self): self.assertTrue(isinstance(query.subqueries[0], dbcore.query.TrueQuery)) self.assertTrue(isinstance(sort, dbcore.query.SlowFieldSort)) self.assertEqual(sort.field, "-bar") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_template.py b/test/test_template.py index 24a5351dfd..1fc35f7a31 100644 --- a/test/test_template.py +++ b/test/test_template.py @@ -290,11 +290,3 @@ def test_not_subtitute_func_with_no_args(self): def test_function_call_with_empty_arg(self): self.assertEqual(self._eval("%len{}"), "0") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_ui.py b/test/test_ui.py index d35a900f91..70266b920f 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -1648,11 +1648,3 @@ def in_encoding_default_utf8(self): with patch("sys.stdin") as stdin: stdin.encoding = None self.assertEqual(ui._in_encoding(), "utf-8") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_ui_commands.py b/test/test_ui_commands.py index 735d0c393c..b88616beec 100644 --- a/test/test_ui_commands.py +++ b/test/test_ui_commands.py @@ -18,7 +18,6 @@ import os import shutil -import unittest from beets import library, ui from beets.test import _common @@ -104,11 +103,3 @@ def test_fields_func(self): self.assertEqual(len(items), 0) self.assertEqual(len(albums), 0) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_ui_importer.py b/test/test_ui_importer.py index 7dfcc205ef..5869badd30 100644 --- a/test/test_ui_importer.py +++ b/test/test_ui_importer.py @@ -18,7 +18,6 @@ ``TerminalImportSession``. So we test this class, too. """ -import unittest from test import test_importer from beets.test.helper import TerminalImportMixin @@ -70,11 +69,3 @@ class GlobalGroupAlbumsImportTest( TerminalImportMixin, test_importer.GlobalGroupAlbumsImportTest ): pass - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_ui_init.py b/test/test_ui_init.py index 813ef2dca8..c11bc5b82b 100644 --- a/test/test_ui_init.py +++ b/test/test_ui_init.py @@ -17,7 +17,6 @@ import os import shutil -import unittest from copy import deepcopy from random import random @@ -160,11 +159,3 @@ def test_create_no(self): if lib: lib._close() raise OSError("Parent directories should not be created.") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_util.py b/test/test_util.py index 63de482ffb..82ee94b377 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -216,11 +216,3 @@ def test_truncate_preserves_extension(self): with _common.platform_posix(): p = util.truncate_path("abcde/fgh.ext", 5) self.assertEqual(p, "abcde/f.ext") - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/test_vfs.py b/test/test_vfs.py index 34a5f5d308..1586493f97 100644 --- a/test/test_vfs.py +++ b/test/test_vfs.py @@ -14,7 +14,6 @@ """Tests for the virtual filesystem builder..""" -import unittest from beets import vfs from beets.test import _common @@ -41,11 +40,3 @@ def test_album_item(self): self.assertEqual( self.tree.dirs["albums"].dirs["the album"].files["the title"], 2 ) - - -def suite(): - return unittest.TestLoader().loadTestsFromName(__name__) - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") diff --git a/test/testall.py b/test/testall.py index 27d852a77b..af83dea88e 100755 --- a/test/testall.py +++ b/test/testall.py @@ -16,25 +16,7 @@ import os -import re import sys -import unittest pkgpath = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) or ".." sys.path.insert(0, pkgpath) - - -def suite(): - s = unittest.TestSuite() - # Get the suite() of every module in this directory beginning with - # "test_". - for fname in os.listdir(os.path.join(pkgpath, "test")): - match = re.match(r"(test_\S+)\.py$", fname) - if match: - modname = match.group(1) - s.addTest(__import__(modname).suite()) - return s - - -if __name__ == "__main__": - unittest.main(defaultTest="suite") From 1f8466f04a29566f246abf9f4a49879b7273b420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Tue, 9 Jul 2024 00:00:41 +0100 Subject: [PATCH 15/29] Move create_importer to ImportHelper --- beets/test/helper.py | 106 +++++++++++++++---------------- test/plugins/test_convert.py | 9 ++- test/plugins/test_keyfinder.py | 4 +- test/plugins/test_permissions.py | 4 +- test/plugins/test_replaygain.py | 4 +- test/test_importer.py | 8 +-- test/test_logging.py | 6 +- 7 files changed, 73 insertions(+), 68 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index c649981749..5409b34258 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -253,59 +253,6 @@ def unload_plugins(self): Item._queries = Item._original_queries Album._queries = Album._original_queries - def create_importer(self, item_count=1, album_count=1): - """Create files to import and return corresponding session. - - Copies the specified number of files to a subdirectory of - `self.temp_dir` and creates a `ImportSessionFixture` for this path. - """ - import_dir = os.path.join(self.temp_dir, b"import") - if not os.path.isdir(syspath(import_dir)): - os.mkdir(syspath(import_dir)) - - album_no = 0 - while album_count: - album = util.bytestring_path(f"album {album_no}") - album_dir = os.path.join(import_dir, album) - if os.path.exists(syspath(album_dir)): - album_no += 1 - continue - os.mkdir(syspath(album_dir)) - album_count -= 1 - - track_no = 0 - album_item_count = item_count - while album_item_count: - title = f"track {track_no}" - src = os.path.join(_common.RSRC, b"full.mp3") - title_file = util.bytestring_path(f"{title}.mp3") - dest = os.path.join(album_dir, title_file) - if os.path.exists(syspath(dest)): - track_no += 1 - continue - album_item_count -= 1 - shutil.copy(syspath(src), syspath(dest)) - mediafile = MediaFile(dest) - mediafile.update( - { - "artist": "artist", - "albumartist": "album artist", - "title": title, - "album": album, - "mb_albumid": None, - "mb_trackid": None, - } - ) - mediafile.save() - - config["import"]["quiet"] = True - config["import"]["autotag"] = False - config["import"]["resume"] = False - - return ImportSessionFixture( - self.lib, loghandler=None, query=None, paths=[import_dir] - ) - # Library fixtures methods def create_item(self, **values): @@ -642,6 +589,59 @@ def _setup_import_session( self._get_import_session(import_dir or self.import_dir) + def create_importer(self, item_count=1, album_count=1): + """Create files to import and return corresponding session. + + Copies the specified number of files to a subdirectory of + `self.temp_dir` and creates a `ImportSessionFixture` for this path. + """ + import_dir = os.path.join(self.temp_dir, b"import") + if not os.path.isdir(syspath(import_dir)): + os.mkdir(syspath(import_dir)) + + album_no = 0 + while album_count: + album = util.bytestring_path(f"album {album_no}") + album_dir = os.path.join(import_dir, album) + if os.path.exists(syspath(album_dir)): + album_no += 1 + continue + os.mkdir(syspath(album_dir)) + album_count -= 1 + + track_no = 0 + album_item_count = item_count + while album_item_count: + title = f"track {track_no}" + src = os.path.join(_common.RSRC, b"full.mp3") + title_file = util.bytestring_path(f"{title}.mp3") + dest = os.path.join(album_dir, title_file) + if os.path.exists(syspath(dest)): + track_no += 1 + continue + album_item_count -= 1 + shutil.copy(syspath(src), syspath(dest)) + mediafile = MediaFile(dest) + mediafile.update( + { + "artist": "artist", + "albumartist": "album artist", + "title": title, + "album": album, + "mb_albumid": None, + "mb_trackid": None, + } + ) + mediafile.save() + + config["import"]["quiet"] = True + config["import"]["autotag"] = False + config["import"]["resume"] = False + + return ImportSessionFixture( + self.lib, loghandler=None, query=None, paths=[import_dir] + ) + def assert_file_in_lib(self, *segments): """Join the ``segments`` and assert that this path exists in the library directory. diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index b82592d640..67b513bb9c 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -23,7 +23,12 @@ from beets import util from beets.test import _common -from beets.test.helper import PluginTestCase, capture_log, control_stdin +from beets.test.helper import ( + ImportHelper, + PluginTestCase, + capture_log, + control_stdin, +) from beets.util import bytestring_path, displayable_path @@ -90,7 +95,7 @@ class ConvertTestCase(ConvertMixin, PluginTestCase): @_common.slow_test() -class ImportConvertTest(ConvertTestCase): +class ImportConvertTest(ImportHelper, ConvertTestCase): def setUp(self): super().setUp() self.importer = self.create_importer() diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index fbf0ae0f67..d941df3cae 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -17,11 +17,11 @@ from beets import util from beets.library import Item -from beets.test.helper import PluginTestCase +from beets.test.helper import ImportTestCase, PluginMixin @patch("beets.util.command_output") -class KeyFinderTest(PluginTestCase): +class KeyFinderTest(PluginMixin, ImportTestCase): plugin = "keyfinder" def test_add_key(self, command_output): diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index e5db878d05..a83fbfb261 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -6,7 +6,7 @@ from unittest.mock import Mock, patch from beets.test._common import touch -from beets.test.helper import PluginTestCase +from beets.test.helper import ImportTestCase, PluginMixin from beets.util import displayable_path from beetsplug.permissions import ( check_permissions, @@ -15,7 +15,7 @@ ) -class PermissionsPluginTest(PluginTestCase): +class PermissionsPluginTest(PluginMixin, ImportTestCase): plugin = "permissions" def setUp(self): diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index 65b27d1bce..342902a631 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -19,7 +19,7 @@ from mediafile import MediaFile from beets import config -from beets.test.helper import BeetsTestCase, has_program +from beets.test.helper import ImportTestCase, has_program from beetsplug.replaygain import ( FatalGstreamerPluginReplayGainError, GStreamerBackend, @@ -52,7 +52,7 @@ def reset_replaygain(item): item.store() -class ReplayGainTestCase(BeetsTestCase): +class ReplayGainTestCase(ImportTestCase): db_on_disk = True backend: ClassVar[str] diff --git a/test/test_importer.py b/test/test_importer.py index 4d150acc32..62daa8a10d 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -1159,7 +1159,7 @@ def match_album_mock(*args, **kwargs): @patch("beets.autotag.mb.match_album", Mock(side_effect=match_album_mock)) -class ImportDuplicateAlbumTest(BeetsTestCase): +class ImportDuplicateAlbumTest(ImportTestCase): def setUp(self): super().setUp() @@ -1278,7 +1278,7 @@ def match_track_mock(*args, **kwargs): @patch("beets.autotag.mb.match_track", Mock(side_effect=match_track_mock)) -class ImportDuplicateSingletonTest(BeetsTestCase): +class ImportDuplicateSingletonTest(ImportTestCase): def setUp(self): super().setUp() @@ -1364,7 +1364,7 @@ def test_tag_log_unicode(self): self.assertIn("status caf\xe9", sio.getvalue()) -class ResumeImportTest(BeetsTestCase): +class ResumeImportTest(ImportTestCase): @patch("beets.plugins.send") def test_resume_album(self, plugins_send): self.importer = self.create_importer(album_count=2) @@ -1409,7 +1409,7 @@ def raise_exception(event, **kwargs): self.assertIsNotNone(self.lib.items("title:track 1").get()) -class IncrementalImportTest(BeetsTestCase): +class IncrementalImportTest(ImportTestCase): def setUp(self): super().setUp() self.config["import"]["incremental"] = True diff --git a/test/test_logging.py b/test/test_logging.py index fbc6a5f336..2919e60307 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -9,7 +9,7 @@ import beetsplug from beets import plugins, ui from beets.test import _common, helper -from beets.test.helper import BeetsTestCase, PluginTestCase +from beets.test.helper import BeetsTestCase, ImportTestCase, PluginMixin class LoggingTest(BeetsTestCase): @@ -46,7 +46,7 @@ def test_str_format_logging(self): self.assertTrue(stream.getvalue(), "foo oof baz") -class LoggingLevelTest(PluginTestCase): +class LoggingLevelTest(PluginMixin, ImportTestCase): plugin = "dummy" class DummyModule: @@ -161,7 +161,7 @@ def test_import_stage_level2(self): @_common.slow_test() -class ConcurrentEventsTest(BeetsTestCase): +class ConcurrentEventsTest(ImportTestCase): """Similar to LoggingLevelTest but lower-level and focused on multiple events interaction. Since this is a bit heavy we don't do it in LoggingLevelTest. From 41bbb77a0befde24f2de708d1796f204423cc248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Mon, 8 Jul 2024 21:52:40 +0100 Subject: [PATCH 16/29] Centralise 'import_dir' creation --- beets/test/helper.py | 19 +++++++++---------- test/plugins/test_filefilter.py | 4 ---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 5409b34258..4fecf796d7 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -39,6 +39,7 @@ import unittest from contextlib import contextmanager from enum import Enum +from functools import cached_property from io import StringIO from tempfile import mkdtemp, mkstemp from typing import ClassVar @@ -504,6 +505,12 @@ class ImportHelper: importer: importer.ImportSession + @cached_property + def import_dir(self): + import_dir = os.path.join(self.temp_dir, b"import") + os.makedirs(syspath(import_dir), exist_ok=True) + return import_dir + def setup_beets(self): super().setup_beets() self.lib.path_formats = [ @@ -526,10 +533,6 @@ def _create_import_dir(self, count=3): :param count: Number of files to create """ - self.import_dir = os.path.join(self.temp_dir, b"testsrcdir") - if os.path.isdir(syspath(self.import_dir)): - shutil.rmtree(syspath(self.import_dir)) - album_path = os.path.join(self.import_dir, b"the_album") os.makedirs(syspath(album_path)) @@ -595,14 +598,10 @@ def create_importer(self, item_count=1, album_count=1): Copies the specified number of files to a subdirectory of `self.temp_dir` and creates a `ImportSessionFixture` for this path. """ - import_dir = os.path.join(self.temp_dir, b"import") - if not os.path.isdir(syspath(import_dir)): - os.mkdir(syspath(import_dir)) - album_no = 0 while album_count: album = util.bytestring_path(f"album {album_no}") - album_dir = os.path.join(import_dir, album) + album_dir = os.path.join(self.import_dir, album) if os.path.exists(syspath(album_dir)): album_no += 1 continue @@ -639,7 +638,7 @@ def create_importer(self, item_count=1, album_count=1): config["import"]["resume"] = False return ImportSessionFixture( - self.lib, loghandler=None, query=None, paths=[import_dir] + self.lib, loghandler=None, query=None, paths=[self.import_dir] ) def assert_file_in_lib(self, *segments): diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index 4af0a4be72..81cd6b43b0 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -46,10 +46,6 @@ def __copy_file(self, dest_path, metadata): medium.save() def __create_import_dir(self, count): - self.import_dir = os.path.join(self.temp_dir, b"testsrcdir") - if os.path.isdir(syspath(self.import_dir)): - shutil.rmtree(syspath(self.import_dir)) - self.artist_path = os.path.join(self.import_dir, b"artist") self.album_path = os.path.join(self.artist_path, b"album") self.misc_path = os.path.join(self.import_dir, b"misc") From c2fdf9873d35127d79cfe10949805e8052d1ffb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Mon, 8 Jul 2024 22:22:00 +0100 Subject: [PATCH 17/29] Synchronise ImportHelper._create_import_dir and TestHelper.create_importer implementations --- beets/test/helper.py | 98 +++++++++++++++----------------- test/plugins/test_edit.py | 30 +++++----- test/plugins/test_filefilter.py | 6 +- test/plugins/test_importadded.py | 6 +- test/plugins/test_mbsubmit.py | 6 +- test/plugins/test_permissions.py | 2 +- test/test_importer.py | 70 +++++++++++------------ test/test_plugins.py | 12 ++-- 8 files changed, 110 insertions(+), 120 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 4fecf796d7..38064fc86e 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -41,6 +41,7 @@ from enum import Enum from functools import cached_property from io import StringIO +from pathlib import Path from tempfile import mkdtemp, mkstemp from typing import ClassVar from unittest.mock import patch @@ -534,35 +535,35 @@ def _create_import_dir(self, count=3): :param count: Number of files to create """ album_path = os.path.join(self.import_dir, b"the_album") - os.makedirs(syspath(album_path)) + os.makedirs(syspath(album_path), exist_ok=True) resource_path = os.path.join(_common.RSRC, b"full.mp3") - metadata = { - "artist": "Tag Artist", - "album": "Tag Album", - "albumartist": None, - "mb_trackid": None, - "mb_albumid": None, - "comp": None, - } - self.media_files = [] - for i in range(count): - # Copy files + album = bytestring_path("album") + album_path = os.path.join(self.import_dir, album) + os.makedirs(syspath(album_path), exist_ok=True) + + self.import_media = [] + for track_id in range(1, count + 1): medium_path = os.path.join( - album_path, bytestring_path("track_%d.mp3" % (i + 1)) + album_path, bytestring_path(f"track_{track_id}.mp3") ) shutil.copy(syspath(resource_path), syspath(medium_path)) medium = MediaFile(medium_path) - - # Set metadata - metadata["track"] = i + 1 - metadata["title"] = "Tag Title %d" % (i + 1) - for attr in metadata: - setattr(medium, attr, metadata[attr]) + medium.update( + { + "album": "Tag Album", + "albumartist": None, + "mb_albumid": None, + "comp": None, + "artist": "Tag Artist", + "title": f"Tag Track {track_id}", + "track": track_id, + "mb_trackid": None, + } + ) medium.save() - self.media_files.append(medium) - self.import_media = self.media_files + self.import_media.append(medium) def _get_import_session(self, import_dir: str) -> None: self.importer = ImportSessionFixture( @@ -598,40 +599,35 @@ def create_importer(self, item_count=1, album_count=1): Copies the specified number of files to a subdirectory of `self.temp_dir` and creates a `ImportSessionFixture` for this path. """ - album_no = 0 - while album_count: - album = util.bytestring_path(f"album {album_no}") - album_dir = os.path.join(self.import_dir, album) - if os.path.exists(syspath(album_dir)): - album_no += 1 - continue - os.mkdir(syspath(album_dir)) - album_count -= 1 - - track_no = 0 - album_item_count = item_count - while album_item_count: - title = f"track {track_no}" - src = os.path.join(_common.RSRC, b"full.mp3") - title_file = util.bytestring_path(f"{title}.mp3") - dest = os.path.join(album_dir, title_file) - if os.path.exists(syspath(dest)): - track_no += 1 - continue - album_item_count -= 1 - shutil.copy(syspath(src), syspath(dest)) - mediafile = MediaFile(dest) - mediafile.update( + resource_path = os.path.join(_common.RSRC, b"full.mp3") + + album_dirs = Path(os.fsdecode(self.import_dir)).glob("album_*") + base_idx = int(str(max(album_dirs, default="0")).split("_")[-1]) + 1 + + for album_id in range(base_idx, album_count + base_idx): + album = bytestring_path(f"album_{album_id}") + album_path = os.path.join(self.import_dir, album) + os.makedirs(syspath(album_path), exist_ok=True) + + for track_id in range(1, item_count + 1): + medium_path = os.path.join( + album_path, bytestring_path(f"track_{track_id}.mp3") + ) + shutil.copy(syspath(resource_path), syspath(medium_path)) + medium = MediaFile(medium_path) + medium.update( { - "artist": "artist", - "albumartist": "album artist", - "title": title, - "album": album, + "album": f"Tag Album {album_id}", + "albumartist": None, "mb_albumid": None, + "comp": None, + "artist": "Tag Artist", + "title": f"Tag Track {track_id}", + "track": track_id, "mb_trackid": None, } ) - mediafile.save() + medium.save() config["import"]["quiet"] = True config["import"]["autotag"] = False @@ -930,7 +926,7 @@ def track_for_id(self, mbid): def _make_track_match(self, artist, album, number): return TrackInfo( - title="Applied Title %d" % number, + title="Applied Track %d" % number, track_id="match %d" % number, artist=artist, length=1, diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 927376a721..047e2c0214 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -332,7 +332,7 @@ def setUp(self): super().setUp() # Create some mediafiles, and store them for comparison. self._create_import_dir(3) - self.items_orig = [Item.from_path(f.path) for f in self.media_files] + self.items_orig = [Item.from_path(f.path) for f in self.import_media] self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.GOOD self.config["import"]["timid"] = True @@ -349,7 +349,7 @@ def test_edit_apply_asis(self): self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( - {"replacements": {"Tag Title": "Edited Title"}}, + {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Apply changes. ["d", "a"], ) @@ -367,7 +367,7 @@ def test_edit_apply_asis(self): ], ) self.assertTrue( - all("Edited Title" in i.title for i in self.lib.items()) + all("Edited Track" in i.title for i in self.lib.items()) ) # Ensure album is *not* fetched from a candidate. @@ -380,7 +380,7 @@ def test_edit_discard_asis(self): self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( - {"replacements": {"Tag Title": "Edited Title"}}, + {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Cancel, Use as-is. ["d", "c", "u"], ) @@ -392,7 +392,7 @@ def test_edit_discard_asis(self): [], self.IGNORED + ["albumartist", "mb_albumartistid"], ) - self.assertTrue(all("Tag Title" in i.title for i in self.lib.items())) + self.assertTrue(all("Tag Track" in i.title for i in self.lib.items())) # Ensure album is *not* fetched from a candidate. self.assertEqual(self.lib.albums()[0].mb_albumid, "") @@ -404,7 +404,7 @@ def test_edit_apply_candidate(self): self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( - {"replacements": {"Applied Title": "Edited Title"}}, + {"replacements": {"Applied Track": "Edited Track"}}, # edit Candidates, 1, Apply changes. ["c", "1", "a"], ) @@ -412,7 +412,7 @@ def test_edit_apply_candidate(self): # Check that 'title' field is modified, and other fields come from # the candidate. self.assertTrue( - all("Edited Title " in i.title for i in self.lib.items()) + 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())) @@ -435,7 +435,7 @@ def test_edit_retag_apply(self): self.importer.paths = [] self.importer.query = TrueQuery() self.run_mocked_interpreter( - {"replacements": {"Applied Title": "Edited Title"}}, + {"replacements": {"Applied Track": "Edited Track"}}, # eDit, Apply changes. ["d", "a"], ) @@ -443,7 +443,7 @@ def test_edit_retag_apply(self): # Check that 'title' field is modified, and other fields come from # the candidate. self.assertTrue( - all("Edited Title " in i.title for i in self.lib.items()) + 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())) @@ -457,7 +457,7 @@ def test_edit_discard_candidate(self): self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( - {"replacements": {"Applied Title": "Edited Title"}}, + {"replacements": {"Applied Track": "Edited Track"}}, # edit Candidates, 1, Apply changes. ["c", "1", "a"], ) @@ -465,7 +465,7 @@ def test_edit_discard_candidate(self): # Check that 'title' field is modified, and other fields come from # the candidate. self.assertTrue( - all("Edited Title " in i.title for i in self.lib.items()) + 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())) @@ -479,7 +479,7 @@ def test_edit_apply_asis_singleton(self): self._setup_import_session(singletons=True) # Edit track titles. self.run_mocked_interpreter( - {"replacements": {"Tag Title": "Edited Title"}}, + {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Apply changes, aBort. ["d", "a", "b"], ) @@ -492,7 +492,7 @@ def test_edit_apply_asis_singleton(self): self.IGNORED + ["albumartist", "mb_albumartistid"], ) self.assertTrue( - all("Edited Title" in i.title for i in self.lib.items()) + all("Edited Track" in i.title for i in self.lib.items()) ) def test_edit_apply_candidate_singleton(self): @@ -502,7 +502,7 @@ def test_edit_apply_candidate_singleton(self): self._setup_import_session() # Edit track titles. self.run_mocked_interpreter( - {"replacements": {"Applied Title": "Edited Title"}}, + {"replacements": {"Applied Track": "Edited Track"}}, # edit Candidates, 1, Apply changes, aBort. ["c", "1", "a", "b"], ) @@ -510,6 +510,6 @@ def test_edit_apply_candidate_singleton(self): # Check that 'title' field is modified, and other fields come from # the candidate. self.assertTrue( - all("Edited Title " in i.title for i in self.lib.items()) + 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 81cd6b43b0..f8ee3191b0 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -63,7 +63,7 @@ def __create_import_dir(self, count): self.album_paths = [] for i in range(count): metadata["track"] = i + 1 - metadata["title"] = "Tag Title Album %d" % (i + 1) + metadata["title"] = "Tag Track Album %d" % (i + 1) track_file = bytestring_path("%02d - track.mp3" % (i + 1)) dest_path = os.path.join(self.album_path, track_file) self.__copy_file(dest_path, metadata) @@ -73,7 +73,7 @@ def __create_import_dir(self, count): metadata["album"] = None for i in range(count): metadata["track"] = i + 10 - metadata["title"] = "Tag Title Artist %d" % (i + 1) + metadata["title"] = "Tag Track Artist %d" % (i + 1) track_file = bytestring_path("track_%d.mp3" % (i + 1)) dest_path = os.path.join(self.artist_path, track_file) self.__copy_file(dest_path, metadata) @@ -83,7 +83,7 @@ def __create_import_dir(self, count): for i in range(count): metadata["artist"] = "Artist %d" % (i + 42) metadata["track"] = i + 5 - metadata["title"] = "Tag Title Misc %d" % (i + 1) + metadata["title"] = "Tag Track Misc %d" % (i + 1) track_file = bytestring_path("track_%d.mp3" % (i + 1)) dest_path = os.path.join(self.misc_path, track_file) self.__copy_file(dest_path, metadata) diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index f1a7746b16..a2ffd4d193 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -50,9 +50,9 @@ def setUp(self): self._create_import_dir(2) # Different mtimes on the files to be imported in order to test the # plugin - modify_mtimes(mfile.path for mfile in self.media_files) + modify_mtimes(mfile.path for mfile in self.import_media) self.min_mtime = min( - os.path.getmtime(mfile.path) for mfile in self.media_files + os.path.getmtime(mfile.path) for mfile in self.import_media ) self.matcher = AutotagStub().install() self.matcher.macthin = AutotagStub.GOOD @@ -65,7 +65,7 @@ def tearDown(self): def find_media_file(self, item): """Find the pre-import MediaFile for an Item""" - for m in self.media_files: + for m in self.import_media: if m.title.replace("Tag", "Applied") == item.title: return m raise AssertionError( diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index 29c8a687a8..cfdb18906d 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -48,8 +48,8 @@ def test_print_tracks_output(self): # Manually build the string for comparing the output. tracklist = ( "Open files with Picard? " - "01. Tag Title 1 - Tag Artist (0:01)\n" - "02. Tag Title 2 - Tag Artist (0:01)" + "01. Tag Track 1 - Tag Artist (0:01)\n" + "02. Tag Track 2 - Tag Artist (0:01)" ) self.assertIn(tracklist, output.getvalue()) @@ -64,6 +64,6 @@ def test_print_tracks_output_as_tracks(self): # Manually build the string for comparing the output. tracklist = ( - "Open files with Picard? " "02. Tag Title 2 - Tag Artist (0:01)" + "Open files with Picard? " "02. Tag Track 2 - Tag Artist (0:01)" ) self.assertIn(tracklist, output.getvalue()) diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index a83fbfb261..c54bb9b832 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -47,7 +47,7 @@ def get_stat(v): self.importer = self.create_importer() typs = ["file", "dir"] - track_file = (b"album 0", b"track 0.mp3") + track_file = (b"album_1", b"track_1.mp3") self.exp_perms = { True: { k: convert_perm(self.config["permissions"][k].get()) diff --git a/test/test_importer.py b/test/test_importer.py index 62daa8a10d..44a4eec5cf 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -144,18 +144,18 @@ def test_import_with_move_deletes_import_files(self): def test_import_with_move_prunes_directory_empty(self): config["import"]["move"] = True - self.assertExists(os.path.join(self.import_dir, b"the_album")) + self.assertExists(os.path.join(self.import_dir, b"album")) self.importer.run() - self.assertNotExists(os.path.join(self.import_dir, b"the_album")) + self.assertNotExists(os.path.join(self.import_dir, b"album")) def test_import_with_move_prunes_with_extra_clutter(self): - self.touch(os.path.join(self.import_dir, b"the_album", b"alog.log")) + self.touch(os.path.join(self.import_dir, b"album", b"alog.log")) config["clutter"] = ["*.log"] config["import"]["move"] = True - self.assertExists(os.path.join(self.import_dir, b"the_album")) + self.assertExists(os.path.join(self.import_dir, b"album")) self.importer.run() - self.assertNotExists(os.path.join(self.import_dir, b"the_album")) + self.assertNotExists(os.path.join(self.import_dir, b"album")) def test_threaded_import_move_arrives(self): config["import"]["move"] = True @@ -192,9 +192,9 @@ def test_import_with_delete_removes_files(self): def test_import_with_delete_prunes_directory_empty(self): config["import"]["delete"] = True - self.assertExists(os.path.join(self.import_dir, b"the_album")) + self.assertExists(os.path.join(self.import_dir, b"album")) self.importer.run() - self.assertNotExists(os.path.join(self.import_dir, b"the_album")) + self.assertNotExists(os.path.join(self.import_dir, b"album")) @unittest.skipUnless(_common.HAVE_SYMLINK, "need symlinks") def test_import_link_arrives(self): @@ -354,7 +354,7 @@ def test_apply_asis_adds_track(self): self.importer.add_choice(importer.action.ASIS) self.importer.run() - self.assertEqual(self.lib.items().get().title, "Tag Title 1") + self.assertEqual(self.lib.items().get().title, "Tag Track 1") def test_apply_asis_does_not_add_album(self): self.assertIsNone(self.lib.albums().get()) @@ -368,14 +368,14 @@ def test_apply_asis_adds_singleton_path(self): self.importer.add_choice(importer.action.ASIS) self.importer.run() - self.assert_file_in_lib(b"singletons", b"Tag Title 1.mp3") + self.assert_file_in_lib(b"singletons", b"Tag Track 1.mp3") def test_apply_candidate_adds_track(self): self.assertIsNone(self.lib.items().get()) self.importer.add_choice(importer.action.APPLY) self.importer.run() - self.assertEqual(self.lib.items().get().title, "Applied Title 1") + self.assertEqual(self.lib.items().get().title, "Applied Track 1") def test_apply_candidate_does_not_add_album(self): self.importer.add_choice(importer.action.APPLY) @@ -387,7 +387,7 @@ def test_apply_candidate_adds_singleton_path(self): self.importer.add_choice(importer.action.APPLY) self.importer.run() - self.assert_file_in_lib(b"singletons", b"Applied Title 1.mp3") + self.assert_file_in_lib(b"singletons", b"Applied Track 1.mp3") def test_skip_does_not_add_first_track(self): self.importer.add_choice(importer.action.SKIP) @@ -407,7 +407,7 @@ def test_import_single_files(self): util.copy(resource_path, single_path) import_files = [ - os.path.join(self.import_dir, b"the_album"), + os.path.join(self.import_dir, b"album"), single_path, ] self._setup_import_session(singletons=False) @@ -439,7 +439,7 @@ def test_set_fields(self): item.load() # TODO: Not sure this is necessary. self.assertEqual(item.genre, genre) self.assertEqual(item.collection, collection) - self.assertEqual(item.title, "Tag Title 1 - formatted") + self.assertEqual(item.title, "Tag Track 1 - formatted") # Remove item from library to test again with APPLY choice. item.remove() @@ -453,7 +453,7 @@ def test_set_fields(self): item.load() self.assertEqual(item.genre, genre) self.assertEqual(item.collection, collection) - self.assertEqual(item.title, "Applied Title 1 - formatted") + self.assertEqual(item.title, "Applied Track 1 - formatted") class ImportTest(ImportTestCase): @@ -481,14 +481,14 @@ def test_apply_asis_adds_tracks(self): self.assertIsNone(self.lib.items().get()) self.importer.add_choice(importer.action.ASIS) self.importer.run() - self.assertEqual(self.lib.items().get().title, "Tag Title 1") + self.assertEqual(self.lib.items().get().title, "Tag Track 1") def test_apply_asis_adds_album_path(self): self.assert_lib_dir_empty() self.importer.add_choice(importer.action.ASIS) self.importer.run() - self.assert_file_in_lib(b"Tag Artist", b"Tag Album", b"Tag Title 1.mp3") + self.assert_file_in_lib(b"Tag Artist", b"Tag Album", b"Tag Track 1.mp3") def test_apply_candidate_adds_album(self): self.assertIsNone(self.lib.albums().get()) @@ -502,7 +502,7 @@ def test_apply_candidate_adds_tracks(self): self.importer.add_choice(importer.action.APPLY) self.importer.run() - self.assertEqual(self.lib.items().get().title, "Applied Title 1") + self.assertEqual(self.lib.items().get().title, "Applied Track 1") def test_apply_candidate_adds_album_path(self): self.assert_lib_dir_empty() @@ -510,7 +510,7 @@ def test_apply_candidate_adds_album_path(self): self.importer.add_choice(importer.action.APPLY) self.importer.run() self.assert_file_in_lib( - b"Applied Artist", b"Applied Album", b"Applied Title 1.mp3" + b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3" ) def test_apply_from_scratch_removes_other_metadata(self): @@ -542,9 +542,7 @@ def test_apply_from_scratch_keeps_bitrate(self): def test_apply_with_move_deletes_import(self): config["import"]["move"] = True - import_file = os.path.join( - self.import_dir, b"the_album", b"track_1.mp3" - ) + import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3") self.assertExists(import_file) self.importer.add_choice(importer.action.APPLY) @@ -554,9 +552,7 @@ def test_apply_with_move_deletes_import(self): def test_apply_with_delete_deletes_import(self): config["import"]["delete"] = True - import_file = os.path.join( - self.import_dir, b"the_album", b"track_1.mp3" - ) + import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3") self.assertExists(import_file) self.importer.add_choice(importer.action.APPLY) @@ -569,7 +565,7 @@ def test_skip_does_not_add_track(self): self.assertIsNone(self.lib.items().get()) def test_skip_non_album_dirs(self): - self.assertIsDir(os.path.join(self.import_dir, b"the_album")) + self.assertIsDir(os.path.join(self.import_dir, b"album")) self.touch(b"cruft", dir=self.import_dir) self.importer.add_choice(importer.action.APPLY) self.importer.run() @@ -691,7 +687,7 @@ def test_apply_tracks_adds_singleton_track(self): self.importer.add_choice(importer.action.APPLY) self.importer.add_choice(importer.action.APPLY) self.importer.run() - self.assertEqual(self.lib.items().get().title, "Applied Title 1") + self.assertEqual(self.lib.items().get().title, "Applied Track 1") self.assertIsNone(self.lib.albums().get()) def test_apply_tracks_adds_singleton_path(self): @@ -701,7 +697,7 @@ def test_apply_tracks_adds_singleton_path(self): self.importer.add_choice(importer.action.APPLY) self.importer.add_choice(importer.action.APPLY) self.importer.run() - self.assert_file_in_lib(b"singletons", b"Applied Title 1.mp3") + self.assert_file_in_lib(b"singletons", b"Applied Track 1.mp3") class ImportCompilationTest(ImportTestCase): @@ -885,7 +881,7 @@ def test_asis_updated_moves_file(self): medium.save() old_path = os.path.join( - b"Applied Artist", b"Applied Album", b"Applied Title 1.mp3" + b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3" ) self.assert_file_in_lib(old_path) @@ -903,7 +899,7 @@ def test_asis_updated_without_copy_does_not_move_file(self): medium.save() old_path = os.path.join( - b"Applied Artist", b"Applied Album", b"Applied Title 1.mp3" + b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3" ) self.assert_file_in_lib(old_path) @@ -927,7 +923,7 @@ def test_outside_file_is_copied(self): self.importer.add_choice(importer.action.APPLY) self.importer.run() new_path = os.path.join( - b"Applied Artist", b"Applied Album", b"Applied Title 1.mp3" + b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3" ) self.assert_file_in_lib(new_path) @@ -1194,7 +1190,7 @@ def test_no_autotag_keeps_duplicate_album(self): # Imported item has the same artist and album as the one in the # library. import_file = os.path.join( - self.importer.paths[0], b"album 0", b"track 0.mp3" + self.importer.paths[0], b"album_1", b"track_1.mp3" ) import_file = MediaFile(import_file) import_file.artist = item["artist"] @@ -1242,7 +1238,7 @@ def test_keep_when_extra_key_is_different(self): item = self.lib.items().get() import_file = MediaFile( - os.path.join(self.importer.paths[0], b"album 0", b"track 0.mp3") + os.path.join(self.importer.paths[0], b"album_1", b"track_1.mp3") ) import_file.artist = item["artist"] import_file.albumartist = item["artist"] @@ -1380,11 +1376,11 @@ def raise_exception(event, **kwargs): self.importer.run() self.assertEqual(len(self.lib.albums()), 1) - self.assertIsNotNone(self.lib.albums("album:album 0").get()) + self.assertIsNotNone(self.lib.albums("album:'Album 1'").get()) self.importer.run() self.assertEqual(len(self.lib.albums()), 2) - self.assertIsNotNone(self.lib.albums("album:album 1").get()) + self.assertIsNotNone(self.lib.albums("album:'Album 2'").get()) @patch("beets.plugins.send") def test_resume_singleton(self, plugins_send): @@ -1402,11 +1398,11 @@ def raise_exception(event, **kwargs): self.importer.run() self.assertEqual(len(self.lib.items()), 1) - self.assertIsNotNone(self.lib.items("title:track 0").get()) + self.assertIsNotNone(self.lib.items("title:'Track 1'").get()) self.importer.run() self.assertEqual(len(self.lib.items()), 2) - self.assertIsNotNone(self.lib.items("title:track 1").get()) + self.assertIsNotNone(self.lib.items("title:'Track 1'").get()) class IncrementalImportTest(ImportTestCase): @@ -1751,7 +1747,7 @@ def __create_import_dir(self): single_path = os.path.join(self.import_dir, b"track_2.mp3") shutil.copy(syspath(resource_path), syspath(single_path)) self.import_paths = [ - os.path.join(self.import_dir, b"the_album"), + os.path.join(self.import_dir, b"album"), single_path, ] self.import_files = [ diff --git a/test/test_plugins.py b/test/test_plugins.py index dd4db6aa28..2fcaf449cf 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -179,12 +179,10 @@ def test_import_task_created(self): logs, [ "Album: {}".format( - displayable_path( - os.path.join(self.import_dir, b"the_album") - ) + displayable_path(os.path.join(self.import_dir, b"album")) ), - " {}".format(displayable_path(self.media_files[0].path)), - " {}".format(displayable_path(self.media_files[1].path)), + " {}".format(displayable_path(self.import_media[0].path)), + " {}".format(displayable_path(self.import_media[1].path)), ], ) @@ -230,10 +228,10 @@ def import_task_created_event(self, session, task): logs, [ "Singleton: {}".format( - displayable_path(self.media_files[0].path) + displayable_path(self.import_media[0].path) ), "Singleton: {}".format( - displayable_path(self.media_files[1].path) + displayable_path(self.import_media[1].path) ), ], ) From 7e444db914e946a5181bce56742c2dd5641b14f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Tue, 9 Jul 2024 12:22:54 +0100 Subject: [PATCH 18/29] Rename _create_import_dir -> prepare_album_for_import --- beets/test/helper.py | 2 +- test/plugins/test_edit.py | 2 +- test/plugins/test_importadded.py | 2 +- test/plugins/test_mbsubmit.py | 2 +- test/test_importer.py | 31 ++++++++++++++++--------------- test/test_plugins.py | 2 +- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 38064fc86e..7186526864 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -520,7 +520,7 @@ def setup_beets(self): ("comp:true", os.path.join("compilations", "$album", "$title")), ] - def _create_import_dir(self, count=3): + def prepare_album_for_import(self, count=3): """Creates a directory with media files to import. Sets ``self.import_dir`` to the path of the directory. Also sets ``self.import_media`` to a list :class:`MediaFile` for all the files in diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 047e2c0214..1053602c84 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -331,7 +331,7 @@ class EditDuringImporterTestCase( def setUp(self): super().setUp() # Create some mediafiles, and store them for comparison. - self._create_import_dir(3) + self.prepare_album_for_import() self.items_orig = [Item.from_path(f.path) for f in self.import_media] self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.GOOD diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index a2ffd4d193..fe8f0466bf 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -47,7 +47,7 @@ class ImportAddedTest(PluginMixin, ImportTestCase): def setUp(self): preserve_plugin_listeners() super().setUp() - self._create_import_dir(2) + self.prepare_album_for_import(2) # Different mtimes on the files to be imported in order to test the # plugin modify_mtimes(mfile.path for mfile in self.import_media) diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index cfdb18906d..f2151736b1 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -28,7 +28,7 @@ class MBSubmitPluginTest(PluginMixin, TerminalImportMixin, ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(2) + self.prepare_album_for_import(2) self._setup_import_session() self.matcher = AutotagStub().install() diff --git a/test/test_importer.py b/test/test_importer.py index 44a4eec5cf..bf2ef2b119 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -51,7 +51,7 @@ class ScrubbedImportTest(PluginMixin, ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(2) + self.prepare_album_for_import(2) self._setup_import_session(autotag=False) def test_tags_not_scrubbed(self): @@ -103,7 +103,7 @@ class NonAutotaggedImportTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(2) + self.prepare_album_for_import(2) self._setup_import_session(autotag=False) def test_album_created_with_track_artist(self): @@ -340,7 +340,7 @@ class ImportSingletonTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(1) + self.prepare_album_for_import(1) self._setup_import_session() config["import"]["singletons"] = True self.matcher = AutotagStub().install() @@ -395,7 +395,7 @@ def test_skip_does_not_add_first_track(self): self.assertIsNone(self.lib.items().get()) def test_skip_adds_other_tracks(self): - self._create_import_dir(2) + self.prepare_album_for_import(2) self.importer.add_choice(importer.action.SKIP) self.importer.add_choice(importer.action.ASIS) self.importer.run() @@ -461,7 +461,7 @@ class ImportTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(1) + self.prepare_album_for_import(1) self._setup_import_session() self.matcher = AutotagStub().install() self.matcher.macthin = AutotagStub.GOOD @@ -572,7 +572,7 @@ def test_skip_non_album_dirs(self): self.assertEqual(len(self.lib.albums()), 1) def test_unmatched_tracks_not_added(self): - self._create_import_dir(2) + self.prepare_album_for_import(2) self.matcher.matching = self.matcher.MISSING self.importer.add_choice(importer.action.APPLY) self.importer.run() @@ -671,7 +671,7 @@ class ImportTracksTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(1) + self.prepare_album_for_import(1) self._setup_import_session() self.matcher = AutotagStub().install() @@ -705,7 +705,7 @@ class ImportCompilationTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(3) + self.prepare_album_for_import(3) self._setup_import_session() self.matcher = AutotagStub().install() @@ -824,7 +824,7 @@ class ImportExistingTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(1) + self.prepare_album_for_import(1) self.matcher = AutotagStub().install() self._setup_import_session() @@ -947,7 +947,7 @@ def test_outside_file_is_moved(self): class GroupAlbumsImportTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(3) + self.prepare_album_for_import(3) self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.NONE self._setup_import_session() @@ -1019,7 +1019,7 @@ def setUp(self): class ChooseCandidateTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(1) + self.prepare_album_for_import(1) self._setup_import_session() self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.BAD @@ -1742,7 +1742,7 @@ def tearDown(self): self.matcher.restore() def __create_import_dir(self): - self._create_import_dir(1) + self.prepare_album_for_import(1) resource_path = os.path.join(_common.RSRC, b"empty.mp3") single_path = os.path.join(self.import_dir, b"track_2.mp3") shutil.copy(syspath(resource_path), syspath(single_path)) @@ -1822,7 +1822,7 @@ def mocked_get_release_by_id( """Mimic musicbrainzngs.get_release_by_id, accepting only a restricted list of MB ids (ID_RELEASE_0, ID_RELEASE_1). The returned dict differs only in the release title and artist name, so that ID_RELEASE_0 is a closer match - to the items created by ImportHelper._create_import_dir().""" + to the items created by ImportHelper.prepare_album_for_import().""" # Map IDs to (release title, artist), so the distances are different. releases = { ImportMusicBrainzIdTest.ID_RELEASE_0: ("VALID_RELEASE_0", "TAG ARTIST"), @@ -1875,7 +1875,8 @@ def mocked_get_recording_by_id( """Mimic musicbrainzngs.get_recording_by_id, accepting only a restricted list of MB ids (ID_RECORDING_0, ID_RECORDING_1). The returned dict differs only in the recording title and artist name, so that ID_RECORDING_0 is a - closer match to the items created by ImportHelper._create_import_dir().""" + closer match to the items created by ImportHelper.prepare_album_for_import(). + """ # Map IDs to (recording title, artist), so the distances are different. releases = { ImportMusicBrainzIdTest.ID_RECORDING_0: ( @@ -1925,7 +1926,7 @@ class ImportMusicBrainzIdTest(ImportTestCase): def setUp(self): super().setUp() - self._create_import_dir(1) + self.prepare_album_for_import(1) def test_one_mbid_one_album(self): self.config["import"]["search_ids"] = [ diff --git a/test/test_plugins.py b/test/test_plugins.py index 2fcaf449cf..4415bebbcc 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -73,7 +73,7 @@ def tearDown(self): class PluginImportTestCase(ImportHelper, PluginLoaderTestCase): def setUp(self): super().setUp() - self._create_import_dir(2) + self.prepare_album_for_import(2) class ItemTypesTest(PluginLoaderTestCase): From 8065ff0461d0dc8fe2796195479609517e145772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sun, 14 Jul 2024 11:24:23 +0100 Subject: [PATCH 19/29] Split album and singleton tests in edit and filefilter --- test/plugins/test_edit.py | 63 ++++++++++-------- test/plugins/test_filefilter.py | 113 +++++++++++++++++++------------- 2 files changed, 102 insertions(+), 74 deletions(-) diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index 1053602c84..fc17984453 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.test import _common from beets.test.helper import ( AutotagStub, + BeetsTestCase, ImportTestCase, - PluginTestCase, + PluginMixin, TerminalImportMixin, control_stdin, ) @@ -72,7 +74,7 @@ def replace_contents(self, filename, log): 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 @@ def run_mocked_command(self, modify_file_args={}, stdin=[], args=[]): @_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 @@ def tearDown(self): 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 @@ def test_edit_discard_asis(self): """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 @@ def test_edit_apply_candidate(self): """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 @@ def test_edit_retag_apply(self): """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 @@ def test_edit_discard_candidate(self): """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 @@ def test_edit_discard_candidate(self): # 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 @@ def test_edit_apply_asis_singleton(self): 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 f8ee3191b0..79aedb53e1 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 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 @@ def __create_import_dir(self, count): 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 @@ def test_import_default(self): 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 @@ def test_import_global(self): " %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 @@ def test_import_album(self): " %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 @@ def test_import_singleton(self): # 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 @@ def test_import_both(self): " %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]), - ], - 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]), + ] + ) + + # 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]), + ] ) From f042f5ad32faba12d4a3d9cd2a301ea4a2c3cbf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Fri, 12 Jul 2024 22:11:48 +0100 Subject: [PATCH 20/29] Leave a single source of truth for importer setup --- beets/test/helper.py | 183 +++++++++++++------------------ beets/util/__init__.py | 2 +- test/plugins/test_convert.py | 3 +- test/plugins/test_edit.py | 14 +-- test/plugins/test_filefilter.py | 17 +-- test/plugins/test_importadded.py | 7 +- test/plugins/test_keyfinder.py | 4 +- test/plugins/test_mbsubmit.py | 2 +- test/plugins/test_permissions.py | 8 +- test/plugins/test_replaygain.py | 3 +- test/test_importer.py | 183 +++++++++++++++---------------- test/test_logging.py | 24 ++-- test/test_plugins.py | 11 +- 13 files changed, 211 insertions(+), 250 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 7186526864..3132026c6e 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -53,6 +53,7 @@ import beets.plugins from beets import autotag, config, importer, logging, util from beets.autotag.hooks import AlbumInfo, TrackInfo +from beets.importer import ImportSession from beets.library import Album, Item, Library from beets.test import _common from beets.ui.commands import TerminalImportSession @@ -498,13 +499,26 @@ class PluginTestCase(PluginMixin, BeetsTestCase): pass -class ImportHelper: +class ImportHelper(TestHelper): """Provides tools to setup a library, a directory containing files that are to be imported and an import session. The class also provides stubs for the autotagging library and several assertions for the library. """ - importer: importer.ImportSession + resource_path = syspath(os.path.join(_common.RSRC, b"full.mp3")) + default_import_config = { + "autotag": True, + "copy": True, + "hardlink": False, + "link": False, + "move": False, + "resume": False, + "singletons": False, + "timid": True, + } + + lib: Library + importer: ImportSession @cached_property def import_dir(self): @@ -512,130 +526,87 @@ def import_dir(self): os.makedirs(syspath(import_dir), exist_ok=True) return import_dir - def setup_beets(self): - super().setup_beets() + def setUp(self): + super().setUp() + self.import_media = [] self.lib.path_formats = [ ("default", os.path.join("$artist", "$album", "$title")), ("singleton:true", os.path.join("singletons", "$title")), ("comp:true", os.path.join("compilations", "$album", "$title")), ] - def prepare_album_for_import(self, count=3): - """Creates a directory with media files to import. - Sets ``self.import_dir`` to the path of the directory. Also sets - ``self.import_media`` to a list :class:`MediaFile` for all the files in - the directory. + def prepare_track_for_import( + self, + track_id: int, + album_path: bytes, + album_id: int | None = None, + ) -> MediaFile: + filename = bytestring_path(f"track_{track_id}.mp3") + medium_path = os.path.join(album_path, filename) + shutil.copy(self.resource_path, syspath(medium_path)) + medium = MediaFile(medium_path) + medium.update( + { + "album": "Tag Album" + (f" {album_id}" if album_id else ""), + "albumartist": None, + "mb_albumid": None, + "comp": None, + "artist": "Tag Artist", + "title": f"Tag Track {track_id}", + "track": track_id, + "mb_trackid": None, + } + ) + medium.save() + return medium + + def prepare_album_for_import( + self, item_count: int, album_id: int | None = None + ) -> None: + """Create an album directory with media files to import. The directory has following layout - the_album/ + album/ track_1.mp3 track_2.mp3 track_3.mp3 - - :param count: Number of files to create """ - album_path = os.path.join(self.import_dir, b"the_album") + album_path = os.path.join( + self.import_dir, + bytestring_path(f"album_{album_id}" if album_id else "album"), + ) os.makedirs(syspath(album_path), exist_ok=True) - resource_path = os.path.join(_common.RSRC, b"full.mp3") + mediums = [ + self.prepare_track_for_import(tid, album_path, album_id=album_id) + for tid in range(1, item_count + 1) + ] + self.import_media.extend(mediums) - album = bytestring_path("album") - album_path = os.path.join(self.import_dir, album) - os.makedirs(syspath(album_path), exist_ok=True) + def prepare_albums_for_import(self, count: int = 1) -> None: + album_dirs = Path(os.fsdecode(self.import_dir)).glob("album_*") + base_idx = int(str(max(album_dirs, default="0")).split("_")[-1]) + 1 - self.import_media = [] - for track_id in range(1, count + 1): - medium_path = os.path.join( - album_path, bytestring_path(f"track_{track_id}.mp3") - ) - shutil.copy(syspath(resource_path), syspath(medium_path)) - medium = MediaFile(medium_path) - medium.update( - { - "album": "Tag Album", - "albumartist": None, - "mb_albumid": None, - "comp": None, - "artist": "Tag Artist", - "title": f"Tag Track {track_id}", - "track": track_id, - "mb_trackid": None, - } - ) - medium.save() - self.import_media.append(medium) + for album_id in range(base_idx, count + base_idx): + self.prepare_album_for_import(1, album_id=album_id) - def _get_import_session(self, import_dir: str) -> None: - self.importer = ImportSessionFixture( + def _get_import_session(self, import_dir: str) -> ImportSession: + return ImportSessionFixture( self.lib, loghandler=None, query=None, paths=[import_dir], ) - def _setup_import_session( - self, - import_dir=None, - singletons=False, - move=False, - autotag=True, - ): - config["import"]["copy"] = True - config["import"]["delete"] = False - config["import"]["timid"] = True - config["threaded"] = False - config["import"]["singletons"] = singletons - config["import"]["move"] = move - config["import"]["autotag"] = autotag - config["import"]["resume"] = False - config["import"]["link"] = False - config["import"]["hardlink"] = False - - self._get_import_session(import_dir or self.import_dir) - - def create_importer(self, item_count=1, album_count=1): - """Create files to import and return corresponding session. - - Copies the specified number of files to a subdirectory of - `self.temp_dir` and creates a `ImportSessionFixture` for this path. - """ - resource_path = os.path.join(_common.RSRC, b"full.mp3") + def setup_importer( + self, import_dir: str | None = None, **kwargs + ) -> ImportSession: + config["import"].set_args({**self.default_import_config, **kwargs}) + self.importer = self._get_import_session(import_dir or self.import_dir) + return self.importer - album_dirs = Path(os.fsdecode(self.import_dir)).glob("album_*") - base_idx = int(str(max(album_dirs, default="0")).split("_")[-1]) + 1 - - for album_id in range(base_idx, album_count + base_idx): - album = bytestring_path(f"album_{album_id}") - album_path = os.path.join(self.import_dir, album) - os.makedirs(syspath(album_path), exist_ok=True) - - for track_id in range(1, item_count + 1): - medium_path = os.path.join( - album_path, bytestring_path(f"track_{track_id}.mp3") - ) - shutil.copy(syspath(resource_path), syspath(medium_path)) - medium = MediaFile(medium_path) - medium.update( - { - "album": f"Tag Album {album_id}", - "albumartist": None, - "mb_albumid": None, - "comp": None, - "artist": "Tag Artist", - "title": f"Tag Track {track_id}", - "track": track_id, - "mb_trackid": None, - } - ) - medium.save() - - config["import"]["quiet"] = True - config["import"]["autotag"] = False - config["import"]["resume"] = False - - return ImportSessionFixture( - self.lib, loghandler=None, query=None, paths=[self.import_dir] - ) + def setup_singleton_importer(self, **kwargs) -> ImportSession: + return self.setup_importer(singletons=True, **kwargs) def assert_file_in_lib(self, *segments): """Join the ``segments`` and assert that this path exists in the @@ -657,7 +628,7 @@ class ImportTestCase(ImportHelper, BeetsTestCase): pass -class ImportSessionFixture(importer.ImportSession): +class ImportSessionFixture(ImportSession): """ImportSession that can be controlled programaticaly. >>> lib = Library(':memory:') @@ -771,9 +742,11 @@ def _add_choice_input(self): class TerminalImportMixin(ImportHelper): """Provides_a terminal importer for the import session.""" - def _get_import_session(self, import_dir: str) -> None: + io: _common.DummyIO + + def _get_import_session(self, import_dir: str) -> importer.ImportSession: self.io.install() - self.importer = TerminalImportSessionFixture( + return TerminalImportSessionFixture( self.lib, loghandler=None, query=None, diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 9076bea30b..64a20722d4 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -434,7 +434,7 @@ def displayable_path( return path.decode("utf-8", "ignore") -def syspath(path: Bytes_or_String, prefix: bool = True) -> Bytes_or_String: +def syspath(path: Bytes_or_String, prefix: bool = True) -> str: """Convert a path for use by the operating system. In particular, paths on Windows must receive a magic prefix and must be converted to Unicode before they are sent to the OS. To disable the magic diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index 67b513bb9c..eca953c436 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -98,7 +98,8 @@ class ConvertTestCase(ConvertMixin, PluginTestCase): class ImportConvertTest(ImportHelper, ConvertTestCase): def setUp(self): super().setUp() - self.importer = self.create_importer() + self.prepare_album_for_import(1) + self.importer = self.setup_importer(autotag=False) self.config["convert"] = { "dest": os.path.join(self.temp_dir, b"convert"), diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index fc17984453..ba068e90dd 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -13,7 +13,6 @@ # 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 @@ -329,17 +328,14 @@ 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.prepare_album_for_import(1) self.items_orig = [Item.from_path(f.path) for f in self.import_media] self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.GOOD - self.config["import"]["timid"] = True def tearDown(self): EditPlugin.listeners = None @@ -349,7 +345,9 @@ def tearDown(self): @_common.slow_test() class EditDuringImporterNonSingletonTest(EditDuringImporterTestCase): - singletons = False + def setUp(self): + super().setUp() + self.importer = self.setup_importer() def test_edit_apply_asis(self): """Edit the album field for all items in the library, apply changes, @@ -497,7 +495,9 @@ def test_edit_apply_candidate_singleton(self): @_common.slow_test() class EditDuringImporterSingletonTest(EditDuringImporterTestCase): - singletons = True + def setUp(self): + super().setUp() + self.importer = self.setup_singleton_importer() def test_edit_apply_asis_singleton(self): """Edit the album field for all items in the library, apply changes, diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index 79aedb53e1..abf2b4c622 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -18,7 +18,6 @@ import os import shutil -from typing import ClassVar from mediafile import MediaFile @@ -30,17 +29,9 @@ 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() @@ -112,7 +103,9 @@ def _run(self, expected_lines): class FileFilterPluginNonSingletonTest(FileFilterPluginMixin): - singletons = False + def setUp(self): + super().setUp() + self.importer = self.setup_importer(pretend=True) def test_import_default(self): """The default configuration should import everything.""" @@ -189,7 +182,9 @@ def test_import_both(self): class FileFilterPluginSingletonTest(FileFilterPluginMixin): - singletons = True + def setUp(self): + super().setUp() + self.importer = self.setup_singleton_importer(pretend=True) def test_import_global(self): config["filefilter"]["path"] = ".*track_1.*\\.mp3" diff --git a/test/plugins/test_importadded.py b/test/plugins/test_importadded.py index fe8f0466bf..b055e16cc0 100644 --- a/test/plugins/test_importadded.py +++ b/test/plugins/test_importadded.py @@ -56,7 +56,7 @@ def setUp(self): ) self.matcher = AutotagStub().install() self.matcher.macthin = AutotagStub.GOOD - self._setup_import_session() + self.importer = self.setup_importer() self.importer.add_choice(importer.action.APPLY) def tearDown(self): @@ -113,7 +113,7 @@ def test_reimported_album_skipped(self): # Newer Item path mtimes as if Beets had modified them modify_mtimes(items_added_before.keys(), offset=10000) # Reimport - self._setup_import_session(import_dir=album.path) + self.setup_importer(import_dir=self.libdir) self.importer.run() # Verify the reimported items album = self.lib.albums().get() @@ -154,8 +154,7 @@ def test_reimported_singletons_skipped(self): # Newer Item path mtimes as if Beets had modified them modify_mtimes(items_added_before.keys(), offset=10000) # Reimport - import_dir = os.path.dirname(list(items_added_before.keys())[0]) - self._setup_import_session(import_dir=import_dir, singletons=True) + self.setup_importer(import_dir=self.libdir, singletons=True) self.importer.run() # Verify the reimported items items_added_after = {item.path: item.added for item in self.lib.items()} diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index d941df3cae..0517c70110 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -39,8 +39,8 @@ def test_add_key(self, command_output): def test_add_key_on_import(self, command_output): command_output.return_value = util.CommandOutput(b"dbm", b"") - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() item = self.lib.items().get() self.assertEqual(item["initial_key"], "C#m") diff --git a/test/plugins/test_mbsubmit.py b/test/plugins/test_mbsubmit.py index f2151736b1..01ef522c63 100644 --- a/test/plugins/test_mbsubmit.py +++ b/test/plugins/test_mbsubmit.py @@ -29,7 +29,7 @@ class MBSubmitPluginTest(PluginMixin, TerminalImportMixin, ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(2) - self._setup_import_session() + self.setup_importer() self.matcher = AutotagStub().install() def tearDown(self): diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index c54bb9b832..b28ee46d5e 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -22,6 +22,7 @@ def setUp(self): super().setUp() self.config["permissions"] = {"file": "777", "dir": "777"} + self.prepare_album_for_import(1) def test_permissions_on_album_imported(self): self.do_thing(True) @@ -44,10 +45,10 @@ def get_stat(v): & 0o777 ) - self.importer = self.create_importer() + self.importer = self.setup_importer(autotag=False) typs = ["file", "dir"] - track_file = (b"album_1", b"track_1.mp3") + track_file = (b"album", b"track_1.mp3") self.exp_perms = { True: { k: convert_perm(self.config["permissions"][k].get()) @@ -93,8 +94,7 @@ def test_failing_permissions_on_set_art(self): def do_set_art(self, expect_success): if platform.system() == "Windows": self.skipTest("permissions not available on Windows") - self.importer = self.create_importer() - self.importer.run() + self.setup_importer(autotag=False).run() album = self.lib.albums().get() artpath = os.path.join(self.temp_dir, b"cover.jpg") touch(artpath) diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index 342902a631..d0532caeda 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -68,7 +68,8 @@ def setUp(self): except Exception: self.tearDown() - self.importer = self.create_importer() + self.prepare_album_for_import(1) + self.importer = self.setup_importer(autotag=False) def tearDown(self): self.unload_plugins() diff --git a/test/test_importer.py b/test/test_importer.py index bf2ef2b119..d0100688bd 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -51,8 +51,8 @@ class ScrubbedImportTest(PluginMixin, ImportTestCase): def setUp(self): super().setUp() - self.prepare_album_for_import(2) - self._setup_import_session(autotag=False) + self.prepare_album_for_import(1) + self.setup_importer(autotag=False) def test_tags_not_scrubbed(self): config["plugins"] = ["scrub"] @@ -103,8 +103,8 @@ class NonAutotaggedImportTest(ImportTestCase): def setUp(self): super().setUp() - self.prepare_album_for_import(2) - self._setup_import_session(autotag=False) + self.prepare_album_for_import(1) + self.setup_importer(autotag=False) def test_album_created_with_track_artist(self): self.importer.run() @@ -285,7 +285,7 @@ def test_rm(self): archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() tmp_path = archive_task.toppath - self._setup_import_session(autotag=False, import_dir=tmp_path) + self.setup_importer(autotag=False, import_dir=tmp_path) self.assertExists(tmp_path) archive_task.finalize(self) self.assertNotExists(tmp_path) @@ -297,7 +297,7 @@ def test_import_zip(self): self.assertEqual(len(self.lib.items()), 0) self.assertEqual(len(self.lib.albums()), 0) - self._setup_import_session(autotag=False, import_dir=zip_path) + self.setup_importer(autotag=False, import_dir=zip_path) self.importer.run() self.assertEqual(len(self.lib.items()), 1) self.assertEqual(len(self.lib.albums()), 1) @@ -341,8 +341,7 @@ class ImportSingletonTest(ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(1) - self._setup_import_session() - config["import"]["singletons"] = True + self.setup_importer(singletons=True) self.matcher = AutotagStub().install() def tearDown(self): @@ -410,7 +409,7 @@ def test_import_single_files(self): os.path.join(self.import_dir, b"album"), single_path, ] - self._setup_import_session(singletons=False) + self.setup_importer() self.importer.paths = import_files self.importer.add_choice(importer.action.ASIS) @@ -462,7 +461,7 @@ class ImportTest(ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(1) - self._setup_import_session() + self.setup_importer() self.matcher = AutotagStub().install() self.matcher.macthin = AutotagStub.GOOD @@ -581,7 +580,7 @@ def test_unmatched_tracks_not_added(self): def test_empty_directory_warning(self): import_dir = os.path.join(self.temp_dir, b"empty") self.touch(b"non-audio", dir=import_dir) - self._setup_import_session(import_dir=import_dir) + self.setup_importer(import_dir=import_dir) with capture_log() as logs: self.importer.run() @@ -591,7 +590,7 @@ def test_empty_directory_warning(self): def test_empty_directory_singleton_warning(self): import_dir = os.path.join(self.temp_dir, b"empty") self.touch(b"non-audio", dir=import_dir) - self._setup_import_session(import_dir=import_dir, singletons=True) + self.setup_importer(import_dir=import_dir, singletons=True) with capture_log() as logs: self.importer.run() @@ -672,7 +671,7 @@ class ImportTracksTest(ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(1) - self._setup_import_session() + self.setup_importer() self.matcher = AutotagStub().install() def tearDown(self): @@ -706,7 +705,7 @@ class ImportCompilationTest(ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(3) - self._setup_import_session() + self.setup_importer() self.matcher = AutotagStub().install() def tearDown(self): @@ -827,55 +826,52 @@ def setUp(self): self.prepare_album_for_import(1) self.matcher = AutotagStub().install() - self._setup_import_session() - self.setup_importer = self.importer - self.setup_importer.default_choice = importer.action.APPLY - - self._setup_import_session(import_dir=self.libdir) + self.reimporter = self.setup_importer(import_dir=self.libdir) + self.importer = self.setup_importer() def tearDown(self): super().tearDown() self.matcher.restore() def test_does_not_duplicate_item(self): - self.setup_importer.run() + self.importer.run() self.assertEqual(len(self.lib.items()), 1) - self.importer.add_choice(importer.action.APPLY) - self.importer.run() + self.reimporter.add_choice(importer.action.APPLY) + self.reimporter.run() self.assertEqual(len(self.lib.items()), 1) def test_does_not_duplicate_album(self): - self.setup_importer.run() + self.importer.run() self.assertEqual(len(self.lib.albums()), 1) - self.importer.add_choice(importer.action.APPLY) - self.importer.run() + self.reimporter.add_choice(importer.action.APPLY) + self.reimporter.run() self.assertEqual(len(self.lib.albums()), 1) def test_does_not_duplicate_singleton_track(self): - self.setup_importer.add_choice(importer.action.TRACKS) - self.setup_importer.add_choice(importer.action.APPLY) - self.setup_importer.run() - self.assertEqual(len(self.lib.items()), 1) - self.importer.add_choice(importer.action.TRACKS) self.importer.add_choice(importer.action.APPLY) self.importer.run() self.assertEqual(len(self.lib.items()), 1) + self.reimporter.add_choice(importer.action.TRACKS) + self.reimporter.add_choice(importer.action.APPLY) + self.reimporter.run() + self.assertEqual(len(self.lib.items()), 1) + def test_asis_updates_metadata(self): - self.setup_importer.run() + self.importer.run() medium = MediaFile(self.lib.items().get().path) medium.title = "New Title" medium.save() - self.importer.add_choice(importer.action.ASIS) - self.importer.run() + self.reimporter.add_choice(importer.action.ASIS) + self.reimporter.run() self.assertEqual(self.lib.items().get().title, "New Title") def test_asis_updated_moves_file(self): - self.setup_importer.run() + self.importer.run() medium = MediaFile(self.lib.items().get().path) medium.title = "New Title" medium.save() @@ -885,15 +881,15 @@ def test_asis_updated_moves_file(self): ) self.assert_file_in_lib(old_path) - self.importer.add_choice(importer.action.ASIS) - self.importer.run() + self.reimporter.add_choice(importer.action.ASIS) + self.reimporter.run() self.assert_file_in_lib( b"Applied Artist", b"Applied Album", b"New Title.mp3" ) self.assert_file_not_in_lib(old_path) def test_asis_updated_without_copy_does_not_move_file(self): - self.setup_importer.run() + self.importer.run() medium = MediaFile(self.lib.items().get().path) medium.title = "New Title" medium.save() @@ -904,8 +900,8 @@ def test_asis_updated_without_copy_does_not_move_file(self): self.assert_file_in_lib(old_path) config["import"]["copy"] = False - self.importer.add_choice(importer.action.ASIS) - self.importer.run() + self.reimporter.add_choice(importer.action.ASIS) + self.reimporter.run() self.assert_file_not_in_lib( b"Applied Artist", b"Applied Album", b"New Title.mp3" ) @@ -913,15 +909,14 @@ def test_asis_updated_without_copy_does_not_move_file(self): def test_outside_file_is_copied(self): config["import"]["copy"] = False - self.setup_importer.run() + self.importer.run() self.assert_equal_path( self.lib.items().get().path, self.import_media[0].path ) - config["import"]["copy"] = True - self._setup_import_session() - self.importer.add_choice(importer.action.APPLY) - self.importer.run() + self.reimporter = self.setup_importer() + self.reimporter.add_choice(importer.action.APPLY) + self.reimporter.run() new_path = os.path.join( b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3" ) @@ -933,14 +928,14 @@ def test_outside_file_is_copied(self): def test_outside_file_is_moved(self): config["import"]["copy"] = False - self.setup_importer.run() + self.importer.run() self.assert_equal_path( self.lib.items().get().path, self.import_media[0].path ) - self._setup_import_session(move=True) - self.importer.add_choice(importer.action.APPLY) - self.importer.run() + self.reimporter = self.setup_importer(move=True) + self.reimporter.add_choice(importer.action.APPLY) + self.reimporter.run() self.assertNotExists(self.import_media[0].path) @@ -950,7 +945,7 @@ def setUp(self): self.prepare_album_for_import(3) self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.NONE - self._setup_import_session() + self.setup_importer() # Split tracks into two albums and use both as-is self.importer.add_choice(importer.action.ALBUMS) @@ -1020,7 +1015,7 @@ class ChooseCandidateTest(ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(1) - self._setup_import_session() + self.setup_importer() self.matcher = AutotagStub().install() self.matcher.matching = AutotagStub.BAD @@ -1163,9 +1158,10 @@ def setUp(self): self.add_album_fixture(albumartist="artist", album="album") # Create import session - self.importer = self.create_importer() - config["import"]["autotag"] = True - config["import"]["duplicate_keys"]["album"] = "albumartist album" + self.prepare_album_for_import(1) + self.importer = self.setup_importer( + duplicate_keys={"album": "albumartist album"} + ) def test_remove_duplicate_album(self): item = self.lib.items().get() @@ -1190,7 +1186,7 @@ def test_no_autotag_keeps_duplicate_album(self): # Imported item has the same artist and album as the one in the # library. import_file = os.path.join( - self.importer.paths[0], b"album_1", b"track_1.mp3" + self.importer.paths[0], b"album", b"track_1.mp3" ) import_file = MediaFile(import_file) import_file.artist = item["artist"] @@ -1238,7 +1234,7 @@ def test_keep_when_extra_key_is_different(self): item = self.lib.items().get() import_file = MediaFile( - os.path.join(self.importer.paths[0], b"album_1", b"track_1.mp3") + os.path.join(self.importer.paths[0], b"album", b"track_1.mp3") ) import_file.artist = item["artist"] import_file.albumartist = item["artist"] @@ -1284,10 +1280,10 @@ def setUp(self): ) # Import session - self.importer = self.create_importer() - config["import"]["autotag"] = True - config["import"]["singletons"] = True - config["import"]["duplicate_keys"]["item"] = "artist title" + self.prepare_album_for_import(1) + self.importer = self.setup_importer( + duplicate_keys={"album": "artist title"}, singletons=True + ) def test_remove_duplicate(self): item = self.lib.items().get() @@ -1363,8 +1359,8 @@ def test_tag_log_unicode(self): class ResumeImportTest(ImportTestCase): @patch("beets.plugins.send") def test_resume_album(self, plugins_send): - self.importer = self.create_importer(album_count=2) - self.config["import"]["resume"] = True + self.prepare_albums_for_import(2) + self.importer = self.setup_importer(autotag=False, resume=True) # Aborts import after one album. This also ensures that we skip # the first album in the second try. @@ -1384,9 +1380,10 @@ def raise_exception(event, **kwargs): @patch("beets.plugins.send") def test_resume_singleton(self, plugins_send): - self.importer = self.create_importer(item_count=2) - self.config["import"]["resume"] = True - self.config["import"]["singletons"] = True + self.prepare_album_for_import(2) + self.importer = self.setup_importer( + autotag=False, resume=True, singletons=True + ) # Aborts import after one track. This also ensures that we skip # the first album in the second try. @@ -1408,10 +1405,10 @@ def raise_exception(event, **kwargs): class IncrementalImportTest(ImportTestCase): def setUp(self): super().setUp() - self.config["import"]["incremental"] = True + self.prepare_album_for_import(1) def test_incremental_album(self): - importer = self.create_importer(album_count=1) + importer = self.setup_importer(autotag=False, incremental=True) importer.run() # Change album name so the original file would be imported again @@ -1420,13 +1417,13 @@ def test_incremental_album(self): album["album"] = "edited album" album.store() - importer = self.create_importer(album_count=1) importer.run() self.assertEqual(len(self.lib.albums()), 2) def test_incremental_item(self): - self.config["import"]["singletons"] = True - importer = self.create_importer(item_count=1) + importer = self.setup_importer( + autotag=False, incremental=True, singletons=True + ) importer.run() # Change track name so the original file would be imported again @@ -1435,12 +1432,11 @@ def test_incremental_item(self): item["artist"] = "edited artist" item.store() - importer = self.create_importer(item_count=1) importer.run() self.assertEqual(len(self.lib.items()), 2) def test_invalid_state_file(self): - importer = self.create_importer() + importer = self.setup_importer(autotag=False, incremental=True) with open(self.config["statefile"].as_filename(), "wb") as f: f.write(b"000") importer.run() @@ -1648,7 +1644,7 @@ def tearDown(self): self.matcher.restore() def _setup_session(self, singletons=False): - self._setup_import_session(self._album().path, singletons=singletons) + self.setup_importer(import_dir=self.libdir, singletons=singletons) self.importer.add_choice(importer.action.APPLY) def _album(self): @@ -1732,8 +1728,7 @@ def setUp(self): super().setUp() self.__create_import_dir() self.__create_empty_import_dir() - self._setup_import_session() - config["import"]["pretend"] = True + self.setup_importer(pretend=True) self.matcher = AutotagStub().install() self.io.install() @@ -1763,7 +1758,7 @@ def __create_empty_import_dir(self): self.empty_path = path def __run(self, import_paths, singletons=True): - self._setup_import_session(singletons=singletons) + self.setup_importer(singletons=singletons) self.importer.paths = import_paths with capture_log() as logs: @@ -1929,21 +1924,21 @@ def setUp(self): self.prepare_album_for_import(1) def test_one_mbid_one_album(self): - self.config["import"]["search_ids"] = [ - self.MB_RELEASE_PREFIX + self.ID_RELEASE_0 - ] - self._setup_import_session() + self.setup_importer( + search_ids=[self.MB_RELEASE_PREFIX + self.ID_RELEASE_0] + ) self.importer.add_choice(importer.action.APPLY) self.importer.run() self.assertEqual(self.lib.albums().get().album, "VALID_RELEASE_0") def test_several_mbid_one_album(self): - self.config["import"]["search_ids"] = [ - self.MB_RELEASE_PREFIX + self.ID_RELEASE_0, - self.MB_RELEASE_PREFIX + self.ID_RELEASE_1, - ] - self._setup_import_session() + self.setup_importer( + search_ids=[ + self.MB_RELEASE_PREFIX + self.ID_RELEASE_0, + self.MB_RELEASE_PREFIX + self.ID_RELEASE_1, + ] + ) self.importer.add_choice(2) # Pick the 2nd best match (release 1). self.importer.add_choice(importer.action.APPLY) @@ -1951,21 +1946,23 @@ def test_several_mbid_one_album(self): self.assertEqual(self.lib.albums().get().album, "VALID_RELEASE_1") def test_one_mbid_one_singleton(self): - self.config["import"]["search_ids"] = [ - self.MB_RECORDING_PREFIX + self.ID_RECORDING_0 - ] - self._setup_import_session(singletons=True) + self.setup_importer( + search_ids=[self.MB_RECORDING_PREFIX + self.ID_RECORDING_0], + singletons=True, + ) self.importer.add_choice(importer.action.APPLY) self.importer.run() self.assertEqual(self.lib.items().get().title, "VALID_RECORDING_0") def test_several_mbid_one_singleton(self): - self.config["import"]["search_ids"] = [ - self.MB_RECORDING_PREFIX + self.ID_RECORDING_0, - self.MB_RECORDING_PREFIX + self.ID_RECORDING_1, - ] - self._setup_import_session(singletons=True) + self.setup_importer( + search_ids=[ + self.MB_RECORDING_PREFIX + self.ID_RECORDING_0, + self.MB_RECORDING_PREFIX + self.ID_RECORDING_1, + ], + singletons=True, + ) self.importer.add_choice(2) # Pick the 2nd best match (recording 1). self.importer.add_choice(importer.action.APPLY) diff --git a/test/test_logging.py b/test/test_logging.py index 2919e60307..29579fdb2d 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -135,8 +135,8 @@ def test_listener_level2(self): def test_import_stage_level0(self): self.config["verbose"] = 0 with helper.capture_log() as logs: - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() self.assertIn("dummy: warning import_stage", logs) self.assertNotIn("dummy: info import_stage", logs) self.assertNotIn("dummy: debug import_stage", logs) @@ -144,8 +144,8 @@ def test_import_stage_level0(self): def test_import_stage_level1(self): self.config["verbose"] = 1 with helper.capture_log() as logs: - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() self.assertIn("dummy: warning import_stage", logs) self.assertIn("dummy: info import_stage", logs) self.assertNotIn("dummy: debug import_stage", logs) @@ -153,8 +153,8 @@ def test_import_stage_level1(self): def test_import_stage_level2(self): self.config["verbose"] = 2 with helper.capture_log() as logs: - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() self.assertIn("dummy: warning import_stage", logs) self.assertIn("dummy: info import_stage", logs) self.assertIn("dummy: debug import_stage", logs) @@ -264,20 +264,20 @@ def test_root_logger_levels(self): blog.getLogger("beets").set_global_level(blog.WARNING) with helper.capture_log() as logs: - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() self.assertEqual(logs, []) blog.getLogger("beets").set_global_level(blog.INFO) with helper.capture_log() as logs: - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() for l in logs: self.assertIn("import", l) self.assertIn("album", l) blog.getLogger("beets").set_global_level(blog.DEBUG) with helper.capture_log() as logs: - importer = self.create_importer() - importer.run() + self.prepare_album_for_import(1) + self.setup_importer(autotag=False).run() self.assertIn("Sending event: database_change", logs) diff --git a/test/test_plugins.py b/test/test_plugins.py index 4415bebbcc..709727d0a3 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -160,12 +160,9 @@ class AdventListenerPlugin(plugins.BeetsPlugin): class EventsTest(PluginImportTestCase): def setUp(self): super().setUp() - config["import"]["pretend"] = True def test_import_task_created(self): - import_files = [self.import_dir] - self._setup_import_session(singletons=False) - self.importer.paths = import_files + self.importer = self.setup_importer(pretend=True) with helper.capture_log() as logs: self.importer.run() @@ -212,9 +209,7 @@ def import_task_created_event(self, session, task): to_singleton_plugin = ToSingletonPlugin self.register_plugin(to_singleton_plugin) - import_files = [self.import_dir] - self._setup_import_session(singletons=False) - self.importer.paths = import_files + self.importer = self.setup_importer(pretend=True) with helper.capture_log() as logs: self.importer.run() @@ -371,7 +366,7 @@ def dummy9(self, **kwargs): class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase): def setUp(self): super().setUp() - self._setup_import_session() + self.setup_importer() self.matcher = AutotagStub().install() # keep track of ui.input_option() calls self.input_options_patcher = patch( From 8d85cfd72ad91413a252ad4bf29e6d46f0e31c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Fri, 12 Jul 2024 22:35:07 +0100 Subject: [PATCH 21/29] Define AsIsImporterMixin to run autotag=False importer --- beets/test/helper.py | 11 ++++ test/plugins/test_convert.py | 12 ++-- test/plugins/test_keyfinder.py | 7 +-- test/plugins/test_permissions.py | 10 ++-- test/plugins/test_replaygain.py | 9 +-- test/test_importer.py | 95 ++++++++++---------------------- test/test_logging.py | 29 +++++----- 7 files changed, 68 insertions(+), 105 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 3132026c6e..6f8607516a 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -624,6 +624,17 @@ def assert_lib_dir_empty(self): self.assertEqual(len(os.listdir(syspath(self.libdir))), 0) +class AsIsImporterMixin: + def setUp(self): + super().setUp() + self.prepare_album_for_import(1) + + def run_asis_importer(self, **kwargs): + importer = self.setup_importer(autotag=False, **kwargs) + importer.run() + return importer + + class ImportTestCase(ImportHelper, BeetsTestCase): pass diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index eca953c436..a60cb531a9 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -24,6 +24,7 @@ from beets import util from beets.test import _common from beets.test.helper import ( + AsIsImporterMixin, ImportHelper, PluginTestCase, capture_log, @@ -95,12 +96,9 @@ class ConvertTestCase(ConvertMixin, PluginTestCase): @_common.slow_test() -class ImportConvertTest(ImportHelper, ConvertTestCase): +class ImportConvertTest(AsIsImporterMixin, ImportHelper, ConvertTestCase): def setUp(self): super().setUp() - self.prepare_album_for_import(1) - self.importer = self.setup_importer(autotag=False) - self.config["convert"] = { "dest": os.path.join(self.temp_dir, b"convert"), "command": self.tagged_copy_cmd("convert"), @@ -111,7 +109,7 @@ def setUp(self): } def test_import_converted(self): - self.importer.run() + self.run_asis_importer() item = self.lib.items().get() self.assertFileTag(item.path, "convert") @@ -120,7 +118,7 @@ def test_import_converted(self): def test_import_original_on_convert_error(self): # `false` exits with non-zero code self.config["convert"]["command"] = "false" - self.importer.run() + self.run_asis_importer() item = self.lib.items().get() self.assertIsNotNone(item) @@ -128,7 +126,7 @@ def test_import_original_on_convert_error(self): def test_delete_originals(self): self.config["convert"]["delete_originals"] = True - self.importer.run() + self.run_asis_importer() for path in self.importer.paths: for root, dirnames, filenames in os.walk(path): self.assertEqual( diff --git a/test/plugins/test_keyfinder.py b/test/plugins/test_keyfinder.py index 0517c70110..ae82438457 100644 --- a/test/plugins/test_keyfinder.py +++ b/test/plugins/test_keyfinder.py @@ -17,11 +17,11 @@ from beets import util from beets.library import Item -from beets.test.helper import ImportTestCase, PluginMixin +from beets.test.helper import AsIsImporterMixin, ImportTestCase, PluginMixin @patch("beets.util.command_output") -class KeyFinderTest(PluginMixin, ImportTestCase): +class KeyFinderTest(AsIsImporterMixin, PluginMixin, ImportTestCase): plugin = "keyfinder" def test_add_key(self, command_output): @@ -39,8 +39,7 @@ def test_add_key(self, command_output): def test_add_key_on_import(self, command_output): command_output.return_value = util.CommandOutput(b"dbm", b"") - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() item = self.lib.items().get() self.assertEqual(item["initial_key"], "C#m") diff --git a/test/plugins/test_permissions.py b/test/plugins/test_permissions.py index b28ee46d5e..928dad5689 100644 --- a/test/plugins/test_permissions.py +++ b/test/plugins/test_permissions.py @@ -6,7 +6,7 @@ from unittest.mock import Mock, patch from beets.test._common import touch -from beets.test.helper import ImportTestCase, PluginMixin +from beets.test.helper import AsIsImporterMixin, ImportTestCase, PluginMixin from beets.util import displayable_path from beetsplug.permissions import ( check_permissions, @@ -15,14 +15,13 @@ ) -class PermissionsPluginTest(PluginMixin, ImportTestCase): +class PermissionsPluginTest(AsIsImporterMixin, PluginMixin, ImportTestCase): plugin = "permissions" def setUp(self): super().setUp() self.config["permissions"] = {"file": "777", "dir": "777"} - self.prepare_album_for_import(1) def test_permissions_on_album_imported(self): self.do_thing(True) @@ -45,7 +44,6 @@ def get_stat(v): & 0o777 ) - self.importer = self.setup_importer(autotag=False) typs = ["file", "dir"] track_file = (b"album", b"track_1.mp3") @@ -57,7 +55,7 @@ def get_stat(v): False: {k: get_stat(v) for (k, v) in zip(typs, (track_file, ()))}, } - self.importer.run() + self.run_asis_importer() item = self.lib.items().get() self.assertPerms(item.path, "file", expect_success) @@ -94,7 +92,7 @@ def test_failing_permissions_on_set_art(self): def do_set_art(self, expect_success): if platform.system() == "Windows": self.skipTest("permissions not available on Windows") - self.setup_importer(autotag=False).run() + self.run_asis_importer() album = self.lib.albums().get() artpath = os.path.join(self.temp_dir, b"cover.jpg") touch(artpath) diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index d0532caeda..0e7b663f5b 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -19,7 +19,7 @@ from mediafile import MediaFile from beets import config -from beets.test.helper import ImportTestCase, has_program +from beets.test.helper import AsIsImporterMixin, ImportTestCase, has_program from beetsplug.replaygain import ( FatalGstreamerPluginReplayGainError, GStreamerBackend, @@ -68,9 +68,6 @@ def setUp(self): except Exception: self.tearDown() - self.prepare_album_for_import(1) - self.importer = self.setup_importer(autotag=False) - def tearDown(self): self.unload_plugins() super().tearDown() @@ -360,9 +357,9 @@ class ReplayGainFfmpegNoiseCliTest( FNAME = "whitenoise" -class ImportTest: +class ImportTest(AsIsImporterMixin): def test_import_converted(self): - self.importer.run() + self.run_asis_importer() for item in self.lib.items(): # FIXME: Add fixtures with known track/album gain (within a # suitable tolerance) so that we can actually check correct diff --git a/test/test_importer.py b/test/test_importer.py index d0100688bd..ab5eb64751 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -35,6 +35,7 @@ from beets.importer import albums_in_dir from beets.test import _common from beets.test.helper import ( + AsIsImporterMixin, AutotagStub, BeetsTestCase, ImportTestCase, @@ -45,15 +46,10 @@ from beets.util import bytestring_path, displayable_path, syspath -class ScrubbedImportTest(PluginMixin, ImportTestCase): +class ScrubbedImportTest(AsIsImporterMixin, PluginMixin, ImportTestCase): db_on_disk = True plugin = "scrub" - def setUp(self): - super().setUp() - self.prepare_album_for_import(1) - self.setup_importer(autotag=False) - def test_tags_not_scrubbed(self): config["plugins"] = ["scrub"] config["scrub"]["auto"] = False @@ -61,7 +57,7 @@ def test_tags_not_scrubbed(self): for mediafile in self.import_media: self.assertEqual(mediafile.artist, "Tag Artist") self.assertEqual(mediafile.album, "Tag Album") - self.importer.run() + self.run_asis_importer() for item in self.lib.items(): imported_file = os.path.join(item.path) imported_file = MediaFile(imported_file) @@ -75,7 +71,7 @@ def test_tags_restored(self): for mediafile in self.import_media: self.assertEqual(mediafile.artist, "Tag Artist") self.assertEqual(mediafile.album, "Tag Album") - self.importer.run() + self.run_asis_importer() for item in self.lib.items(): imported_file = os.path.join(item.path) imported_file = MediaFile(imported_file) @@ -89,7 +85,7 @@ def test_tags_not_restored(self): for mediafile in self.import_media: self.assertEqual(mediafile.artist, "Tag Artist") self.assertEqual(mediafile.album, "Tag Album") - self.importer.run() + self.run_asis_importer() for item in self.lib.items(): imported_file = os.path.join(item.path) imported_file = MediaFile(imported_file) @@ -98,22 +94,17 @@ def test_tags_not_restored(self): @_common.slow_test() -class NonAutotaggedImportTest(ImportTestCase): +class NonAutotaggedImportTest(AsIsImporterMixin, ImportTestCase): db_on_disk = True - def setUp(self): - super().setUp() - self.prepare_album_for_import(1) - self.setup_importer(autotag=False) - def test_album_created_with_track_artist(self): - self.importer.run() + self.run_asis_importer() albums = self.lib.albums() self.assertEqual(len(albums), 1) self.assertEqual(albums[0].albumartist, "Tag Artist") def test_import_copy_arrives(self): - self.importer.run() + self.run_asis_importer() for mediafile in self.import_media: self.assert_file_in_lib( b"Tag Artist", @@ -124,7 +115,7 @@ def test_import_copy_arrives(self): def test_threaded_import_copy_arrives(self): config["threaded"] = True - self.importer.run() + self.run_asis_importer() for mediafile in self.import_media: self.assert_file_in_lib( b"Tag Artist", @@ -133,35 +124,27 @@ def test_threaded_import_copy_arrives(self): ) def test_import_with_move_deletes_import_files(self): - config["import"]["move"] = True - for mediafile in self.import_media: self.assertExists(mediafile.path) - self.importer.run() + self.run_asis_importer(move=True) for mediafile in self.import_media: self.assertNotExists(mediafile.path) def test_import_with_move_prunes_directory_empty(self): - config["import"]["move"] = True - self.assertExists(os.path.join(self.import_dir, b"album")) - self.importer.run() + self.run_asis_importer(move=True) self.assertNotExists(os.path.join(self.import_dir, b"album")) def test_import_with_move_prunes_with_extra_clutter(self): self.touch(os.path.join(self.import_dir, b"album", b"alog.log")) config["clutter"] = ["*.log"] - config["import"]["move"] = True self.assertExists(os.path.join(self.import_dir, b"album")) - self.importer.run() + self.run_asis_importer(move=True) self.assertNotExists(os.path.join(self.import_dir, b"album")) def test_threaded_import_move_arrives(self): - config["import"]["move"] = True - config["import"]["threaded"] = True - - self.importer.run() + self.run_asis_importer(move=True, threaded=True) for mediafile in self.import_media: self.assert_file_in_lib( b"Tag Artist", @@ -170,36 +153,28 @@ def test_threaded_import_move_arrives(self): ) def test_threaded_import_move_deletes_import(self): - config["import"]["move"] = True - config["threaded"] = True - - self.importer.run() + self.run_asis_importer(move=True, threaded=True) for mediafile in self.import_media: self.assertNotExists(mediafile.path) def test_import_without_delete_retains_files(self): - config["import"]["delete"] = False - self.importer.run() + self.run_asis_importer(delete=False) for mediafile in self.import_media: self.assertExists(mediafile.path) def test_import_with_delete_removes_files(self): - config["import"]["delete"] = True - - self.importer.run() + self.run_asis_importer(delete=True) for mediafile in self.import_media: self.assertNotExists(mediafile.path) def test_import_with_delete_prunes_directory_empty(self): - config["import"]["delete"] = True self.assertExists(os.path.join(self.import_dir, b"album")) - self.importer.run() + self.run_asis_importer(delete=True) self.assertNotExists(os.path.join(self.import_dir, b"album")) @unittest.skipUnless(_common.HAVE_SYMLINK, "need symlinks") def test_import_link_arrives(self): - config["import"]["link"] = True - self.importer.run() + self.run_asis_importer(link=True) for mediafile in self.import_media: filename = os.path.join( self.libdir, @@ -216,8 +191,7 @@ def test_import_link_arrives(self): @unittest.skipUnless(_common.HAVE_HARDLINK, "need hardlinks") def test_import_hardlink_arrives(self): - config["import"]["hardlink"] = True - self.importer.run() + self.run_asis_importer(hardlink=True) for mediafile in self.import_media: filename = os.path.join( self.libdir, @@ -237,8 +211,7 @@ def test_import_hardlink_arrives(self): def test_import_reflink_arrives(self): # Detecting reflinks is currently tricky due to various fs # implementations, we'll just check the file exists. - config["import"]["reflink"] = True - self.importer.run() + self.run_asis_importer(reflink=True) for mediafile in self.import_media: self.assert_file_in_lib( b"Tag Artist", @@ -248,8 +221,7 @@ def test_import_reflink_arrives(self): def test_import_reflink_auto_arrives(self): # Should pass regardless of reflink support due to fallback. - config["import"]["reflink"] = "auto" - self.importer.run() + self.run_asis_importer(reflink="auto") for mediafile in self.import_media: self.assert_file_in_lib( b"Tag Artist", @@ -269,7 +241,7 @@ def create_archive(session): return path -class RmTempTest(ImportTestCase): +class RmTempTest(BeetsTestCase): """Tests that temporarily extracted archives are properly removed after usage. """ @@ -285,20 +257,18 @@ def test_rm(self): archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() tmp_path = archive_task.toppath - self.setup_importer(autotag=False, import_dir=tmp_path) self.assertExists(tmp_path) archive_task.finalize(self) self.assertNotExists(tmp_path) -class ImportZipTest(ImportTestCase): +class ImportZipTest(AsIsImporterMixin, ImportTestCase): def test_import_zip(self): zip_path = create_archive(self) self.assertEqual(len(self.lib.items()), 0) self.assertEqual(len(self.lib.albums()), 0) - self.setup_importer(autotag=False, import_dir=zip_path) - self.importer.run() + self.run_asis_importer(import_dir=zip_path) self.assertEqual(len(self.lib.items()), 1) self.assertEqual(len(self.lib.albums()), 1) @@ -1402,14 +1372,9 @@ def raise_exception(event, **kwargs): self.assertIsNotNone(self.lib.items("title:'Track 1'").get()) -class IncrementalImportTest(ImportTestCase): - def setUp(self): - super().setUp() - self.prepare_album_for_import(1) - +class IncrementalImportTest(AsIsImporterMixin, ImportTestCase): def test_incremental_album(self): - importer = self.setup_importer(autotag=False, incremental=True) - importer.run() + importer = self.run_asis_importer(incremental=True) # Change album name so the original file would be imported again # if incremental was off. @@ -1421,10 +1386,7 @@ def test_incremental_album(self): self.assertEqual(len(self.lib.albums()), 2) def test_incremental_item(self): - importer = self.setup_importer( - autotag=False, incremental=True, singletons=True - ) - importer.run() + importer = self.run_asis_importer(incremental=True, singletons=True) # Change track name so the original file would be imported again # if incremental was off. @@ -1436,10 +1398,9 @@ def test_incremental_item(self): self.assertEqual(len(self.lib.items()), 2) def test_invalid_state_file(self): - importer = self.setup_importer(autotag=False, incremental=True) with open(self.config["statefile"].as_filename(), "wb") as f: f.write(b"000") - importer.run() + self.run_asis_importer(incremental=True) self.assertEqual(len(self.lib.albums()), 1) diff --git a/test/test_logging.py b/test/test_logging.py index 29579fdb2d..0cd5b68180 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -9,7 +9,12 @@ import beetsplug from beets import plugins, ui from beets.test import _common, helper -from beets.test.helper import BeetsTestCase, ImportTestCase, PluginMixin +from beets.test.helper import ( + AsIsImporterMixin, + BeetsTestCase, + ImportTestCase, + PluginMixin, +) class LoggingTest(BeetsTestCase): @@ -46,7 +51,7 @@ def test_str_format_logging(self): self.assertTrue(stream.getvalue(), "foo oof baz") -class LoggingLevelTest(PluginMixin, ImportTestCase): +class LoggingLevelTest(AsIsImporterMixin, PluginMixin, ImportTestCase): plugin = "dummy" class DummyModule: @@ -135,8 +140,7 @@ def test_listener_level2(self): def test_import_stage_level0(self): self.config["verbose"] = 0 with helper.capture_log() as logs: - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() self.assertIn("dummy: warning import_stage", logs) self.assertNotIn("dummy: info import_stage", logs) self.assertNotIn("dummy: debug import_stage", logs) @@ -144,8 +148,7 @@ def test_import_stage_level0(self): def test_import_stage_level1(self): self.config["verbose"] = 1 with helper.capture_log() as logs: - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() self.assertIn("dummy: warning import_stage", logs) self.assertIn("dummy: info import_stage", logs) self.assertNotIn("dummy: debug import_stage", logs) @@ -153,15 +156,14 @@ def test_import_stage_level1(self): def test_import_stage_level2(self): self.config["verbose"] = 2 with helper.capture_log() as logs: - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() self.assertIn("dummy: warning import_stage", logs) self.assertIn("dummy: info import_stage", logs) self.assertIn("dummy: debug import_stage", logs) @_common.slow_test() -class ConcurrentEventsTest(ImportTestCase): +class ConcurrentEventsTest(AsIsImporterMixin, ImportTestCase): """Similar to LoggingLevelTest but lower-level and focused on multiple events interaction. Since this is a bit heavy we don't do it in LoggingLevelTest. @@ -264,20 +266,17 @@ def test_root_logger_levels(self): blog.getLogger("beets").set_global_level(blog.WARNING) with helper.capture_log() as logs: - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() self.assertEqual(logs, []) blog.getLogger("beets").set_global_level(blog.INFO) with helper.capture_log() as logs: - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() for l in logs: self.assertIn("import", l) self.assertIn("album", l) blog.getLogger("beets").set_global_level(blog.DEBUG) with helper.capture_log() as logs: - self.prepare_album_for_import(1) - self.setup_importer(autotag=False).run() + self.run_asis_importer() self.assertIn("Sending event: database_change", logs) From 92f79dbfb9b6efe15a654da1ed95f2a3c22171c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 13 Jul 2024 19:18:27 +0100 Subject: [PATCH 22/29] Fix ConfigTest failures locally A couple of `ConfigTest` would previously fail locally since they somehow depended on the local environment to work fine. This commmit decouples them from any environment by setting up patching of the environment variables properly. --- test/test_ui.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/test/test_ui.py b/test/test_ui.py index 70266b920f..6d5c294a1f 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -831,12 +831,9 @@ def setUp(self): # Don't use the BEETSDIR from `helper`. Instead, we point the home # directory there. Some tests will set `BEETSDIR` themselves. del os.environ["BEETSDIR"] - self._old_home = os.environ.get("HOME") - os.environ["HOME"] = os.fsdecode(self.temp_dir) # Also set APPDATA, the Windows equivalent of setting $HOME. - self._old_appdata = os.environ.get("APPDATA") - os.environ["APPDATA"] = os.fsdecode( + appdata_dir = os.fsdecode( os.path.join(self.temp_dir, b"AppData", b"Roaming") ) @@ -846,8 +843,8 @@ def setUp(self): # Default user configuration if platform.system() == "Windows": - self.user_config_dir = os.path.join( - self.temp_dir, b"AppData", b"Roaming", b"beets" + self.user_config_dir = os.fsencode( + os.path.join(appdata_dir, "beets") ) else: self.user_config_dir = os.path.join( @@ -861,19 +858,19 @@ def setUp(self): # Custom BEETSDIR self.beetsdir = os.path.join(self.temp_dir, b"beetsdir") os.makedirs(syspath(self.beetsdir)) + self.env_patcher = patch( + "os.environ", + {"HOME": os.fsdecode(self.temp_dir), "APPDATA": appdata_dir}, + ) + self.env_patcher.start() self._reset_config() self.load_plugins() def tearDown(self): + self.env_patcher.stop() commands.default_commands.pop() os.chdir(syspath(self._orig_cwd)) - if self._old_home is not None: - os.environ["HOME"] = self._old_home - if self._old_appdata is None: - del os.environ["APPDATA"] - else: - os.environ["APPDATA"] = self._old_appdata self.unload_plugins() super().tearDown() From 139b54ebd19a9acc86d4a02f965dc279f094fe55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sun, 14 Jul 2024 12:39:40 +0100 Subject: [PATCH 23/29] Add setup_singleton_importer for singleton importer --- test/test_importer.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/test/test_importer.py b/test/test_importer.py index ab5eb64751..80378626e1 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -311,7 +311,7 @@ class ImportSingletonTest(ImportTestCase): def setUp(self): super().setUp() self.prepare_album_for_import(1) - self.setup_importer(singletons=True) + self.importer = self.setup_singleton_importer() self.matcher = AutotagStub().install() def tearDown(self): @@ -560,7 +560,7 @@ def test_empty_directory_warning(self): def test_empty_directory_singleton_warning(self): import_dir = os.path.join(self.temp_dir, b"empty") self.touch(b"non-audio", dir=import_dir) - self.setup_importer(import_dir=import_dir, singletons=True) + self.setup_singleton_importer(import_dir=import_dir) with capture_log() as logs: self.importer.run() @@ -1251,8 +1251,8 @@ def setUp(self): # Import session self.prepare_album_for_import(1) - self.importer = self.setup_importer( - duplicate_keys={"album": "artist title"}, singletons=True + self.importer = self.setup_singleton_importer( + duplicate_keys={"album": "artist title"} ) def test_remove_duplicate(self): @@ -1351,8 +1351,8 @@ def raise_exception(event, **kwargs): @patch("beets.plugins.send") def test_resume_singleton(self, plugins_send): self.prepare_album_for_import(2) - self.importer = self.setup_importer( - autotag=False, resume=True, singletons=True + self.importer = self.setup_singleton_importer( + autotag=False, resume=True ) # Aborts import after one track. This also ensures that we skip @@ -1718,10 +1718,8 @@ def __create_empty_import_dir(self): os.makedirs(syspath(path)) self.empty_path = path - def __run(self, import_paths, singletons=True): - self.setup_importer(singletons=singletons) + def __run(self, import_paths): self.importer.paths = import_paths - with capture_log() as logs: self.importer.run() @@ -1733,6 +1731,7 @@ def __run(self, import_paths, singletons=True): return logs def test_import_singletons_pretend(self): + self.importer = self.setup_singleton_importer() logs = self.__run(self.import_paths) self.assertEqual( @@ -1744,7 +1743,8 @@ def test_import_singletons_pretend(self): ) def test_import_album_pretend(self): - logs = self.__run(self.import_paths, singletons=False) + self.importer = self.setup_importer() + logs = self.__run(self.import_paths) self.assertEqual( logs, @@ -1757,6 +1757,7 @@ def test_import_album_pretend(self): ) def test_import_pretend_empty(self): + self.importer = self.setup_importer() logs = self.__run([self.empty_path]) self.assertEqual( @@ -1907,9 +1908,8 @@ def test_several_mbid_one_album(self): self.assertEqual(self.lib.albums().get().album, "VALID_RELEASE_1") def test_one_mbid_one_singleton(self): - self.setup_importer( - search_ids=[self.MB_RECORDING_PREFIX + self.ID_RECORDING_0], - singletons=True, + self.setup_singleton_importer( + search_ids=[self.MB_RECORDING_PREFIX + self.ID_RECORDING_0] ) self.importer.add_choice(importer.action.APPLY) @@ -1917,12 +1917,11 @@ def test_one_mbid_one_singleton(self): self.assertEqual(self.lib.items().get().title, "VALID_RECORDING_0") def test_several_mbid_one_singleton(self): - self.setup_importer( + self.setup_singleton_importer( search_ids=[ self.MB_RECORDING_PREFIX + self.ID_RECORDING_0, self.MB_RECORDING_PREFIX + self.ID_RECORDING_1, - ], - singletons=True, + ] ) self.importer.add_choice(2) # Pick the 2nd best match (recording 1). From 01c24bb3a72760cd82c3f3417b56c5796ac55077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sun, 14 Jul 2024 16:40:30 +0100 Subject: [PATCH 24/29] Return paths from import files prep This aids with the removal of custom import files prep implementations. --- beets/test/helper.py | 45 +++++++++++++++++++++--------------------- beets/util/__init__.py | 42 ++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 6f8607516a..965d418f88 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -521,10 +521,14 @@ class ImportHelper(TestHelper): importer: ImportSession @cached_property - def import_dir(self): - import_dir = os.path.join(self.temp_dir, b"import") - os.makedirs(syspath(import_dir), exist_ok=True) - return import_dir + def import_path(self) -> Path: + import_path = Path(os.fsdecode(self.temp_dir)) / "import" + import_path.mkdir(exist_ok=True) + return import_path + + @cached_property + def import_dir(self) -> bytes: + return bytestring_path(self.import_path) def setUp(self): super().setUp() @@ -538,13 +542,12 @@ def setUp(self): def prepare_track_for_import( self, track_id: int, - album_path: bytes, + album_path: Path, album_id: int | None = None, - ) -> MediaFile: - filename = bytestring_path(f"track_{track_id}.mp3") - medium_path = os.path.join(album_path, filename) - shutil.copy(self.resource_path, syspath(medium_path)) - medium = MediaFile(medium_path) + ) -> Path: + track_path = album_path / f"track_{track_id}.mp3" + shutil.copy(self.resource_path, track_path) + medium = MediaFile(track_path) medium.update( { "album": "Tag Album" + (f" {album_id}" if album_id else ""), @@ -558,11 +561,12 @@ def prepare_track_for_import( } ) medium.save() - return medium + self.import_media.append(medium) + return track_path def prepare_album_for_import( self, item_count: int, album_id: int | None = None - ) -> None: + ) -> list[Path]: """Create an album directory with media files to import. The directory has following layout @@ -571,17 +575,14 @@ def prepare_album_for_import( track_2.mp3 track_3.mp3 """ - album_path = os.path.join( - self.import_dir, - bytestring_path(f"album_{album_id}" if album_id else "album"), - ) - os.makedirs(syspath(album_path), exist_ok=True) + album_dir = f"album_{album_id}" if album_id else "album" + album_path = self.import_path / album_dir + album_path.mkdir(exist_ok=True) - mediums = [ + return [ self.prepare_track_for_import(tid, album_path, album_id=album_id) for tid in range(1, item_count + 1) ] - self.import_media.extend(mediums) def prepare_albums_for_import(self, count: int = 1) -> None: album_dirs = Path(os.fsdecode(self.import_dir)).glob("album_*") @@ -590,7 +591,7 @@ def prepare_albums_for_import(self, count: int = 1) -> None: for album_id in range(base_idx, count + base_idx): self.prepare_album_for_import(1, album_id=album_id) - def _get_import_session(self, import_dir: str) -> ImportSession: + def _get_import_session(self, import_dir: bytes) -> ImportSession: return ImportSessionFixture( self.lib, loghandler=None, @@ -599,7 +600,7 @@ def _get_import_session(self, import_dir: str) -> ImportSession: ) def setup_importer( - self, import_dir: str | None = None, **kwargs + self, import_dir: bytes | None = None, **kwargs ) -> ImportSession: config["import"].set_args({**self.default_import_config, **kwargs}) self.importer = self._get_import_session(import_dir or self.import_dir) @@ -755,7 +756,7 @@ class TerminalImportMixin(ImportHelper): io: _common.DummyIO - def _get_import_session(self, import_dir: str) -> importer.ImportSession: + def _get_import_session(self, import_dir: bytes) -> importer.ImportSession: self.io.install() return TerminalImportSessionFixture( self.lib, diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 64a20722d4..bfb23c0539 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -387,7 +387,7 @@ def _fsencoding() -> str: return encoding -def bytestring_path(path: Bytes_or_String) -> bytes: +def bytestring_path(path: PathLike) -> bytes: """Given a path, which is either a bytes or a unicode, returns a str path (ensuring that we never deal with Unicode pathnames). Path should be bytes but has safeguards for strings to be converted. @@ -396,17 +396,21 @@ def bytestring_path(path: Bytes_or_String) -> bytes: if isinstance(path, bytes): return path + str_path = str(path) + # On Windows, remove the magic prefix added by `syspath`. This makes # ``bytestring_path(syspath(X)) == X``, i.e., we can safely # round-trip through `syspath`. - if os.path.__name__ == "ntpath" and path.startswith(WINDOWS_MAGIC_PREFIX): - path = path[len(WINDOWS_MAGIC_PREFIX) :] + if os.path.__name__ == "ntpath" and str_path.startswith( + WINDOWS_MAGIC_PREFIX + ): + str_path = str_path[len(WINDOWS_MAGIC_PREFIX) :] # Try to encode with default encodings, but fall back to utf-8. try: - return path.encode(_fsencoding()) + return str_path.encode(_fsencoding()) except (UnicodeError, LookupError): - return path.encode("utf-8") + return str_path.encode("utf-8") PATH_SEP: bytes = bytestring_path(os.sep) @@ -434,39 +438,27 @@ def displayable_path( return path.decode("utf-8", "ignore") -def syspath(path: Bytes_or_String, prefix: bool = True) -> str: +def syspath(path: PathLike, prefix: bool = True) -> str: """Convert a path for use by the operating system. In particular, paths on Windows must receive a magic prefix and must be converted to Unicode before they are sent to the OS. To disable the magic prefix on Windows, set `prefix` to False---but only do this if you *really* know what you're doing. """ + str_path = os.fsdecode(path) # Don't do anything if we're not on windows if os.path.__name__ != "ntpath": - return path - - if not isinstance(path, str): - # Beets currently represents Windows paths internally with UTF-8 - # arbitrarily. But earlier versions used MBCS because it is - # reported as the FS encoding by Windows. Try both. - try: - path = path.decode("utf-8") - except UnicodeError: - # The encoding should always be MBCS, Windows' broken - # Unicode representation. - assert isinstance(path, bytes) - encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() - path = path.decode(encoding, "replace") + return str_path # Add the magic prefix if it isn't already there. # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx - if prefix and not path.startswith(WINDOWS_MAGIC_PREFIX): - if path.startswith("\\\\"): + if prefix and not str_path.startswith(WINDOWS_MAGIC_PREFIX): + if str_path.startswith("\\\\"): # UNC path. Final path should look like \\?\UNC\... - path = "UNC" + path[1:] - path = WINDOWS_MAGIC_PREFIX + path + str_path = "UNC" + str_path[1:] + str_path = WINDOWS_MAGIC_PREFIX + str_path - return path + return str_path def samefile(p1: bytes, p2: bytes) -> bool: From 6dda984862e91ee207058ce1904b7a04b362961d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sun, 14 Jul 2024 16:41:26 +0100 Subject: [PATCH 25/29] Standardize ImportPretendTest import files prep --- test/test_importer.py | 78 ++++++++++++------------------------------- 1 file changed, 22 insertions(+), 56 deletions(-) diff --git a/test/test_importer.py b/test/test_importer.py index 80378626e1..ac370a9c1b 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -23,6 +23,7 @@ import unicodedata import unittest from io import StringIO +from pathlib import Path from tarfile import TarFile from tempfile import mkstemp from unittest.mock import Mock, patch @@ -1681,92 +1682,57 @@ def test_reimported_album_not_preserves_flexattr(self): class ImportPretendTest(ImportTestCase): """Test the pretend commandline option""" - def __init__(self, method_name="runTest"): - super().__init__(method_name) - self.matcher = None - def setUp(self): super().setUp() - self.__create_import_dir() - self.__create_empty_import_dir() - self.setup_importer(pretend=True) self.matcher = AutotagStub().install() self.io.install() + self.album_track_path, *_ = self.prepare_album_for_import(1) + self.single_path = self.prepare_track_for_import(2, self.import_path) + self.album_path = self.album_track_path.parent + def tearDown(self): super().tearDown() self.matcher.restore() - def __create_import_dir(self): - self.prepare_album_for_import(1) - resource_path = os.path.join(_common.RSRC, b"empty.mp3") - single_path = os.path.join(self.import_dir, b"track_2.mp3") - shutil.copy(syspath(resource_path), syspath(single_path)) - self.import_paths = [ - os.path.join(self.import_dir, b"album"), - single_path, - ] - self.import_files = [ - displayable_path( - os.path.join(self.import_paths[0], b"track_1.mp3") - ), - displayable_path(single_path), - ] - - def __create_empty_import_dir(self): - path = os.path.join(self.temp_dir, b"empty") - os.makedirs(syspath(path)) - self.empty_path = path - - def __run(self, import_paths): - self.importer.paths = import_paths + def __run(self, importer): with capture_log() as logs: - self.importer.run() - - logs = [line for line in logs if not line.startswith("Sending event:")] + importer.run() self.assertEqual(len(self.lib.items()), 0) self.assertEqual(len(self.lib.albums()), 0) - return logs + return [line for line in logs if not line.startswith("Sending event:")] def test_import_singletons_pretend(self): - self.importer = self.setup_singleton_importer() - logs = self.__run(self.import_paths) - self.assertEqual( - logs, + self.__run(self.setup_singleton_importer(pretend=True)), [ - "Singleton: %s" % displayable_path(self.import_files[0]), - "Singleton: %s" % displayable_path(self.import_paths[1]), + f"Singleton: {self.single_path}", + f"Singleton: {self.album_track_path}", ], ) def test_import_album_pretend(self): - self.importer = self.setup_importer() - logs = self.__run(self.import_paths) - self.assertEqual( - logs, + self.__run(self.setup_importer(pretend=True)), [ - "Album: %s" % displayable_path(self.import_paths[0]), - " %s" % displayable_path(self.import_files[0]), - "Album: %s" % displayable_path(self.import_paths[1]), - " %s" % displayable_path(self.import_paths[1]), + f"Album: {self.import_path}", + f" {self.single_path}", + f"Album: {self.album_path}", + f" {self.album_track_path}", ], ) def test_import_pretend_empty(self): - self.importer = self.setup_importer() - logs = self.__run([self.empty_path]) + empty_path = Path(os.fsdecode(self.temp_dir)) / "empty" + empty_path.mkdir() + + importer = self.setup_importer(pretend=True, import_dir=empty_path) self.assertEqual( - logs, - [ - "No files imported from {}".format( - displayable_path(self.empty_path) - ) - ], + self.__run(importer), + [f"No files imported from {empty_path}"], ) From e097f1a8c63f77f5e71a6a3787d3e4652efba15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Mon, 15 Jul 2024 04:16:33 +0100 Subject: [PATCH 26/29] Rewrite FileFilterPluginTest And rewrite the tests since they were far too confusing to follow. --- beets/test/helper.py | 11 +- test/plugins/test_filefilter.py | 220 +++++++------------------------- 2 files changed, 53 insertions(+), 178 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 965d418f88..4a217e53f0 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -565,7 +565,10 @@ def prepare_track_for_import( return track_path def prepare_album_for_import( - self, item_count: int, album_id: int | None = None + self, + item_count: int, + album_id: int | None = None, + album_path: Path | None = None, ) -> list[Path]: """Create an album directory with media files to import. @@ -575,8 +578,10 @@ def prepare_album_for_import( track_2.mp3 track_3.mp3 """ - album_dir = f"album_{album_id}" if album_id else "album" - album_path = self.import_path / album_dir + if not album_path: + album_dir = f"album_{album_id}" if album_id else "album" + album_path = self.import_path / album_dir + album_path.mkdir(exist_ok=True) return [ diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index abf2b4c622..37058878ea 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -14,217 +14,87 @@ """Tests for the `filefilter` plugin. """ - - -import os -import shutil - -from mediafile import MediaFile - from beets import config -from beets.test import _common -from beets.test.helper import ImportTestCase, capture_log -from beets.util import bytestring_path, displayable_path, syspath +from beets.test.helper import ImportTestCase +from beets.util import bytestring_path from beetsplug.filefilter import FileFilterPlugin class FileFilterPluginMixin(ImportTestCase): def setUp(self): super().setUp() - self.__create_import_dir(2) + self.prepare_tracks_for_import() 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") - shutil.copy(syspath(resource_path), syspath(dest_path)) - medium = MediaFile(dest_path) - # Set metadata - for attr in metadata: - setattr(medium, attr, metadata[attr]) - medium.save() - - def __create_import_dir(self, count): - self.artist_path = os.path.join(self.import_dir, b"artist") - self.album_path = os.path.join(self.artist_path, b"album") - self.misc_path = os.path.join(self.import_dir, b"misc") - os.makedirs(syspath(self.album_path)) - os.makedirs(syspath(self.misc_path)) - - metadata = { - "artist": "Tag Artist", - "album": "Tag Album", - "albumartist": None, - "mb_trackid": None, - "mb_albumid": None, - "comp": None, + def prepare_tracks_for_import(self): + self.album_track, self.other_album_track, self.single_track = ( + bytestring_path(self.prepare_album_for_import(1, album_path=p)[0]) + for p in [ + self.import_path / "album", + self.import_path / "other_album", + self.import_path, + ] + ) + self.all_tracks = { + self.album_track, + self.other_album_track, + self.single_track, } - self.album_paths = [] - for i in range(count): - metadata["track"] = i + 1 - metadata["title"] = "Tag Track Album %d" % (i + 1) - track_file = bytestring_path("%02d - track.mp3" % (i + 1)) - dest_path = os.path.join(self.album_path, track_file) - self.__copy_file(dest_path, metadata) - self.album_paths.append(dest_path) - - self.artist_paths = [] - metadata["album"] = None - for i in range(count): - metadata["track"] = i + 10 - metadata["title"] = "Tag Track Artist %d" % (i + 1) - track_file = bytestring_path("track_%d.mp3" % (i + 1)) - dest_path = os.path.join(self.artist_path, track_file) - self.__copy_file(dest_path, metadata) - self.artist_paths.append(dest_path) - - self.misc_paths = [] - for i in range(count): - metadata["artist"] = "Artist %d" % (i + 42) - metadata["track"] = i + 5 - metadata["title"] = "Tag Track Misc %d" % (i + 1) - track_file = bytestring_path("track_%d.mp3" % (i + 1)) - dest_path = os.path.join(self.misc_path, track_file) - self.__copy_file(dest_path, metadata) - self.misc_paths.append(dest_path) - - def _run(self, expected_lines): + + def _run(self, expected_album_count, expected_paths): self.load_plugins("filefilter") - with capture_log() as logs: - self.importer.run() - logs = [line for line in logs if not line.startswith("Sending event:")] + self.importer.run() - self.assertEqual(logs, expected_lines) + self.assertEqual(len(self.lib.albums()), expected_album_count) + self.assertEqual({i.path for i in self.lib.items()}, expected_paths) class FileFilterPluginNonSingletonTest(FileFilterPluginMixin): def setUp(self): super().setUp() - self.importer = self.setup_importer(pretend=True) + self.importer = self.setup_importer(autotag=False, copy=False) def test_import_default(self): """The default configuration should import everything.""" - self._run( - [ - "Album: %s" % displayable_path(self.artist_path), - " %s" % displayable_path(self.artist_paths[0]), - " %s" % displayable_path(self.artist_paths[1]), - "Album: %s" % displayable_path(self.album_path), - " %s" % displayable_path(self.album_paths[0]), - " %s" % displayable_path(self.album_paths[1]), - "Album: %s" % displayable_path(self.misc_path), - " %s" % displayable_path(self.misc_paths[0]), - " %s" % displayable_path(self.misc_paths[1]), - ] - ) + self._run(3, self.all_tracks) def test_import_nothing(self): config["filefilter"]["path"] = "not_there" - self._run( - ["No files imported from %s" % displayable_path(self.import_dir)] - ) + self._run(0, set()) - # Global options - def test_import_global(self): - config["filefilter"]["path"] = ".*track_1.*\\.mp3" - self._run( - [ - "Album: %s" % displayable_path(self.artist_path), - " %s" % displayable_path(self.artist_paths[0]), - "Album: %s" % displayable_path(self.misc_path), - " %s" % displayable_path(self.misc_paths[0]), - ] - ) + def test_global_config(self): + config["filefilter"]["path"] = ".*album.*" + self._run(2, {self.album_track, self.other_album_track}) - def test_import_album(self): - config["filefilter"]["album_path"] = ".*track_1.*\\.mp3" - self._run( - [ - "Album: %s" % displayable_path(self.artist_path), - " %s" % displayable_path(self.artist_paths[0]), - "Album: %s" % displayable_path(self.misc_path), - " %s" % displayable_path(self.misc_paths[0]), - ] - ) + def test_album_config(self): + config["filefilter"]["album_path"] = ".*other_album.*" + self._run(1, {self.other_album_track}) - def test_import_singleton(self): - config["filefilter"]["singleton_path"] = ".*track_1.*\\.mp3" - self._run( - [ - "Album: %s" % displayable_path(self.artist_path), - " %s" % displayable_path(self.artist_paths[0]), - " %s" % displayable_path(self.artist_paths[1]), - "Album: %s" % displayable_path(self.album_path), - " %s" % displayable_path(self.album_paths[0]), - " %s" % displayable_path(self.album_paths[1]), - "Album: %s" % displayable_path(self.misc_path), - " %s" % displayable_path(self.misc_paths[0]), - " %s" % displayable_path(self.misc_paths[1]), - ] - ) - - # Album and singleton options - def test_import_both(self): - config["filefilter"]["album_path"] = ".*track_1.*\\.mp3" - self._run( - [ - "Album: %s" % displayable_path(self.artist_path), - " %s" % displayable_path(self.artist_paths[0]), - "Album: %s" % displayable_path(self.misc_path), - " %s" % displayable_path(self.misc_paths[0]), - ] - ) + def test_singleton_config(self): + """Check that singleton configuration is ignored for album import.""" + config["filefilter"]["singleton_path"] = ".*other_album.*" + self._run(3, self.all_tracks) class FileFilterPluginSingletonTest(FileFilterPluginMixin): def setUp(self): super().setUp() - self.importer = self.setup_singleton_importer(pretend=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]), - ] - ) + self.importer = self.setup_singleton_importer(autotag=False, copy=False) - # 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]), - ] - ) + def test_global_config(self): + config["filefilter"]["path"] = ".*album.*" + self._run(0, {self.album_track, self.other_album_track}) - # 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]), - ] - ) + def test_album_config(self): + """Check that album configuration is ignored for singleton import.""" + config["filefilter"]["album_path"] = ".*other_album.*" + self._run(0, self.all_tracks) - # 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]), - ] - ) + def test_singleton_config(self): + config["filefilter"]["singleton_path"] = ".*other_album.*" + self._run(0, {self.other_album_track}) From 9c75513686c3880f8e08f578f54ce65519665b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Wed, 17 Jul 2024 05:31:40 +0100 Subject: [PATCH 27/29] test_ui: Fix Config/Plugin/Completion tests interdependency "test" plugin was not properly cleaned up after loading and would therefore stay around and picked up by other tests. --- beets/test/helper.py | 8 ++++---- test/test_ui.py | 29 +++++++++++++---------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index 4a217e53f0..aa883ade10 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -251,10 +251,10 @@ def unload_plugins(self): beets.config["plugins"] = [] beets.plugins._classes = set() beets.plugins._instances = {} - Item._types = Item._original_types - Album._types = Album._original_types - Item._queries = Item._original_queries - Album._queries = Album._original_queries + Item._types = getattr(Item, "_original_types", {}) + Album._types = getattr(Album, "_original_types", {}) + Item._queries = getattr(Item, "_original_queries", {}) + Album._queries = getattr(Album, "_original_queries", {}) # Library fixtures methods diff --git a/test/test_ui.py b/test/test_ui.py index 6d5c294a1f..7e2886e871 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -32,6 +32,7 @@ from beets.test import _common from beets.test.helper import ( BeetsTestCase, + PluginTestCase, capture_stdout, control_stdin, has_program, @@ -824,7 +825,15 @@ def test_parse_paths_from_logfile(self): @_common.slow_test() -class ConfigTest(BeetsTestCase): +class TestPluginTestCase(PluginTestCase): + plugin = "test" + + def setUp(self): + super().setUp() + config["pluginpath"] = [_common.PLUGINPATH] + + +class ConfigTest(TestPluginTestCase): def setUp(self): super().setUp() @@ -865,13 +874,11 @@ def setUp(self): self.env_patcher.start() self._reset_config() - self.load_plugins() def tearDown(self): self.env_patcher.stop() commands.default_commands.pop() os.chdir(syspath(self._orig_cwd)) - self.unload_plugins() super().tearDown() def _make_test_cmd(self): @@ -1064,6 +1071,7 @@ def test_cli_config_file_loads_plugin_commands(self): self.run_command("--config", cli_config_path, "plugin", lib=None) self.assertTrue(plugins.find_plugins()[0].is_test_plugin) + self.unload_plugins() def test_beetsdir_config(self): os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir) @@ -1385,20 +1393,14 @@ def test_custom_paths_prepend(self): @_common.slow_test() -class PluginTest(BeetsTestCase): +class PluginTest(TestPluginTestCase): def test_plugin_command_from_pluginpath(self): - config["pluginpath"] = [_common.PLUGINPATH] - config["plugins"] = ["test"] self.run_command("test", lib=None) @_common.slow_test() -class CompletionTest(BeetsTestCase): +class CompletionTest(TestPluginTestCase): def test_completion(self): - # Load plugin commands - config["pluginpath"] = [_common.PLUGINPATH] - config["plugins"] = ["test"] - # Do not load any other bash completion scripts on the system. env = dict(os.environ) env["BASH_COMPLETION_DIR"] = os.devnull @@ -1456,11 +1458,6 @@ def setUp(self): self.item.path = b"xxx/yyy" self.lib.add(self.item) self.lib.add_album([self.item]) - self.load_plugins() - - def tearDown(self): - self.unload_plugins() - super().tearDown() def test_base(self): l = self.run_with_output("ls") From 199f3079f21c255f977cbda6d38a3463f3dcae22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Wed, 17 Jul 2024 10:44:24 +0100 Subject: [PATCH 28/29] Use PluginMixin in tests that load plugins manually A constant `preload_plugin` is used to disable loading the plugin in the `setUp` initialisation, allowing the plugin to be loaded manually by the tests. Also added a cleanup instruction to remove listeners from configured plugins, and removed this logic from several tests. --- beets/test/helper.py | 76 +++++++++++++++------------- test/plugins/test_advancedrewrite.py | 9 ++-- test/plugins/test_edit.py | 6 --- test/plugins/test_filefilter.py | 13 ++--- test/plugins/test_hook.py | 10 ++-- test/plugins/test_playlist.py | 13 +++-- test/plugins/test_replaygain.py | 21 ++++---- test/plugins/test_zero.py | 12 ++--- test/test_logging.py | 7 --- 9 files changed, 75 insertions(+), 92 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index aa883ade10..e2bf98dee4 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -221,41 +221,6 @@ def teardown_beets(self): beets.config.clear() beets.config._materialized = False - def load_plugins(self, *plugins): - """Load and initialize plugins by names. - - Similar setting a list of plugins in the configuration. Make - sure you call ``unload_plugins()`` afterwards. - """ - # FIXME this should eventually be handled by a plugin manager - plugins = (self.plugin,) if hasattr(self, "plugin") else plugins - beets.config["plugins"] = plugins - beets.plugins.load_plugins(plugins) - beets.plugins.find_plugins() - - # Take a backup of the original _types and _queries to restore - # when unloading. - Item._original_types = dict(Item._types) - Album._original_types = dict(Album._types) - Item._types.update(beets.plugins.types(Item)) - Album._types.update(beets.plugins.types(Album)) - - Item._original_queries = dict(Item._queries) - Album._original_queries = dict(Album._queries) - Item._queries.update(beets.plugins.named_queries(Item)) - Album._queries.update(beets.plugins.named_queries(Album)) - - def unload_plugins(self): - """Unload all plugins and remove them from the configuration.""" - # FIXME this should eventually be handled by a plugin manager - beets.config["plugins"] = [] - beets.plugins._classes = set() - beets.plugins._instances = {} - Item._types = getattr(Item, "_original_types", {}) - Album._types = getattr(Album, "_original_types", {}) - Item._queries = getattr(Item, "_original_queries", {}) - Album._queries = getattr(Album, "_original_queries", {}) - # Library fixtures methods def create_item(self, **values): @@ -485,15 +450,54 @@ def setUp(self): class PluginMixin: plugin: ClassVar[str] + preload_plugin: ClassVar[bool] = True def setUp(self): super().setUp() - self.load_plugins() + if self.preload_plugin: + self.load_plugins() def tearDown(self): super().tearDown() self.unload_plugins() + def load_plugins(self, *plugins: str) -> None: + """Load and initialize plugins by names. + + Similar setting a list of plugins in the configuration. Make + sure you call ``unload_plugins()`` afterwards. + """ + # FIXME this should eventually be handled by a plugin manager + plugins = (self.plugin,) if hasattr(self, "plugin") else plugins + beets.config["plugins"] = plugins + beets.plugins.load_plugins(plugins) + beets.plugins.find_plugins() + + # Take a backup of the original _types and _queries to restore + # when unloading. + Item._original_types = dict(Item._types) + Album._original_types = dict(Album._types) + Item._types.update(beets.plugins.types(Item)) + Album._types.update(beets.plugins.types(Album)) + + Item._original_queries = dict(Item._queries) + Album._original_queries = dict(Album._queries) + Item._queries.update(beets.plugins.named_queries(Item)) + Album._queries.update(beets.plugins.named_queries(Album)) + + def unload_plugins(self) -> None: + """Unload all plugins and remove them from the configuration.""" + # FIXME this should eventually be handled by a plugin manager + for plugin_class in beets.plugins._instances: + plugin_class.listeners = None + beets.config["plugins"] = [] + beets.plugins._classes = set() + beets.plugins._instances = {} + Item._types = getattr(Item, "_original_types", {}) + Album._types = getattr(Album, "_original_types", {}) + Item._queries = getattr(Item, "_original_queries", {}) + Album._queries = getattr(Album, "_original_queries", {}) + class PluginTestCase(PluginMixin, BeetsTestCase): pass diff --git a/test/plugins/test_advancedrewrite.py b/test/plugins/test_advancedrewrite.py index 782b779e82..55f090d74d 100644 --- a/test/plugins/test_advancedrewrite.py +++ b/test/plugins/test_advancedrewrite.py @@ -16,16 +16,15 @@ """ -from beets.test.helper import BeetsTestCase +from beets.test.helper import BeetsTestCase, PluginMixin from beets.ui import UserError PLUGIN_NAME = "advancedrewrite" -class AdvancedRewritePluginTest(BeetsTestCase): - def tearDown(self): - self.unload_plugins() - super().tearDown() +class AdvancedRewritePluginTest(PluginMixin, BeetsTestCase): + plugin = "advancedrewrite" + preload_plugin = False def test_simple_rewrite_example(self): self.config[PLUGIN_NAME] = [ diff --git a/test/plugins/test_edit.py b/test/plugins/test_edit.py index ba068e90dd..e15caaa57d 100644 --- a/test/plugins/test_edit.py +++ b/test/plugins/test_edit.py @@ -26,7 +26,6 @@ TerminalImportMixin, control_stdin, ) -from beetsplug.edit import EditPlugin class ModifyFileMocker: @@ -135,10 +134,6 @@ def setUp(self): {f: item[f] for f in item._fields} for item in self.album.items() ] - def tearDown(self): - EditPlugin.listeners = None - super().tearDown() - def assertCounts( # noqa self, mock_write, @@ -338,7 +333,6 @@ def setUp(self): self.matcher.matching = AutotagStub.GOOD def tearDown(self): - EditPlugin.listeners = None super().tearDown() self.matcher.restore() diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index 37058878ea..194cafff63 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -15,21 +15,18 @@ """Tests for the `filefilter` plugin. """ from beets import config -from beets.test.helper import ImportTestCase +from beets.test.helper import ImportTestCase, PluginMixin from beets.util import bytestring_path -from beetsplug.filefilter import FileFilterPlugin -class FileFilterPluginMixin(ImportTestCase): +class FileFilterPluginMixin(PluginMixin, ImportTestCase): + plugin = "filefilter" + preload_plugin = False + def setUp(self): super().setUp() self.prepare_tracks_for_import() - def tearDown(self): - self.unload_plugins() - FileFilterPlugin.listeners = None - super().tearDown() - def prepare_tracks_for_import(self): self.album_track, self.other_album_track, self.single_track = ( bytestring_path(self.prepare_album_for_import(1, album_path=p)[0]) diff --git a/test/plugins/test_hook.py b/test/plugins/test_hook.py index 8d44423181..f935039adc 100644 --- a/test/plugins/test_hook.py +++ b/test/plugins/test_hook.py @@ -19,7 +19,7 @@ import unittest from beets import config, plugins -from beets.test.helper import BeetsTestCase, capture_log +from beets.test.helper import BeetsTestCase, PluginMixin, capture_log def get_temporary_path(): @@ -29,13 +29,11 @@ def get_temporary_path(): return os.path.join(temporary_directory, temporary_name) -class HookTest(BeetsTestCase): +class HookTest(PluginMixin, BeetsTestCase): + plugin = "hook" + preload_plugin = False TEST_HOOK_COUNT = 5 - def tearDown(self): - self.unload_plugins() - super().tearDown() - def _add_hook(self, event, command): hook = {"event": event, "command": command} diff --git a/test/plugins/test_playlist.py b/test/plugins/test_playlist.py index 8a8ef85a77..53f4d8a4e4 100644 --- a/test/plugins/test_playlist.py +++ b/test/plugins/test_playlist.py @@ -18,10 +18,13 @@ import beets from beets.test import _common -from beets.test.helper import BeetsTestCase +from beets.test.helper import PluginTestCase -class PlaylistTestCase(BeetsTestCase): +class PlaylistTestCase(PluginTestCase): + plugin = "playlist" + preload_plugin = False + def setUp(self): super().setUp() @@ -77,15 +80,11 @@ def setUp(self): self.config["playlist"]["playlist_dir"] = self.playlist_dir self.setup_test() - self.load_plugins("playlist") + self.load_plugins() def setup_test(self): raise NotImplementedError - def tearDown(self): - self.unload_plugins() - super().tearDown() - class PlaylistQueryTest: def test_name_query_with_absolute_paths_in_playlist(self): diff --git a/test/plugins/test_replaygain.py b/test/plugins/test_replaygain.py index 0e7b663f5b..348725a6f2 100644 --- a/test/plugins/test_replaygain.py +++ b/test/plugins/test_replaygain.py @@ -19,7 +19,12 @@ from mediafile import MediaFile from beets import config -from beets.test.helper import AsIsImporterMixin, ImportTestCase, has_program +from beets.test.helper import ( + AsIsImporterMixin, + ImportTestCase, + PluginMixin, + has_program, +) from beetsplug.replaygain import ( FatalGstreamerPluginReplayGainError, GStreamerBackend, @@ -52,8 +57,11 @@ def reset_replaygain(item): item.store() -class ReplayGainTestCase(ImportTestCase): +class ReplayGainTestCase(PluginMixin, ImportTestCase): db_on_disk = True + plugin = "replaygain" + preload_plugin = False + backend: ClassVar[str] def setUp(self): @@ -63,14 +71,7 @@ def setUp(self): super().setUp() self.config["replaygain"]["backend"] = self.backend - try: - self.load_plugins("replaygain") - except Exception: - self.tearDown() - - def tearDown(self): - self.unload_plugins() - super().tearDown() + self.load_plugins() class ThreadedImportMixin: diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index 8b6427ae16..cc67d0095a 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -3,12 +3,15 @@ from mediafile import MediaFile from beets.library import Item -from beets.test.helper import BeetsTestCase, control_stdin +from beets.test.helper import BeetsTestCase, PluginMixin, control_stdin from beets.util import syspath from beetsplug.zero import ZeroPlugin -class ZeroPluginTest(BeetsTestCase): +class ZeroPluginTest(PluginMixin, BeetsTestCase): + plugin = "zero" + preload_plugin = False + def setUp(self): super().setUp() self.config["zero"] = { @@ -17,11 +20,6 @@ def setUp(self): "update_database": False, } - def tearDown(self): - ZeroPlugin.listeners = None - super().tearDown() - self.unload_plugins() - def test_no_patterns(self): self.config["zero"]["fields"] = ["comments", "month"] diff --git a/test/test_logging.py b/test/test_logging.py index 0cd5b68180..30d79f57e0 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -82,13 +82,6 @@ def setUp(self): beetsplug.dummy = self.DummyModule super().setUp() - def tearDown(self): - super().tearDown() - del beetsplug.dummy - sys.modules.pop("beetsplug.dummy") - self.DummyModule.DummyPlugin.listeners = None - self.DummyModule.DummyPlugin._raw_listeners = None - def test_command_level0(self): self.config["verbose"] = 0 with helper.capture_log() as logs: From 5f395ab4f4f4ec434a38aeb817bebb8bb2ce82c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Mon, 29 Jul 2024 15:33:12 +0100 Subject: [PATCH 29/29] Configure plugins using PluginMixin.configure_plugin --- beets/test/helper.py | 15 ++- test/plugins/test_advancedrewrite.py | 179 +++++++++++-------------- test/plugins/test_filefilter.py | 43 +++--- test/plugins/test_hook.py | 188 +++++++++++---------------- test/plugins/test_zero.py | 136 ++++++++----------- test/test_importer.py | 2 +- 6 files changed, 238 insertions(+), 325 deletions(-) diff --git a/beets/test/helper.py b/beets/test/helper.py index e2bf98dee4..e94bf86cd1 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -43,7 +43,7 @@ from io import StringIO from pathlib import Path from tempfile import mkdtemp, mkstemp -from typing import ClassVar +from typing import Any, ClassVar from unittest.mock import patch import responses @@ -498,6 +498,19 @@ def unload_plugins(self) -> None: Item._queries = getattr(Item, "_original_queries", {}) Album._queries = getattr(Album, "_original_queries", {}) + @contextmanager + def configure_plugin(self, config: list[Any] | dict[str, Any]): + if isinstance(config, list): + beets.config[self.plugin] = config + else: + for key, value in config.items(): + beets.config[self.plugin][key] = value + self.load_plugins(self.plugin) + + yield + + self.unload_plugins() + class PluginTestCase(PluginMixin, BeetsTestCase): pass diff --git a/test/plugins/test_advancedrewrite.py b/test/plugins/test_advancedrewrite.py index 55f090d74d..65dece2473 100644 --- a/test/plugins/test_advancedrewrite.py +++ b/test/plugins/test_advancedrewrite.py @@ -16,139 +16,106 @@ """ -from beets.test.helper import BeetsTestCase, PluginMixin +from beets.test.helper import PluginTestCase from beets.ui import UserError PLUGIN_NAME = "advancedrewrite" -class AdvancedRewritePluginTest(PluginMixin, BeetsTestCase): +class AdvancedRewritePluginTest(PluginTestCase): plugin = "advancedrewrite" preload_plugin = False def test_simple_rewrite_example(self): - self.config[PLUGIN_NAME] = [ - {"artist ODD EYE CIRCLE": "이달의 소녀 오드아이써클"}, - ] - self.load_plugins(PLUGIN_NAME) - - item = self.add_item( - title="Uncover", - artist="ODD EYE CIRCLE", - albumartist="ODD EYE CIRCLE", - album="Mix & Match", - ) + with self.configure_plugin( + [{"artist ODD EYE CIRCLE": "이달의 소녀 오드아이써클"}] + ): + item = self.add_item( + artist="ODD EYE CIRCLE", + albumartist="ODD EYE CIRCLE", + ) - self.assertEqual(item.artist, "이달의 소녀 오드아이써클") + self.assertEqual(item.artist, "이달의 소녀 오드아이써클") def test_advanced_rewrite_example(self): - self.config[PLUGIN_NAME] = [ - { - "match": "mb_artistid:dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c year:..2022", - "replacements": { - "artist": "이달의 소녀 오드아이써클", - "artist_sort": "LOONA / ODD EYE CIRCLE", + with self.configure_plugin( + [ + { + "match": "mb_artistid:dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c year:..2022", # noqa: E501 + "replacements": { + "artist": "이달의 소녀 오드아이써클", + "artist_sort": "LOONA / ODD EYE CIRCLE", + }, }, - }, - ] - self.load_plugins(PLUGIN_NAME) - - item_a = self.add_item( - title="Uncover", - artist="ODD EYE CIRCLE", - albumartist="ODD EYE CIRCLE", - artist_sort="ODD EYE CIRCLE", - albumartist_sort="ODD EYE CIRCLE", - album="Mix & Match", - mb_artistid="dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c", - year=2017, - ) - item_b = self.add_item( - title="Air Force One", - artist="ODD EYE CIRCLE", - albumartist="ODD EYE CIRCLE", - artist_sort="ODD EYE CIRCLE", - albumartist_sort="ODD EYE CIRCLE", - album="ODD EYE CIRCLE ", - mb_artistid="dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c", - year=2023, - ) - - # Assert that all replacements were applied to item_a - self.assertEqual("이달의 소녀 오드아이써클", item_a.artist) - self.assertEqual("LOONA / ODD EYE CIRCLE", item_a.artist_sort) - self.assertEqual("LOONA / ODD EYE CIRCLE", item_a.albumartist_sort) - - # Assert that no replacements were applied to item_b - self.assertEqual("ODD EYE CIRCLE", item_b.artist) + ] + ): + item_a = self.add_item( + artist="ODD EYE CIRCLE", + artist_sort="ODD EYE CIRCLE", + mb_artistid="dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c", + year=2017, + ) + item_b = self.add_item( + artist="ODD EYE CIRCLE", + artist_sort="ODD EYE CIRCLE", + mb_artistid="dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c", + year=2023, + ) + + # Assert that all replacements were applied to item_a + self.assertEqual("이달의 소녀 오드아이써클", item_a.artist) + self.assertEqual("LOONA / ODD EYE CIRCLE", item_a.artist_sort) + self.assertEqual("LOONA / ODD EYE CIRCLE", item_a.albumartist_sort) + + # Assert that no replacements were applied to item_b + self.assertEqual("ODD EYE CIRCLE", item_b.artist) def test_advanced_rewrite_example_with_multi_valued_field(self): - self.config[PLUGIN_NAME] = [ - { - "match": "artist:배유빈 feat. 김미현", - "replacements": { - "artists": ["유빈", "미미"], + with self.configure_plugin( + [ + { + "match": "artist:배유빈 feat. 김미현", + "replacements": {"artists": ["유빈", "미미"]}, }, - }, - ] - self.load_plugins(PLUGIN_NAME) - - item = self.add_item( - artist="배유빈 feat. 김미현", - artists=["배유빈", "김미현"], - ) + ] + ): + item = self.add_item( + artist="배유빈 feat. 김미현", + artists=["배유빈", "김미현"], + ) - self.assertEqual(item.artists, ["유빈", "미미"]) + self.assertEqual(item.artists, ["유빈", "미미"]) def test_fail_when_replacements_empty(self): - self.config[PLUGIN_NAME] = [ - { - "match": "artist:A", - "replacements": {}, - }, - ] with self.assertRaises( UserError, msg="Advanced rewrites must have at least one replacement", - ): - self.load_plugins(PLUGIN_NAME) + ), self.configure_plugin([{"match": "artist:A", "replacements": {}}]): + pass def test_fail_when_rewriting_single_valued_field_with_list(self): - self.config[PLUGIN_NAME] = [ - { - "match": "artist:'A & B'", - "replacements": { - "artist": ["C", "D"], - }, - }, - ] with self.assertRaises( UserError, msg="Field artist is not a multi-valued field but a list was given: C, D", + ), self.configure_plugin( + [ + { + "match": "artist:'A & B'", + "replacements": {"artist": ["C", "D"]}, + }, + ] ): - self.load_plugins(PLUGIN_NAME) + pass def test_combined_rewrite_example(self): - self.config[PLUGIN_NAME] = [ - {"artist A": "B"}, - { - "match": "album:'C'", - "replacements": { - "artist": "D", - }, - }, - ] - self.load_plugins(PLUGIN_NAME) - - item = self.add_item( - artist="A", - albumartist="A", - ) - self.assertEqual(item.artist, "B") - - item = self.add_item( - artist="C", - albumartist="C", - album="C", - ) - self.assertEqual(item.artist, "D") + with self.configure_plugin( + [ + {"artist A": "B"}, + {"match": "album:'C'", "replacements": {"artist": "D"}}, + ] + ): + item = self.add_item(artist="A", albumartist="A") + self.assertEqual(item.artist, "B") + + item = self.add_item(artist="C", albumartist="C", album="C") + self.assertEqual(item.artist, "D") diff --git a/test/plugins/test_filefilter.py b/test/plugins/test_filefilter.py index 194cafff63..d17539166f 100644 --- a/test/plugins/test_filefilter.py +++ b/test/plugins/test_filefilter.py @@ -14,7 +14,6 @@ """Tests for the `filefilter` plugin. """ -from beets import config from beets.test.helper import ImportTestCase, PluginMixin from beets.util import bytestring_path @@ -42,10 +41,9 @@ def prepare_tracks_for_import(self): self.single_track, } - def _run(self, expected_album_count, expected_paths): - self.load_plugins("filefilter") - - self.importer.run() + def _run(self, config, expected_album_count, expected_paths): + with self.configure_plugin(config): + self.importer.run() self.assertEqual(len(self.lib.albums()), expected_album_count) self.assertEqual({i.path for i in self.lib.items()}, expected_paths) @@ -58,24 +56,28 @@ def setUp(self): def test_import_default(self): """The default configuration should import everything.""" - self._run(3, self.all_tracks) + self._run({}, 3, self.all_tracks) def test_import_nothing(self): - config["filefilter"]["path"] = "not_there" - self._run(0, set()) + self._run({"path": "not_there"}, 0, set()) def test_global_config(self): - config["filefilter"]["path"] = ".*album.*" - self._run(2, {self.album_track, self.other_album_track}) + self._run( + {"path": ".*album.*"}, + 2, + {self.album_track, self.other_album_track}, + ) def test_album_config(self): - config["filefilter"]["album_path"] = ".*other_album.*" - self._run(1, {self.other_album_track}) + self._run( + {"album_path": ".*other_album.*"}, + 1, + {self.other_album_track}, + ) def test_singleton_config(self): """Check that singleton configuration is ignored for album import.""" - config["filefilter"]["singleton_path"] = ".*other_album.*" - self._run(3, self.all_tracks) + self._run({"singleton_path": ".*other_album.*"}, 3, self.all_tracks) class FileFilterPluginSingletonTest(FileFilterPluginMixin): @@ -84,14 +86,15 @@ def setUp(self): self.importer = self.setup_singleton_importer(autotag=False, copy=False) def test_global_config(self): - config["filefilter"]["path"] = ".*album.*" - self._run(0, {self.album_track, self.other_album_track}) + self._run( + {"path": ".*album.*"}, 0, {self.album_track, self.other_album_track} + ) def test_album_config(self): """Check that album configuration is ignored for singleton import.""" - config["filefilter"]["album_path"] = ".*other_album.*" - self._run(0, self.all_tracks) + self._run({"album_path": ".*other_album.*"}, 0, self.all_tracks) def test_singleton_config(self): - config["filefilter"]["singleton_path"] = ".*other_album.*" - self._run(0, {self.other_album_track}) + self._run( + {"singleton_path": ".*other_album.*"}, 0, {self.other_album_track} + ) diff --git a/test/plugins/test_hook.py b/test/plugins/test_hook.py index f935039adc..01abbcb1cf 100644 --- a/test/plugins/test_hook.py +++ b/test/plugins/test_hook.py @@ -13,148 +13,112 @@ # included in all copies or substantial portions of the Software. +from __future__ import annotations + import os.path import sys -import tempfile import unittest +from contextlib import contextmanager +from typing import Callable, Iterator -from beets import config, plugins -from beets.test.helper import BeetsTestCase, PluginMixin, capture_log - - -def get_temporary_path(): - temporary_directory = tempfile._get_default_tempdir() - temporary_name = next(tempfile._get_candidate_names()) +from beets import plugins +from beets.test.helper import PluginTestCase, capture_log - return os.path.join(temporary_directory, temporary_name) - -class HookTest(PluginMixin, BeetsTestCase): +class HookTestCase(PluginTestCase): plugin = "hook" preload_plugin = False - TEST_HOOK_COUNT = 5 - - def _add_hook(self, event, command): - hook = {"event": event, "command": command} - hooks = config["hook"]["hooks"].get(list) if "hook" in config else [] - hooks.append(hook) + def _get_hook(self, event: str, command: str) -> dict[str, str]: + return {"event": event, "command": command} - config["hook"]["hooks"] = hooks - def test_hook_empty_command(self): - self._add_hook("test_event", "") +class HookLogsTest(HookTestCase): + @contextmanager + def _configure_logs(self, command: str) -> Iterator[list[str]]: + config = {"hooks": [self._get_hook("test_event", command)]} - self.load_plugins("hook") - - with capture_log("beets.hook") as logs: + with self.configure_plugin(config), capture_log("beets.hook") as logs: plugins.send("test_event") + yield logs - self.assertIn('hook: invalid command ""', logs) + def test_hook_empty_command(self): + with self._configure_logs("") as logs: + self.assertIn('hook: invalid command ""', logs) # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_hook_non_zero_exit(self): - self._add_hook("test_event", 'sh -c "exit 1"') - - self.load_plugins("hook") - - with capture_log("beets.hook") as logs: - plugins.send("test_event") - - self.assertIn("hook: hook for test_event exited with status 1", logs) + with self._configure_logs('sh -c "exit 1"') as logs: + self.assertIn( + "hook: hook for test_event exited with status 1", logs + ) def test_hook_non_existent_command(self): - self._add_hook("test_event", "non-existent-command") - - self.load_plugins("hook") + with self._configure_logs("non-existent-command") as logs: + logs = "\n".join(logs) + + self.assertIn("hook: hook for test_event failed: ", logs) + # The error message is different for each OS. Unfortunately the text is + # different in each case, where the only shared text is the string + # 'file' and substring 'Err' + self.assertIn("Err", logs) + self.assertIn("file", logs) + + +class HookCommandTest(HookTestCase): + TEST_HOOK_COUNT = 2 + + events = [f"test_event_{i}" for i in range(TEST_HOOK_COUNT)] + + def setUp(self): + super().setUp() + temp_dir = os.fsdecode(self.temp_dir) + self.paths = [os.path.join(temp_dir, e) for e in self.events] + + def _test_command( + self, + make_test_path: Callable[[str, str], str], + send_path_kwarg: bool = False, + ) -> None: + """Check that each of the configured hooks is executed. + + Configure hooks for each event: + 1. Use the given 'make_test_path' callable to create a test path from the event + and the original path. + 2. Configure a hook with a command to touch this path. + + For each of the original paths: + 1. Send a test event + 2. Assert that a file has been created under the original path, which proves + that the configured hook command has been executed. + """ + hooks = [ + self._get_hook(e, f"touch {make_test_path(e, p)}") + for e, p in zip(self.events, self.paths) + ] - with capture_log("beets.hook") as logs: - plugins.send("test_event") + with self.configure_plugin({"hooks": hooks}): + for event, path in zip(self.events, self.paths): + if send_path_kwarg: + plugins.send(event, path=path) + else: + plugins.send(event) + self.assertTrue(os.path.isfile(path)) - self.assertTrue( - any( - message.startswith("hook: hook for test_event failed: ") - for message in logs - ) - ) - - # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_hook_no_arguments(self): - temporary_paths = [ - get_temporary_path() for i in range(self.TEST_HOOK_COUNT) - ] - - for index, path in enumerate(temporary_paths): - self._add_hook(f"test_no_argument_event_{index}", f'touch "{path}"') - - self.load_plugins("hook") + self._test_command(lambda _, p: p) - for index in range(len(temporary_paths)): - plugins.send(f"test_no_argument_event_{index}") - - for path in temporary_paths: - self.assertTrue(os.path.isfile(path)) - os.remove(path) - - # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_hook_event_substitution(self): - temporary_directory = tempfile._get_default_tempdir() - event_names = [ - f"test_event_event_{i}" for i in range(self.TEST_HOOK_COUNT) - ] - - for event in event_names: - self._add_hook(event, f'touch "{temporary_directory}/{{event}}"') - - self.load_plugins("hook") + self._test_command(lambda e, p: p.replace(e, "{event}")) - for event in event_names: - plugins.send(event) - - for event in event_names: - path = os.path.join(temporary_directory, event) - - self.assertTrue(os.path.isfile(path)) - os.remove(path) - - # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_hook_argument_substitution(self): - temporary_paths = [ - get_temporary_path() for i in range(self.TEST_HOOK_COUNT) - ] + self._test_command(lambda *_: "{path}", send_path_kwarg=True) - for index, path in enumerate(temporary_paths): - self._add_hook(f"test_argument_event_{index}", 'touch "{path}"') - - self.load_plugins("hook") - - for index, path in enumerate(temporary_paths): - plugins.send(f"test_argument_event_{index}", path=path) - - for path in temporary_paths: - self.assertTrue(os.path.isfile(path)) - os.remove(path) - - # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_hook_bytes_interpolation(self): - temporary_paths = [ - get_temporary_path().encode("utf-8") - for i in range(self.TEST_HOOK_COUNT) - ] - - for index, path in enumerate(temporary_paths): - self._add_hook(f"test_bytes_event_{index}", 'touch "{path}"') - - self.load_plugins("hook") - - for index, path in enumerate(temporary_paths): - plugins.send(f"test_bytes_event_{index}", path=path) - - for path in temporary_paths: - self.assertTrue(os.path.isfile(path)) - os.remove(path) + self.paths = [p.encode() for p in self.paths] + self._test_command(lambda *_: "{path}", send_path_kwarg=True) diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index cc67d0095a..c267c0708b 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -3,26 +3,16 @@ from mediafile import MediaFile from beets.library import Item -from beets.test.helper import BeetsTestCase, PluginMixin, control_stdin +from beets.test.helper import PluginTestCase, control_stdin from beets.util import syspath from beetsplug.zero import ZeroPlugin -class ZeroPluginTest(PluginMixin, BeetsTestCase): +class ZeroPluginTest(PluginTestCase): plugin = "zero" preload_plugin = False - def setUp(self): - super().setUp() - self.config["zero"] = { - "fields": [], - "keep_fields": [], - "update_database": False, - } - def test_no_patterns(self): - self.config["zero"]["fields"] = ["comments", "month"] - item = self.add_item_fixture( comments="test comment", title="Title", @@ -31,8 +21,8 @@ def test_no_patterns(self): ) item.write() - self.load_plugins("zero") - item.write() + with self.configure_plugin({"fields": ["comments", "month"]}): + item.write() mf = MediaFile(syspath(item.path)) self.assertIsNone(mf.comments) @@ -41,76 +31,67 @@ def test_no_patterns(self): self.assertEqual(mf.year, 2000) def test_pattern_match(self): - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["comments"] = ["encoded by"] - item = self.add_item_fixture(comments="encoded by encoder") item.write() - self.load_plugins("zero") - item.write() + with self.configure_plugin( + {"fields": ["comments"], "comments": ["encoded by"]} + ): + item.write() mf = MediaFile(syspath(item.path)) self.assertIsNone(mf.comments) def test_pattern_nomatch(self): - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["comments"] = ["encoded by"] - item = self.add_item_fixture(comments="recorded at place") item.write() - self.load_plugins("zero") - item.write() + with self.configure_plugin( + {"fields": ["comments"], "comments": ["encoded_by"]} + ): + item.write() mf = MediaFile(syspath(item.path)) self.assertEqual(mf.comments, "recorded at place") def test_do_not_change_database(self): - self.config["zero"]["fields"] = ["year"] - item = self.add_item_fixture(year=2000) item.write() - self.load_plugins("zero") - item.write() + with self.configure_plugin({"fields": ["year"]}): + item.write() self.assertEqual(item["year"], 2000) def test_change_database(self): - self.config["zero"]["fields"] = ["year"] - self.config["zero"]["update_database"] = True - item = self.add_item_fixture(year=2000) item.write() - self.load_plugins("zero") - item.write() + with self.configure_plugin( + {"fields": ["year"], "update_database": True} + ): + item.write() self.assertEqual(item["year"], 0) def test_album_art(self): - self.config["zero"]["fields"] = ["images"] - path = self.create_mediafile_fixture(images=["jpg"]) item = Item.from_path(path) - self.load_plugins("zero") - item.write() + with self.configure_plugin({"fields": ["images"]}): + item.write() mf = MediaFile(syspath(path)) self.assertFalse(mf.images) def test_auto_false(self): - self.config["zero"]["fields"] = ["year"] - self.config["zero"]["update_database"] = True - self.config["zero"]["auto"] = False - item = self.add_item_fixture(year=2000) item.write() - self.load_plugins("zero") - item.write() + with self.configure_plugin( + {"fields": ["year"], "update_database": True, "auto": False} + ): + item.write() self.assertEqual(item["year"], 2000) @@ -120,12 +101,10 @@ def test_subcommand_update_database_true(self): ) item.write() item_id = item.id - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["update_database"] = True - self.config["zero"]["auto"] = False - self.load_plugins("zero") - with control_stdin("y"): + with self.configure_plugin( + {"fields": ["comments"], "update_database": True, "auto": False} + ), control_stdin("y"): self.run_command("zero") mf = MediaFile(syspath(item.path)) @@ -143,12 +122,9 @@ def test_subcommand_update_database_false(self): item.write() item_id = item.id - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["update_database"] = False - self.config["zero"]["auto"] = False - - self.load_plugins("zero") - with control_stdin("y"): + with self.configure_plugin( + {"fields": ["comments"], "update_database": False, "auto": False} + ), control_stdin("y"): self.run_command("zero") mf = MediaFile(syspath(item.path)) @@ -166,12 +142,10 @@ def test_subcommand_query_include(self): item.write() - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["update_database"] = False - self.config["zero"]["auto"] = False - - self.load_plugins("zero") - self.run_command("zero", "year: 2016") + with self.configure_plugin( + {"fields": ["comments"], "update_database": False, "auto": False} + ): + self.run_command("zero", "year: 2016") mf = MediaFile(syspath(item.path)) @@ -185,12 +159,10 @@ def test_subcommand_query_exclude(self): item.write() - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["update_database"] = False - self.config["zero"]["auto"] = False - - self.load_plugins("zero") - self.run_command("zero", "year: 0000") + with self.configure_plugin( + {"fields": ["comments"], "update_database": False, "auto": False} + ): + self.run_command("zero", "year: 0000") mf = MediaFile(syspath(item.path)) @@ -205,8 +177,7 @@ def test_no_fields(self): item_id = item.id - self.load_plugins("zero") - with control_stdin("y"): + with self.configure_plugin({"fields": []}), control_stdin("y"): self.run_command("zero") item = self.lib.get_item(item_id) @@ -221,11 +192,10 @@ def test_whitelist_and_blacklist(self): self.assertEqual(mf.year, 2016) item_id = item.id - self.config["zero"]["fields"] = ["year"] - self.config["zero"]["keep_fields"] = ["comments"] - self.load_plugins("zero") - with control_stdin("y"): + with self.configure_plugin( + {"fields": ["year"], "keep_fields": ["comments"]} + ), control_stdin("y"): self.run_command("zero") item = self.lib.get_item(item_id) @@ -235,18 +205,17 @@ def test_whitelist_and_blacklist(self): def test_keep_fields(self): item = self.add_item_fixture(year=2016, comments="test comment") - self.config["zero"]["keep_fields"] = ["year"] - self.config["zero"]["fields"] = None - self.config["zero"]["update_database"] = True - tags = { "comments": "test comment", "year": 2016, } - self.load_plugins("zero") - z = ZeroPlugin() - z.write_event(item, item.path, tags) + with self.configure_plugin( + {"fields": None, "keep_fields": ["year"], "update_database": True} + ): + z = ZeroPlugin() + z.write_event(item, item.path, tags) + self.assertIsNone(tags["comments"]) self.assertEqual(tags["year"], 2016) @@ -273,12 +242,9 @@ def test_empty_query_n_response_no_changes(self): ) item.write() item_id = item.id - self.config["zero"]["fields"] = ["comments"] - self.config["zero"]["update_database"] = True - self.config["zero"]["auto"] = False - - self.load_plugins("zero") - with control_stdin("n"): + with self.configure_plugin( + {"fields": ["comments"], "update_database": True, "auto": False} + ), control_stdin("n"): self.run_command("zero") mf = MediaFile(syspath(item.path)) diff --git a/test/test_importer.py b/test/test_importer.py index ac370a9c1b..80f3954224 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -1687,7 +1687,7 @@ def setUp(self): self.matcher = AutotagStub().install() self.io.install() - self.album_track_path, *_ = self.prepare_album_for_import(1) + self.album_track_path = self.prepare_album_for_import(1)[0] self.single_path = self.prepare_track_for_import(2, self.import_path) self.album_path = self.album_track_path.parent