"""Tests for io_utils.""" from __future__ import annotations import json from pathlib import Path from app.io_utils import read_json, write_json_atomic def test_read_json_missing_returns_default(tmp_path: Path) -> None: assert read_json(tmp_path / "missing.json", default={}) == {} def test_read_json_corrupt_returns_default(tmp_path: Path) -> None: path = tmp_path / "bad.json" path.write_text("not json", encoding="utf-8") assert read_json(path, default=None) is None def test_write_json_atomic_roundtrip(tmp_path: Path) -> None: path = tmp_path / "data.json" payload = {"job_id": "photo", "variants": []} write_json_atomic(path, payload) assert json.loads(path.read_text(encoding="utf-8")) == payload assert not path.with_suffix(path.suffix + ".tmp").exists() def test_file_lock_exclusive(tmp_path: Path) -> None: from concurrent.futures import ThreadPoolExecutor from app.io_utils import file_lock lock_path = tmp_path / "job.lock" counter = {"n": 0} def bump() -> None: with file_lock(lock_path): current = counter["n"] counter["n"] = current + 1 with ThreadPoolExecutor(max_workers=8) as pool: list(pool.map(lambda _: bump(), range(40))) assert counter["n"] == 40