xlsx-and-csv-read (#3)
Reviewed-on: #3 Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com> Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
This commit is contained in:
118
tests/test_xlsx_simple.py
Normal file
118
tests/test_xlsx_simple.py
Normal file
@@ -0,0 +1,118 @@
|
||||
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"<html></html>", source="mem", content_type=ContentType.HTML))
|
||||
Reference in New Issue
Block a user