Skip to content

Commit 60b01bb

Browse files
committed
test: verify CSV structural validity (headers, row/column count)
1 parent fae10fe commit 60b01bb

1 file changed

Lines changed: 31 additions & 2 deletions

File tree

‎tests/unit/test_datasets_export_csv.py‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,14 @@ def test_default_sanitizes_formula_prefixes(self, tmp_path):
3030
filepath = export_csv(data, tmp_path / "out.csv")
3131

3232
with open(filepath, newline="", encoding="utf-8") as f:
33-
rows = list(csv.DictReader(f))
34-
33+
reader = csv.DictReader(f)
34+
assert reader.fieldnames == ["name"]
35+
rows = list(reader)
36+
37+
# Sanitization must not drop, merge, or duplicate rows/columns even
38+
# though several payloads contain commas and embedded quotes that
39+
# exercise the CSV module's own quoting.
40+
assert len(rows) == len(FORMULA_PAYLOADS)
3541
for row, payload in zip(rows, FORMULA_PAYLOADS):
3642
# Reader gives us the value with the CSV-level quoting already
3743
# stripped, so a leading "'" means our sanitizer ran.
@@ -106,3 +112,26 @@ def test_empty_data_still_touches_file(self, tmp_path):
106112
filepath = export_csv([], tmp_path / "out.csv")
107113
assert filepath.exists()
108114
assert filepath.read_text(encoding="utf-8") == ""
115+
116+
def test_output_is_well_formed_csv_across_multiple_rows_and_columns(self, tmp_path):
117+
# Mixes sanitized and unsanitized values across several rows/columns
118+
# to make sure escaping one cell doesn't corrupt column alignment,
119+
# row count, or the header for the rest of the file.
120+
data = [
121+
{"name": '=HYPERLINK("https://x","y")', "price": "9.99", "note": "ok"},
122+
{"name": "Regular Item", "price": "-1.00", "note": "@mention in review"},
123+
{"name": "Another Item", "price": "5.00", "note": "plain text"},
124+
]
125+
filepath = export_csv(data, tmp_path / "out.csv")
126+
127+
with open(filepath, newline="", encoding="utf-8") as f:
128+
reader = csv.DictReader(f)
129+
assert reader.fieldnames == ["name", "price", "note"]
130+
rows = list(reader)
131+
132+
assert len(rows) == len(data)
133+
assert rows[0]["name"] == '\'=HYPERLINK("https://x","y")'
134+
assert rows[0]["price"] == "9.99"
135+
assert rows[1]["price"] == "'-1.00"
136+
assert rows[1]["note"] == "'@mention in review"
137+
assert rows[2] == {"name": "Another Item", "price": "5.00", "note": "plain text"}

0 commit comments

Comments
 (0)