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