diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6ddee3ec..8e96d1e0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -50,6 +50,7 @@ Make CSVRecord#values() public. Add DuplicateHeaderMode for flexibility with header strictness. #114. Support for parallelism in CSVPrinter. + Add CSVPrinter.printRecord[s](Stream). Add github/codeql-action. Bump actions/cache from 2.1.6 to 3.0.6 #196, #233, #243. diff --git a/src/main/java/org/apache/commons/csv/CSVPrinter.java b/src/main/java/org/apache/commons/csv/CSVPrinter.java index 9dcb95cd..6cefff9e 100644 --- a/src/main/java/org/apache/commons/csv/CSVPrinter.java +++ b/src/main/java/org/apache/commons/csv/CSVPrinter.java @@ -1,412 +1,507 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.csv; - -import static org.apache.commons.csv.Constants.CR; -import static org.apache.commons.csv.Constants.LF; -import static org.apache.commons.csv.Constants.SP; - -import java.io.Closeable; -import java.io.Flushable; -import java.io.IOException; -import java.sql.Clob; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Objects; - -/** - * Prints values in a {@link CSVFormat CSV format}. - * - *

Values can be appended to the output by calling the {@link #print(Object)} method. - * Values are printed according to {@link String#valueOf(Object)}. - * To complete a record the {@link #println()} method has to be called. - * Comments can be appended by calling {@link #printComment(String)}. - * However a comment will only be written to the output if the {@link CSVFormat} supports comments. - *

- * - *

The printer also supports appending a complete record at once by calling {@link #printRecord(Object...)} - * or {@link #printRecord(Iterable)}. - * Furthermore {@link #printRecords(Object...)}, {@link #printRecords(Iterable)} and {@link #printRecords(ResultSet)} - * methods can be used to print several records at once. - *

- * - *

Example:

- * - *
- * try (CSVPrinter printer = new CSVPrinter(new FileWriter("csv.txt"), CSVFormat.EXCEL)) {
- *     printer.printRecord("id", "userName", "firstName", "lastName", "birthday");
- *     printer.printRecord(1, "john73", "John", "Doe", LocalDate.of(1973, 9, 15));
- *     printer.println();
- *     printer.printRecord(2, "mary", "Mary", "Meyer", LocalDate.of(1985, 3, 29));
- * } catch (IOException ex) {
- *     ex.printStackTrace();
- * }
- * 
- * - *

This code will write the following to csv.txt:

- *
- * id,userName,firstName,lastName,birthday
- * 1,john73,John,Doe,1973-09-15
- *
- * 2,mary,Mary,Meyer,1985-03-29
- * 
- */ -public final class CSVPrinter implements Flushable, Closeable { - - /** The place that the values get written. */ - private final Appendable appendable; - private final CSVFormat format; - - /** True if we just began a new record. */ - private boolean newRecord = true; - - /** - * Creates a printer that will print values to the given stream following the CSVFormat. - *

- * Currently, only a pure encapsulation format or a pure escaping format is supported. Hybrid formats (encapsulation - * and escaping with a different character) are not supported. - *

- * - * @param appendable - * stream to which to print. Must not be null. - * @param format - * the CSV format. Must not be null. - * @throws IOException - * thrown if the optional header cannot be printed. - * @throws IllegalArgumentException - * thrown if the parameters of the format are inconsistent or if either out or format are null. - */ - public CSVPrinter(final Appendable appendable, final CSVFormat format) throws IOException { - Objects.requireNonNull(appendable, "appendable"); - Objects.requireNonNull(format, "format"); - - this.appendable = appendable; - this.format = format.copy(); - // TODO: Is it a good idea to do this here instead of on the first call to a print method? - // It seems a pain to have to track whether the header has already been printed or not. - if (format.getHeaderComments() != null) { - for (final String line : format.getHeaderComments()) { - this.printComment(line); - } - } - if (format.getHeader() != null && !format.getSkipHeaderRecord()) { - this.printRecord((Object[]) format.getHeader()); - } - } - - @Override - public void close() throws IOException { - close(false); - } - - /** - * Closes the underlying stream with an optional flush first. - * @param flush whether to flush before the actual close. - * - * @throws IOException - * If an I/O error occurs - * @since 1.6 - */ - public void close(final boolean flush) throws IOException { - if (flush || format.getAutoFlush()) { - flush(); - } - if (appendable instanceof Closeable) { - ((Closeable) appendable).close(); - } - } - - /** - * Flushes the underlying stream. - * - * @throws IOException - * If an I/O error occurs - */ - @Override - public void flush() throws IOException { - if (appendable instanceof Flushable) { - ((Flushable) appendable).flush(); - } - } - - /** - * Gets the target Appendable. - * - * @return the target Appendable. - */ - public Appendable getOut() { - return this.appendable; - } - - /** - * Prints the string as the next value on the line. The value will be escaped or encapsulated as needed. - * - * @param value - * value to be output. - * @throws IOException - * If an I/O error occurs - */ - public synchronized void print(final Object value) throws IOException { - format.print(value, appendable, newRecord); - newRecord = false; - } - - /** - * Prints a comment on a new line among the delimiter separated values. - * - *

- * Comments will always begin on a new line and occupy at least one full line. The character specified to start - * comments and a space will be inserted at the beginning of each new line in the comment. - *

- * - *

- * If comments are disabled in the current CSV format this method does nothing. - *

- * - *

This method detects line breaks inside the comment string and inserts {@link CSVFormat#getRecordSeparator()} - * to start a new line of the comment. Note that this might produce unexpected results for formats that do not use - * line breaks as record separator.

- * - * @param comment - * the comment to output - * @throws IOException - * If an I/O error occurs - */ - public synchronized void printComment(final String comment) throws IOException { - if (comment == null || !format.isCommentMarkerSet()) { - return; - } - if (!newRecord) { - println(); - } - appendable.append(format.getCommentMarker().charValue()); - appendable.append(SP); - for (int i = 0; i < comment.length(); i++) { - final char c = comment.charAt(i); - switch (c) { - case CR: - if (i + 1 < comment.length() && comment.charAt(i + 1) == LF) { - i++; - } - //$FALL-THROUGH$ break intentionally excluded. - case LF: - println(); - appendable.append(format.getCommentMarker().charValue()); - appendable.append(SP); - break; - default: - appendable.append(c); - break; - } - } - println(); - } - - /** - * Prints headers for a result set based on its metadata. - * - * @param resultSet The result set to query for metadata. - * @throws IOException If an I/O error occurs. - * @throws SQLException If a database access error occurs or this method is called on a closed result set. - * @since 1.9.0 - */ - public synchronized void printHeaders(final ResultSet resultSet) throws IOException, SQLException { - printRecord((Object[]) format.builder().setHeader(resultSet).build().getHeader()); - } - - /** - * Outputs the record separator. - * - * @throws IOException - * If an I/O error occurs - */ - public synchronized void println() throws IOException { - format.println(appendable); - newRecord = true; - } - - /** - * Prints the given values a single record of delimiter separated values followed by the record separator. - * - *

- * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record - * separator to the output after printing the record, so there is no need to call {@link #println()}. - *

- * - * @param values - * values to output. - * @throws IOException - * If an I/O error occurs - */ - public synchronized void printRecord(final Iterable values) throws IOException { - for (final Object value : values) { - print(value); - } - println(); - } - - /** - * Prints the given values a single record of delimiter separated values followed by the record separator. - * - *

- * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record - * separator to the output after printing the record, so there is no need to call {@link #println()}. - *

- * - * @param values - * values to output. - * @throws IOException - * If an I/O error occurs - */ - public void printRecord(final Object... values) throws IOException { - printRecord(Arrays.asList(values)); - } - - /** - * Prints all the objects in the given collection handling nested collections/arrays as records. - * - *

- * If the given collection only contains simple objects, this method will print a single record like - * {@link #printRecord(Iterable)}. If the given collections contains nested collections/arrays those nested elements - * will each be printed as records using {@link #printRecord(Object...)}. - *

- * - *

- * Given the following data structure: - *

- * - *
-     * 
-     * List<String[]> data = ...
-     * data.add(new String[]{ "A", "B", "C" });
-     * data.add(new String[]{ "1", "2", "3" });
-     * data.add(new String[]{ "A1", "B2", "C3" });
-     * 
-     * 
- * - *

- * Calling this method will print: - *

- * - *
-     * 
-     * A, B, C
-     * 1, 2, 3
-     * A1, B2, C3
-     * 
-     * 
- * - * @param values - * the values to print. - * @throws IOException - * If an I/O error occurs - */ - public void printRecords(final Iterable values) throws IOException { - for (final Object value : values) { - if (value instanceof Object[]) { - this.printRecord((Object[]) value); - } else if (value instanceof Iterable) { - this.printRecord((Iterable) value); - } else { - this.printRecord(value); - } - } - } - - /** - * Prints all the objects in the given array handling nested collections/arrays as records. - * - *

- * If the given array only contains simple objects, this method will print a single record like - * {@link #printRecord(Object...)}. If the given collections contains nested collections/arrays those nested - * elements will each be printed as records using {@link #printRecord(Object...)}. - *

- * - *

- * Given the following data structure: - *

- * - *
-     * 
-     * String[][] data = new String[3][]
-     * data[0] = String[]{ "A", "B", "C" };
-     * data[1] = new String[]{ "1", "2", "3" };
-     * data[2] = new String[]{ "A1", "B2", "C3" };
-     * 
-     * 
- * - *

- * Calling this method will print: - *

- * - *
-     * 
-     * A, B, C
-     * 1, 2, 3
-     * A1, B2, C3
-     * 
-     * 
- * - * @param values - * the values to print. - * @throws IOException - * If an I/O error occurs - */ - public void printRecords(final Object... values) throws IOException { - printRecords(Arrays.asList(values)); - } - - /** - * Prints all the objects in the given JDBC result set. - * - * @param resultSet - * result set the values to print. - * @throws IOException - * If an I/O error occurs - * @throws SQLException - * if a database access error occurs - */ - public void printRecords(final ResultSet resultSet) throws SQLException, IOException { - final int columnCount = resultSet.getMetaData().getColumnCount(); - while (resultSet.next()) { - for (int i = 1; i <= columnCount; i++) { - final Object object = resultSet.getObject(i); - // TODO Who manages the Clob? The JDBC driver or must we close it? Is it driver-dependent? - print(object instanceof Clob ? ((Clob) object).getCharacterStream() : object); - } - println(); - } - } - - /** - * Prints all the objects with metadata in the given JDBC result set based on the header boolean. - * - * @param resultSet source of row data. - * @param printHeader whether to print headers. - * @throws IOException If an I/O error occurs - * @throws SQLException if a database access error occurs - * @since 1.9.0 - */ - public void printRecords(final ResultSet resultSet, final boolean printHeader) throws SQLException, IOException { - if (printHeader) { - printHeaders(resultSet); - } - printRecords(resultSet); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.csv; + +import static org.apache.commons.csv.Constants.CR; +import static org.apache.commons.csv.Constants.LF; +import static org.apache.commons.csv.Constants.SP; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.sql.Clob; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * Prints values in a {@link CSVFormat CSV format}. + * + *

Values can be appended to the output by calling the {@link #print(Object)} method. + * Values are printed according to {@link String#valueOf(Object)}. + * To complete a record the {@link #println()} method has to be called. + * Comments can be appended by calling {@link #printComment(String)}. + * However a comment will only be written to the output if the {@link CSVFormat} supports comments. + *

+ * + *

The printer also supports appending a complete record at once by calling {@link #printRecord(Object...)} + * or {@link #printRecord(Iterable)}. + * Furthermore {@link #printRecords(Object...)}, {@link #printRecords(Iterable)} and {@link #printRecords(ResultSet)} + * methods can be used to print several records at once. + *

+ * + *

Example:

+ * + *
+ * try (CSVPrinter printer = new CSVPrinter(new FileWriter("csv.txt"), CSVFormat.EXCEL)) {
+ *     printer.printRecord("id", "userName", "firstName", "lastName", "birthday");
+ *     printer.printRecord(1, "john73", "John", "Doe", LocalDate.of(1973, 9, 15));
+ *     printer.println();
+ *     printer.printRecord(2, "mary", "Mary", "Meyer", LocalDate.of(1985, 3, 29));
+ * } catch (IOException ex) {
+ *     ex.printStackTrace();
+ * }
+ * 
+ * + *

This code will write the following to csv.txt:

+ *
+ * id,userName,firstName,lastName,birthday
+ * 1,john73,John,Doe,1973-09-15
+ *
+ * 2,mary,Mary,Meyer,1985-03-29
+ * 
+ */ +public final class CSVPrinter implements Flushable, Closeable { + + /** + * Throws the given throwable. + * + * @param The throwable cast type. + * @param throwable The throwable to rethrow. + * @return nothing because we throw. + * @throws T Always thrown. + */ + @SuppressWarnings("unchecked") + private static RuntimeException rethrow(final Throwable throwable) throws T { + throw (T) throwable; + } + /** The place that the values get written. */ + private final Appendable appendable; + + private final CSVFormat format; + + /** True if we just began a new record. */ + private boolean newRecord = true; + + /** + * Creates a printer that will print values to the given stream following the CSVFormat. + *

+ * Currently, only a pure encapsulation format or a pure escaping format is supported. Hybrid formats (encapsulation + * and escaping with a different character) are not supported. + *

+ * + * @param appendable + * stream to which to print. Must not be null. + * @param format + * the CSV format. Must not be null. + * @throws IOException + * thrown if the optional header cannot be printed. + * @throws IllegalArgumentException + * thrown if the parameters of the format are inconsistent or if either out or format are null. + */ + public CSVPrinter(final Appendable appendable, final CSVFormat format) throws IOException { + Objects.requireNonNull(appendable, "appendable"); + Objects.requireNonNull(format, "format"); + + this.appendable = appendable; + this.format = format.copy(); + // TODO: Is it a good idea to do this here instead of on the first call to a print method? + // It seems a pain to have to track whether the header has already been printed or not. + if (format.getHeaderComments() != null) { + for (final String line : format.getHeaderComments()) { + this.printComment(line); + } + } + if (format.getHeader() != null && !format.getSkipHeaderRecord()) { + this.printRecord((Object[]) format.getHeader()); + } + } + + @Override + public void close() throws IOException { + close(false); + } + + /** + * Closes the underlying stream with an optional flush first. + * @param flush whether to flush before the actual close. + * + * @throws IOException + * If an I/O error occurs + * @since 1.6 + */ + public void close(final boolean flush) throws IOException { + if (flush || format.getAutoFlush()) { + flush(); + } + if (appendable instanceof Closeable) { + ((Closeable) appendable).close(); + } + } + + /** + * Flushes the underlying stream. + * + * @throws IOException + * If an I/O error occurs + */ + @Override + public void flush() throws IOException { + if (appendable instanceof Flushable) { + ((Flushable) appendable).flush(); + } + } + + /** + * Gets the target Appendable. + * + * @return the target Appendable. + */ + public Appendable getOut() { + return this.appendable; + } + + /** + * Prints the string as the next value on the line. The value will be escaped or encapsulated as needed. + * + * @param value + * value to be output. + * @throws IOException + * If an I/O error occurs + */ + public synchronized void print(final Object value) throws IOException { + format.print(value, appendable, newRecord); + newRecord = false; + } + + /** + * Prints a comment on a new line among the delimiter separated values. + * + *

+ * Comments will always begin on a new line and occupy at least one full line. The character specified to start + * comments and a space will be inserted at the beginning of each new line in the comment. + *

+ * + *

+ * If comments are disabled in the current CSV format this method does nothing. + *

+ * + *

This method detects line breaks inside the comment string and inserts {@link CSVFormat#getRecordSeparator()} + * to start a new line of the comment. Note that this might produce unexpected results for formats that do not use + * line breaks as record separator.

+ * + * @param comment + * the comment to output + * @throws IOException + * If an I/O error occurs + */ + public synchronized void printComment(final String comment) throws IOException { + if (comment == null || !format.isCommentMarkerSet()) { + return; + } + if (!newRecord) { + println(); + } + appendable.append(format.getCommentMarker().charValue()); + appendable.append(SP); + for (int i = 0; i < comment.length(); i++) { + final char c = comment.charAt(i); + switch (c) { + case CR: + if (i + 1 < comment.length() && comment.charAt(i + 1) == LF) { + i++; + } + //$FALL-THROUGH$ break intentionally excluded. + case LF: + println(); + appendable.append(format.getCommentMarker().charValue()); + appendable.append(SP); + break; + default: + appendable.append(c); + break; + } + } + println(); + } + + /** + * Prints headers for a result set based on its metadata. + * + * @param resultSet The result set to query for metadata. + * @throws IOException If an I/O error occurs. + * @throws SQLException If a database access error occurs or this method is called on a closed result set. + * @since 1.9.0 + */ + public synchronized void printHeaders(final ResultSet resultSet) throws IOException, SQLException { + printRecord((Object[]) format.builder().setHeader(resultSet).build().getHeader()); + } + + /** + * Outputs the record separator. + * + * @throws IOException + * If an I/O error occurs + */ + public synchronized void println() throws IOException { + format.println(appendable); + newRecord = true; + } + + /** + * Prints the given values as a single record of delimiter separated values followed by the record separator. + * + *

+ * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record + * separator to the output after printing the record, so there is no need to call {@link #println()}. + *

+ * + * @param values + * values to output. + * @throws IOException + * If an I/O error occurs + */ + public synchronized void printRecord(final Iterable values) throws IOException { + for (final Object value : values) { + print(value); + } + println(); + } + + /** + * Prints the given values as a single record of delimiter separated values followed by the record separator. + * + *

+ * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record + * separator to the output after printing the record, so there is no need to call {@link #println()}. + *

+ * + * @param values + * values to output. + * @throws IOException + * If an I/O error occurs + */ + public void printRecord(final Object... values) throws IOException { + printRecord(Arrays.asList(values)); + } + + /** + * Prints the given values as a single record of delimiter separated values followed by the record separator. + * + *

+ * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record + * separator to the output after printing the record, so there is no need to call {@link #println()}. + *

+ * + * @param values + * values to output. + * @throws IOException + * If an I/O error occurs + * @since 1.10.0 + */ + public synchronized void printRecord(final Stream values) throws IOException { + values.forEachOrdered(t -> { + try { + print(t); + } catch (IOException e) { + throw rethrow(e); + } + }); + println(); + } + + private void printRecordObject(final Object value) throws IOException { + if (value instanceof Object[]) { + this.printRecord((Object[]) value); + } else if (value instanceof Iterable) { + this.printRecord((Iterable) value); + } else { + this.printRecord(value); + } + } + + /** + * Prints all the objects in the given {@link Iterable} handling nested collections/arrays as records. + * + *

+ * If the given Iterable only contains simple objects, this method will print a single record like + * {@link #printRecord(Iterable)}. If the given Iterable contains nested collections/arrays those nested elements + * will each be printed as records using {@link #printRecord(Object...)}. + *

+ * + *

+ * Given the following data structure: + *

+ * + *
+     * 
+     * List<String[]> data = new ArrayList<>();
+     * data.add(new String[]{ "A", "B", "C" });
+     * data.add(new String[]{ "1", "2", "3" });
+     * data.add(new String[]{ "A1", "B2", "C3" });
+     * 
+     * 
+ * + *

+ * Calling this method will print: + *

+ * + *
+     * 
+     * A, B, C
+     * 1, 2, 3
+     * A1, B2, C3
+     * 
+     * 
+ * + * @param values + * the values to print. + * @throws IOException + * If an I/O error occurs + */ + public void printRecords(final Iterable values) throws IOException { + for (final Object value : values) { + printRecordObject(value); + } + } + + /** + * Prints all the objects in the given array handling nested collections/arrays as records. + * + *

+ * If the given array only contains simple objects, this method will print a single record like + * {@link #printRecord(Object...)}. If the given collections contains nested collections/arrays those nested + * elements will each be printed as records using {@link #printRecord(Object...)}. + *

+ * + *

+ * Given the following data structure: + *

+ * + *
+     * 
+     * String[][] data = new String[3][]
+     * data[0] = String[]{ "A", "B", "C" };
+     * data[1] = new String[]{ "1", "2", "3" };
+     * data[2] = new String[]{ "A1", "B2", "C3" };
+     * 
+     * 
+ * + *

+ * Calling this method will print: + *

+ * + *
+     * 
+     * A, B, C
+     * 1, 2, 3
+     * A1, B2, C3
+     * 
+     * 
+ * + * @param values + * the values to print. + * @throws IOException + * If an I/O error occurs + */ + public void printRecords(final Object... values) throws IOException { + printRecords(Arrays.asList(values)); + } + + /** + * Prints all the objects in the given JDBC result set. + * + * @param resultSet + * result set the values to print. + * @throws IOException + * If an I/O error occurs + * @throws SQLException + * if a database access error occurs + */ + public void printRecords(final ResultSet resultSet) throws SQLException, IOException { + final int columnCount = resultSet.getMetaData().getColumnCount(); + while (resultSet.next()) { + for (int i = 1; i <= columnCount; i++) { + final Object object = resultSet.getObject(i); + // TODO Who manages the Clob? The JDBC driver or must we close it? Is it driver-dependent? + print(object instanceof Clob ? ((Clob) object).getCharacterStream() : object); + } + println(); + } + } + + /** + * Prints all the objects with metadata in the given JDBC result set based on the header boolean. + * + * @param resultSet source of row data. + * @param printHeader whether to print headers. + * @throws IOException If an I/O error occurs + * @throws SQLException if a database access error occurs + * @since 1.9.0 + */ + public void printRecords(final ResultSet resultSet, final boolean printHeader) throws SQLException, IOException { + if (printHeader) { + printHeaders(resultSet); + } + printRecords(resultSet); + } + + /** + * Prints all the objects in the given {@link Stream} handling nested collections/arrays as records. + * + *

+ * If the given Stream only contains simple objects, this method will print a single record like + * {@link #printRecord(Iterable)}. If the given Stream contains nested collections/arrays those nested elements + * will each be printed as records using {@link #printRecord(Object...)}. + *

+ * + *

+ * Given the following data structure: + *

+ * + *
+     * 
+     * List<String[]> data = new ArrayList<>();
+     * data.add(new String[]{ "A", "B", "C" });
+     * data.add(new String[]{ "1", "2", "3" });
+     * data.add(new String[]{ "A1", "B2", "C3" });
+     * Stream<String[]> stream = data.stream();
+     * 
+     * 
+ * + *

+ * Calling this method will print: + *

+ * + *
+     * 
+     * A, B, C
+     * 1, 2, 3
+     * A1, B2, C3
+     * 
+     * 
+ * + * @param values + * the values to print. + * @throws IOException + * If an I/O error occurs + * @since 1.10.0 + */ + @SuppressWarnings("unused") // rethrow() throws IOException + public void printRecords(final Stream values) throws IOException { + values.forEachOrdered(t -> { + try { + printRecordObject(t); + } catch (IOException e) { + throw rethrow(e); + } + }); + } +} diff --git a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java index 6890bc26..8a9a36bc 100644 --- a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java +++ b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java @@ -1,1710 +1,1742 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.csv; - -import static org.apache.commons.csv.Constants.BACKSLASH; -import static org.apache.commons.csv.Constants.CR; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintStream; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.sql.BatchUpdateException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Arrays; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.Random; -import java.util.Vector; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.output.NullOutputStream; -import org.apache.commons.lang3.StringUtils; -import org.h2.tools.SimpleResultSet; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -/** - * Tests {@link CSVPrinter}. - */ -public class CSVPrinterTest { - - private static final char DQUOTE_CHAR = '"'; - private static final char EURO_CH = '\u20AC'; - private static final int ITERATIONS_FOR_RANDOM_TEST = 50000; - private static final char QUOTE_CH = '\''; - - private static String printable(final String s) { - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - final char ch = s.charAt(i); - if (ch <= ' ' || ch >= 128) { - sb.append("(").append((int) ch).append(")"); - } else { - sb.append(ch); - } - } - return sb.toString(); - } - - private String longText2; - - private final String recordSeparator = CSVFormat.DEFAULT.getRecordSeparator(); - - private void doOneRandom(final CSVFormat format) throws Exception { - final Random r = new Random(); - - final int nLines = r.nextInt(4) + 1; - final int nCol = r.nextInt(3) + 1; - // nLines=1;nCol=2; - final String[][] lines = generateLines(nLines, nCol); - - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - - for (int i = 0; i < nLines; i++) { - // for (int j=0; j parseResult = parser.getRecords(); - - final String[][] expected = lines.clone(); - for (int i = 0; i < expected.length; i++) { - expected[i] = expectNulls(expected[i], format); - } - Utils.compare("Printer output :" + printable(result), expected, parseResult); - } - } - - private void doRandom(final CSVFormat format, final int iter) throws Exception { - for (int i = 0; i < iter; i++) { - doOneRandom(format); - } - } - - /** - * Converts an input CSV array into expected output values WRT NULLs. NULL strings are converted to null values - * because the parser will convert these strings to null. - */ - private T[] expectNulls(final T[] original, final CSVFormat csvFormat) { - final T[] fixed = original.clone(); - for (int i = 0; i < fixed.length; i++) { - if (Objects.equals(csvFormat.getNullString(), fixed[i])) { - fixed[i] = null; - } - } - return fixed; - } - - private String[][] generateLines(final int nLines, final int nCol) { - final String[][] lines = new String[nLines][]; - for (int i = 0; i < nLines; i++) { - final String[] line = new String[nCol]; - lines[i] = line; - for (int j = 0; j < nCol; j++) { - line[j] = randStr(); - } - } - return lines; - } - - private Connection getH2Connection() throws SQLException, ClassNotFoundException { - Class.forName("org.h2.Driver"); - return DriverManager.getConnection("jdbc:h2:mem:my_test;", "sa", ""); - } - - private CSVPrinter printWithHeaderComments(final StringWriter sw, final Date now, final CSVFormat baseFormat) - throws IOException { - // Use withHeaderComments first to test CSV-145 - // @formatter:off - final CSVFormat format = baseFormat.builder() - .setHeaderComments("Generated by Apache Commons CSV 1.1", now) - .setCommentMarker('#') - .setHeader("Col1", "Col2") - .build(); - // @formatter:on - final CSVPrinter csvPrinter = format.print(sw); - csvPrinter.printRecord("A", "B"); - csvPrinter.printRecord("C", "D"); - csvPrinter.close(); - return csvPrinter; - } - - private String randStr() { - final Random r = new Random(); - - final int sz = r.nextInt(20); - // sz = r.nextInt(3); - final char[] buf = new char[sz]; - for (int i = 0; i < sz; i++) { - // stick in special chars with greater frequency - final char ch; - final int what = r.nextInt(20); - switch (what) { - case 0: - ch = '\r'; - break; - case 1: - ch = '\n'; - break; - case 2: - ch = '\t'; - break; - case 3: - ch = '\f'; - break; - case 4: - ch = ' '; - break; - case 5: - ch = ','; - break; - case 6: - ch = DQUOTE_CHAR; - break; - case 7: - ch = '\''; - break; - case 8: - ch = BACKSLASH; - break; - default: - ch = (char) r.nextInt(300); - break; - // default: ch = 'a'; break; - } - buf[i] = ch; - } - return new String(buf); - } - - private void setUpTable(final Connection connection) throws SQLException { - try (final Statement statement = connection.createStatement()) { - statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), TEXT CLOB)"); - statement.execute("insert into TEST values(1, 'r1', 'long text 1')"); - longText2 = StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 4); - longText2 += "\"\r\n\"a\""; - longText2 += StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 1); - statement.execute("insert into TEST values(2, 'r2', '" + longText2 + "')"); - longText2 = longText2.replace("\"","\"\""); - } - } - - @Test - public void testCloseBackwardCompatibility() throws IOException { - try (final Writer writer = mock(Writer.class)) { - final CSVFormat csvFormat = CSVFormat.DEFAULT; - try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) { - // empty - } - verify(writer, never()).flush(); - verify(writer, times(1)).close(); - }} - - @Test - public void testCloseWithCsvFormatAutoFlushOff() throws IOException { - try (final Writer writer = mock(Writer.class)) { - final CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(false); - try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) { - // empty - } - verify(writer, never()).flush(); - verify(writer, times(1)).close(); - } - } - - @Test - public void testCloseWithCsvFormatAutoFlushOn() throws IOException { - // System.out.println("start method"); - try (final Writer writer = mock(Writer.class)) { - final CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(true); - try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) { - // empty - } - verify(writer, times(1)).flush(); - verify(writer, times(1)).close(); - }} - - @Test - public void testCloseWithFlushOff() throws IOException { - try (final Writer writer = mock(Writer.class)) { - final CSVFormat csvFormat = CSVFormat.DEFAULT; - @SuppressWarnings("resource") - final CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat); - csvPrinter.close(false); - verify(writer, never()).flush(); - verify(writer, times(1)).close(); - } - } - - @Test - public void testCloseWithFlushOn() throws IOException { - try (final Writer writer = mock(Writer.class)) { - @SuppressWarnings("resource") - final CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT); - csvPrinter.close(true); - verify(writer, times(1)).flush(); - } - } - - @Test - public void testCRComment() throws IOException { - final StringWriter sw = new StringWriter(); - final Object value = "abc"; - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) { - printer.print(value); - printer.printComment("This is a comment\r\non multiple lines\rthis is next comment\r"); - assertEquals("abc" + recordSeparator + "# This is a comment" + recordSeparator + "# on multiple lines" - + recordSeparator + "# this is next comment" + recordSeparator + "# " + recordSeparator, sw.toString()); - } - } - - @Test - public void testCSV135() throws IOException { - final List list = new LinkedList<>(); - list.add("\"\""); // "" - list.add("\\\\"); // \\ - list.add("\\\"\\"); // \"\ - // - // "",\\,\"\ (unchanged) - tryFormat(list, null, null, "\"\",\\\\,\\\"\\"); - // - // """""",\\,"\""\" (quoted, and embedded DQ doubled) - tryFormat(list, '"', null, "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); - // - // "",\\\\,\\"\\ (escapes escaped, not quoted) - tryFormat(list, null, '\\', "\"\",\\\\\\\\,\\\\\"\\\\"); - // - // "\"\"","\\\\","\\\"\\" (quoted, and embedded DQ & escape escaped) - tryFormat(list, '"', '\\', "\"\\\"\\\"\",\"\\\\\\\\\",\"\\\\\\\"\\\\\""); - // - // """""",\\,"\""\" (quoted, embedded DQ escaped) - tryFormat(list, '"', '"', "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); - } - - @Test - public void testCSV259() throws IOException { - final StringWriter sw = new StringWriter(); - try (final Reader reader = new FileReader("src/test/resources/org/apache/commons/csv/CSV-259/sample.txt"); - final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape('!').withQuote(null))) { - printer.print(reader); - assertEquals("x!,y!,z", sw.toString()); - } - } - - @Test - public void testDelimeterQuoted() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { - printer.print("a,b,c"); - printer.print("xyz"); - assertEquals("'a,b,c',xyz", sw.toString()); - } - } - - @Test - public void testDelimeterQuoteNone() throws IOException { - final StringWriter sw = new StringWriter(); - final CSVFormat format = CSVFormat.DEFAULT.withEscape('!').withQuoteMode(QuoteMode.NONE); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - printer.print("a,b,c"); - printer.print("xyz"); - assertEquals("a!,b!,c,xyz", sw.toString()); - } - } - - @Test - public void testDelimeterStringQuoted() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.builder().setDelimiter("[|]").setQuote('\'').build())) { - printer.print("a[|]b[|]c"); - printer.print("xyz"); - assertEquals("'a[|]b[|]c'[|]xyz", sw.toString()); - } - } - - @Test - public void testDelimeterStringQuoteNone() throws IOException { - final StringWriter sw = new StringWriter(); - final CSVFormat format = CSVFormat.DEFAULT.builder().setDelimiter("[|]").setEscape('!').setQuoteMode(QuoteMode.NONE).build(); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - printer.print("a[|]b[|]c"); - printer.print("xyz"); - printer.print("a[xy]bc[]"); - assertEquals("a![!|!]b![!|!]c[|]xyz[|]a[xy]bc[]", sw.toString()); - } - } - - @Test - public void testDelimiterEscaped() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape('!').withQuote(null))) { - printer.print("a,b,c"); - printer.print("xyz"); - assertEquals("a!,b!,c,xyz", sw.toString()); - } - } - - @Test - public void testDelimiterPlain() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { - printer.print("a,b,c"); - printer.print("xyz"); - assertEquals("a,b,c,xyz", sw.toString()); - } - } - - @Test - public void testDelimiterStringEscaped() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.builder().setDelimiter("|||").setEscape('!').setQuote(null).build())) { - printer.print("a|||b|||c"); - printer.print("xyz"); - assertEquals("a!|!|!|b!|!|!|c|||xyz", sw.toString()); - } - } - - @Test - public void testDisabledComment() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printComment("This is a comment"); - assertEquals("", sw.toString()); - } - } - - @Test - public void testDontQuoteEuroFirstChar() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.RFC4180)) { - printer.printRecord(EURO_CH, "Deux"); - assertEquals(EURO_CH + ",Deux" + recordSeparator, sw.toString()); - } - } - - @Test - public void testEolEscaped() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withEscape('!'))) { - printer.print("a\rb\nc"); - printer.print("x\fy\bz"); - assertEquals("a!rb!nc,x\fy\bz", sw.toString()); - } - } - - @Test - public void testEolPlain() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { - printer.print("a\rb\nc"); - printer.print("x\fy\bz"); - assertEquals("a\rb\nc,x\fy\bz", sw.toString()); - } - } - - @Test - public void testEolQuoted() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { - printer.print("a\rb\nc"); - printer.print("x\by\fz"); - assertEquals("'a\rb\nc',x\by\fz", sw.toString()); - } - } - - @Test - public void testEscapeBackslash1() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { - printer.print("\\"); - } - assertEquals("\\", sw.toString()); - } - - @Test - public void testEscapeBackslash2() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { - printer.print("\\\r"); - } - assertEquals("'\\\r'", sw.toString()); - } - - @Test - public void testEscapeBackslash3() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { - printer.print("X\\\r"); - } - assertEquals("'X\\\r'", sw.toString()); - } - - @Test - public void testEscapeBackslash4() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { - printer.print("\\\\"); - } - assertEquals("\\\\", sw.toString()); - } - - @Test - public void testEscapeBackslash5() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { - printer.print("\\\\"); - } - assertEquals("\\\\", sw.toString()); - } - - @Test - public void testEscapeNull1() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { - printer.print("\\"); - } - assertEquals("\\", sw.toString()); - } - - @Test - public void testEscapeNull2() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { - printer.print("\\\r"); - } - assertEquals("\"\\\r\"", sw.toString()); - } - - @Test - public void testEscapeNull3() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { - printer.print("X\\\r"); - } - assertEquals("\"X\\\r\"", sw.toString()); - } - - @Test - public void testEscapeNull4() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { - printer.print("\\\\"); - } - assertEquals("\\\\", sw.toString()); - } - - @Test - public void testEscapeNull5() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { - printer.print("\\\\"); - } - assertEquals("\\\\", sw.toString()); - } - - @Test - public void testExcelPrintAllArrayOfArrays() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { - printer.printRecords((Object[]) new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } }); - assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); - } - } - - @Test - public void testExcelPrintAllArrayOfLists() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { - printer.printRecords( - (Object[]) new List[] { Arrays.asList("r1c1", "r1c2"), Arrays.asList("r2c1", "r2c2") }); - assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); - } - } - - @Test - public void testExcelPrintAllIterableOfArrays() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { - printer.printRecords(Arrays.asList(new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } })); - assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); - } - } - - @Test - public void testExcelPrintAllIterableOfLists() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { - printer.printRecords( - Arrays.asList(Arrays.asList("r1c1", "r1c2"), Arrays.asList("r2c1", "r2c2"))); - assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); - } - } - - @Test - public void testExcelPrinter1() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { - printer.printRecord("a", "b"); - assertEquals("a,b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testExcelPrinter2() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { - printer.printRecord("a,b", "b"); - assertEquals("\"a,b\",b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testHeader() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, - CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3"))) { - printer.printRecord("a", "b", "c"); - printer.printRecord("x", "y", "z"); - assertEquals("C1,C2,C3\r\na,b,c\r\nx,y,z\r\n", sw.toString()); - } - } - - @Test - public void testHeaderCommentExcel() throws IOException { - final StringWriter sw = new StringWriter(); - final Date now = new Date(); - final CSVFormat format = CSVFormat.EXCEL; - try (final CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format)) { - assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + "\r\nCol1,Col2\r\nA,B\r\nC,D\r\n", - sw.toString()); - } - } - - @Test - public void testHeaderCommentTdf() throws IOException { - final StringWriter sw = new StringWriter(); - final Date now = new Date(); - final CSVFormat format = CSVFormat.TDF; - try (final CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format)) { - assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + "\r\nCol1\tCol2\r\nA\tB\r\nC\tD\r\n", - sw.toString()); - } - } - - @Test - public void testHeaderNotSet() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { - printer.printRecord("a", "b", "c"); - printer.printRecord("x", "y", "z"); - assertEquals("a,b,c\r\nx,y,z\r\n", sw.toString()); - } - } - - @Test - public void testInvalidFormat() { - assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withDelimiter(CR)); - } - - @Test - public void testJdbcPrinter() throws IOException, ClassNotFoundException, SQLException { - final StringWriter sw = new StringWriter(); - try (final Connection connection = getH2Connection()) { - setUpTable(connection); - try (final Statement stmt = connection.createStatement(); - final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT); - final ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST");) { - printer.printRecords(resultSet); - } - } - assertEquals("1,r1,\"long text 1\"" + recordSeparator + "2,r2,\"" + longText2 + "\"" + recordSeparator, sw.toString()); - } - - @Test - public void testJdbcPrinterWithResultSet() throws IOException, ClassNotFoundException, SQLException { - final StringWriter sw = new StringWriter(); - Class.forName("org.h2.Driver"); - try (final Connection connection = getH2Connection()) { - setUpTable(connection); - try (final Statement stmt = connection.createStatement(); - final ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST"); - final CSVPrinter printer = CSVFormat.DEFAULT.withHeader(resultSet).print(sw)) { - printer.printRecords(resultSet); - } - } - assertEquals("ID,NAME,TEXT" + recordSeparator + "1,r1,\"long text 1\"" + recordSeparator + "2,r2,\"" + longText2 - + "\"" + recordSeparator, sw.toString()); - } - - @Test - public void testJdbcPrinterWithResultSetHeader() throws IOException, ClassNotFoundException, SQLException { - final StringWriter sw = new StringWriter(); - try (final Connection connection = getH2Connection()) { - setUpTable(connection); - try (final Statement stmt = connection.createStatement(); - final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT);) { - try (final ResultSet resultSet = stmt.executeQuery("select ID, NAME from TEST")) { - printer.printRecords(resultSet, true); - assertEquals("ID,NAME" + recordSeparator + "1,r1" + recordSeparator + "2,r2" + recordSeparator, - sw.toString()); - } - try (final ResultSet resultSet = stmt.executeQuery("select ID, NAME from TEST")) { - printer.printRecords(resultSet, false); - assertNotEquals("ID,NAME" + recordSeparator + "1,r1" + recordSeparator + "2,r2" + recordSeparator, - sw.toString()); - } - } - } - } - - @Test - public void testJdbcPrinterWithResultSetMetaData() throws IOException, ClassNotFoundException, SQLException { - final StringWriter sw = new StringWriter(); - Class.forName("org.h2.Driver"); - try (final Connection connection = getH2Connection()) { - setUpTable(connection); - try (final Statement stmt = connection.createStatement(); - final ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST"); - final CSVPrinter printer = CSVFormat.DEFAULT.withHeader(resultSet.getMetaData()).print(sw)) { - printer.printRecords(resultSet); - assertEquals("ID,NAME,TEXT" + recordSeparator + "1,r1,\"long text 1\"" + recordSeparator + "2,r2,\"" - + longText2 + "\"" + recordSeparator, sw.toString()); - } - } - } - - @Test - @Disabled - public void testJira135_part1() throws IOException { - final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); - final StringWriter sw = new StringWriter(); - final List list = new LinkedList<>(); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - list.add("\""); - printer.printRecord(list); - } - final String expected = "\"\\\"\"" + format.getRecordSeparator(); - assertEquals(expected, sw.toString()); - final String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(list.toArray(), format), record0); - } - - @Test - @Disabled - public void testJira135_part2() throws IOException { - final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); - final StringWriter sw = new StringWriter(); - final List list = new LinkedList<>(); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - list.add("\n"); - printer.printRecord(list); - } - final String expected = "\"\\n\"" + format.getRecordSeparator(); - assertEquals(expected, sw.toString()); - final String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(list.toArray(), format), record0); - } - - @Test - @Disabled - public void testJira135_part3() throws IOException { - final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); - final StringWriter sw = new StringWriter(); - final List list = new LinkedList<>(); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - list.add("\\"); - printer.printRecord(list); - } - final String expected = "\"\\\\\"" + format.getRecordSeparator(); - assertEquals(expected, sw.toString()); - final String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(list.toArray(), format), record0); - } - - @Test - @Disabled - public void testJira135All() throws IOException { - final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); - final StringWriter sw = new StringWriter(); - final List list = new LinkedList<>(); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - list.add("\""); - list.add("\n"); - list.add("\\"); - printer.printRecord(list); - } - final String expected = "\"\\\"\",\"\\n\",\"\\\"" + format.getRecordSeparator(); - assertEquals(expected, sw.toString()); - final String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(list.toArray(), format), record0); - } - - @Test - public void testMongoDbCsvBasic() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { - printer.printRecord("a", "b"); - assertEquals("a,b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMongoDbCsvCommaInValue() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { - printer.printRecord("a,b", "c"); - assertEquals("\"a,b\",c" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMongoDbCsvDoubleQuoteInValue() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { - printer.printRecord("a \"c\" b", "d"); - assertEquals("\"a \"\"c\"\" b\",d" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMongoDbCsvTabInValue() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { - printer.printRecord("a\tb", "c"); - assertEquals("a\tb,c" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMongoDbTsvBasic() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) { - printer.printRecord("a", "b"); - assertEquals("a\tb" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMongoDbTsvCommaInValue() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) { - printer.printRecord("a,b", "c"); - assertEquals("a,b\tc" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMongoDbTsvTabInValue() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) { - printer.printRecord("a\tb", "c"); - assertEquals("\"a\tb\"\tc" + recordSeparator, sw.toString()); - } - } - - @Test - public void testMultiLineComment() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) { - printer.printComment("This is a comment\non multiple lines"); - - assertEquals("# This is a comment" + recordSeparator + "# on multiple lines" + recordSeparator, - sw.toString()); - } - } - - @Test - public void testMySqlNullOutput() throws IOException { - Object[] s = new String[] { "NULL", null }; - CSVFormat format = CSVFormat.MYSQL.withQuote(DQUOTE_CHAR).withNullString("NULL") - .withQuoteMode(QuoteMode.NON_NUMERIC); - StringWriter writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - String expected = "\"NULL\"\tNULL\n"; - assertEquals(expected, writer.toString()); - String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(s, record0); - - s = new String[] { "\\N", null }; - format = CSVFormat.MYSQL.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\t\\N\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\N", "A" }; - format = CSVFormat.MYSQL.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\tA\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\n", "A" }; - format = CSVFormat.MYSQL.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\n\tA\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "", null }; - format = CSVFormat.MYSQL.withNullString("NULL"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\tNULL\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "", null }; - format = CSVFormat.MYSQL; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\t\\N\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\N", "", "\u000e,\\\r" }; - format = CSVFormat.MYSQL; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\t\t\u000e,\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "NULL", "\\\r" }; - format = CSVFormat.MYSQL; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "NULL\t\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\\r" }; - format = CSVFormat.MYSQL; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - } - - @Test - public void testMySqlNullStringDefault() { - assertEquals("\\N", CSVFormat.MYSQL.getNullString()); - } - - @Test - public void testNewCsvPrinterAppendableNullFormat() { - assertThrows(NullPointerException.class, () -> new CSVPrinter(new StringWriter(), null)); - } - - @Test - public void testNewCsvPrinterNullAppendableFormat() { - assertThrows(NullPointerException.class, () -> new CSVPrinter(null, CSVFormat.DEFAULT)); - } - - @Test - public void testNotFlushable() throws IOException { - final Appendable out = new StringBuilder(); - try (final CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT)) { - printer.printRecord("a", "b", "c"); - assertEquals("a,b,c" + recordSeparator, out.toString()); - printer.flush(); - } - } - - @Test - public void testParseCustomNullValues() throws IOException { - final StringWriter sw = new StringWriter(); - final CSVFormat format = CSVFormat.DEFAULT.withNullString("NULL"); - try (final CSVPrinter printer = new CSVPrinter(sw, format)) { - printer.printRecord("a", null, "b"); - } - final String csvString = sw.toString(); - assertEquals("a,NULL,b" + recordSeparator, csvString); - try (final CSVParser iterable = format.parse(new StringReader(csvString))) { - final Iterator iterator = iterable.iterator(); - final CSVRecord record = iterator.next(); - assertEquals("a", record.get(0)); - assertNull(record.get(1)); - assertEquals("b", record.get(2)); - assertFalse(iterator.hasNext()); - } - } - - @Test - public void testPlainEscaped() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withEscape('!'))) { - printer.print("abc"); - printer.print("xyz"); - assertEquals("abc,xyz", sw.toString()); - } - } - - @Test - public void testPlainPlain() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { - printer.print("abc"); - printer.print("xyz"); - assertEquals("abc,xyz", sw.toString()); - } - } - - @Test - public void testPlainQuoted() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { - printer.print("abc"); - assertEquals("abc", sw.toString()); - } - } - - @Test - @Disabled - public void testPostgreSqlCsvNullOutput() throws IOException { - Object[] s = new String[] { "NULL", null }; - CSVFormat format = CSVFormat.POSTGRESQL_CSV.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.ALL_NON_NULL); - StringWriter writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - String expected = "\"NULL\",NULL\n"; - assertEquals(expected, writer.toString()); - String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(new Object[2], record0); - - s = new String[] { "\\N", null }; - format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\t\\N\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\N", "A" }; - format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\tA\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\n", "A" }; - format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\n\tA\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "", null }; - format = CSVFormat.POSTGRESQL_CSV.withNullString("NULL"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\tNULL\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "", null }; - format = CSVFormat.POSTGRESQL_CSV; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\t\\N\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\N", "", "\u000e,\\\r" }; - format = CSVFormat.POSTGRESQL_CSV; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\t\t\u000e,\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "NULL", "\\\r" }; - format = CSVFormat.POSTGRESQL_CSV; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "NULL\t\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\\r" }; - format = CSVFormat.POSTGRESQL_CSV; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - } - - @Test - @Disabled - public void testPostgreSqlCsvTextOutput() throws IOException { - Object[] s = new String[] { "NULL", null }; - CSVFormat format = CSVFormat.POSTGRESQL_TEXT.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.ALL_NON_NULL); - StringWriter writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - String expected = "\"NULL\"\tNULL\n"; - assertEquals(expected, writer.toString()); - String[] record0 = toFirstRecordValues(expected, format); - assertArrayEquals(new Object[2], record0); - - s = new String[] { "\\N", null }; - format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\t\\N\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\N", "A" }; - format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\tA\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\n", "A" }; - format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\n\tA\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "", null }; - format = CSVFormat.POSTGRESQL_TEXT.withNullString("NULL"); - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\tNULL\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "", null }; - format = CSVFormat.POSTGRESQL_TEXT; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\t\\N\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\N", "", "\u000e,\\\r" }; - format = CSVFormat.POSTGRESQL_TEXT; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\N\t\t\u000e,\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "NULL", "\\\r" }; - format = CSVFormat.POSTGRESQL_TEXT; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "NULL\t\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - - s = new String[] { "\\\r" }; - format = CSVFormat.POSTGRESQL_TEXT; - writer = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(writer, format)) { - printer.printRecord(s); - } - expected = "\\\\\\r\n"; - assertEquals(expected, writer.toString()); - record0 = toFirstRecordValues(expected, format); - assertArrayEquals(expectNulls(s, format), record0); - } - - @Test - public void testPostgreSqlNullStringDefaultCsv() { - assertEquals("", CSVFormat.POSTGRESQL_CSV.getNullString()); - } - - @Test - public void testPostgreSqlNullStringDefaultText() { - assertEquals("\\N", CSVFormat.POSTGRESQL_TEXT.getNullString()); - } - - @Test - public void testPrint() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = CSVFormat.DEFAULT.print(sw)) { - printer.printRecord("a", "b\\c"); - assertEquals("a,b\\c" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrintCSVParser() throws IOException { - final String code = "a1,b1\n" // 1) - + "a2,b2\n" // 2) - + "a3,b3\n" // 3) - + "a4,b4\n"// 4) - ; - final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; - final CSVFormat format = CSVFormat.DEFAULT; - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { - printer.printRecords(parser); - } - try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { - final List records = parser.getRecords(); - assertFalse(records.isEmpty()); - Utils.compare("Fail", res, records); - } - } - - @Test - public void testPrintCSVRecord() throws IOException { - final String code = "a1,b1\n" // 1) - + "a2,b2\n" // 2) - + "a3,b3\n" // 3) - + "a4,b4\n"// 4) - ; - final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; - final CSVFormat format = CSVFormat.DEFAULT; - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { - for (final CSVRecord record : parser) { - printer.printRecord(record); - } - } - try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { - final List records = parser.getRecords(); - assertFalse(records.isEmpty()); - Utils.compare("Fail", res, records); - } - } - - @Test - public void testPrintCSVRecords() throws IOException { - final String code = "a1,b1\n" // 1) - + "a2,b2\n" // 2) - + "a3,b3\n" // 3) - + "a4,b4\n"// 4) - ; - final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; - final CSVFormat format = CSVFormat.DEFAULT; - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { - printer.printRecords(parser.getRecords()); - } - try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { - final List records = parser.getRecords(); - assertFalse(records.isEmpty()); - Utils.compare("Fail", res, records); - } - } - - @Test - public void testPrintCustomNullValues() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withNullString("NULL"))) { - printer.printRecord("a", null, "b"); - assertEquals("a,NULL,b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter1() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a", "b"); - assertEquals("a,b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter2() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a,b", "b"); - assertEquals("\"a,b\",b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter3() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a, b", "b "); - assertEquals("\"a, b\",\"b \"" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter4() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a", "b\"c"); - assertEquals("a,\"b\"\"c\"" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter5() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a", "b\nc"); - assertEquals("a,\"b\nc\"" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter6() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a", "b\r\nc"); - assertEquals("a,\"b\r\nc\"" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrinter7() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a", "b\\c"); - assertEquals("a,b\\c" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrintNullValues() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { - printer.printRecord("a", null, "b"); - assertEquals("a,,b" + recordSeparator, sw.toString()); - } - } - - @Test - public void testPrintOnePositiveInteger() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.MINIMAL))) { - printer.print(Integer.MAX_VALUE); - assertEquals(String.valueOf(Integer.MAX_VALUE), sw.toString()); - } - } - - /** - * Test to target the use of {@link IOUtils#copy(java.io.Reader, Appendable)} which directly - * buffers the value from the Reader to the Appendable. - * - *

Requires the format to have no quote or escape character, value to be a - * {@link java.io.Reader Reader} and the output MUST NOT be a - * {@link java.io.Writer Writer} but some other Appendable.

- * - * @throws IOException Not expected to happen - */ - @Test - public void testPrintReaderWithoutQuoteToAppendable() throws IOException { - final StringBuilder sb = new StringBuilder(); - final String content = "testValue"; - try (final CSVPrinter printer = new CSVPrinter(sb, CSVFormat.DEFAULT.withQuote(null))) { - final StringReader value = new StringReader(content); - printer.print(value); - } - assertEquals(content, sb.toString()); - } - - /** - * Test to target the use of {@link IOUtils#copyLarge(java.io.Reader, Writer)} which directly - * buffers the value from the Reader to the Writer. - * - *

Requires the format to have no quote or escape character, value to be a - * {@link java.io.Reader Reader} and the output MUST be a - * {@link java.io.Writer Writer}.

- * - * @throws IOException Not expected to happen - */ - @Test - public void testPrintReaderWithoutQuoteToWriter() throws IOException { - final StringWriter sw = new StringWriter(); - final String content = "testValue"; - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { - final StringReader value = new StringReader(content); - printer.print(value); - } - assertEquals(content, sw.toString()); - } - - @Test - public void testPrintRecordsWithCSVRecord() throws IOException { - final String[] values = {"A", "B", "C"}; - final String rowData = StringUtils.join(values, ','); - final CharArrayWriter charArrayWriter = new CharArrayWriter(0); - try (final CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(rowData)); - final CSVPrinter csvPrinter = CSVFormat.INFORMIX_UNLOAD.print(charArrayWriter)) { - for (final CSVRecord record : parser) { - csvPrinter.printRecord(record); - } - } - assertEquals(6, charArrayWriter.size()); - assertEquals("A|B|C" + CSVFormat.INFORMIX_UNLOAD.getRecordSeparator(), charArrayWriter.toString()); - } - - @Test - public void testPrintRecordsWithEmptyVector() throws IOException { - final PrintStream out = System.out; - try { - System.setOut(new PrintStream(NullOutputStream.NULL_OUTPUT_STREAM)); - try (CSVPrinter csvPrinter = CSVFormat.POSTGRESQL_TEXT.printer()) { - final Vector vector = new Vector<>(); - final int expectedCapacity = 23; - vector.setSize(expectedCapacity); - csvPrinter.printRecords(vector); - assertEquals(expectedCapacity, vector.capacity()); - } - } finally { - System.setOut(out); - } - } - - @Test - public void testPrintRecordsWithObjectArray() throws IOException { - final CharArrayWriter charArrayWriter = new CharArrayWriter(0); - try (CSVPrinter csvPrinter = CSVFormat.INFORMIX_UNLOAD.print(charArrayWriter)) { - final HashSet hashSet = new HashSet<>(); - final Object[] objectArray = new Object[6]; - objectArray[3] = hashSet; - csvPrinter.printRecords(objectArray); - } - assertEquals(6, charArrayWriter.size()); - assertEquals("\n\n\n\n\n\n", charArrayWriter.toString()); - } - - @Test - public void testPrintRecordsWithResultSetOneRow() throws IOException, SQLException { - try (CSVPrinter csvPrinter = CSVFormat.MYSQL.printer()) { - try (ResultSet resultSet = new SimpleResultSet()) { - csvPrinter.printRecords(resultSet); - assertEquals(0, resultSet.getRow()); - } - } - } - - @Test - public void testPrintToFileWithCharsetUtf16Be() throws IOException { - final File file = File.createTempFile(getClass().getName(), ".csv"); - try (final CSVPrinter printer = CSVFormat.DEFAULT.print(file, StandardCharsets.UTF_16BE)) { - printer.printRecord("a", "b\\c"); - } - assertEquals("a,b\\c" + recordSeparator, FileUtils.readFileToString(file, StandardCharsets.UTF_16BE)); - } - - @Test - public void testPrintToFileWithDefaultCharset() throws IOException { - final File file = File.createTempFile(getClass().getName(), ".csv"); - try (final CSVPrinter printer = CSVFormat.DEFAULT.print(file, Charset.defaultCharset())) { - printer.printRecord("a", "b\\c"); - } - assertEquals("a,b\\c" + recordSeparator, FileUtils.readFileToString(file, Charset.defaultCharset())); - } - - @Test - public void testPrintToPathWithDefaultCharset() throws IOException { - final File file = File.createTempFile(getClass().getName(), ".csv"); - try (final CSVPrinter printer = CSVFormat.DEFAULT.print(file.toPath(), Charset.defaultCharset())) { - printer.printRecord("a", "b\\c"); - } - assertEquals("a,b\\c" + recordSeparator, FileUtils.readFileToString(file, Charset.defaultCharset())); - } - - @Test - public void testQuoteAll() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.ALL))) { - printer.printRecord("a", "b\nc", "d"); - assertEquals("\"a\",\"b\nc\",\"d\"" + recordSeparator, sw.toString()); - } - } - - @Test - public void testQuoteCommaFirstChar() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.RFC4180)) { - printer.printRecord(","); - assertEquals("\",\"" + recordSeparator, sw.toString()); - } - } - - @Test - public void testQuoteNonNumeric() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.NON_NUMERIC))) { - printer.printRecord("a", "b\nc", Integer.valueOf(1)); - assertEquals("\"a\",\"b\nc\",1" + recordSeparator, sw.toString()); - } - } - - @Test - public void testRandomDefault() throws Exception { - doRandom(CSVFormat.DEFAULT, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - public void testRandomExcel() throws Exception { - doRandom(CSVFormat.EXCEL, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - @Disabled - public void testRandomMongoDbCsv() throws Exception { - doRandom(CSVFormat.MONGODB_CSV, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - public void testRandomMySql() throws Exception { - doRandom(CSVFormat.MYSQL, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - @Disabled - public void testRandomOracle() throws Exception { - doRandom(CSVFormat.ORACLE, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - @Disabled - public void testRandomPostgreSqlCsv() throws Exception { - doRandom(CSVFormat.POSTGRESQL_CSV, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - @Disabled - public void testRandomPostgreSqlText() throws Exception { - doRandom(CSVFormat.POSTGRESQL_TEXT, ITERATIONS_FOR_RANDOM_TEST); - } - - - @Test - public void testRandomRfc4180() throws Exception { - doRandom(CSVFormat.RFC4180, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - public void testRandomTdf() throws Exception { - doRandom(CSVFormat.TDF, ITERATIONS_FOR_RANDOM_TEST); - } - - @Test - public void testSingleLineComment() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) { - printer.printComment("This is a comment"); - assertEquals("# This is a comment" + recordSeparator, sw.toString()); - } - } - - @Test - public void testSingleQuoteQuoted() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { - printer.print("a'b'c"); - printer.print("xyz"); - assertEquals("'a''b''c',xyz", sw.toString()); - } - } - - @Test - public void testSkipHeaderRecordFalse() throws IOException { - // functionally identical to testHeader, used to test CSV-153 - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, - CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3").withSkipHeaderRecord(false))) { - printer.printRecord("a", "b", "c"); - printer.printRecord("x", "y", "z"); - assertEquals("C1,C2,C3\r\na,b,c\r\nx,y,z\r\n", sw.toString()); - } - } - - @Test - public void testSkipHeaderRecordTrue() throws IOException { - // functionally identical to testHeaderNotSet, used to test CSV-153 - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, - CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3").withSkipHeaderRecord(true))) { - printer.printRecord("a", "b", "c"); - printer.printRecord("x", "y", "z"); - assertEquals("a,b,c\r\nx,y,z\r\n", sw.toString()); - } - } - - @Test - public void testTrailingDelimiterOnTwoColumns() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrailingDelimiter())) { - printer.printRecord("A", "B"); - assertEquals("A,B,\r\n", sw.toString()); - } - } - - @Test - public void testTrimOffOneColumn() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim(false))) { - printer.print(" A "); - assertEquals("\" A \"", sw.toString()); - } - } - - @Test - public void testTrimOnOneColumn() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim())) { - printer.print(" A "); - assertEquals("A", sw.toString()); - } - } - - @Test - public void testTrimOnTwoColumns() throws IOException { - final StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim())) { - printer.print(" A "); - printer.print(" B "); - assertEquals("A,B", sw.toString()); - } - } - - private String[] toFirstRecordValues(final String expected, final CSVFormat format) throws IOException { - return CSVParser.parse(expected, format).getRecords().get(0).values(); - } - - private void tryFormat(final List list, final Character quote, final Character escape, final String expected) throws IOException { - final CSVFormat format = CSVFormat.DEFAULT.withQuote(quote).withEscape(escape).withRecordSeparator(null); - final Appendable out = new StringBuilder(); - try (final CSVPrinter printer = new CSVPrinter(out, format)) { - printer.printRecord(list); - } - assertEquals(expected, out.toString()); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.csv; + +import static org.apache.commons.csv.Constants.BACKSLASH; +import static org.apache.commons.csv.Constants.CR; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.CharArrayWriter; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.sql.BatchUpdateException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.Vector; +import java.util.stream.Stream; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.output.NullOutputStream; +import org.apache.commons.lang3.StringUtils; +import org.h2.tools.SimpleResultSet; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +/** + * Tests {@link CSVPrinter}. + */ +public class CSVPrinterTest { + + private static final char DQUOTE_CHAR = '"'; + private static final char EURO_CH = '\u20AC'; + private static final int ITERATIONS_FOR_RANDOM_TEST = 50000; + private static final char QUOTE_CH = '\''; + + private static String printable(final String s) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + final char ch = s.charAt(i); + if (ch <= ' ' || ch >= 128) { + sb.append("(").append((int) ch).append(")"); + } else { + sb.append(ch); + } + } + return sb.toString(); + } + + private String longText2; + + private final String recordSeparator = CSVFormat.DEFAULT.getRecordSeparator(); + + private void doOneRandom(final CSVFormat format) throws Exception { + final Random r = new Random(); + + final int nLines = r.nextInt(4) + 1; + final int nCol = r.nextInt(3) + 1; + // nLines=1;nCol=2; + final String[][] lines = generateLines(nLines, nCol); + + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + + for (int i = 0; i < nLines; i++) { + // for (int j=0; j parseResult = parser.getRecords(); + + final String[][] expected = lines.clone(); + for (int i = 0; i < expected.length; i++) { + expected[i] = expectNulls(expected[i], format); + } + Utils.compare("Printer output :" + printable(result), expected, parseResult); + } + } + + private void doRandom(final CSVFormat format, final int iter) throws Exception { + for (int i = 0; i < iter; i++) { + doOneRandom(format); + } + } + + /** + * Converts an input CSV array into expected output values WRT NULLs. NULL strings are converted to null values + * because the parser will convert these strings to null. + */ + private T[] expectNulls(final T[] original, final CSVFormat csvFormat) { + final T[] fixed = original.clone(); + for (int i = 0; i < fixed.length; i++) { + if (Objects.equals(csvFormat.getNullString(), fixed[i])) { + fixed[i] = null; + } + } + return fixed; + } + + private String[][] generateLines(final int nLines, final int nCol) { + final String[][] lines = new String[nLines][]; + for (int i = 0; i < nLines; i++) { + final String[] line = new String[nCol]; + lines[i] = line; + for (int j = 0; j < nCol; j++) { + line[j] = randStr(); + } + } + return lines; + } + + private Connection getH2Connection() throws SQLException, ClassNotFoundException { + Class.forName("org.h2.Driver"); + return DriverManager.getConnection("jdbc:h2:mem:my_test;", "sa", ""); + } + + private CSVPrinter printWithHeaderComments(final StringWriter sw, final Date now, final CSVFormat baseFormat) + throws IOException { + // Use withHeaderComments first to test CSV-145 + // @formatter:off + final CSVFormat format = baseFormat.builder() + .setHeaderComments("Generated by Apache Commons CSV 1.1", now) + .setCommentMarker('#') + .setHeader("Col1", "Col2") + .build(); + // @formatter:on + final CSVPrinter csvPrinter = format.print(sw); + csvPrinter.printRecord("A", "B"); + csvPrinter.printRecord("C", "D"); + csvPrinter.close(); + return csvPrinter; + } + + private String randStr() { + final Random r = new Random(); + + final int sz = r.nextInt(20); + // sz = r.nextInt(3); + final char[] buf = new char[sz]; + for (int i = 0; i < sz; i++) { + // stick in special chars with greater frequency + final char ch; + final int what = r.nextInt(20); + switch (what) { + case 0: + ch = '\r'; + break; + case 1: + ch = '\n'; + break; + case 2: + ch = '\t'; + break; + case 3: + ch = '\f'; + break; + case 4: + ch = ' '; + break; + case 5: + ch = ','; + break; + case 6: + ch = DQUOTE_CHAR; + break; + case 7: + ch = '\''; + break; + case 8: + ch = BACKSLASH; + break; + default: + ch = (char) r.nextInt(300); + break; + // default: ch = 'a'; break; + } + buf[i] = ch; + } + return new String(buf); + } + + private void setUpTable(final Connection connection) throws SQLException { + try (final Statement statement = connection.createStatement()) { + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), TEXT CLOB)"); + statement.execute("insert into TEST values(1, 'r1', 'long text 1')"); + longText2 = StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 4); + longText2 += "\"\r\n\"a\""; + longText2 += StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 1); + statement.execute("insert into TEST values(2, 'r2', '" + longText2 + "')"); + longText2 = longText2.replace("\"","\"\""); + } + } + + @Test + public void testCloseBackwardCompatibility() throws IOException { + try (final Writer writer = mock(Writer.class)) { + final CSVFormat csvFormat = CSVFormat.DEFAULT; + try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) { + // empty + } + verify(writer, never()).flush(); + verify(writer, times(1)).close(); + }} + + @Test + public void testCloseWithCsvFormatAutoFlushOff() throws IOException { + try (final Writer writer = mock(Writer.class)) { + final CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(false); + try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) { + // empty + } + verify(writer, never()).flush(); + verify(writer, times(1)).close(); + } + } + + @Test + public void testCloseWithCsvFormatAutoFlushOn() throws IOException { + // System.out.println("start method"); + try (final Writer writer = mock(Writer.class)) { + final CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(true); + try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) { + // empty + } + verify(writer, times(1)).flush(); + verify(writer, times(1)).close(); + }} + + @Test + public void testCloseWithFlushOff() throws IOException { + try (final Writer writer = mock(Writer.class)) { + final CSVFormat csvFormat = CSVFormat.DEFAULT; + @SuppressWarnings("resource") + final CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat); + csvPrinter.close(false); + verify(writer, never()).flush(); + verify(writer, times(1)).close(); + } + } + + @Test + public void testCloseWithFlushOn() throws IOException { + try (final Writer writer = mock(Writer.class)) { + @SuppressWarnings("resource") + final CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT); + csvPrinter.close(true); + verify(writer, times(1)).flush(); + } + } + + @Test + public void testCRComment() throws IOException { + final StringWriter sw = new StringWriter(); + final Object value = "abc"; + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) { + printer.print(value); + printer.printComment("This is a comment\r\non multiple lines\rthis is next comment\r"); + assertEquals("abc" + recordSeparator + "# This is a comment" + recordSeparator + "# on multiple lines" + + recordSeparator + "# this is next comment" + recordSeparator + "# " + recordSeparator, sw.toString()); + } + } + + @Test + public void testCSV135() throws IOException { + final List list = new LinkedList<>(); + list.add("\"\""); // "" + list.add("\\\\"); // \\ + list.add("\\\"\\"); // \"\ + // + // "",\\,\"\ (unchanged) + tryFormat(list, null, null, "\"\",\\\\,\\\"\\"); + // + // """""",\\,"\""\" (quoted, and embedded DQ doubled) + tryFormat(list, '"', null, "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); + // + // "",\\\\,\\"\\ (escapes escaped, not quoted) + tryFormat(list, null, '\\', "\"\",\\\\\\\\,\\\\\"\\\\"); + // + // "\"\"","\\\\","\\\"\\" (quoted, and embedded DQ & escape escaped) + tryFormat(list, '"', '\\', "\"\\\"\\\"\",\"\\\\\\\\\",\"\\\\\\\"\\\\\""); + // + // """""",\\,"\""\" (quoted, embedded DQ escaped) + tryFormat(list, '"', '"', "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); + } + + @Test + public void testCSV259() throws IOException { + final StringWriter sw = new StringWriter(); + try (final Reader reader = new FileReader("src/test/resources/org/apache/commons/csv/CSV-259/sample.txt"); + final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape('!').withQuote(null))) { + printer.print(reader); + assertEquals("x!,y!,z", sw.toString()); + } + } + + @Test + public void testDelimeterQuoted() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { + printer.print("a,b,c"); + printer.print("xyz"); + assertEquals("'a,b,c',xyz", sw.toString()); + } + } + + @Test + public void testDelimeterQuoteNone() throws IOException { + final StringWriter sw = new StringWriter(); + final CSVFormat format = CSVFormat.DEFAULT.withEscape('!').withQuoteMode(QuoteMode.NONE); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + printer.print("a,b,c"); + printer.print("xyz"); + assertEquals("a!,b!,c,xyz", sw.toString()); + } + } + + @Test + public void testDelimeterStringQuoted() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.builder().setDelimiter("[|]").setQuote('\'').build())) { + printer.print("a[|]b[|]c"); + printer.print("xyz"); + assertEquals("'a[|]b[|]c'[|]xyz", sw.toString()); + } + } + + @Test + public void testDelimeterStringQuoteNone() throws IOException { + final StringWriter sw = new StringWriter(); + final CSVFormat format = CSVFormat.DEFAULT.builder().setDelimiter("[|]").setEscape('!').setQuoteMode(QuoteMode.NONE).build(); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + printer.print("a[|]b[|]c"); + printer.print("xyz"); + printer.print("a[xy]bc[]"); + assertEquals("a![!|!]b![!|!]c[|]xyz[|]a[xy]bc[]", sw.toString()); + } + } + + @Test + public void testDelimiterEscaped() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape('!').withQuote(null))) { + printer.print("a,b,c"); + printer.print("xyz"); + assertEquals("a!,b!,c,xyz", sw.toString()); + } + } + + @Test + public void testDelimiterPlain() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { + printer.print("a,b,c"); + printer.print("xyz"); + assertEquals("a,b,c,xyz", sw.toString()); + } + } + + @Test + public void testDelimiterStringEscaped() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.builder().setDelimiter("|||").setEscape('!').setQuote(null).build())) { + printer.print("a|||b|||c"); + printer.print("xyz"); + assertEquals("a!|!|!|b!|!|!|c|||xyz", sw.toString()); + } + } + + @Test + public void testDisabledComment() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printComment("This is a comment"); + assertEquals("", sw.toString()); + } + } + + @Test + public void testDontQuoteEuroFirstChar() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.RFC4180)) { + printer.printRecord(EURO_CH, "Deux"); + assertEquals(EURO_CH + ",Deux" + recordSeparator, sw.toString()); + } + } + + @Test + public void testEolEscaped() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withEscape('!'))) { + printer.print("a\rb\nc"); + printer.print("x\fy\bz"); + assertEquals("a!rb!nc,x\fy\bz", sw.toString()); + } + } + + @Test + public void testEolPlain() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { + printer.print("a\rb\nc"); + printer.print("x\fy\bz"); + assertEquals("a\rb\nc,x\fy\bz", sw.toString()); + } + } + + @Test + public void testEolQuoted() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { + printer.print("a\rb\nc"); + printer.print("x\by\fz"); + assertEquals("'a\rb\nc',x\by\fz", sw.toString()); + } + } + + @Test + public void testEscapeBackslash1() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { + printer.print("\\"); + } + assertEquals("\\", sw.toString()); + } + + @Test + public void testEscapeBackslash2() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { + printer.print("\\\r"); + } + assertEquals("'\\\r'", sw.toString()); + } + + @Test + public void testEscapeBackslash3() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { + printer.print("X\\\r"); + } + assertEquals("'X\\\r'", sw.toString()); + } + + @Test + public void testEscapeBackslash4() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { + printer.print("\\\\"); + } + assertEquals("\\\\", sw.toString()); + } + + @Test + public void testEscapeBackslash5() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(QUOTE_CH))) { + printer.print("\\\\"); + } + assertEquals("\\\\", sw.toString()); + } + + @Test + public void testEscapeNull1() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { + printer.print("\\"); + } + assertEquals("\\", sw.toString()); + } + + @Test + public void testEscapeNull2() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { + printer.print("\\\r"); + } + assertEquals("\"\\\r\"", sw.toString()); + } + + @Test + public void testEscapeNull3() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { + printer.print("X\\\r"); + } + assertEquals("\"X\\\r\"", sw.toString()); + } + + @Test + public void testEscapeNull4() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { + printer.print("\\\\"); + } + assertEquals("\\\\", sw.toString()); + } + + @Test + public void testEscapeNull5() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withEscape(null))) { + printer.print("\\\\"); + } + assertEquals("\\\\", sw.toString()); + } + + @Test + public void testExcelPrintAllArrayOfArrays() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecords((Object[]) new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } }); + assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); + } + } + + @Test + public void testExcelPrintAllArrayOfLists() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecords( + (Object[]) new List[] { Arrays.asList("r1c1", "r1c2"), Arrays.asList("r2c1", "r2c2") }); + assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); + } + } + + @Test + public void testExcelPrintAllIterableOfArrays() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecords(Arrays.asList(new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } })); + assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); + } + } + + @Test + public void testExcelPrintAllIterableOfLists() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecords( + Arrays.asList(Arrays.asList("r1c1", "r1c2"), Arrays.asList("r2c1", "r2c2"))); + assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); + } + } + + @Test + public void testExcelPrintAllStreamOfArrays() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecords(Stream.of(new String[][] { { "r1c1", "r1c2" }, { "r2c1", "r2c2" } })); + assertEquals("r1c1,r1c2" + recordSeparator + "r2c1,r2c2" + recordSeparator, sw.toString()); + } + } + + @Test + public void testExcelPrinter1() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecord("a", "b"); + assertEquals("a,b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testExcelPrinter2() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.EXCEL)) { + printer.printRecord("a,b", "b"); + assertEquals("\"a,b\",b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testHeader() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, + CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3"))) { + printer.printRecord("a", "b", "c"); + printer.printRecord("x", "y", "z"); + assertEquals("C1,C2,C3\r\na,b,c\r\nx,y,z\r\n", sw.toString()); + } + } + + @Test + public void testHeaderCommentExcel() throws IOException { + final StringWriter sw = new StringWriter(); + final Date now = new Date(); + final CSVFormat format = CSVFormat.EXCEL; + try (final CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format)) { + assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + "\r\nCol1,Col2\r\nA,B\r\nC,D\r\n", + sw.toString()); + } + } + + @Test + public void testHeaderCommentTdf() throws IOException { + final StringWriter sw = new StringWriter(); + final Date now = new Date(); + final CSVFormat format = CSVFormat.TDF; + try (final CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format)) { + assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + "\r\nCol1\tCol2\r\nA\tB\r\nC\tD\r\n", + sw.toString()); + } + } + + @Test + public void testHeaderNotSet() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { + printer.printRecord("a", "b", "c"); + printer.printRecord("x", "y", "z"); + assertEquals("a,b,c\r\nx,y,z\r\n", sw.toString()); + } + } + + @Test + public void testInvalidFormat() { + assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withDelimiter(CR)); + } + + @Test + public void testJdbcPrinter() throws IOException, ClassNotFoundException, SQLException { + final StringWriter sw = new StringWriter(); + try (final Connection connection = getH2Connection()) { + setUpTable(connection); + try (final Statement stmt = connection.createStatement(); + final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT); + final ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST");) { + printer.printRecords(resultSet); + } + } + assertEquals("1,r1,\"long text 1\"" + recordSeparator + "2,r2,\"" + longText2 + "\"" + recordSeparator, sw.toString()); + } + + @Test + public void testJdbcPrinterWithResultSet() throws IOException, ClassNotFoundException, SQLException { + final StringWriter sw = new StringWriter(); + Class.forName("org.h2.Driver"); + try (final Connection connection = getH2Connection()) { + setUpTable(connection); + try (final Statement stmt = connection.createStatement(); + final ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST"); + final CSVPrinter printer = CSVFormat.DEFAULT.withHeader(resultSet).print(sw)) { + printer.printRecords(resultSet); + } + } + assertEquals("ID,NAME,TEXT" + recordSeparator + "1,r1,\"long text 1\"" + recordSeparator + "2,r2,\"" + longText2 + + "\"" + recordSeparator, sw.toString()); + } + + @Test + public void testJdbcPrinterWithResultSetHeader() throws IOException, ClassNotFoundException, SQLException { + final StringWriter sw = new StringWriter(); + try (final Connection connection = getH2Connection()) { + setUpTable(connection); + try (final Statement stmt = connection.createStatement(); + final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT);) { + try (final ResultSet resultSet = stmt.executeQuery("select ID, NAME from TEST")) { + printer.printRecords(resultSet, true); + assertEquals("ID,NAME" + recordSeparator + "1,r1" + recordSeparator + "2,r2" + recordSeparator, + sw.toString()); + } + try (final ResultSet resultSet = stmt.executeQuery("select ID, NAME from TEST")) { + printer.printRecords(resultSet, false); + assertNotEquals("ID,NAME" + recordSeparator + "1,r1" + recordSeparator + "2,r2" + recordSeparator, + sw.toString()); + } + } + } + } + + @Test + public void testJdbcPrinterWithResultSetMetaData() throws IOException, ClassNotFoundException, SQLException { + final StringWriter sw = new StringWriter(); + Class.forName("org.h2.Driver"); + try (final Connection connection = getH2Connection()) { + setUpTable(connection); + try (final Statement stmt = connection.createStatement(); + final ResultSet resultSet = stmt.executeQuery("select ID, NAME, TEXT from TEST"); + final CSVPrinter printer = CSVFormat.DEFAULT.withHeader(resultSet.getMetaData()).print(sw)) { + printer.printRecords(resultSet); + assertEquals("ID,NAME,TEXT" + recordSeparator + "1,r1,\"long text 1\"" + recordSeparator + "2,r2,\"" + + longText2 + "\"" + recordSeparator, sw.toString()); + } + } + } + + @Test + @Disabled + public void testJira135_part1() throws IOException { + final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); + final StringWriter sw = new StringWriter(); + final List list = new LinkedList<>(); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + list.add("\""); + printer.printRecord(list); + } + final String expected = "\"\\\"\"" + format.getRecordSeparator(); + assertEquals(expected, sw.toString()); + final String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(list.toArray(), format), record0); + } + + @Test + @Disabled + public void testJira135_part2() throws IOException { + final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); + final StringWriter sw = new StringWriter(); + final List list = new LinkedList<>(); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + list.add("\n"); + printer.printRecord(list); + } + final String expected = "\"\\n\"" + format.getRecordSeparator(); + assertEquals(expected, sw.toString()); + final String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(list.toArray(), format), record0); + } + + @Test + @Disabled + public void testJira135_part3() throws IOException { + final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); + final StringWriter sw = new StringWriter(); + final List list = new LinkedList<>(); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + list.add("\\"); + printer.printRecord(list); + } + final String expected = "\"\\\\\"" + format.getRecordSeparator(); + assertEquals(expected, sw.toString()); + final String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(list.toArray(), format), record0); + } + + @Test + @Disabled + public void testJira135All() throws IOException { + final CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator('\n').withQuote(DQUOTE_CHAR).withEscape(BACKSLASH); + final StringWriter sw = new StringWriter(); + final List list = new LinkedList<>(); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + list.add("\""); + list.add("\n"); + list.add("\\"); + printer.printRecord(list); + } + final String expected = "\"\\\"\",\"\\n\",\"\\\"" + format.getRecordSeparator(); + assertEquals(expected, sw.toString()); + final String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(list.toArray(), format), record0); + } + + @Test + public void testMongoDbCsvBasic() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { + printer.printRecord("a", "b"); + assertEquals("a,b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMongoDbCsvCommaInValue() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { + printer.printRecord("a,b", "c"); + assertEquals("\"a,b\",c" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMongoDbCsvDoubleQuoteInValue() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { + printer.printRecord("a \"c\" b", "d"); + assertEquals("\"a \"\"c\"\" b\",d" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMongoDbCsvTabInValue() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_CSV)) { + printer.printRecord("a\tb", "c"); + assertEquals("a\tb,c" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMongoDbTsvBasic() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) { + printer.printRecord("a", "b"); + assertEquals("a\tb" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMongoDbTsvCommaInValue() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) { + printer.printRecord("a,b", "c"); + assertEquals("a,b\tc" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMongoDbTsvTabInValue() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.MONGODB_TSV)) { + printer.printRecord("a\tb", "c"); + assertEquals("\"a\tb\"\tc" + recordSeparator, sw.toString()); + } + } + + @Test + public void testMultiLineComment() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) { + printer.printComment("This is a comment\non multiple lines"); + + assertEquals("# This is a comment" + recordSeparator + "# on multiple lines" + recordSeparator, + sw.toString()); + } + } + + @Test + public void testMySqlNullOutput() throws IOException { + Object[] s = new String[] { "NULL", null }; + CSVFormat format = CSVFormat.MYSQL.withQuote(DQUOTE_CHAR).withNullString("NULL") + .withQuoteMode(QuoteMode.NON_NUMERIC); + StringWriter writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + String expected = "\"NULL\"\tNULL\n"; + assertEquals(expected, writer.toString()); + String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(s, record0); + + s = new String[] { "\\N", null }; + format = CSVFormat.MYSQL.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\t\\N\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\N", "A" }; + format = CSVFormat.MYSQL.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\tA\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\n", "A" }; + format = CSVFormat.MYSQL.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\n\tA\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "", null }; + format = CSVFormat.MYSQL.withNullString("NULL"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\tNULL\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "", null }; + format = CSVFormat.MYSQL; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\t\\N\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\N", "", "\u000e,\\\r" }; + format = CSVFormat.MYSQL; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\t\t\u000e,\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "NULL", "\\\r" }; + format = CSVFormat.MYSQL; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "NULL\t\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\\r" }; + format = CSVFormat.MYSQL; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + } + + @Test + public void testMySqlNullStringDefault() { + assertEquals("\\N", CSVFormat.MYSQL.getNullString()); + } + + @Test + public void testNewCsvPrinterAppendableNullFormat() { + assertThrows(NullPointerException.class, () -> new CSVPrinter(new StringWriter(), null)); + } + + @Test + public void testNewCsvPrinterNullAppendableFormat() { + assertThrows(NullPointerException.class, () -> new CSVPrinter(null, CSVFormat.DEFAULT)); + } + + @Test + public void testNotFlushable() throws IOException { + final Appendable out = new StringBuilder(); + try (final CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT)) { + printer.printRecord("a", "b", "c"); + assertEquals("a,b,c" + recordSeparator, out.toString()); + printer.flush(); + } + } + + @Test + public void testParseCustomNullValues() throws IOException { + final StringWriter sw = new StringWriter(); + final CSVFormat format = CSVFormat.DEFAULT.withNullString("NULL"); + try (final CSVPrinter printer = new CSVPrinter(sw, format)) { + printer.printRecord("a", null, "b"); + } + final String csvString = sw.toString(); + assertEquals("a,NULL,b" + recordSeparator, csvString); + try (final CSVParser iterable = format.parse(new StringReader(csvString))) { + final Iterator iterator = iterable.iterator(); + final CSVRecord record = iterator.next(); + assertEquals("a", record.get(0)); + assertNull(record.get(1)); + assertEquals("b", record.get(2)); + assertFalse(iterator.hasNext()); + } + } + + @Test + public void testPlainEscaped() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null).withEscape('!'))) { + printer.print("abc"); + printer.print("xyz"); + assertEquals("abc,xyz", sw.toString()); + } + } + + @Test + public void testPlainPlain() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { + printer.print("abc"); + printer.print("xyz"); + assertEquals("abc,xyz", sw.toString()); + } + } + + @Test + public void testPlainQuoted() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { + printer.print("abc"); + assertEquals("abc", sw.toString()); + } + } + + @Test + @Disabled + public void testPostgreSqlCsvNullOutput() throws IOException { + Object[] s = new String[] { "NULL", null }; + CSVFormat format = CSVFormat.POSTGRESQL_CSV.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.ALL_NON_NULL); + StringWriter writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + String expected = "\"NULL\",NULL\n"; + assertEquals(expected, writer.toString()); + String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(new Object[2], record0); + + s = new String[] { "\\N", null }; + format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\t\\N\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\N", "A" }; + format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\tA\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\n", "A" }; + format = CSVFormat.POSTGRESQL_CSV.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\n\tA\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "", null }; + format = CSVFormat.POSTGRESQL_CSV.withNullString("NULL"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\tNULL\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "", null }; + format = CSVFormat.POSTGRESQL_CSV; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\t\\N\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\N", "", "\u000e,\\\r" }; + format = CSVFormat.POSTGRESQL_CSV; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\t\t\u000e,\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "NULL", "\\\r" }; + format = CSVFormat.POSTGRESQL_CSV; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "NULL\t\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\\r" }; + format = CSVFormat.POSTGRESQL_CSV; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + } + + @Test + @Disabled + public void testPostgreSqlCsvTextOutput() throws IOException { + Object[] s = new String[] { "NULL", null }; + CSVFormat format = CSVFormat.POSTGRESQL_TEXT.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.ALL_NON_NULL); + StringWriter writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + String expected = "\"NULL\"\tNULL\n"; + assertEquals(expected, writer.toString()); + String[] record0 = toFirstRecordValues(expected, format); + assertArrayEquals(new Object[2], record0); + + s = new String[] { "\\N", null }; + format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\t\\N\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\N", "A" }; + format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\tA\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\n", "A" }; + format = CSVFormat.POSTGRESQL_TEXT.withNullString("\\N"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\n\tA\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "", null }; + format = CSVFormat.POSTGRESQL_TEXT.withNullString("NULL"); + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\tNULL\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "", null }; + format = CSVFormat.POSTGRESQL_TEXT; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\t\\N\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\N", "", "\u000e,\\\r" }; + format = CSVFormat.POSTGRESQL_TEXT; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\N\t\t\u000e,\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "NULL", "\\\r" }; + format = CSVFormat.POSTGRESQL_TEXT; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "NULL\t\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + + s = new String[] { "\\\r" }; + format = CSVFormat.POSTGRESQL_TEXT; + writer = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(writer, format)) { + printer.printRecord(s); + } + expected = "\\\\\\r\n"; + assertEquals(expected, writer.toString()); + record0 = toFirstRecordValues(expected, format); + assertArrayEquals(expectNulls(s, format), record0); + } + + @Test + public void testPostgreSqlNullStringDefaultCsv() { + assertEquals("", CSVFormat.POSTGRESQL_CSV.getNullString()); + } + + @Test + public void testPostgreSqlNullStringDefaultText() { + assertEquals("\\N", CSVFormat.POSTGRESQL_TEXT.getNullString()); + } + + @Test + public void testPrint() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = CSVFormat.DEFAULT.print(sw)) { + printer.printRecord("a", "b\\c"); + assertEquals("a,b\\c" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrintCSVParser() throws IOException { + final String code = "a1,b1\n" // 1) + + "a2,b2\n" // 2) + + "a3,b3\n" // 3) + + "a4,b4\n"// 4) + ; + final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; + final CSVFormat format = CSVFormat.DEFAULT; + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { + printer.printRecords(parser); + } + try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { + final List records = parser.getRecords(); + assertFalse(records.isEmpty()); + Utils.compare("Fail", res, records); + } + } + + @Test + public void testPrintCSVRecord() throws IOException { + final String code = "a1,b1\n" // 1) + + "a2,b2\n" // 2) + + "a3,b3\n" // 3) + + "a4,b4\n"// 4) + ; + final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; + final CSVFormat format = CSVFormat.DEFAULT; + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { + for (final CSVRecord record : parser) { + printer.printRecord(record); + } + } + try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { + final List records = parser.getRecords(); + assertFalse(records.isEmpty()); + Utils.compare("Fail", res, records); + } + } + + @Test + public void testPrintCSVRecords() throws IOException { + final String code = "a1,b1\n" // 1) + + "a2,b2\n" // 2) + + "a3,b3\n" // 3) + + "a4,b4\n"// 4) + ; + final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; + final CSVFormat format = CSVFormat.DEFAULT; + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { + printer.printRecords(parser.getRecords()); + } + try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { + final List records = parser.getRecords(); + assertFalse(records.isEmpty()); + Utils.compare("Fail", res, records); + } + } + + @Test + public void testPrintCustomNullValues() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withNullString("NULL"))) { + printer.printRecord("a", null, "b"); + assertEquals("a,NULL,b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter1() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a", "b"); + assertEquals("a,b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter2() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a,b", "b"); + assertEquals("\"a,b\",b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter3() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a, b", "b "); + assertEquals("\"a, b\",\"b \"" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter4() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a", "b\"c"); + assertEquals("a,\"b\"\"c\"" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter5() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a", "b\nc"); + assertEquals("a,\"b\nc\"" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter6() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a", "b\r\nc"); + assertEquals("a,\"b\r\nc\"" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrinter7() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a", "b\\c"); + assertEquals("a,b\\c" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrintNullValues() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) { + printer.printRecord("a", null, "b"); + assertEquals("a,,b" + recordSeparator, sw.toString()); + } + } + + @Test + public void testPrintOnePositiveInteger() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.MINIMAL))) { + printer.print(Integer.MAX_VALUE); + assertEquals(String.valueOf(Integer.MAX_VALUE), sw.toString()); + } + } + + /** + * Test to target the use of {@link IOUtils#copy(java.io.Reader, Appendable)} which directly + * buffers the value from the Reader to the Appendable. + * + *

Requires the format to have no quote or escape character, value to be a + * {@link java.io.Reader Reader} and the output MUST NOT be a + * {@link java.io.Writer Writer} but some other Appendable.

+ * + * @throws IOException Not expected to happen + */ + @Test + public void testPrintReaderWithoutQuoteToAppendable() throws IOException { + final StringBuilder sb = new StringBuilder(); + final String content = "testValue"; + try (final CSVPrinter printer = new CSVPrinter(sb, CSVFormat.DEFAULT.withQuote(null))) { + final StringReader value = new StringReader(content); + printer.print(value); + } + assertEquals(content, sb.toString()); + } + + /** + * Test to target the use of {@link IOUtils#copyLarge(java.io.Reader, Writer)} which directly + * buffers the value from the Reader to the Writer. + * + *

Requires the format to have no quote or escape character, value to be a + * {@link java.io.Reader Reader} and the output MUST be a + * {@link java.io.Writer Writer}.

+ * + * @throws IOException Not expected to happen + */ + @Test + public void testPrintReaderWithoutQuoteToWriter() throws IOException { + final StringWriter sw = new StringWriter(); + final String content = "testValue"; + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote(null))) { + final StringReader value = new StringReader(content); + printer.print(value); + } + assertEquals(content, sw.toString()); + } + + @Test + public void testPrintRecordStream() throws IOException { + final String code = "a1,b1\n" // 1) + + "a2,b2\n" // 2) + + "a3,b3\n" // 3) + + "a4,b4\n"// 4) + ; + final String[][] res = {{"a1", "b1"}, {"a2", "b2"}, {"a3", "b3"}, {"a4", "b4"}}; + final CSVFormat format = CSVFormat.DEFAULT; + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = format.print(sw); final CSVParser parser = CSVParser.parse(code, format)) { + for (final CSVRecord record : parser) { + printer.printRecord(record.stream()); + } + } + try (final CSVParser parser = CSVParser.parse(sw.toString(), format)) { + final List records = parser.getRecords(); + assertFalse(records.isEmpty()); + Utils.compare("Fail", res, records); + } + } + + @Test + public void testPrintRecordsWithCSVRecord() throws IOException { + final String[] values = {"A", "B", "C"}; + final String rowData = StringUtils.join(values, ','); + final CharArrayWriter charArrayWriter = new CharArrayWriter(0); + try (final CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(rowData)); + final CSVPrinter csvPrinter = CSVFormat.INFORMIX_UNLOAD.print(charArrayWriter)) { + for (final CSVRecord record : parser) { + csvPrinter.printRecord(record); + } + } + assertEquals(6, charArrayWriter.size()); + assertEquals("A|B|C" + CSVFormat.INFORMIX_UNLOAD.getRecordSeparator(), charArrayWriter.toString()); + } + + @Test + public void testPrintRecordsWithEmptyVector() throws IOException { + final PrintStream out = System.out; + try { + System.setOut(new PrintStream(NullOutputStream.NULL_OUTPUT_STREAM)); + try (CSVPrinter csvPrinter = CSVFormat.POSTGRESQL_TEXT.printer()) { + final Vector vector = new Vector<>(); + final int expectedCapacity = 23; + vector.setSize(expectedCapacity); + csvPrinter.printRecords(vector); + assertEquals(expectedCapacity, vector.capacity()); + } + } finally { + System.setOut(out); + } + } + + @Test + public void testPrintRecordsWithObjectArray() throws IOException { + final CharArrayWriter charArrayWriter = new CharArrayWriter(0); + try (CSVPrinter csvPrinter = CSVFormat.INFORMIX_UNLOAD.print(charArrayWriter)) { + final HashSet hashSet = new HashSet<>(); + final Object[] objectArray = new Object[6]; + objectArray[3] = hashSet; + csvPrinter.printRecords(objectArray); + } + assertEquals(6, charArrayWriter.size()); + assertEquals("\n\n\n\n\n\n", charArrayWriter.toString()); + } + + @Test + public void testPrintRecordsWithResultSetOneRow() throws IOException, SQLException { + try (CSVPrinter csvPrinter = CSVFormat.MYSQL.printer()) { + try (ResultSet resultSet = new SimpleResultSet()) { + csvPrinter.printRecords(resultSet); + assertEquals(0, resultSet.getRow()); + } + } + } + + @Test + public void testPrintToFileWithCharsetUtf16Be() throws IOException { + final File file = File.createTempFile(getClass().getName(), ".csv"); + try (final CSVPrinter printer = CSVFormat.DEFAULT.print(file, StandardCharsets.UTF_16BE)) { + printer.printRecord("a", "b\\c"); + } + assertEquals("a,b\\c" + recordSeparator, FileUtils.readFileToString(file, StandardCharsets.UTF_16BE)); + } + + @Test + public void testPrintToFileWithDefaultCharset() throws IOException { + final File file = File.createTempFile(getClass().getName(), ".csv"); + try (final CSVPrinter printer = CSVFormat.DEFAULT.print(file, Charset.defaultCharset())) { + printer.printRecord("a", "b\\c"); + } + assertEquals("a,b\\c" + recordSeparator, FileUtils.readFileToString(file, Charset.defaultCharset())); + } + + @Test + public void testPrintToPathWithDefaultCharset() throws IOException { + final File file = File.createTempFile(getClass().getName(), ".csv"); + try (final CSVPrinter printer = CSVFormat.DEFAULT.print(file.toPath(), Charset.defaultCharset())) { + printer.printRecord("a", "b\\c"); + } + assertEquals("a,b\\c" + recordSeparator, FileUtils.readFileToString(file, Charset.defaultCharset())); + } + + @Test + public void testQuoteAll() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.ALL))) { + printer.printRecord("a", "b\nc", "d"); + assertEquals("\"a\",\"b\nc\",\"d\"" + recordSeparator, sw.toString()); + } + } + + @Test + public void testQuoteCommaFirstChar() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.RFC4180)) { + printer.printRecord(","); + assertEquals("\",\"" + recordSeparator, sw.toString()); + } + } + + @Test + public void testQuoteNonNumeric() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuoteMode(QuoteMode.NON_NUMERIC))) { + printer.printRecord("a", "b\nc", Integer.valueOf(1)); + assertEquals("\"a\",\"b\nc\",1" + recordSeparator, sw.toString()); + } + } + + @Test + public void testRandomDefault() throws Exception { + doRandom(CSVFormat.DEFAULT, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + public void testRandomExcel() throws Exception { + doRandom(CSVFormat.EXCEL, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + @Disabled + public void testRandomMongoDbCsv() throws Exception { + doRandom(CSVFormat.MONGODB_CSV, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + public void testRandomMySql() throws Exception { + doRandom(CSVFormat.MYSQL, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + @Disabled + public void testRandomOracle() throws Exception { + doRandom(CSVFormat.ORACLE, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + @Disabled + public void testRandomPostgreSqlCsv() throws Exception { + doRandom(CSVFormat.POSTGRESQL_CSV, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + @Disabled + public void testRandomPostgreSqlText() throws Exception { + doRandom(CSVFormat.POSTGRESQL_TEXT, ITERATIONS_FOR_RANDOM_TEST); + } + + + @Test + public void testRandomRfc4180() throws Exception { + doRandom(CSVFormat.RFC4180, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + public void testRandomTdf() throws Exception { + doRandom(CSVFormat.TDF, ITERATIONS_FOR_RANDOM_TEST); + } + + @Test + public void testSingleLineComment() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withCommentMarker('#'))) { + printer.printComment("This is a comment"); + assertEquals("# This is a comment" + recordSeparator, sw.toString()); + } + } + + @Test + public void testSingleQuoteQuoted() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withQuote('\''))) { + printer.print("a'b'c"); + printer.print("xyz"); + assertEquals("'a''b''c',xyz", sw.toString()); + } + } + + @Test + public void testSkipHeaderRecordFalse() throws IOException { + // functionally identical to testHeader, used to test CSV-153 + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, + CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3").withSkipHeaderRecord(false))) { + printer.printRecord("a", "b", "c"); + printer.printRecord("x", "y", "z"); + assertEquals("C1,C2,C3\r\na,b,c\r\nx,y,z\r\n", sw.toString()); + } + } + + @Test + public void testSkipHeaderRecordTrue() throws IOException { + // functionally identical to testHeaderNotSet, used to test CSV-153 + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, + CSVFormat.DEFAULT.withQuote(null).withHeader("C1", "C2", "C3").withSkipHeaderRecord(true))) { + printer.printRecord("a", "b", "c"); + printer.printRecord("x", "y", "z"); + assertEquals("a,b,c\r\nx,y,z\r\n", sw.toString()); + } + } + + @Test + public void testTrailingDelimiterOnTwoColumns() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrailingDelimiter())) { + printer.printRecord("A", "B"); + assertEquals("A,B,\r\n", sw.toString()); + } + } + + @Test + public void testTrimOffOneColumn() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim(false))) { + printer.print(" A "); + assertEquals("\" A \"", sw.toString()); + } + } + + @Test + public void testTrimOnOneColumn() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim())) { + printer.print(" A "); + assertEquals("A", sw.toString()); + } + } + + @Test + public void testTrimOnTwoColumns() throws IOException { + final StringWriter sw = new StringWriter(); + try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withTrim())) { + printer.print(" A "); + printer.print(" B "); + assertEquals("A,B", sw.toString()); + } + } + + private String[] toFirstRecordValues(final String expected, final CSVFormat format) throws IOException { + return CSVParser.parse(expected, format).getRecords().get(0).values(); + } + + private void tryFormat(final List list, final Character quote, final Character escape, final String expected) throws IOException { + final CSVFormat format = CSVFormat.DEFAULT.withQuote(quote).withEscape(escape).withRecordSeparator(null); + final Appendable out = new StringBuilder(); + try (final CSVPrinter printer = new CSVPrinter(out, format)) { + printer.printRecord(list); + } + assertEquals(expected, out.toString()); + } +}