import json import re from decimal import Decimal from pathlib import Path import pytest from app.parsers.registry import parse_pdf from app.parsers.validate import balance_difference FIXTURES = Path(__file__).parent / "fixtures" CASES = [("vr_beispiel.pdf", "vr"), ("hvb_beispiel.pdf", "hvb"), ("dkb_beispiel.pdf", "dkb")] NOISE = re.compile( r"(Kontostand|Übertrag|alter Saldo|neuer Saldo|Seite \d|Blatt \d)", re.I) @pytest.mark.parametrize("filename,bank", CASES) def test_parse_fixture(filename, bank): path = FIXTURES / filename if not path.exists(): pytest.skip(f"Fixture {filename} fehlt") stmt = parse_pdf(path) assert stmt.bank == bank assert stmt.opening_balance is not None assert stmt.closing_balance is not None assert len(stmt.transactions) > 0 assert balance_difference(stmt) == Decimal("0") @pytest.mark.parametrize("filename,bank", CASES) def test_no_noise_in_parsed_fields(filename, bank): path = FIXTURES / filename if not path.exists(): pytest.skip(f"Fixture {filename} fehlt") stmt = parse_pdf(path) for t in stmt.transactions: assert not NOISE.search(t.purpose), f"Noise im Verwendungszweck: #{stmt.transactions.index(t)}" assert not NOISE.search(t.counterparty), f"Noise im Empfänger: #{stmt.transactions.index(t)}" assert stmt.period_start <= t.booking_date <= stmt.period_end @pytest.mark.parametrize("filename,bank", CASES) def test_expected_values(filename, bank): path = FIXTURES / filename exp_path = FIXTURES / f"expected_{bank}.json" if not path.exists() or not exp_path.exists(): pytest.skip("Fixture oder expected-Datei fehlt") stmt = parse_pdf(path) exp = json.loads(exp_path.read_text()) assert len(stmt.transactions) == exp["transaction_count"] for c in exp["spot_checks"]: t = stmt.transactions[c["index"]] assert str(t.booking_date) == c["booking_date"] assert str(t.amount) == c["amount"] assert c["counterparty_contains"].lower() in t.counterparty.lower() assert c["purpose_contains"].lower() in t.purpose.lower()