#!/usr/bin/env python3 """Tests for the SHA-256 content cache. Run: python3 docs_sp/tools/test_content_cache.py """ import sys import tempfile from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from content_cache import ContentCache # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def make_cache(tmp: str) -> ContentCache: return ContentCache(cache_dir=Path(tmp) / ".discourse_sync_cache") # --------------------------------------------------------------------------- # Tests # --------------------------------------------------------------------------- def test_compute_hash_deterministic(): """Same content always produces the same hash.""" h1 = ContentCache.compute_hash("hello world") h2 = ContentCache.compute_hash("hello world") assert h1 == h2 assert len(h1) == 64 # SHA-256 hex digest length print(" PASS: compute_hash_deterministic") def test_compute_hash_differs(): """Different content produces different hashes.""" h1 = ContentCache.compute_hash("hello world") h2 = ContentCache.compute_hash("hello world!") assert h1 != h2 print(" PASS: compute_hash_differs") def test_is_changed_no_cache(): """First run (no cache file) should report changed.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) assert cache.is_changed("features/icbm.md", "content") print(" PASS: is_changed_no_cache") def test_is_changed_after_save(): """After saving, same content should report unchanged.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) cache.save("features/icbm.md", "content v1") assert not cache.is_changed("features/icbm.md", "content v1") print(" PASS: is_changed_after_save") def test_is_changed_after_modification(): """After saving, different content should report changed.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) cache.save("features/icbm.md", "content v1") assert cache.is_changed("features/icbm.md", "content v2") print(" PASS: is_changed_after_modification") def test_separate_paths_independent(): """Different doc paths have independent caches.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) cache.save("features/icbm.md", "content A") cache.save("safety/safety.md", "content B") assert not cache.is_changed("features/icbm.md", "content A") assert not cache.is_changed("safety/safety.md", "content B") assert cache.is_changed("features/icbm.md", "content B") assert cache.is_changed("safety/safety.md", "content A") print(" PASS: separate_paths_independent") def test_cache_dir_created_on_save(): """Cache directory is created automatically on first save.""" with tempfile.TemporaryDirectory() as tmp: cache_dir = Path(tmp) / "nested" / "cache" cache = ContentCache(cache_dir=cache_dir) assert not cache_dir.exists() cache.save("test.md", "content") assert cache_dir.exists() assert (cache_dir / "test.sha256").exists() print(" PASS: cache_dir_created_on_save") def test_cache_file_naming(): """Cache files use slug derived from doc path.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) cache.save("settings/cruise/speed-limit/source.md", "content") expected_name = "settings_cruise_speed-limit_source.sha256" cached_files = list(cache.cache_dir.glob("*.sha256")) assert len(cached_files) == 1 assert cached_files[0].name == expected_name print(" PASS: cache_file_naming") def test_clear_removes_all(): """clear() removes all .sha256 files and returns count.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) cache.save("a.md", "aaa") cache.save("b.md", "bbb") cache.save("c.md", "ccc") removed = cache.clear() assert removed == 3 assert list(cache.cache_dir.glob("*.sha256")) == [] print(" PASS: clear_removes_all") def test_clear_empty_cache(): """clear() on nonexistent cache dir returns 0.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) assert cache.clear() == 0 print(" PASS: clear_empty_cache") def test_overwrite_on_resave(): """Saving again overwrites the previous hash.""" with tempfile.TemporaryDirectory() as tmp: cache = make_cache(tmp) cache.save("doc.md", "version 1") assert not cache.is_changed("doc.md", "version 1") assert cache.is_changed("doc.md", "version 2") cache.save("doc.md", "version 2") assert cache.is_changed("doc.md", "version 1") assert not cache.is_changed("doc.md", "version 2") print(" PASS: overwrite_on_resave") # --------------------------------------------------------------------------- # Runner # --------------------------------------------------------------------------- if __name__ == "__main__": print("Testing content cache:") tests = [ test_compute_hash_deterministic, test_compute_hash_differs, test_is_changed_no_cache, test_is_changed_after_save, test_is_changed_after_modification, test_separate_paths_independent, test_cache_dir_created_on_save, test_cache_file_naming, test_clear_removes_all, test_clear_empty_cache, test_overwrite_on_resave, ] passed = 0 failed = 0 for test in tests: try: test() passed += 1 except AssertionError as e: print(f" FAIL: {test.__name__}: {e}") failed += 1 except Exception as e: print(f" ERROR: {test.__name__}: {e}") failed += 1 print(f"\n{passed}/{passed + failed} tests passed") sys.exit(1 if failed > 0 else 0)