from __future__ import annotations import sqlite3 from jarca_ledger_mcp.application.account_valuation_service import ( list_account_valuations, register_account_valuation, ) from jarca_ledger_mcp.application.assets_service import ( create_manual_asset, list_manual_assets, preview_asset_snapshot_close, ) from jarca_ledger_mcp.application.settlement_draft_service import create_settlement_draft from jarca_ledger_mcp.infrastructure.sqlite.migrations import init_db def _tables(path): with sqlite3.connect(path) as conn: return {r[0] for r in conn.execute("select name from sqlite_master where type='table'")} EXPECTED_TABLES = { # Sourced from schema.py plus migration-created settlement draft tables. "schema_meta", "manual_assets", "asset_snapshots", "asset_snapshot_runs", "account_valuations", "accounts", "transactions", "budgets", "import_batches", "category_rules", "ledger_categories", "account_snapshot", "settlement_cashflow_snapshots", "review_decisions", "reconciliation_sessions", "monthly_settlement", "settlement_drafts", "settlement_draft_items", } def test_fresh_init_preserves_account_valuations_and_exact_schema_tables(tmp_path): path = tmp_path / "fresh.sqlite3" init_db(str(path)) tables = _tables(path) assert "account_valuations" in tables assert tables == EXPECTED_TABLES def test_init_is_idempotent(tmp_path): path = tmp_path / "repeat.sqlite3" assert init_db(str(path)) == str(path) assert init_db(str(path)) == str(path) assert _tables(path) == EXPECTED_TABLES def test_legacy_nonempty_account_valuations_row_is_preserved(tmp_path): path = tmp_path / "legacy.sqlite3" init_db(str(path)) with sqlite3.connect(path) as conn: conn.execute("insert into account_valuations (id,account_id,amount,basis_date,recorded_at) values ('legacy-1','acct-1',123,'2026-09-30','t')") conn.execute("insert into accounts (id,name,type,active,created_at,updated_at) values ('acct-1','Keep me','bank',1,'t','t')") conn.commit() init_db(str(path)) with sqlite3.connect(path) as conn: assert conn.execute("select count(*) from accounts where id='acct-1'").fetchone()[0] == 1 assert conn.execute("select amount from account_valuations where id='legacy-1'").fetchone() == (123,) def test_invalid_valuation_operations_do_not_create_db(tmp_path): path = tmp_path / "must-not-exist.sqlite3" result = register_account_valuation("acct", "invalid-date", 1, db_path=str(path)) listed = list_account_valuations("acct", db_path=str(path)) assert result["success"] is False and result["error_code"] == "validation_error" assert listed["success"] is False and listed["error_code"] == "db_not_initialized" assert not path.exists() def test_active_account_preview_reports_missing_without_sql_error(tmp_path): path = tmp_path / "preview.sqlite3" init_db(str(path)) with sqlite3.connect(path) as conn: conn.execute("insert into accounts (id,name,type,active,created_at,updated_at) values ('acct-1','Active','bank',1,'t','t')") conn.commit() result = preview_asset_snapshot_close("2026-09-30", db_path=str(path)) assert result["success"] is True assert result["close_status"] in {"incomplete_draft", "complete_exact"} assert not any(w.get("code") == "db_error" for w in result["warnings"]) def test_active_account_draft_returns_review_blocker_without_sql_error(tmp_path): path = tmp_path / "draft.sqlite3" init_db(str(path)) with sqlite3.connect(path) as conn: conn.execute("insert into accounts (id,name,type,active,created_at,updated_at) values ('acct-1','Active','bank',1,'t','t')") conn.commit() result = create_settlement_draft("2026-09", "tester", "draft-key", db_path=str(path)) assert result["success"] is True assert result.get("review", {}).get("approval_required") is True assert not any("sql" in str(v).lower() for v in result.get("review", {}).values()) def test_manual_asset_flow_remains_supported(tmp_path): path = tmp_path / "manual.sqlite3" init_db(str(path)) created = create_manual_asset("Emergency fund", 100000, "2026-09-30", "cash", db_path=str(path)) listed = list_manual_assets(db_path=str(path)) assert created["success"] and listed["success"] assert listed["manual_assets"][0]["id"] == created["manual_asset"]["id"] assert listed["manual_assets"][0]["valuation_amount"] == 100000