@@ -262,6 +262,100 @@ public void TestExportAsMemoryStream()
262262 var expectedCsv = "sep=,\r \n Region,Sales,Date Opened\r \n \" Los Angeles, USA\" ,100000,2003-12-31\r \n \" Canberra \" \" in\" \" Australia\" ,50000,2005-01-01 09:30:00" ;
263263 Assert . AreEqual ( expectedCsv , contentWithoutBom . Trim ( ) ) ;
264264 }
265+
266+ [ TestMethod ]
267+ public void TestMakeValueCsvFriendly ( )
268+ {
269+ Assert . AreEqual ( "" , CsvExport . MakeValueCsvFriendly ( null ) ) ;
270+ Assert . AreEqual ( "123" , CsvExport . MakeValueCsvFriendly ( 123 ) ) ;
271+ Assert . AreEqual ( "\" Los Angeles, USA\" " , CsvExport . MakeValueCsvFriendly ( "Los Angeles, USA" ) ) ;
272+ Assert . AreEqual ( "\" \" \" quoted\" \" \" " , CsvExport . MakeValueCsvFriendly ( "\" quoted\" " ) ) ;
273+ Assert . AreEqual ( "2003-12-31" , CsvExport . MakeValueCsvFriendly ( new DateTime ( 2003 , 12 , 31 ) ) ) ;
274+ Assert . AreEqual ( "2005-01-01 09:30:00" , CsvExport . MakeValueCsvFriendly ( new DateTime ( 2005 , 1 , 1 , 9 , 30 , 0 ) ) ) ;
275+
276+ // custom separator - semicolon triggers quoting, comma does not
277+ Assert . AreEqual ( "a,b" , CsvExport . MakeValueCsvFriendly ( "a,b" , ';' ) ) ;
278+ Assert . AreEqual ( "\" a;b\" " , CsvExport . MakeValueCsvFriendly ( "a;b" , ';' ) ) ;
279+ }
280+
281+ [ TestMethod ]
282+ public void TestNewColumnIntroducedByLaterRow ( )
283+ {
284+ var myExport = new CsvExport ( ) ;
285+ myExport . AddRow ( ) ;
286+ myExport [ "A" ] = 1 ;
287+
288+ myExport . AddRow ( ) ;
289+ myExport [ "A" ] = 2 ;
290+ myExport [ "B" ] = "new" ; //column B appears only starting from row 2
291+
292+ string csv = myExport . Export ( ) ;
293+ Assert . IsTrue ( csv . Trim ( ) == "sep=,\r \n A,B\r \n 1\r \n 2,new" , csv ) ;
294+ }
295+
296+ [ TestMethod ]
297+ public void TestWriteToStream ( )
298+ {
299+ var myExport = new CsvExport ( ) ;
300+ myExport . AddRow ( ) ;
301+ myExport [ "Region" ] = "Los Angeles, USA" ;
302+ myExport [ "Sales" ] = 100000 ;
303+
304+ using var ms = new MemoryStream ( ) ;
305+ myExport . WriteToStream ( ms ) ;
306+
307+ Assert . IsTrue ( ms . CanWrite , "Stream should not be closed by WriteToStream" ) ;
308+
309+ var content = Encoding . UTF8 . GetString ( ms . ToArray ( ) ) . Trim ( new char [ ] { '' } ) ;
310+ Assert . AreEqual ( "sep=,\r \n Region,Sales\r \n \" Los Angeles, USA\" ,100000" , content . Trim ( ) ) ;
311+ }
312+
313+ [ TestMethod ]
314+ public void TestCustomEncoding ( )
315+ {
316+ var myExport = new CsvExport ( ) ;
317+ myExport . AddRow ( ) ;
318+ myExport [ "Name" ] = "Москва" ; //non-ASCII
319+
320+ var bytes = myExport . ExportToBytes ( Encoding . Unicode ) ;
321+
322+ //UTF-16 LE BOM
323+ Assert . IsTrue ( bytes [ 0 ] == 0xFF && bytes [ 1 ] == 0xFE ) ;
324+
325+ var content = Encoding . Unicode . GetString ( bytes ) . Trim ( new char [ ] { '' } ) ;
326+ Assert . IsTrue ( content . Contains ( "Москва" ) ) ;
327+ }
328+
329+ [ TestMethod ]
330+ public void TestExportToBytesHasBom ( )
331+ {
332+ var myExport = new CsvExport ( ) ;
333+ myExport . AddRow ( ) ;
334+ myExport [ "Name" ] = "John" ;
335+
336+ var bytes = myExport . ExportToBytes ( ) ;
337+
338+ //UTF-8 BOM
339+ Assert . IsTrue ( bytes . Length >= 3 && bytes [ 0 ] == 0xEF && bytes [ 1 ] == 0xBB && bytes [ 2 ] == 0xBF ) ;
340+ }
341+
342+ [ TestMethod ]
343+ public void TestExportAndWriteToStreamMatch ( )
344+ {
345+ var myExport = new CsvExport ( ) ;
346+ myExport . AddRow ( ) ;
347+ myExport [ "Region" ] = "Canberra \" in\" Australia" ;
348+ myExport [ "Sales" ] = 50000 ;
349+ myExport [ "Date Opened" ] = new DateTime ( 2005 , 1 , 1 , 9 , 30 , 0 ) ;
350+
351+ string fromExport = myExport . Export ( ) ;
352+
353+ using var ms = new MemoryStream ( ) ;
354+ myExport . WriteToStream ( ms ) ;
355+ string fromStream = Encoding . UTF8 . GetString ( ms . ToArray ( ) ) . Trim ( new char [ ] { '' } ) ;
356+
357+ Assert . AreEqual ( fromExport , fromStream ) ;
358+ }
265359 }
266360
267361 public class MyClass
0 commit comments