mirror of
https://github.com/shadoll/moma.git
synced 2026-08-28 11:33:25 +00:00
chore: Bump version to 0.6.1 and update decorators to use new cache system
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
"""Tests for formatter decorators."""
|
||||
|
||||
import pytest
|
||||
from renamer.formatters import (
|
||||
date_decorators,
|
||||
special_info_decorators,
|
||||
text_decorators,
|
||||
conditional_decorators
|
||||
)
|
||||
|
||||
|
||||
class TestDateDecorators:
|
||||
"""Test date formatting decorators."""
|
||||
|
||||
def test_modification_date_decorator(self):
|
||||
"""Test @date_decorators.modification_date() decorator."""
|
||||
class TestClass:
|
||||
def __init__(self, mtime):
|
||||
self.mtime = mtime
|
||||
|
||||
@date_decorators.modification_date()
|
||||
def get_mtime(self):
|
||||
return self.mtime
|
||||
|
||||
# Test with a known timestamp (2020-01-01 00:00:00 UTC)
|
||||
obj = TestClass(1577836800.0)
|
||||
result = obj.get_mtime()
|
||||
assert "2020-01-01" in result # Date part should be present
|
||||
|
||||
|
||||
class TestSpecialInfoDecorators:
|
||||
"""Test special info formatting decorators."""
|
||||
|
||||
def test_special_info_decorator(self):
|
||||
"""Test @special_info_decorators.special_info() decorator."""
|
||||
class TestClass:
|
||||
def __init__(self, special_info):
|
||||
self.special_info = special_info
|
||||
|
||||
@special_info_decorators.special_info()
|
||||
def get_special_info(self):
|
||||
return self.special_info
|
||||
|
||||
obj = TestClass(["Director's Cut", "Extended Edition"])
|
||||
assert obj.get_special_info() == "Director's Cut, Extended Edition"
|
||||
|
||||
obj_none = TestClass(None)
|
||||
assert obj_none.get_special_info() == ""
|
||||
|
||||
def test_database_info_decorator(self):
|
||||
"""Test @special_info_decorators.database_info() decorator."""
|
||||
class TestClass:
|
||||
def __init__(self, db_info):
|
||||
self.db_info = db_info
|
||||
|
||||
@special_info_decorators.database_info()
|
||||
def get_db_info(self):
|
||||
return self.db_info
|
||||
|
||||
obj = TestClass(["tmdb", "12345"])
|
||||
assert obj.get_db_info() == "tmdbid-12345"
|
||||
|
||||
obj_dict = TestClass({"name": "imdb", "id": "tt1234567"})
|
||||
assert obj_dict.get_db_info() == "imdbid-tt1234567"
|
||||
|
||||
|
||||
class TestTextDecorators:
|
||||
"""Test text formatting decorators."""
|
||||
|
||||
def test_bold_decorator(self):
|
||||
"""Test @text_decorators.bold() decorator."""
|
||||
class TestClass:
|
||||
@text_decorators.bold()
|
||||
def get_text(self):
|
||||
return "Hello"
|
||||
|
||||
obj = TestClass()
|
||||
assert obj.get_text() == "[bold]Hello[/bold]"
|
||||
|
||||
def test_green_decorator(self):
|
||||
"""Test @text_decorators.green() decorator."""
|
||||
class TestClass:
|
||||
@text_decorators.green()
|
||||
def get_text(self):
|
||||
return "Success"
|
||||
|
||||
obj = TestClass()
|
||||
assert obj.get_text() == "[green]Success[/green]"
|
||||
|
||||
|
||||
class TestConditionalDecorators:
|
||||
"""Test conditional formatting decorators."""
|
||||
|
||||
def test_wrap_decorator_both_sides(self):
|
||||
"""Test @conditional_decorators.wrap() with both left and right."""
|
||||
class TestClass:
|
||||
def __init__(self, order):
|
||||
self.order = order
|
||||
|
||||
@conditional_decorators.wrap("[", "] ")
|
||||
def get_order(self):
|
||||
return self.order
|
||||
|
||||
obj = TestClass("01")
|
||||
assert obj.get_order() == "[01] "
|
||||
|
||||
obj_none = TestClass(None)
|
||||
assert obj_none.get_order() == ""
|
||||
|
||||
def test_wrap_decorator_prefix_only(self):
|
||||
"""Test @conditional_decorators.wrap() as prefix (right="")."""
|
||||
class TestClass:
|
||||
def __init__(self, source):
|
||||
self.source = source
|
||||
|
||||
@conditional_decorators.wrap(" ")
|
||||
def get_source(self):
|
||||
return self.source
|
||||
|
||||
obj = TestClass("BDRip")
|
||||
assert obj.get_source() == " BDRip"
|
||||
|
||||
obj_none = TestClass(None)
|
||||
assert obj_none.get_source() == ""
|
||||
|
||||
def test_wrap_decorator_suffix_only(self):
|
||||
"""Test @conditional_decorators.wrap() as suffix (left="")."""
|
||||
class TestClass:
|
||||
def __init__(self, hdr):
|
||||
self.hdr = hdr
|
||||
|
||||
@conditional_decorators.wrap("", ",")
|
||||
def get_hdr(self):
|
||||
return self.hdr
|
||||
|
||||
obj = TestClass("HDR")
|
||||
assert obj.get_hdr() == "HDR,"
|
||||
|
||||
obj_none = TestClass(None)
|
||||
assert obj_none.get_hdr() == ""
|
||||
|
||||
def test_replace_slashes_decorator(self):
|
||||
"""Test @conditional_decorators.replace_slashes() decorator."""
|
||||
class TestClass:
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
|
||||
@conditional_decorators.replace_slashes()
|
||||
def get_title(self):
|
||||
return self.title
|
||||
|
||||
obj = TestClass("Movie/Title\\Test")
|
||||
assert obj.get_title() == "Movie-Title-Test"
|
||||
|
||||
def test_default_decorator(self):
|
||||
"""Test @conditional_decorators.default() decorator."""
|
||||
class TestClass:
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
|
||||
@conditional_decorators.default("Unknown Title")
|
||||
def get_title(self):
|
||||
return self.title
|
||||
|
||||
obj = TestClass(None)
|
||||
assert obj.get_title() == "Unknown Title"
|
||||
|
||||
obj_with_title = TestClass("Movie Title")
|
||||
assert obj_with_title.get_title() == "Movie Title"
|
||||
|
||||
def test_chained_decorators(self):
|
||||
"""Test chaining multiple decorators."""
|
||||
class TestClass:
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
|
||||
@conditional_decorators.replace_slashes()
|
||||
@conditional_decorators.default("Unknown Title")
|
||||
def get_title(self):
|
||||
return self.title
|
||||
|
||||
obj = TestClass("Movie/Title")
|
||||
assert obj.get_title() == "Movie-Title"
|
||||
|
||||
obj_none = TestClass(None)
|
||||
assert obj_none.get_title() == "Unknown Title"
|
||||
@@ -0,0 +1,195 @@
|
||||
"""Tests for ProposedNameFormatter with decorator pattern."""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from renamer.formatters.proposed_name_formatter import ProposedNameFormatter
|
||||
|
||||
|
||||
class TestProposedNameFormatter:
|
||||
"""Test ProposedNameFormatter with decorator pattern."""
|
||||
|
||||
def test_basic_formatting(self):
|
||||
"""Test basic filename formatting with all fields."""
|
||||
extractor = {
|
||||
'order': '01',
|
||||
'title': 'Movie Title',
|
||||
'year': 2020,
|
||||
'source': 'BDRip',
|
||||
'frame_class': '1080p',
|
||||
'hdr': 'HDR',
|
||||
'audio_langs': 'ukr,eng',
|
||||
'special_info': ["Director's Cut"],
|
||||
'movie_db': ['tmdb', '12345'],
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
assert '[01]' in result
|
||||
assert 'Movie Title' in result
|
||||
assert '(2020)' in result
|
||||
assert 'BDRip' in result
|
||||
assert '1080p' in result
|
||||
assert 'HDR' in result
|
||||
assert 'ukr,eng' in result
|
||||
assert "Director's Cut" in result
|
||||
assert 'tmdbid-12345' in result
|
||||
assert '.mkv' in result
|
||||
|
||||
def test_minimal_formatting(self):
|
||||
"""Test formatting with minimal fields."""
|
||||
extractor = {
|
||||
'title': 'Simple Movie',
|
||||
'year': 2020,
|
||||
'extension': 'mp4'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
assert 'Simple Movie' in result
|
||||
assert '(2020)' in result
|
||||
assert '.mp4' in result
|
||||
assert '[01]' not in result # No order
|
||||
|
||||
def test_title_slash_replacement(self):
|
||||
"""Test that slashes in title are replaced with dashes."""
|
||||
extractor = {
|
||||
'title': 'Movie/Title\\Test',
|
||||
'year': 2020,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
assert 'Movie-Title-Test' in result
|
||||
assert '/' not in result
|
||||
assert '\\' not in result
|
||||
|
||||
def test_none_title(self):
|
||||
"""Test formatting when title is None (extractor should provide default)."""
|
||||
extractor = {
|
||||
'title': None,
|
||||
'year': 2020,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
# Since title is None, it won't appear (unless extractor provides default)
|
||||
assert result is not None
|
||||
|
||||
def test_none_extension(self):
|
||||
"""Test formatting when extension is None (extractor should provide default)."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'extension': None
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
# Extension handling depends on extractor default
|
||||
assert result is not None
|
||||
|
||||
def test_special_info_list_formatting(self):
|
||||
"""Test special info list is formatted correctly."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'special_info': ['Extended Edition', 'Remastered'],
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
assert 'Extended Edition, Remastered' in result
|
||||
|
||||
def test_database_info_formatting(self):
|
||||
"""Test database info is formatted correctly."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'movie_db': {'name': 'imdb', 'id': 'tt1234567'},
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
assert 'imdbid-tt1234567' in result
|
||||
|
||||
def test_str_method(self):
|
||||
"""Test __str__ method returns same as rename_line()."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
assert str(formatter) == formatter.rename_line
|
||||
|
||||
def test_formatted_display_matching_name(self):
|
||||
"""Test rename_line_formatted when filename matches proposed name."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
proposed = str(formatter)
|
||||
file_path = Path(proposed)
|
||||
|
||||
result = formatter.rename_line_formatted(file_path)
|
||||
assert '>>' in result
|
||||
assert '<<' in result
|
||||
assert '[green]' in result
|
||||
|
||||
def test_formatted_display_different_name(self):
|
||||
"""Test rename_line_formatted when filename differs from proposed name."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
file_path = Path('different_name.mkv')
|
||||
|
||||
result = formatter.rename_line_formatted(file_path)
|
||||
assert '>>' in result
|
||||
assert '<<' in result
|
||||
|
||||
def test_year_formatting(self):
|
||||
"""Test year is wrapped in parentheses."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': 2020,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
assert '(2020)' in result
|
||||
|
||||
def test_no_year(self):
|
||||
"""Test formatting when no year provided."""
|
||||
extractor = {
|
||||
'title': 'Movie',
|
||||
'year': None,
|
||||
'extension': 'mkv'
|
||||
}
|
||||
|
||||
formatter = ProposedNameFormatter(extractor)
|
||||
result = formatter.rename_line
|
||||
|
||||
# Should not have empty parentheses
|
||||
assert '()' not in result
|
||||
Reference in New Issue
Block a user