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