from __future__ import annotations import json from datetime import UTC, datetime from pathlib import Path from broker_sync.providers._checkpoint import Checkpoint def test_load_missing_returns_none(tmp_path: Path) -> None: cp = Checkpoint(tmp_path, provider="t212", account_id="isa") assert cp.load() is None def test_save_then_load_roundtrip(tmp_path: Path) -> None: cp = Checkpoint(tmp_path, provider="t212", account_id="isa") cp.save("cursor-xyz") assert cp.load() == "cursor-xyz" def test_save_writes_expected_filename(tmp_path: Path) -> None: cp = Checkpoint(tmp_path, provider="t212", account_id="isa") cp.save("cursor-abc") expected = tmp_path / "t212-isa.json" assert expected.exists() raw = json.loads(expected.read_text()) assert raw["cursor"] == "cursor-abc" # updated_at is ISO-8601 with tz — just confirm it parses. parsed = datetime.fromisoformat(raw["updated_at"]) assert parsed.tzinfo is not None def test_save_overwrites_previous(tmp_path: Path) -> None: cp = Checkpoint(tmp_path, provider="t212", account_id="isa") cp.save("first") cp.save("second") assert cp.load() == "second" def test_separate_accounts_are_isolated(tmp_path: Path) -> None: a = Checkpoint(tmp_path, provider="t212", account_id="isa") b = Checkpoint(tmp_path, provider="t212", account_id="gia") a.save("isa-cursor") b.save("gia-cursor") assert a.load() == "isa-cursor" assert b.load() == "gia-cursor" def test_save_creates_parent_dir(tmp_path: Path) -> None: nested = tmp_path / "a" / "b" / "c" cp = Checkpoint(nested, provider="t212", account_id="isa") cp.save("cursor") assert (nested / "t212-isa.json").exists() def test_load_rejects_legacy_future_time(tmp_path: Path) -> None: # Malformed file (missing 'cursor' key) → treat as absent rather than crash. p = tmp_path / "t212-isa.json" p.write_text(json.dumps({"updated_at": datetime.now(UTC).isoformat()})) cp = Checkpoint(tmp_path, provider="t212", account_id="isa") assert cp.load() is None