Skip to content

Commit

Permalink
Move to pytest fixtures instead of unittest.TestCase
Browse files Browse the repository at this point in the history
  • Loading branch information
geigerzaehler committed Apr 1, 2024
1 parent a9bd552 commit e4461e5
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 89 deletions.
66 changes: 34 additions & 32 deletions test/cli_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import os.path
import shutil
from pathlib import Path

import pytest
from beets import util
Expand All @@ -24,13 +25,13 @@
)


class DocTest(TestHelper):
class TestDoc(TestHelper):
"""Test alternatives in a larger-scale scenario with transcoding and
multiple changes to the library.
"""

def test_external(self):
external_dir = os.path.join(self.mkdtemp(), "myplayer")
def test_external(self, tmp_path: Path):
external_dir = str(tmp_path / "myplayer")
self.config["convert"]["formats"] = {
"aac": {
"command": "bash -c \"cp '$source' '$dest';"
Expand Down Expand Up @@ -109,12 +110,12 @@ def test_external(self):
assert_file_tag(external_beet, b"ISAAC")


class SymlinkViewTest(TestHelper):
class TestSymlinkView(TestHelper):
"""Test alternatives with the ``link`` format producing symbolic links."""

def setUp(self):
super().setUp()
self.set_paths_config({"default": "$artist/$album/$title"})
@pytest.fixture(autouse=True)
def _symlink_view(self):
self.lib.path_formats = (("default", "$artist/$album/$title"),)
self.config["alternatives"] = {
"by-year": {
"paths": {"default": "$year/$album/$title"},
Expand Down Expand Up @@ -233,17 +234,16 @@ def test_valid_options(self):
self.runcli("alt", "update", "by-year")


class ExternalCopyTest(TestHelper):
class TestExternalCopy(TestHelper):
"""Test alternatives with empty ``format `` option, i.e. only copying
without transcoding.
"""

def setUp(self):
super().setUp()
external_dir = self.mkdtemp()
@pytest.fixture(autouse=True)
def _external_copy(self, tmp_path: Path, _setup: None):
self.config["alternatives"] = {
"myexternal": {
"directory": external_dir,
"directory": str(tmp_path),
"query": "myexternal:true",
}
}
Expand Down Expand Up @@ -375,7 +375,7 @@ def test_unkown_collection(self):
self.runcli("alt", "update", "unkown")
assert str(e.value) == "Alternative collection 'unkown' not found."

def test_embed_art(self):
def test_embed_art(self, tmp_path: Path):
"""Test that artwork is embedded and updated to match the source file.
There used to be a bug that meant that albumart was only embedded
Expand Down Expand Up @@ -409,8 +409,7 @@ def touch_art(item, image_path):

# Make a copy of the artwork, so that changing mtime/content won't
# affect the repository.
image_dir = bytestring_path(self.mkdtemp())
image_path = os.path.join(image_dir, b"image")
image_path = bytes(tmp_path / "image")
shutil.copy(self.IMAGE_FIXTURE1, check_type(syspath(image_path), bytes))
touch_art(item, image_path)

Expand All @@ -432,9 +431,13 @@ def touch_art(item, image_path):
item = album.items().get()
assert_has_embedded_artwork(self.get_path(item), self.IMAGE_FIXTURE2)

def test_update_all(self):
dir_a = self.mkdtemp()
dir_b = self.mkdtemp()
def test_update_all(self, tmp_path: Path):
dir_a = tmp_path / "a"
dir_a.mkdir()
dir_a = str(dir_a)
dir_b = tmp_path / "b"
dir_b.mkdir()
dir_b = str(dir_b)
self.config["alternatives"].get().clear() # type: ignore
self.config["alternatives"] = {
"a": {
Expand Down Expand Up @@ -468,14 +471,14 @@ def test_update_all(self):
assert self.runcli("alt", "update", "--all") == ""


class ExternalConvertTest(TestHelper):
class TestExternalConvert(TestHelper):
"""Test alternatives with non-empty ``format`` option, i.e. transcoding
some of the files.
"""

def setUp(self):
super().setUp()
external_dir = self.mkdtemp()
@pytest.fixture(autouse=True)
def _external_convert(self, tmp_path: Path, _setup: None):
external_dir = str(tmp_path)
self.config["convert"]["formats"] = {
"ogg": "bash -c \"cp '$source' '$dest';" + "printf ISOGG >> '$dest'\""
}
Expand Down Expand Up @@ -555,15 +558,15 @@ def test_no_move_on_extension_change(self):
assert_file_tag(converted_path, b"ISMP3")


class ExternalConvertWorkerTest(TestHelper):
class TestExternalConvertWorker(TestHelper):
"""Test alternatives with non-empty ``format`` option, i.e. transcoding
some of the files. In contrast to the previous test, these test do use
the parallelizing ``beetsplug.alternatives.Worker``.
"""

def setUp(self):
super().setUp(mock_worker=False)
external_dir = self.mkdtemp()
def test_convert_multiple(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
monkeypatch.undo()
external_dir = str(tmp_path)
self.config["convert"]["formats"] = {
"ogg": "bash -c \"cp '{source}' '$dest'\"".format(
# The convert plugin will encode this again using arg_encoding
Expand All @@ -578,7 +581,6 @@ def setUp(self):
}
}

def test_convert_multiple(self):
items = [
self.add_track(
title=f"track {i}",
Expand All @@ -594,14 +596,14 @@ def test_convert_multiple(self):
assert_media_file_fields(converted_path, type="ogg", title=item.title)


class ExternalRemovableTest(TestHelper):
class TestExternalRemovable(TestHelper):
"""Test whether alternatives properly detects ``removable`` collections
and performs the expected user queries before doing anything.
"""

def setUp(self):
super().setUp()
external_dir = os.path.join(self.mkdtemp(), "\u00e9xt")
@pytest.fixture(autouse=True)
def _external_removable(self, tmp_path: Path, _setup: None):
external_dir = str(tmp_path / "\u00e9xt")
self.config["alternatives"] = {
"myexternal": {
"directory": external_dir,
Expand Down Expand Up @@ -648,7 +650,7 @@ def test_not_removable(self):
assert "alt.myexternal" in item


class CompletionTest(TestHelper):
class TestCompletion(TestHelper):
"""Test invocation of ``beet completion`` with this plugin.
Only ensures that command does not fail.
Expand Down
70 changes: 13 additions & 57 deletions test/helper.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import os
import shutil
import sys
import tempfile
from concurrent import futures
from contextlib import contextmanager
from io import StringIO
from pathlib import Path
from typing import Optional
from unittest import TestCase
from unittest.mock import patch
from zlib import crc32

import beets
import beets.library
import pytest
from beets import logging, plugins, ui, util
from beets.library import Item
from beets.util import MoveOperation, bytestring_path, displayable_path, syspath
Expand All @@ -20,7 +18,10 @@
import beetsplug.alternatives as alternatives
import beetsplug.convert as convert

logging.getLogger("beets").propagate = True
beetsLogger = logging.getLogger("beets")
beetsLogger.propagate = True
for h in beetsLogger.handlers:
beetsLogger.removeHandler(h)


@contextmanager
Expand Down Expand Up @@ -139,41 +140,12 @@ def assert_media_file_fields(path, **kwargs):
assert actual == v, f"MediaFile has tag {k}='{actual}' " f"instead of '{v}'"


class TestHelper(TestCase):
def setUp(self, mock_worker=True):
"""Setup required for running test. Must be called before
running any tests.
class TestHelper:
@pytest.fixture(autouse=True)
def _setup(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr("beetsplug.alternatives.Worker", MockedWorker)

If ``mock_worker`` is ``True`` the simple non-threaded
``MockedWorker`` is used to run file conversion commands. In
particular, in contrast to the actual conversion routine from the
``convert`` plugin, it will not attempt to write tags to the output
files. Thus, the 'converted' files need not be valid audio files.
"""
if mock_worker:
patcher = patch("beetsplug.alternatives.Worker", new=MockedWorker)
patcher.start()
self.addCleanup(patcher.stop)

self._tempdirs = []
plugins._classes = {alternatives.AlternativesPlugin, convert.ConvertPlugin}
self.setup_beets()

def tearDown(self):
self.unload_plugins()
for tempdir in self._tempdirs:
shutil.rmtree(syspath(tempdir))

def mkdtemp(self):
# This return a str path, i.e. Unicode on Python 3. We need this in
# order to put paths into the configuration.
path = tempfile.mkdtemp()
self._tempdirs.append(path)
return path

def setup_beets(self):
self.addCleanup(self.teardown_beets)
os.environ["BEETSDIR"] = self.mkdtemp()

self.config = beets.config
self.config.clear()
Expand All @@ -185,7 +157,8 @@ def setup_beets(self):
self.config["threaded"] = False
self.config["import"]["copy"] = False

libdir = self.mkdtemp()
libdir = str(tmp_path / "beets_lib")
os.environ["BEETSDIR"] = libdir
self.config["directory"] = libdir
self.libdir = bytestring_path(libdir)

Expand All @@ -199,18 +172,7 @@ def setup_beets(self):

self.IMAGE_FIXTURE1 = os.path.join(self.fixture_dir, b"image.png")
self.IMAGE_FIXTURE2 = os.path.join(self.fixture_dir, b"image_black.png")

def teardown_beets(self):
del self.lib._connections
if "BEETSDIR" in os.environ:
del os.environ["BEETSDIR"]
self.config.clear()
beets.config.read(user=False, defaults=True)

def set_paths_config(self, conf):
self.lib.path_formats = conf.items()

def unload_plugins(self):
yield
for plugin in plugins._classes:
plugin.listeners = None
plugins._classes = set()
Expand Down Expand Up @@ -294,12 +256,6 @@ def submit(self, *args, **kwargs):
fut = futures.Future()
res = self._fn(*args, **kwargs)
fut.set_result(res)
# try:
# res = fn(*args, **kwargs)
# except Exception as e:
# fut.set_exception(e)
# else:
# fut.set_result(res)
self._tasks.add(fut)
return fut

Expand Down

0 comments on commit e4461e5

Please sign in to comment.