1 package com.opencsv.bean;
2
3 import com.opencsv.*;
4 import com.opencsv.bean.mocks.*;
5 import com.opencsv.bean.verifier.PositiveEvensOnly;
6 import com.opencsv.bean.verifier.PositiveOddsOnly;
7 import com.opencsv.enums.CSVReaderNullFieldIndicator;
8 import com.opencsv.exceptions.CsvConstraintViolationException;
9 import com.opencsv.exceptions.CsvException;
10 import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
11 import org.apache.commons.lang3.StringUtils;
12 import org.junit.jupiter.api.*;
13
14 import java.io.FileNotFoundException;
15 import java.io.FileReader;
16 import java.io.Reader;
17 import java.io.StringReader;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.stream.Collectors;
21
22 import static org.junit.jupiter.api.Assertions.*;
23
24 public class CsvToBeanTest {
25 private static final String TEST_STRING = "name,orderNumber,num\n" +
26 "kyle,abc123456,123\n" +
27 "jimmy,def098765,456 ";
28
29 private static final String TEST_STRING_WITH_BLANK_LINES = "name,orderNumber,num\n" +
30 "kyle,abc123456,123\n\n\n" +
31 "jimmy,def098765,456";
32
33 private static final String TEST_STRING_WITHOUT_MANDATORY_FIELD = "name,orderNumber,num\n" +
34 "kyle,abc123456,123\n" +
35 "jimmy,def098765,";
36
37 private static final String GOOD_NUMBERS = "number\n0\n1\n2\n3\n4\n";
38 private static final String BAD_NUMBERS = "number\n0\n1\n2\n-5\n3\n4\n";
39
40 private static Locale systemLocale;
41
42 @BeforeAll
43 public static void storeSystemLocale() {
44 systemLocale = Locale.getDefault();
45 }
46
47 @BeforeEach
48 public void setSystemLocaleToValueNotGerman() {
49 Locale.setDefault(Locale.US);
50 }
51
52 @AfterEach
53 public void setSystemLocaleBackToDefault() {
54 Locale.setDefault(systemLocale);
55 }
56
57 @SuppressWarnings("unchecked")
58 @Test
59 public void throwRuntimeExceptionWhenExceptionIsThrown() {
60 Assertions.assertThrows(RuntimeException.class, () -> {
61 new CsvToBeanBuilder(new StringReader(TEST_STRING))
62 .withMappingStrategy(new ErrorHeaderMappingStrategy())
63 .build().parse();
64 });
65 }
66
67 @SuppressWarnings("unchecked")
68 @Test
69 public void throwRuntimeExceptionLineWhenExceptionIsThrown() {
70 Assertions.assertThrows(RuntimeException.class, () -> {
71 new CsvToBeanBuilder(new StringReader(TEST_STRING))
72 .withMappingStrategy(new ErrorLineMappingStrategy())
73 .withThrowExceptions(false)
74 .build().parse();
75 });
76 }
77
78 @Test
79 public void parseBeanWithNoAnnotations() {
80 HeaderColumnNameMappingStrategy<MockBean> strategy = new HeaderColumnNameMappingStrategy<>();
81 strategy.setType(MockBean.class);
82 List<MockBean> beanList = new CsvToBeanBuilder<MockBean>(new StringReader(TEST_STRING))
83 .withMappingStrategy(strategy)
84 .withFilter(null)
85 .build().parse();
86
87 assertEquals(2, beanList.size());
88 assertTrue(beanList.contains(new MockBean("kyle", null, "abc123456", 123, 0.0)));
89 assertTrue(beanList.contains(new MockBean("jimmy", null, "def098765", 456, 0.0)));
90 }
91
92 @DisplayName("Blank lines are ignored when withIgnoreEmptyLine is set to true.")
93 @Test
94 public void parseBeanWithIgnoreEmptyLines() {
95 HeaderColumnNameMappingStrategy<MockBean> strategy = new HeaderColumnNameMappingStrategy<>();
96 strategy.setType(MockBean.class);
97 List<MockBean> beanList = new CsvToBeanBuilder<MockBean>(new StringReader(TEST_STRING_WITH_BLANK_LINES))
98 .withMappingStrategy(strategy)
99 .withIgnoreEmptyLine(true)
100 .withFilter(null)
101 .build().parse();
102
103 assertEquals(2, beanList.size());
104 assertTrue(beanList.contains(new MockBean("kyle", null, "abc123456", 123, 0.0)));
105 assertTrue(beanList.contains(new MockBean("jimmy", null, "def098765", 456, 0.0)));
106 }
107
108 @DisplayName("Blank lines are ignored when withIgnoreEmptyLine is set to true and withFieldAsNull is set to EMPTY_SEPARATORS.")
109 @Test
110 public void parseBeanWithIgnoreEmptyLinesAndEmptyIsNull() {
111 HeaderColumnNameMappingStrategy<MockBean> strategy = new HeaderColumnNameMappingStrategy<>();
112 strategy.setType(MockBean.class);
113 List<MockBean> beanList = new CsvToBeanBuilder<MockBean>(new StringReader(TEST_STRING_WITH_BLANK_LINES))
114 .withMappingStrategy(strategy)
115 .withIgnoreEmptyLine(true)
116 .withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS)
117 .build().parse();
118
119 assertEquals(2, beanList.size());
120 assertTrue(beanList.contains(new MockBean("kyle", null, "abc123456", 123, 0.0)));
121 assertTrue(beanList.contains(new MockBean("jimmy", null, "def098765", 456, 0.0)));
122 }
123
124 @Test
125 public void bug133ShouldNotThrowNullPointerExceptionWhenProcessingEmptyWithNoAnnotations() {
126 HeaderColumnNameMappingStrategy<Bug133Bean> strategy = new HeaderColumnNameMappingStrategy<>();
127 strategy.setType(Bug133Bean.class);
128
129 StringReader reader = new StringReader("one;two;three\n" +
130 "kyle;;123\n" +
131 "jimmy;;456 ");
132
133 CSVParserBuilder parserBuilder = new CSVParserBuilder();
134 CSVReaderBuilder readerBuilder = new CSVReaderBuilder(reader);
135
136 CSVParser parser = parserBuilder.withFieldAsNull(CSVReaderNullFieldIndicator.BOTH).withSeparator(';').build();
137 CSVReader csvReader = readerBuilder.withCSVParser(parser).build();
138
139 List<Bug133Bean> beanList = new CsvToBeanBuilder<Bug133Bean>(csvReader)
140 .withMappingStrategy(strategy)
141 .withFilter(null)
142 .withThrowExceptions(true)
143 .build().parse();
144
145 assertEquals(2, beanList.size());
146 }
147
148 @Test
149 public void throwIllegalStateWhenParseWithoutArgumentsIsCalled() {
150 CsvToBean csvtb = new CsvToBean();
151 String englishErrorMessage = null;
152 try {
153 csvtb.parse();
154 fail("IllegalStateException should have been thrown.");
155 } catch (IllegalStateException e) {
156 englishErrorMessage = e.getLocalizedMessage();
157 }
158
159
160 csvtb.setErrorLocale(Locale.GERMAN);
161 try {
162 csvtb.parse();
163 fail("IllegalStateException should have been thrown.");
164 } catch (IllegalStateException e) {
165 assertNotSame(englishErrorMessage, e.getLocalizedMessage());
166 }
167 }
168
169 @Test
170 public void throwIllegalStateWhenOnlyReaderIsSpecifiedToParseWithoutArguments() {
171 CsvToBean csvtb = new CsvToBean();
172 csvtb.setCsvReader(new CSVReader(new StringReader(TEST_STRING)));
173 Assertions.assertThrows(IllegalStateException.class, csvtb::parse);
174 }
175
176 @Test
177 public void throwIllegalStateWhenOnlyMapperIsSpecifiedToParseWithoutArguments() {
178 CsvToBean<AnnotatedMockBeanFull> csvtb = new CsvToBean<>();
179 HeaderColumnNameMappingStrategy<AnnotatedMockBeanFull> strat = new HeaderColumnNameMappingStrategy<>();
180 strat.setType(AnnotatedMockBeanFull.class);
181 csvtb.setMappingStrategy(strat);
182 Assertions.assertThrows(IllegalStateException.class, csvtb::parse);
183 }
184
185 @Test
186 public void throwIllegalArguementWhenReaderNotProvidedInBuilder() {
187 Assertions.assertThrows(IllegalArgumentException.class, () -> {
188 new CsvToBeanBuilder<AnnotatedMockBeanFull>((Reader) null)
189 .withType(AnnotatedMockBeanFull.class)
190 .build();
191 });
192 }
193
194 @Test
195 public void throwIllegalStateWhenTypeAndMapperNotProvidedInBuilder() {
196 String englishErrorMessage = null;
197 try {
198 new CsvToBeanBuilder<>(new StringReader(TEST_STRING_WITHOUT_MANDATORY_FIELD))
199 .build();
200 fail("IllegalStateException should have been thrown.");
201 } catch (IllegalStateException e) {
202 englishErrorMessage = e.getLocalizedMessage();
203 }
204
205
206 try {
207 new CsvToBeanBuilder<>(new StringReader(TEST_STRING_WITHOUT_MANDATORY_FIELD))
208 .withErrorLocale(Locale.GERMAN)
209 .build();
210 fail("IllegalStateException should have been thrown.");
211 } catch (IllegalStateException e) {
212 assertNotSame(englishErrorMessage, e.getLocalizedMessage());
213 }
214 }
215
216 @Test
217 public void testMinimumBuilder() {
218 List<MinimalCsvBindByPositionBeanForWriting> result =
219 new CsvToBeanBuilder<MinimalCsvBindByPositionBeanForWriting>(new StringReader("1,2,3\n4,5,6"))
220 .withType(MinimalCsvBindByPositionBeanForWriting.class)
221 .build()
222 .parse();
223 assertEquals(2, result.size());
224 }
225
226 @Test
227 public void testMinimumBuilderWithCSVReader() {
228 CSVReaderBuilder readerBuilder = new CSVReaderBuilder(new StringReader("1,2,3\n4,5,6"));
229 List<MinimalCsvBindByPositionBeanForWriting> result =
230 new CsvToBeanBuilder<MinimalCsvBindByPositionBeanForWriting>(readerBuilder.build())
231 .withType(MinimalCsvBindByPositionBeanForWriting.class)
232 .build()
233 .parse();
234 assertEquals(2, result.size());
235 }
236
237 @Test
238 public void testParseVsStream() {
239 List<MinimalCsvBindByPositionBeanForWriting> resultList =
240 new CsvToBeanBuilder<MinimalCsvBindByPositionBeanForWriting>(new StringReader("1,2,3\n4,5,6"))
241 .withType(MinimalCsvBindByPositionBeanForWriting.class)
242 .build()
243 .parse();
244 List<MinimalCsvBindByPositionBeanForWriting> resultStream =
245 new CsvToBeanBuilder<MinimalCsvBindByPositionBeanForWriting>(new StringReader("1,2,3\n4,5,6"))
246 .withType(MinimalCsvBindByPositionBeanForWriting.class)
247 .build()
248 .stream().collect(Collectors.toList());
249 assertEquals(resultList, resultStream);
250 }
251
252 private static class BegToBeFiltered implements CsvToBeanFilter {
253
254 @Override
255 public boolean allowLine(String[] line) {
256 for (String col : line) {
257 if (col.equals("filtermebaby")) return false;
258 }
259 return true;
260 }
261
262 }
263
264 @Test
265 public void testMaximumBuilder() throws FileNotFoundException {
266 HeaderColumnNameMappingStrategy<AnnotatedMockBeanFull> map = new HeaderColumnNameMappingStrategy<>();
267 map.setType(AnnotatedMockBeanFull.class);
268
269
270
271
272 CsvToBean<AnnotatedMockBeanFull> csvtb =
273 new CsvToBeanBuilder<AnnotatedMockBeanFull>(new FileReader("src/test/resources/testinputmaximumbuilder.csv"))
274 .withEscapeChar('?')
275 .withFieldAsNull(CSVReaderNullFieldIndicator.NEITHER)
276 .withFilter(new BegToBeFiltered())
277 .withIgnoreLeadingWhiteSpace(false)
278 .withIgnoreQuotations(true)
279 .withKeepCarriageReturn(false)
280 .withMappingStrategy(map)
281 .withQuoteChar('!')
282 .withSeparator('#')
283 .withSkipLines(1)
284 .withStrictQuotes(false)
285 .withThrowExceptions(false)
286 .withType(AnnotatedMockBeanFull.class)
287 .withVerifyReader(false)
288 .withMultilineLimit(Integer.MAX_VALUE)
289 .build();
290 List<CsvException> capturedExceptions = csvtb.getCapturedExceptions();
291 assertNotNull(capturedExceptions);
292 assertEquals(0, capturedExceptions.size());
293 List<AnnotatedMockBeanFull> result = csvtb.parse();
294
295
296 assertEquals(1, result.size());
297 assertEquals(1, csvtb.getCapturedExceptions().size());
298 AnnotatedMockBeanFull bean = result.get(0);
299 assertEquals("\ttest string of everything!", bean.getStringClass());
300 assertTrue(bean.getBoolWrapped());
301 assertFalse(bean.isBoolPrimitive());
302 assertEquals(1, (byte) bean.getByteWrappedDefaultLocale());
303
304 }
305
306 @Test
307 public void testMaximumBuilderWithCSVReader() throws FileNotFoundException {
308 HeaderColumnNameMappingStrategy<AnnotatedMockBeanFull> map = new HeaderColumnNameMappingStrategy<>();
309 map.setType(AnnotatedMockBeanFull.class);
310
311 CSVParserBuilder cpb = new CSVParserBuilder();
312 CSVParser csvParser = cpb.withEscapeChar('?')
313 .withFieldAsNull(CSVReaderNullFieldIndicator.NEITHER)
314 .withIgnoreLeadingWhiteSpace(false)
315 .withIgnoreQuotations(true)
316 .withQuoteChar('!')
317 .withSeparator('#')
318 .withStrictQuotes(false)
319 .build();
320
321 CSVReaderBuilder crb = new CSVReaderBuilder(new FileReader("src/test/resources/testinputmaximumbuilder.csv"));
322 CSVReader csvReader = crb.withCSVParser(csvParser)
323 .withSkipLines(1)
324 .withKeepCarriageReturn(false)
325 .withVerifyReader(false)
326 .withMultilineLimit(Integer.MAX_VALUE)
327 .build();
328
329
330
331
332 CsvToBean<AnnotatedMockBeanFull> csvtb =
333 new CsvToBeanBuilder<AnnotatedMockBeanFull>(csvReader)
334 .withFilter(new BegToBeFiltered())
335 .withMappingStrategy(map)
336 .withThrowExceptions(false)
337 .withType(AnnotatedMockBeanFull.class)
338 .build();
339 List<CsvException> capturedExceptions = csvtb.getCapturedExceptions();
340 assertNotNull(capturedExceptions);
341 assertEquals(0, capturedExceptions.size());
342 List<AnnotatedMockBeanFull> result = csvtb.parse();
343
344
345 assertEquals(1, result.size());
346 assertEquals(1, csvtb.getCapturedExceptions().size());
347 AnnotatedMockBeanFull bean = result.get(0);
348 assertEquals("\ttest string of everything!", bean.getStringClass());
349 assertTrue(bean.getBoolWrapped());
350 assertFalse(bean.isBoolPrimitive());
351 assertEquals(1, (byte) bean.getByteWrappedDefaultLocale());
352
353 }
354
355 @Test
356 public void testColumnMappingStrategyWithBuilder() throws FileNotFoundException {
357 List<AnnotatedMockBeanFull> result =
358 new CsvToBeanBuilder<AnnotatedMockBeanFull>(new FileReader("src/test/resources/testinputposfullgood.csv"))
359 .withSeparator(';')
360 .withType(AnnotatedMockBeanFull.class)
361 .build()
362 .parse();
363 assertEquals(2, result.size());
364 }
365
366 @Test
367 public void testMappingWithoutAnnotationsWithBuilder() {
368 List<MockBean> result =
369 new CsvToBeanBuilder<MockBean>(new StringReader(TEST_STRING))
370 .withType(MockBean.class)
371 .build()
372 .parse();
373 assertEquals(2, result.size());
374 }
375
376 @Test
377 public void testEmptyInputWithHeaderNameMappingAndRequiredField() {
378 MappingStrategy<AnnotatedMockBeanFull> map = new HeaderColumnNameMappingStrategy<>();
379 map.setType(AnnotatedMockBeanFull.class);
380 try {
381 new CsvToBeanBuilder<AnnotatedMockBeanFull>(new StringReader(StringUtils.EMPTY))
382 .withType(AnnotatedMockBeanFull.class)
383 .withMappingStrategy(map)
384 .build()
385 .parse();
386 fail("An exception should have been thrown.");
387 } catch (RuntimeException re) {
388 Throwable t = re.getCause();
389 assertNotNull(t);
390 assertTrue(t instanceof CsvRequiredFieldEmptyException);
391 }
392 }
393
394 @Test
395 public void testMismatchNumberOfData() {
396 MappingStrategy<AnnotatedMockBeanFull> map = new HeaderColumnNameMappingStrategy<>();
397 map.setType(AnnotatedMockBeanFull.class);
398 StringBuilder sb = new StringBuilder(ICSVParser.INITIAL_READ_SIZE);
399 String dateString = "19780115T063209";
400 sb.append("BYTE1,BYTE2,BYTE3,DATE1\n");
401 sb.append("1,2,3,").append(dateString).append("\n");
402 sb.append("4,5,6,").append(dateString).append("\n");
403 sb.append("7\n");
404 sb.append("8,9,10,").append(dateString).append("\n");
405 try {
406 new CsvToBeanBuilder<AnnotatedMockBeanFull>(new StringReader(sb.toString()))
407 .withType(AnnotatedMockBeanFull.class)
408 .withMappingStrategy(map)
409 .build()
410 .parse();
411 fail("An exception should have been thrown.");
412 } catch (RuntimeException re) {
413 Throwable t = re.getCause();
414 assertNotNull(t);
415 assertTrue(t instanceof CsvRequiredFieldEmptyException);
416 }
417 }
418
419 @Test
420 public void bug154WhenUsingIteratorTheLineNumbersInTheExceptionShouldBePopulated() {
421 String data = "a,b\n" +
422 "P,1\n" +
423 "Q,12\n" +
424 "R,1a\n" +
425 "S,1b";
426 CsvToBean<Bug154Bean> c = new CsvToBeanBuilder<Bug154Bean>(new StringReader(data))
427 .withType(Bug154Bean.class)
428 .withThrowExceptions(false)
429 .withErrorLocale(Locale.ROOT)
430 .build();
431 for (Bug154Bean mockBean : c) {
432 System.out.println(mockBean.toString());
433 }
434 assertEquals(2, c.getCapturedExceptions().size());
435 CsvException exception1 = c.getCapturedExceptions().get(0);
436 assertEquals(4, exception1.getLineNumber());
437 assertNotNull(exception1.getLine());
438 CsvException exception2 = c.getCapturedExceptions().get(1);
439 assertEquals(5, exception2.getLineNumber());
440 assertNotNull(exception2.getLine());
441 }
442
443
444
445
446
447
448
449
450
451 @Test
452 public void testSingleVerifier() {
453 List<SingleNumber> beans = new CsvToBeanBuilder<SingleNumber>(new StringReader(GOOD_NUMBERS))
454 .withType(SingleNumber.class)
455 .withVerifier(null)
456 .withVerifier(new PositiveEvensOnly())
457 .withOrderedResults(true)
458 .build().parse();
459 assertNotNull(beans);
460 assertEquals(3, beans.size());
461 assertEquals(0, beans.get(0).getNumber());
462 assertEquals(2, beans.get(1).getNumber());
463 assertEquals(4, beans.get(2).getNumber());
464 }
465
466
467
468
469
470
471 @Test
472 public void testMultipleVerifiers() {
473 List<SingleNumber> beans = new CsvToBeanBuilder<SingleNumber>(new StringReader(GOOD_NUMBERS))
474 .withType(SingleNumber.class)
475 .withVerifier(new PositiveEvensOnly())
476 .withVerifier(new PositiveOddsOnly())
477 .withVerifier(null)
478 .build().parse();
479 assertNotNull(beans);
480 assertTrue(beans.isEmpty());
481 }
482
483 @Test
484 public void testNullVerifierClearsList() {
485 CsvToBean<SingleNumber> csvToBean = new CsvToBeanBuilder<SingleNumber>(new StringReader(GOOD_NUMBERS))
486 .withType(SingleNumber.class)
487 .withVerifier(new PositiveEvensOnly())
488 .withVerifier(new PositiveOddsOnly())
489 .withOrderedResults(true)
490 .build();
491 csvToBean.setVerifiers(null);
492 List<SingleNumber> beans = csvToBean.parse();
493 assertNotNull(beans);
494 assertEquals(5, beans.size());
495 assertEquals(0, beans.get(0).getNumber());
496 assertEquals(1, beans.get(1).getNumber());
497 assertEquals(2, beans.get(2).getNumber());
498 assertEquals(3, beans.get(3).getNumber());
499 assertEquals(4, beans.get(4).getNumber());
500 }
501
502 @Test
503 public void testVerifierThrowsExceptionCollected() {
504 CsvToBean<SingleNumber> csvToBean = new CsvToBeanBuilder<SingleNumber>(new StringReader(BAD_NUMBERS))
505 .withType(SingleNumber.class)
506 .withVerifier(new PositiveOddsOnly())
507 .withThrowExceptions(false)
508 .withOrderedResults(true)
509 .build();
510 List<SingleNumber> beans = csvToBean.parse();
511 List<CsvException> exceptions = csvToBean.getCapturedExceptions();
512 assertNotNull(beans);
513 assertEquals(2, beans.size());
514 assertEquals(1, beans.get(0).getNumber());
515 assertEquals(3, beans.get(1).getNumber());
516 assertNotNull(exceptions);
517 assertEquals(1, exceptions.size());
518 assertTrue(exceptions.get(0) instanceof CsvConstraintViolationException);
519 CsvConstraintViolationException csve = (CsvConstraintViolationException) exceptions.get(0);
520 assertEquals(5, csve.getLineNumber());
521 assertNotNull(csve.getLine());
522 }
523
524 @Test
525 public void testVerifierThrowsExceptionRethrown() {
526 try {
527 new CsvToBeanBuilder<SingleNumber>(new StringReader(BAD_NUMBERS))
528 .withType(SingleNumber.class)
529 .withVerifier(new PositiveOddsOnly())
530 .withThrowExceptions(true)
531 .withOrderedResults(true)
532 .build().parse();
533
534 fail("Expecting exception thrown in parse.");
535 } catch (RuntimeException re) {
536 Throwable e = re.getCause();
537 assertTrue(e instanceof CsvConstraintViolationException);
538 CsvConstraintViolationException csve = (CsvConstraintViolationException) e;
539 assertEquals(5, csve.getLineNumber());
540 assertNotNull(csve.getLine());
541 }
542 }
543
544 @Test
545 public void testBug194() {
546 String testString = "name,id,orderNumber\n" +
547 "1,\"foo\", 3\n" +
548 "1,\"a \" string with a quote in the middle\", 3\n" +
549 "1,\"bar\", 3";
550
551 String expectedString = "Error parsing CSV line: 3, values: a \" string with a quote in the middle, 3\n" +
552 "1,bar, 3\n";
553 StringReader stringReader = new StringReader(testString);
554
555 CsvToBean<MockBean> csvToBean = new CsvToBeanBuilder<MockBean>(stringReader)
556 .withType(MockBean.class)
557 .withIgnoreLeadingWhiteSpace(true)
558 .withQuoteChar('"')
559 .withSeparator(',')
560 .withThrowExceptions(true)
561 .build();
562
563 try {
564 csvToBean.parse();
565 fail("Expected exception to be thrown.");
566 } catch (Exception e) {
567 assertEquals(expectedString, e.getMessage());
568 }
569 }
570 }