1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.commons.csv;
21
22 import static org.apache.commons.csv.Constants.CR;
23 import static org.apache.commons.csv.Constants.CRLF;
24 import static org.apache.commons.csv.Constants.LF;
25 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertFalse;
28 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
29 import static org.junit.jupiter.api.Assertions.assertNotNull;
30 import static org.junit.jupiter.api.Assertions.assertNull;
31 import static org.junit.jupiter.api.Assertions.assertThrows;
32 import static org.junit.jupiter.api.Assertions.assertTrue;
33
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.PipedReader;
39 import java.io.PipedWriter;
40 import java.io.Reader;
41 import java.io.StringReader;
42 import java.io.StringWriter;
43 import java.io.UncheckedIOException;
44 import java.net.URL;
45 import java.nio.charset.Charset;
46 import java.nio.charset.StandardCharsets;
47 import java.nio.file.Files;
48 import java.nio.file.Path;
49 import java.nio.file.Paths;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.NoSuchElementException;
56 import java.util.stream.Collectors;
57 import java.util.stream.Stream;
58
59 import org.apache.commons.io.input.BOMInputStream;
60 import org.apache.commons.io.input.BrokenInputStream;
61 import org.junit.jupiter.api.Assertions;
62 import org.junit.jupiter.api.Disabled;
63 import org.junit.jupiter.api.Test;
64 import org.junit.jupiter.params.ParameterizedTest;
65 import org.junit.jupiter.params.provider.EnumSource;
66 import org.junit.jupiter.params.provider.ValueSource;
67
68
69
70
71
72
73
74 public class CSVParserTest {
75
76 private static final CSVFormat EXCEL_WITH_HEADER = CSVFormat.EXCEL.withHeader();
77
78 private static final Charset UTF_8 = StandardCharsets.UTF_8;
79
80 private static final String UTF_8_NAME = UTF_8.name();
81
82 private static final String CSV_INPUT = "a,b,c,d\n" + " a , b , 1 2 \n" + "\"foo baar\", b,\n" +
83
84 " \"foo\n,,\n\"\",,\n\"\"\",d,e\n";
85
86 private static final String CSV_INPUT_1 = "a,b,c,d";
87
88 private static final String CSV_INPUT_2 = "a,b,1 2";
89
90 private static final String[][] RESULT = { { "a", "b", "c", "d" }, { "a", "b", "1 2" }, { "foo baar", "b", "" }, { "foo\n,,\n\",,\n\"", "d", "e" } };
91
92
93 private static final String CSV_INPUT_NO_COMMENT = "A,B" + CRLF + "1,2" + CRLF;
94
95
96 private static final String CSV_INPUT_HEADER_COMMENT = "# header comment" + CRLF + "A,B" + CRLF + "1,2" + CRLF;
97
98
99 private static final String CSV_INPUT_HEADER_TRAILER_COMMENT = "# header comment" + CRLF + "A,B" + CRLF + "1,2" + CRLF + "# comment";
100
101
102 private static final String CSV_INPUT_MULTILINE_HEADER_TRAILER_COMMENT = "# multi-line" + CRLF + "# header comment" + CRLF + "A,B" + CRLF + "1,2" + CRLF +
103 "# multi-line" + CRLF + "# comment";
104
105
106 private static final CSVFormat FORMAT_AUTO_HEADER = CSVFormat.Builder.create(CSVFormat.DEFAULT).setCommentMarker('#').setHeader().get();
107
108
109
110 private static final CSVFormat FORMAT_EXPLICIT_HEADER = CSVFormat.Builder.create(CSVFormat.DEFAULT)
111 .setSkipHeaderRecord(true)
112 .setCommentMarker('#')
113 .setHeader("A", "B")
114 .get();
115
116
117
118
119 CSVFormat FORMAT_EXPLICIT_HEADER_NOSKIP = CSVFormat.Builder.create(CSVFormat.DEFAULT)
120 .setCommentMarker('#')
121 .setHeader("A", "B")
122 .get();
123
124
125 @SuppressWarnings("resource")
126 private BOMInputStream createBOMInputStream(final String resource) throws IOException {
127 return new BOMInputStream(ClassLoader.getSystemClassLoader().getResource(resource).openStream());
128 }
129
130 CSVRecord parse(final CSVParser parser, final int failParseRecordNo) throws IOException {
131 if (parser.getRecordNumber() + 1 == failParseRecordNo) {
132 assertThrows(IOException.class, () -> parser.nextRecord());
133 return null;
134 }
135 return parser.nextRecord();
136 }
137
138 private void parseFully(final CSVParser parser) {
139 parser.forEach(Assertions::assertNotNull);
140 }
141
142 @Test
143 public void testBackslashEscaping() throws IOException {
144
145
146
147
148
149 final String code = "one,two,three\n" +
150 "'',''\n" +
151 "/',/'\n" +
152 "'/'','/''\n" +
153 "'''',''''\n" +
154 "/,,/,\n" +
155 "//,//\n" + // 6) escape escaped
156 "'//','//'\n" + // 7) escape escaped in encapsulation
157 " 8 , \"quoted \"\" /\" // string\" \n" + // don't eat spaces
158 "9, /\n \n" +
159 "";
160 final String[][] res = {{"one", "two", "three"},
161 {"", ""},
162 {"'", "'"},
163 {"'", "'"},
164 {"'", "'"},
165 {",", ","},
166 {"/", "/"},
167 {"/", "/"},
168 {" 8 ", " \"quoted \"\" /\" / string\" "}, {"9", " \n "} };
169
170 final CSVFormat format = CSVFormat.newFormat(',').withQuote('\'').withRecordSeparator(CRLF).withEscape('/').withIgnoreEmptyLines();
171 try (CSVParser parser = CSVParser.parse(code, format)) {
172 final List<CSVRecord> records = parser.getRecords();
173 assertFalse(records.isEmpty());
174 Utils.compare("Records do not match expected result", res, records, -1);
175 }
176 }
177
178 @Test
179 public void testBackslashEscaping2() throws IOException {
180
181
182
183
184 final String code = "" + " , , \n" +
185 " \t , , \n" +
186 " // , /, , /,\n" + // 3)
187 "";
188 final String[][] res = {{" ", " ", " "},
189 {" \t ", " ", " "},
190 {" / ", " , ", " ,"},
191 };
192
193 final CSVFormat format = CSVFormat.newFormat(',').withRecordSeparator(CRLF).withEscape('/').withIgnoreEmptyLines();
194 try (CSVParser parser = CSVParser.parse(code, format)) {
195 final List<CSVRecord> records = parser.getRecords();
196 assertFalse(records.isEmpty());
197 Utils.compare("", res, records, -1);
198 }
199 }
200
201 @Test
202 @Disabled
203 public void testBackslashEscapingOld() throws IOException {
204 final String code = "one,two,three\n" + "on\\\"e,two\n" + "on\"e,two\n" + "one,\"tw\\\"o\"\n" + "one,\"t\\,wo\"\n" + "one,two,\"th,ree\"\n" +
205 "\"a\\\\\"\n" + "a\\,b\n" + "\"a\\\\,b\"";
206 final String[][] res = { { "one", "two", "three" }, { "on\\\"e", "two" }, { "on\"e", "two" }, { "one", "tw\"o" }, { "one", "t\\,wo" },
207
208
209
210
211 { "one", "two", "th,ree" }, { "a\\\\" },
212 { "a\\", "b" },
213 { "a\\\\,b" }
214 };
215 try (CSVParser parser = CSVParser.parse(code, CSVFormat.DEFAULT)) {
216 final List<CSVRecord> records = parser.getRecords();
217 assertEquals(res.length, records.size());
218 assertFalse(records.isEmpty());
219 for (int i = 0; i < res.length; i++) {
220 assertArrayEquals(res[i], records.get(i).values());
221 }
222 }
223 }
224
225 @Test
226 @Disabled("CSV-107")
227 public void testBOM() throws IOException {
228 final URL url = ClassLoader.getSystemClassLoader().getResource("org/apache/commons/csv/CSVFileParser/bom.csv");
229 try (CSVParser parser = CSVParser.parse(url, StandardCharsets.UTF_8, EXCEL_WITH_HEADER)) {
230 parser.forEach(record -> assertNotNull(record.get("Date")));
231 }
232 }
233
234 @Test
235 public void testBOMInputStreamParserWithInputStream() throws IOException {
236 try (BOMInputStream inputStream = createBOMInputStream("org/apache/commons/csv/CSVFileParser/bom.csv");
237 CSVParser parser = CSVParser.parse(inputStream, UTF_8, EXCEL_WITH_HEADER)) {
238 parser.forEach(record -> assertNotNull(record.get("Date")));
239 }
240 }
241
242 @Test
243 public void testBOMInputStreamParserWithReader() throws IOException {
244 try (Reader reader = new InputStreamReader(createBOMInputStream("org/apache/commons/csv/CSVFileParser/bom.csv"), UTF_8_NAME);
245 CSVParser parser = CSVParser.builder()
246 .setReader(reader)
247 .setFormat(EXCEL_WITH_HEADER)
248 .get()) {
249 parser.forEach(record -> assertNotNull(record.get("Date")));
250 }
251 }
252
253 @Test
254 public void testBOMInputStreamParseWithReader() throws IOException {
255 try (Reader reader = new InputStreamReader(createBOMInputStream("org/apache/commons/csv/CSVFileParser/bom.csv"), UTF_8_NAME);
256 CSVParser parser = CSVParser.builder()
257 .setReader(reader)
258 .setFormat(EXCEL_WITH_HEADER)
259 .get()) {
260 parser.forEach(record -> assertNotNull(record.get("Date")));
261 }
262 }
263
264 @Test
265 public void testCarriageReturnEndings() throws IOException {
266 final String string = "foo\rbaar,\rhello,world\r,kanu";
267 try (CSVParser parser = CSVParser.builder().setCharSequence(string).get()) {
268 final List<CSVRecord> records = parser.getRecords();
269 assertEquals(4, records.size());
270 }
271 }
272
273 @Test
274 public void testCarriageReturnLineFeedEndings() throws IOException {
275 final String string = "foo\r\nbaar,\r\nhello,world\r\n,kanu";
276 try (CSVParser parser = CSVParser.builder().setCharSequence(string).get()) {
277 final List<CSVRecord> records = parser.getRecords();
278 assertEquals(4, records.size());
279 }
280 }
281
282 @Test
283 public void testClose() throws Exception {
284 final Reader in = new StringReader("# comment\na,b,c\n1,2,3\nx,y,z");
285 final Iterator<CSVRecord> records;
286 try (CSVParser parser = CSVFormat.DEFAULT.withCommentMarker('#').withHeader().parse(in)) {
287 records = parser.iterator();
288 assertTrue(records.hasNext());
289 }
290 assertFalse(records.hasNext());
291 assertThrows(NoSuchElementException.class, records::next);
292 }
293
294 @Test
295 public void testCSV141CSVFormat_DEFAULT() throws Exception {
296 testCSV141Failure(CSVFormat.DEFAULT, 3);
297 }
298
299 @Test
300 public void testCSV141CSVFormat_INFORMIX_UNLOAD() throws Exception {
301 testCSV141Failure(CSVFormat.INFORMIX_UNLOAD, 1);
302 }
303
304 @Test
305 public void testCSV141CSVFormat_INFORMIX_UNLOAD_CSV() throws Exception {
306 testCSV141Failure(CSVFormat.INFORMIX_UNLOAD_CSV, 3);
307 }
308
309 @Test
310 public void testCSV141CSVFormat_ORACLE() throws Exception {
311 testCSV141Failure(CSVFormat.ORACLE, 2);
312 }
313
314 @Test
315 public void testCSV141CSVFormat_POSTGRESQL_CSV() throws Exception {
316 testCSV141Failure(CSVFormat.POSTGRESQL_CSV, 3);
317 }
318
319 @Test
320 public void testCSV141Excel() throws Exception {
321 testCSV141Ok(CSVFormat.EXCEL);
322 }
323
324 private void testCSV141Failure(final CSVFormat format, final int failParseRecordNo) throws IOException {
325 final Path path = Paths.get("src/test/resources/org/apache/commons/csv/CSV-141/csv-141.csv");
326 try (CSVParser parser = CSVParser.parse(path, StandardCharsets.UTF_8, format)) {
327
328 CSVRecord record = parse(parser, failParseRecordNo);
329 if (record == null) {
330 return;
331 }
332 assertEquals("1414770317901", record.get(0));
333 assertEquals("android.widget.EditText", record.get(1));
334 assertEquals("pass sem1 _84*|*", record.get(2));
335 assertEquals("0", record.get(3));
336 assertEquals("pass sem1 _8", record.get(4));
337 assertEquals(5, record.size());
338
339 record = parse(parser, failParseRecordNo);
340 if (record == null) {
341 return;
342 }
343 assertEquals("1414770318470", record.get(0));
344 assertEquals("android.widget.EditText", record.get(1));
345 assertEquals("pass sem1 _84:|", record.get(2));
346 assertEquals("0", record.get(3));
347 assertEquals("pass sem1 _84:\\", record.get(4));
348 assertEquals(5, record.size());
349
350 assertThrows(IOException.class, () -> parser.nextRecord());
351 }
352 }
353
354 private void testCSV141Ok(final CSVFormat format) throws IOException {
355 final Path path = Paths.get("src/test/resources/org/apache/commons/csv/CSV-141/csv-141.csv");
356 try (CSVParser parser = CSVParser.parse(path, StandardCharsets.UTF_8, format)) {
357
358 CSVRecord record = parser.nextRecord();
359 assertEquals("1414770317901", record.get(0));
360 assertEquals("android.widget.EditText", record.get(1));
361 assertEquals("pass sem1 _84*|*", record.get(2));
362 assertEquals("0", record.get(3));
363 assertEquals("pass sem1 _8", record.get(4));
364 assertEquals(5, record.size());
365
366 record = parser.nextRecord();
367 assertEquals("1414770318470", record.get(0));
368 assertEquals("android.widget.EditText", record.get(1));
369 assertEquals("pass sem1 _84:|", record.get(2));
370 assertEquals("0", record.get(3));
371 assertEquals("pass sem1 _84:\\", record.get(4));
372 assertEquals(5, record.size());
373
374 record = parser.nextRecord();
375 assertEquals("1414770318327", record.get(0));
376 assertEquals("android.widget.EditText", record.get(1));
377 assertEquals("pass sem1\n1414770318628\"", record.get(2));
378 assertEquals("android.widget.EditText", record.get(3));
379 assertEquals("pass sem1 _84*|*", record.get(4));
380 assertEquals("0", record.get(5));
381 assertEquals("pass sem1\n", record.get(6));
382 assertEquals(7, record.size());
383
384 record = parser.nextRecord();
385 assertNull(record);
386 }
387 }
388
389 @Test
390 public void testCSV141RFC4180() throws Exception {
391 testCSV141Failure(CSVFormat.RFC4180, 3);
392 }
393
394 @Test
395 public void testCSV235() throws IOException {
396 final String dqString = "\"aaa\",\"b\"\"bb\",\"ccc\"";
397 try (CSVParser parser = CSVFormat.RFC4180.parse(new StringReader(dqString))) {
398 final Iterator<CSVRecord> records = parser.iterator();
399 final CSVRecord record = records.next();
400 assertFalse(records.hasNext());
401 assertEquals(3, record.size());
402 assertEquals("aaa", record.get(0));
403 assertEquals("b\"bb", record.get(1));
404 assertEquals("ccc", record.get(2));
405 }
406 }
407
408 @Test
409 public void testCSV57() throws Exception {
410 try (CSVParser parser = CSVParser.parse("", CSVFormat.DEFAULT)) {
411 final List<CSVRecord> list = parser.getRecords();
412 assertNotNull(list);
413 assertEquals(0, list.size());
414 }
415 }
416
417 @Test
418 public void testDefaultFormat() throws IOException {
419
420 final String code = "" + "a,b#\n" +
421 "\"\n\",\" \",#\n" +
422 "#,\"\"\n" +
423 "# Final comment\n"
424 ;
425
426 final String[][] res = { { "a", "b#" }, { "\n", " ", "#" }, { "#", "" }, { "# Final comment" } };
427 CSVFormat format = CSVFormat.DEFAULT;
428 assertFalse(format.isCommentMarkerSet());
429 final String[][] resComments = { { "a", "b#" }, { "\n", " ", "#" } };
430 try (CSVParser parser = CSVParser.parse(code, format)) {
431 final List<CSVRecord> records = parser.getRecords();
432 assertFalse(records.isEmpty());
433 Utils.compare("Failed to parse without comments", res, records, -1);
434 format = CSVFormat.DEFAULT.withCommentMarker('#');
435 }
436 try (CSVParser parser = CSVParser.parse(code, format)) {
437 final List<CSVRecord> records = parser.getRecords();
438 Utils.compare("Failed to parse with comments", resComments, records, -1);
439 }
440 }
441
442 @Test
443 public void testDuplicateHeadersAllowedByDefault() throws Exception {
444 try (CSVParser parser = CSVParser.parse("a,b,a\n1,2,3\nx,y,z", CSVFormat.DEFAULT.withHeader())) {
445
446 }
447 }
448
449 @Test
450 public void testDuplicateHeadersNotAllowed() {
451 assertThrows(IllegalArgumentException.class,
452 () -> CSVParser.parse("a,b,a\n1,2,3\nx,y,z", CSVFormat.DEFAULT.withHeader().withAllowDuplicateHeaderNames(false)));
453 }
454
455 @Test
456 public void testEmptyFile() throws Exception {
457 try (CSVParser parser = CSVParser.parse(Paths.get("src/test/resources/org/apache/commons/csv/empty.txt"), StandardCharsets.UTF_8,
458 CSVFormat.DEFAULT)) {
459 assertNull(parser.nextRecord());
460 }
461 }
462
463 @Test
464 public void testEmptyFileHeaderParsing() throws Exception {
465 try (CSVParser parser = CSVParser.parse("", CSVFormat.DEFAULT.withFirstRecordAsHeader())) {
466 assertNull(parser.nextRecord());
467 assertTrue(parser.getHeaderNames().isEmpty());
468 }
469 }
470
471 @Test
472 public void testEmptyLineBehaviorCSV() throws Exception {
473 final String[] codes = { "hello,\r\n\r\n\r\n", "hello,\n\n\n", "hello,\"\"\r\n\r\n\r\n", "hello,\"\"\n\n\n" };
474 final String[][] res = { { "hello", "" }
475 };
476 for (final String code : codes) {
477 try (CSVParser parser = CSVParser.parse(code, CSVFormat.DEFAULT)) {
478 final List<CSVRecord> records = parser.getRecords();
479 assertEquals(res.length, records.size());
480 assertFalse(records.isEmpty());
481 for (int i = 0; i < res.length; i++) {
482 assertArrayEquals(res[i], records.get(i).values());
483 }
484 }
485 }
486 }
487
488 @Test
489 public void testEmptyLineBehaviorExcel() throws Exception {
490 final String[] codes = { "hello,\r\n\r\n\r\n", "hello,\n\n\n", "hello,\"\"\r\n\r\n\r\n", "hello,\"\"\n\n\n" };
491 final String[][] res = { { "hello", "" }, { "" },
492 { "" } };
493 for (final String code : codes) {
494 try (CSVParser parser = CSVParser.parse(code, CSVFormat.EXCEL)) {
495 final List<CSVRecord> records = parser.getRecords();
496 assertEquals(res.length, records.size());
497 assertFalse(records.isEmpty());
498 for (int i = 0; i < res.length; i++) {
499 assertArrayEquals(res[i], records.get(i).values());
500 }
501 }
502 }
503 }
504
505 @Test
506 public void testEmptyString() throws Exception {
507 try (CSVParser parser = CSVParser.parse("", CSVFormat.DEFAULT)) {
508 assertNull(parser.nextRecord());
509 }
510 }
511
512 @Test
513 public void testEndOfFileBehaviorCSV() throws Exception {
514 final String[] codes = { "hello,\r\n\r\nworld,\r\n", "hello,\r\n\r\nworld,", "hello,\r\n\r\nworld,\"\"\r\n", "hello,\r\n\r\nworld,\"\"",
515 "hello,\r\n\r\nworld,\n", "hello,\r\n\r\nworld,", "hello,\r\n\r\nworld,\"\"\n", "hello,\r\n\r\nworld,\"\"" };
516 final String[][] res = { { "hello", "" },
517 { "world", "" } };
518 for (final String code : codes) {
519 try (CSVParser parser = CSVParser.parse(code, CSVFormat.DEFAULT)) {
520 final List<CSVRecord> records = parser.getRecords();
521 assertEquals(res.length, records.size());
522 assertFalse(records.isEmpty());
523 for (int i = 0; i < res.length; i++) {
524 assertArrayEquals(res[i], records.get(i).values());
525 }
526 }
527 }
528 }
529
530 @Test
531 public void testEndOfFileBehaviorExcel() throws Exception {
532 final String[] codes = { "hello,\r\n\r\nworld,\r\n", "hello,\r\n\r\nworld,", "hello,\r\n\r\nworld,\"\"\r\n", "hello,\r\n\r\nworld,\"\"",
533 "hello,\r\n\r\nworld,\n", "hello,\r\n\r\nworld,", "hello,\r\n\r\nworld,\"\"\n", "hello,\r\n\r\nworld,\"\"" };
534 final String[][] res = { { "hello", "" }, { "" },
535 { "world", "" } };
536
537 for (final String code : codes) {
538 try (CSVParser parser = CSVParser.parse(code, CSVFormat.EXCEL)) {
539 final List<CSVRecord> records = parser.getRecords();
540 assertEquals(res.length, records.size());
541 assertFalse(records.isEmpty());
542 for (int i = 0; i < res.length; i++) {
543 assertArrayEquals(res[i], records.get(i).values());
544 }
545 }
546 }
547 }
548
549 @Test
550 public void testExcelFormat1() throws IOException {
551 final String code = "value1,value2,value3,value4\r\na,b,c,d\r\n x,,," + "\r\n\r\n\"\"\"hello\"\"\",\" \"\"world\"\"\",\"abc\ndef\",\r\n";
552 final String[][] res = { { "value1", "value2", "value3", "value4" }, { "a", "b", "c", "d" }, { " x", "", "", "" }, { "" },
553 { "\"hello\"", " \"world\"", "abc\ndef", "" } };
554 try (CSVParser parser = CSVParser.parse(code, CSVFormat.EXCEL)) {
555 final List<CSVRecord> records = parser.getRecords();
556 assertEquals(res.length, records.size());
557 assertFalse(records.isEmpty());
558 for (int i = 0; i < res.length; i++) {
559 assertArrayEquals(res[i], records.get(i).values());
560 }
561 }
562 }
563
564 @Test
565 public void testExcelFormat2() throws Exception {
566 final String code = "foo,baar\r\n\r\nhello,\r\n\r\nworld,\r\n";
567 final String[][] res = { { "foo", "baar" }, { "" }, { "hello", "" }, { "" }, { "world", "" } };
568 try (CSVParser parser = CSVParser.parse(code, CSVFormat.EXCEL)) {
569 final List<CSVRecord> records = parser.getRecords();
570 assertEquals(res.length, records.size());
571 assertFalse(records.isEmpty());
572 for (int i = 0; i < res.length; i++) {
573 assertArrayEquals(res[i], records.get(i).values());
574 }
575 }
576 }
577
578
579
580
581 @Test
582 public void testExcelHeaderCountLessThanData() throws Exception {
583 final String code = "A,B,C,,\r\na,b,c,d,e\r\n";
584 try (CSVParser parser = CSVParser.parse(code, EXCEL_WITH_HEADER)) {
585 parser.getRecords().forEach(record -> {
586 assertEquals("a", record.get("A"));
587 assertEquals("b", record.get("B"));
588 assertEquals("c", record.get("C"));
589 });
590 }
591 }
592
593 @Test
594 public void testFirstEndOfLineCr() throws IOException {
595 final String data = "foo\rbaar,\rhello,world\r,kanu";
596 try (CSVParser parser = CSVParser.parse(data, CSVFormat.DEFAULT)) {
597 final List<CSVRecord> records = parser.getRecords();
598 assertEquals(4, records.size());
599 assertEquals("\r", parser.getFirstEndOfLine());
600 }
601 }
602
603 @Test
604 public void testFirstEndOfLineCrLf() throws IOException {
605 final String data = "foo\r\nbaar,\r\nhello,world\r\n,kanu";
606 try (CSVParser parser = CSVParser.parse(data, CSVFormat.DEFAULT)) {
607 final List<CSVRecord> records = parser.getRecords();
608 assertEquals(4, records.size());
609 assertEquals("\r\n", parser.getFirstEndOfLine());
610 }
611 }
612
613 @Test
614 public void testFirstEndOfLineLf() throws IOException {
615 final String data = "foo\nbaar,\nhello,world\n,kanu";
616 try (CSVParser parser = CSVParser.parse(data, CSVFormat.DEFAULT)) {
617 final List<CSVRecord> records = parser.getRecords();
618 assertEquals(4, records.size());
619 assertEquals("\n", parser.getFirstEndOfLine());
620 }
621 }
622
623 @Test
624 public void testForEach() throws Exception {
625 try (Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
626 CSVParser parser = CSVFormat.DEFAULT.parse(in)) {
627 final List<CSVRecord> records = new ArrayList<>();
628 for (final CSVRecord record : parser) {
629 records.add(record);
630 }
631 assertEquals(3, records.size());
632 assertArrayEquals(new String[] { "a", "b", "c" }, records.get(0).values());
633 assertArrayEquals(new String[] { "1", "2", "3" }, records.get(1).values());
634 assertArrayEquals(new String[] { "x", "y", "z" }, records.get(2).values());
635 }
636 }
637
638 @Test
639 public void testGetHeaderComment_HeaderComment1() throws IOException {
640 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_COMMENT, FORMAT_AUTO_HEADER)) {
641 parser.getRecords();
642
643 assertTrue(parser.hasHeaderComment());
644 assertEquals("header comment", parser.getHeaderComment());
645 }
646 }
647
648 @Test
649 public void testGetHeaderComment_HeaderComment2() throws IOException {
650 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_COMMENT, FORMAT_EXPLICIT_HEADER)) {
651 parser.getRecords();
652
653 assertTrue(parser.hasHeaderComment());
654 assertEquals("header comment", parser.getHeaderComment());
655 }
656 }
657
658 @Test
659 public void testGetHeaderComment_HeaderComment3() throws IOException {
660 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_COMMENT, FORMAT_EXPLICIT_HEADER_NOSKIP)) {
661 parser.getRecords();
662
663 assertFalse(parser.hasHeaderComment());
664 assertNull(parser.getHeaderComment());
665 }
666 }
667
668 @Test
669 public void testGetHeaderComment_HeaderTrailerComment() throws IOException {
670 try (CSVParser parser = CSVParser.parse(CSV_INPUT_MULTILINE_HEADER_TRAILER_COMMENT, FORMAT_AUTO_HEADER)) {
671 parser.getRecords();
672
673 assertTrue(parser.hasHeaderComment());
674 assertEquals("multi-line" + LF + "header comment", parser.getHeaderComment());
675 }
676 }
677
678 @Test
679 public void testGetHeaderComment_NoComment1() throws IOException {
680 try (CSVParser parser = CSVParser.parse(CSV_INPUT_NO_COMMENT, FORMAT_AUTO_HEADER)) {
681 parser.getRecords();
682
683 assertFalse(parser.hasHeaderComment());
684 assertNull(parser.getHeaderComment());
685 }
686 }
687
688 @Test
689 public void testGetHeaderComment_NoComment2() throws IOException {
690 try (CSVParser parser = CSVParser.parse(CSV_INPUT_NO_COMMENT, FORMAT_EXPLICIT_HEADER)) {
691 parser.getRecords();
692
693 assertFalse(parser.hasHeaderComment());
694 assertNull(parser.getHeaderComment());
695 }
696 }
697
698 @Test
699 public void testGetHeaderComment_NoComment3() throws IOException {
700 try (CSVParser parser = CSVParser.parse(CSV_INPUT_NO_COMMENT, FORMAT_EXPLICIT_HEADER_NOSKIP)) {
701 parser.getRecords();
702
703 assertFalse(parser.hasHeaderComment());
704 assertNull(parser.getHeaderComment());
705 }
706 }
707
708 @Test
709 public void testGetHeaderMap() throws Exception {
710 try (CSVParser parser = CSVParser.parse("a,b,c\n1,2,3\nx,y,z", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
711 final Map<String, Integer> headerMap = parser.getHeaderMap();
712 final Iterator<String> columnNames = headerMap.keySet().iterator();
713
714 assertEquals("A", columnNames.next());
715 assertEquals("B", columnNames.next());
716 assertEquals("C", columnNames.next());
717 final Iterator<CSVRecord> records = parser.iterator();
718
719
720 for (int i = 0; i < 3; i++) {
721 assertTrue(records.hasNext());
722 final CSVRecord record = records.next();
723 assertEquals(record.get(0), record.get("A"));
724 assertEquals(record.get(1), record.get("B"));
725 assertEquals(record.get(2), record.get("C"));
726 }
727
728 assertFalse(records.hasNext());
729 }
730 }
731
732 @Test
733 public void testGetHeaderNames() throws IOException {
734 try (CSVParser parser = CSVParser.parse("a,b,c\n1,2,3\nx,y,z", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
735 final Map<String, Integer> nameIndexMap = parser.getHeaderMap();
736 final List<String> headerNames = parser.getHeaderNames();
737 assertNotNull(headerNames);
738 assertEquals(nameIndexMap.size(), headerNames.size());
739 for (int i = 0; i < headerNames.size(); i++) {
740 final String name = headerNames.get(i);
741 assertEquals(i, nameIndexMap.get(name).intValue());
742 }
743 }
744 }
745
746 @Test
747 public void testGetHeaderNamesReadOnly() throws IOException {
748 try (CSVParser parser = CSVParser.parse("a,b,c\n1,2,3\nx,y,z", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
749 final List<String> headerNames = parser.getHeaderNames();
750 assertNotNull(headerNames);
751 assertThrows(UnsupportedOperationException.class, () -> headerNames.add("This is a read-only list."));
752 }
753 }
754
755 @Test
756 public void testGetLine() throws IOException {
757 try (CSVParser parser = CSVParser.parse(CSV_INPUT, CSVFormat.DEFAULT.withIgnoreSurroundingSpaces())) {
758 for (final String[] re : RESULT) {
759 assertArrayEquals(re, parser.nextRecord().values());
760 }
761
762 assertNull(parser.nextRecord());
763 }
764 }
765
766 @Test
767 public void testGetLineNumberWithCR() throws Exception {
768 validateLineNumbers(String.valueOf(CR));
769 }
770
771 @Test
772 public void testGetLineNumberWithCRLF() throws Exception {
773 validateLineNumbers(CRLF);
774 }
775
776 @Test
777 public void testGetLineNumberWithLF() throws Exception {
778 validateLineNumbers(String.valueOf(LF));
779 }
780
781 @Test
782 public void testGetOneLine() throws IOException {
783 try (CSVParser parser = CSVParser.parse(CSV_INPUT_1, CSVFormat.DEFAULT)) {
784 final CSVRecord record = parser.getRecords().get(0);
785 assertArrayEquals(RESULT[0], record.values());
786 }
787 }
788
789
790
791
792
793
794 @Test
795 public void testGetOneLineOneParser() throws IOException {
796 final CSVFormat format = CSVFormat.DEFAULT;
797 try (PipedWriter writer = new PipedWriter();
798 PipedReader origin = new PipedReader(writer);
799 CSVParser parser = CSVParser.builder()
800 .setReader(origin)
801 .setFormat(format)
802 .get()) {
803 writer.append(CSV_INPUT_1);
804 writer.append(format.getRecordSeparator());
805 final CSVRecord record1 = parser.nextRecord();
806 assertArrayEquals(RESULT[0], record1.values());
807 writer.append(CSV_INPUT_2);
808 writer.append(format.getRecordSeparator());
809 final CSVRecord record2 = parser.nextRecord();
810 assertArrayEquals(RESULT[1], record2.values());
811 }
812 }
813
814 @Test
815 public void testGetRecordFourBytesRead() throws Exception {
816 final String code = "id,a,b,c\n" +
817 "1,😊,🤔,😂\n" +
818 "2,😊,🤔,😂\n" +
819 "3,😊,🤔,😂\n";
820 final CSVFormat format = CSVFormat.Builder.create()
821 .setDelimiter(',')
822 .setQuote('\'')
823 .get();
824 try (CSVParser parser = CSVParser.builder().setReader(new StringReader(code)).setFormat(format).setCharset(UTF_8).setTrackBytes(true).get()) {
825 CSVRecord record = new CSVRecord(parser, null, null, 1L, 0L, 0L);
826
827 assertEquals(0, parser.getRecordNumber());
828 assertNotNull(record = parser.nextRecord());
829 assertEquals(1, record.getRecordNumber());
830 assertEquals(code.indexOf('i'), record.getCharacterPosition());
831 assertEquals(record.getBytePosition(), record.getCharacterPosition());
832
833 assertNotNull(record = parser.nextRecord());
834 assertEquals(2, record.getRecordNumber());
835 assertEquals(code.indexOf('1'), record.getCharacterPosition());
836 assertEquals(record.getBytePosition(), record.getCharacterPosition());
837 assertNotNull(record = parser.nextRecord());
838 assertEquals(3, record.getRecordNumber());
839 assertEquals(code.indexOf('2'), record.getCharacterPosition());
840 assertEquals(record.getBytePosition(), 26);
841 assertNotNull(record = parser.nextRecord());
842 assertEquals(4, record.getRecordNumber());
843 assertEquals(code.indexOf('3'), record.getCharacterPosition());
844 assertEquals(record.getBytePosition(), 43);
845 }
846 }
847
848 @Test
849 public void testGetRecordNumberWithCR() throws Exception {
850 validateRecordNumbers(String.valueOf(CR));
851 }
852
853 @Test
854 public void testGetRecordNumberWithCRLF() throws Exception {
855 validateRecordNumbers(CRLF);
856 }
857
858 @Test
859 public void testGetRecordNumberWithLF() throws Exception {
860 validateRecordNumbers(String.valueOf(LF));
861 }
862
863 @Test
864 public void testGetRecordPositionWithCRLF() throws Exception {
865 validateRecordPosition(CRLF);
866 }
867
868 @Test
869 public void testGetRecordPositionWithLF() throws Exception {
870 validateRecordPosition(String.valueOf(LF));
871 }
872
873 @Test
874 public void testGetRecords() throws IOException {
875 try (CSVParser parser = CSVParser.parse(CSV_INPUT, CSVFormat.DEFAULT.withIgnoreSurroundingSpaces())) {
876 final List<CSVRecord> records = parser.getRecords();
877 assertEquals(RESULT.length, records.size());
878 assertFalse(records.isEmpty());
879 for (int i = 0; i < RESULT.length; i++) {
880 assertArrayEquals(RESULT[i], records.get(i).values());
881 }
882 }
883 }
884
885 @Test
886 public void testGetRecordsFromBrokenInputStream() throws IOException {
887 @SuppressWarnings("resource")
888 final CSVParser parser = CSVParser.parse(new BrokenInputStream(), UTF_8, CSVFormat.DEFAULT);
889 assertThrows(UncheckedIOException.class, parser::getRecords);
890
891 }
892
893 @ParameterizedTest
894 @ValueSource(longs = { -1, 0, 1, 2, 3, 4, Long.MAX_VALUE })
895 public void testGetRecordsMaxRows(final long maxRows) throws IOException {
896 try (CSVParser parser = CSVParser.parse(CSV_INPUT, CSVFormat.DEFAULT.builder().setIgnoreSurroundingSpaces(true).setMaxRows(maxRows).get())) {
897 final List<CSVRecord> records = parser.getRecords();
898 final long expectedLength = maxRows <= 0 || maxRows > RESULT.length ? RESULT.length : maxRows;
899 assertEquals(expectedLength, records.size());
900 assertFalse(records.isEmpty());
901 for (int i = 0; i < expectedLength; i++) {
902 assertArrayEquals(RESULT[i], records.get(i).values());
903 }
904 }
905 }
906
907 @Test
908 public void testGetRecordThreeBytesRead() throws Exception {
909 final String code = "id,date,val5,val4\n" +
910 "11111111111111,'4017-09-01',きちんと節分近くには咲いてる~,v4\n" +
911 "22222222222222,'4017-01-01',おはよう私の友人~,v4\n" +
912 "33333333333333,'4017-01-01',きる自然の力ってすごいな~,v4\n";
913 final CSVFormat format = CSVFormat.Builder.create()
914 .setDelimiter(',')
915 .setQuote('\'')
916 .get();
917 try (CSVParser parser = CSVParser.builder().setReader(new StringReader(code)).setFormat(format).setCharset(UTF_8).setTrackBytes(true).get()) {
918 CSVRecord record = new CSVRecord(parser, null, null, 1L, 0L, 0L);
919
920 assertEquals(0, parser.getRecordNumber());
921 assertNotNull(record = parser.nextRecord());
922 assertEquals(1, record.getRecordNumber());
923 assertEquals(code.indexOf('i'), record.getCharacterPosition());
924 assertEquals(record.getBytePosition(), record.getCharacterPosition());
925
926 assertNotNull(record = parser.nextRecord());
927 assertEquals(2, record.getRecordNumber());
928 assertEquals(code.indexOf('1'), record.getCharacterPosition());
929 assertEquals(record.getBytePosition(), record.getCharacterPosition());
930
931 assertNotNull(record = parser.nextRecord());
932 assertEquals(3, record.getRecordNumber());
933 assertEquals(code.indexOf('2'), record.getCharacterPosition());
934 assertEquals(record.getBytePosition(), 95);
935
936 assertNotNull(record = parser.nextRecord());
937 assertEquals(4, record.getRecordNumber());
938 assertEquals(code.indexOf('3'), record.getCharacterPosition());
939 assertEquals(record.getBytePosition(), 154);
940 }
941 }
942
943 @Test
944 public void testGetRecordWithMultiLineValues() throws Exception {
945 try (CSVParser parser = CSVParser.parse("\"a\r\n1\",\"a\r\n2\"" + CRLF + "\"b\r\n1\",\"b\r\n2\"" + CRLF + "\"c\r\n1\",\"c\r\n2\"",
946 CSVFormat.DEFAULT.withRecordSeparator(CRLF))) {
947 CSVRecord record;
948 assertEquals(0, parser.getRecordNumber());
949 assertEquals(0, parser.getCurrentLineNumber());
950 assertNotNull(record = parser.nextRecord());
951 assertEquals(3, parser.getCurrentLineNumber());
952 assertEquals(1, record.getRecordNumber());
953 assertEquals(1, parser.getRecordNumber());
954 assertNotNull(record = parser.nextRecord());
955 assertEquals(6, parser.getCurrentLineNumber());
956 assertEquals(2, record.getRecordNumber());
957 assertEquals(2, parser.getRecordNumber());
958 assertNotNull(record = parser.nextRecord());
959 assertEquals(9, parser.getCurrentLineNumber());
960 assertEquals(3, record.getRecordNumber());
961 assertEquals(3, parser.getRecordNumber());
962 assertNull(record = parser.nextRecord());
963 assertEquals(9, parser.getCurrentLineNumber());
964 assertEquals(3, parser.getRecordNumber());
965 }
966 }
967
968 @Test
969 public void testGetTrailerComment_HeaderComment1() throws IOException {
970 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_COMMENT, FORMAT_AUTO_HEADER)) {
971 parser.getRecords();
972 assertFalse(parser.hasTrailerComment());
973 assertNull(parser.getTrailerComment());
974 }
975 }
976
977 @Test
978 public void testGetTrailerComment_HeaderComment2() throws IOException {
979 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_COMMENT, FORMAT_EXPLICIT_HEADER)) {
980 parser.getRecords();
981 assertFalse(parser.hasTrailerComment());
982 assertNull(parser.getTrailerComment());
983 }
984 }
985
986 @Test
987 public void testGetTrailerComment_HeaderComment3() throws IOException {
988 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_COMMENT, FORMAT_EXPLICIT_HEADER_NOSKIP)) {
989 parser.getRecords();
990 assertFalse(parser.hasTrailerComment());
991 assertNull(parser.getTrailerComment());
992 }
993 }
994
995 @Test
996 public void testGetTrailerComment_HeaderTrailerComment1() throws IOException {
997 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_TRAILER_COMMENT, FORMAT_AUTO_HEADER)) {
998 parser.getRecords();
999 assertTrue(parser.hasTrailerComment());
1000 assertEquals("comment", parser.getTrailerComment());
1001 }
1002 }
1003
1004 @Test
1005 public void testGetTrailerComment_HeaderTrailerComment2() throws IOException {
1006 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_TRAILER_COMMENT, FORMAT_EXPLICIT_HEADER)) {
1007 parser.getRecords();
1008 assertTrue(parser.hasTrailerComment());
1009 assertEquals("comment", parser.getTrailerComment());
1010 }
1011 }
1012
1013 @Test
1014 public void testGetTrailerComment_HeaderTrailerComment3() throws IOException {
1015 try (CSVParser parser = CSVParser.parse(CSV_INPUT_HEADER_TRAILER_COMMENT, FORMAT_EXPLICIT_HEADER_NOSKIP)) {
1016 parser.getRecords();
1017 assertTrue(parser.hasTrailerComment());
1018 assertEquals("comment", parser.getTrailerComment());
1019 }
1020 }
1021
1022 @Test
1023 public void testGetTrailerComment_MultilineComment() throws IOException {
1024 try (CSVParser parser = CSVParser.parse(CSV_INPUT_MULTILINE_HEADER_TRAILER_COMMENT, FORMAT_AUTO_HEADER)) {
1025 parser.getRecords();
1026 assertTrue(parser.hasTrailerComment());
1027 assertEquals("multi-line" + LF + "comment", parser.getTrailerComment());
1028 }
1029 }
1030
1031 @Test
1032 public void testHeader() throws Exception {
1033 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1034
1035 try (CSVParser parser = CSVFormat.DEFAULT.withHeader().parse(in)) {
1036 final Iterator<CSVRecord> records = parser.iterator();
1037
1038 for (int i = 0; i < 2; i++) {
1039 assertTrue(records.hasNext());
1040 final CSVRecord record = records.next();
1041 assertEquals(record.get(0), record.get("a"));
1042 assertEquals(record.get(1), record.get("b"));
1043 assertEquals(record.get(2), record.get("c"));
1044 }
1045
1046 assertFalse(records.hasNext());
1047 }
1048 }
1049
1050 @Test
1051 public void testHeaderComment() throws Exception {
1052 final Reader in = new StringReader("# comment\na,b,c\n1,2,3\nx,y,z");
1053 try (CSVParser parser = CSVFormat.DEFAULT.withCommentMarker('#').withHeader().parse(in)) {
1054 final Iterator<CSVRecord> records = parser.iterator();
1055 for (int i = 0; i < 2; i++) {
1056 assertTrue(records.hasNext());
1057 final CSVRecord record = records.next();
1058 assertEquals(record.get(0), record.get("a"));
1059 assertEquals(record.get(1), record.get("b"));
1060 assertEquals(record.get(2), record.get("c"));
1061 }
1062 assertFalse(records.hasNext());
1063 }
1064 }
1065
1066 @Test
1067 public void testHeaderMissing() throws Exception {
1068 final Reader in = new StringReader("a,,c\n1,2,3\nx,y,z");
1069 try (CSVParser parser = CSVFormat.DEFAULT.withHeader().withAllowMissingColumnNames().parse(in)) {
1070 final Iterator<CSVRecord> records = parser.iterator();
1071 for (int i = 0; i < 2; i++) {
1072 assertTrue(records.hasNext());
1073 final CSVRecord record = records.next();
1074 assertEquals(record.get(0), record.get("a"));
1075 assertEquals(record.get(2), record.get("c"));
1076 }
1077 assertFalse(records.hasNext());
1078 }
1079 }
1080
1081 @Test
1082 public void testHeaderMissingWithNull() throws Exception {
1083 final Reader in = new StringReader("a,,c,,e\n1,2,3,4,5\nv,w,x,y,z");
1084 try (CSVParser parser = CSVFormat.DEFAULT.withHeader().withNullString("").withAllowMissingColumnNames().parse(in)) {
1085 parser.iterator();
1086 }
1087 }
1088
1089 @Test
1090 public void testHeadersMissing() throws Exception {
1091 try (Reader in = new StringReader("a,,c,,e\n1,2,3,4,5\nv,w,x,y,z");
1092 CSVParser parser = CSVFormat.DEFAULT.withHeader().withAllowMissingColumnNames().parse(in)) {
1093 parser.iterator();
1094 }
1095 }
1096
1097 @Test
1098 public void testHeadersMissingException() {
1099 final Reader in = new StringReader("a,,c,,e\n1,2,3,4,5\nv,w,x,y,z");
1100 assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
1101 }
1102
1103 @Test
1104 public void testHeadersMissingOneColumnException() {
1105 final Reader in = new StringReader("a,,c,d,e\n1,2,3,4,5\nv,w,x,y,z");
1106 assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
1107 }
1108
1109 @Test
1110 public void testHeadersWithNullColumnName() throws IOException {
1111 final Reader in = new StringReader("header1,null,header3\n1,2,3\n4,5,6");
1112 try (CSVParser parser = CSVFormat.DEFAULT.withHeader().withNullString("null").withAllowMissingColumnNames().parse(in)) {
1113 final Iterator<CSVRecord> records = parser.iterator();
1114 final CSVRecord record = records.next();
1115
1116 @SuppressWarnings("resource")
1117 final CSVParser recordParser = record.getParser();
1118 assertEquals(Arrays.asList("header1", "header3"), recordParser.getHeaderNames());
1119 assertEquals(2, recordParser.getHeaderMap().size());
1120 }
1121 }
1122
1123 @Test
1124 public void testIgnoreCaseHeaderMapping() throws Exception {
1125 final Reader reader = new StringReader("1,2,3");
1126 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("One", "TWO", "three").withIgnoreHeaderCase().parse(reader)) {
1127 final Iterator<CSVRecord> records = parser.iterator();
1128 final CSVRecord record = records.next();
1129 assertEquals("1", record.get("one"));
1130 assertEquals("2", record.get("two"));
1131 assertEquals("3", record.get("THREE"));
1132 }
1133 }
1134
1135 @Test
1136 public void testIgnoreEmptyLines() throws IOException {
1137 final String code = "\nfoo,baar\n\r\n,\n\n,world\r\n\n";
1138
1139
1140 try (CSVParser parser = CSVParser.parse(code, CSVFormat.DEFAULT)) {
1141 final List<CSVRecord> records = parser.getRecords();
1142 assertEquals(3, records.size());
1143 }
1144 }
1145
1146 @Test
1147 public void testInvalidFormat() {
1148 assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withDelimiter(CR));
1149 }
1150
1151 @Test
1152 public void testIterator() throws Exception {
1153 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1154 try (CSVParser parser = CSVFormat.DEFAULT.parse(in)) {
1155 final Iterator<CSVRecord> iterator = parser.iterator();
1156 assertTrue(iterator.hasNext());
1157 assertThrows(UnsupportedOperationException.class, iterator::remove);
1158 assertArrayEquals(new String[] { "a", "b", "c" }, iterator.next().values());
1159 assertArrayEquals(new String[] { "1", "2", "3" }, iterator.next().values());
1160 assertTrue(iterator.hasNext());
1161 assertTrue(iterator.hasNext());
1162 assertTrue(iterator.hasNext());
1163 assertArrayEquals(new String[] { "x", "y", "z" }, iterator.next().values());
1164 assertFalse(iterator.hasNext());
1165 assertThrows(NoSuchElementException.class, iterator::next);
1166 }
1167 }
1168
1169 @ParameterizedTest
1170 @ValueSource(longs = { -1, 0, 1, 2, 3, 4, 5, Long.MAX_VALUE })
1171 public void testIteratorMaxRows(final long maxRows) throws Exception {
1172 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1173 try (CSVParser parser = CSVFormat.DEFAULT.builder().setMaxRows(maxRows).get().parse(in)) {
1174 final Iterator<CSVRecord> iterator = parser.iterator();
1175 assertTrue(iterator.hasNext());
1176 assertThrows(UnsupportedOperationException.class, iterator::remove);
1177 assertArrayEquals(new String[] { "a", "b", "c" }, iterator.next().values());
1178 final boolean noLimit = maxRows <= 0;
1179 final int fixtureLen = 3;
1180 final long expectedLen = noLimit ? fixtureLen : Math.min(fixtureLen, maxRows);
1181 if (expectedLen > 1) {
1182 assertTrue(iterator.hasNext());
1183 assertArrayEquals(new String[] { "1", "2", "3" }, iterator.next().values());
1184 }
1185 assertEquals(expectedLen > 2, iterator.hasNext());
1186
1187 assertEquals(expectedLen > 2, iterator.hasNext());
1188 if (expectedLen == fixtureLen) {
1189 assertTrue(iterator.hasNext());
1190 assertArrayEquals(new String[] { "x", "y", "z" }, iterator.next().values());
1191 }
1192 assertFalse(iterator.hasNext());
1193 assertThrows(NoSuchElementException.class, iterator::next);
1194 }
1195 }
1196
1197 @Test
1198 public void testIteratorSequenceBreaking() throws IOException {
1199 final String fiveRows = "1\n2\n3\n4\n5\n";
1200
1201 try (CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(fiveRows))) {
1202 final Iterator<CSVRecord> iter = parser.iterator();
1203 int recordNumber = 0;
1204 while (iter.hasNext()) {
1205 final CSVRecord record = iter.next();
1206 recordNumber++;
1207 assertEquals(String.valueOf(recordNumber), record.get(0));
1208 if (recordNumber >= 2) {
1209 break;
1210 }
1211 }
1212 iter.hasNext();
1213 while (iter.hasNext()) {
1214 final CSVRecord record = iter.next();
1215 recordNumber++;
1216 assertEquals(String.valueOf(recordNumber), record.get(0));
1217 }
1218 }
1219
1220 try (CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(fiveRows))) {
1221 int recordNumber = 0;
1222 for (final CSVRecord record : parser) {
1223 recordNumber++;
1224 assertEquals(String.valueOf(recordNumber), record.get(0));
1225 if (recordNumber >= 2) {
1226 break;
1227 }
1228 }
1229 for (final CSVRecord record : parser) {
1230 recordNumber++;
1231 assertEquals(String.valueOf(recordNumber), record.get(0));
1232 }
1233 }
1234
1235 try (CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(fiveRows))) {
1236 int recordNumber = 0;
1237 for (final CSVRecord record : parser) {
1238 recordNumber++;
1239 assertEquals(String.valueOf(recordNumber), record.get(0));
1240 if (recordNumber >= 2) {
1241 break;
1242 }
1243 }
1244 parser.iterator().hasNext();
1245 for (final CSVRecord record : parser) {
1246 recordNumber++;
1247 assertEquals(String.valueOf(recordNumber), record.get(0));
1248 }
1249 }
1250 }
1251
1252 @Test
1253 public void testLineFeedEndings() throws IOException {
1254 final String code = "foo\nbaar,\nhello,world\n,kanu";
1255 try (CSVParser parser = CSVParser.parse(code, CSVFormat.DEFAULT)) {
1256 final List<CSVRecord> records = parser.getRecords();
1257 assertEquals(4, records.size());
1258 }
1259 }
1260
1261 @Test
1262 public void testMappedButNotSetAsOutlook2007ContactExport() throws Exception {
1263 final Reader in = new StringReader("a,b,c\n1,2\nx,y,z");
1264 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("A", "B", "C").withSkipHeaderRecord().parse(in)) {
1265 final Iterator<CSVRecord> records = parser.iterator();
1266 CSVRecord record;
1267
1268 record = records.next();
1269 assertTrue(record.isMapped("A"));
1270 assertTrue(record.isMapped("B"));
1271 assertTrue(record.isMapped("C"));
1272 assertTrue(record.isSet("A"));
1273 assertTrue(record.isSet("B"));
1274 assertFalse(record.isSet("C"));
1275 assertEquals("1", record.get("A"));
1276 assertEquals("2", record.get("B"));
1277 assertFalse(record.isConsistent());
1278
1279 record = records.next();
1280 assertTrue(record.isMapped("A"));
1281 assertTrue(record.isMapped("B"));
1282 assertTrue(record.isMapped("C"));
1283 assertTrue(record.isSet("A"));
1284 assertTrue(record.isSet("B"));
1285 assertTrue(record.isSet("C"));
1286 assertEquals("x", record.get("A"));
1287 assertEquals("y", record.get("B"));
1288 assertEquals("z", record.get("C"));
1289 assertTrue(record.isConsistent());
1290
1291 assertFalse(records.hasNext());
1292 }
1293 }
1294
1295 @Test
1296 @Disabled
1297 public void testMongoDbCsv() throws Exception {
1298 try (CSVParser parser = CSVParser.parse("\"a a\",b,c" + LF + "d,e,f", CSVFormat.MONGODB_CSV)) {
1299 final Iterator<CSVRecord> itr1 = parser.iterator();
1300 final Iterator<CSVRecord> itr2 = parser.iterator();
1301
1302 final CSVRecord first = itr1.next();
1303 assertEquals("a a", first.get(0));
1304 assertEquals("b", first.get(1));
1305 assertEquals("c", first.get(2));
1306
1307 final CSVRecord second = itr2.next();
1308 assertEquals("d", second.get(0));
1309 assertEquals("e", second.get(1));
1310 assertEquals("f", second.get(2));
1311 }
1312 }
1313
1314 @Test
1315
1316 public void testMultipleIterators() throws Exception {
1317 try (CSVParser parser = CSVParser.parse("a,b,c" + CRLF + "d,e,f", CSVFormat.DEFAULT)) {
1318 final Iterator<CSVRecord> itr1 = parser.iterator();
1319
1320 final CSVRecord first = itr1.next();
1321 assertEquals("a", first.get(0));
1322 assertEquals("b", first.get(1));
1323 assertEquals("c", first.get(2));
1324
1325 final CSVRecord second = itr1.next();
1326 assertEquals("d", second.get(0));
1327 assertEquals("e", second.get(1));
1328 assertEquals("f", second.get(2));
1329 }
1330 }
1331
1332 @Test
1333 public void testNewCSVParserNullReaderFormat() {
1334 assertThrows(NullPointerException.class, () -> new CSVParser(null, CSVFormat.DEFAULT));
1335 }
1336
1337 @Test
1338 public void testNewCSVParserReaderNullFormat() {
1339 assertThrows(NullPointerException.class, () -> new CSVParser(new StringReader(""), null));
1340 }
1341
1342 @Test
1343 public void testNoHeaderMap() throws Exception {
1344 try (CSVParser parser = CSVParser.parse("a,b,c\n1,2,3\nx,y,z", CSVFormat.DEFAULT)) {
1345 assertNull(parser.getHeaderMap());
1346 }
1347 }
1348
1349 @Test
1350 public void testNotValueCSV() throws IOException {
1351 final String source = "#";
1352 final CSVFormat csvFormat = CSVFormat.DEFAULT.withCommentMarker('#');
1353 try (CSVParser csvParser = csvFormat.parse(new StringReader(source))) {
1354 final CSVRecord csvRecord = csvParser.nextRecord();
1355 assertNull(csvRecord);
1356 }
1357 }
1358
1359 @Test
1360 public void testParse() throws Exception {
1361 final URL url = ClassLoader.getSystemClassLoader().getResource("org/apache/commons/csv/CSVFileParser/test.csv");
1362 final CSVFormat format = CSVFormat.DEFAULT.builder().setHeader("A", "B", "C", "D").get();
1363 final Charset charset = StandardCharsets.UTF_8;
1364
1365 try (CSVParser parser = CSVParser.parse(new InputStreamReader(url.openStream(), charset), format)) {
1366 parseFully(parser);
1367 }
1368 try (CSVParser parser = CSVParser.builder().setReader(new InputStreamReader(url.openStream(), charset)).setFormat(format).get()) {
1369 parseFully(parser);
1370 }
1371
1372 final Path path = Paths.get(url.toURI());
1373 final String string = new String(Files.readAllBytes(path), charset);
1374 try (CSVParser parser = CSVParser.parse(string, format)) {
1375 parseFully(parser);
1376 }
1377 try (CSVParser parser = CSVParser.builder().setCharSequence(string).setFormat(format).get()) {
1378 parseFully(parser);
1379 }
1380
1381 final File file = new File(url.toURI());
1382 try (CSVParser parser = CSVParser.parse(file, charset, format)) {
1383 parseFully(parser);
1384 }
1385 try (CSVParser parser = CSVParser.builder().setFile(file).setCharset(charset).setFormat(format).get()) {
1386 parseFully(parser);
1387 }
1388
1389 try (CSVParser parser = CSVParser.parse(url.openStream(), charset, format)) {
1390 parseFully(parser);
1391 }
1392 try (CSVParser parser = CSVParser.builder().setInputStream(url.openStream()).setCharset(charset).setFormat(format).get()) {
1393 parseFully(parser);
1394 }
1395
1396 try (CSVParser parser = CSVParser.parse(path, charset, format)) {
1397 parseFully(parser);
1398 }
1399 try (CSVParser parser = CSVParser.builder().setPath(path).setCharset(charset).setFormat(format).get()) {
1400 parseFully(parser);
1401 }
1402
1403 try (CSVParser parser = CSVParser.parse(url, charset, format)) {
1404 parseFully(parser);
1405 }
1406 try (CSVParser parser = CSVParser.builder().setURI(url.toURI()).setCharset(charset).setFormat(format).get()) {
1407 parseFully(parser);
1408 }
1409
1410 try (CSVParser parser = new CSVParser(new InputStreamReader(url.openStream(), charset), format)) {
1411 parseFully(parser);
1412 }
1413 try (CSVParser parser = CSVParser.builder().setReader(new InputStreamReader(url.openStream(), charset)).setFormat(format).get()) {
1414 parseFully(parser);
1415 }
1416
1417 try (CSVParser parser = new CSVParser(new InputStreamReader(url.openStream(), charset), format, 0, 1)) {
1418 parseFully(parser);
1419 }
1420 try (CSVParser parser = CSVParser.builder().setReader(new InputStreamReader(url.openStream(), charset)).setFormat(format).setCharacterOffset(0)
1421 .setRecordNumber(0).get()) {
1422 parseFully(parser);
1423 }
1424 }
1425
1426 @Test
1427 public void testParseFileCharsetNullFormat() throws IOException {
1428 final File file = new File("src/test/resources/org/apache/commons/csv/CSVFileParser/test.csv");
1429 try (CSVParser parser = CSVParser.parse(file, Charset.defaultCharset(), null)) {
1430
1431 parseFully(parser);
1432 }
1433 }
1434
1435 @Test
1436 public void testParseInputStreamCharsetNullFormat() throws IOException {
1437 try (InputStream in = Files.newInputStream(Paths.get("src/test/resources/org/apache/commons/csv/CSVFileParser/test.csv"));
1438 CSVParser parser = CSVParser.parse(in, Charset.defaultCharset(), null)) {
1439
1440 parseFully(parser);
1441 }
1442 }
1443
1444 @Test
1445 public void testParseNullFileFormat() {
1446 assertThrows(NullPointerException.class, () -> CSVParser.parse((File) null, Charset.defaultCharset(), CSVFormat.DEFAULT));
1447 }
1448
1449 @Test
1450 public void testParseNullPathFormat() {
1451 assertThrows(NullPointerException.class, () -> CSVParser.parse((Path) null, Charset.defaultCharset(), CSVFormat.DEFAULT));
1452 }
1453
1454 @Test
1455 public void testParseNullStringFormat() {
1456 assertThrows(NullPointerException.class, () -> CSVParser.parse((String) null, CSVFormat.DEFAULT));
1457 }
1458
1459 @Test
1460 public void testParseNullUrlCharsetFormat() {
1461 assertThrows(NullPointerException.class, () -> CSVParser.parse((URL) null, Charset.defaultCharset(), CSVFormat.DEFAULT));
1462 }
1463
1464 @Test
1465 public void testParsePathCharsetNullFormat() throws IOException {
1466 final Path path = Paths.get("src/test/resources/org/apache/commons/csv/CSVFileParser/test.csv");
1467 try (CSVParser parser = CSVParser.parse(path, Charset.defaultCharset(), null)) {
1468
1469 parseFully(parser);
1470 }
1471 }
1472
1473 @Test
1474 public void testParserUrlNullCharsetFormat() throws IOException {
1475 final URL url = ClassLoader.getSystemClassLoader().getResource("org/apache/commons/csv/CSVFileParser/test.csv");
1476 try (CSVParser parser = CSVParser.parse(url, null, CSVFormat.DEFAULT)) {
1477
1478 parseFully(parser);
1479 }
1480 }
1481
1482 @Test
1483 public void testParseStringNullFormat() throws IOException {
1484 try (CSVParser parser = CSVParser.parse("1,2,3", null)) {
1485
1486 final List<CSVRecord> records = parser.getRecords();
1487 assertEquals(1, records.size());
1488 final CSVRecord record = records.get(0);
1489 assertEquals(3, record.size());
1490 assertEquals("1", record.get(0));
1491 assertEquals("2", record.get(1));
1492 assertEquals("3", record.get(2));
1493 }
1494 }
1495
1496 @Test
1497 public void testParseUrlCharsetNullFormat() throws IOException {
1498 final URL url = ClassLoader.getSystemClassLoader().getResource("org/apache/commons/csv/CSVFileParser/test.csv");
1499 try (CSVParser parser = CSVParser.parse(url, Charset.defaultCharset(), null)) {
1500
1501 parseFully(parser);
1502 }
1503 }
1504
1505 @Test
1506 public void testParseWithDelimiterStringWithEscape() throws IOException {
1507 final String source = "a![!|!]b![|]c[|]xyz\r\nabc[abc][|]xyz";
1508 final CSVFormat csvFormat = CSVFormat.DEFAULT.builder().setDelimiter("[|]").setEscape('!').get();
1509 try (CSVParser csvParser = csvFormat.parse(new StringReader(source))) {
1510 CSVRecord csvRecord = csvParser.nextRecord();
1511 assertEquals("a[|]b![|]c", csvRecord.get(0));
1512 assertEquals("xyz", csvRecord.get(1));
1513 csvRecord = csvParser.nextRecord();
1514 assertEquals("abc[abc]", csvRecord.get(0));
1515 assertEquals("xyz", csvRecord.get(1));
1516 }
1517 }
1518
1519 @Test
1520 public void testParseWithDelimiterStringWithQuote() throws IOException {
1521 final String source = "'a[|]b[|]c'[|]xyz\r\nabc[abc][|]xyz";
1522 final CSVFormat csvFormat = CSVFormat.DEFAULT.builder().setDelimiter("[|]").setQuote('\'').get();
1523 try (CSVParser csvParser = csvFormat.parse(new StringReader(source))) {
1524 CSVRecord csvRecord = csvParser.nextRecord();
1525 assertEquals("a[|]b[|]c", csvRecord.get(0));
1526 assertEquals("xyz", csvRecord.get(1));
1527 csvRecord = csvParser.nextRecord();
1528 assertEquals("abc[abc]", csvRecord.get(0));
1529 assertEquals("xyz", csvRecord.get(1));
1530 }
1531 }
1532
1533 @Test
1534 public void testParseWithDelimiterWithEscape() throws IOException {
1535 final String source = "a!,b!,c,xyz";
1536 final CSVFormat csvFormat = CSVFormat.DEFAULT.withEscape('!');
1537 try (CSVParser csvParser = csvFormat.parse(new StringReader(source))) {
1538 final CSVRecord csvRecord = csvParser.nextRecord();
1539 assertEquals("a,b,c", csvRecord.get(0));
1540 assertEquals("xyz", csvRecord.get(1));
1541 }
1542 }
1543
1544 @Test
1545 public void testParseWithDelimiterWithQuote() throws IOException {
1546 final String source = "'a,b,c',xyz";
1547 final CSVFormat csvFormat = CSVFormat.DEFAULT.withQuote('\'');
1548 try (CSVParser csvParser = csvFormat.parse(new StringReader(source))) {
1549 final CSVRecord csvRecord = csvParser.nextRecord();
1550 assertEquals("a,b,c", csvRecord.get(0));
1551 assertEquals("xyz", csvRecord.get(1));
1552 }
1553 }
1554
1555 @Test
1556 public void testParseWithQuoteThrowsException() {
1557 final CSVFormat csvFormat = CSVFormat.DEFAULT.withQuote('\'');
1558 assertThrows(IOException.class, () -> csvFormat.parse(new StringReader("'a,b,c','")).nextRecord());
1559 assertThrows(IOException.class, () -> csvFormat.parse(new StringReader("'a,b,c'abc,xyz")).nextRecord());
1560 assertThrows(IOException.class, () -> csvFormat.parse(new StringReader("'abc'a,b,c',xyz")).nextRecord());
1561 }
1562
1563 @Test
1564 public void testParseWithQuoteWithEscape() throws IOException {
1565 final String source = "'a?,b?,c?d',xyz";
1566 final CSVFormat csvFormat = CSVFormat.DEFAULT.withQuote('\'').withEscape('?');
1567 try (CSVParser csvParser = csvFormat.parse(new StringReader(source))) {
1568 final CSVRecord csvRecord = csvParser.nextRecord();
1569 assertEquals("a,b,c?d", csvRecord.get(0));
1570 assertEquals("xyz", csvRecord.get(1));
1571 }
1572 }
1573
1574 @ParameterizedTest
1575 @EnumSource(CSVFormat.Predefined.class)
1576 public void testParsingPrintedEmptyFirstColumn(final CSVFormat.Predefined format) throws Exception {
1577 final String[][] lines = { { "a", "b" }, { "", "x" } };
1578 final StringWriter buf = new StringWriter();
1579 try (CSVPrinter printer = new CSVPrinter(buf, format.getFormat())) {
1580 printer.printRecords(Stream.of(lines));
1581 }
1582 try (CSVParser csvRecords = CSVParser.builder()
1583 .setReader(new StringReader(buf.toString()))
1584 .setFormat(format.getFormat())
1585 .get()) {
1586 for (final String[] line : lines) {
1587 assertArrayEquals(line, csvRecords.nextRecord().values());
1588 }
1589 assertNull(csvRecords.nextRecord());
1590 }
1591 }
1592
1593 @Test
1594 public void testProvidedHeader() throws Exception {
1595 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1596 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("A", "B", "C").parse(in)) {
1597 final Iterator<CSVRecord> records = parser.iterator();
1598 for (int i = 0; i < 3; i++) {
1599 assertTrue(records.hasNext());
1600 final CSVRecord record = records.next();
1601 assertTrue(record.isMapped("A"));
1602 assertTrue(record.isMapped("B"));
1603 assertTrue(record.isMapped("C"));
1604 assertFalse(record.isMapped("NOT MAPPED"));
1605 assertEquals(record.get(0), record.get("A"));
1606 assertEquals(record.get(1), record.get("B"));
1607 assertEquals(record.get(2), record.get("C"));
1608 }
1609 assertFalse(records.hasNext());
1610 }
1611 }
1612
1613 @Test
1614 public void testProvidedHeaderAuto() throws Exception {
1615 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1616 try (CSVParser parser = CSVFormat.DEFAULT.withHeader().parse(in)) {
1617 final Iterator<CSVRecord> records = parser.iterator();
1618 for (int i = 0; i < 2; i++) {
1619 assertTrue(records.hasNext());
1620 final CSVRecord record = records.next();
1621 assertTrue(record.isMapped("a"));
1622 assertTrue(record.isMapped("b"));
1623 assertTrue(record.isMapped("c"));
1624 assertFalse(record.isMapped("NOT MAPPED"));
1625 assertEquals(record.get(0), record.get("a"));
1626 assertEquals(record.get(1), record.get("b"));
1627 assertEquals(record.get(2), record.get("c"));
1628 }
1629 assertFalse(records.hasNext());
1630 }
1631 }
1632
1633 @Test
1634 public void testRepeatedHeadersAreReturnedInCSVRecordHeaderNames() throws IOException {
1635 final Reader in = new StringReader("header1,header2,header1\n1,2,3\n4,5,6");
1636 try (CSVParser parser = CSVFormat.DEFAULT.withFirstRecordAsHeader().withTrim().parse(in)) {
1637 final Iterator<CSVRecord> records = parser.iterator();
1638 final CSVRecord record = records.next();
1639 @SuppressWarnings("resource")
1640 final CSVParser recordParser = record.getParser();
1641 assertEquals(Arrays.asList("header1", "header2", "header1"), recordParser.getHeaderNames());
1642 }
1643 }
1644
1645 @Test
1646 public void testRoundtrip() throws Exception {
1647 final StringWriter out = new StringWriter();
1648 final String data = "a,b,c\r\n1,2,3\r\nx,y,z\r\n";
1649 try (CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT);
1650 CSVParser parse = CSVParser.parse(data, CSVFormat.DEFAULT)) {
1651 for (final CSVRecord record : parse) {
1652 printer.printRecord(record);
1653 }
1654 assertEquals(data, out.toString());
1655 }
1656 }
1657
1658 @Test
1659 public void testSkipAutoHeader() throws Exception {
1660 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1661 try (CSVParser parser = CSVFormat.DEFAULT.withHeader().parse(in)) {
1662 final Iterator<CSVRecord> records = parser.iterator();
1663 final CSVRecord record = records.next();
1664 assertEquals("1", record.get("a"));
1665 assertEquals("2", record.get("b"));
1666 assertEquals("3", record.get("c"));
1667 }
1668 }
1669
1670 @Test
1671 public void testSkipHeaderOverrideDuplicateHeaders() throws Exception {
1672 final Reader in = new StringReader("a,a,a\n1,2,3\nx,y,z");
1673 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("X", "Y", "Z").withSkipHeaderRecord().parse(in)) {
1674 final Iterator<CSVRecord> records = parser.iterator();
1675 final CSVRecord record = records.next();
1676 assertEquals("1", record.get("X"));
1677 assertEquals("2", record.get("Y"));
1678 assertEquals("3", record.get("Z"));
1679 }
1680 }
1681
1682 @Test
1683 public void testSkipSetAltHeaders() throws Exception {
1684 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1685 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("X", "Y", "Z").withSkipHeaderRecord().parse(in)) {
1686 final Iterator<CSVRecord> records = parser.iterator();
1687 final CSVRecord record = records.next();
1688 assertEquals("1", record.get("X"));
1689 assertEquals("2", record.get("Y"));
1690 assertEquals("3", record.get("Z"));
1691 }
1692 }
1693
1694 @Test
1695 public void testSkipSetHeader() throws Exception {
1696 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1697 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("a", "b", "c").withSkipHeaderRecord().parse(in)) {
1698 final Iterator<CSVRecord> records = parser.iterator();
1699 final CSVRecord record = records.next();
1700 assertEquals("1", record.get("a"));
1701 assertEquals("2", record.get("b"));
1702 assertEquals("3", record.get("c"));
1703 }
1704 }
1705
1706 @Test
1707 @Disabled
1708 public void testStartWithEmptyLinesThenHeaders() throws Exception {
1709 final String[] codes = { "\r\n\r\n\r\nhello,\r\n\r\n\r\n", "hello,\n\n\n", "hello,\"\"\r\n\r\n\r\n", "hello,\"\"\n\n\n" };
1710 final String[][] res = { { "hello", "" }, { "" },
1711 { "" } };
1712 for (final String code : codes) {
1713 try (CSVParser parser = CSVParser.parse(code, CSVFormat.EXCEL)) {
1714 final List<CSVRecord> records = parser.getRecords();
1715 assertEquals(res.length, records.size());
1716 assertFalse(records.isEmpty());
1717 for (int i = 0; i < res.length; i++) {
1718 assertArrayEquals(res[i], records.get(i).values());
1719 }
1720 }
1721 }
1722 }
1723
1724 @Test
1725 public void testStream() throws Exception {
1726 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1727 try (CSVParser parser = CSVFormat.DEFAULT.parse(in)) {
1728 final List<CSVRecord> list = parser.stream().collect(Collectors.toList());
1729 assertFalse(list.isEmpty());
1730 assertArrayEquals(new String[] { "a", "b", "c" }, list.get(0).values());
1731 assertArrayEquals(new String[] { "1", "2", "3" }, list.get(1).values());
1732 assertArrayEquals(new String[] { "x", "y", "z" }, list.get(2).values());
1733 }
1734 }
1735
1736 @ParameterizedTest
1737 @ValueSource(longs = { -1, 0, 1, 2, 3, 4, Long.MAX_VALUE })
1738 public void testStreamMaxRows(final long maxRows) throws Exception {
1739 final Reader in = new StringReader("a,b,c\n1,2,3\nx,y,z");
1740 try (CSVParser parser = CSVFormat.DEFAULT.builder().setMaxRows(maxRows).get().parse(in)) {
1741 final List<CSVRecord> list = parser.stream().collect(Collectors.toList());
1742 assertFalse(list.isEmpty());
1743 assertArrayEquals(new String[] { "a", "b", "c" }, list.get(0).values());
1744 if (maxRows <= 0 || maxRows > 1) {
1745 assertArrayEquals(new String[] { "1", "2", "3" }, list.get(1).values());
1746 }
1747 if (maxRows <= 0 || maxRows > 2) {
1748 assertArrayEquals(new String[] { "x", "y", "z" }, list.get(2).values());
1749 }
1750 }
1751 }
1752
1753 @Test
1754 public void testThrowExceptionWithLineAndPosition() throws IOException {
1755 final String csvContent = "col1,col2,col3,col4,col5,col6,col7,col8,col9,col10\nrec1,rec2,rec3,rec4,rec5,rec6,rec7,rec8,\"\"rec9\"\",rec10";
1756 final StringReader stringReader = new StringReader(csvContent);
1757
1758 final CSVFormat csvFormat = CSVFormat.DEFAULT.builder()
1759 .setHeader()
1760 .setSkipHeaderRecord(true)
1761 .get();
1762
1763 try (CSVParser csvParser = csvFormat.parse(stringReader)) {
1764 final UncheckedIOException exception = assertThrows(UncheckedIOException.class, csvParser::getRecords);
1765 assertInstanceOf(CSVException.class, exception.getCause());
1766 assertTrue(exception.getMessage().contains("Invalid character between encapsulated token and delimiter at line: 2, position: 94"),
1767 exception::getMessage);
1768 }
1769 }
1770
1771 @Test
1772 public void testTrailingDelimiter() throws Exception {
1773 final Reader in = new StringReader("a,a,a,\n\"1\",\"2\",\"3\",\nx,y,z,");
1774 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("X", "Y", "Z").withSkipHeaderRecord().withTrailingDelimiter().parse(in)) {
1775 final Iterator<CSVRecord> records = parser.iterator();
1776 final CSVRecord record = records.next();
1777 assertEquals("1", record.get("X"));
1778 assertEquals("2", record.get("Y"));
1779 assertEquals("3", record.get("Z"));
1780 assertEquals(3, record.size());
1781 }
1782 }
1783
1784 @Test
1785 public void testTrim() throws Exception {
1786 final Reader in = new StringReader("a,a,a\n\" 1 \",\" 2 \",\" 3 \"\nx,y,z");
1787 try (CSVParser parser = CSVFormat.DEFAULT.withHeader("X", "Y", "Z").withSkipHeaderRecord().withTrim().parse(in)) {
1788 final Iterator<CSVRecord> records = parser.iterator();
1789 final CSVRecord record = records.next();
1790 assertEquals("1", record.get("X"));
1791 assertEquals("2", record.get("Y"));
1792 assertEquals("3", record.get("Z"));
1793 assertEquals(3, record.size());
1794 }
1795 }
1796
1797 private void validateLineNumbers(final String lineSeparator) throws IOException {
1798 try (CSVParser parser = CSVParser.parse("a" + lineSeparator + "b" + lineSeparator + "c", CSVFormat.DEFAULT.withRecordSeparator(lineSeparator))) {
1799 assertEquals(0, parser.getCurrentLineNumber());
1800 assertNotNull(parser.nextRecord());
1801 assertEquals(1, parser.getCurrentLineNumber());
1802 assertNotNull(parser.nextRecord());
1803 assertEquals(2, parser.getCurrentLineNumber());
1804 assertNotNull(parser.nextRecord());
1805
1806 assertEquals(3, parser.getCurrentLineNumber());
1807 assertNull(parser.nextRecord());
1808
1809 assertEquals(3, parser.getCurrentLineNumber());
1810 }
1811 }
1812
1813 private void validateRecordNumbers(final String lineSeparator) throws IOException {
1814 try (CSVParser parser = CSVParser.parse("a" + lineSeparator + "b" + lineSeparator + "c", CSVFormat.DEFAULT.withRecordSeparator(lineSeparator))) {
1815 CSVRecord record;
1816 assertEquals(0, parser.getRecordNumber());
1817 assertNotNull(record = parser.nextRecord());
1818 assertEquals(1, record.getRecordNumber());
1819 assertEquals(1, parser.getRecordNumber());
1820 assertNotNull(record = parser.nextRecord());
1821 assertEquals(2, record.getRecordNumber());
1822 assertEquals(2, parser.getRecordNumber());
1823 assertNotNull(record = parser.nextRecord());
1824 assertEquals(3, record.getRecordNumber());
1825 assertEquals(3, parser.getRecordNumber());
1826 assertNull(record = parser.nextRecord());
1827 assertEquals(3, parser.getRecordNumber());
1828 }
1829 }
1830
1831 private void validateRecordPosition(final String lineSeparator) throws IOException {
1832 final String nl = lineSeparator;
1833 final String code = "a,b,c" + lineSeparator + "1,2,3" + lineSeparator +
1834
1835 "'A" + nl + "A','B" + nl + "B',CC" + lineSeparator +
1836
1837
1838 "\u00c4,\u00d6,\u00dc" + lineSeparator + "EOF,EOF,EOF";
1839 final CSVFormat format = CSVFormat.newFormat(',').withQuote('\'').withRecordSeparator(lineSeparator);
1840 final long positionRecord3;
1841 try (CSVParser parser = CSVParser.parse(code, format)) {
1842 CSVRecord record;
1843 assertEquals(0, parser.getRecordNumber());
1844
1845 assertNotNull(record = parser.nextRecord());
1846 assertEquals(1, record.getRecordNumber());
1847 assertEquals(code.indexOf('a'), record.getCharacterPosition());
1848
1849 assertNotNull(record = parser.nextRecord());
1850 assertEquals(2, record.getRecordNumber());
1851 assertEquals(code.indexOf('1'), record.getCharacterPosition());
1852
1853 assertNotNull(record = parser.nextRecord());
1854 positionRecord3 = record.getCharacterPosition();
1855 assertEquals(3, record.getRecordNumber());
1856 assertEquals(code.indexOf("'A"), record.getCharacterPosition());
1857 assertEquals("A" + lineSeparator + "A", record.get(0));
1858 assertEquals("B" + lineSeparator + "B", record.get(1));
1859 assertEquals("CC", record.get(2));
1860
1861 assertNotNull(record = parser.nextRecord());
1862 assertEquals(4, record.getRecordNumber());
1863 assertEquals(code.indexOf('\u00c4'), record.getCharacterPosition());
1864
1865 assertNotNull(record = parser.nextRecord());
1866 assertEquals(5, record.getRecordNumber());
1867 assertEquals(code.indexOf("EOF"), record.getCharacterPosition());
1868 }
1869
1870 try (CSVParser parser = CSVParser.builder()
1871 .setReader(new StringReader(code.substring((int) positionRecord3)))
1872 .setFormat(format)
1873 .setCharacterOffset(positionRecord3)
1874 .setRecordNumber(3)
1875 .get()) {
1876 CSVRecord record;
1877
1878 assertNotNull(record = parser.nextRecord());
1879 assertEquals(3, record.getRecordNumber());
1880 assertEquals(code.indexOf("'A"), record.getCharacterPosition());
1881 assertEquals("A" + lineSeparator + "A", record.get(0));
1882 assertEquals("B" + lineSeparator + "B", record.get(1));
1883 assertEquals("CC", record.get(2));
1884
1885 assertNotNull(record = parser.nextRecord());
1886 assertEquals(4, record.getRecordNumber());
1887 assertEquals(code.indexOf('\u00c4'), record.getCharacterPosition());
1888 assertEquals("\u00c4", record.get(0));
1889 }
1890 try (CSVParser parser = new CSVParser(new StringReader(code.substring((int) positionRecord3)), format, positionRecord3, 3)) {
1891 CSVRecord record;
1892
1893 assertNotNull(record = parser.nextRecord());
1894 assertEquals(3, record.getRecordNumber());
1895 assertEquals(code.indexOf("'A"), record.getCharacterPosition());
1896 assertEquals("A" + lineSeparator + "A", record.get(0));
1897 assertEquals("B" + lineSeparator + "B", record.get(1));
1898 assertEquals("CC", record.get(2));
1899
1900 assertNotNull(record = parser.nextRecord());
1901 assertEquals(4, record.getRecordNumber());
1902 assertEquals(code.indexOf('\u00c4'), record.getCharacterPosition());
1903 assertEquals("\u00c4", record.get(0));
1904 }
1905 }
1906 }