beets/test/ui/commands/test_import.py
Šarūnas Nejus 2a003ac709
Refactor ShowChangeTest to use snapshot-style assertions
Replace multiple small tests with two comprehensive snapshot tests
covering the same edge cases and newline and column layouts.

Use BeetsTestCase to ensure that the local dev config is ignored.
2026-03-17 17:59:51 +00:00

185 lines
6.8 KiB
Python

import os
import unittest
from unittest.mock import Mock, patch
import pytest
from beets import autotag, config, library, ui
from beets.autotag.match import distance
from beets.test import _common
from beets.test.helper import BeetsTestCase, IOMixin
from beets.ui.commands.import_ import import_files, paths_from_logfile
from beets.ui.commands.import_.display import show_change
from beets.ui.commands.import_.session import summarize_items
class ImportTest(BeetsTestCase):
def test_quiet_timid_disallowed(self):
config["import"]["quiet"] = True
config["import"]["timid"] = True
with pytest.raises(ui.UserError):
import_files(None, [], None)
def test_parse_paths_from_logfile(self):
if os.path.__name__ == "ntpath":
logfile_content = (
"import started Wed Jun 15 23:08:26 2022\n"
"asis C:\\music\\Beatles, The\\The Beatles; C:\\music\\Beatles, The\\The Beatles\\CD 01; C:\\music\\Beatles, The\\The Beatles\\CD 02\n" # noqa: E501
"duplicate-replace C:\\music\\Bill Evans\\Trio '65\n"
"skip C:\\music\\Michael Jackson\\Bad\n"
"skip C:\\music\\Soulwax\\Any Minute Now\n"
)
expected_paths = [
"C:\\music\\Beatles, The\\The Beatles",
"C:\\music\\Michael Jackson\\Bad",
"C:\\music\\Soulwax\\Any Minute Now",
]
else:
logfile_content = (
"import started Wed Jun 15 23:08:26 2022\n"
"asis /music/Beatles, The/The Beatles; /music/Beatles, The/The Beatles/CD 01; /music/Beatles, The/The Beatles/CD 02\n" # noqa: E501
"duplicate-replace /music/Bill Evans/Trio '65\n"
"skip /music/Michael Jackson/Bad\n"
"skip /music/Soulwax/Any Minute Now\n"
)
expected_paths = [
"/music/Beatles, The/The Beatles",
"/music/Michael Jackson/Bad",
"/music/Soulwax/Any Minute Now",
]
logfile = os.path.join(self.temp_dir, b"logfile.log")
with open(logfile, mode="w") as fp:
fp.write(logfile_content)
actual_paths = list(paths_from_logfile(logfile))
assert actual_paths == expected_paths
@patch("beets.ui.term_width", Mock(return_value=54))
class ShowChangeTestCase(IOMixin, BeetsTestCase):
def _show_change(self):
"""Return an unicode string representing the changes"""
long_name = f"a{' very' * 10} long name"
items = [
_common.item(track=1, title="first title"),
_common.item(track=2, title="", path=b"/path/to/file.mp3"),
_common.item(track=3, title="caf\xe9"),
_common.item(track=4, title=f"title with {long_name}"),
]
info = autotag.AlbumInfo(
album="caf\xe9",
album_id="album id",
artist="the artist",
artist_id="artist id",
tracks=[
autotag.TrackInfo(title="first title", index=1),
autotag.TrackInfo(title="second title", index=2),
autotag.TrackInfo(title="third title", index=3),
autotag.TrackInfo(title="fourth title", index=4),
],
)
item_info_pairs = list(zip(items, info.tracks))
self.config["ui"]["color"] = False
self.config["import"]["detail"] = True
change_dist = distance(items, info, item_info_pairs)
change_dist._penalties = {"album": [0.1], "artist": [0.1]}
show_change(
f"another artist with {long_name}",
"another album",
autotag.AlbumMatch(
change_dist, info, dict(item_info_pairs), set(), set()
),
)
return self.io.getoutput()
def test_newline_layout(self):
self.config["ui"]["import"]["layout"] = "newline"
msg = self._show_change()
assert (
msg
== """
Match (90.0%):
the artist - café
≠ album, artist
None, None, None, None, None, None, None
≠ Artist: another artist with a very very very very
very very very very very very long name
-> the artist
≠ Album: another album -> café
* (#1) first title (1:00)
≠ (#2) file.mp3 (1:00)
-> (#2) second title (0:00)
≠ (#3) café (1:00) -> (#3) third title (0:00)
≠ (#4) title with a very very very very very very
very very very very long name (1:00)
-> (#4) fourth title (0:00)
"""
)
def test_column_layout(self):
self.config["ui"]["import"]["layout"] = "column"
msg = self._show_change()
assert (
msg
== """
Match (90.0%):
the artist - café
≠ album, artist
None, None, None, None, None, None, None
≠ Artist: another artist -> the artist
with a very
very very very
very very very
very very very
long name
≠ Album: another album -> café
* (#1) first title (1:00)
≠ (#2) file.mp (1:00) -> (#2) second (0:00)
3 title
≠ (#3) café (1:00) -> (#3) third title (0:00)
≠ (#4) title (1:00) -> (#4) fourth (0:00)
with a very title
very very very
very very very
very very very
long name
""" # noqa: W291
)
@patch("beets.library.Item.try_filesize", Mock(return_value=987))
class SummarizeItemsTest(unittest.TestCase):
def setUp(self):
super().setUp()
item = library.Item()
item.bitrate = 4321
item.length = 10 * 60 + 54
item.format = "F"
self.item = item
def test_summarize_item(self):
summary = summarize_items([], True)
assert summary == ""
summary = summarize_items([self.item], True)
assert summary == "F, 4kbps, 10:54, 987.0 B"
def test_summarize_items(self):
summary = summarize_items([], False)
assert summary == "0 items"
summary = summarize_items([self.item], False)
assert summary == "1 items, F, 4kbps, 10:54, 987.0 B"
# make a copy of self.item
i2 = self.item.copy()
summary = summarize_items([self.item, i2], False)
assert summary == "2 items, F, 4kbps, 21:48, 1.9 KiB"
i2.format = "G"
summary = summarize_items([self.item, i2], False)
assert summary == "2 items, F 1, G 1, 4kbps, 21:48, 1.9 KiB"
summary = summarize_items([self.item, i2, i2], False)
assert summary == "3 items, G 2, F 1, 4kbps, 32:42, 2.9 KiB"