From 4fcb148d602cb8378e26b1e044a43587133c33e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Thu, 13 Mar 2025 08:18:31 +0000 Subject: [PATCH] Add test for legalization logic --- test/test_library.py | 31 --------------- test/test_util.py | 92 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 43 deletions(-) diff --git a/test/test_library.py b/test/test_library.py index a4e6dab44..d90b9efd7 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -487,37 +487,6 @@ class DestinationTest(BeetsTestCase): self.i.path = "foo.mp3" assert self.i.destination() == np("base/one/_.mp3") - def test_legalize_path_one_for_one_replacement(self): - # Use a replacement that should always replace the last X in any - # path component with a Z. - self.lib.replacements = [ - (re.compile(r"X$"), "Z"), - ] - - # Construct an item whose untruncated path ends with a Y but whose - # truncated version ends with an X. - self.i.title = "X" * 300 + "Y" - - # The final path should reflect the replacement. - dest = self.i.destination() - assert dest[-2:] == b"XZ" - - def test_legalize_path_one_for_many_replacement(self): - # Use a replacement that should always replace the last X in any - # path component with four Zs. - self.lib.replacements = [ - (re.compile(r"X$"), "ZZZZ"), - ] - - # Construct an item whose untruncated path ends with a Y but whose - # truncated version ends with an X. - self.i.title = "X" * 300 + "Y" - - # The final path should ignore the user replacement and create a path - # of the correct length, containing Xs. - dest = self.i.destination() - assert dest[-2:] == b"XX" - def test_album_field_query(self): self.lib.directory = b"one" self.lib.path_formats = [("default", "two"), ("flex:foo", "three")] diff --git a/test/test_util.py b/test/test_util.py index a4b224ee3..b82ebed10 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -175,15 +175,83 @@ class PathConversionTest(BeetsTestCase): assert outpath == "C:\\caf\xe9".encode() -@patch("beets.util.get_max_filename_length", lambda: 5) -@pytest.mark.parametrize( - "path, expected", - [ - ("abcdeX/fgh", "abcde/fgh"), - ("abcde/fXX.ext", "abcde/f.ext"), - ("a🎹/a.ext", "a🎹/a.ext"), - ("ab🎹/a.ext", "ab/a.ext"), - ], -) -def test_truncate_path(path, expected): - assert util.truncate_path(path) == expected +class TestPathLegalization: + @pytest.fixture(autouse=True) + def _patch_max_filename_length(self, monkeypatch): + monkeypatch.setattr("beets.util.get_max_filename_length", lambda: 5) + + @pytest.mark.parametrize( + "path, expected", + [ + ("abcdeX/fgh", "abcde/fgh"), + ("abcde/fXX.ext", "abcde/f.ext"), + ("a🎹/a.ext", "a🎹/a.ext"), + ("ab🎹/a.ext", "ab/a.ext"), + ], + ) + def test_truncate(self, path, expected): + assert util.truncate_path(path) == expected + + @pytest.mark.parametrize( + "pre_trunc_repl, post_trunc_repl, expected", + [ + pytest.param( + [], + [], + ("_abcd", False), + id="default", + ), + pytest.param( + [(re.compile(r"abcdX$"), "PRE")], + [], + (":PRE", False), + id="valid path after initial repl", + ), + pytest.param( + [(re.compile(r"abcdX$"), "PRE_LONG")], + [], + (":PRE_", False), + id="too long path after initial repl is truncated", + ), + pytest.param( + [], + [(re.compile(r"abcdX$"), "POST")], + (":POST", False), + id="valid path after post-trunc repl", + ), + pytest.param( + [], + [(re.compile(r"abcdX$"), "POST_LONG")], + (":POST", False), + id="too long path after post-trunc repl is truncated", + ), + pytest.param( + [(re.compile(r"abcdX$"), "PRE")], + [(re.compile(r"PRE$"), "POST")], + (":POST", False), + id="both replacements within filename length limit", + ), + pytest.param( + [(re.compile(r"abcdX$"), "PRE_LONG")], + [(re.compile(r"PRE_$"), "POST")], + (":POST", False), + id="too long initial path is truncated and valid post-trunc repl", + ), + pytest.param( + [(re.compile(r"abcdX$"), "PRE")], + [(re.compile(r"PRE$"), "POST_LONG")], + (":POST", False), + id="valid pre-trunc repl and too long post-trunc path is truncated", + ), + pytest.param( + [(re.compile(r"abcdX$"), "PRE_LONG")], + [(re.compile(r"PRE_$"), "POST_LONG")], + ("_PRE_", True), + id="too long repl both times force default ones to be applied", + ), + ], + ) + def test_replacements(self, pre_trunc_repl, post_trunc_repl, expected): + replacements = pre_trunc_repl + post_trunc_repl + + assert util.legalize_path(":abcdX", replacements, "") == expected