"""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"