View Javadoc
1   /*
2    * Copyright 2017 Andrew Rucker Jones.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.opencsv.bean;
17  
18  import com.opencsv.bean.customconverter.BadCollectionConverter;
19  import com.opencsv.bean.mocks.join.BadSplitConverter;
20  import com.opencsv.bean.mocks.join.ErrorCode;
21  import com.opencsv.bean.mocks.join.IdAndErrorSplitByName;
22  import com.opencsv.bean.mocks.join.IdAndErrorSplitByPosition;
23  import com.opencsv.bean.mocks.split.*;
24  import com.opencsv.enums.CSVReaderNullFieldIndicator;
25  import com.opencsv.exceptions.CsvBadConverterException;
26  import com.opencsv.exceptions.CsvDataTypeMismatchException;
27  import com.opencsv.exceptions.CsvException;
28  import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
29  import org.apache.commons.collections4.Bag;
30  import org.apache.commons.collections4.SortedBag;
31  import org.apache.commons.collections4.bag.HashBag;
32  import org.apache.commons.collections4.bag.TreeBag;
33  import org.junit.jupiter.api.AfterEach;
34  import org.junit.jupiter.api.BeforeAll;
35  import org.junit.jupiter.api.BeforeEach;
36  import org.junit.jupiter.api.Test;
37  
38  import java.io.FileReader;
39  import java.io.IOException;
40  import java.io.StringReader;
41  import java.io.StringWriter;
42  import java.text.SimpleDateFormat;
43  import java.util.*;
44  
45  import static org.junit.jupiter.api.Assertions.*;
46  
47  /**
48   *
49   * @author Andrew Rucker Jones
50   */
51  public class CollectionSplitTest {
52  
53      private static Locale systemLocale;
54  
55      @BeforeAll
56      public static void storeSystemLocale() {
57          systemLocale = Locale.getDefault();
58      }
59  
60      @BeforeEach
61      public void setSystemLocaleToValueNotGerman() {
62          Locale.setDefault(Locale.US);
63      }
64  
65      @AfterEach
66      public void setSystemLocaleBackToDefault() {
67          Locale.setDefault(systemLocale);
68      }
69  
70      /**
71       * Tests a collection of a wrapped primitive type.
72       * <p>Also incidentally tests:
73       * <ul><li>Capture by name without a matching regular expression</li>
74       * <li>Correct use of {@link java.util.Collection}</li></ul></p>
75       *
76       * @throws IOException Never
77       */
78      @Test
79      public void testGoodCollectionPrimitive() throws IOException {
80          List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
81                  .withType(DerivedMockBeanCollectionSplit.class).build().parse();
82          assertEquals(1, beanList.size());
83          DerivedMockBeanCollectionSplit bean = beanList.get(0);
84          
85          // Representative of a primitive type
86          Collection<Integer> collectionType = bean.getCollectionType();
87          assertTrue(collectionType instanceof ArrayList);
88          assertEquals(6, collectionType.size());
89          assertEquals("[2, 2, 1, 3, 3, 3]", collectionType.toString());
90      }
91      
92      @Test
93      public void testGoodCollectionDate() throws IOException {
94          List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
95                  .withType(DerivedMockBeanCollectionSplit.class).build().parse();
96          assertEquals(1, beanList.size());
97          DerivedMockBeanCollectionSplit bean = beanList.get(0);
98          
99          // Representative of a date type
100         Set<Date> setType = bean.getSetType();
101         assertTrue(setType instanceof HashSet);
102         assertEquals(2, setType.size());
103         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
104         for(Date d : setType) {
105             String formattedDate = sdf.format(d);
106             assertTrue("1978-01-15".equals(formattedDate) || "2018-01-01".equals(formattedDate));
107         }
108     }
109 
110     /**
111      * Tests correct use of {@link java.util.List}.
112      * <p>Also incidentally tests:
113      * <ul><li>Capture by name with a matching regular expression</li></ul></p>
114      *
115      * @throws IOException Never
116      */
117     @Test
118     public void testGoodCollectionTypeList() throws IOException {
119         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
120                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
121         assertEquals(1, beanList.size());
122         DerivedMockBeanCollectionSplit bean = beanList.get(0);
123         
124         List<Integer> listType = bean.getListType();
125         assertTrue(listType instanceof LinkedList);
126         assertEquals(6, listType.size());
127         assertEquals("[2, 2, 1, 3, 3, 3]", listType.toString());
128     }
129 
130     @Test
131     public void testNullCollection() throws IOException {
132         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testnullcollections.csv"))
133                 .withType(DerivedMockBeanCollectionSplit.class)
134                 .withFieldAsNull(CSVReaderNullFieldIndicator.BOTH)
135                 .build().parse();
136         assertEquals(1, beanList.size());
137         DerivedMockBeanCollectionSplit bean = beanList.get(0);
138 
139         List<Integer> listType = bean.getListType();
140         assertTrue(listType instanceof LinkedList);
141         assertEquals(0, listType.size());
142     }
143 
144     @Test
145     public void testGoodCollectionTypeSet() throws IOException {
146         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
147                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
148         assertEquals(1, beanList.size());
149         DerivedMockBeanCollectionSplit bean = beanList.get(0);
150         
151         Set<Date> setType = bean.getSetType();
152         assertTrue(setType instanceof HashSet);
153         assertEquals(2, setType.size());
154         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
155         for(Date d : setType) {
156             String formattedDate = sdf.format(d);
157             assertTrue("1978-01-15".equals(formattedDate) || "2018-01-01".equals(formattedDate));
158         }
159     }
160     
161     @Test
162     public void testGoodCollectionTypeSortedSet() throws IOException {
163         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
164                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
165         assertEquals(1, beanList.size());
166         DerivedMockBeanCollectionSplit bean = beanList.get(0);
167         
168         SortedSet<? extends Number> sortedSetType = bean.getSortedSetType();
169         assertTrue(sortedSetType instanceof TreeSet);
170         assertEquals(3, sortedSetType.size());
171         assertEquals("[1, 2, 3]", sortedSetType.toString());
172     }
173     
174     @Test
175     public void testGoodCollectionTypeNavigableSet() throws IOException {
176         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
177                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
178         assertEquals(1, beanList.size());
179         DerivedMockBeanCollectionSplit bean = beanList.get(0);
180         
181         NavigableSet<Integer> navigableSetType = bean.getNavigableSetType();
182         assertTrue(navigableSetType instanceof TreeSet);
183         assertEquals(3, navigableSetType.size());
184         assertEquals("[1, 2, 3]", navigableSetType.toString());
185     }
186     
187     @Test
188     public void testGoodCollectionTypeQueue() throws IOException {
189         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
190                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
191         assertEquals(1, beanList.size());
192         DerivedMockBeanCollectionSplit bean = beanList.get(0);
193         
194         Queue<Integer> queueType = bean.getQueueType();
195         assertTrue(queueType instanceof ArrayDeque);
196         assertEquals(6, queueType.size());
197         assertEquals("[2, 2, 1, 3, 3, 3]", queueType.toString());
198     }
199     
200     @Test
201     public void testGoodCollectionTypeDeque() throws IOException {
202         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
203                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
204         assertEquals(1, beanList.size());
205         DerivedMockBeanCollectionSplit bean = beanList.get(0);
206         
207         Deque<Integer> dequeType = bean.getDequeType();
208         assertTrue(dequeType instanceof ArrayDeque);
209         assertEquals(6, dequeType.size());
210         assertEquals("[2, 2, 1, 3, 3, 3]", dequeType.toString());
211     }
212     
213     @Test
214     public void testGoodCollectionTypeBag() throws IOException {
215         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
216                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
217         assertEquals(1, beanList.size());
218         DerivedMockBeanCollectionSplit bean = beanList.get(0);
219         
220         Bag<Integer> bagType = bean.getBagType();
221         assertTrue(bagType instanceof HashBag);
222         assertEquals(6, bagType.size());
223         assertEquals("[1:1,2:2,3:3]", bagType.toString());
224     }
225     
226     @Test
227     public void testGoodCollectionTypeSortedBag() throws IOException {
228         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
229                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
230         assertEquals(1, beanList.size());
231         DerivedMockBeanCollectionSplit bean = beanList.get(0);
232         
233         SortedBag<Integer> sortedBagType = bean.getSortedBagType();
234         assertTrue(sortedBagType instanceof TreeBag);
235         assertEquals(6, sortedBagType.size());
236         assertEquals("[1:1,2:2,3:3]", sortedBagType.toString());
237     }
238     
239     @Test
240     public void testGoodCollectionTypeNamedParametrized() throws IOException {
241         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
242                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
243         assertEquals(1, beanList.size());
244         DerivedMockBeanCollectionSplit bean = beanList.get(0);
245         
246         Stack<Integer> stackType = bean.getStackType();
247         assertTrue(stackType instanceof Stack);
248         assertEquals(6, stackType.size());
249         assertEquals("[2, 2, 1, 3, 3, 3]", stackType.toString());
250     }
251     
252     @Test
253     public void testGoodCollectionTypeNamedUnparametrized() throws IOException {
254         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
255                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
256         assertEquals(1, beanList.size());
257         DerivedMockBeanCollectionSplit bean = beanList.get(0);
258         
259         IntegerSetSortedToString nonparameterizedCollectionType = bean.getNonparameterizedCollectionType();
260         assertTrue(nonparameterizedCollectionType instanceof IntegerSetSortedToString);
261         assertEquals(3, nonparameterizedCollectionType.size());
262         assertEquals("[1,2,3]", nonparameterizedCollectionType.toString());
263     }
264 
265     /**
266      * Tests good things one can do with enumeration collections.
267      * <p>This includes:<ul>
268      *     <li>Variable declared as Set</li>
269      *     <li>Variable declared as Collection</li>
270      *     <li>Variable declared as EnumSet</li>
271      *     <li>Variable declared as Collection with collectionType EnumSet</li>
272      * </ul></p>
273      */
274     @Test
275     public void testGoodEnums() {
276         String input = "collectionEnum,setEnum,enumSetEnum,collectionEnumWithHint\nsplit1 split2,split2 split3,split3 split1,split1 split2\n";
277         List<AnnotatedEnumCollection> beans = new CsvToBeanBuilder<AnnotatedEnumCollection>(new StringReader(input))
278                 .withType(AnnotatedEnumCollection.class).build().parse();
279         assertEquals(1, beans.size());
280         AnnotatedEnumCollection bean = beans.get(0);
281 
282         List<SplitEnum> split1split2 = new ArrayList<>();
283         split1split2.add(SplitEnum.SPLIT1); split1split2.add(SplitEnum.Split2);
284         assertTrue(bean.getCollectionEnum() instanceof ArrayList);
285         assertEquals(split1split2, bean.getCollectionEnum());
286         assertEquals(EnumSet.of(SplitEnum.SPLIT1, SplitEnum.Split2), bean.getCollectionEnumWithHint());
287         assertEquals(EnumSet.of(SplitEnum.Split2, SplitEnum.split3), bean.getSetEnum());
288         assertEquals(EnumSet.of(SplitEnum.split3, SplitEnum.SPLIT1), bean.getEnumSetEnum());
289     }
290 
291     @Test
292     public void testGoodCollectionHeaderMapping() throws IOException {
293         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
294                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
295         assertEquals(1, beanList.size());
296         DerivedMockBeanCollectionSplit bean = beanList.get(0);
297         
298         // Representative of anything, demonstrating correct mapping
299         Collection<Integer> collectionType = bean.getCollectionType();
300         assertTrue(collectionType instanceof ArrayList);
301         assertEquals(6, collectionType.size());
302         assertEquals("[2, 2, 1, 3, 3, 3]", collectionType.toString());
303     }
304 
305     /**
306      * Tests a good split using column mapping.
307      * <p>Also incidentally tests:
308      * <ul><li>Capture by position without a matching regular expression</li>
309      * <li>Capture by position with a matching regular expression</li></ul></p>
310      */
311     @Test
312     public void testGoodCollectionColumnMapping() {
313         List<AnnotatedMockBeanCollectionSplitByColumn> beanList =
314                 new CsvToBeanBuilder<AnnotatedMockBeanCollectionSplitByColumn>(new StringReader("A string is great,f:1.0 f:2.0 f:3.0"))
315                         .withType(AnnotatedMockBeanCollectionSplitByColumn.class)
316                         .build().parse();
317         assertEquals(1, beanList.size());
318         AnnotatedMockBeanCollectionSplitByColumn bean = beanList.get(0);
319         assertEquals("[A, string, is, great]", bean.getStringList().toString());
320         assertEquals("[1.0, 2.0, 3.0]", bean.getFloatList().toString());
321     }
322     
323     @Test
324     public void testPrecedenceCustomAndCollectionConverter() {
325         List<AnnotationPrecedenceWithCollections> beanList =
326                 new CsvToBeanBuilder<AnnotationPrecedenceWithCollections>(
327                         new StringReader(
328                                 "precedenceGoesToCustom,precedenceGoesToCollection\nThis is a string,2 2 1 3 3 3"))
329                         .withType(AnnotationPrecedenceWithCollections.class).build().parse();
330         assertEquals(1, beanList.size());
331         AnnotationPrecedenceWithCollections bean = beanList.get(0);
332         
333         // Custom converter always comes first
334         List<String> precedenceGoesToCustom = bean.getPrecedenceGoesToCustom();
335         assertEquals("[This, is, a, string]", precedenceGoesToCustom.toString());
336     }
337     
338     @Test
339     public void testPrecedenceCollectionAndStandardConverter() {
340         List<AnnotationPrecedenceWithCollections> beanList =
341                 new CsvToBeanBuilder<AnnotationPrecedenceWithCollections>(
342                         new StringReader(
343                                 "precedenceGoesToCustom,precedenceGoesToCollection\nThis is a string,2 2 1 3 3 3"))
344                         .withType(AnnotationPrecedenceWithCollections.class).build().parse();
345         assertEquals(1, beanList.size());
346         AnnotationPrecedenceWithCollections bean = beanList.get(0);
347         
348         // Collections rank higher than standard conversion
349         List<Integer> precedenceGoesToCollection = bean.getPrecedenceGoesToCollection();
350         assertEquals("[2, 2, 1, 3, 3, 3]", precedenceGoesToCollection.toString());
351     }
352     
353     @Test
354     public void testUnknownElementType() {
355         final String input = "America/New_York";
356         CsvToBean<UnknownElementType> csv2b = new CsvToBeanBuilder<UnknownElementType>(new StringReader(input))
357                 .withType(UnknownElementType.class)
358                 .withThrowExceptions(false)
359                 .build();
360         csv2b.parse();
361         List<CsvException> exceptionList = csv2b.getCapturedExceptions();
362         assertEquals(1, exceptionList.size());
363         CsvException csve = exceptionList.get(0);
364         assertTrue(csve instanceof CsvDataTypeMismatchException);
365         CsvDataTypeMismatchException dtme = (CsvDataTypeMismatchException) csve;
366         assertEquals(1, dtme.getLineNumber());
367         assertNotNull(dtme.getLine());
368         assertEquals(TimeZone.class, dtme.getDestinationClass());
369         assertEquals(input, dtme.getSourceObject());
370     }
371     
372     @Test
373     public void testNonCollectionBeanMember() {
374         try {
375             new CsvToBeanBuilder<NonCollectionBeanMember>(new StringReader("1 2 3"))
376                     .withType(NonCollectionBeanMember.class)
377                     .build().parse();
378             fail("Should have thrown exception.");
379         }
380         catch(CsvBadConverterException csve) {
381             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
382         }
383     }
384     
385     @Test
386     public void testWrongCollectionTypeBeanMember() {
387         try {
388             new CsvToBeanBuilder<WrongCollectionType>(new StringReader("l\n2 2 1 3 3 3"))
389                     .withType(WrongCollectionType.class)
390                     .build().parse();
391             fail("Exception should have been thrown.");
392         }
393         catch(CsvBadConverterException csve) {
394             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
395         }
396     }
397     
398     @Test
399     public void testWrongElementTypeBeanMember() {
400         CsvToBean<WrongElementType> csv2b = new CsvToBeanBuilder<WrongElementType>(new StringReader("l\n2 2 1 3 3 3"))
401                 .withType(WrongElementType.class)
402                 .withThrowExceptions(false).build();
403         List<WrongElementType> beanList = csv2b.parse();
404         
405         // This is Java Generics. Type erasure allows this assignment, because
406         // at runtime, everything is List<Object>. It's just when accessing the
407         // elements of the collection later that things blow up if you try to
408         // access them as the type they're supposed to be instead of the type
409         // they are.
410         assertEquals(1, beanList.size());
411         List<CsvException> exceptionList = csv2b.getCapturedExceptions();
412         assertTrue(exceptionList.isEmpty());
413     }
414     
415     @Test
416     public void testInterfaceAsCollectionTypeInAnnotation() {
417         List<InterfaceAsCollectionType> beanList = new CsvToBeanBuilder<InterfaceAsCollectionType>(new StringReader("1 2 3 4"))
418                 .withType(InterfaceAsCollectionType.class)
419                 .build().parse();
420         assertEquals(1, beanList.size());
421         InterfaceAsCollectionType bean = beanList.get(0);
422         assertEquals("[1, 2, 3, 4]", bean.getS().toString());
423     }
424     
425     @Test
426     public void testEmptySplitOn() {
427         try {
428             new CsvToBeanBuilder<InvalidRegexAsSplitOn>(new StringReader("1a2b3c4"))
429                     .withType(InvalidRegexAsSplitOn.class)
430                     .build().parse();
431             fail("Should have thrown exception.");
432         }
433         catch(CsvBadConverterException csve) {
434             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
435         }
436     }
437     
438     @Test
439     public void testInvalidRegexAsSplitOn() {
440         try {
441             new CsvToBeanBuilder<InvalidRegexAsSplitOn>(new StringReader("1a2b3c4"))
442                     .withType(InvalidRegexAsSplitOn.class)
443                     .build().parse();
444             fail("Should have thrown exception.");
445         }
446         catch(CsvBadConverterException csve) {
447             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
448         }
449     }
450     
451     @Test
452     public void testUnknownCollectionType() {
453         try {
454             new CsvToBeanBuilder<UnknownCollectionType>(new StringReader("2 2 1 3 3 3"))
455                     .withType(UnknownCollectionType.class).build().parse();
456             fail("Exception should have been thrown.");
457         }
458         catch(CsvBadConverterException csve) {
459             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
460         }
461     }
462 
463     /**
464      * Tests writing with a header name mapping strategy.
465      * <p>Also incidentally tests:
466      * <ul><li>Writing with a format string and a header name mapping strategy</li>
467      * <li>Writing with a different format for SimpleDateFormat-based writing</li>
468      * <li>Setting an explicit chronology for SimpleDateFormat-based reading or writing</li></ul></p>
469      *
470      * @throws CsvDataTypeMismatchException Never
471      * @throws CsvRequiredFieldEmptyException Never
472      */
473     @Test
474     public void testWriteHeaderNameStrategy() throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
475         StringWriter writer = new StringWriter();
476         StatefulBeanToCsv<AnnotatedMockBeanCollectionSplit> b2csv =
477                 new StatefulBeanToCsvBuilder<AnnotatedMockBeanCollectionSplit>(writer).build();
478         AnnotatedMockBeanCollectionSplit bean = new AnnotatedMockBeanCollectionSplit();
479         SortedSet<Integer> sortedSet = new TreeSet<>(Arrays.asList(2, 2, 1, 3, 3, 3));
480         bean.setSortedSetType(sortedSet);
481         Set<Date> set = new HashSet<>();
482         Calendar cal = new GregorianCalendar(1978, Calendar.JANUARY, 15);
483         set.add(cal.getTime());
484         cal = new GregorianCalendar(2018, Calendar.JANUARY, 1);
485         set.add(cal.getTime());
486         bean.setSetType(set);
487         b2csv.write(bean);
488         String s = writer.toString();
489         
490         // Unfortunately, the set the dates are read into is not sorted, so
491         // depending on I don't know what (probably the JDK version), the order
492         // can change.
493         String option1 = "\"COLLECTIONTYPE\",\"DEQUETYPE\",\"LISTTYPE\",\"NAVIGABLESETTYPE\",\"QUEUETYPE\",\"SETTYPE\",\"SORTEDSETTYPE\"\n" +
494                 "\"\",\"\",\"\",\"\",\"\",\"1978-Jan-15 2018-Jan-01\",\"a1j a2j a3j\"\n";
495         String option2 = "\"COLLECTIONTYPE\",\"DEQUETYPE\",\"LISTTYPE\",\"NAVIGABLESETTYPE\",\"QUEUETYPE\",\"SETTYPE\",\"SORTEDSETTYPE\"\n" +
496                 "\"\",\"\",\"\",\"\",\"\",\"2018-Jan-01 1978-Jan-15\",\"a1j a2j a3j\"\n";
497         assertTrue(option1.equals(s) || option2.equals(s));
498     }
499     
500     /**
501      * Tests writing with a delimiter.
502      * <p>Also incidentally tests:
503      * <ul><li>writing with {@link ColumnPositionMappingStrategy}</li>
504      * <li>Writing with a format string and {@link ColumnPositionMappingStrategy}</li>
505      * <li>Writing with an empty list</li>
506      * <li>Writing with a list full of {@code null}</li>
507      * <li>Writing with a format string and empty input</li></ul></p>
508      * 
509      * @throws CsvDataTypeMismatchException Never
510      * @throws CsvRequiredFieldEmptyException Never
511      */
512     @Test
513     public void testWriteWithWriteDelimiter() throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
514         StringWriter writer = new StringWriter();
515         StatefulBeanToCsv<AnnotatedMockBeanCollectionSplitByColumn> b2csv =
516                 new StatefulBeanToCsvBuilder<AnnotatedMockBeanCollectionSplitByColumn>(writer).build();
517         AnnotatedMockBeanCollectionSplitByColumn bean = new AnnotatedMockBeanCollectionSplitByColumn();
518         Queue<Float> floatList = new ArrayDeque<>(Arrays.asList(1.0f, 2.0f, 3.0f));
519         bean.setFloatList(floatList);
520         bean.setStringList(Arrays.asList("This", "string", "dumb"));
521         b2csv.write(bean);
522         floatList = new LinkedList<>(Arrays.asList(4.0f, 5.0f, 6.0f));
523         bean.setFloatList(floatList);
524         bean.setStringList(Arrays.<String>asList(null, null, null));
525         b2csv.write(bean);
526         floatList = new ArrayDeque<>(Arrays.asList(7.0f, 8.0f, 9.0f));
527         bean.setFloatList(floatList);
528         bean.setStringList(null);
529         b2csv.write(bean);
530         assertEquals(
531                 "\"g:This,g:string,g:dumb\",\"1.0 silly delimiter 2.0 silly delimiter 3.0\"\n"
532                 + "\",,\",\"4.0 silly delimiter 5.0 silly delimiter 6.0\"\n"
533                 + "\"\",\"7.0 silly delimiter 8.0 silly delimiter 9.0\"\n",
534                 writer.toString());
535     }
536     
537     @Test
538     public void testWithSplitOn() throws IOException {
539         List<DerivedMockBeanCollectionSplit> beanList = new CsvToBeanBuilder<DerivedMockBeanCollectionSplit>(new FileReader("src/test/resources/testgoodcollections.csv"))
540                 .withType(DerivedMockBeanCollectionSplit.class).build().parse();
541         assertEquals(1, beanList.size());
542         DerivedMockBeanCollectionSplit bean = beanList.get(0);
543         
544         Stack<Integer> stackType = bean.getStackType();
545         assertEquals(6, stackType.size());
546         assertEquals("[2, 2, 1, 3, 3, 3]", stackType.toString());
547     }
548     
549     @Test
550     public void testRequiredNotPresentOnRead() {
551         CsvToBean<AnnotatedMockBeanCollectionSplitByColumn> csv2b = new CsvToBeanBuilder<AnnotatedMockBeanCollectionSplitByColumn>(new StringReader("A string is great"))
552                         .withType(AnnotatedMockBeanCollectionSplitByColumn.class)
553                         .withThrowExceptions(false).build();
554         List<AnnotatedMockBeanCollectionSplitByColumn> beanList = csv2b.parse();
555         List<CsvException> exceptionList = csv2b.getCapturedExceptions();
556         assertTrue(beanList.isEmpty());
557         assertEquals(1, exceptionList.size());
558         CsvException csve = exceptionList.get(0);
559         assertTrue(csve instanceof CsvRequiredFieldEmptyException);
560         CsvRequiredFieldEmptyException rfee = (CsvRequiredFieldEmptyException) csve;
561         assertEquals(AnnotatedMockBeanCollectionSplitByColumn.class, rfee.getBeanClass());
562         assertEquals(1, rfee.getLineNumber());
563         assertNotNull(rfee.getLine());
564     }
565     
566     @Test
567     public void testRequiredNotPresentOnWrite() throws CsvDataTypeMismatchException {
568         AnnotatedMockBeanCollectionSplitByColumn bean = new AnnotatedMockBeanCollectionSplitByColumn();
569         bean.setFloatList(new ArrayDeque<>());
570         bean.setStringList(Collections.singletonList("Test"));
571         StringWriter writer = new StringWriter();
572         StatefulBeanToCsv<AnnotatedMockBeanCollectionSplitByColumn> b2csv = new StatefulBeanToCsvBuilder<AnnotatedMockBeanCollectionSplitByColumn>(writer).build();
573         try {
574             b2csv.write(bean);
575             fail("Exception should have been thrown.");
576         }
577         catch(CsvRequiredFieldEmptyException csve) {
578             assertEquals(AnnotatedMockBeanCollectionSplitByColumn.class, csve.getBeanClass());
579             assertEquals("floatList", csve.getDestinationField().getName());
580             assertEquals(1, csve.getLineNumber());
581         }
582     }
583 
584     @Test
585     public void testCustomConverterByNameRead() throws IOException {
586         ResourceBundle res = ResourceBundle.getBundle("collectionconverter", Locale.GERMAN);
587         List<IdAndErrorSplitByName> beanList = new CsvToBeanBuilder<IdAndErrorSplitByName>(new FileReader("src/test/resources/testinputsplitcustombyname.csv"))
588                 .withType(IdAndErrorSplitByName.class).build().parse();
589         assertEquals(2, beanList.size());
590 
591         // Bean one
592         IdAndErrorSplitByName bean = beanList.get(0);
593         assertEquals(1, bean.getId());
594         List<ErrorCode> errorCodes = bean.getEc();
595         assertEquals(3, errorCodes.size());
596         ErrorCode ec = errorCodes.get(0);
597         assertEquals(10, ec.errorCode);
598         assertEquals(res.getString("default.error"), ec.errorMessage);
599         ec = errorCodes.get(1);
600         assertEquals(11, ec.errorCode);
601         assertEquals("doesnt.exist", ec.errorMessage);
602         ec = errorCodes.get(2);
603         assertEquals(12, ec.errorCode);
604         assertEquals(res.getString("default.error"), ec.errorMessage);
605 
606         // Bean two
607         bean = beanList.get(1);
608         assertEquals(2, bean.getId());
609         errorCodes = bean.getEc();
610         assertEquals(3, errorCodes.size());
611         ec = errorCodes.get(0);
612         assertEquals(20, ec.errorCode);
613         assertEquals("doesnt.exist", ec.errorMessage);
614         ec = errorCodes.get(1);
615         assertEquals(21, ec.errorCode);
616         assertEquals(res.getString("default.error"), ec.errorMessage);
617         ec = errorCodes.get(2);
618         assertEquals(22, ec.errorCode);
619         assertEquals("doesnt.exist", ec.errorMessage);
620     }
621 
622     @Test
623     public void testCustomConverterByPositionRead() throws IOException {
624         ResourceBundle res = ResourceBundle.getBundle("collectionconverter");
625         List<IdAndErrorSplitByPosition> beanList = new CsvToBeanBuilder<IdAndErrorSplitByPosition>(new FileReader("src/test/resources/testinputsplitcustombyposition.csv"))
626                 .withType(IdAndErrorSplitByPosition.class).build().parse();
627         assertEquals(2, beanList.size());
628 
629         // Bean one
630         IdAndErrorSplitByPosition bean = beanList.get(0);
631         assertEquals(1, bean.getId());
632         List<ErrorCode> errorCodes = bean.getEc();
633         assertEquals(3, errorCodes.size());
634         ErrorCode ec = errorCodes.get(0);
635         assertEquals(10, ec.errorCode);
636         assertEquals(res.getString("default.error"), ec.errorMessage);
637         ec = errorCodes.get(1);
638         assertEquals(11, ec.errorCode);
639         assertEquals("doesnt.exist", ec.errorMessage);
640         ec = errorCodes.get(2);
641         assertEquals(12, ec.errorCode);
642         assertEquals(res.getString("default.error"), ec.errorMessage);
643 
644         // Bean two
645         bean = beanList.get(1);
646         assertEquals(2, bean.getId());
647         errorCodes = bean.getEc();
648         assertEquals(3, errorCodes.size());
649         ec = errorCodes.get(0);
650         assertEquals(20, ec.errorCode);
651         assertEquals("doesnt.exist", ec.errorMessage);
652         ec = errorCodes.get(1);
653         assertEquals(21, ec.errorCode);
654         assertEquals(res.getString("default.error"), ec.errorMessage);
655         ec = errorCodes.get(2);
656         assertEquals(22, ec.errorCode);
657         assertEquals("doesnt.exist", ec.errorMessage);
658     }
659 
660     @Test
661     public void testCustomConverterByNameWrite() throws IOException, CsvException {
662         List<IdAndErrorSplitByName> beanList = new CsvToBeanBuilder<IdAndErrorSplitByName>(new FileReader("src/test/resources/testinputsplitcustombyname.csv"))
663                 .withType(IdAndErrorSplitByName.class).build().parse();
664         StringWriter writer = new StringWriter();
665         new StatefulBeanToCsvBuilder<IdAndErrorSplitByName>(writer).build().write(beanList);
666         assertEquals("\"EC\",\"ID\"\n\"10default.error 11default.error 12default.error\",\"1\"\n\"20default.error 21default.error 22default.error\",\"2\"\n", writer.toString());
667     }
668 
669     @Test
670     public void testCustomConverterByPositionWrite() throws IOException, CsvException {
671         List<IdAndErrorSplitByPosition> beanList = new CsvToBeanBuilder<IdAndErrorSplitByPosition>(new FileReader("src/test/resources/testinputsplitcustombyposition.csv"))
672                 .withType(IdAndErrorSplitByPosition.class).build().parse();
673         StringWriter writer = new StringWriter();
674         new StatefulBeanToCsvBuilder<IdAndErrorSplitByPosition>(writer).build().write(beanList);
675         assertEquals("\"1\",\"10default.error 11default.error 12default.error\"\n\"2\",\"20default.error 21default.error 22default.error\"\n", writer.toString());
676     }
677 
678     @Test
679     public void testBadCustomConverter() throws IOException {
680         try {
681             // Input doesn't matter. The test doesn't get that far.
682             new CsvToBeanBuilder<BadSplitConverter>(new FileReader("src/test/resources/testinputsplitcustombyname.csv"))
683                     .withType(BadSplitConverter.class)
684                     .build().parse();
685         }
686         catch(CsvBadConverterException csve) {
687             assertEquals(BadCollectionConverter.class, csve.getConverterClass());
688         }
689     }
690 
691     @Test
692     public void testCaptureByNameInvalidRegex() {
693         try {
694             MappingStrategy<InvalidCapture> strat = new HeaderColumnNameMappingStrategy<>();
695             strat.setType(InvalidCapture.class);
696             fail("Exception should have been thrown.");
697         }
698         catch(CsvBadConverterException csve) {
699             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
700             assertNotNull(csve.getCause());
701         }
702     }
703 
704     @Test
705     public void testCaptureByPositionInvalidRegex() {
706         try {
707             MappingStrategy<InvalidCapture> strat = new ColumnPositionMappingStrategy<>();
708             strat.setType(InvalidCapture.class);
709             fail("Exception should have been thrown.");
710         }
711         catch(CsvBadConverterException csve) {
712             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
713             assertNotNull(csve.getCause());
714         }
715     }
716 
717     @Test
718     public void testCaptureByNameRegexWithoutCaptureGroup() {
719         try {
720             MappingStrategy<NoCaptureGroup> strat = new HeaderColumnNameMappingStrategy<>();
721             strat.setType(NoCaptureGroup.class);
722             fail("Exception should have been thrown.");
723         }
724         catch(CsvBadConverterException csve) {
725             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
726             assertNull(csve.getCause());
727         }
728     }
729 
730     @Test
731     public void testCaptureByPositionRegexWithoutCaptureGroup() {
732         try {
733             MappingStrategy<NoCaptureGroup> strat = new ColumnPositionMappingStrategy<>();
734             strat.setType(NoCaptureGroup.class);
735             fail("Exception should have been thrown.");
736         }
737         catch(CsvBadConverterException csve) {
738             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
739             assertNull(csve.getCause());
740         }
741     }
742 
743     @Test
744     public void testFormatByNameWriteInvalidFormatString() {
745         try {
746             MappingStrategy<InvalidFormatString> strat = new HeaderColumnNameMappingStrategy<>();
747             strat.setType(InvalidFormatString.class);
748             fail("Exception should have been thrown.");
749         }
750         catch(CsvBadConverterException csve) {
751             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
752             assertNotNull(csve.getCause());
753         }
754     }
755 
756     @Test
757     public void testFormatByPositionWriteInvalidFormatString() {
758         try {
759             MappingStrategy<InvalidFormatString> strat = new ColumnPositionMappingStrategy<>();
760             strat.setType(InvalidFormatString.class);
761             fail("Exception should have been thrown.");
762         }
763         catch(CsvBadConverterException csve) {
764             assertEquals(BeanFieldSplit.class, csve.getConverterClass());
765             assertNotNull(csve.getCause());
766         }
767     }
768 }