discogs: refactor and clean up tests (#6817)

- **What changed**
- Simplifies `DiscogsPlugin.get_album_info` by removing a redundant
"required fields" guard and relying on the plugin's normal parsing flow
instead.
- Reworks `test/plugins/test_discogs.py` around shared fixtures and
helpers, including a common `DiscogsTestMixin`, reusable
`plugin`/`plugin_config` fixtures, and a global patch for
`DiscogsPlugin.setup`.
- Expands and consolidates coverage for tracklist parsing, especially
`_coalesce_tracks`-related behavior, `index_tracks`, grouped/sub-tracks,
inherited artists, medium titles, and disambiguation handling.

- **Architecture impact**
- Test structure is now more modular and configuration-driven: scenarios
pass settings through `plugin_config` instead of mutating global state
inline.
- Discogs test data now uses real `discogs_client.Release` objects via
`get_release(...)` instead of the custom `Bag` stub, making tests closer
to production behavior.
- Repeated one-off tests were collapsed into parametrized suites, so
tracklist behavior lives in one place and is easier to extend.
This commit is contained in:
Šarūnas Nejus
2026-07-16 11:56:47 +01:00
committed by GitHub
4 changed files with 262 additions and 309 deletions

View File

@@ -237,3 +237,5 @@ ca8e9f69a8a0254aa767dc86f6d808d02f6af05d
b1701c2e12b2de8e5462affe46ecc6816a5fc508
# typing: type beets.dbcore.types
ea3d6af6169d33be009b86bf5607baae7cf9652a
# Fix #6177, remove derived types, refactor coalesce tracks
9efe87101ce03706660129633e03147a222765cf

View File

@@ -167,19 +167,6 @@ def touch(path):
open(syspath(path), "a").close()
class Bag:
"""An object that exposes a set of fields given as keyword
arguments. Any field not found in the dictionary appears to be None.
Used for mocking Album objects and the like.
"""
def __init__(self, **fields):
self.fields = fields
def __getattr__(self, key):
return self.fields.get(key)
# Platform mocking.

View File

@@ -345,20 +345,6 @@ class DiscogsPlugin(SearchApiMetadataSourcePlugin[IDResponse]):
)
return None
# Sanity check for required fields. The list of required fields is
# defined at Guideline 1.3.1.a, but in practice some releases might be
# lacking some of these fields. This function expects at least:
# `artists` (>0), `title`, `id`, `tracklist` (>0)
# https://www.discogs.com/help/doc/submission-guidelines-general-rules
if not all(
[
result.data.get(k)
for k in ["artists", "title", "id", "tracklist"]
]
):
self._log.warning("Release does not contain the required fields")
return None
artist_data = [a.data for a in result.artists]
# Information for the album artist
albumartist = ArtistState.from_config(

View File

@@ -1,15 +1,17 @@
"""Tests for discogs plugin."""
from unittest.mock import Mock, patch
from typing import Any
import pytest
from discogs_client import Client, Release
from beets import config
from beets.library import Item
from beets.test._common import Bag
from beets.test.helper import TestHelper
from beetsplug.discogs import ArtistState, DiscogsPlugin
_p = pytest.param
def _artist(name: str, **kwargs):
return {
@@ -23,17 +25,49 @@ def _artist(name: str, **kwargs):
} | kwargs
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
class TestDGAlbumInfo(TestHelper):
def _track(title: str, position: str = "", duration: str = "", **kwargs):
return {
"title": title,
"position": position,
"duration": duration,
"type_": "track",
} | kwargs
def get_release(data: dict[str, Any]) -> Release:
return Release(Client("doesn't matter"), data)
@pytest.fixture(autouse=True)
def _patch_discogs_setup(monkeypatch):
"""Autouse fixture to patch DiscogsPlugin.setup for each test."""
monkeypatch.setattr(
"beetsplug.discogs.DiscogsPlugin.setup", lambda *_: None
)
class DiscogsTestMixin:
@pytest.fixture
def plugin_config(self):
return {}
@pytest.fixture
def plugin(self, plugin_config):
plugin = DiscogsPlugin()
plugin.config.set(plugin_config)
return plugin
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
those required for the tests on this class."""
"""Return discogs_client.Release.
The returned object is incomplete, including just the fields required
for tests in this module.
"""
data = {
"id": "ALBUM ID",
"uri": "https://www.discogs.com/release/release/13633721",
"id": 11111111,
"uri": "https://www.discogs.com/release/111111111",
"title": "ALBUM TITLE",
"year": "3001",
"year": 3001,
"artists": [_artist("ARTIST NAME", join=",")],
"formats": [
{
@@ -46,42 +80,25 @@ class TestDGAlbumInfo(TestHelper):
"genres": ["STYLE1", "STYLE2"],
"styles": ["GENRE1", "GENRE2"],
"labels": [{"name": "LABEL NAME", "catno": "CATALOG NUMBER"}],
"tracklist": [],
"tracklist": tracks or [],
}
if tracks:
for recording in tracks:
data["tracklist"].append(recording)
return Bag(
data=data,
# Make some fields available as properties, as they are
# accessed by DiscogsPlugin methods.
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
def _make_track(self, title, position="", duration="", type_=None):
return {
"title": title,
"position": position,
"duration": duration,
"type_": type_,
}
return get_release(data)
def _make_release_from_positions(self, positions):
"""Return a Bag that mimics a discogs_client.Release with a
tracklist where tracks have the specified `positions`."""
"""Return discogs_client.Release with tracks at the given positions."""
tracks = [
self._make_track(f"TITLE{i}", position)
_track(f"TITLE{i}", position)
for (i, position) in enumerate(positions, start=1)
]
return self._make_release(tracks)
class TestDGAlbumInfo(DiscogsTestMixin, TestHelper):
def test_parse_media_for_tracks(self):
tracks = [
self._make_track("TITLE ONE", "1", "01:01"),
self._make_track("TITLE TWO", "2", "02:02"),
_track("TITLE ONE", "1", "01:01"),
_track("TITLE TWO", "2", "02:02"),
]
release = self._make_release(tracks=tracks)
@@ -162,184 +179,21 @@ class TestDGAlbumInfo(TestHelper):
assert t[3].index == 4
assert t[3].medium_total == 1
def test_parse_tracklist_without_sides(self):
"""Test standard Discogs position 12.2.9#1: "without sides"."""
release = self._make_release_from_positions(["1", "2", "3"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
def test_parse_tracklist_with_sides(self):
"""Test standard Discogs position 12.2.9#2: "with sides"."""
release = self._make_release_from_positions(["A1", "A2", "B1", "B2"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1 # 2 sides = 1 LP
assert len(d.tracks) == 4
def test_parse_tracklist_multiple_lp(self):
"""Test standard Discogs position 12.2.9#3: "multiple LP"."""
release = self._make_release_from_positions(["A1", "A2", "B1", "C1"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 2 # 3 sides = 1 LP + 1 LP
assert len(d.tracks) == 4
def test_parse_tracklist_multiple_cd(self):
"""Test standard Discogs position 12.2.9#4: "multiple CDs"."""
release = self._make_release_from_positions(
["1-1", "1-2", "2-1", "3-1"]
)
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 3
assert len(d.tracks) == 4
def test_parse_tracklist_non_standard(self):
"""Test non standard Discogs position."""
release = self._make_release_from_positions(["I", "II", "III", "IV"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 4
def test_parse_tracklist_subtracks_dot(self):
"""Test standard Discogs position 12.2.9#5: "sub tracks, dots"."""
release = self._make_release_from_positions(["1", "2.1", "2.2", "3"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
release = self._make_release_from_positions(
["A1", "A2.1", "A2.2", "A3"]
)
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
def test_parse_tracklist_subtracks_letter(self):
"""Test standard Discogs position 12.2.9#5: "sub tracks, letter"."""
release = self._make_release_from_positions(["A1", "A2a", "A2b", "A3"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
release = self._make_release_from_positions(
["A1", "A2.a", "A2.b", "A3"]
)
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
def test_parse_tracklist_subtracks_extra_material(self):
"""Test standard Discogs position 12.2.9#6: "extra material"."""
release = self._make_release_from_positions(["1", "2", "Video 1"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 2
assert len(d.tracks) == 3
def test_parse_tracklist_subtracks_indices(self):
"""Test parsing of subtracks that include index tracks."""
release = self._make_release_from_positions(["", "", "1.1", "1.2"])
# Track 1: Index track with medium title
release.data["tracklist"][0]["title"] = "MEDIUM TITLE"
# Track 2: Index track with track group title
release.data["tracklist"][1]["title"] = "TRACK GROUP TITLE"
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert d.tracks[0].disctitle == "MEDIUM TITLE"
assert len(d.tracks) == 1
assert d.tracks[0].title == "TRACK GROUP TITLE"
def test_parse_tracklist_subtracks_nested_logical(self):
"""Test parsing of subtracks defined inside a index track that are
logical subtracks (ie. should be grouped together into a single track).
"""
release = self._make_release_from_positions(["1", "", "3"])
# Track 2: Index track with track group title, and sub_tracks
release.data["tracklist"][1]["title"] = "TRACK GROUP TITLE"
release.data["tracklist"][1]["sub_tracks"] = [
self._make_track("TITLE ONE", "2.1", "01:01"),
self._make_track("TITLE TWO", "2.2", "02:02"),
]
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
assert d.tracks[1].title == "TRACK GROUP TITLE"
def test_parse_tracklist_subtracks_nested_physical(self):
"""Test parsing of subtracks defined inside a index track that are
physical subtracks (ie. should not be grouped together).
"""
release = self._make_release_from_positions(["1", "", "4"])
# Track 2: Index track with track group title, and sub_tracks
release.data["tracklist"][1]["title"] = "TRACK GROUP TITLE"
release.data["tracklist"][1]["sub_tracks"] = [
self._make_track("TITLE ONE", "2", "01:01"),
self._make_track("TITLE TWO", "3", "02:02"),
]
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 4
assert d.tracks[1].title == "TITLE ONE"
assert d.tracks[2].title == "TITLE TWO"
def test_parse_tracklist_disctitles(self):
"""Test parsing of index tracks that act as disc titles."""
release = self._make_release_from_positions(
["", "1-1", "1-2", "", "2-1"]
)
# Track 1: Index track with medium title (Cd1)
release.data["tracklist"][0]["title"] = "MEDIUM TITLE CD1"
# Track 4: Index track with medium title (Cd2)
release.data["tracklist"][3]["title"] = "MEDIUM TITLE CD2"
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 2
assert d.tracks[0].disctitle == "MEDIUM TITLE CD1"
assert d.tracks[1].disctitle == "MEDIUM TITLE CD1"
assert d.tracks[2].disctitle == "MEDIUM TITLE CD2"
assert len(d.tracks) == 3
def test_parse_minimal_release(self):
"""Test parsing of a release with the minimal amount of information."""
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [self._make_track("A", "1", "01:01")],
"tracklist": [_track("A", "1", "01:01")],
"artists": [_artist("ARTIST NAME", id=321)],
"title": "TITLE",
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
release = get_release(data)
d = DiscogsPlugin().get_album_info(release)
assert d.artist == "ARTIST NAME"
assert d.album == "TITLE"
assert len(d.tracks) == 1
def test_parse_release_without_required_fields(self, caplog):
"""Test parsing of a release that does not have the required fields."""
release = Bag(data={}, refresh=lambda *args: None)
with caplog.at_level("DEBUG"):
d = DiscogsPlugin().get_album_info(release)
assert d is None
assert (
"Release does not contain the required fields" in caplog.messages[0]
)
def test_default_genre_style_settings(self):
"""Test genre default settings, genres to genre, styles to style"""
release = self._make_release_from_positions(["1", "2"])
@@ -367,79 +221,215 @@ class TestDGAlbumInfo(TestHelper):
assert d.style is None
assert d.genres == ["GENRE1", "GENRE2"]
def test_strip_disambiguation(self):
class TestStripDisambiguation(DiscogsTestMixin):
@pytest.fixture
def album_info(self, plugin):
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
"artists": [_artist("TEST ARTIST (5)", id=11146)],
}
],
"artists": [
_artist("ARTIST NAME (2)", id=321, join="&"),
_artist("OTHER ARTIST (5)", id=322),
],
"title": "title",
"labels": [{"name": "LABEL NAME (5)", "catno": "catalog number"}],
}
return plugin.get_album_info(get_release(data))
@pytest.mark.parametrize("plugin_config", [{"strip_disambiguation": True}])
def test_strip_disambiguation(self, album_info):
"""Test removing disambiguation from all disambiguated fields."""
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
"artists": [_artist("TEST ARTIST (5)", id=11146)],
}
],
"artists": [
_artist("ARTIST NAME (2)", id=321, join="&"),
_artist("OTHER ARTIST (5)", id=322),
],
"title": "title",
"labels": [{"name": "LABEL NAME (5)", "catno": "catalog number"}],
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
d = DiscogsPlugin().get_album_info(release)
assert d.artist == "ARTIST NAME & OTHER ARTIST"
assert d.artists == ["ARTIST NAME", "OTHER ARTIST"]
assert d.artists_ids == ["321", "322"]
assert d.tracks[0].artist == "TEST ARTIST"
assert d.tracks[0].artists == ["TEST ARTIST"]
assert d.tracks[0].artist_id == "11146"
assert d.tracks[0].artists_ids == ["11146"]
assert d.label == "LABEL NAME"
assert album_info.artist == "ARTIST NAME & OTHER ARTIST"
assert album_info.artists == ["ARTIST NAME", "OTHER ARTIST"]
assert album_info.artists_ids == ["321", "322"]
assert album_info.tracks[0].artist == "TEST ARTIST"
assert album_info.tracks[0].artists == ["TEST ARTIST"]
assert album_info.tracks[0].artist_id == "11146"
assert album_info.tracks[0].artists_ids == ["11146"]
assert album_info.label == "LABEL NAME"
def test_strip_disambiguation_false(self):
@pytest.mark.parametrize("plugin_config", [{"strip_disambiguation": False}])
def test_dont_strip_disambiguation(self, album_info):
"""Test disabling disambiguation removal from all disambiguated fields."""
config["discogs"]["strip_disambiguation"] = False
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
"artists": [_artist("TEST ARTIST (5)", id=11146)],
}
],
"artists": [
_artist("ARTIST NAME (2)", id=321, join="&"),
_artist("OTHER ARTIST (5)", id=322),
],
"title": "title",
"labels": [{"name": "LABEL NAME (5)", "catno": "catalog number"}],
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
d = DiscogsPlugin().get_album_info(release)
assert d.artist == "ARTIST NAME (2) & OTHER ARTIST (5)"
assert d.artists == ["ARTIST NAME (2)", "OTHER ARTIST (5)"]
assert d.tracks[0].artist == "TEST ARTIST (5)"
assert d.tracks[0].artists == ["TEST ARTIST (5)"]
assert d.label == "LABEL NAME (5)"
config["discogs"]["strip_disambiguation"] = True
assert album_info.artist == "ARTIST NAME (2) & OTHER ARTIST (5)"
assert album_info.artists == ["ARTIST NAME (2)", "OTHER ARTIST (5)"]
assert album_info.tracks[0].artist == "TEST ARTIST (5)"
assert album_info.tracks[0].artists == ["TEST ARTIST (5)"]
assert album_info.label == "LABEL NAME (5)"
class TestTracklist(DiscogsTestMixin):
@pytest.mark.parametrize(
"positions,expected_mediums,expected_tracks",
[
_p(["1", "2", "3"], 1, 3, id="without-sides"),
_p(["A1", "A2", "B1", "B2"], 1, 4, id="with-sides"),
_p(["A1", "A2", "B1", "C1"], 2, 4, id="multiple-lp"),
_p(["1-1", "1-2", "2-1", "3-1"], 3, 4, id="multiple-cd"),
_p(["I", "II", "III", "IV"], 1, 4, id="non-standard"),
_p(["1", "2.1", "2.2", "3"], 1, 3, id="subtracks-dot"),
_p(["A1", "A2.1", "A2.2", "A3"], 1, 3, id="subtracks-dot-with-sides"),
_p(["A1", "A2a", "A2b", "A3"], 1, 3, id="subtracks-letter"),
_p(["A1", "A2.a", "A2.b", "A3"], 1, 3, id="subtracks-letter-with-dot"),
_p(["1.1", "1.2", "2.1", "2.2"], 1, 2, id="multiple-subtrack-groups"),
_p(["1", "2", "Video 1"], 2, 3, id="subtracks-extra-material"),
],
) # fmt: skip
def test_parse_tracklist_positions(
self, plugin, positions, expected_mediums, expected_tracks
):
release = self._make_release_from_positions(positions)
d = plugin.get_album_info(release)
assert d.mediums == expected_mediums
assert len(d.tracks) == expected_tracks
@pytest.mark.parametrize(
"plugin_config,tracks,expected_mediums,expected_tracks",
[
_p(
{"index_tracks": False},
[
_track("MEDIUM TITLE"),
_track("TRACK GROUP TITLE"),
_track("TITLE ONE", "1.1"),
_track("TITLE TWO", "1.2"),
],
1,
[("TRACK GROUP TITLE", "MEDIUM TITLE")],
id="flat-logical-subtracks",
),
_p(
{"index_tracks": False},
[
_track("TITLE ONE", "1"),
_track(
"TRACK GROUP TITLE",
sub_tracks=[
_track("SUBTITLE ONE", "2.1", "01:01"),
_track("SUBTITLE TWO", "2.2", "02:02"),
],
),
_track("TITLE THREE", "3"),
],
1,
[
("TITLE ONE", None),
("TRACK GROUP TITLE", None),
("TITLE THREE", None),
],
id="nested-logical-subtracks",
),
_p(
{"index_tracks": False},
[
_track("TITLE ONE", "1"),
_track(
"TRACK GROUP TITLE",
sub_tracks=[
_track("SUBTITLE ONE", "2", "01:01"),
_track("SUBTITLE TWO", "3", "02:02"),
],
),
_track("TITLE FOUR", "4"),
],
1,
[
("TITLE ONE", None),
("SUBTITLE ONE", None),
("SUBTITLE TWO", None),
("TITLE FOUR", None),
],
id="nested-physical-subtracks",
),
_p(
{"index_tracks": True},
[
_track("TITLE ONE", "1"),
_track(
"TRACK GROUP TITLE",
sub_tracks=[
_track("SUBTITLE ONE", "2", "01:01"),
_track("SUBTITLE TWO", "3", "02:02"),
],
),
_track("TITLE FOUR", "4"),
],
1,
[
("TITLE ONE", None),
("TRACK GROUP TITLE: SUBTITLE ONE", None),
("TRACK GROUP TITLE: SUBTITLE TWO", None),
("TITLE FOUR", None),
],
id="nested-physical-subtracks-with-index-tracks",
),
_p(
{"index_tracks": False},
[
_track("MEDIUM TITLE CD1"),
_track("TITLE ONE", "1-1"),
_track("TITLE TWO", "1-2"),
_track("MEDIUM TITLE CD2"),
_track("TITLE THREE", "2-1"),
],
2,
[
("TITLE ONE", "MEDIUM TITLE CD1"),
("TITLE TWO", "MEDIUM TITLE CD1"),
("TITLE THREE", "MEDIUM TITLE CD2"),
],
id="medium-titles",
),
],
) # fmt: skip
def test_parse_tracklist_index_tracks(
self, plugin, tracks, expected_mediums, expected_tracks
):
release = self._make_release(tracks)
album = plugin.get_album_info(release)
assert album.mediums == expected_mediums
assert [(t.title, t.disctitle) for t in album.tracks] == expected_tracks
def test_parse_tracklist_inherited_artists(self, plugin):
"""Verify grouped tracks combine explicit and inherited artist credits.
This covers releases where a track group provides the default artist for
sub-tracks that do not declare one themselves.
Note: this is based on the following release:
https://www.discogs.com/release/3647530
"""
track_artist = "TRACK ARTIST"
group_artist = "GROUP ARTIST"
tracks = [
_track(
"TRACK GROUP TITLE",
artists=[_artist(group_artist)],
sub_tracks=[
_track("TRACK ONE", "2", artists=[_artist(track_artist)]),
_track("SUBTITLE TWO", "3"),
],
)
]
release = self._make_release(tracks)
album = plugin.get_album_info(release)
assert album.mediums == 1
assert {t.artist for t in album.tracks} == {track_artist, group_artist}
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
class TestDGSearchQuery(TestHelper):
def test_default_search_filters_without_extra_tags(self):
"""Discogs search uses only the type filter when no extra_tags are set."""
@@ -506,11 +496,7 @@ class TestAnv:
],
"title": "title",
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
release = get_release(data)
plugin = DiscogsPlugin()
plugin.config["anv"].set(
{"artist": False, "album_artist": False, "artist_credit": False}
@@ -601,7 +587,6 @@ class TestAnv:
self._assert_fields(album_info, expected_album_fields)
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_anv_album_artist():
"""Test using artist name variations when the album artist
is the same as the track artist, but only the track artist
@@ -620,11 +605,7 @@ def test_anv_album_artist():
"artists": [_artist("ARTIST (4)", id=321, anv="VARIATION")],
"title": "title",
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
release = get_release(data)
config["discogs"]["anv"]["album_artist"] = False
config["discogs"]["anv"]["artist"] = True
config["discogs"]["anv"]["artist_credit"] = False
@@ -640,7 +621,6 @@ def test_anv_album_artist():
assert r.tracks[0].artists_credit == ["ARTIST"]
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_parse_featured_artists():
"""Tests the plugins ability to parse a featured artist.
Ignores artists that are not listed as featured."""
@@ -678,7 +658,6 @@ def test_parse_featured_artists():
assert t.composers == ["RANDOM"]
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_parse_extraartist_roles():
plugin = DiscogsPlugin()
artistinfo = ArtistState.from_config(plugin.config, [_artist("ARTIST")])
@@ -729,7 +708,6 @@ def test_get_media_and_albumtype(formats, expected_media, expected_albumtype):
assert result == (expected_media, expected_albumtype)
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_va_buildartistinfo():
config["va_name"] = "VARIOUS ARTISTS"
expected_info = {