View Javadoc
1   package com.opencsv;
2   
3   import com.opencsv.enums.CSVReaderNullFieldIndicator;
4   import com.opencsv.exceptions.CsvMultilineLimitBrokenException;
5   import com.opencsv.exceptions.CsvValidationException;
6   import org.junit.jupiter.api.*;
7   
8   import java.io.FileReader;
9   import java.io.IOException;
10  import java.util.Locale;
11  
12  import static org.junit.jupiter.api.Assertions.*;
13  
14  public class CSVParserTest {
15  
16      private static final String ESCAPE_TEST_STRING = "\\\\1\\2\\\"3\\"; // \\1\2\"\
17      CSVParser csvParser;
18      private static Locale systemLocale;
19  
20      @BeforeAll
21      public static void storeSystemLocale() {
22          systemLocale = Locale.getDefault();
23      }
24  
25      @AfterEach
26      public void setSystemLocaleBackToDefault() {
27          Locale.setDefault(systemLocale);
28      }
29  
30      @BeforeEach
31      public void setUp() {
32          Locale.setDefault(Locale.US);
33          csvParser = new CSVParser();
34      }
35  
36      @Test
37      public void testParseLine() throws Exception {
38          String[] nextItem = csvParser.parseLine("This, is, a, test.");
39          assertEquals(4, nextItem.length);
40          assertEquals("This", nextItem[0]);
41          assertEquals(" is", nextItem[1]);
42          assertEquals(" a", nextItem[2]);
43          assertEquals(" test.", nextItem[3]);
44      }
45  
46      @Test
47      public void parseSimpleString() throws IOException {
48  
49          String[] nextLine = csvParser.parseLine("a,b,c");
50          assertEquals(3, nextLine.length);
51          assertEquals("a", nextLine[0]);
52          assertEquals("b", nextLine[1]);
53          assertEquals("c", nextLine[2]);
54          assertFalse(csvParser.isPending());
55      }
56  
57      @Test
58      public void parseEscapingTheEscapeCharacter() throws IOException {
59          String[] nextLine = csvParser.parseLine("\"a\",\"b\\\\c\",\"d\"");
60          assertEquals(3, nextLine.length);
61          assertEquals("a", nextLine[0]);
62          assertEquals("b\\c", nextLine[1]);
63          assertEquals("d", nextLine[2]);
64          assertFalse(csvParser.isPending());
65      }
66  
67      @Test
68      public void parseEscapingTheSeparatorCharacter() throws IOException {
69          String[] nextLine = csvParser.parseLine("\"a\",\"b\\,c\",\"d\"");
70          assertEquals(3, nextLine.length);
71          assertEquals("a", nextLine[0]);
72          assertEquals("b,c", nextLine[1]);
73          assertEquals("d", nextLine[2]);
74          assertFalse(csvParser.isPending());
75      }
76  
77      @Test
78      public void parseEscapingTheSeparatorCharacterWithoutQuotes() throws IOException {
79          String[] nextLine = csvParser.parseLine("a,b\\,c,d");
80          assertEquals(3, nextLine.length);
81          assertEquals("a", nextLine[0]);
82          assertEquals("b,c", nextLine[1]);
83          assertEquals("d", nextLine[2]);
84          assertFalse(csvParser.isPending());
85      }
86  
87      @Test
88      public void parseEscapingTheFirstCharacter() throws IOException {
89  
90          // Escaping a separator
91          String[] nextLine = csvParser.parseLine("\\,a,b,c,d");
92          assertEquals(4, nextLine.length);
93          assertEquals(",a", nextLine[0]);
94          assertEquals("b", nextLine[1]);
95          assertEquals("c", nextLine[2]);
96          assertEquals("d", nextLine[3]);
97          assertFalse(csvParser.isPending());
98  
99          // Escaping an escape
100         nextLine = csvParser.parseLine("\\\\a,b,c,d");
101         assertEquals(4, nextLine.length);
102         assertEquals("\\a", nextLine[0]);
103         assertEquals("b", nextLine[1]);
104         assertEquals("c", nextLine[2]);
105         assertEquals("d", nextLine[3]);
106         assertFalse(csvParser.isPending());
107 
108         // Escaping a quotation character
109         nextLine = csvParser.parseLine("\\\"a,b,c,d");
110         assertEquals(4, nextLine.length);
111         assertEquals("\"a", nextLine[0]);
112         assertEquals("b", nextLine[1]);
113         assertEquals("c", nextLine[2]);
114         assertEquals("d", nextLine[3]);
115         assertFalse(csvParser.isPending());
116     }
117 
118     @Test
119     public void parseSimpleQuotedString() throws IOException {
120 
121         String[] nextLine = csvParser.parseLine("\"a\",\"b\",\"c\"");
122         assertEquals(3, nextLine.length);
123         assertEquals("a", nextLine[0]);
124         assertEquals("b", nextLine[1]);
125         assertEquals("c", nextLine[2]);
126         assertFalse(csvParser.isPending());
127     }
128 
129     @Test
130     public void parseSimpleQuotedStringWithSpaces() throws IOException {
131         ICSVParser parser = new CSVParserBuilder()
132                 .withStrictQuotes(true)
133                 .withIgnoreLeadingWhiteSpace(false)
134                 .build();
135 
136         String[] nextLine = parser.parseLine(" \"a\" , \"b\" , \"c\" ");
137         assertEquals(3, nextLine.length);
138         assertEquals("a", nextLine[0]);
139         assertEquals("b", nextLine[1]);
140         assertEquals("c", nextLine[2]);
141         assertFalse(parser.isPending());
142     }
143 
144     /**
145      * Tests quotes in the middle of an element.
146      *
147      * @throws IOException if bad things happen
148      */
149     @Test
150     public void testParsedLineWithInternalQuote() throws IOException {
151 
152         String[] nextLine = csvParser.parseLine("a,123\"4\"567,c");
153         assertEquals(3, nextLine.length);
154 
155         assertEquals("123\"4\"567", nextLine[1]);
156 
157     }
158 
159     @Test
160     public void parseQuotedStringWithCommas() throws IOException {
161         String[] nextLine = csvParser.parseLine("a,\"b,b,b\",c");
162         assertEquals("a", nextLine[0]);
163         assertEquals("b,b,b", nextLine[1]);
164         assertEquals("c", nextLine[2]);
165         assertEquals(3, nextLine.length);
166     }
167 
168     @Test
169     public void parseQuotedStringWithDefinedSeparator() throws IOException {
170         csvParser = new CSVParserBuilder().withSeparator(':').build();
171 
172         String[] nextLine = csvParser.parseLine("a:\"b:b:b\":c");
173         assertEquals("a", nextLine[0]);
174         assertEquals("b:b:b", nextLine[1]);
175         assertEquals("c", nextLine[2]);
176         assertEquals(3, nextLine.length);
177     }
178 
179     @Test
180     public void parseQuotedStringWithDefinedSeparatorAndQuote() throws IOException {
181         csvParser = new CSVParserBuilder()
182                 .withSeparator(':')
183                 .withQuoteChar('\'')
184                 .build();
185 
186         String[] nextLine = csvParser.parseLine("a:'b:b:b':c");
187         assertEquals("a", nextLine[0]);
188         assertEquals("b:b:b", nextLine[1]);
189         assertEquals("c", nextLine[2]);
190         assertEquals(3, nextLine.length);
191     }
192 
193     @Test
194     public void parseEmptyElements() throws IOException {
195         String[] nextLine = csvParser.parseLine(",,");
196         assertEquals(3, nextLine.length);
197         assertEquals("", nextLine[0]);
198         assertEquals("", nextLine[1]);
199         assertEquals("", nextLine[2]);
200     }
201 
202     @Test
203     public void parseMultiLinedQuoted() throws IOException {
204         String[] nextLine = csvParser.parseLine("a,\"PO Box 123,\nKippax,ACT. 2615.\nAustralia\",d.\n");
205         assertEquals(3, nextLine.length);
206         assertEquals("a", nextLine[0]);
207         assertEquals("PO Box 123,\nKippax,ACT. 2615.\nAustralia", nextLine[1]);
208         assertEquals("d.\n", nextLine[2]);
209     }
210 
211     @Test
212     public void parseMultiLinedQuotedWithCarriageReturns() throws IOException {
213         String[] nextLine = csvParser.parseLine("a,\"PO Box 123,\r\nKippax,ACT. 2615.\r\nAustralia\",d.\n");
214         assertEquals(3, nextLine.length);
215         assertEquals("a", nextLine[0]);
216         assertEquals("PO Box 123,\r\nKippax,ACT. 2615.\r\nAustralia", nextLine[1]);
217         assertEquals("d.\n", nextLine[2]);
218     }
219 
220     @Test
221     public void testADoubleQuoteAsDataElement() throws IOException {
222 
223         String[] nextLine = csvParser.parseLine("a,\"\"\"\",c");// a,"""",c
224 
225         assertEquals(3, nextLine.length);
226 
227         assertEquals("a", nextLine[0]);
228         assertEquals(1, nextLine[1].length());
229         assertEquals("\"", nextLine[1]);
230         assertEquals("c", nextLine[2]);
231 
232     }
233 
234     @Test
235     public void testEscapedDoubleQuoteAsDataElement() throws IOException {
236 
237         String[] nextLine = csvParser.parseLine("\"test\",\"this,test,is,good\",\"\\\"test\\\"\",\"\\\"quote\\\"\""); // "test","this,test,is,good","\"test\",\"quote\""
238 
239         assertEquals(4, nextLine.length);
240 
241         assertEquals("test", nextLine[0]);
242         assertEquals("this,test,is,good", nextLine[1]);
243         assertEquals("\"test\"", nextLine[2]);
244         assertEquals("\"quote\"", nextLine[3]);
245 
246     }
247 
248     @Test
249     public void parseQuotedQuoteCharacters() throws IOException {
250         String[] nextLine = csvParser.parseLineMulti("\"Glen \"\"The Man\"\" Smith\",Athlete,Developer\n");
251         assertEquals(3, nextLine.length);
252         assertEquals("Glen \"The Man\" Smith", nextLine[0]);
253         assertEquals("Athlete", nextLine[1]);
254         assertEquals("Developer\n", nextLine[2]);
255     }
256 
257     @Test
258     public void parseMultipleQuotes() throws IOException {
259         String[] nextLine = csvParser.parseLine("\"\"\"\"\"\",\"test\"\n"); // """""","test"  representing:  "", test
260         assertEquals("\"\"", nextLine[0]); // check the tricky situation
261         assertEquals("test\"\n", nextLine[1]); // make sure we didn't ruin the next field..
262         assertEquals(2, nextLine.length);
263     }
264 
265     @Test
266     public void parseTrickyString() throws IOException {
267         String[] nextLine = csvParser.parseLine("\"a\nb\",b,\"\nd\",e\n");
268         assertEquals(4, nextLine.length);
269         assertEquals("a\nb", nextLine[0]);
270         assertEquals("b", nextLine[1]);
271         assertEquals("\nd", nextLine[2]);
272         assertEquals("e\n", nextLine[3]);
273     }
274 
275     private String setUpMultiLineInsideQuotes() {
276         StringBuilder sb = new StringBuilder(ICSVParser.INITIAL_READ_SIZE);
277 
278         sb.append("Small test,\"This is a test across \ntwo lines.\"");
279 
280         return sb.toString();
281     }
282 
283     @Test
284     public void testAMultiLineInsideQuotes() throws IOException {
285 
286         String testString = setUpMultiLineInsideQuotes();
287 
288         String[] nextLine = csvParser.parseLine(testString);
289         assertEquals(2, nextLine.length);
290         assertEquals("Small test", nextLine[0]);
291         assertEquals("This is a test across \ntwo lines.", nextLine[1]);
292         assertFalse(csvParser.isPending());
293     }
294 
295     @Test
296     public void testStrictQuoteSimple() throws IOException {
297         csvParser = new CSVParserBuilder()
298                 .withStrictQuotes(true)
299                 .build();
300         String testString = "\"a\",\"b\",\"c\"";
301 
302         String[] nextLine = csvParser.parseLine(testString);
303         assertEquals(3, nextLine.length);
304         assertEquals("a", nextLine[0]);
305         assertEquals("b", nextLine[1]);
306         assertEquals("c", nextLine[2]);
307     }
308 
309     @Test
310     public void testNotStrictQuoteSimple() throws IOException {
311         csvParser = new CSVParserBuilder().build();
312         String testString = "\"a\",\"b\",\"c\"";
313 
314         String[] nextLine = csvParser.parseLine(testString);
315         assertEquals(3, nextLine.length);
316         assertEquals("a", nextLine[0]);
317         assertEquals("b", nextLine[1]);
318         assertEquals("c", nextLine[2]);
319     }
320 
321     @Test
322     public void testStrictQuoteWithSpacesAndTabs() throws IOException {
323         csvParser = new CSVParserBuilder()
324                 .withStrictQuotes(true)
325                 .build();
326         String testString = " \t      \"a\",\"b\"      \t       ,   \"c\"   ";
327 
328         String[] nextLine = csvParser.parseLine(testString);
329         assertEquals(3, nextLine.length);
330         assertEquals("a", nextLine[0]);
331         assertEquals("b", nextLine[1]);
332         assertEquals("c", nextLine[2]);
333     }
334 
335     /**
336      * Shows that without the strict quotes opencsv will read until the separator or the end of the line.
337      *
338      * @throws IOException But not really
339      */
340     @Test
341     public void testNotStrictQuoteWithSpacesAndTabs() throws IOException {
342         csvParser = new CSVParserBuilder().build();
343         String testString = " \t      \"a\",\"b\"      \t       ,   \"c\"   ";
344 
345         String[] nextLine = csvParser.parseLine(testString);
346         assertEquals(3, nextLine.length);
347         assertEquals("a", nextLine[0]);
348         assertEquals("b\"      \t       ", nextLine[1]);
349         assertEquals("c\"   ", nextLine[2]);
350     }
351 
352     @Test
353     public void testStrictQuoteWithGarbage() throws IOException {
354         csvParser = new CSVParserBuilder()
355                 .withStrictQuotes(true)
356                 .build();
357         String testString = "abc',!@#\",\\\"\"   xyz,";
358 
359         String[] nextLine = csvParser.parseLine(testString);
360         assertEquals(3, nextLine.length);
361         assertEquals("", nextLine[0]);
362         assertEquals(",\"", nextLine[1]);
363         assertEquals("", nextLine[2]);
364     }
365 
366     @Test
367     public void testCanIgnoreQuotations() throws IOException {
368         csvParser = new CSVParserBuilder()
369                 .withIgnoreQuotations(true)
370                 .build();
371         String testString = "Bob,test\",Beaumont,TX";
372 
373         String[] nextLine = csvParser.parseLine(testString);
374         assertEquals(4, nextLine.length);
375         assertEquals("Bob", nextLine[0]);
376         assertEquals("test", nextLine[1]);
377         assertEquals("Beaumont", nextLine[2]);
378         assertEquals("TX", nextLine[3]);
379     }
380 
381     @Test
382     public void testFalseIgnoreQuotations() {
383         csvParser = new CSVParserBuilder()
384                 .withIgnoreQuotations(false)
385                 .build();
386         String testString = "Bob,test\",Beaumont,TX";
387 
388         Assertions.assertThrows(IOException.class, () -> csvParser.parseLine(testString));
389     }
390 
391     /**
392      * This is an interesting issue where the data does not use quotes but IS
393      * using a quote within the field as an inch symbol.
394      * <p>So we want to keep that quote as part of the field and not as the
395      * start or end of a field.</p>
396      * <p>Test data are as follows.
397      * {@code
398      * RPO;2012;P; ; ; ;SDX;ACCESSORY WHEEL, 16", ALUMINUM, DESIGN 1
399      * RPO;2012;P; ; ; ;SDZ;ACCESSORY WHEEL - 17" - ALLOY - DESIGN 1}
400      * </p>
401      *
402      * @throws IOException But not really
403      */
404     @Test
405     public void testIssue3314579() throws IOException {
406         csvParser = new CSVParserBuilder()
407                 .withSeparator(';')
408                 .withIgnoreQuotations(true)
409                 .build();
410         String testString = "RPO;2012;P; ; ; ;SDX;ACCESSORY WHEEL, 16\", ALUMINUM, DESIGN 1";
411 
412         String[] nextLine = csvParser.parseLine(testString);
413         assertEquals(8, nextLine.length);
414         assertEquals("RPO", nextLine[0]);
415         assertEquals("2012", nextLine[1]);
416         assertEquals("P", nextLine[2]);
417         assertEquals(" ", nextLine[3]);
418         assertEquals(" ", nextLine[4]);
419         assertEquals(" ", nextLine[5]);
420         assertEquals("SDX", nextLine[6]);
421         assertEquals("ACCESSORY WHEEL, 16\", ALUMINUM, DESIGN 1", nextLine[7]);
422     }
423 
424     /**
425      * Test issue 2263439 where an escaped quote was causing the parse to fail.
426      * Special thanks to Chris Morris for fixing this (id 1979054)
427      *
428      * @throws IOException But not really
429      */
430     @Test
431     public void testIssue2263439() throws IOException {
432         csvParser = new CSVParserBuilder()
433                 .withSeparator(',')
434                 .withQuoteChar('\'')
435                 .build();
436 
437         String[] nextLine = csvParser.parseLine("865,0,'America\\'s_Most_Wanted','',294,0,0,0.734338696798625,'20081002052147',242429208,18448");
438 
439         assertEquals(11, nextLine.length);
440 
441         assertEquals("865", nextLine[0]);
442         assertEquals("0", nextLine[1]);
443         assertEquals("America's_Most_Wanted", nextLine[2]);
444         assertEquals("", nextLine[3]);
445         assertEquals("18448", nextLine[10]);
446 
447     }
448 
449     /**
450      * Test issue 2859181 where an escaped character before a character
451      * that did not need escaping was causing the parse to fail.
452      *
453      * @throws IOException But not really
454      */
455     @Test
456     public void testIssue2859181() throws IOException {
457         csvParser = new CSVParserBuilder().withSeparator(';').build();
458         String[] nextLine = csvParser.parseLine("field1;\\=field2;\"\"\"field3\"\"\""); // field1;\=field2;"""field3"""
459 
460         assertEquals(3, nextLine.length);
461 
462         assertEquals("field1", nextLine[0]);
463         assertEquals("=field2", nextLine[1]);
464         assertEquals("\"field3\"", nextLine[2]);
465 
466     }
467 
468     /**
469      * Test issue 2726363.
470      * <p>Data given:
471      * {@code
472      * "804503689","London",""London""shop","address","116.453182","39.918884"
473      * "453074125","NewYork","brief","address"","121.514683","31.228511"
474      * }</p>
475      * @throws IOException But not really
476      */
477     @Test
478     public void testIssue2726363() throws IOException {
479 
480         String[] nextLine = csvParser.parseLine("\"804503689\",\"London\",\"\"London\"shop\",\"address\",\"116.453182\",\"39.918884\"");
481 
482         assertEquals(6, nextLine.length);
483 
484 
485         assertEquals("804503689", nextLine[0]);
486         assertEquals("London", nextLine[1]);
487         assertEquals("\"London\"shop", nextLine[2]);
488         assertEquals("address", nextLine[3]);
489         assertEquals("116.453182", nextLine[4]);
490         assertEquals("39.918884", nextLine[5]);
491 
492     }
493 
494     @Test
495     public void anIOExceptionThrownIfStringEndsInsideAQuotedString() {
496         final String part1 = "This,is a \"";
497         final String part2 = "bad line to parse.";
498         try {
499             csvParser.parseLine(part1+part2);
500             fail("Exception should have been thrown.");
501         }
502         catch(IOException e) {
503             assertTrue(e.getMessage().contains(part2));
504         }
505     }
506 
507     @Test
508     public void parseLineMultiAllowsQuotesAcrossMultipleLines() throws IOException {
509         String[] nextLine = csvParser.parseLineMulti("This,\"is a \"good\" line\\\\ to parse");
510 
511         assertEquals(1, nextLine.length);
512         assertEquals("This", nextLine[0]);
513         assertTrue(csvParser.isPending());
514 
515         nextLine = csvParser.parseLineMulti("because we are using parseLineMulti.\"");
516 
517         assertEquals(1, nextLine.length);
518         assertEquals("is a \"good\" line\\ to parse\nbecause we are using parseLineMulti.", nextLine[0]);
519         assertFalse(csvParser.isPending());
520     }
521 
522     @Test
523     public void pendingIsClearedAfterCallToParseLine() throws IOException {
524         String[] nextLine = csvParser.parseLineMulti("This,\"is a \"good\" line\\\\ to parse");
525 
526         assertEquals(1, nextLine.length);
527         assertEquals("This", nextLine[0]);
528         assertTrue(csvParser.isPending());
529 
530         nextLine = csvParser.parseLine("because we are using parseLineMulti.");
531 
532         assertEquals(1, nextLine.length);
533         assertEquals("because we are using parseLineMulti.", nextLine[0]);
534         assertFalse(csvParser.isPending());
535     }
536 
537     @Test
538     public void returnPendingIfNullIsPassedIntoParseLineMulti() throws IOException {
539         String[] nextLine = csvParser.parseLineMulti("This,\"is a \"goo\\d\" line\\\\ to parse\\");
540 
541         assertEquals(1, nextLine.length);
542         assertEquals("This", nextLine[0]);
543         assertTrue(csvParser.isPending());
544 
545         nextLine = csvParser.parseLineMulti(null);
546 
547         assertEquals(1, nextLine.length);
548         assertEquals("is a \"good\" line\\ to parse\n", nextLine[0]);
549         assertFalse(csvParser.isPending());
550     }
551 
552     @Test
553     public void spacesAtEndOfQuotedStringDoNotCountIfStrictQuotesIsTrue() throws IOException {
554         ICSVParser parser = new CSVParserBuilder()
555                 .withStrictQuotes(true)
556                 .build();
557         String[] nextLine = parser.parseLine("\"Line with\", \"spaces at end\"  ");
558 
559         assertEquals(2, nextLine.length);
560         assertEquals("Line with", nextLine[0]);
561         assertEquals("spaces at end", nextLine[1]);
562     }
563 
564     @Test
565     public void returnNullWhenNullPassedIn() throws IOException {
566         String[] nextLine = csvParser.parseLine(null);
567         assertNull(nextLine);
568     }
569 
570     @Test
571     public void validateEscapeStringBeforeRealTest() {
572         assertNotNull(ESCAPE_TEST_STRING);
573         assertEquals(9, ESCAPE_TEST_STRING.length());
574     }
575 
576     @Test
577     public void whichCharactersAreEscapable() {
578         assertTrue(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, true, 0));
579         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, false, 0));
580         // Second character is not escapable because there is a non quote or non slash after it.
581         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, true, 1));
582         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, false, 1));
583         // Fourth character is not escapable because there is a non quote or non slash after it.
584         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, true, 3));
585         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, false, 3));
586 
587         assertTrue(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, true, 5));
588         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, false, 5));
589 
590         int lastChar = ESCAPE_TEST_STRING.length() - 1;
591         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, true, lastChar));
592         assertFalse(csvParser.isNextCharacterEscapable(ESCAPE_TEST_STRING, false, lastChar));
593     }
594 
595 
596     @Test
597     public void whitespaceBeforeEscape() throws IOException {
598         String[] nextItem = csvParser.parseLine("\"this\", \"is\",\"a test\""); //"this", "is","a test"
599         assertEquals("this", nextItem[0]);
600         assertEquals("is", nextItem[1]);
601         assertEquals("a test", nextItem[2]);
602     }
603 
604     @Test
605     public void testIssue2958242WithoutQuotes() throws IOException {
606         ICSVParser testParser = new CSVParserBuilder().withSeparator('\t').build();
607         String[] nextItem = testParser.parseLine("zo\"\"har\"\"at\t10-04-1980\t29\tC:\\\\foo.txt");
608         assertEquals(4, nextItem.length);
609         assertEquals("zo\"har\"at", nextItem[0]);
610         assertEquals("10-04-1980", nextItem[1]);
611         assertEquals("29", nextItem[2]);
612         assertEquals("C:\\foo.txt", nextItem[3]);
613     }
614 
615     @Test
616     public void quoteAndEscapeCannotBeTheSame() {
617         Assertions.assertThrows(UnsupportedOperationException.class, () -> {
618             new CSVParserBuilder()
619                     .withQuoteChar(ICSVParser.DEFAULT_QUOTE_CHARACTER)
620                     .withEscapeChar(ICSVParser.DEFAULT_QUOTE_CHARACTER)
621                     .build();
622         });
623     }
624 
625     @Test
626     public void quoteAndEscapeCanBeTheSameIfNull() {
627         new CSVParserBuilder()
628                 .withQuoteChar(ICSVParser.NULL_CHARACTER)
629                 .withEscapeChar(ICSVParser.NULL_CHARACTER)
630                 .build();
631     }
632 
633     @Test
634     public void separatorCharacterCannotBeNull() {
635         Assertions.assertThrows(UnsupportedOperationException.class, () -> new CSVParserBuilder().withSeparator(ICSVParser.NULL_CHARACTER).build());
636     }
637 
638     @Test
639     public void separatorAndEscapeCannotBeTheSame() {
640         Assertions.assertThrows(UnsupportedOperationException.class, () -> {
641             new CSVParserBuilder()
642                     .withSeparator(ICSVParser.DEFAULT_SEPARATOR)
643                     .withEscapeChar(ICSVParser.DEFAULT_SEPARATOR)
644                     .build();
645         });
646     }
647 
648     @Test
649     public void separatorAndQuoteCannotBeTheSame() {
650         String englishErrorMessage = null;
651         try {
652             new CSVParserBuilder()
653                     .withSeparator(ICSVParser.DEFAULT_SEPARATOR)
654                     .withQuoteChar(ICSVParser.DEFAULT_SEPARATOR)
655                     .build();
656             fail("UnsupportedOperationException should have been thrown.");
657         }
658         catch(UnsupportedOperationException e) {
659             englishErrorMessage = e.getLocalizedMessage();
660         }
661         
662         // Now try with a different locale
663         try {
664             new CSVParser(
665                     ICSVParser.DEFAULT_SEPARATOR, ICSVParser.DEFAULT_SEPARATOR,
666                     ICSVParser.DEFAULT_ESCAPE_CHARACTER,
667                     ICSVParser.DEFAULT_STRICT_QUOTES,
668                     ICSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE,
669                     ICSVParser.DEFAULT_IGNORE_QUOTATIONS,
670                     ICSVParser.DEFAULT_NULL_FIELD_INDICATOR, Locale.GERMAN);
671             fail("UnsupportedOperationException should have been thrown.");
672         }
673         catch(UnsupportedOperationException e) {
674             assertNotSame(englishErrorMessage, e.getLocalizedMessage());
675         }
676     }
677 
678     @Test
679     public void shouldSupportPortugueseLocale() {
680 
681         try {
682             new CSVParser(
683                     ICSVParser.DEFAULT_SEPARATOR, ICSVParser.DEFAULT_SEPARATOR,
684                     ICSVParser.DEFAULT_ESCAPE_CHARACTER,
685                     ICSVParser.DEFAULT_STRICT_QUOTES,
686                     ICSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE,
687                     ICSVParser.DEFAULT_IGNORE_QUOTATIONS,
688                     ICSVParser.DEFAULT_NULL_FIELD_INDICATOR, new Locale("pt", "BR"));
689             fail("UnsupportedOperationException should have been thrown.");
690         }
691         catch(UnsupportedOperationException e) {
692             assertEquals("O separador, delimitador de texto e caractere de escape precisam ser diferentes!", e.getLocalizedMessage());
693         }
694     }
695 
696     @Test
697     public void parserHandlesNullInString() throws IOException {
698         String[] nextLine = csvParser.parseLine("because we are using\0 parseLineMulti.");
699 
700         assertEquals(1, nextLine.length);
701         assertEquals("because we are using\0 parseLineMulti.", nextLine[0]);
702     }
703 
704     @Test
705     public void featureRequest60ByDefaultEmptyFieldsAreBlank() throws IOException {
706         StringBuilder sb = new StringBuilder(ICSVParser.INITIAL_READ_SIZE);
707 
708         sb.append(",,,\"\",");
709 
710         CSVParserBuilder builder = new CSVParserBuilder();
711         ICSVParser parser = builder.build();
712 
713         String[] item = parser.parseLine(sb.toString());
714 
715         assertEquals(5, item.length);
716         assertEquals("", item[0]);
717         assertEquals("", item[1]);
718         assertEquals("", item[2]);
719         assertEquals("", item[3]);
720         assertEquals("", item[4]);
721     }
722 
723     @Test
724     public void featureRequest60TreatEmptyFieldsAsNull() throws IOException {
725 
726         StringBuilder sb = new StringBuilder(ICSVParser.INITIAL_READ_SIZE);
727 
728         sb.append(", ,,\"\",");
729 
730         CSVParserBuilder builder = new CSVParserBuilder();
731         ICSVParser parser = builder.withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS).build();
732 
733         String[] item = parser.parseLine(sb.toString());
734 
735         assertEquals(5, item.length);
736         assertNull(item[0]);
737         assertEquals(" ", item[1]);
738         assertNull(item[2]);
739         assertEquals("", item[3]);
740         assertNull(item[4]);
741 
742     }
743 
744     @Test
745     public void featureRequest60TreatEmptyDelimitedFieldsAsNull() throws IOException {
746         StringBuilder sb = new StringBuilder(ICSVParser.INITIAL_READ_SIZE);
747 
748         sb.append(",\" \",,\"\",");
749 
750         CSVParserBuilder builder = new CSVParserBuilder();
751         ICSVParser parser = builder.withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_QUOTES).build();
752 
753         String[] item = parser.parseLine(sb.toString());
754 
755         assertEquals(5, item.length);
756         assertEquals("", item[0]);
757         assertEquals(" ", item[1]);
758         assertEquals("", item[2]);
759         assertNull(item[3]);
760         assertEquals("", item[4]);
761     }
762 
763     @Test
764     public void featureRequest60TreatEmptyFieldsDelimitedOrNotAsNull() throws IOException {
765 
766         StringBuilder sb = new StringBuilder(ICSVParser.INITIAL_READ_SIZE);
767 
768         sb.append(", ,,\"\",");
769 
770         CSVParserBuilder builder = new CSVParserBuilder();
771         ICSVParser parser = builder.withFieldAsNull(CSVReaderNullFieldIndicator.BOTH).build();
772 
773         String[] item = parser.parseLine(sb.toString());
774 
775         assertEquals(5, item.length);
776         assertNull(item[0]);
777         assertEquals(" ", item[1]);
778         assertNull(item[2]);
779         assertNull(item[3]);
780         assertNull(item[4]);
781 
782     }
783 
784     @Test
785     public void testStrictQuotesEndsFieldAtQuote() throws IOException {
786         CSVParserBuilder builder = new CSVParserBuilder();
787         ICSVParser parser = builder.withStrictQuotes(true).build();
788         // "one","t"wo,"three"
789         String[] nextLine = parser.parseLineMulti("\"one\",\"t\"wo,\"three\"");
790 
791         assertEquals(3, nextLine.length);
792 
793         assertEquals("one", nextLine[0]);
794         assertEquals("t", nextLine[1]);
795         assertEquals("three", nextLine[2]);
796     }
797 
798     @Test
799     public void testStrictQuotesEndsFieldAtQuoteWithEscapedQuoteInMiddle() throws IOException {
800         CSVParserBuilder builder = new CSVParserBuilder();
801         ICSVParser parser = builder.withStrictQuotes(true).build();
802         // "one","t""w"o,"three"
803         String[] nextLine = parser.parseLineMulti("\"one\",\"t\"\"w\"o,\"three\"");
804 
805         assertEquals(3, nextLine.length);
806 
807         assertEquals("one", nextLine[0]);
808         assertEquals("t\"w", nextLine[1]);
809         assertEquals("three", nextLine[2]);
810     }
811 
812     @Test
813     public void testNotStrictQuotesAllowsEmbeddedEscapedQuote() throws IOException {
814         CSVParserBuilder builder = new CSVParserBuilder();
815         ICSVParser parser = builder.withStrictQuotes(false).build();
816         // "one","t"wo","three"
817         String[] nextLine = parser.parseLineMulti("\"one\",\"t\"\"wo\",\"three\"");
818 
819         assertEquals(3, nextLine.length);
820 
821         assertEquals("one", nextLine[0]);
822         assertEquals("t\"wo", nextLine[1]);
823         assertEquals("three", nextLine[2]);
824     }
825 
826     @Test
827     public void testNotStrictQuotesAllowsEmbeddedQuote() throws IOException {
828         CSVParserBuilder builder = new CSVParserBuilder();
829         ICSVParser parser = builder.withStrictQuotes(false).build();
830         // "one",t""wo,"three"
831         String[] nextLine = parser.parseLineMulti("\"one\",t\"\"wo,\"three\"");
832 
833         assertEquals(3, nextLine.length);
834 
835         assertEquals("one", nextLine[0]);
836         assertEquals("t\"wo", nextLine[1]);
837         assertEquals("three", nextLine[2]);
838     }
839 
840     @Test
841     public void issue93ParsingEmptyDoubleQuoteField() throws IOException {
842         CSVParserBuilder builder = new CSVParserBuilder();
843         ICSVParser parser = builder.withStrictQuotes(false).build();
844         // "",2
845         String[] nextLine = parser.parseLineMulti("\"\",2");
846 
847         assertEquals(2, nextLine.length);
848 
849         assertTrue(nextLine[0].isEmpty());
850         assertEquals("2", nextLine[1]);
851     }
852 
853     @Test
854     public void parseToLineApplyQuotesToAllIsFalse() {
855         String[] items = {"This", " is", " a", " test."};
856         assertEquals("This, is, a, test.", csvParser.parseToLine(items, false));
857     }
858 
859     @Test
860     public void parseToLineApplyQuotesToAllIsTrue() {
861         String[] items = {"This", " is", " a", " test."};
862         assertEquals("\"This\",\" is\",\" a\",\" test.\"", csvParser.parseToLine(items, true));
863     }
864 
865     @Test
866     public void parseToLineUsesCorrectSeparator() {
867         CSVParserBuilder builder = new CSVParserBuilder();
868         ICSVParser parser = builder.withSeparator('.').withQuoteChar('\'').build();
869 
870         String[] items = {"This", " is", " a", " test."};
871         assertEquals("This. is. a.' test.'", parser.parseToLine(items, false));
872     }
873 
874     /**
875      * Test to check if we have a good detail in the error message when there
876      * is a quote that wasn't closed (beginning of the field).
877      * Check if the attributes of the CsvMultilineLimitBrokenException are set.
878      * @throws IOException Never
879      */
880     @Test
881     public void testMultilineLimitBrokeErrorDetailWithQuoteBegin() throws IOException, CsvValidationException {
882         csvParser = new CSVParser();
883 
884         int multilineLimit = 10;
885         try {
886             CSVReaderBuilder csvReaderBuilder = new CSVReaderBuilder(new FileReader("src/test/resources/testmultilinelimitebroke1.csv"));
887 
888             CSVReader reader = csvReaderBuilder.withMultilineLimit(multilineLimit).build();
889             while (true) {
890                 if (reader.readNext() == null) {
891                     break;
892                 }
893             }
894             fail("Should have thrown exception");
895         } catch (CsvMultilineLimitBrokenException e) {
896 
897             String contextLabel = "Context: ";
898             int contextPosition = e.getMessage().indexOf("Context:");
899 
900             assertEquals(e.getRow(),11L);
901             assertTrue(e.getContext().startsWith("xaxax\"axa,sasasasas,babaababab,121212,6581"));
902             assertEquals(e.getMultilineLimit(),multilineLimit);
903             assertTrue(e.getMessage().contains("row"));
904             assertTrue(e.getMessage().contains(contextLabel));
905 
906             // checking the size of the context in the error message
907             assertEquals(e.getMessage().substring(contextPosition).length(), CSVReader.CONTEXT_MULTILINE_EXCEPTION_MESSAGE_SIZE
908                     + contextLabel.length());
909 
910         }
911     }
912 
913     /**
914      * Test to check if we have a good detail in the error message when there
915      * is a quote that wasn't closed (middle of the field).
916      * Check if the attributes of the CsvMultilineLimitBrokenException are set.
917      * @throws IOException Never
918      */
919     @Test
920     public void testMultilineLimitBrokeErrorDetailWithQuoteMiddle() throws IOException, CsvValidationException {
921         csvParser = new CSVParser();
922         int multilineLimit = 10;
923 
924         try {
925             CSVReaderBuilder csvReaderBuilder = new CSVReaderBuilder(new FileReader("src/test/resources/testmultilinelimitebroke2.csv"));
926 
927             CSVReader reader = csvReaderBuilder.withMultilineLimit(multilineLimit).build();
928             while (true) {
929                 if (reader.readNext() == null) {
930                     break;
931                 }
932             }
933             fail("Should have thrown exception");
934         } catch (CsvMultilineLimitBrokenException e) {
935 
936             String contextLabel = "Context: ";
937             int contextPosition = e.getMessage().indexOf("Context:");
938 
939             assertEquals(e.getRow(),18L);
940             assertTrue(e.getContext().startsWith("xaxaxxaxaxxaxaxxaxaxxaxaxxaxa\"xxaxaxxaxaxxaxaxxaxa"));
941             assertEquals(e.getMultilineLimit(),multilineLimit);
942             assertTrue(e.getMessage().contains("row"));
943             assertTrue(e.getMessage().contains(contextLabel));
944 
945             // checking the size of the context in the error message
946             assertEquals(e.getMessage().substring(contextPosition).length(), CSVReader.CONTEXT_MULTILINE_EXCEPTION_MESSAGE_SIZE
947                     + contextLabel.length());
948 
949         }
950     }
951 
952     /**
953      * Test to check if we have a good detail in the error message when there
954      * is a quote that wasn't closed (end of the field).
955      * Check if the attributes of the CsvMultilineLimitBrokenException are set.
956      * @throws IOException Never
957      */
958     @Test
959     public void testMultilineLimitBrokeErrorDetailWithQuoteEnd() throws IOException, CsvValidationException {
960         csvParser = new CSVParser();
961         int multilineLimit = 10;
962         try {
963             CSVReaderBuilder csvReaderBuilder = new CSVReaderBuilder(new FileReader("src/test/resources/testmultilinelimitebroke3.csv"));
964 
965             CSVReader reader = csvReaderBuilder.withMultilineLimit(multilineLimit).build();
966             while (true) {
967                 if (reader.readNext() == null) {
968                     break;
969                 }
970             }
971             fail("Should have thrown exception");
972         } catch (CsvMultilineLimitBrokenException e) {
973 
974             String contextLabel = "Context: ";
975             int contextPosition = e.getMessage().indexOf("Context:");
976 
977             assertEquals(e.getRow(),18L);
978             assertTrue(e.getContext().startsWith("xaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxxaxaxx\"axax,sasasasas"));
979             assertEquals(e.getMultilineLimit(),multilineLimit);
980             assertTrue(e.getMessage().contains("row"));
981             assertTrue(e.getMessage().contains(contextLabel));
982 
983             // checking the size of the context in the error message
984             assertEquals(e.getMessage().substring(contextPosition).length(), CSVReader.CONTEXT_MULTILINE_EXCEPTION_MESSAGE_SIZE
985                     + contextLabel.length());
986 
987         }
988     }
989 
990     @Test
991     @DisplayName("handling of an empty string")
992     public void testEmptyString() throws IOException {
993         csvParser = new CSVParser();
994         String[] nextLine = csvParser.parseLineMulti("");
995         assertEquals(1, nextLine.length);
996         assertTrue(nextLine[0].isEmpty());
997     }
998 }