package no.priv.garshol.duke.utils; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.InputStreamReader; import org.junit.Test; import static org.junit.Assert.fail; import static org.junit.Assert.assertTrue; import no.priv.garshol.duke.DukeException; public class CSVReaderTest { @Test public void testEmpty() throws IOException { String data = ""; CSVReader reader = new CSVReader(new StringReader(data)); compareRows("couldn't read empty file correctly", null, reader.next()); } @Test public void testOneRow() throws IOException { String data = "a,b,c"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowWithLineBreak() throws IOException { String data = "a,b,c\n"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testTwoRows() throws IOException { String data = "a,b,c\nd,e,f"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); row = reader.next(); compareRows("second row read incorrectly", new String[]{"d", "e", "f"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowQuotes() throws IOException { String data = "\"a\",\"b\",\"c\""; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowInconsistentQuotes() throws IOException { String data = "\"a\",b,\"c\""; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testTwoRowsQuotes() throws IOException { String data = "\"a\",\"b\",\"c\"\n\"d\",\"e\",\"f\""; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); row = reader.next(); compareRows("second row read incorrectly", new String[]{"d", "e", "f"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowQuotesLineBreak() throws IOException { String data = "\"a\",\"b\nc\",\"d\""; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b\nc", "d"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testTwoRowsRN() throws IOException { String data = "a,b,c\r\nd,e,f"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); row = reader.next(); compareRows("second row read incorrectly", new String[]{"d", "e", "f"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testTwoRowsR() throws IOException { String data = "a,b,c\rd,e,f"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); row = reader.next(); compareRows("second row read incorrectly", new String[]{"d", "e", "f"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testTwoRowsBuffering() throws IOException { String data = "aaa,bbb,ccc\nddd,eee,fff"; CSVReader reader = new CSVReader(new StringReader(data), 15, null); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"aaa", "bbb", "ccc"}, row); row = reader.next(); compareRows("second row read incorrectly", new String[]{"ddd", "eee", "fff"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowQuotesAndComma() throws IOException { String data = "aaa,\"b,b\",ccc"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"aaa", "b,b", "ccc"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowEmptyQuoted() throws IOException { String data = "aaa,\"\",ccc"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"aaa", "", "ccc"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowWithQuoteCharacters() throws IOException { String data = "TRMMMXN128F42936A5,\"Symphony No. 1 G minor \"\"Sinfonie Serieuse\"\"/Allegro con energia\",SOZVAPQ12A8C13B63C,\"Berwald: Symphonies Nos. 1/2/3/4\",AR2NS5Y1187FB5879D"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"TRMMMXN128F42936A5", "Symphony No. 1 G minor \"Sinfonie Serieuse\"/Allegro con energia", "SOZVAPQ12A8C13B63C", "Berwald: Symphonies Nos. 1/2/3/4", "AR2NS5Y1187FB5879D"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testOneRowWithQuoteCharacters2() throws IOException { String data = "\"\"\"quoted\"\"\""; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"\"quoted\""}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testSeparator() throws IOException { String data = "a;b;c\nd;e;f"; CSVReader reader = new CSVReader(new StringReader(data)); reader.setSeparator(';'); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"a", "b", "c"}, row); row = reader.next(); compareRows("second row read incorrectly", new String[]{"d", "e", "f"}, row); compareRows("reading not terminated correctly", null, reader.next()); } @Test public void testBigBadFile2() throws IOException { // the problem with this file is that it contains unbalanced quotes, // but now we've set the buffer size bigger than the file size. that // should lead to a different error message ClassLoader cloader = Thread.currentThread().getContextClassLoader(); InputStream istream = cloader.getResourceAsStream("big-bad.csv"); CSVReader reader = new CSVReader(new InputStreamReader(istream), 90000, "big-bad.csv"); try { String[] row = reader.next(); while (reader.next() != null) ; fail("Shouldn't accept malformed file"); } catch (DukeException e) { // error message must contain name of file assertTrue(e.getMessage().indexOf("big-bad.csv") != -1); } } @Test public void testBigBadFile() throws IOException { // the problem with this file is that it contains unbalanced quotes, // leading to a row that's longer than the buffer. that used to cause // a stack overflow crash. we verify that instead we get an error message ClassLoader cloader = Thread.currentThread().getContextClassLoader(); InputStream istream = cloader.getResourceAsStream("big-bad.csv"); CSVReader reader = new CSVReader(new InputStreamReader(istream), 65536, "big-bad.csv"); try { String[] row = reader.next(); while (reader.next() != null) ; fail("Shouldn't accept malformed file"); } catch (DukeException e) { // error message must contain name of file assertTrue(e.getMessage().indexOf("big-bad.csv") != -1); } } @Test public void testOneRowQuotesAndNewline() throws IOException { String data = "aaa,\"b,b\",\"ccc\"\n"; CSVReader reader = new CSVReader(new StringReader(data)); String[] row = reader.next(); compareRows("first row read incorrectly", new String[]{"aaa", "b,b", "ccc"}, row); compareRows("reading not terminated correctly", null, reader.next()); } // ===== UTILITIES private void compareRows(String msg, String[] row1, String[] row2) { if (row1 == row2) return; if (row1 == null && row2 != null) fail(msg + " expected null, but received " + toString(row2)); if (row1 != null && row2 == null) fail(msg + " expected " + toString(row1) + ", but received null"); boolean equals = row1.length == row2.length; for (int ix = 0; equals && ix < row1.length; ix++) if (!row1[ix].equals(row2[ix])) equals = false; if (!equals) fail(msg + " expected " + toString(row1) + ", but received " + toString(row2)); } public static String toString(String[] row) { if (row == null) return "null"; StringBuffer buf = new StringBuffer(); buf.append("["); for (int ix = 0; ix < row.length; ix++) { buf.append("\"" + row[ix] + "\""); if (ix + 1 < row.length) buf.append(", "); } buf.append("]"); return buf.toString(); } }