Merge branch 'master' into release
This commit is contained in:
commit
660f7c9f85
|
@ -5,14 +5,16 @@
|
|||
|
||||
INTRODUCTION:
|
||||
|
||||
This document contains the release notes for the 1.8 version of Apache Commons CSV.
|
||||
This document contains the release notes for the 1.8-SNAPSHOT version of Apache Commons CSV.
|
||||
Commons CSV reads and writes files in variations of the Comma Separated Value (CSV) format.
|
||||
|
||||
Commons CSV requires at least Java 6.
|
||||
|
||||
The Apache Commons CSV library provides a simple interface for reading and writing CSV files of various types.
|
||||
|
||||
Feature and bug fix release (Java 8)
|
||||
Feature and bug fix release (Java 8).
|
||||
This release fixes serialization compatibility of CSVRecord with versions 1.0 to 1.6. New fields added since
|
||||
1.7 are not serialized. Support for Serializable is scheduled to be removed in version 2.0.
|
||||
|
||||
Changes in this version include:
|
||||
|
||||
|
@ -32,6 +34,7 @@ o CSV-241: CSVFormat#validate() does not account for allowDuplicateHeaderNames
|
|||
o CSV-245: Post 1.7 release fixes. Thanks to Alex Herbert.
|
||||
o CSV-252: Upgrade test framework to JUnit 5 Jupiter #49, #50. Thanks to Alex Herbert.
|
||||
o CSV-247: A single empty header is allowed when not allowing empty column headers. #47. Thanks to Alex Herbert, Gary Gregory.
|
||||
o CSV-248: CSVRecord is not Serializable. Thanks to Alex Herbert.
|
||||
o Use test scope for supercsv #48. Thanks to Alex Herbert.
|
||||
|
||||
CHANGES
|
||||
|
@ -41,6 +44,7 @@ o Update tests from H2 1.4.199 to 1.4.200. Thanks to Gary Gregory.
|
|||
o Update tests from Hamcrest 2.1 to 2.2. Thanks to Gary Gregory.
|
||||
o Update tests from Mockito 3.1.0 to 3.2.4. Thanks to Gary Gregory.
|
||||
o Fix typos in site and test #53. Thanks to Chen.
|
||||
o Fix typo performance test #55. Thanks to Chen.
|
||||
|
||||
|
||||
Historical list of changes: https://commons.apache.org/proper/commons-csv/changes-report.html
|
||||
|
|
6
pom.xml
6
pom.xml
|
@ -32,7 +32,7 @@
|
|||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.5.2</version>
|
||||
<version>5.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -140,7 +140,7 @@
|
|||
<commons.release.version>1.8</commons.release.version>
|
||||
<commons.release.desc>(Java 8)</commons.release.desc>
|
||||
<!-- The RC version used in the staging repository URL. -->
|
||||
<commons.rc.version>RC1</commons.rc.version>
|
||||
<commons.rc.version>RC2</commons.rc.version>
|
||||
<commons.bc.version>1.7</commons.bc.version>
|
||||
<commons.componentid>csv</commons.componentid>
|
||||
<commons.module.name>org.apache.commons.csv</commons.module.name>
|
||||
|
@ -258,6 +258,7 @@
|
|||
<!-- The ferc.gov files are included discussion in https://issues.apache.org/jira/browse/LEGAL-175. -->
|
||||
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
|
||||
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
|
||||
<exclude>src/test/resources/**/*.bin</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
@ -376,6 +377,7 @@
|
|||
<exclude>src/test/resources/CSVFileParser/testCSV85_ignoreEmpty.txt</exclude>
|
||||
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
|
||||
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
|
||||
<exclude>src/test/resources/**/*.bin</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -38,7 +38,12 @@
|
|||
<title>Apache Commons CSV Release Notes</title>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="1.8" date="2019-01-18" description="Feature and bug fix release (Java 8)">
|
||||
<release version="1.8" date="2019-02-01" description="Feature and bug fix release (Java 8).
|
||||
|
||||
This release fixes serialization compatibility of CSVRecord with versions 1.0 to 1.6.
|
||||
New fields added since 1.7 are not serialized. Support for Serializable is scheduled to be
|
||||
removed in version 2.0.
|
||||
">
|
||||
<action issue="CSV-255" type="add" dev="ggregory" due-to="0x100">Add CSVRecord.isSet(int) method #52.</action>
|
||||
<action issue="CSV-135" type="fix" dev="sebb" due-to="Mateusz Zakarczemny">Char escape doesn't work properly with quoting.</action>
|
||||
<action issue="CSV-244" type="fix" dev="sebb">Test case failures following CSVFormat#equals() update.</action>
|
||||
|
@ -48,11 +53,13 @@
|
|||
<action issue="CSV-245" type="fix" dev="ggregory" due-to="Alex Herbert">Post 1.7 release fixes.</action>
|
||||
<action issue="CSV-252" type="fix" dev="ggregory" due-to= "Alex Herbert">Upgrade test framework to JUnit 5 Jupiter #49, #50.</action>
|
||||
<action issue="CSV-247" type="fix" dev="ggregory" due-to="Alex Herbert, Gary Gregory">A single empty header is allowed when not allowing empty column headers. #47.</action>
|
||||
<action issue="CSV-248" type="fix" dev="ggregory" due-to="Alex Herbert">CSVRecord is not Serializable.</action>
|
||||
<action type="fix" dev="ggregory" due-to="Alex Herbert">Use test scope for supercsv #48.</action>
|
||||
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from H2 1.4.199 to 1.4.200.</action>
|
||||
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Hamcrest 2.1 to 2.2.</action>
|
||||
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Mockito 3.1.0 to 3.2.4.</action>
|
||||
<action type="update" dev="ggregory" due-to="Chen">Fix typos in site and test #53.</action>
|
||||
<action type="update" dev="ggregory" due-to="Chen">Fix typo performance test #55.</action>
|
||||
</release>
|
||||
<release version="1.7" date="2019-06-01" description="Feature and bug fix release (Java 8)">
|
||||
<action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action>
|
||||
|
|
|
@ -555,6 +555,11 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||
* <p>
|
||||
* The map keys are column names. The map values are 0-based indices.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: The map can only provide a one-to-one mapping when the format did not
|
||||
* contain null or duplicate column names.
|
||||
* </p>
|
||||
*
|
||||
* @return a copy of the header map.
|
||||
*/
|
||||
public Map<String, Integer> getHeaderMap() {
|
||||
|
@ -577,8 +582,14 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||
|
||||
/**
|
||||
* Returns a read-only list of header names that iterates in column order.
|
||||
* <p>
|
||||
* Note: The list provides strings that can be used as keys in the header map.
|
||||
* The list will not contain null column names if they were present in the input
|
||||
* format.
|
||||
* </p>
|
||||
*
|
||||
* @return read-only list of header names that iterates in column order.
|
||||
* @see #getHeaderMap()
|
||||
* @since 1.7
|
||||
*/
|
||||
public List<String> getHeaderNames() {
|
||||
|
|
|
@ -24,9 +24,19 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A CSV record parsed from a CSV file.
|
||||
*
|
||||
* <p>
|
||||
* Note: Support for {@link Serializable} is scheduled to be removed in version 2.0.
|
||||
* In version 1.8 the mapping between the column header and the column index was
|
||||
* removed from the serialised state. The class maintains serialization compatibility
|
||||
* with versions pre-1.8 for the record values; these must be accessed by index
|
||||
* following deserialization. There will be loss of any functionally linked to the header
|
||||
* mapping when transferring serialised forms pre-1.8 to 1.8 and vice versa.
|
||||
* </p>
|
||||
*/
|
||||
public final class CSVRecord implements Serializable, Iterable<String> {
|
||||
|
||||
|
@ -45,8 +55,8 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||
/** The values of the record */
|
||||
private final String[] values;
|
||||
|
||||
/** The parser that originates this record. */
|
||||
private final CSVParser parser;
|
||||
/** The parser that originates this record. This is not serialized. */
|
||||
private final transient CSVParser parser;
|
||||
|
||||
CSVRecord(final CSVParser parser, final String[] values, final String comment, final long recordNumber,
|
||||
final long characterPosition) {
|
||||
|
@ -65,7 +75,7 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||
* @return the String at the given enum String
|
||||
*/
|
||||
public String get(final Enum<?> e) {
|
||||
return get(e.toString());
|
||||
return get(Objects.toString(e, null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,6 +92,14 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||
/**
|
||||
* Returns a value by name.
|
||||
*
|
||||
* <p>
|
||||
* Note: This requires a field mapping obtained from the original parser.
|
||||
* A check using {@link #isMapped(String)} should be used to determine if a
|
||||
* mapping exists from the provided {@code name} to a field index. In this case an
|
||||
* exception will only be thrown if the record does not contain a field corresponding
|
||||
* to the mapping, that is the record length is not consistent with the mapping size.
|
||||
* </p>
|
||||
*
|
||||
* @param name
|
||||
* the name of the column to be retrieved.
|
||||
* @return the column value, maybe null depending on {@link CSVFormat#getNullString()}.
|
||||
|
@ -89,7 +107,9 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||
* if no header mapping was provided
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code name} is not mapped or if the record is inconsistent
|
||||
* @see #isMapped(String)
|
||||
* @see #isConsistent()
|
||||
* @see #getParser()
|
||||
* @see CSVFormat#withNullString(String)
|
||||
*/
|
||||
public String get(final String name) {
|
||||
|
@ -135,12 +155,17 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||
}
|
||||
|
||||
private Map<String, Integer> getHeaderMapRaw() {
|
||||
return parser.getHeaderMapRaw();
|
||||
return parser == null ? null : parser.getHeaderMapRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parser.
|
||||
*
|
||||
* <p>
|
||||
* Note: The parser is not part of the serialized state of the record. A null check
|
||||
* should be used when the record may have originated from a serialized form.
|
||||
* </p>
|
||||
*
|
||||
* @return the parser.
|
||||
* @since 1.7
|
||||
*/
|
||||
|
|
|
@ -32,7 +32,7 @@ limitations under the License.
|
|||
|
||||
Parsing files with Apache Commons CSV is relatively straight forward.
|
||||
The CSVFormat class provides some commonly used CSV variants:
|
||||
|
||||
|
||||
<dl>
|
||||
<dt><a href="https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#DEFAULT">DEFAULT</a></dt><dd>Standard Comma Separated Value format, as for RFC4180 but allowing empty lines.</dd>
|
||||
<dt><a href="https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#EXCEL">EXCEL</a></dt><dd>The Microsoft Excel CSV format.</dd>
|
||||
|
|
|
@ -79,7 +79,7 @@ public class CSVBenchmark {
|
|||
while ((line = in.readLine()) != null) {
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
bh.consume(count);
|
||||
in.close();
|
||||
return count;
|
||||
|
@ -94,7 +94,7 @@ public class CSVBenchmark {
|
|||
final String[] values = StringUtils.split(line, ',');
|
||||
count += values.length;
|
||||
}
|
||||
|
||||
|
||||
bh.consume(count);
|
||||
in.close();
|
||||
return count;
|
||||
|
@ -103,7 +103,7 @@ public class CSVBenchmark {
|
|||
@Benchmark
|
||||
public int parseCommonsCSV(final Blackhole bh) throws Exception {
|
||||
final BufferedReader in = getReader();
|
||||
|
||||
|
||||
final CSVFormat format = CSVFormat.DEFAULT.withHeader();
|
||||
|
||||
int count = 0;
|
||||
|
@ -119,7 +119,7 @@ public class CSVBenchmark {
|
|||
@Benchmark
|
||||
public int parseGenJavaCSV(final Blackhole bh) throws Exception {
|
||||
final BufferedReader in = getReader();
|
||||
|
||||
|
||||
final CsvReader reader = new CsvReader(in);
|
||||
reader.setFieldDelimiter(',');
|
||||
|
||||
|
@ -137,7 +137,7 @@ public class CSVBenchmark {
|
|||
@Benchmark
|
||||
public int parseJavaCSV(final Blackhole bh) throws Exception {
|
||||
final BufferedReader in = getReader();
|
||||
|
||||
|
||||
final com.csvreader.CsvReader reader = new com.csvreader.CsvReader(in, ',');
|
||||
reader.setRecordDelimiter('\n');
|
||||
|
||||
|
@ -154,7 +154,7 @@ public class CSVBenchmark {
|
|||
@Benchmark
|
||||
public int parseOpenCSV(final Blackhole bh) throws Exception {
|
||||
final BufferedReader in = getReader();
|
||||
|
||||
|
||||
final com.opencsv.CSVReader reader = new com.opencsv.CSVReader(in, ',');
|
||||
|
||||
int count = 0;
|
||||
|
@ -170,10 +170,10 @@ public class CSVBenchmark {
|
|||
@Benchmark
|
||||
public int parseSkifeCSV(final Blackhole bh) throws Exception {
|
||||
final BufferedReader in = getReader();
|
||||
|
||||
|
||||
final org.skife.csv.CSVReader reader = new org.skife.csv.SimpleReader();
|
||||
reader.setSeperator(',');
|
||||
|
||||
|
||||
final CountingReaderCallback callback = new CountingReaderCallback();
|
||||
reader.parse(in, callback);
|
||||
|
||||
|
@ -194,7 +194,7 @@ public class CSVBenchmark {
|
|||
@Benchmark
|
||||
public int parseSuperCSV(final Blackhole bh) throws Exception {
|
||||
final BufferedReader in = getReader();
|
||||
|
||||
|
||||
final CsvListReader reader = new CsvListReader(in, CsvPreference.STANDARD_PREFERENCE);
|
||||
|
||||
int count = 0;
|
||||
|
|
|
@ -42,7 +42,7 @@ public class CSVFileParserTest {
|
|||
|
||||
private static final File BASE = new File("src/test/resources/CSVFileParser");
|
||||
|
||||
private String readTestData(BufferedReader reader) throws IOException {
|
||||
private String readTestData(final BufferedReader reader) throws IOException {
|
||||
String line;
|
||||
do {
|
||||
line = reader.readLine();
|
||||
|
@ -61,7 +61,7 @@ public class CSVFileParserTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("generateData")
|
||||
public void testCSVFile(File testFile) throws Exception {
|
||||
public void testCSVFile(final File testFile) throws Exception {
|
||||
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
|
||||
String line = readTestData(testData);
|
||||
assertNotNull("file must contain config line", line);
|
||||
|
@ -108,7 +108,7 @@ public class CSVFileParserTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("generateData")
|
||||
public void testCSVUrl(File testFile) throws Exception {
|
||||
public void testCSVUrl(final File testFile) throws Exception {
|
||||
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
|
||||
String line = readTestData(testData);
|
||||
assertNotNull("file must contain config line", line);
|
||||
|
|
|
@ -64,7 +64,7 @@ public class CSVFormatTest {
|
|||
return format.withDelimiter(format.getDelimiter());
|
||||
}
|
||||
|
||||
private void assertNotEquals(String name, String type, Object left, Object right) {
|
||||
private void assertNotEquals(final String name, final String type, final Object left, final Object right) {
|
||||
if (left.equals(right) || right.equals(left)) {
|
||||
fail("Objects must not compare equal for " + name + "(" + type + ")");
|
||||
}
|
||||
|
@ -153,12 +153,12 @@ public class CSVFormatTest {
|
|||
|
||||
@Test
|
||||
public void testEqualsHash() throws Exception {
|
||||
Method[] methods = CSVFormat.class.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
final Method[] methods = CSVFormat.class.getDeclaredMethods();
|
||||
for (final Method method : methods) {
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
final String name = method.getName();
|
||||
if (name.startsWith("with")) {
|
||||
for (Class<?> cls : method.getParameterTypes()) {
|
||||
for (final Class<?> cls : method.getParameterTypes()) {
|
||||
final String type = cls.getCanonicalName();
|
||||
if ("boolean".equals(type)) {
|
||||
final Object defTrue = method.invoke(CSVFormat.DEFAULT, new Object[] {Boolean.TRUE});
|
||||
|
@ -550,7 +550,7 @@ public class CSVFormatTest {
|
|||
|
||||
final CSVFormat csvFormat = CSVFormat.MYSQL;
|
||||
|
||||
NullPointerException e = assertThrows(NullPointerException.class, () -> csvFormat.format((Object[]) null));
|
||||
final NullPointerException e = assertThrows(NullPointerException.class, () -> csvFormat.format((Object[]) null));
|
||||
assertEquals(CSVFormat.class.getName(), e.getStackTrace()[0].getClassName());
|
||||
}
|
||||
|
||||
|
|
|
@ -724,6 +724,20 @@ public class CSVParserTest {
|
|||
assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadersWithNullColumnName() throws IOException {
|
||||
final Reader in = new StringReader("header1,null,header3\n1,2,3\n4,5,6");
|
||||
final Iterator<CSVRecord> records = CSVFormat.DEFAULT
|
||||
.withHeader()
|
||||
.withNullString("null")
|
||||
.withAllowMissingColumnNames()
|
||||
.parse(in).iterator();
|
||||
final CSVRecord record = records.next();
|
||||
// Expect the null header to be missing
|
||||
assertEquals(Arrays.asList("header1", "header3"), record.getParser().getHeaderNames());
|
||||
assertEquals(2, record.getParser().getHeaderMap().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreCaseHeaderMapping() throws Exception {
|
||||
final Reader reader = new StringReader("1,2,3");
|
||||
|
|
|
@ -289,15 +289,25 @@ public class CSVPrinterTest {
|
|||
|
||||
@Test
|
||||
public void testCSV135() throws IOException {
|
||||
List<String> l = new LinkedList<String>();
|
||||
l.add("\"\""); // ""
|
||||
l.add("\\\\"); // \\
|
||||
l.add("\\\"\\"); // \"\
|
||||
tryFormat(l, null, null, "\"\",\\\\,\\\"\\"); // "",\\,\"\ (unchanged)
|
||||
tryFormat(l, '"', null, "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); // """""",\\,"\""\" (quoted, and embedded DQ doubled)
|
||||
tryFormat(l, null, '\\', "\"\",\\\\\\\\,\\\\\"\\\\"); // "",\\\\,\\"\\ (escapes escaped, not quoted)
|
||||
tryFormat(l, '"', '\\', "\"\\\"\\\"\",\"\\\\\\\\\",\"\\\\\\\"\\\\\""); // "\"\"","\\\\","\\\"\\" (quoted, and embedded DQ & escape escaped)
|
||||
tryFormat(l, '"', '"', "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); // """""",\\,"\""\" (quoted, embedded DQ escaped)
|
||||
final List<String> 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
|
||||
|
@ -772,7 +782,8 @@ public class CSVPrinterTest {
|
|||
@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);
|
||||
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);
|
||||
|
@ -1519,10 +1530,10 @@ public class CSVPrinterTest {
|
|||
return CSVParser.parse(expected, format).getRecords().get(0).values();
|
||||
}
|
||||
|
||||
private void tryFormat(List<String> l, Character quote, Character escape, String expected) throws IOException {
|
||||
CSVFormat format = CSVFormat.DEFAULT.withQuote(quote).withEscape(escape).withRecordSeparator(null);
|
||||
Appendable out = new StringBuilder();
|
||||
CSVPrinter printer = new CSVPrinter(out, format);
|
||||
private void tryFormat(final List<String> l, 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();
|
||||
final CSVPrinter printer = new CSVPrinter(out, format);
|
||||
printer.printRecord(l);
|
||||
printer.close();
|
||||
assertEquals(expected, out.toString());
|
||||
|
|
|
@ -23,10 +23,15 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
|||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -41,9 +46,9 @@ public class CSVRecordTest {
|
|||
UNKNOWN_COLUMN
|
||||
}
|
||||
|
||||
private String[] values;
|
||||
private CSVRecord record, recordWithHeader;
|
||||
private Map<String, Integer> headerMap;
|
||||
private CSVRecord record, recordWithHeader;
|
||||
private String[] values;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
@ -89,6 +94,11 @@ public class CSVRecordTest {
|
|||
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNullEnum() {
|
||||
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get((Enum<?>) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnmappedName() {
|
||||
assertThrows(IllegalArgumentException.class, () -> assertNull(recordWithHeader.get("fourth")));
|
||||
|
@ -133,13 +143,6 @@ public class CSVRecordTest {
|
|||
assertFalse(recordWithHeader.isMapped("fourth"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSetString() {
|
||||
assertFalse(record.isSet("first"));
|
||||
assertTrue(recordWithHeader.isSet("first"));
|
||||
assertFalse(recordWithHeader.isSet("fourth"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSetInt() {
|
||||
assertFalse(record.isSet(-1));
|
||||
|
@ -150,6 +153,13 @@ public class CSVRecordTest {
|
|||
assertFalse(recordWithHeader.isSet(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSetString() {
|
||||
assertFalse(record.isSet("first"));
|
||||
assertTrue(recordWithHeader.isSet("first"));
|
||||
assertFalse(recordWithHeader.isSet("fourth"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIterator() {
|
||||
int i = 0;
|
||||
|
@ -185,17 +195,47 @@ public class CSVRecordTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testToMap() {
|
||||
final Map<String, String> map = this.recordWithHeader.toMap();
|
||||
this.validateMap(map, true);
|
||||
public void testSerialization() throws IOException, ClassNotFoundException {
|
||||
CSVRecord shortRec;
|
||||
try (final CSVParser parser = CSVParser.parse("A,B\n#my comment\nOne,Two", CSVFormat.DEFAULT.withHeader().withCommentMarker('#'))) {
|
||||
shortRec = parser.iterator().next();
|
||||
}
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
|
||||
oos.writeObject(shortRec);
|
||||
}
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
try (ObjectInputStream ois = new ObjectInputStream(in)) {
|
||||
final Object object = ois.readObject();
|
||||
assertTrue(object instanceof CSVRecord);
|
||||
final CSVRecord rec = (CSVRecord) object;
|
||||
assertEquals(1L, rec.getRecordNumber());
|
||||
assertEquals("One", rec.get(0));
|
||||
assertEquals("Two", rec.get(1));
|
||||
assertEquals(2, rec.size());
|
||||
assertEquals(shortRec.getCharacterPosition(), rec.getCharacterPosition());
|
||||
assertEquals("my comment", rec.getComment());
|
||||
// The parser is not serialized
|
||||
assertNull(rec.getParser());
|
||||
// Check all header map functionality is absent
|
||||
assertTrue(rec.isConsistent());
|
||||
assertFalse(rec.isMapped("A"));
|
||||
assertFalse(rec.isSet("A"));
|
||||
assertEquals(0, rec.toMap().size());
|
||||
// This will throw
|
||||
try {
|
||||
rec.get("A");
|
||||
org.junit.jupiter.api.Assertions.fail("Access by name is not expected after deserialisation");
|
||||
} catch (final IllegalStateException expected) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMapWithShortRecord() throws Exception {
|
||||
try (final CSVParser parser = CSVParser.parse("a,b", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
|
||||
final CSVRecord shortRec = parser.iterator().next();
|
||||
shortRec.toMap();
|
||||
}
|
||||
public void testToMap() {
|
||||
final Map<String, String> map = this.recordWithHeader.toMap();
|
||||
this.validateMap(map, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -208,6 +248,14 @@ public class CSVRecordTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMapWithShortRecord() throws Exception {
|
||||
try (final CSVParser parser = CSVParser.parse("a,b", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
|
||||
final CSVRecord shortRec = parser.iterator().next();
|
||||
shortRec.toMap();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMap(final Map<String, String> map, final boolean allowsNulls) {
|
||||
assertTrue(map.containsKey("first"));
|
||||
assertTrue(map.containsKey("second"));
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.nio.charset.StandardCharsets;
|
|||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.apache.commons.csv.QuoteMode;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.issues;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
public class JiraCsv248Test {
|
||||
/**
|
||||
* Test deserialisation of a CSVRecord created using version 1.6.
|
||||
*
|
||||
* <p>This test asserts that serialization from 1.8 onwards is consistent with
|
||||
* previous versions. Serialization was broken in version 1.7.
|
||||
*
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
* @throws ClassNotFoundException If the CSVRecord cannot be deserialized
|
||||
*/
|
||||
@Test
|
||||
public void testJiraCsv248() throws IOException, ClassNotFoundException {
|
||||
// Record was originally created using CSV version 1.6 with the following code:
|
||||
//try (final CSVParser parser = CSVParser.parse("A,B\n#my comment\nOne,Two", CSVFormat.DEFAULT.withHeader().withCommentMarker('#'))) {
|
||||
// CSVRecord rec = parser.iterator().next();
|
||||
//}
|
||||
try (InputStream in = getTestInput();
|
||||
ObjectInputStream ois = new ObjectInputStream(in)) {
|
||||
final Object object = ois.readObject();
|
||||
assertTrue(object instanceof CSVRecord);
|
||||
final CSVRecord rec = (CSVRecord) object;
|
||||
assertEquals(1L, rec.getRecordNumber());
|
||||
assertEquals("One", rec.get(0));
|
||||
assertEquals("Two", rec.get(1));
|
||||
assertEquals(2, rec.size());
|
||||
// The comment and whitespace are ignored so this is not 17 but 4
|
||||
assertEquals(4, rec.getCharacterPosition());
|
||||
assertEquals("my comment", rec.getComment());
|
||||
// The parser is not serialized
|
||||
assertNull(rec.getParser());
|
||||
// Check all header map functionality is absent
|
||||
assertTrue(rec.isConsistent());
|
||||
assertFalse(rec.isMapped("A"));
|
||||
assertFalse(rec.isSet("A"));
|
||||
assertEquals(0, rec.toMap().size());
|
||||
// This will throw
|
||||
try {
|
||||
rec.get("A");
|
||||
org.junit.jupiter.api.Assertions.fail("Access by name is not expected after deserialisation");
|
||||
} catch (final IllegalStateException expected) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static InputStream getTestInput() {
|
||||
return ClassLoader.getSystemClassLoader().getResourceAsStream("CSV-248/csvRecord.bin");
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ import org.junit.jupiter.api.Test;
|
|||
/**
|
||||
* Tests performance.
|
||||
*
|
||||
* To run this test, use: mvn test -Dtest=PeformanceTest
|
||||
* To run this test, use: mvn test -Dtest=PerformanceTest
|
||||
*/
|
||||
@SuppressWarnings("boxing") // test code
|
||||
public class PerformanceTest {
|
||||
|
@ -112,12 +112,11 @@ public class PerformanceTest {
|
|||
@Test
|
||||
public void testReadBigFile() throws Exception {
|
||||
long bestTime = Long.MAX_VALUE;
|
||||
long count;
|
||||
for (int i = 0; i < this.max; i++) {
|
||||
final long startMillis;
|
||||
long count;
|
||||
try (final BufferedReader in = this.createBufferedReader()) {
|
||||
startMillis = System.currentTimeMillis();
|
||||
count = 0;
|
||||
count = this.readAll(in);
|
||||
}
|
||||
final long totalMillis = System.currentTimeMillis() - startMillis;
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue