mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
lastgenre: Test blacklist feature
- test blacklist patterns - test file format - test complex regex patterns - test invalid regex gets escaped
This commit is contained in:
parent
fb65d852c5
commit
5d333dca3b
1 changed files with 161 additions and 0 deletions
|
|
@ -14,12 +14,17 @@
|
|||
|
||||
"""Tests for the 'lastgenre' plugin."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from collections import defaultdict
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from beets.test import _common
|
||||
from beets.test.helper import BeetsTestCase
|
||||
from beets.ui import UserError
|
||||
from beetsplug import lastgenre
|
||||
|
||||
|
||||
|
|
@ -544,3 +549,159 @@ def test_get_genre(config_values, item_genre, mock_genres, expected_result):
|
|||
# Run
|
||||
res = plugin._get_genre(item)
|
||||
assert res == expected_result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"blacklist_dict, artist, genre, expected_forbidden",
|
||||
[
|
||||
# Global blacklist - simple word
|
||||
({"*": ["spoken word"]}, "Any Artist", "spoken word", True),
|
||||
({"*": ["spoken word"]}, "Any Artist", "jazz", False),
|
||||
# Global blacklist - regex pattern
|
||||
({"*": [".*electronic.*"]}, "Any Artist", "ambient electronic", True),
|
||||
({"*": [".*electronic.*"]}, "Any Artist", "jazz", False),
|
||||
# Artist-specific blacklist
|
||||
({"metallica": ["metal"]}, "Metallica", "metal", True),
|
||||
({"metallica": ["metal"]}, "Iron Maiden", "metal", False),
|
||||
# Case insensitive matching
|
||||
({"metallica": ["metal"]}, "METALLICA", "METAL", True),
|
||||
# Artist-specific blacklist - exact match
|
||||
({"metallica": ["^Heavy Metal$"]}, "Metallica", "classic metal", False),
|
||||
# Combined global and artist-specific
|
||||
(
|
||||
{"*": ["spoken word"], "metallica": ["metal"]},
|
||||
"Metallica",
|
||||
"spoken word",
|
||||
True,
|
||||
),
|
||||
(
|
||||
{"*": ["spoken word"], "metallica": ["metal"]},
|
||||
"Metallica",
|
||||
"metal",
|
||||
True,
|
||||
),
|
||||
# Complex regex pattern with multiple features (raw string)
|
||||
(
|
||||
{
|
||||
"fracture": [
|
||||
r"^(heavy|black|power|death)?\s?(metal|rock)$|\w+-metal\d*$"
|
||||
]
|
||||
},
|
||||
"Fracture",
|
||||
"power metal",
|
||||
True,
|
||||
),
|
||||
# Complex regex pattern with multiple features (regular string)
|
||||
(
|
||||
{"amon tobin": ["d(rum)?[ n/]*b(ass)?"]},
|
||||
"Amon Tobin",
|
||||
"dnb",
|
||||
True,
|
||||
),
|
||||
# Empty blacklist
|
||||
({}, "Any Artist", "any genre", False),
|
||||
],
|
||||
)
|
||||
def test_blacklist_patterns(blacklist_dict, artist, genre, expected_forbidden):
|
||||
"""Test blacklist pattern matching logic directly."""
|
||||
|
||||
# Initialize plugin
|
||||
plugin = lastgenre.LastGenrePlugin()
|
||||
|
||||
# Set up compiled blacklist directly (skipping file parsing)
|
||||
compiled_blacklist = defaultdict(list)
|
||||
for artist_name, patterns in blacklist_dict.items():
|
||||
compiled_blacklist[artist_name.lower()] = [
|
||||
re.compile(pattern) for pattern in patterns
|
||||
]
|
||||
|
||||
plugin.blacklist = compiled_blacklist
|
||||
|
||||
# Test the _is_forbidden method
|
||||
result = plugin._is_forbidden(genre, artist)
|
||||
assert result == expected_forbidden
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_content, expected_blacklist",
|
||||
[
|
||||
# Basic artist with pattern
|
||||
("metallica:\n metal", {"metallica": ["metal"]}),
|
||||
# Global blacklist
|
||||
("*:\n spoken word", {"*": ["spoken word"]}),
|
||||
# Multiple patterns per artist
|
||||
(
|
||||
"metallica:\n metal\n .*rock.*",
|
||||
{"metallica": ["metal", ".*rock.*"]},
|
||||
),
|
||||
# Comments and empty lines ignored
|
||||
(
|
||||
"# comment\n*:\n spoken word\n\nmetallica:\n metal",
|
||||
{"*": ["spoken word"], "metallica": ["metal"]},
|
||||
),
|
||||
# Case insensitive artist names
|
||||
("METALLICA:\n METAL", {"metallica": ["metal"]}),
|
||||
# Invalid regex pattern that gets escaped
|
||||
("artist:\n [invalid(regex", {"artist": ["\\[invalid\\(regex"]}),
|
||||
# Empty file
|
||||
("", {}),
|
||||
],
|
||||
)
|
||||
def test_blacklist_file_format(file_content, expected_blacklist):
|
||||
"""Test blacklist file format parsing."""
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".txt", delete=False, encoding="utf-8"
|
||||
) as f:
|
||||
f.write(file_content)
|
||||
blacklist_file = f.name
|
||||
|
||||
try:
|
||||
plugin = lastgenre.LastGenrePlugin()
|
||||
plugin.config["blacklist"] = blacklist_file
|
||||
blacklist_result = plugin._load_blacklist()
|
||||
|
||||
# Convert compiled regex patterns back to strings for comparison
|
||||
string_blacklist = {}
|
||||
for artist, compiled_patterns in blacklist_result.items():
|
||||
string_blacklist[artist] = [
|
||||
pattern.pattern for pattern in compiled_patterns
|
||||
]
|
||||
|
||||
assert string_blacklist == expected_blacklist
|
||||
|
||||
finally:
|
||||
os.unlink(blacklist_file)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_content, expected_error_message",
|
||||
[
|
||||
# Missing colon
|
||||
("metallica\n metal", "Malformed blacklist section header"),
|
||||
# Pattern before section
|
||||
(" metal\nmetallica:\n heavy metal", "before any section header"),
|
||||
# Unindented pattern
|
||||
("metallica:\nmetal", "Malformed blacklist section header"),
|
||||
],
|
||||
)
|
||||
def test_blacklist_file_format_errors(invalid_content, expected_error_message):
|
||||
"""Test blacklist file format error handling."""
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".txt", delete=False, encoding="utf-8"
|
||||
) as f:
|
||||
f.write(invalid_content)
|
||||
blacklist_file = f.name
|
||||
|
||||
try:
|
||||
plugin = lastgenre.LastGenrePlugin()
|
||||
plugin.config["blacklist"] = blacklist_file
|
||||
|
||||
with pytest.raises(UserError) as exc_info:
|
||||
plugin._load_blacklist()
|
||||
|
||||
assert expected_error_message in str(exc_info.value)
|
||||
|
||||
finally:
|
||||
os.unlink(blacklist_file)
|
||||
|
|
|
|||
Loading…
Reference in a new issue