View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.commons.csv;
21  
22  import static org.apache.commons.csv.Constants.BACKSLASH;
23  import static org.apache.commons.csv.Constants.CR;
24  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
25  import static org.junit.jupiter.api.Assertions.assertEquals;
26  import static org.junit.jupiter.api.Assertions.assertFalse;
27  import static org.junit.jupiter.api.Assertions.assertNotEquals;
28  import static org.junit.jupiter.api.Assertions.assertNull;
29  import static org.junit.jupiter.api.Assertions.assertThrows;
30  import static org.mockito.Mockito.mock;
31  import static org.mockito.Mockito.never;
32  import static org.mockito.Mockito.times;
33  import static org.mockito.Mockito.verify;
34  
35  import java.io.CharArrayWriter;
36  import java.io.File;
37  import java.io.FileReader;
38  import java.io.IOException;
39  import java.io.PrintStream;
40  import java.io.Reader;
41  import java.io.StringReader;
42  import java.io.StringWriter;
43  import java.io.Writer;
44  import java.nio.charset.Charset;
45  import java.nio.charset.StandardCharsets;
46  import java.nio.file.Files;
47  import java.nio.file.Path;
48  import java.sql.BatchUpdateException;
49  import java.sql.Connection;
50  import java.sql.DriverManager;
51  import java.sql.ResultSet;
52  import java.sql.SQLException;
53  import java.sql.Statement;
54  import java.util.Arrays;
55  import java.util.Date;
56  import java.util.HashSet;
57  import java.util.Iterator;
58  import java.util.LinkedList;
59  import java.util.List;
60  import java.util.Objects;
61  import java.util.Random;
62  import java.util.Vector;
63  import java.util.stream.Stream;
64  
65  import org.apache.commons.io.FileUtils;
66  import org.apache.commons.io.IOUtils;
67  import org.apache.commons.io.output.NullOutputStream;
68  import org.apache.commons.lang3.StringUtils;
69  import org.h2.tools.SimpleResultSet;
70  import org.junit.jupiter.api.Disabled;
71  import org.junit.jupiter.api.Test;
72  import org.junit.jupiter.params.ParameterizedTest;
73  import org.junit.jupiter.params.provider.ValueSource;
74  
75  /**
76   * Tests {@link CSVPrinter}.
77   */
78  public class CSVPrinterTest {
79  
80      private static final int TABLE_RECORD_COUNT = 2;
81      private static final int TABLE_AND_HEADER_RECORD_COUNT = TABLE_RECORD_COUNT + 1;
82      private static final char DQUOTE_CHAR = '"';
83      private static final char EURO_CH = '\u20AC';
84      private static final int ITERATIONS_FOR_RANDOM_TEST = 50_000;
85      private static final char QUOTE_CH = '\'';
86      private static final String RECORD_SEPARATOR = CSVFormat.DEFAULT.getRecordSeparator();
87  
88      private static String printable(final String s) {
89          final StringBuilder sb = new StringBuilder();
90          for (int i = 0; i < s.length(); i++) {
91              final char ch = s.charAt(i);
92              if (ch <= ' ' || ch >= 128) {
93                  sb.append("(").append((int) ch).append(")");
94              } else {
95                  sb.append(ch);
96              }
97          }
98          return sb.toString();
99      }
100 
101     private String longText2;
102 
103     private void assertInitialState(final CSVPrinter printer) {
104         assertEquals(0, printer.getRecordCount());
105     }
106 
107     private void assertRowCount(final CSVFormat format, final String resultString, final int rowCount) throws IOException {
108         try (CSVParser parser = format.parse(new StringReader(resultString))) {
109             assertEquals(rowCount, parser.getRecords().size());
110         }
111     }
112 
113     private File createTempFile() throws IOException {
114         return createTempPath().toFile();
115     }
116 
117     private Path createTempPath() throws IOException {
118         return Files.createTempFile(getClass().getName(), ".csv");
119     }
120 
121     private void doOneRandom(final CSVFormat format) throws Exception {
122         final Random r = new Random();
123 
124         final int nLines = r.nextInt(4) + 1;
125         final int nCol = r.nextInt(3) + 1;
126         // nLines=1;nCol=2;
127         final String[][] lines = generateLines(nLines, nCol);
128 
129         final StringWriter sw = new StringWriter();
130         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
131 
132             for (int i = 0; i < nLines; i++) {
133                 // for (int j=0; j<lines[i].length; j++) System.out.println("### VALUE=:" + printable(lines[i][j]));
134                 printer.printRecord((Object[]) lines[i]);
135             }
136 
137             printer.flush();
138         }
139         final String result = sw.toString();
140         // System.out.println("### :" + printable(result));
141 
142         try (CSVParser parser = CSVParser.parse(result, format)) {
143             final List<CSVRecord> parseResult = parser.getRecords();
144 
145             final String[][] expected = lines.clone();
146             for (int i = 0; i < expected.length; i++) {
147                 expected[i] = expectNulls(expected[i], format);
148             }
149             Utils.compare("Printer output :" + printable(result), expected, parseResult, -1);
150         }
151     }
152 
153     private void doRandom(final CSVFormat format, final int iter) throws Exception {
154         for (int i = 0; i < iter; i++) {
155             doOneRandom(format);
156         }
157     }
158 
159     /**
160      * Converts an input CSV array into expected output values WRT NULLs. NULL strings are converted to null values because the parser will convert these
161      * strings to null.
162      */
163     private <T> T[] expectNulls(final T[] original, final CSVFormat csvFormat) {
164         final T[] fixed = original.clone();
165         for (int i = 0; i < fixed.length; i++) {
166             if (Objects.equals(csvFormat.getNullString(), fixed[i])) {
167                 fixed[i] = null;
168             }
169         }
170         return fixed;
171     }
172 
173     private String[][] generateLines(final int nLines, final int nCol) {
174         final String[][] lines = new String[nLines][];
175         for (int i = 0; i < nLines; i++) {
176             final String[] line = new String[nCol];
177             lines[i] = line;
178             for (int j = 0; j < nCol; j++) {
179                 line[j] = randStr();
180             }
181         }
182         return lines;
183     }
184 
185     private Connection getH2Connection() throws SQLException, ClassNotFoundException {
186         Class.forName("org.h2.Driver");
187         return DriverManager.getConnection("jdbc:h2:mem:my_test;", "sa", "");
188     }
189 
190     private CSVPrinter printWithHeaderComments(final StringWriter sw, final Date now, final CSVFormat baseFormat) throws IOException {
191         // Use withHeaderComments first to test CSV-145
192         // @formatter:off
193         final CSVFormat format = baseFormat.builder()
194                 .setHeaderComments((String[]) null) // don't blow up
195                 .setHeaderComments((Object[]) null) // don't blow up
196                 .setHeaderComments("Generated by Apache Commons CSV 1.1", now)
197                 .setCommentMarker('#')
198                 .setHeader("Col1", "Col2")
199                 .get();
200         // @formatter:on
201         final CSVPrinter printer = format.print(sw);
202         printer.printRecord("A", "B");
203         printer.printRecord("C", "D");
204         printer.close();
205         return printer;
206     }
207 
208     private String randStr() {
209         final Random r = new Random();
210         final int sz = r.nextInt(20);
211         // sz = r.nextInt(3);
212         final char[] buf = new char[sz];
213         for (int i = 0; i < sz; i++) {
214             // stick in special chars with greater frequency
215             final char ch;
216             final int what = r.nextInt(20);
217             switch (what) {
218             case 0:
219                 ch = '\r';
220                 break;
221             case 1:
222                 ch = '\n';
223                 break;
224             case 2:
225                 ch = '\t';
226                 break;
227             case 3:
228                 ch = '\f';
229                 break;
230             case 4:
231                 ch = ' ';
232                 break;
233             case 5:
234                 ch = ',';
235                 break;
236             case 6:
237                 ch = DQUOTE_CHAR;
238                 break;
239             case 7:
240                 ch = '\'';
241                 break;
242             case 8:
243                 ch = BACKSLASH;
244                 break;
245             default:
246                 ch = (char) r.nextInt(300);
247                 break;
248             // default: ch = 'a'; break;
249             }
250             buf[i] = ch;
251         }
252         return new String(buf);
253     }
254 
255     private void setUpTable(final Connection connection) throws SQLException {
256         try (Statement statement = connection.createStatement()) {
257             statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), TEXT CLOB, BIN_DATA BLOB)");
258             statement.execute("insert into TEST values(1, 'r1', 'long text 1', 'binary data 1')");
259             longText2 = StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 4);
260             longText2 += "\"\r\n\"b\"";
261             longText2 += StringUtils.repeat('c', IOUtils.DEFAULT_BUFFER_SIZE - 1);
262             statement.execute("insert into TEST values(2, 'r2', '" + longText2 + "', 'binary data 2')");
263             longText2 = longText2.replace("\"", "\"\"");
264         }
265     }
266 
267     @Test
268     public void testCloseBackwardCompatibility() throws IOException {
269         try (Writer writer = mock(Writer.class)) {
270             final CSVFormat csvFormat = CSVFormat.DEFAULT;
271             try (CSVPrinter printer = new CSVPrinter(writer, csvFormat)) {
272                 assertInitialState(printer);
273             }
274             verify(writer, never()).flush();
275             verify(writer, times(1)).close();
276         }
277     }
278 
279     @Test
280     public void testCloseWithCsvFormatAutoFlushOff() throws IOException {
281         try (Writer writer = mock(Writer.class)) {
282             final CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(false);
283             try (CSVPrinter printer = new CSVPrinter(writer, csvFormat)) {
284                 assertInitialState(printer);
285             }
286             verify(writer, never()).flush();
287             verify(writer, times(1)).close();
288         }
289     }
290 
291     @Test
292     public void testCloseWithCsvFormatAutoFlushOn() throws IOException {
293         // System.out.println("start method");
294         try (Writer writer = mock(Writer.class)) {
295             final CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(true);
296             try (CSVPrinter printer = new CSVPrinter(writer, csvFormat)) {
297                 assertInitialState(printer);
298             }
299             verify(writer, times(1)).flush();
300             verify(writer, times(1)).close();
301         }
302     }
303 
304     @Test
305     public void testCloseWithFlushOff() throws IOException {
306         try (Writer writer = mock(Writer.class)) {
307             final CSVFormat csvFormat = CSVFormat.DEFAULT;
308             @SuppressWarnings("resource")
309             final CSVPrinter printer = new CSVPrinter(writer, csvFormat);
310             assertInitialState(printer);
311             printer.close(false);
312             assertEquals(0, printer.getRecordCount());
313             verify(writer, never()).flush();
314             verify(writer, times(1)).close();
315         }
316     }
317 
318     @Test
319     public void testCloseWithFlushOn() throws IOException {
320         try (Writer writer = mock(Writer.class)) {
321             @SuppressWarnings("resource")
322             final CSVPrinter printer = new CSVPrinter(writer, CSVFormat.DEFAULT);
323             assertInitialState(printer);
324             printer.close(true);
325             assertEquals(0, printer.getRecordCount());
326             verify(writer, times(1)).flush();
327         }
328     }
329 
330     @Test
331     public void testCRComment() throws IOException {
332         final StringWriter sw = new StringWriter();
333         final Object value = "abc";
334         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) {
335             assertInitialState(printer);
336             printer.print(value);
337             assertEquals(0, printer.getRecordCount());
338             printer.printComment("This is a comment\r\non multiple lines\rthis is next comment\r");
339             assertEquals("abc" + RECORD_SEPARATOR + "# This is a comment" + RECORD_SEPARATOR + "# on multiple lines" + RECORD_SEPARATOR +
340                     "# this is next comment" + RECORD_SEPARATOR + "# " + RECORD_SEPARATOR, sw.toString());
341             assertEquals(0, printer.getRecordCount());
342         }
343     }
344 
345     @Test
346     public void testCSV135() throws IOException {
347         final List<String> list = new LinkedList<>();
348         list.add("\"\""); // ""
349         list.add("\\\\"); // \\
350         list.add("\\\"\\"); // \"\
351         //
352         // "",\\,\"\ (unchanged)
353         tryFormat(list, null, null, "\"\",\\\\,\\\"\\");
354         //
355         // """""",\\,"\""\" (quoted, and embedded DQ doubled)
356         tryFormat(list, '"', null, "\"\"\"\"\"\",\\\\,\"\\\"\"\\\"");
357         //
358         // "",\\\\,\\"\\ (escapes escaped, not quoted)
359         tryFormat(list, null, '\\', "\"\",\\\\\\\\,\\\\\"\\\\");
360         //
361         // "\"\"","\\\\","\\\"\\" (quoted, and embedded DQ & escape escaped)
362         tryFormat(list, '"', '\\', "\"\\\"\\\"\",\"\\\\\\\\\",\"\\\\\\\"\\\\\"");
363         //
364         // """""",\\,"\""\" (quoted, embedded DQ escaped)
365         tryFormat(list, '"', '"', "\"\"\"\"\"\",\\\\,\"\\\"\"\\\"");
366     }
367 
368     @Test
369     public void testCSV259() throws IOException {
370         final StringWriter sw = new StringWriter();
371         try (Reader reader = new FileReader("src/test/resources/org/apache/commons/csv/CSV-259/sample.txt");
372                 CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape('!').withQuote(null))) {
373             assertInitialState(printer);
374             printer.print(reader);
375             assertEquals("x!,y!,z", sw.toString());
376         }
377     }
378 
379     @Test
380     public void testDelimeterQuoted() throws IOException {
381         final StringWriter sw = new StringWriter();
382         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) {
383             assertInitialState(printer);
384             printer.print("a,b,c");
385             printer.print("xyz");
386             assertEquals("'a,b,c',xyz", sw.toString());
387         }
388     }
389 
390     @Test
391     public void testDelimeterQuoteNone() throws IOException {
392         final StringWriter sw = new StringWriter();
393         final CSVFormat format = CSVFormat.DEFAULT.withEscape('!').withQuoteMode(QuoteMode.NONE);
394         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
395             assertInitialState(printer);
396             printer.print("a,b,c");
397             printer.print("xyz");
398             assertEquals("a!,b!,c,xyz", sw.toString());
399         }
400     }
401 
402     @Test
403     public void testDelimeterStringQuoted() throws IOException {
404         final StringWriter sw = new StringWriter();
405         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.builder().setDelimiter("[|]").setQuote('\'').get())) {
406             assertInitialState(printer);
407             printer.print("a[|]b[|]c");
408             printer.print("xyz");
409             assertEquals("'a[|]b[|]c'[|]xyz", sw.toString());
410         }
411     }
412 
413     @Test
414     public void testDelimeterStringQuoteNone() throws IOException {
415         final StringWriter sw = new StringWriter();
416         final CSVFormat format = CSVFormat.DEFAULT.builder().setDelimiter("[|]").setEscape('!').setQuoteMode(QuoteMode.NONE).get();
417         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
418             assertInitialState(printer);
419             printer.print("a[|]b[|]c");
420             printer.print("xyz");
421             printer.print("a[xy]bc[]");
422             assertEquals("a![!|!]b![!|!]c[|]xyz[|]a[xy]bc[]", sw.toString());
423         }
424     }
425 
426     @Test
427     public void testDelimiterEscaped() throws IOException {
428         final StringWriter sw = new StringWriter();
429         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape('!').withQuote(null))) {
430             assertInitialState(printer);
431             printer.print("a,b,c");
432             printer.print("xyz");
433             assertEquals("a!,b!,c,xyz", sw.toString());
434         }
435     }
436 
437     @Test
438     public void testDelimiterPlain() throws IOException {
439         final StringWriter sw = new StringWriter();
440         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) {
441             assertInitialState(printer);
442             printer.print("a,b,c");
443             printer.print("xyz");
444             assertEquals("a,b,c,xyz", sw.toString());
445         }
446     }
447 
448     @Test
449     public void testDelimiterStringEscaped() throws IOException {
450         final StringWriter sw = new StringWriter();
451         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.builder().setDelimiter("|||").setEscape('!').setQuote(null).get())) {
452             assertInitialState(printer);
453             printer.print("a|||b|||c");
454             printer.print("xyz");
455             assertEquals("a!|!|!|b!|!|!|c|||xyz", sw.toString());
456         }
457     }
458 
459     @Test
460     public void testDisabledComment() throws IOException {
461         final StringWriter sw = new StringWriter();
462         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
463             assertInitialState(printer);
464             printer.printComment("This is a comment");
465             assertEquals("", sw.toString());
466             assertEquals(0, printer.getRecordCount());
467         }
468     }
469 
470     @Test
471     public void testDontQuoteEuroFirstChar() throws IOException {
472         final StringWriter sw = new StringWriter();
473         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.RFC4180)) {
474             assertInitialState(printer);
475             printer.printRecord(EURO_CH, "Deux");
476             assertEquals(EURO_CH + ",Deux" + RECORD_SEPARATOR, sw.toString());
477         }
478     }
479 
480     @Test
481     public void testEolEscaped() throws IOException {
482         final StringWriter sw = new StringWriter();
483         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withEscape('!'))) {
484             assertInitialState(printer);
485             printer.print("a\rb\nc");
486             printer.print("x\fy\bz");
487             assertEquals("a!rb!nc,x\fy\bz", sw.toString());
488         }
489     }
490 
491     @Test
492     public void testEolPlain() throws IOException {
493         final StringWriter sw = new StringWriter();
494         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) {
495             assertInitialState(printer);
496             printer.print("a\rb\nc");
497             printer.print("x\fy\bz");
498             assertEquals("a\rb\nc,x\fy\bz", sw.toString());
499         }
500     }
501 
502     @Test
503     public void testEolQuoted() throws IOException {
504         final StringWriter sw = new StringWriter();
505         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) {
506             assertInitialState(printer);
507             printer.print("a\rb\nc");
508             printer.print("x\by\fz");
509             assertEquals("'a\rb\nc',x\by\fz", sw.toString());
510         }
511     }
512 
513     @SuppressWarnings("unlikely-arg-type")
514     @Test
515     public void testEquals() throws IOException {
516         // Don't use assertNotEquals here
517         assertFalse(CSVFormat.DEFAULT.equals(null));
518         // Don't use assertNotEquals here
519         assertFalse(CSVFormat.DEFAULT.equals(""));
520     }
521 
522     @Test
523     public void testEscapeBackslash1() throws IOException {
524         final StringWriter sw = new StringWriter();
525         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) {
526             assertInitialState(printer);
527             printer.print("\\");
528         }
529         assertEquals("\\", sw.toString());
530     }
531 
532     @Test
533     public void testEscapeBackslash2() throws IOException {
534         final StringWriter sw = new StringWriter();
535         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) {
536             assertInitialState(printer);
537             printer.print("\\\r");
538         }
539         assertEquals("'\\\r'", sw.toString());
540     }
541 
542     @Test
543     public void testEscapeBackslash3() throws IOException {
544         final StringWriter sw = new StringWriter();
545         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) {
546             assertInitialState(printer);
547             printer.print("X\\\r");
548         }
549         assertEquals("'X\\\r'", sw.toString());
550     }
551 
552     @Test
553     public void testEscapeBackslash4() throws IOException {
554         final StringWriter sw = new StringWriter();
555         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) {
556             assertInitialState(printer);
557             printer.print("\\\\");
558         }
559         assertEquals("\\\\", sw.toString());
560     }
561 
562     @Test
563     public void testEscapeBackslash5() throws IOException {
564         final StringWriter sw = new StringWriter();
565         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) {
566             assertInitialState(printer);
567             printer.print("\\\\");
568         }
569         assertEquals("\\\\", sw.toString());
570     }
571 
572     @Test
573     public void testEscapeNull1() throws IOException {
574         final StringWriter sw = new StringWriter();
575         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) {
576             assertInitialState(printer);
577             printer.print("\\");
578         }
579         assertEquals("\\", sw.toString());
580     }
581 
582     @Test
583     public void testEscapeNull2() throws IOException {
584         final StringWriter sw = new StringWriter();
585         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) {
586             assertInitialState(printer);
587             printer.print("\\\r");
588         }
589         assertEquals("\"\\\r\"", sw.toString());
590     }
591 
592     @Test
593     public void testEscapeNull3() throws IOException {
594         final StringWriter sw = new StringWriter();
595         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) {
596             assertInitialState(printer);
597             printer.print("X\\\r");
598         }
599         assertEquals("\"X\\\r\"", sw.toString());
600     }
601 
602     @Test
603     public void testEscapeNull4() throws IOException {
604         final StringWriter sw = new StringWriter();
605         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) {
606             assertInitialState(printer);
607             printer.print("\\\\");
608         }
609         assertEquals("\\\\", sw.toString());
610     }
611 
612     @Test
613     public void testEscapeNull5() throws IOException {
614         final StringWriter sw = new StringWriter();
615         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) {
616             assertInitialState(printer);
617             printer.print("\\\\");
618         }
619         assertEquals("\\\\", sw.toString());
620     }
621 
622     @Test
623     public void testExcelPrintAllArrayOfArrays() throws IOException {
624         final StringWriter sw = new StringWriter();
625         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
626             assertInitialState(printer);
627             printer.printRecords((Object[]) new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } });
628             assertEquals("r1c1,r1c2" + RECORD_SEPARATOR + "r2c1,r2c2" + RECORD_SEPARATOR, sw.toString());
629         }
630     }
631 
632     @Test
633     public void testExcelPrintAllArrayOfArraysWithFirstEmptyValue2() throws IOException {
634         final StringWriter sw = new StringWriter();
635         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
636             assertInitialState(printer);
637             printer.printRecords((Object[]) new String[][] { { "" } });
638             assertEquals("\"\"" + RECORD_SEPARATOR, sw.toString());
639         }
640     }
641 
642     @Test
643     public void testExcelPrintAllArrayOfArraysWithFirstSpaceValue1() throws IOException {
644         final StringWriter sw = new StringWriter();
645         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
646             assertInitialState(printer);
647             printer.printRecords((Object[]) new String[][] { { " ", "r1c2" } });
648             assertEquals("\" \",r1c2" + RECORD_SEPARATOR, sw.toString());
649         }
650     }
651 
652     @Test
653     public void testExcelPrintAllArrayOfArraysWithFirstTabValue1() throws IOException {
654         final StringWriter sw = new StringWriter();
655         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
656             assertInitialState(printer);
657             printer.printRecords((Object[]) new String[][] { { "\t", "r1c2" } });
658             assertEquals("\"\t\",r1c2" + RECORD_SEPARATOR, sw.toString());
659         }
660     }
661 
662     @Test
663     public void testExcelPrintAllArrayOfLists() throws IOException {
664         final StringWriter sw = new StringWriter();
665         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
666             assertInitialState(printer);
667             printer.printRecords((Object[]) new List[] { Arrays.asList("r1c1", "r1c2"), Arrays.asList("r2c1", "r2c2") });
668             assertEquals("r1c1,r1c2" + RECORD_SEPARATOR + "r2c1,r2c2" + RECORD_SEPARATOR, sw.toString());
669         }
670     }
671 
672     @Test
673     public void testExcelPrintAllArrayOfListsWithFirstEmptyValue2() throws IOException {
674         final StringWriter sw = new StringWriter();
675         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
676             assertInitialState(printer);
677             printer.printRecords((Object[]) new List[] { Arrays.asList("") });
678             assertEquals("\"\"" + RECORD_SEPARATOR, sw.toString());
679         }
680     }
681 
682     @Test
683     public void testExcelPrintAllIterableOfArrays() throws IOException {
684         final StringWriter sw = new StringWriter();
685         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
686             assertInitialState(printer);
687             printer.printRecords(Arrays.asList(new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } }));
688             assertEquals("r1c1,r1c2" + RECORD_SEPARATOR + "r2c1,r2c2" + RECORD_SEPARATOR, sw.toString());
689         }
690     }
691 
692     @Test
693     public void testExcelPrintAllIterableOfArraysWithFirstEmptyValue2() throws IOException {
694         final StringWriter sw = new StringWriter();
695         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
696             assertInitialState(printer);
697             printer.printRecords(Arrays.asList(new String[][] { { "" } }));
698             assertEquals("\"\"" + RECORD_SEPARATOR, sw.toString());
699         }
700     }
701 
702     @Test
703     public void testExcelPrintAllIterableOfLists() throws IOException {
704         final StringWriter sw = new StringWriter();
705         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
706             assertInitialState(printer);
707             printer.printRecords(Arrays.asList(Arrays.asList("r1c1", "r1c2"), Arrays.asList("r2c1", "r2c2")));
708             assertEquals("r1c1,r1c2" + RECORD_SEPARATOR + "r2c1,r2c2" + RECORD_SEPARATOR, sw.toString());
709         }
710     }
711 
712     @ParameterizedTest
713     @ValueSource(longs = { -1, 0, 1, 2, Long.MAX_VALUE })
714     public void testExcelPrintAllStreamOfArrays(final long maxRows) throws IOException {
715         final StringWriter sw = new StringWriter();
716         final CSVFormat format = CSVFormat.EXCEL.builder().setMaxRows(maxRows).get();
717         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
718             assertInitialState(printer);
719             printer.printRecords(Stream.of(new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } }));
720             String expected = "r1c1,r1c2" + RECORD_SEPARATOR;
721             if (maxRows != 1) {
722                 expected += "r2c1,r2c2" + RECORD_SEPARATOR;
723             }
724             assertEquals(expected, sw.toString());
725         }
726     }
727 
728     @Test
729     public void testExcelPrinter1() throws IOException {
730         final StringWriter sw = new StringWriter();
731         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
732             assertInitialState(printer);
733             printer.printRecord("a", "b");
734             assertEquals("a,b" + RECORD_SEPARATOR, sw.toString());
735         }
736     }
737 
738     @Test
739     public void testExcelPrinter2() throws IOException {
740         final StringWriter sw = new StringWriter();
741         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) {
742             assertInitialState(printer);
743             printer.printRecord("a,b", "b");
744             assertEquals("\"a,b\",b" + RECORD_SEPARATOR, sw.toString());
745         }
746     }
747 
748     @Test
749     public void testHeader() throws IOException {
750         final StringWriter sw = new StringWriter();
751         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3"))) {
752             assertEquals(1, printer.getRecordCount());
753             printer.printRecord("a", "b", "c");
754             printer.printRecord("x", "y", "z");
755             assertEquals("C1,C2,C3\r\na,b,c\r\nx,y,z\r\n", sw.toString());
756         }
757     }
758 
759     @Test
760     public void testHeaderCommentExcel() throws IOException {
761         final StringWriter sw = new StringWriter();
762         final Date now = new Date();
763         final CSVFormat format = CSVFormat.EXCEL;
764         try (CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format)) {
765             assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + "\r\nCol1,Col2\r\nA,B\r\nC,D\r\n", sw.toString());
766         }
767     }
768 
769     @Test
770     public void testHeaderCommentTdf() throws IOException {
771         final StringWriter sw = new StringWriter();
772         final Date now = new Date();
773         final CSVFormat format = CSVFormat.TDF;
774         try (CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format)) {
775             assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + "\r\nCol1\tCol2\r\nA\tB\r\nC\tD\r\n", sw.toString());
776         }
777     }
778 
779     @Test
780     public void testHeaderNotSet() throws IOException {
781         final StringWriter sw = new StringWriter();
782         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) {
783             assertInitialState(printer);
784             printer.printRecord("a", "b", "c");
785             printer.printRecord("x", "y", "z");
786             assertEquals("a,b,c\r\nx,y,z\r\n", sw.toString());
787         }
788     }
789 
790     @Test
791     public void testInvalidFormat() {
792         assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withDelimiter(CR));
793     }
794 
795     @Test
796     public void testJdbcPrinter() throws IOException, ClassNotFoundException, SQLException {
797         final StringWriter sw = new StringWriter();
798         final CSVFormat csvFormat = CSVFormat.DEFAULT;
799         try (Connection connection = getH2Connection()) {
800             setUpTable(connection);
801             try (Statement stmt = connection.createStatement();
802                     CSVPrinter printer = new CSVPrinter(sw, csvFormat);
803                     ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT, BIN_DATA from TEST")) {
804                 assertInitialState(printer);
805                 printer.printRecords(resultSet);
806                 assertEquals(TABLE_RECORD_COUNT, printer.getRecordCount());
807             }
808         }
809         final String csv = sw.toString();
810         assertEquals("1,r1,\"long text 1\",\"YmluYXJ5IGRhdGEgMQ==\r\n\"" + RECORD_SEPARATOR + "2,r2,\"" + longText2 + "\",\"YmluYXJ5IGRhdGEgMg==\r\n\"" +
811                 RECORD_SEPARATOR, csv);
812         // Round trip the data
813         try (StringReader reader = new StringReader(csv);
814                 CSVParser csvParser = csvFormat.parse(reader)) {
815             // Row 1
816             CSVRecord record = csvParser.nextRecord();
817             assertEquals("1", record.get(0));
818             assertEquals("r1", record.get(1));
819             assertEquals("long text 1", record.get(2));
820             assertEquals("YmluYXJ5IGRhdGEgMQ==\r\n", record.get(3));
821             // Row 2
822             record = csvParser.nextRecord();
823             assertEquals("2", record.get(0));
824             assertEquals("r2", record.get(1));
825             assertEquals("YmluYXJ5IGRhdGEgMg==\r\n", record.get(3));
826         }
827     }
828 
829     @Test
830     public void testJdbcPrinterWithFirstEmptyValue2() throws IOException, ClassNotFoundException, SQLException {
831         final StringWriter sw = new StringWriter();
832         try (Connection connection = getH2Connection()) {
833             try (Statement stmt = connection.createStatement();
834                     ResultSet resultSet = stmt.executeQuery("select '' AS EMPTYVALUE from DUAL");
835                     CSVPrinter printer = CSVFormat.DEFAULT.withHeader(resultSet).print(sw)) {
836                 printer.printRecords(resultSet);
837             }
838         }
839         assertEquals("EMPTYVALUE" + RECORD_SEPARATOR + "\"\"" + RECORD_SEPARATOR, sw.toString());
840     }
841 
842     @ParameterizedTest
843     @ValueSource(longs = { -1, 0, 1, 2, 3, 4, Long.MAX_VALUE })
844     public void testJdbcPrinterWithResultSet(final long maxRows) throws IOException, ClassNotFoundException, SQLException {
845         final StringWriter sw = new StringWriter();
846         final CSVFormat format = CSVFormat.DEFAULT.builder().setMaxRows(maxRows).get();
847         try (Connection connection = getH2Connection()) {
848             setUpTable(connection);
849             try (Statement stmt = connection.createStatement();
850                     ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST");
851                     CSVPrinter printer = format.withHeader(resultSet).print(sw)) {
852                 printer.printRecords(resultSet);
853             }
854         }
855         final String resultString = sw.toString();
856         final String header = "ID,NAME,TEXT";
857         final String headerRow1 = header + RECORD_SEPARATOR + "1,r1,\"long text 1\"" + RECORD_SEPARATOR;
858         final String allRows = headerRow1 + "2,r2,\"" + longText2 + "\"" + RECORD_SEPARATOR;
859         final int expectedRowsWithHeader;
860         if (maxRows == 1) {
861             assertEquals(headerRow1, resultString);
862             expectedRowsWithHeader = 2;
863         } else {
864             assertEquals(allRows, resultString);
865             expectedRowsWithHeader = TABLE_AND_HEADER_RECORD_COUNT;
866         }
867         assertRowCount(CSVFormat.DEFAULT, resultString, expectedRowsWithHeader);
868     }
869 
870     @ParameterizedTest
871     @ValueSource(longs = { -1, 0, 3, 4, Long.MAX_VALUE })
872     public void testJdbcPrinterWithResultSetHeader(final long maxRows) throws IOException, ClassNotFoundException, SQLException {
873         final StringWriter sw = new StringWriter();
874         try (Connection connection = getH2Connection()) {
875             setUpTable(connection);
876             final CSVFormat format = CSVFormat.DEFAULT.builder().setMaxRows(maxRows).get();
877             try (Statement stmt = connection.createStatement();
878                     CSVPrinter printer = new CSVPrinter(sw, format)) {
879                 try (ResultSet resultSet = stmt.executeQuery("select ID, NAME from TEST")) {
880                     printer.printRecords(resultSet, true);
881                     assertEquals(TABLE_RECORD_COUNT, printer.getRecordCount());
882                     assertEquals("ID,NAME" + RECORD_SEPARATOR + "1,r1" + RECORD_SEPARATOR + "2,r2" + RECORD_SEPARATOR, sw.toString());
883                 }
884                 assertRowCount(format, sw.toString(), TABLE_AND_HEADER_RECORD_COUNT);
885                 try (ResultSet resultSet = stmt.executeQuery("select ID, NAME from TEST")) {
886                     printer.printRecords(resultSet, false);
887                     assertEquals(TABLE_RECORD_COUNT * 2, printer.getRecordCount());
888                     assertNotEquals("ID,NAME" + RECORD_SEPARATOR + "1,r1" + RECORD_SEPARATOR + "2,r2" + RECORD_SEPARATOR, sw.toString());
889                 }
890                 assertRowCount(CSVFormat.DEFAULT, sw.toString(), TABLE_AND_HEADER_RECORD_COUNT + TABLE_RECORD_COUNT);
891             }
892         }
893     }
894 
895     @ParameterizedTest
896     @ValueSource(longs = { -1, 0, 3, 4, Long.MAX_VALUE })
897     public void testJdbcPrinterWithResultSetMetaData(final long maxRows) throws IOException, ClassNotFoundException, SQLException {
898         final StringWriter sw = new StringWriter();
899         try (Connection connection = getH2Connection()) {
900             setUpTable(connection);
901             final CSVFormat format = CSVFormat.DEFAULT.builder().setMaxRows(maxRows).get();
902             try (Statement stmt = connection.createStatement();
903                     ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST");
904                     CSVPrinter printer = format.withHeader(resultSet.getMetaData()).print(sw)) {
905                 // The header is the first record.
906                 assertEquals(1, printer.getRecordCount());
907                 printer.printRecords(resultSet);
908                 assertEquals(3, printer.getRecordCount());
909                 assertEquals("ID,NAME,TEXT" + RECORD_SEPARATOR + "1,r1,\"long text 1\"" + RECORD_SEPARATOR + "2,r2,\"" + longText2 + "\"" + RECORD_SEPARATOR,
910                         sw.toString());
911             }
912             assertRowCount(format, sw.toString(), TABLE_AND_HEADER_RECORD_COUNT);
913         }
914     }
915 
916     @Test
917     public void testJira135_part1() throws IOException {
918         final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH);
919         final StringWriter sw = new StringWriter();
920         final List<String> list = new LinkedList<>();
921         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
922             list.add("\"");
923             printer.printRecord(list);
924         }
925         final String expected = "\"\\\"\"" + format.getRecordSeparator();
926         assertEquals(expected, sw.toString());
927         final String[] record0 = toFirstRecordValues(expected, format);
928         assertArrayEquals(expectNulls(list.toArray(), format), record0);
929     }
930 
931     @Test
932     @Disabled
933     public void testJira135_part2() throws IOException {
934         final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH);
935         final StringWriter sw = new StringWriter();
936         final List<String> list = new LinkedList<>();
937         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
938             list.add("\n");
939             printer.printRecord(list);
940         }
941         final String expected = "\"\\n\"" + format.getRecordSeparator();
942         assertEquals(expected, sw.toString());
943         final String[] record0 = toFirstRecordValues(expected, format);
944         assertArrayEquals(expectNulls(list.toArray(), format), record0);
945     }
946 
947     @Test
948     public void testJira135_part3() throws IOException {
949         final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH);
950         final StringWriter sw = new StringWriter();
951         final List<String> list = new LinkedList<>();
952         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
953             list.add("\\");
954             printer.printRecord(list);
955         }
956         final String expected = "\"\\\\\"" + format.getRecordSeparator();
957         assertEquals(expected, sw.toString());
958         final String[] record0 = toFirstRecordValues(expected, format);
959         assertArrayEquals(expectNulls(list.toArray(), format), record0);
960     }
961 
962     @Test
963     @Disabled
964     public void testJira135All() throws IOException {
965         final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH);
966         final StringWriter sw = new StringWriter();
967         final List<String> list = new LinkedList<>();
968         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
969             list.add("\"");
970             list.add("\n");
971             list.add("\\");
972             printer.printRecord(list);
973         }
974         final String expected = "\"\\\"\",\"\\n\",\"\\\"" + format.getRecordSeparator();
975         assertEquals(expected, sw.toString());
976         final String[] record0 = toFirstRecordValues(expected, format);
977         assertArrayEquals(expectNulls(list.toArray(), format), record0);
978     }
979 
980     @Test
981     public void testMongoDbCsvBasic() throws IOException {
982         final StringWriter sw = new StringWriter();
983         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) {
984             printer.printRecord("a", "b");
985             assertEquals("a,b" + RECORD_SEPARATOR, sw.toString());
986             assertEquals(1, printer.getRecordCount());
987         }
988     }
989 
990     @Test
991     public void testMongoDbCsvCommaInValue() throws IOException {
992         final StringWriter sw = new StringWriter();
993         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) {
994             printer.printRecord("a,b", "c");
995             assertEquals("\"a,b\",c" + RECORD_SEPARATOR, sw.toString());
996             assertEquals(1, printer.getRecordCount());
997         }
998     }
999 
1000     @Test
1001     public void testMongoDbCsvDoubleQuoteInValue() throws IOException {
1002         final StringWriter sw = new StringWriter();
1003         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) {
1004             printer.printRecord("a \"c\" b", "d");
1005             assertEquals("\"a \"\"c\"\" b\",d" + RECORD_SEPARATOR, sw.toString());
1006             assertEquals(1, printer.getRecordCount());
1007         }
1008     }
1009 
1010     @Test
1011     public void testMongoDbCsvTabInValue() throws IOException {
1012         final StringWriter sw = new StringWriter();
1013         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) {
1014             printer.printRecord("a\tb", "c");
1015             assertEquals("a\tb,c" + RECORD_SEPARATOR, sw.toString());
1016             assertEquals(1, printer.getRecordCount());
1017         }
1018     }
1019 
1020     @Test
1021     public void testMongoDbTsvBasic() throws IOException {
1022         final StringWriter sw = new StringWriter();
1023         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) {
1024             printer.printRecord("a", "b");
1025             assertEquals("a\tb" + RECORD_SEPARATOR, sw.toString());
1026             assertEquals(1, printer.getRecordCount());
1027         }
1028     }
1029 
1030     @Test
1031     public void testMongoDbTsvCommaInValue() throws IOException {
1032         final StringWriter sw = new StringWriter();
1033         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) {
1034             printer.printRecord("a,b", "c");
1035             assertEquals("a,b\tc" + RECORD_SEPARATOR, sw.toString());
1036             assertEquals(1, printer.getRecordCount());
1037         }
1038     }
1039 
1040     @Test
1041     public void testMongoDbTsvTabInValue() throws IOException {
1042         final StringWriter sw = new StringWriter();
1043         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) {
1044             printer.printRecord("a\tb", "c");
1045             assertEquals("\"a\tb\"\tc" + RECORD_SEPARATOR, sw.toString());
1046         }
1047     }
1048 
1049     @Test
1050     public void testMultiLineComment() throws IOException {
1051         final StringWriter sw = new StringWriter();
1052         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) {
1053             printer.printComment("This is a comment\non multiple lines");
1054             assertEquals("# This is a comment" + RECORD_SEPARATOR + "# on multiple lines" + RECORD_SEPARATOR, sw.toString());
1055             assertEquals(0, printer.getRecordCount());
1056         }
1057     }
1058 
1059     @Test
1060     public void testMySqlNullOutput() throws IOException {
1061         Object[] s = new String[] { "NULL", null };
1062         CSVFormat format = CSVFormat.MYSQL.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.NON_NUMERIC);
1063         StringWriter writer = new StringWriter();
1064         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1065             printer.printRecord(s);
1066         }
1067         String expected = "\"NULL\"\tNULL\n";
1068         assertEquals(expected, writer.toString());
1069         String[] record0 = toFirstRecordValues(expected, format);
1070         assertArrayEquals(s, record0);
1071 
1072         s = new String[] { "\\N", null };
1073         format = CSVFormat.MYSQL.withNullString("\\N");
1074         writer = new StringWriter();
1075         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1076             printer.printRecord(s);
1077         }
1078         expected = "\\\\N\t\\N\n";
1079         assertEquals(expected, writer.toString());
1080         record0 = toFirstRecordValues(expected, format);
1081         assertArrayEquals(expectNulls(s, format), record0);
1082 
1083         s = new String[] { "\\N", "A" };
1084         format = CSVFormat.MYSQL.withNullString("\\N");
1085         writer = new StringWriter();
1086         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1087             printer.printRecord(s);
1088         }
1089         expected = "\\\\N\tA\n";
1090         assertEquals(expected, writer.toString());
1091         record0 = toFirstRecordValues(expected, format);
1092         assertArrayEquals(expectNulls(s, format), record0);
1093 
1094         s = new String[] { "\n", "A" };
1095         format = CSVFormat.MYSQL.withNullString("\\N");
1096         writer = new StringWriter();
1097         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1098             printer.printRecord(s);
1099         }
1100         expected = "\\n\tA\n";
1101         assertEquals(expected, writer.toString());
1102         record0 = toFirstRecordValues(expected, format);
1103         assertArrayEquals(expectNulls(s, format), record0);
1104 
1105         s = new String[] { "", null };
1106         format = CSVFormat.MYSQL.withNullString("NULL");
1107         writer = new StringWriter();
1108         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1109             printer.printRecord(s);
1110         }
1111         expected = "\tNULL\n";
1112         assertEquals(expected, writer.toString());
1113         record0 = toFirstRecordValues(expected, format);
1114         assertArrayEquals(expectNulls(s, format), record0);
1115 
1116         s = new String[] { "", null };
1117         format = CSVFormat.MYSQL;
1118         writer = new StringWriter();
1119         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1120             printer.printRecord(s);
1121         }
1122         expected = "\t\\N\n";
1123         assertEquals(expected, writer.toString());
1124         record0 = toFirstRecordValues(expected, format);
1125         assertArrayEquals(expectNulls(s, format), record0);
1126 
1127         s = new String[] { "\\N", "", "\u000e,\\\r" };
1128         format = CSVFormat.MYSQL;
1129         writer = new StringWriter();
1130         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1131             printer.printRecord(s);
1132         }
1133         expected = "\\\\N\t\t\u000e,\\\\\\r\n";
1134         assertEquals(expected, writer.toString());
1135         record0 = toFirstRecordValues(expected, format);
1136         assertArrayEquals(expectNulls(s, format), record0);
1137 
1138         s = new String[] { "NULL", "\\\r" };
1139         format = CSVFormat.MYSQL;
1140         writer = new StringWriter();
1141         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1142             printer.printRecord(s);
1143         }
1144         expected = "NULL\t\\\\\\r\n";
1145         assertEquals(expected, writer.toString());
1146         record0 = toFirstRecordValues(expected, format);
1147         assertArrayEquals(expectNulls(s, format), record0);
1148 
1149         s = new String[] { "\\\r" };
1150         format = CSVFormat.MYSQL;
1151         writer = new StringWriter();
1152         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1153             printer.printRecord(s);
1154         }
1155         expected = "\\\\\\r\n";
1156         assertEquals(expected, writer.toString());
1157         record0 = toFirstRecordValues(expected, format);
1158         assertArrayEquals(expectNulls(s, format), record0);
1159     }
1160 
1161     @Test
1162     public void testMySqlNullStringDefault() {
1163         assertEquals("\\N", CSVFormat.MYSQL.getNullString());
1164     }
1165 
1166     @Test
1167     public void testNewCsvPrinterAppendableNullFormat() {
1168         assertThrows(NullPointerException.class, () -> new CSVPrinter(new StringWriter(), null));
1169     }
1170 
1171     @Test
1172     public void testNewCsvPrinterNullAppendableFormat() {
1173         assertThrows(NullPointerException.class, () -> new CSVPrinter(null, CSVFormat.DEFAULT));
1174     }
1175 
1176     @Test
1177     public void testNotFlushable() throws IOException {
1178         final Appendable out = new StringBuilder();
1179         try (CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT)) {
1180             printer.printRecord("a", "b", "c");
1181             assertEquals("a,b,c" + RECORD_SEPARATOR, out.toString());
1182             printer.flush();
1183         }
1184     }
1185 
1186     @Test
1187     public void testParseCustomNullValues() throws IOException {
1188         final StringWriter sw = new StringWriter();
1189         final CSVFormat format = CSVFormat.DEFAULT.withNullString("NULL");
1190         try (CSVPrinter printer = new CSVPrinter(sw, format)) {
1191             printer.printRecord("a", null, "b");
1192         }
1193         final String csvString = sw.toString();
1194         assertEquals("a,NULL,b" + RECORD_SEPARATOR, csvString);
1195         try (CSVParser iterable = format.parse(new StringReader(csvString))) {
1196             final Iterator<CSVRecord> iterator = iterable.iterator();
1197             final CSVRecord record = iterator.next();
1198             assertEquals("a", record.get(0));
1199             assertNull(record.get(1));
1200             assertEquals("b", record.get(2));
1201             assertFalse(iterator.hasNext());
1202         }
1203     }
1204 
1205     @Test
1206     public void testPlainEscaped() throws IOException {
1207         final StringWriter sw = new StringWriter();
1208         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withEscape('!'))) {
1209             printer.print("abc");
1210             printer.print("xyz");
1211             assertEquals("abc,xyz", sw.toString());
1212         }
1213     }
1214 
1215     @Test
1216     public void testPlainPlain() throws IOException {
1217         final StringWriter sw = new StringWriter();
1218         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) {
1219             printer.print("abc");
1220             printer.print("xyz");
1221             assertEquals("abc,xyz", sw.toString());
1222         }
1223     }
1224 
1225     @Test
1226     public void testPlainQuoted() throws IOException {
1227         final StringWriter sw = new StringWriter();
1228         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) {
1229             printer.print("abc");
1230             assertEquals("abc", sw.toString());
1231         }
1232     }
1233 
1234     @Test
1235     @Disabled
1236     public void testPostgreSqlCsvNullOutput() throws IOException {
1237         Object[] s = new String[] { "NULL", null };
1238         CSVFormat format = CSVFormat.POSTGRESQL_CSV.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.ALL_NON_NULL);
1239         StringWriter writer = new StringWriter();
1240         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1241             printer.printRecord(s);
1242         }
1243         String expected = "\"NULL\",NULL\n";
1244         assertEquals(expected, writer.toString());
1245         String[] record0 = toFirstRecordValues(expected, format);
1246         assertArrayEquals(new Object[2], record0);
1247 
1248         s = new String[] { "\\N", null };
1249         format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N");
1250         writer = new StringWriter();
1251         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1252             printer.printRecord(s);
1253         }
1254         expected = "\\\\N\t\\N\n";
1255         assertEquals(expected, writer.toString());
1256         record0 = toFirstRecordValues(expected, format);
1257         assertArrayEquals(expectNulls(s, format), record0);
1258 
1259         s = new String[] { "\\N", "A" };
1260         format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N");
1261         writer = new StringWriter();
1262         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1263             printer.printRecord(s);
1264         }
1265         expected = "\\\\N\tA\n";
1266         assertEquals(expected, writer.toString());
1267         record0 = toFirstRecordValues(expected, format);
1268         assertArrayEquals(expectNulls(s, format), record0);
1269 
1270         s = new String[] { "\n", "A" };
1271         format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N");
1272         writer = new StringWriter();
1273         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1274             printer.printRecord(s);
1275         }
1276         expected = "\\n\tA\n";
1277         assertEquals(expected, writer.toString());
1278         record0 = toFirstRecordValues(expected, format);
1279         assertArrayEquals(expectNulls(s, format), record0);
1280 
1281         s = new String[] { "", null };
1282         format = CSVFormat.POSTGRESQL_CSV.withNullString("NULL");
1283         writer = new StringWriter();
1284         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1285             printer.printRecord(s);
1286         }
1287         expected = "\tNULL\n";
1288         assertEquals(expected, writer.toString());
1289         record0 = toFirstRecordValues(expected, format);
1290         assertArrayEquals(expectNulls(s, format), record0);
1291 
1292         s = new String[] { "", null };
1293         format = CSVFormat.POSTGRESQL_CSV;
1294         writer = new StringWriter();
1295         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1296             printer.printRecord(s);
1297         }
1298         expected = "\t\\N\n";
1299         assertEquals(expected, writer.toString());
1300         record0 = toFirstRecordValues(expected, format);
1301         assertArrayEquals(expectNulls(s, format), record0);
1302 
1303         s = new String[] { "\\N", "", "\u000e,\\\r" };
1304         format = CSVFormat.POSTGRESQL_CSV;
1305         writer = new StringWriter();
1306         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1307             printer.printRecord(s);
1308         }
1309         expected = "\\\\N\t\t\u000e,\\\\\\r\n";
1310         assertEquals(expected, writer.toString());
1311         record0 = toFirstRecordValues(expected, format);
1312         assertArrayEquals(expectNulls(s, format), record0);
1313 
1314         s = new String[] { "NULL", "\\\r" };
1315         format = CSVFormat.POSTGRESQL_CSV;
1316         writer = new StringWriter();
1317         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1318             printer.printRecord(s);
1319         }
1320         expected = "NULL\t\\\\\\r\n";
1321         assertEquals(expected, writer.toString());
1322         record0 = toFirstRecordValues(expected, format);
1323         assertArrayEquals(expectNulls(s, format), record0);
1324 
1325         s = new String[] { "\\\r" };
1326         format = CSVFormat.POSTGRESQL_CSV;
1327         writer = new StringWriter();
1328         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1329             printer.printRecord(s);
1330         }
1331         expected = "\\\\\\r\n";
1332         assertEquals(expected, writer.toString());
1333         record0 = toFirstRecordValues(expected, format);
1334         assertArrayEquals(expectNulls(s, format), record0);
1335     }
1336 
1337     @Test
1338     @Disabled
1339     public void testPostgreSqlCsvTextOutput() throws IOException {
1340         Object[] s = new String[] { "NULL", null };
1341         CSVFormat format = CSVFormat.POSTGRESQL_TEXT.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.ALL_NON_NULL);
1342         StringWriter writer = new StringWriter();
1343         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1344             printer.printRecord(s);
1345         }
1346         String expected = "\"NULL\"\tNULL\n";
1347         assertEquals(expected, writer.toString());
1348         String[] record0 = toFirstRecordValues(expected, format);
1349         assertArrayEquals(new Object[2], record0);
1350 
1351         s = new String[] { "\\N", null };
1352         format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N");
1353         writer = new StringWriter();
1354         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1355             printer.printRecord(s);
1356         }
1357         expected = "\\\\N\t\\N\n";
1358         assertEquals(expected, writer.toString());
1359         record0 = toFirstRecordValues(expected, format);
1360         assertArrayEquals(expectNulls(s, format), record0);
1361 
1362         s = new String[] { "\\N", "A" };
1363         format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N");
1364         writer = new StringWriter();
1365         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1366             printer.printRecord(s);
1367         }
1368         expected = "\\\\N\tA\n";
1369         assertEquals(expected, writer.toString());
1370         record0 = toFirstRecordValues(expected, format);
1371         assertArrayEquals(expectNulls(s, format), record0);
1372 
1373         s = new String[] { "\n", "A" };
1374         format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N");
1375         writer = new StringWriter();
1376         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1377             printer.printRecord(s);
1378         }
1379         expected = "\\n\tA\n";
1380         assertEquals(expected, writer.toString());
1381         record0 = toFirstRecordValues(expected, format);
1382         assertArrayEquals(expectNulls(s, format), record0);
1383 
1384         s = new String[] { "", null };
1385         format = CSVFormat.POSTGRESQL_TEXT.withNullString("NULL");
1386         writer = new StringWriter();
1387         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1388             printer.printRecord(s);
1389         }
1390         expected = "\tNULL\n";
1391         assertEquals(expected, writer.toString());
1392         record0 = toFirstRecordValues(expected, format);
1393         assertArrayEquals(expectNulls(s, format), record0);
1394 
1395         s = new String[] { "", null };
1396         format = CSVFormat.POSTGRESQL_TEXT;
1397         writer = new StringWriter();
1398         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1399             printer.printRecord(s);
1400         }
1401         expected = "\t\\N\n";
1402         assertEquals(expected, writer.toString());
1403         record0 = toFirstRecordValues(expected, format);
1404         assertArrayEquals(expectNulls(s, format), record0);
1405 
1406         s = new String[] { "\\N", "", "\u000e,\\\r" };
1407         format = CSVFormat.POSTGRESQL_TEXT;
1408         writer = new StringWriter();
1409         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1410             printer.printRecord(s);
1411         }
1412         expected = "\\\\N\t\t\u000e,\\\\\\r\n";
1413         assertEquals(expected, writer.toString());
1414         record0 = toFirstRecordValues(expected, format);
1415         assertArrayEquals(expectNulls(s, format), record0);
1416 
1417         s = new String[] { "NULL", "\\\r" };
1418         format = CSVFormat.POSTGRESQL_TEXT;
1419         writer = new StringWriter();
1420         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1421             printer.printRecord(s);
1422         }
1423         expected = "NULL\t\\\\\\r\n";
1424         assertEquals(expected, writer.toString());
1425         record0 = toFirstRecordValues(expected, format);
1426         assertArrayEquals(expectNulls(s, format), record0);
1427 
1428         s = new String[] { "\\\r" };
1429         format = CSVFormat.POSTGRESQL_TEXT;
1430         writer = new StringWriter();
1431         try (CSVPrinter printer = new CSVPrinter(writer, format)) {
1432             printer.printRecord(s);
1433         }
1434         expected = "\\\\\\r\n";
1435         assertEquals(expected, writer.toString());
1436         record0 = toFirstRecordValues(expected, format);
1437         assertArrayEquals(expectNulls(s, format), record0);
1438     }
1439 
1440     @Test
1441     public void testPostgreSqlNullStringDefaultCsv() {
1442         assertEquals("", CSVFormat.POSTGRESQL_CSV.getNullString());
1443     }
1444 
1445     @Test
1446     public void testPostgreSqlNullStringDefaultText() {
1447         assertEquals("\\N", CSVFormat.POSTGRESQL_TEXT.getNullString());
1448     }
1449 
1450     @Test
1451     public void testPrint() throws IOException {
1452         final StringWriter sw = new StringWriter();
1453         try (CSVPrinter printer = CSVFormat.DEFAULT.print(sw)) {
1454             assertInitialState(printer);
1455             printer.printRecord("a", "b\\c");
1456             assertEquals("a,b\\c" + RECORD_SEPARATOR, sw.toString());
1457         }
1458     }
1459 
1460     @Test
1461     public void testPrintCSVParser() throws IOException {
1462         // @formatter:off
1463         final String code = "a1,b1\n" + // 1)
1464                 "a2,b2\n" + // 2)
1465                 "a3,b3\n" + // 3)
1466                 "a4,b4\n";  // 4)
1467         // @formatter:on
1468         final String[][] res = { { "a1", "b1" }, { "a2", "b2" }, { "a3", "b3" }, { "a4", "b4" } };
1469         final CSVFormat format = CSVFormat.DEFAULT;
1470         final StringWriter sw = new StringWriter();
1471         try (CSVPrinter printer = format.print(sw);
1472                 CSVParser parser = CSVParser.parse(code, format)) {
1473             assertInitialState(printer);
1474             printer.printRecords(parser);
1475         }
1476         try (CSVParser parser = CSVParser.parse(sw.toString(), format)) {
1477             final List<CSVRecord> records = parser.getRecords();
1478             assertFalse(records.isEmpty());
1479             Utils.compare("Fail", res, records, -1);
1480         }
1481     }
1482 
1483     @Test
1484     public void testPrintCSVRecord() throws IOException {
1485         // @formatter:off
1486         final String code = "a1,b1\n" + // 1)
1487                 "a2,b2\n" +  // 2)
1488                 "a3,b3\n" +  // 3)
1489                 "a4,b4\n";   // 4)
1490         // @formatter:on
1491         final String[][] res = { { "a1", "b1" }, { "a2", "b2" }, { "a3", "b3" }, { "a4", "b4" } };
1492         final CSVFormat format = CSVFormat.DEFAULT;
1493         final StringWriter sw = new StringWriter();
1494         int row = 0;
1495         try (CSVPrinter printer = format.print(sw);
1496                 CSVParser parser = CSVParser.parse(code, format)) {
1497             assertInitialState(printer);
1498             for (final CSVRecord record : parser) {
1499                 printer.printRecord(record);
1500                 assertEquals(++row, printer.getRecordCount());
1501             }
1502             assertEquals(row, printer.getRecordCount());
1503         }
1504         try (CSVParser parser = CSVParser.parse(sw.toString(), format)) {
1505             final List<CSVRecord> records = parser.getRecords();
1506             assertFalse(records.isEmpty());
1507             Utils.compare("Fail", res, records, -1);
1508         }
1509     }
1510 
1511     @ParameterizedTest
1512     @ValueSource(longs = { -1, 0, 3, 4, Long.MAX_VALUE })
1513     public void testPrintCSVRecords(final long maxRows) throws IOException {
1514         // @formatter:off
1515         final String code = "a1,b1\n" + // 1)
1516                 "a2,b2\n" + // 2)
1517                 "a3,b3\n" + // 3)
1518                 "a4,b4\n";  // 4)
1519         // @formatter:on
1520         final String[][] expected = { { "a1", "b1" }, { "a2", "b2" }, { "a3", "b3" }, { "a4", "b4" } };
1521         final CSVFormat format = CSVFormat.DEFAULT.builder().setMaxRows(maxRows).get();
1522         final StringWriter sw = new StringWriter();
1523         try (CSVPrinter printer = format.print(sw);
1524                 CSVParser parser = CSVParser.parse(code, format)) {
1525             assertInitialState(printer);
1526             printer.printRecords(parser.getRecords());
1527         }
1528         try (CSVParser parser = CSVParser.parse(sw.toString(), format)) {
1529             final List<CSVRecord> records = parser.getRecords();
1530             assertFalse(records.isEmpty());
1531             Utils.compare("Fail", expected, records, maxRows);
1532         }
1533     }
1534 
1535     @Test
1536     public void testPrintCustomNullValues() throws IOException {
1537         final StringWriter sw = new StringWriter();
1538         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withNullString("NULL"))) {
1539             assertInitialState(printer);
1540             printer.printRecord("a", null, "b");
1541             assertEquals("a,NULL,b" + RECORD_SEPARATOR, sw.toString());
1542         }
1543     }
1544 
1545     @Test
1546     public void testPrinter1() throws IOException {
1547         final StringWriter sw = new StringWriter();
1548         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1549             assertInitialState(printer);
1550             printer.printRecord("a", "b");
1551             assertEquals(1, printer.getRecordCount());
1552             assertEquals("a,b" + RECORD_SEPARATOR, sw.toString());
1553         }
1554     }
1555 
1556     @Test
1557     public void testPrinter2() throws IOException {
1558         final StringWriter sw = new StringWriter();
1559         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1560             assertInitialState(printer);
1561             printer.printRecord("a,b", "b");
1562             assertEquals("\"a,b\",b" + RECORD_SEPARATOR, sw.toString());
1563         }
1564     }
1565 
1566     @Test
1567     public void testPrinter3() throws IOException {
1568         final StringWriter sw = new StringWriter();
1569         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1570             assertInitialState(printer);
1571             printer.printRecord("a, b", "b ");
1572             assertEquals("\"a, b\",\"b \"" + RECORD_SEPARATOR, sw.toString());
1573         }
1574     }
1575 
1576     @Test
1577     public void testPrinter4() throws IOException {
1578         final StringWriter sw = new StringWriter();
1579         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1580             assertInitialState(printer);
1581             printer.printRecord("a", "b\"c");
1582             assertEquals("a,\"b\"\"c\"" + RECORD_SEPARATOR, sw.toString());
1583         }
1584     }
1585 
1586     @Test
1587     public void testPrinter5() throws IOException {
1588         final StringWriter sw = new StringWriter();
1589         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1590             assertInitialState(printer);
1591             printer.printRecord("a", "b\nc");
1592             assertEquals("a,\"b\nc\"" + RECORD_SEPARATOR, sw.toString());
1593         }
1594     }
1595 
1596     @Test
1597     public void testPrinter6() throws IOException {
1598         final StringWriter sw = new StringWriter();
1599         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1600             assertInitialState(printer);
1601             printer.printRecord("a", "b\r\nc");
1602             assertEquals("a,\"b\r\nc\"" + RECORD_SEPARATOR, sw.toString());
1603         }
1604     }
1605 
1606     @Test
1607     public void testPrinter7() throws IOException {
1608         final StringWriter sw = new StringWriter();
1609         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1610             assertInitialState(printer);
1611             printer.printRecord("a", "b\\c");
1612             assertEquals("a,b\\c" + RECORD_SEPARATOR, sw.toString());
1613         }
1614     }
1615 
1616     @Test
1617     public void testPrintNullValues() throws IOException {
1618         final StringWriter sw = new StringWriter();
1619         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
1620             assertInitialState(printer);
1621             printer.printRecord("a", null, "b");
1622             assertEquals("a,,b" + RECORD_SEPARATOR, sw.toString());
1623         }
1624     }
1625 
1626     @Test
1627     public void testPrintOnePositiveInteger() throws IOException {
1628         final StringWriter sw = new StringWriter();
1629         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.MINIMAL))) {
1630             assertInitialState(printer);
1631             printer.print(Integer.MAX_VALUE);
1632             assertEquals(String.valueOf(Integer.MAX_VALUE), sw.toString());
1633         }
1634     }
1635 
1636     /**
1637      * Test to target the use of {@link IOUtils#copy(java.io.Reader, Appendable)} which directly buffers the value from the Reader to the Appendable.
1638      *
1639      * <p>
1640      * Requires the format to have no quote or escape character, value to be a {@link Reader Reader} and the output <em>MUST NOT</em> be a {@link Writer Writer}
1641      * but some other Appendable.
1642      * </p>
1643      *
1644      * @throws IOException Not expected to happen
1645      */
1646     @Test
1647     public void testPrintReaderWithoutQuoteToAppendable() throws IOException {
1648         final StringBuilder sb = new StringBuilder();
1649         final String content = "testValue";
1650         try (CSVPrinter printer = new CSVPrinter(sb, CSVFormat.DEFAULT.withQuote(null))) {
1651             assertInitialState(printer);
1652             final StringReader value = new StringReader(content);
1653             printer.print(value);
1654         }
1655         assertEquals(content, sb.toString());
1656     }
1657 
1658     /**
1659      * Test to target the use of {@link IOUtils#copyLarge(java.io.Reader, Writer)} which directly buffers the value from the Reader to the Writer.
1660      *
1661      * <p>
1662      * Requires the format to have no quote or escape character, value to be a {@link Reader Reader} and the output <em>MUST</em> be a {@link Writer Writer}.
1663      * </p>
1664      *
1665      * @throws IOException Not expected to happen
1666      */
1667     @Test
1668     public void testPrintReaderWithoutQuoteToWriter() throws IOException {
1669         final StringWriter sw = new StringWriter();
1670         final String content = "testValue";
1671         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) {
1672             final StringReader value = new StringReader(content);
1673             printer.print(value);
1674         }
1675         assertEquals(content, sw.toString());
1676     }
1677 
1678     @Test
1679     public void testPrintRecordStream() throws IOException {
1680         // @formatter:off
1681         final String code = "a1,b1\n" + // 1)
1682                 "a2,b2\n" + // 2)
1683                 "a3,b3\n" + // 3)
1684                 "a4,b4\n";  // 4)
1685         // @formatter:on
1686         final String[][] res = { { "a1", "b1" }, { "a2", "b2" }, { "a3", "b3" }, { "a4", "b4" } };
1687         final CSVFormat format = CSVFormat.DEFAULT;
1688         final StringWriter sw = new StringWriter();
1689         try (CSVPrinter printer = format.print(sw);
1690                 CSVParser parser = CSVParser.parse(code, format)) {
1691             long count = 0;
1692             for (final CSVRecord record : parser) {
1693                 printer.printRecord(record.stream());
1694                 assertEquals(++count, printer.getRecordCount());
1695             }
1696         }
1697         try (CSVParser parser = CSVParser.parse(sw.toString(), format)) {
1698             final List<CSVRecord> records = parser.getRecords();
1699             assertFalse(records.isEmpty());
1700             Utils.compare("Fail", res, records, -1);
1701         }
1702     }
1703 
1704     @Test
1705     public void testPrintRecordsWithCSVRecord() throws IOException {
1706         final String[] values = { "A", "B", "C" };
1707         final String rowData = StringUtils.join(values, ',');
1708         final CharArrayWriter charArrayWriter = new CharArrayWriter(0);
1709         try (CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(rowData));
1710                 CSVPrinter printer = CSVFormat.INFORMIX_UNLOAD.print(charArrayWriter)) {
1711             long count = 0;
1712             for (final CSVRecord record : parser) {
1713                 printer.printRecord(record);
1714                 assertEquals(++count, printer.getRecordCount());
1715             }
1716         }
1717         assertEquals(6, charArrayWriter.size());
1718         assertEquals("A|B|C" + CSVFormat.INFORMIX_UNLOAD.getRecordSeparator(), charArrayWriter.toString());
1719     }
1720 
1721     @Test
1722     public void testPrintRecordsWithEmptyVector() throws IOException {
1723         final PrintStream out = System.out;
1724         try {
1725             System.setOut(new PrintStream(NullOutputStream.INSTANCE));
1726             try (CSVPrinter printer = CSVFormat.POSTGRESQL_TEXT.printer()) {
1727                 final Vector<CSVFormatTest.EmptyEnum> vector = new Vector<>();
1728                 final int expectedCapacity = 23;
1729                 vector.setSize(expectedCapacity);
1730                 printer.printRecords(vector);
1731                 assertEquals(expectedCapacity, vector.capacity());
1732                 assertEquals(expectedCapacity, printer.getRecordCount());
1733             }
1734         } finally {
1735             System.setOut(out);
1736         }
1737     }
1738 
1739     @Test
1740     public void testPrintRecordsWithObjectArray() throws IOException {
1741         final CharArrayWriter charArrayWriter = new CharArrayWriter(0);
1742         final Object[] objectArray = new Object[6];
1743         try (CSVPrinter printer = CSVFormat.INFORMIX_UNLOAD.print(charArrayWriter)) {
1744             final HashSet<BatchUpdateException> hashSet = new HashSet<>();
1745             objectArray[3] = hashSet;
1746             printer.printRecords(objectArray);
1747             assertEquals(objectArray.length, printer.getRecordCount());
1748         }
1749         assertEquals(6, charArrayWriter.size());
1750         assertEquals("\n\n\n\n\n\n", charArrayWriter.toString());
1751     }
1752 
1753     @Test
1754     public void testPrintRecordsWithResultSetOneRow() throws IOException, SQLException {
1755         try (CSVPrinter printer = CSVFormat.MYSQL.printer()) {
1756             try (ResultSet resultSet = new SimpleResultSet()) {
1757                 assertInitialState(printer);
1758                 printer.printRecords(resultSet);
1759                 assertInitialState(printer);
1760                 assertEquals(0, resultSet.getRow());
1761             }
1762         }
1763     }
1764 
1765     @Test
1766     public void testPrintToFileWithCharsetUtf16Be() throws IOException {
1767         final File file = createTempFile();
1768         try (CSVPrinter printer = CSVFormat.DEFAULT.print(file, StandardCharsets.UTF_16BE)) {
1769             printer.printRecord("a", "b\\c");
1770         }
1771         assertEquals("a,b\\c" + RECORD_SEPARATOR, FileUtils.readFileToString(file, StandardCharsets.UTF_16BE));
1772     }
1773 
1774     @Test
1775     public void testPrintToFileWithDefaultCharset() throws IOException {
1776         final File file = createTempFile();
1777         try (CSVPrinter printer = CSVFormat.DEFAULT.print(file, Charset.defaultCharset())) {
1778             printer.printRecord("a", "b\\c");
1779         }
1780         assertEquals("a,b\\c" + RECORD_SEPARATOR, FileUtils.readFileToString(file, Charset.defaultCharset()));
1781     }
1782 
1783     @Test
1784     public void testPrintToPathWithDefaultCharset() throws IOException {
1785         final Path file = createTempPath();
1786         try (CSVPrinter printer = CSVFormat.DEFAULT.print(file, Charset.defaultCharset())) {
1787             printer.printRecord("a", "b\\c");
1788         }
1789         assertEquals("a,b\\c" + RECORD_SEPARATOR, new String(Files.readAllBytes(file), Charset.defaultCharset()));
1790     }
1791 
1792     @Test
1793     public void testQuoteAll() throws IOException {
1794         final StringWriter sw = new StringWriter();
1795         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.ALL))) {
1796             printer.printRecord("a", "b\nc", "d");
1797             assertEquals("\"a\",\"b\nc\",\"d\"" + RECORD_SEPARATOR, sw.toString());
1798         }
1799     }
1800 
1801     @Test
1802     public void testQuoteCommaFirstChar() throws IOException {
1803         final StringWriter sw = new StringWriter();
1804         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.RFC4180)) {
1805             printer.printRecord(",");
1806             assertEquals("\",\"" + RECORD_SEPARATOR, sw.toString());
1807         }
1808     }
1809 
1810     @Test
1811     public void testQuoteNonNumeric() throws IOException {
1812         final StringWriter sw = new StringWriter();
1813         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.NON_NUMERIC))) {
1814             printer.printRecord("a", "b\nc", Integer.valueOf(1));
1815             assertEquals("\"a\",\"b\nc\",1" + RECORD_SEPARATOR, sw.toString());
1816         }
1817     }
1818 
1819     @Test
1820     public void testRandomDefault() throws Exception {
1821         doRandom(CSVFormat.DEFAULT, ITERATIONS_FOR_RANDOM_TEST);
1822     }
1823 
1824     @Test
1825     public void testRandomExcel() throws Exception {
1826         doRandom(CSVFormat.EXCEL, ITERATIONS_FOR_RANDOM_TEST);
1827     }
1828 
1829     @Test
1830     @Disabled
1831     public void testRandomMongoDbCsv() throws Exception {
1832         doRandom(CSVFormat.MONGODB_CSV, ITERATIONS_FOR_RANDOM_TEST);
1833     }
1834 
1835     @Test
1836     public void testRandomMySql() throws Exception {
1837         doRandom(CSVFormat.MYSQL, ITERATIONS_FOR_RANDOM_TEST);
1838     }
1839 
1840     @Test
1841     @Disabled
1842     public void testRandomOracle() throws Exception {
1843         doRandom(CSVFormat.ORACLE, ITERATIONS_FOR_RANDOM_TEST);
1844     }
1845 
1846     @Test
1847     @Disabled
1848     public void testRandomPostgreSqlCsv() throws Exception {
1849         doRandom(CSVFormat.POSTGRESQL_CSV, ITERATIONS_FOR_RANDOM_TEST);
1850     }
1851 
1852     @Test
1853     public void testRandomPostgreSqlText() throws Exception {
1854         doRandom(CSVFormat.POSTGRESQL_TEXT, ITERATIONS_FOR_RANDOM_TEST);
1855     }
1856 
1857     @Test
1858     public void testRandomRfc4180() throws Exception {
1859         doRandom(CSVFormat.RFC4180, ITERATIONS_FOR_RANDOM_TEST);
1860     }
1861 
1862     @Test
1863     public void testRandomTdf() throws Exception {
1864         doRandom(CSVFormat.TDF, ITERATIONS_FOR_RANDOM_TEST);
1865     }
1866 
1867     @Test
1868     public void testSingleLineComment() throws IOException {
1869         final StringWriter sw = new StringWriter();
1870         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) {
1871             printer.printComment("This is a comment");
1872             assertEquals("# This is a comment" + RECORD_SEPARATOR, sw.toString());
1873             assertEquals(0, printer.getRecordCount());
1874         }
1875     }
1876 
1877     @Test
1878     public void testSingleQuoteQuoted() throws IOException {
1879         final StringWriter sw = new StringWriter();
1880         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) {
1881             printer.print("a'b'c");
1882             printer.print("xyz");
1883             assertEquals("'a''b''c',xyz", sw.toString());
1884         }
1885     }
1886 
1887     @Test
1888     public void testSkipHeaderRecordFalse() throws IOException {
1889         // functionally identical to testHeader, used to test CSV-153
1890         final StringWriter sw = new StringWriter();
1891         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3").withSkipHeaderRecord(false))) {
1892             printer.printRecord("a", "b", "c");
1893             printer.printRecord("x", "y", "z");
1894             assertEquals("C1,C2,C3\r\na,b,c\r\nx,y,z\r\n", sw.toString());
1895         }
1896     }
1897 
1898     @Test
1899     public void testSkipHeaderRecordTrue() throws IOException {
1900         // functionally identical to testHeaderNotSet, used to test CSV-153
1901         final StringWriter sw = new StringWriter();
1902         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3").withSkipHeaderRecord(true))) {
1903             printer.printRecord("a", "b", "c");
1904             printer.printRecord("x", "y", "z");
1905             assertEquals("a,b,c\r\nx,y,z\r\n", sw.toString());
1906         }
1907     }
1908 
1909     @Test
1910     public void testTrailingDelimiterOnTwoColumns() throws IOException {
1911         final StringWriter sw = new StringWriter();
1912         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrailingDelimiter())) {
1913             printer.printRecord("A", "B");
1914             assertEquals("A,B,\r\n", sw.toString());
1915         }
1916     }
1917 
1918     @Test
1919     public void testTrimOffOneColumn() throws IOException {
1920         final StringWriter sw = new StringWriter();
1921         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim(false))) {
1922             printer.print(" A ");
1923             assertEquals("\" A \"", sw.toString());
1924         }
1925     }
1926 
1927     @Test
1928     public void testTrimOnOneColumn() throws IOException {
1929         final StringWriter sw = new StringWriter();
1930         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim())) {
1931             printer.print(" A ");
1932             assertEquals("A", sw.toString());
1933         }
1934     }
1935 
1936     @Test
1937     public void testTrimOnTwoColumns() throws IOException {
1938         final StringWriter sw = new StringWriter();
1939         try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim())) {
1940             printer.print(" A ");
1941             printer.print(" B ");
1942             assertEquals("A,B", sw.toString());
1943         }
1944     }
1945 
1946     private String[] toFirstRecordValues(final String expected, final CSVFormat format) throws IOException {
1947         try (CSVParser parser = CSVParser.parse(expected, format)) {
1948             return parser.getRecords().get(0).values();
1949         }
1950     }
1951 
1952     private void tryFormat(final List<String> list, final Character quote, final Character escape, final String expected) throws IOException {
1953         final CSVFormat format = CSVFormat.DEFAULT.withQuote(quote).withEscape(escape).withRecordSeparator(null);
1954         final Appendable out = new StringBuilder();
1955         try (CSVPrinter printer = new CSVPrinter(out, format)) {
1956             printer.printRecord(list);
1957         }
1958         assertEquals(expected, out.toString());
1959     }
1960 
1961 }