121 lines
4.5 KiB
Python
121 lines
4.5 KiB
Python
from backend.app.utils.sidecar import SidecarData, find_sidecar, parse_sidecar
|
|
|
|
|
|
def test_find_sidecar_stem_json(tmp_path):
|
|
media = tmp_path / "photo.jpg"
|
|
media.write_bytes(b"x")
|
|
sc = tmp_path / "photo.json"
|
|
sc.write_text("{}")
|
|
assert find_sidecar(media) == sc
|
|
|
|
|
|
def test_find_sidecar_full_name_json(tmp_path):
|
|
media = tmp_path / "photo.jpg"
|
|
media.write_bytes(b"x")
|
|
sc = tmp_path / "photo.jpg.json"
|
|
sc.write_text("{}")
|
|
assert find_sidecar(media) == sc
|
|
|
|
|
|
def test_find_sidecar_none(tmp_path):
|
|
media = tmp_path / "photo.jpg"
|
|
media.write_bytes(b"x")
|
|
assert find_sidecar(media) is None
|
|
|
|
|
|
def test_find_sidecar_gallerydl_numbered_prefix(tmp_path):
|
|
"""gallery-dl prefixes media filenames with NN_ for in-post ordering
|
|
(e.g. `01_HOLLOW-ICHIGO.png`) but writes the post-level sidecar under
|
|
the attachment stem WITHOUT the prefix (`HOLLOW-ICHIGO.json`).
|
|
Confirmed against real Patreon downloads 2026-05-26 — operator's deep
|
|
scan produced 24 refresh calls but 0 Posts because the unprefixed
|
|
sidecar was invisible to find_sidecar."""
|
|
media = tmp_path / "01_HOLLOW-ICHIGO.png"
|
|
media.write_bytes(b"x")
|
|
sc = tmp_path / "HOLLOW-ICHIGO.json"
|
|
sc.write_text("{}")
|
|
assert find_sidecar(media) == sc
|
|
|
|
|
|
def test_find_sidecar_multidigit_prefix(tmp_path):
|
|
"""Numbering prefix can be wider than 2 digits (`001_...`); the strip
|
|
handles any \\d+_ form."""
|
|
media = tmp_path / "001_mirko-sketch.png"
|
|
media.write_bytes(b"x")
|
|
sc = tmp_path / "mirko-sketch.json"
|
|
sc.write_text("{}")
|
|
assert find_sidecar(media) == sc
|
|
|
|
|
|
def test_find_sidecar_prefers_attachment_level_over_post_level(tmp_path):
|
|
"""If BOTH a per-attachment sidecar and a post-level sidecar exist,
|
|
the attachment-level one wins (it's more specific)."""
|
|
media = tmp_path / "01_image.png"
|
|
media.write_bytes(b"x")
|
|
per_attachment = tmp_path / "01_image.json"
|
|
per_attachment.write_text('{"specific": true}')
|
|
post_level = tmp_path / "image.json"
|
|
post_level.write_text('{"specific": false}')
|
|
assert find_sidecar(media) == per_attachment
|
|
|
|
|
|
def test_find_sidecar_no_underscore_not_treated_as_prefix(tmp_path):
|
|
"""`01.png` (just digits, no underscore-separated stem) shouldn't
|
|
match. The regex requires NN_<something>."""
|
|
media = tmp_path / "01.png"
|
|
media.write_bytes(b"x")
|
|
(tmp_path / ".json").write_text("{}") # would be matched only if buggy
|
|
assert find_sidecar(media) is None
|
|
|
|
|
|
def test_parse_empty_dict_all_none():
|
|
sd = parse_sidecar({})
|
|
assert isinstance(sd, SidecarData)
|
|
assert (sd.platform, sd.external_post_id, sd.post_url, sd.post_title,
|
|
sd.description, sd.attachment_count, sd.post_date) == (
|
|
None, None, None, None, None, None, None)
|
|
assert sd.raw == {}
|
|
|
|
|
|
def test_parse_core_fields_and_id_priority():
|
|
sd = parse_sidecar({
|
|
"category": "patreon",
|
|
"id": 12345, "post_id": 999,
|
|
"url": "https://patreon.com/posts/12345",
|
|
"title": " Hello ",
|
|
"content": "<p>body</p>",
|
|
"page_count": 4,
|
|
"published_at": "2023-08-01T04:20:02Z",
|
|
})
|
|
assert sd.platform == "patreon"
|
|
assert sd.external_post_id == "12345" # 'id' wins over 'post_id'
|
|
assert sd.post_url == "https://patreon.com/posts/12345"
|
|
assert sd.post_title == "Hello"
|
|
assert sd.description == "<p>body</p>"
|
|
assert sd.attachment_count == 4
|
|
assert sd.post_date.year == 2023 and sd.post_date.tzinfo is not None
|
|
|
|
|
|
def test_parse_description_precedence_and_images_count():
|
|
sd = parse_sidecar({"description": "d", "caption": "c",
|
|
"images": [1, 2, 3]})
|
|
assert sd.description == "d" # content>description>caption
|
|
assert sd.attachment_count == 3 # len(images) fallback
|
|
|
|
|
|
def test_parse_date_epoch_and_unparseable_and_naive():
|
|
assert parse_sidecar({"timestamp": 1690857602}).post_date.tzinfo is not None
|
|
assert parse_sidecar({"date": "not-a-date"}).post_date is None
|
|
naive = parse_sidecar({"date": "2023-08-01T00:00:00"}).post_date
|
|
assert naive is not None and naive.utcoffset().total_seconds() == 0
|
|
|
|
|
|
def test_parse_ignores_non_str_junk():
|
|
sd = parse_sidecar({"category": 5, "title": 7, "page_count": "x",
|
|
"id": True})
|
|
assert sd.platform is None and sd.post_title is None
|
|
assert sd.attachment_count is None
|
|
assert sd.external_post_id is None # bool is not a valid id
|
|
assert sd.raw == {"category": 5, "title": 7, "page_count": "x",
|
|
"id": True}
|