"""Tests for app.db — database schema initialisation.""" from pathlib import Path import aiosqlite import pytest from app.db import init_db @pytest.mark.asyncio async def test_init_db_creates_settings_table(tmp_path: Path) -> None: """``init_db`` must create the ``settings`` table.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) async with db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='settings';") as cursor: row = await cursor.fetchone() assert row is not None @pytest.mark.asyncio async def test_init_db_creates_sessions_table(tmp_path: Path) -> None: """``init_db`` must create the ``sessions`` table.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) async with db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='sessions';") as cursor: row = await cursor.fetchone() assert row is not None @pytest.mark.asyncio async def test_init_db_creates_blocklist_sources_table(tmp_path: Path) -> None: """``init_db`` must create the ``blocklist_sources`` table.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) async with db.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name='blocklist_sources';" ) as cursor: row = await cursor.fetchone() assert row is not None @pytest.mark.asyncio async def test_init_db_creates_import_log_table(tmp_path: Path) -> None: """``init_db`` must create the ``import_log`` table.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) async with db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='import_log';") as cursor: row = await cursor.fetchone() assert row is not None @pytest.mark.asyncio async def test_init_db_is_idempotent(tmp_path: Path) -> None: """Calling ``init_db`` twice on the same database must not raise.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) await init_db(db) # Second call must be a no-op. @pytest.mark.asyncio async def test_init_db_records_schema_version(tmp_path: Path) -> None: """``init_db`` must record the current schema version.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) async with db.execute("SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;") as cursor: row = await cursor.fetchone() assert row is not None assert row[0] == 9 @pytest.mark.asyncio async def test_init_db_migrates_legacy_database_without_schema_version(tmp_path: Path) -> None: """Legacy databases without a schema marker must be migrated on startup.""" db_path = str(tmp_path / "test.db") async with aiosqlite.connect(db_path) as db: await init_db(db) await db.execute("DROP TABLE schema_migrations;") await db.commit() await init_db(db) async with db.execute("SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;") as cursor: row = await cursor.fetchone() assert row is not None assert row[0] == 9