# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """Writing into the album, and putting it back the way it was.""" from __future__ import annotations import json from typing import TYPE_CHECKING from signal_bot.pack import TAGS_FILE from signal_bot.pack_custom import CUSTOM_FILE from signal_bot.pack_store import ( ADDS_FILE, content_name, record_adds, restore, snapshot, write_media, write_tags, ) if TYPE_CHECKING: from pathlib import Path def test_the_name_comes_from_the_bytes_not_the_upload(tmp_path: Path) -> None: """Which is what makes "already in the album?" a lookup, not a comparison.""" assert content_name(b"same", ".jpg") == content_name(b"same", ".jpg") assert content_name(b"same", ".jpg") != content_name(b"other", ".jpg") assert content_name(b"same", ".jpg").endswith(".jpg") def test_a_written_file_lands_in_media_and_is_not_world_readable(tmp_path: Path) -> None: write_media(tmp_path, "abc.jpg", b"payload") stored = tmp_path / "media" / "abc.jpg" assert stored.read_bytes() == b"payload" assert stored.stat().st_mode & 0o077 == 0 def test_no_temporary_file_is_left_behind(tmp_path: Path) -> None: """A .tmp beside media/ would fail the next load as an untagged file.""" write_media(tmp_path, "abc.jpg", b"payload") assert [p.name for p in (tmp_path / "media").iterdir()] == ["abc.jpg"] def test_tags_are_written_sorted_and_reloadable(tmp_path: Path) -> None: write_tags(tmp_path, {"b.jpg": frozenset({"p2", "p1"}), "a.jpg": frozenset({"p1"})}) document = json.loads((tmp_path / TAGS_FILE).read_text(encoding="utf-8")) assert document == {"a.jpg": ["p1"], "b.jpg": ["p1", "p2"]} assert list(document) == ["a.jpg", "b.jpg"] def test_adds_accumulate_rather_than_replace(tmp_path: Path) -> None: record_adds(tmp_path, {"a.jpg": {"by": "uuid-1", "at": 10}}) record_adds(tmp_path, {"b.jpg": {"by": "uuid-2", "at": 20}}) document = json.loads((tmp_path / ADDS_FILE).read_text(encoding="utf-8")) assert set(document) == {"a.jpg", "b.jpg"} assert document["a.jpg"]["by"] == "uuid-1" def test_a_corrupt_adds_file_does_not_block_an_upload(tmp_path: Path) -> None: """It is write-only bookkeeping; refusing a photo over it is backwards.""" (tmp_path / ADDS_FILE).write_text("{ not json", encoding="utf-8") record_adds(tmp_path, {"a.jpg": {"by": "uuid-1", "at": 10}}) assert json.loads((tmp_path / ADDS_FILE).read_text(encoding="utf-8")) == { "a.jpg": {"by": "uuid-1", "at": 10} } def test_an_adds_file_that_is_not_an_object_is_replaced(tmp_path: Path) -> None: (tmp_path / ADDS_FILE).write_text("[1, 2]", encoding="utf-8") record_adds(tmp_path, {"a.jpg": {"by": "uuid-1", "at": 10}}) assert set(json.loads((tmp_path / ADDS_FILE).read_text(encoding="utf-8"))) == {"a.jpg"} def test_restore_puts_the_manifests_back_and_removes_the_new_files(tmp_path: Path) -> None: (tmp_path / TAGS_FILE).write_text('{"old.jpg": ["p1"]}', encoding="utf-8") (tmp_path / CUSTOM_FILE).write_text('{"t1": ["was-here"]}', encoding="utf-8") before = snapshot(tmp_path) write_media(tmp_path, "new.jpg", b"payload") write_tags(tmp_path, {"old.jpg": frozenset({"p1"}), "new.jpg": frozenset({"p2"})}) record_adds(tmp_path, {"new.jpg": {"by": "uuid-1", "at": 1}}) restore(tmp_path, before, ("new.jpg",)) assert json.loads((tmp_path / TAGS_FILE).read_text(encoding="utf-8")) == {"old.jpg": ["p1"]} assert json.loads((tmp_path / CUSTOM_FILE).read_text(encoding="utf-8")) == {"t1": ["was-here"]} # adds.json did not exist before, so restoring means removing it. assert not (tmp_path / ADDS_FILE).exists() assert not (tmp_path / "media" / "new.jpg").exists() def test_restoring_a_file_that_was_already_gone_is_not_an_error(tmp_path: Path) -> None: before = snapshot(tmp_path) restore(tmp_path, before, ("never-written.jpg",)) assert not (tmp_path / TAGS_FILE).exists() def test_a_snapshot_of_an_empty_album_records_three_absences(tmp_path: Path) -> None: before = snapshot(tmp_path) assert (before.tags, before.custom, before.adds) == (None, None, None)