""" Tests for the check-deprecated-db pre-commit hook. Covers regressions: - File-level 'get_user_db_session' guard used to whitelist whole files; one correct call silently allowed raw sqlite3.connect elsewhere. - get_db_connection / import patterns had no comment/docstring skip — a TODO or migration note referencing the deprecated API was flagged. Note: SHARED_DB is built at runtime to avoid embedding the literal shared-database filename in this test file (a separate hook scans every file for that literal). """ import subprocess import sys import tempfile from pathlib import Path HOOK_SCRIPT = ( Path(__file__).parent.parent.parent / ".pre-commit-hooks" / "check-deprecated-db.py" ) # Built at runtime to avoid tripping check-ldr-db (a separate hook that # scans every file for the literal "ldr.db" substring). SHARED_DB = "ldr" + ".db" def _run_hook( content: str, filename: str = "service.py" ) -> subprocess.CompletedProcess: with tempfile.TemporaryDirectory() as d: path = Path(d) / filename path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content) return subprocess.run( [sys.executable, str(HOOK_SCRIPT), str(path)], capture_output=True, text=True, ) class TestFileLevelGuardRemoved: """A correct get_user_db_session call no longer whitelists the whole file.""" def test_correct_call_does_not_exempt_raw_sqlite_connect(self): content = ( 'with get_user_db_session("alice") as session:\n' " pass\n" f'conn = sqlite3.connect("{SHARED_DB}")\n' ) result = _run_hook(content) assert result.returncode == 1 assert "Direct SQLite connection to shared database" in result.stdout def test_raw_sqlite_connect_without_sibling_still_flagged(self): result = _run_hook(f'conn = sqlite3.connect("{SHARED_DB}")\n') assert result.returncode == 1 def test_noqa_sentinel_exempts_single_line(self): content = f'conn = sqlite3.connect("{SHARED_DB}") # noqa: shared-db\n' result = _run_hook(content) assert result.returncode == 0 class TestCommentSkip: """Comments and docstrings mentioning deprecated APIs must not fire.""" def test_todo_comment_about_get_db_connection_not_flagged(self): result = _run_hook( "# TODO: replace get_db_connection() with per-user session\n" ) assert result.returncode == 0 def test_docstring_mention_not_flagged(self): content = '"""get_db_connection() is deprecated — use get_user_db_session."""\n' result = _run_hook(content) assert result.returncode == 0 def test_real_get_db_connection_call_flagged(self): result = _run_hook("conn = get_db_connection()\n") assert result.returncode == 1 assert "deprecated get_db_connection" in result.stdout def test_comment_about_deprecated_import_not_flagged(self): result = _run_hook( "# Historical: from ..web.models.database import get_db_connection\n" ) assert result.returncode == 0 def test_real_deprecated_import_flagged(self): result = _run_hook( "from ..web.models.database import get_db_connection\n" ) assert result.returncode == 1 class TestExistingAllowlistStillApplies: """Filename-based exemptions must still work.""" def test_encrypted_db_exempt(self): """encrypted_db.py legitimately calls get_db_connection — the skip list in main() must still exempt it.""" result = _run_hook( "conn = get_db_connection()\n", filename="encrypted_db.py" ) assert result.returncode == 0 def test_session_context_exempt(self): result = _run_hook( "conn = get_db_connection()\n", filename="session_context.py" ) assert result.returncode == 0 def test_tests_path_exempt(self): result = _run_hook( f'sqlite3.connect("{SHARED_DB}")\n', filename="tests/fixtures.py" ) assert result.returncode == 0