# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """The import ledger: what the album has already taken in, and from what.""" from __future__ import annotations import json from typing import TYPE_CHECKING from signal_bot import pack_ledger from signal_bot.pack import MEDIA_DIR from signal_bot.pack_custom import FILE_MODE from signal_bot.pack_ledger import LEDGER_FILE, Entry from signal_bot.pack_store import ADDS_FILE from tests.pack_fixture import PIXEL if TYPE_CHECKING: from pathlib import Path def _album(tmp_path: Path, files: dict[str, bytes]) -> Path: """A pack directory holding exactly ``files`` in media/.""" media = tmp_path / MEDIA_DIR media.mkdir(parents=True) for name, payload in files.items(): (media / name).write_bytes(payload) return tmp_path def test_digest_is_a_full_sha256() -> None: # Not content_name's truncated 32: a filename is a name, this is identity. assert len(pack_ledger.digest(b"x")) == 64 def test_a_missing_ledger_reads_as_empty(tmp_path: Path) -> None: assert pack_ledger.read(tmp_path) == {} def test_a_corrupt_ledger_degrades_instead_of_raising(tmp_path: Path) -> None: # The whole point: pack_load raises at startup and Restart=always turns # that into a loop. A broken ledger must cost a duplicate, not the bot. (tmp_path / LEDGER_FILE).write_text("{not json", encoding="utf-8") assert pack_ledger.read(tmp_path) == {} def test_a_ledger_that_is_not_an_object_reads_as_empty(tmp_path: Path) -> None: (tmp_path / LEDGER_FILE).write_text("[1, 2]", encoding="utf-8") assert pack_ledger.read(tmp_path) == {} def test_one_malformed_row_does_not_lose_the_others(tmp_path: Path) -> None: (tmp_path / LEDGER_FILE).write_text( json.dumps( { "good.jpg": {"source": "a" * 64, "stored": "b" * 64}, "not-a-dict.jpg": "nonsense", "no-stored.jpg": {"source": "c" * 64}, "bad-source.jpg": {"source": 7, "stored": "d" * 64}, } ), encoding="utf-8", ) assert set(pack_ledger.read(tmp_path)) == {"good.jpg"} def test_a_null_source_round_trips(tmp_path: Path) -> None: entries = {"chat.jpg": Entry(source=None, stored="e" * 64)} pack_ledger.write(tmp_path, entries) assert pack_ledger.read(tmp_path) == entries def test_the_ledger_is_written_private(tmp_path: Path) -> None: pack_ledger.write(tmp_path, {"a.jpg": Entry(source="1" * 64, stored="2" * 64)}) assert (tmp_path / LEDGER_FILE).stat().st_mode & 0o777 == FILE_MODE def test_source_hashes_skips_the_unrecoverable_ones() -> None: entries = { "a.jpg": Entry(source="1" * 64, stored="2" * 64), "b.jpg": Entry(source=None, stored="3" * 64), } assert pack_ledger.source_hashes(entries) == {"1" * 64} assert pack_ledger.stored_hashes(entries) == {"2" * 64, "3" * 64} def test_backfill_records_an_imported_file_as_its_own_source(tmp_path: Path) -> None: # shutil.copy2 copied these verbatim, so the bytes on disk *are* the # source bytes. This is the only moment that is recoverable. directory = _album(tmp_path, {"IMG_1.jpg": PIXEL}) entries = pack_ledger.backfill(directory) assert entries["IMG_1.jpg"].source == entries["IMG_1.jpg"].stored assert entries["IMG_1.jpg"].stored == pack_ledger.digest(PIXEL) def test_backfill_leaves_a_chat_upload_without_a_source(tmp_path: Path) -> None: # adds.json is the exact record of what came in through !add_photo, and # those were stripped on the way in: the source bytes never existed here. directory = _album(tmp_path, {"abc123.jpg": PIXEL}) (directory / ADDS_FILE).write_text( json.dumps({"abc123.jpg": {"by": "someone", "at": 1}}), encoding="utf-8" ) entries = pack_ledger.backfill(directory) assert entries["abc123.jpg"].source is None assert entries["abc123.jpg"].stored == pack_ledger.digest(PIXEL) def test_backfill_persists_what_it_found(tmp_path: Path) -> None: directory = _album(tmp_path, {"IMG_1.jpg": PIXEL}) pack_ledger.backfill(directory) assert set(pack_ledger.read(directory)) == {"IMG_1.jpg"} def test_backfill_never_revises_an_entry_it_already_has(tmp_path: Path) -> None: # Re-running must not overwrite a source hash recorded before a strip # with the post-strip bytes, which would silently lose the origin. directory = _album(tmp_path, {"IMG_1.jpg": PIXEL}) pack_ledger.write(directory, {"IMG_1.jpg": Entry(source="old", stored="older")}) entries = pack_ledger.backfill(directory) assert entries["IMG_1.jpg"] == Entry(source="old", stored="older") def test_backfill_is_idempotent(tmp_path: Path) -> None: directory = _album(tmp_path, {"IMG_1.jpg": PIXEL}) assert pack_ledger.backfill(directory) == pack_ledger.backfill(directory) def test_backfill_ignores_a_directory_inside_media(tmp_path: Path) -> None: directory = _album(tmp_path, {"IMG_1.jpg": PIXEL}) (directory / MEDIA_DIR / "subdir").mkdir() assert set(pack_ledger.backfill(directory)) == {"IMG_1.jpg"} def test_backfill_on_an_album_with_no_media_directory(tmp_path: Path) -> None: assert pack_ledger.backfill(tmp_path) == {}