csv: Add a reader.
[nit.git] / lib / csv / test_csv.nit
index c176a67..074fced 100644 (file)
@@ -83,3 +83,120 @@ class TestCsvWriter
                        "1,,/\r\n",
                        "1::////#")
 end
+
+class TestCsvReader
+       super TestSuite
+
+       # The custom CSV format used in the tests.
+       private var custom_format = new CsvFormat('/', ':', "#")
+
+       # Expect to read `expected`.
+       #
+       # Parameters:
+       #
+       # * `skip_empty`: value of the `skip_empty` option.
+       # * `modal_escaping`: value of the `modal_escaping` option.
+       # * `input_rfc4180`: input in the RFC 4180 format.
+       # * `input_custom`: input in the custom CSV format.
+       # * `expected`: expected resulting table.
+       private fun expect(skip_empty: Bool,
+                       input_rfc4180: String,
+                       input_custom: String,
+                       expected: SequenceRead[SequenceRead[String]]) do
+               var istream: IStream
+               var reader: CsvReader
+               var i = 0
+
+               istream = new StringIStream(input_rfc4180)
+               reader = new CsvReader(istream)
+               reader.skip_empty = skip_empty
+               assert_table_equals("RFC 4180", reader, expected.iterator)
+
+               istream = new StringIStream(input_custom)
+               reader = new CsvReader.with_format(istream, custom_format)
+               reader.skip_empty = skip_empty
+               assert_table_equals("{custom_format.delimiter} " +
+                               "{custom_format.separator} " +
+                               "{custom_format.eol.escape_to_nit}", reader, expected.iterator)
+       end
+
+       # Check if tables are equal.
+       private fun assert_table_equals(format: String,
+                       actual: Iterator[SequenceRead[String]],
+                       expected: Iterator[SequenceRead[String]]) do
+               var i = 0
+
+               for actual_row in actual do
+                       assert expected.is_ok else fail(format,"Too many rows.")
+                       var expected_row = expected.item
+                       assert_row_equals(format, i, actual_row, expected_row)
+                       expected.next
+                       i += 1
+               end
+               assert not expected.is_ok else fail(format, "Not enough rows.")
+               expected.finish
+       end
+
+       # Check if rows are equal.
+       private fun assert_row_equals(format: String,
+                       row_index: Int,
+                       actual: SequenceRead[String],
+                       expected: SequenceRead[String]) do
+               assert actual == expected else
+                       fail(format, """
+At row {{{row_index}}}.
+Expecting: {{{expected.join("|")}}}
+Got: {{{actual.join("|")}}}""")
+               end
+       end
+
+       # Output an error message with an indication of the format used.
+       private fun fail(format: Text, message: Text) do
+               sys.stderr.write "\nFormat: {format}\n"
+               sys.stderr.write message
+               sys.stderr.write "\n"
+       end
+
+       fun test_empty do expect(false, "", "", new Array[Array[String]])
+
+       fun test_empty_eol do expect(false, "\r\n", "#", [[""]])
+
+       fun test_empty_skip do expect(true, "", "", new Array[Array[String]])
+
+       fun test_empty_skip1 do expect(true, "\r\n", "#", new Array[Array[String]])
+
+       fun test_empty_skip2 do expect(true, "\r\n\r\n", "##", new Array[Array[String]])
+
+       fun test_escaped do expect(false, "\"foo/\"\"\r\n,\"\r\n",
+                       "/foo//\"\r\n,/#", [["foo/\"\r\n,"]])
+
+       fun test_unescaped do expect(false, "foo bar\r\n",
+                       "foo bar#", [["foo bar"]])
+
+       fun test_escaped_no_eol do expect(false, "\"foo/\"\"\r\n,\"",
+                       "/foo//\"\r\n,/", [["foo/\"\r\n,"]])
+
+       fun test_unescaped_no_eol do expect(false, "foo bar",
+                       "foo bar", [["foo bar"]])
+
+       fun test_multiple_cells do expect(false, "\"1\",,\"/\"\r\n",
+                       "/1/::////#", [["1", "", "/"]])
+
+       fun test_multiple_cells_unescaped do expect(false, "1,,/\r\n",
+                       "1::////#", [["1", "", "/"]])
+
+       fun test_modal_escaping do expect(false, """a"b""/c","d"e""",
+                       """/ab"///c:d/e/""", [["""ab"/c""", "de"]])
+
+       fun test_skip_start do expect(true, "\r\n1,,/\r\n",
+                       "#1::////#", [["1", "", "/"]])
+
+       fun test_dont_skip_empty_delimited do expect(true, "\"\"\r\n",
+                       "//#", [[""]])
+
+       fun test_dont_skip_multiple_empty_cells do expect(true, ",\r\n",
+                       ":#", [["",""]])
+
+       fun test_mutiple_rows do expect(false, "\"a\r\nb#\",c\r\nd,\r\n,e\r\n",
+                       "/a\r\nb#/:c#d:#:e#", [["a\r\nb#", "c"], ["d", ""], ["", "e"]])
+end