142 lines
5.0 KiB
Python
142 lines
5.0 KiB
Python
"""Testes do app: fallback de data, autenticação e CRUD de documentos."""
|
|
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
from datetime import date
|
|
from pathlib import Path
|
|
|
|
|
|
class DateFallbackTests(unittest.TestCase):
|
|
def test_iso_date_is_kept(self):
|
|
from app.dates import resolve_purchase_date
|
|
|
|
self.assertEqual(resolve_purchase_date("2026-06-09"), "2026-06-09")
|
|
|
|
def test_br_date_is_normalized(self):
|
|
from app.dates import resolve_purchase_date
|
|
|
|
self.assertEqual(resolve_purchase_date("09/06/2026"), "2026-06-09")
|
|
|
|
def test_illegible_date_falls_back_to_first_of_month(self):
|
|
from app.dates import resolve_purchase_date
|
|
|
|
ref = date(2026, 7, 24)
|
|
self.assertEqual(resolve_purchase_date("ilegível", reference=ref), "2026-07-01")
|
|
self.assertEqual(resolve_purchase_date(None, reference=ref), "2026-07-01")
|
|
self.assertEqual(resolve_purchase_date("", reference=ref), "2026-07-01")
|
|
|
|
def test_invalid_calendar_date_falls_back(self):
|
|
from app.dates import resolve_purchase_date
|
|
|
|
ref = date(2026, 7, 24)
|
|
self.assertEqual(resolve_purchase_date("2026-13-40", reference=ref), "2026-07-01")
|
|
|
|
|
|
class PasswordTests(unittest.TestCase):
|
|
def test_hash_and_verify(self):
|
|
from app import auth
|
|
|
|
h = auth.hash_password("segredo-forte")
|
|
self.assertTrue(auth.verify_password("segredo-forte", h))
|
|
self.assertFalse(auth.verify_password("errada", h))
|
|
|
|
|
|
class CrudTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
os.environ["DB_PATH"] = str(Path(self._tmp.name) / "crud.sqlite3")
|
|
# zera o cache de settings para pegar o DB_PATH novo
|
|
from app.config import get_settings
|
|
|
|
get_settings.cache_clear()
|
|
|
|
def tearDown(self):
|
|
os.environ.pop("DB_PATH", None)
|
|
from app.config import get_settings
|
|
|
|
get_settings.cache_clear()
|
|
self._tmp.cleanup()
|
|
|
|
def test_create_update_delete_list(self):
|
|
from app import database as db
|
|
|
|
with db.session() as conn:
|
|
doc_id = db.create_fiscal(
|
|
conn, purchase_date="2026-07-01", supplier_name="Padaria X", total_paid=10.0
|
|
)
|
|
self.assertEqual(db.overall_totals(conn)["count"], 1)
|
|
|
|
db.update_fiscal(
|
|
conn, doc_id, purchase_date="2026-07-02", supplier_name="Padaria Y", total_paid=12.5
|
|
)
|
|
row = db.get_fiscal(conn, doc_id)
|
|
self.assertEqual(row["supplier_name"], "Padaria Y")
|
|
self.assertEqual(row["total_paid"], 12.5)
|
|
|
|
rows = db.list_fiscal(conn, supplier="Padaria")
|
|
self.assertEqual(len(rows), 1)
|
|
|
|
db.delete_fiscal(conn, doc_id)
|
|
self.assertEqual(db.overall_totals(conn)["count"], 0)
|
|
|
|
|
|
class StagingGateTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
os.environ["DB_PATH"] = str(Path(self._tmp.name) / "stage.sqlite3")
|
|
from app.config import get_settings
|
|
|
|
get_settings.cache_clear()
|
|
|
|
def tearDown(self):
|
|
os.environ.pop("DB_PATH", None)
|
|
from app.config import get_settings
|
|
|
|
get_settings.cache_clear()
|
|
self._tmp.cleanup()
|
|
|
|
def _stage(self, conn, batch_id, upload_id, **over):
|
|
base = dict(
|
|
upload_id=upload_id, batch_id=batch_id, source_file_name="f.pdf",
|
|
source_page=None, source_location="f.pdf", raw_text="",
|
|
purchase_date="2026-07-01", supplier_name="Loja", total_paid=10.0,
|
|
confidence="high", field_confidence={}, legible=True,
|
|
uncertain_fields=[], extractor="local",
|
|
)
|
|
base.update(over)
|
|
from app import database as db
|
|
|
|
return db.insert_detected(conn, **base)
|
|
|
|
def test_incomplete_row_counts_as_pending_and_is_not_imported(self):
|
|
from app import database as db
|
|
|
|
with db.session() as conn:
|
|
batch = db.create_batch(conn)
|
|
up = db.insert_upload(conn, batch, "f.pdf", Path("f.pdf"), "application/pdf", 1)
|
|
self._stage(conn, batch, up) # completo
|
|
# legível mas SEM fornecedor -> incompleto, deve contar como pendente
|
|
self._stage(conn, batch, up, supplier_name=None, legible=True)
|
|
|
|
summary = db.batch_summary(conn, batch)
|
|
self.assertEqual(summary["count"], 2)
|
|
self.assertEqual(summary["incompletos"], 1)
|
|
self.assertEqual(summary["pendentes"], 1)
|
|
|
|
def test_confirm_only_promotes_complete_rows(self):
|
|
from app import database as db
|
|
|
|
with db.session() as conn:
|
|
batch = db.create_batch(conn)
|
|
up = db.insert_upload(conn, batch, "f.pdf", Path("f.pdf"), "application/pdf", 1)
|
|
self._stage(conn, batch, up, supplier_name="Loja A", total_paid=10.0)
|
|
self._stage(conn, batch, up, supplier_name="Loja B", total_paid=20.0)
|
|
inserted = db.confirm_batch(conn, batch)
|
|
self.assertEqual(inserted, 2)
|
|
self.assertEqual(db.overall_totals(conn)["total"], 30.0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|