import io import pytest from openpyxl import Workbook from app.importing.parser import ImportParseError, parse_upload def _xlsx_bytes(rows: list[list[object]]) -> bytes: wb = Workbook() ws = wb.active for row in rows: ws.append(row) buffer = io.BytesIO() wb.save(buffer) return buffer.getvalue() def test_csv_semicolon_with_bom(): raw = "Prénom;Nom;Email\nAlex;Martin;a@b.fr\n".encode() table = parse_upload("benevoles.csv", raw) assert table.headers == ["Prénom", "Nom", "Email"] assert table.as_dicts() == [ {"Prénom": "Alex", "Nom": "Martin", "Email": "a@b.fr"} ] def test_csv_comma_delimiter(): raw = b"first,last\nSam,Nguyen\n" table = parse_upload("x.csv", raw) assert table.headers == ["first", "last"] assert table.rows == [["Sam", "Nguyen"]] def test_csv_blank_lines_dropped_and_short_rows_padded(): raw = b"a;b;c\n\n1;2\n3;4;5;6\n" table = parse_upload("x.csv", raw) assert table.rows == [["1", "2", ""], ["3", "4", "5"]] def test_xlsx_detected_by_magic_without_extension(): data = _xlsx_bytes([["Prénom", "Nom"], ["Alex", "Martin"], [None, None]]) table = parse_upload("upload.dat", data) assert table.headers == ["Prénom", "Nom"] assert table.rows == [["Alex", "Martin"]] def test_xlsx_numeric_cells_become_plain_strings(): data = _xlsx_bytes([["Nom", "Tel"], ["Martin", 601020304]]) table = parse_upload("x.xlsx", data) assert table.rows == [["Martin", "601020304"]] def test_empty_file_raises(): with pytest.raises(ImportParseError) as err: parse_upload("x.csv", b"") assert err.value.code == "import.error.empty_file" def test_unreadable_xlsx_raises(): with pytest.raises(ImportParseError) as err: parse_upload("x.xlsx", b"not a real workbook") assert err.value.code == "import.error.unreadable_file"