from __future__ import annotations import hashlib import os import tempfile import unittest from pathlib import Path from docforge.errors import DocForgeError from docforge.incremental import ( CachedSource, ExtractionCache, load_extraction_cache, write_extraction_cache, ) class ExtractionCacheBoundsTests(unittest.TestCase): @staticmethod def cache(*, payload: str = "ok", count: int = 1) -> ExtractionCache: sources = tuple( CachedSource( source_id=f"source-{index}", source_path=f"src/{index}.txt", fingerprint=hashlib.sha256(str(index).encode()).hexdigest(), extractor_version="fixture@1", dependencies=(), payload={"content": payload}, ) for index in range(count) ) return ExtractionCache("fixture", "fixture-adapter", "1", sources) def test_bounded_round_trip_and_oversized_read_is_a_cache_miss(self) -> None: with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "extractions.json" write_extraction_cache(path, self.cache(), max_bytes=1_000, max_sources=2) loaded = load_extraction_cache( path, project_id="fixture", adapter_id="fixture-adapter", adapter_version="1", max_bytes=1_000, max_sources=2, ) self.assertEqual(self.cache(), loaded) with path.open("ab") as handle: handle.write(b" " * 1_000) self.assertIsNone( load_extraction_cache( path, project_id="fixture", adapter_id="fixture-adapter", adapter_version="1", max_bytes=1_000, max_sources=2, ) ) def test_write_rejects_byte_and_source_limits_without_replacing_target(self) -> None: with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "extractions.json" path.write_bytes(b"preserved\n") for cache, maximum_bytes, maximum_sources in ( (self.cache(payload="x" * 500), 100, 2), (self.cache(count=2), 1_000, 1), ): with self.assertRaises(DocForgeError) as captured: write_extraction_cache( path, cache, max_bytes=maximum_bytes, max_sources=maximum_sources, ) self.assertEqual("cache_limit", captured.exception.code) self.assertEqual(b"preserved\n", path.read_bytes()) def test_symlink_and_non_regular_targets_are_cache_misses(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) real = root / "real.json" write_extraction_cache(real, self.cache(), max_bytes=1_000, max_sources=2) linked = root / "linked.json" linked.symlink_to(real) fifo = root / "fifo" os.mkfifo(fifo) for path in (linked, fifo): self.assertIsNone( load_extraction_cache( path, project_id="fixture", adapter_id="fixture-adapter", adapter_version="1", max_bytes=1_000, max_sources=2, ) ) if __name__ == "__main__": unittest.main()