Part 1 covered converting the contents of a DataTable into CSV format. Part 2 explained how to read a CSV file back into a DataTable.
Finally we will look at some test cases for use with NUnit, a very important tool that I'll describe in more detail in an upcoming article. There is quite a bit of code, but it is all very simple and easy to understand. Each method marked with [Test] will be called by NUnit and run one of the CSV related methods in turn. Assert statements will then check if the returned values are valid or not.
using System.Data;
using System.IO;
using NUnit.Framework;
namespace CsvParser
{
[TestFixture]
public class TestCsvParser
{
[Test]
public void UnquotedLine()
{
DataTable table = CsvParser.Parse("one,two,three");
Assert.IsNotNull(table);
Assert.AreEqual(3, table.Columns.Count);
Assert.AreEqual(1, table.Rows.Count);
Assert.AreEqual("one", table.Rows[0][0]);
Assert.AreEqual("two", table.Rows[0][1]);
Assert.AreEqual("three", table.Rows[0][2]);
}
[Test]
public void QuotedLine()
{
DataTable table = CsvParser.Parse("\"one\",\"two\",\"three\"");
Assert.IsNotNull(table);
Assert.AreEqual(3, table.Columns.Count);
Assert.AreEqual(1, table.Rows.Count);
Assert.AreEqual("one", table.Rows[0][0]);
Assert.AreEqual("two", table.Rows[0][1]);
Assert.AreEqual("three", table.Rows[0][2]);
}
[Test]
public void TwoLines()
{
DataTable table = CsvParser.Parse("one,two,three\nfour,five,six\n");
Assert.IsNotNull(table);
Assert.AreEqual(3, table.Columns.Count);
Assert.AreEqual(2, table.Rows.Count);
Assert.AreEqual("one", table.Rows[0][0]);
Assert.AreEqual("two", table.Rows[0][1]);
Assert.AreEqual("three", table.Rows[0][2]);
Assert.AreEqual("four", table.Rows[1][0]);
Assert.AreEqual("five", table.Rows[1][1]);
Assert.AreEqual("six", table.Rows[1][2]);
}
[Test]
public void QuotedMultilineValue()
{
DataTable table = CsvParser.Parse(
"\"one\n\"\"beer\"\"\",\"\"\"two\"\"\nbeers\",\"three\nbeers\"");
Assert.IsNotNull(table);
Assert.AreEqual(3, table.Columns.Count);
Assert.AreEqual(1, table.Rows.Count);
Assert.AreEqual("one\n\"beer\"", table.Rows[0][0]);
Assert.AreEqual("\"two\"\nbeers", table.Rows[0][1]);
Assert.AreEqual("three\nbeers", table.Rows[0][2]);
}
[Test]
public void Headers()
{
DataTable table = CsvParser.Parse(
"First,Last,Email\nAndreas,Knab,knabar@yahoo.com", true);
Assert.IsNotNull(table);
Assert.AreEqual(3, table.Columns.Count);
Assert.AreEqual(1, table.Rows.Count);
Assert.AreEqual("Andreas", table.Rows[0]["First"]);
Assert.AreEqual("Knab", table.Rows[0]["Last"]);
Assert.AreEqual("knabar@yahoo.com", table.Rows[0]["Email"]);
}
[Test]
public void TrailingNewlines()
{
DataTable table = CsvParser.Parse("test\n\n\n\n\n\n");
Assert.IsNotNull(table);
Assert.AreEqual(1, table.Columns.Count);
Assert.AreEqual(6, table.Rows.Count);
Assert.AreEqual("test", table.Rows[0][0]);
}
[Test]
public void Newlines()
{
DataTable table = CsvParser.Parse("test1\x0Atest2\x0Dtest3\x0D\x0Atest4");
Assert.IsNotNull(table);
Assert.AreEqual(1, table.Columns.Count);
Assert.AreEqual(4, table.Rows.Count);
Assert.AreEqual("test1", table.Rows[0][0]);
Assert.AreEqual("test2", table.Rows[1][0]);
Assert.AreEqual("test3", table.Rows[2][0]);
Assert.AreEqual("test4", table.Rows[3][0]);
}
}
}
Second, the opposite route – testing the CsvWriter. Since it takes quite a bit of effort to completely populate a DataTable, I'll cheat and create the DataTable using the CsvParser, which has been tested separately and is known to work.
using System.Data;
using System.IO;
using NUnit.Framework;
using CsvParser;
namespace CsvWriter
{
[TestFixture]
public class TestCsvWriter
{
[Test]
public void PlainText()
{
string s = "one,two,three\n";
DataTable table = CsvParser.Parse(s);
string t = CsvWriter.WriteToString(table, false, false);
Assert.AreEqual(s, t);
}
[Test]
public void QuotedText()
{
string s = "\"one\",\"two\",\"three\"\n";
DataTable table = CsvParser.Parse(s);
string t = CsvWriter.WriteToString(table, false, true);
Assert.AreEqual(s, t);
}
[Test]
public void MultiLineText()
{
string s = "\"one\nline\",\"two\nline\",\"three\nline\"\n";
DataTable table = CsvParser.Parse(s);
string t = CsvWriter.WriteToString(table, false, false);
Assert.AreEqual(s, t);
}
[Test]
public void Headers()
{
string s = "First,Last,Email\nAndreas,Knab,knabar@yahoo.com\n";
DataTable table = CsvParser.Parse(s, true);
string t = CsvWriter.WriteToString(table, true, false);
Assert.AreEqual(s, t);
}
}
}
And that's it! There are more special cases that could be tested, especially invalid input like non-CSV files, but technically everything can be interpreted as CSV, so the question would be what output to expect.
As I mentioned earlier, NUnit is worth a closer look, so check back for more.