Skip to content

Commit 9bd70f5

Browse files
Improve test suite (#137)
1 parent b7a31c9 commit 9bd70f5

File tree

7 files changed

+315
-0
lines changed

7 files changed

+315
-0
lines changed

tests/comic/comic_test.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from unittest.mock import MagicMock
2+
3+
import pytest
4+
5+
from perdoo.cli.process import generate_naming
6+
from perdoo.comic.archives import CBTArchive, CBZArchive
7+
from perdoo.comic.comic import Comic
8+
from perdoo.comic.metadata import ComicInfo, MetronInfo
9+
from perdoo.settings import Naming
10+
11+
12+
@pytest.fixture
13+
def cbz_comic(cbz_archive: CBZArchive) -> Comic:
14+
return Comic(filepath=cbz_archive.filepath)
15+
16+
17+
@pytest.fixture
18+
def cbt_comic(cbt_archive: CBTArchive) -> Comic:
19+
return Comic(filepath=cbt_archive.filepath)
20+
21+
22+
def test_convert_to_cbz(cbt_comic: Comic) -> None:
23+
cbt_comic.convert_to(extension="cbz")
24+
assert isinstance(cbt_comic.archive, CBZArchive)
25+
assert cbt_comic.filepath.suffix == ".cbz"
26+
27+
28+
def test_convert_to_cbt(cbz_comic: Comic) -> None:
29+
cbz_comic.convert_to(extension="cbt")
30+
assert isinstance(cbz_comic.archive, CBTArchive)
31+
assert cbz_comic.filepath.suffix == ".cbt"
32+
33+
34+
def test_clean_archive(cbz_comic: Comic) -> None:
35+
cbz_comic.archive.list_filenames = MagicMock(
36+
return_value=["001.jpg", "info.txt", "ComicInfo.xml", "cover.png"]
37+
)
38+
cbz_comic.archive.delete_file = MagicMock()
39+
with cbz_comic.open_session() as session:
40+
for extra in cbz_comic.list_extras():
41+
session.delete(filename=extra.name)
42+
cbz_comic.archive.delete_file.assert_called_once_with(filename="info.txt")
43+
44+
45+
def test_write_comicinfo(cbz_comic: Comic, comic_info: ComicInfo) -> None:
46+
with cbz_comic.open_session() as session:
47+
_, info = cbz_comic.read_metadata(session=session)
48+
assert info is None
49+
session.write(filename=ComicInfo.FILENAME, data=comic_info.to_bytes())
50+
_, info = cbz_comic.read_metadata(session=session)
51+
assert info == comic_info
52+
53+
54+
def test_write_metroninfo(cbz_comic: Comic, metron_info: MetronInfo) -> None:
55+
with cbz_comic.open_session() as session:
56+
info, _ = cbz_comic.read_metadata(session=session)
57+
assert info is None
58+
session.write(filename=MetronInfo.FILENAME, data=metron_info.to_bytes())
59+
info, _ = cbz_comic.read_metadata(session=session)
60+
assert info == metron_info
61+
62+
63+
def test_write_metadata_override(cbz_comic: Comic, metron_info: MetronInfo) -> None:
64+
metadata_copy = metron_info.model_copy(deep=True)
65+
metadata_copy.series.volume = 2
66+
67+
with cbz_comic.open_session() as session:
68+
info, _ = cbz_comic.read_metadata(session=session)
69+
assert info is None
70+
session.write(filename=MetronInfo.FILENAME, data=metron_info.to_bytes())
71+
info, _ = cbz_comic.read_metadata(session=session)
72+
assert info == metron_info
73+
session.write(filename=MetronInfo.FILENAME, data=metadata_copy.to_bytes())
74+
info, _ = cbz_comic.read_metadata(session=session)
75+
assert info == metadata_copy
76+
77+
78+
def test_rename(cbz_comic: Comic, metron_info: MetronInfo) -> None:
79+
naming = generate_naming(settings=Naming(), metron_info=metron_info, comic_info=None)
80+
cbz_comic.move_to(naming=naming, output_folder=cbz_comic.filepath.parent)
81+
assert cbz_comic.filepath.name == "Test-Series-v1_#.cbz"

tests/comic/metadata/__init__.py

Whitespace-only changes.

tests/comic/metadata/base_test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from pathlib import Path
2+
3+
from perdoo.comic.metadata import ComicInfo
4+
from perdoo.comic.metadata._base import sanitize
5+
from perdoo.settings import Naming
6+
7+
8+
def test_sanitize_basic() -> None:
9+
assert sanitize(value="Example Title!", seperator="-") == "Example-Title!"
10+
assert sanitize(value="Example/Title: 123", seperator="-") == "ExampleTitle-123"
11+
assert sanitize(value=" already spaced ", seperator="_") == "already_spaced"
12+
13+
14+
def test_sanitize_none_and_empty() -> None:
15+
assert sanitize(value=None, seperator="-") is None
16+
assert sanitize(value="", seperator="-") == ""
17+
18+
19+
def test_evaluate_pattern() -> None:
20+
obj = ComicInfo(series="Series", volume=1, number=2, format="Single Issue", publisher="Pub")
21+
settings = Naming(seperator="-", default="{series-name}-{unknown}-{number:03}")
22+
name = obj.get_filename(settings=settings)
23+
24+
assert name == "Series-unknown-002"
25+
26+
27+
def test_metadata_to_file(tmp_path: Path) -> None:
28+
obj = ComicInfo(series="Example", number=1, format="Single Issue")
29+
out = tmp_path / obj.FILENAME
30+
obj.to_file(file=out)
31+
32+
assert out.exists()
33+
34+
loaded = ComicInfo.from_bytes(content=out.read_bytes())
35+
36+
assert loaded.series == "Example"
37+
assert loaded.number == "1"
38+
assert loaded.format == "Single Issue"
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from datetime import date
2+
3+
from perdoo.comic.metadata import ComicInfo
4+
from perdoo.comic.metadata.comic_info import Page, PageType
5+
from perdoo.settings import Naming
6+
7+
8+
def test_cover_date_property(comic_info: ComicInfo) -> None:
9+
assert comic_info.cover_date is None
10+
11+
comic_info.cover_date = date(2020, 2, 29)
12+
assert comic_info.year == 2020
13+
assert comic_info.month == 2
14+
assert comic_info.day == 29
15+
assert comic_info.cover_date == date(2020, 2, 29)
16+
17+
comic_info.year = None
18+
assert comic_info.year is None
19+
assert comic_info.month == 2
20+
assert comic_info.day == 29
21+
assert comic_info.cover_date is None
22+
23+
24+
def test_page_ordering_and_hashing() -> None:
25+
p1 = Page(image=2, type=PageType.STORY)
26+
p2 = Page(image=1, type=PageType.FRONT_COVER)
27+
p3 = Page(image=2, type=PageType.OTHER)
28+
29+
assert sorted([p1, p2]) == [p2, p1]
30+
assert p1 == p3
31+
assert len({p1, p2, p3}) == 2
32+
33+
34+
def test_credits_property(comic_info: ComicInfo) -> None:
35+
comic_info.credits = {
36+
"Alice": ["Writer"],
37+
"Bob": ["Inker", "Colorist"],
38+
"Charles": ["Writer", "Inker"],
39+
}
40+
41+
assert comic_info.writer == "Alice,Charles"
42+
assert comic_info.inker == "Bob,Charles"
43+
assert comic_info.colorist == "Bob"
44+
45+
46+
def test_list_fields_mapping(comic_info: ComicInfo) -> None:
47+
comic_info.genre_list = ["Sci-Fi", "Noir"]
48+
comic_info.character_list = ["Alice", "Bob"]
49+
comic_info.team_list = ["Team X"]
50+
comic_info.location_list = ["Gotham"]
51+
comic_info.story_arc_list = ["Arc 1", "Arc 2"]
52+
53+
assert comic_info.genre == "Sci-Fi,Noir"
54+
assert comic_info.characters == "Alice,Bob"
55+
assert comic_info.teams == "Team X"
56+
assert comic_info.locations == "Gotham"
57+
assert comic_info.story_arc == "Arc 1,Arc 2"
58+
59+
60+
def test_get_filename_padding_and_sanitization() -> None:
61+
obj = ComicInfo(
62+
publisher="Example Publisher",
63+
series="Example Series",
64+
volume=1,
65+
number=2,
66+
format="Single Issue",
67+
title="Hello: World / ???",
68+
)
69+
settings = Naming(
70+
seperator="-",
71+
default="{publisher-name}/{series-name}-v{volume}/{series-name}-v{volume}_#{number:02}-{title}",
72+
)
73+
name = obj.get_filename(settings=settings)
74+
75+
assert "#02" in name
76+
assert "Hello-World" in name
77+
78+
79+
def test_xml_bytes_preserves_pages() -> None:
80+
obj = ComicInfo(
81+
series="Series",
82+
number=1,
83+
format="Single Issue",
84+
pages=[
85+
Page(image=1, type=PageType.FRONT_COVER, image_size=123),
86+
Page(image=2, type=PageType.STORY, image_size=456),
87+
],
88+
)
89+
loaded = ComicInfo.from_bytes(content=obj.to_bytes())
90+
91+
assert loaded.series == obj.series
92+
assert len(loaded.pages) == len(obj.pages)
93+
assert loaded.pages[0].image == obj.pages[0].image
94+
assert loaded.pages[0].type == obj.pages[0].type
95+
assert loaded.pages[1].image == obj.pages[1].image
96+
assert loaded.pages[1].type == obj.pages[1].type
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from datetime import date, datetime
2+
3+
import pytest
4+
5+
from perdoo.comic.metadata import MetronInfo
6+
from perdoo.comic.metadata.metron_info import (
7+
GTIN,
8+
Credit,
9+
Format,
10+
Id,
11+
InformationSource,
12+
Publisher,
13+
Resource,
14+
Role,
15+
)
16+
from perdoo.settings import Naming
17+
18+
19+
def test_information_source_load_valid() -> None:
20+
assert InformationSource.load(value="Metron") is InformationSource.METRON
21+
assert InformationSource.load(value="Comic Vine") is InformationSource.COMIC_VINE
22+
with pytest.raises(ValueError, match=r"isn't a valid InformationSource"):
23+
InformationSource.load(value="Not Real")
24+
25+
26+
def test_role_load_unknown_fallback() -> None:
27+
assert Role.load(value="Writer") is Role.WRITER
28+
assert Role.load(value="Not Real") is Role.OTHER
29+
30+
31+
def test_ensure_timezone_adds_local_tz(metron_info: MetronInfo) -> None:
32+
naive = datetime(2020, 1, 1, 12, 0, 0) # tzinfo=None
33+
metron_info.last_modified = naive
34+
35+
assert metron_info.last_modified is not None
36+
assert metron_info.last_modified.tzinfo is not None
37+
38+
39+
def test_get_filename_padding_and_sanitization(metron_info: MetronInfo) -> None:
40+
metron_info.number = 2
41+
metron_info.cover_date = date(2021, 7, 4)
42+
metron_info.ids = [
43+
Id(primary=False, source=InformationSource.METRON, value="abc"),
44+
Id(primary=True, source=InformationSource.COMIC_VINE, value="cv-123"),
45+
]
46+
settings = Naming(
47+
seperator="-",
48+
default="{publisher-name}/{series-name}-v{volume}/{series-name}-v{volume}_#{number:03}_{cover-year}_{id}",
49+
)
50+
name = metron_info.get_filename(settings=settings)
51+
52+
assert "#002" in name
53+
assert "2021" in name
54+
assert "cv-123" in name
55+
56+
57+
def test_pattern_map(metron_info: MetronInfo) -> None:
58+
metron_info.publisher = Publisher(name="Pub", imprint=Resource(value="Imprint Name"))
59+
metron_info.gtin = GTIN(isbn="9781234567890", upc="012345678905")
60+
settings = Naming(seperator="-", default="{publisher-name}/{imprint}/{isbn}/{upc}")
61+
name = metron_info.get_filename(settings=settings)
62+
63+
assert "Pub" in name
64+
assert "Imprint-Name" in name
65+
assert "9781234567890" in name
66+
assert "012345678905" in name
67+
68+
69+
def test_xml_bytes_preserved(metron_info: MetronInfo) -> None:
70+
metron_info.credits = [
71+
Credit(
72+
creator=Resource(value="Alice"),
73+
roles=[Resource(value=Role.WRITER), Resource(value=Role.INKER)],
74+
)
75+
]
76+
metron_info.series.format = Format.SINGLE_ISSUE
77+
metron_info.number = 2
78+
loaded = MetronInfo.from_bytes(content=metron_info.to_bytes())
79+
80+
assert loaded.series.name == metron_info.series.name
81+
assert loaded.series.format == metron_info.series.format
82+
assert loaded.number == metron_info.number
83+
assert loaded.credits[0].creator.value == metron_info.credits[0].creator.value
84+
assert {r.value for r in loaded.credits[0].roles} == {
85+
r.value for r in metron_info.credits[0].roles
86+
}

tests/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import pytest
2+
3+
from perdoo.comic.metadata import ComicInfo, MetronInfo
4+
from perdoo.comic.metadata.metron_info import Series
5+
6+
7+
@pytest.fixture
8+
def metron_info() -> MetronInfo:
9+
return MetronInfo(series=Series(name="Test Series"))
10+
11+
12+
@pytest.fixture
13+
def comic_info() -> ComicInfo:
14+
return ComicInfo()

0 commit comments

Comments
 (0)