Finance-Accounts/ar-aging-app/backend/tests/test_robustness.py

70 lines
2.6 KiB
Python

"""Error-handling / robustness tests: corrupt files, missing headers, duplicates."""
from __future__ import annotations
import os
import zipfile
from datetime import date
import openpyxl
import pytest
from app.core.xlsx_reader import TransactionReader, ParseError
from app.core.settlements import aggregate
def test_non_zip_file_raises_parseerror(tmp_path):
p = tmp_path / "garbage.xlsx"
p.write_bytes(b"this is not a zip file at all")
with pytest.raises(ParseError):
TransactionReader(str(p)).detect()
def test_truncated_xlsx_raises_parseerror(tmp_path):
"""Mimic the original 01-10 file: a valid xlsx truncated mid-stream."""
good = tmp_path / "good.xlsx"
wb = openpyxl.Workbook()
wb.active["A1"] = "x"
wb.save(good)
data = good.read_bytes()
bad = tmp_path / "truncated.xlsx"
bad.write_bytes(data[: len(data) // 2]) # cut off the central directory
with pytest.raises(ParseError):
TransactionReader(str(bad)).detect()
def test_workbook_without_transaction_header_raises(tmp_path):
p = tmp_path / "notxn.xlsx"
wb = openpyxl.Workbook()
ws = wb.active
ws.append(["hello", "world"])
ws.append(["foo", "bar"])
wb.save(p)
with pytest.raises(ParseError):
TransactionReader(str(p)).detect()
def test_duplicate_detection_counts_not_drops():
def rec(sid, total, oid, ttype="Order", acct="Standard Orders"):
return {"settlement_id": sid, "txn_type": ttype, "account_type": acct,
"order_id": oid, "sku": "SKU1", "date_time": "Jan 15, 2026 1:00:00 PM PST",
"total": total, "_date": date(2026, 1, 15), "_marketplace": "USA",
"_source_file": "f.xlsx", "_source_row": 9}
rows = [rec("200", 10.0, "A"), rec("200", 20.0, "B"), rec("200", 30.0, "C")]
dupes = [rec("200", 10.0, "A"), rec("200", 20.0, "B")] # two exact duplicates
agg = aggregate(rows + dupes)
assert agg.duplicate_count == 2
# duplicates are NOT dropped from the total (surfaced, not silently removed)
assert agg.settlements[("USA", "Standard Orders", "200")].order_total == pytest.approx(90.0)
assert len(agg.duplicate_samples) == 2
def test_amount_and_int_coercion(tmp_path):
"""Blank amounts -> 0.0; bad quantity -> None; ids strip trailing .0."""
from app.core.xlsx_reader import _convert
assert _convert("total", "") == 0.0
assert _convert("total", None) == 0.0
assert _convert("total", "12.5") == 12.5
assert _convert("total", "notnum") == 0.0
assert _convert("quantity", "3") == 3
assert _convert("settlement_id", "25468048861.0") == "25468048861"