import datetime from io import BytesIO import openpyxl import pytest from omniread import ( # core Content, ContentType, # xlsx FileSystemXlsxClient, XlsxParser, XlsxScraper, ) def _fixture_xlsx_bytes() -> bytes: wb = openpyxl.Workbook() ws = wb.active ws.title = "Statement" ws.append(["DETAILED STATEMENT", None, None, ""]) ws.append([]) ws.append( [ "S No", "Value Date", "Txn Date", "Remarks", "Withdrawal", "Deposit", "Balance", ] ) ws.append( [ 1, "01/06/2026", "01/06/2026", "UPI/NPCI BHIM/bhimcashback@h/B", 0.0, 10.0, 250285.24, ] ) row = 4 ws.cell(row=row, column=5).value = 100.0 # ensure float rendering path buf = BytesIO() wb.save(buf) return buf.getvalue() @pytest.fixture def xlsx_bytes() -> bytes: return _fixture_xlsx_bytes() @pytest.fixture def xlsx_path(tmp_path, xlsx_bytes): p = tmp_path / "statement.xlsx" p.write_bytes(xlsx_bytes) return p def test_content_type_value(): assert ContentType.XLSX.value == ( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) def test_scraper_round_trip(xlsx_path, xlsx_bytes): scraper = XlsxScraper(client=FileSystemXlsxClient()) content = scraper.fetch(xlsx_path) assert content.raw == xlsx_bytes assert content.content_type is ContentType.XLSX def test_client_missing_file_raises(tmp_path): with pytest.raises(FileNotFoundError): FileSystemXlsxClient().fetch(tmp_path / "nope.xlsx") def test_client_directory_raises(tmp_path): with pytest.raises(ValueError): FileSystemXlsxClient().fetch(tmp_path) def test_parser_rows_skip_empty_and_trim(xlsx_bytes): parser = XlsxParser( Content(raw=xlsx_bytes, source="mem", content_type=ContentType.XLSX) ) rows = parser.rows() # empty row dropped by skip_empty; metadata + header + data remain assert len(rows) == 3 assert rows[0] == ["DETAILED STATEMENT"] header = rows[1] assert header[:7] == [ "S No", "Value Date", "Txn Date", "Remarks", "Withdrawal", "Deposit", "Balance", ] data = rows[2] assert data[3] == "UPI/NPCI BHIM/bhimcashback@h/B" assert data[6] == "250285.24" def test_parser_keep_empty_rows(xlsx_bytes): parser = XlsxParser( Content(raw=xlsx_bytes, source="mem", content_type=ContentType.XLSX) ) rows = parser.rows(skip_empty=False) assert len(rows) == 4 # includes blank second row and padded metadata row def test_parser_sheet_selection_and_names(xlsx_bytes): parser = XlsxParser( Content(raw=xlsx_bytes, source="mem", content_type=ContentType.XLSX) ) assert parser.sheet_names == ["Statement"] assert parser.rows(sheet="Statement") == parser.rows(sheet=0) assert parser.parse() == parser.rows() with pytest.raises(ValueError, match="not found"): parser.rows(sheet="Missing") def test_parser_date_cell_isoformat(): wb = openpyxl.Workbook() ws = wb.active ws.append([datetime.date(2026, 6, 1), "x"]) buf = BytesIO() wb.save(buf) parser = XlsxParser( Content(raw=buf.getvalue(), source="mem", content_type=ContentType.XLSX) ) # openpyxl surfaces date cells as datetime; ISO rendering keeps determinism assert parser.parse()[0][0] == "2026-06-01T00:00:00" def test_parser_rejects_non_xlsx_content(): with pytest.raises(ValueError, match="does not support"): XlsxParser( Content(raw=b"", source="mem", content_type=ContentType.HTML) )