CSV-264: CSVParser identifies null, empty or blank headers as 'missing'
Duplicate missing header names are handled consistently between CSVFormat and CSVParser. Document that the ignore header case flag is for parser behaviour. Update CSVDuplicateHeaderTest to add the ignore header case flag to tests. Add test cases with case insensitive duplicates.
This commit is contained in:
parent
8ad07df0d4
commit
69aa686187
|
@ -289,7 +289,7 @@ public final class CSVFormat implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the missing column names parser behavior, {@code true} to allow missing column names in the header line, {@code false} to cause an
|
||||
* Sets the parser missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to cause an
|
||||
* {@link IllegalArgumentException} to be thrown.
|
||||
*
|
||||
* @param allowMissingColumnNames the missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to
|
||||
|
@ -564,7 +564,7 @@ public final class CSVFormat implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
|
||||
* Sets the parser case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
|
||||
*
|
||||
* @param ignoreHeaderCase the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
|
||||
* @return This instance.
|
||||
|
@ -1599,7 +1599,7 @@ public final class CSVFormat implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets whether header names will be accessed ignoring case.
|
||||
* Gets whether header names will be accessed ignoring case when parsing input.
|
||||
*
|
||||
* @return {@code true} if header names cases are ignored, {@code false} if they are case sensitive.
|
||||
* @since 1.3
|
||||
|
|
|
@ -499,6 +499,8 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||
|
||||
// build the name to index mappings
|
||||
if (headerRecord != null) {
|
||||
// Track an occurrence of a null, empty or blank header.
|
||||
boolean observedMissing = false;
|
||||
for (int i = 0; i < headerRecord.length; i++) {
|
||||
final String header = headerRecord[i];
|
||||
final boolean blankHeader = CSVFormat.isBlank(header);
|
||||
|
@ -507,7 +509,7 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||
"A header name is missing in " + Arrays.toString(headerRecord));
|
||||
}
|
||||
|
||||
final boolean containsHeader = header != null && hdrMap.containsKey(header);
|
||||
final boolean containsHeader = blankHeader ? observedMissing : hdrMap.containsKey(header);
|
||||
final DuplicateHeaderMode headerMode = this.format.getDuplicateHeaderMode();
|
||||
final boolean duplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_ALL;
|
||||
final boolean emptyDuplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_EMPTY;
|
||||
|
@ -518,6 +520,7 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||
"The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.Builder.setDuplicateHeaderMode().",
|
||||
header, Arrays.toString(headerRecord)));
|
||||
}
|
||||
observedMissing |= blankHeader;
|
||||
if (header != null) {
|
||||
hdrMap.put(header, Integer.valueOf(i));
|
||||
if (headerNames == null) {
|
||||
|
|
|
@ -46,144 +46,181 @@ public class CSVDuplicateHeaderTest {
|
|||
*/
|
||||
static Stream<Arguments> duplicateHeaderData() {
|
||||
return Stream.of(
|
||||
// TODO: Fix CSVParser which does not sanitise 'empty' names or
|
||||
// equate null names with empty as duplications
|
||||
|
||||
// Any combination with a valid header
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "B"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "B"}, true),
|
||||
|
||||
// Any combination with a valid header including empty
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", ""}, true),
|
||||
|
||||
// Any combination with a valid header including blank (1 space)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", " "}, true),
|
||||
|
||||
// Any combination with a valid header including null
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", null}, true),
|
||||
|
||||
// Duplicate non-empty names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", "A"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", "A"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "A"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "A"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "A"}, true),
|
||||
|
||||
// Duplicate empty names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"", ""}, true),
|
||||
|
||||
// Duplicate blank names (1 space)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {" ", " "}, true),
|
||||
|
||||
// Duplicate blank names (3 spaces)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {" ", " "}, true),
|
||||
|
||||
// Duplicate null names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {null, null}, false),
|
||||
// Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {null, null}, true),
|
||||
|
||||
// Duplicate blank names (1+3 spaces)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {" ", " "}, false),
|
||||
// Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {" ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {" ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {" ", " "}, true),
|
||||
|
||||
// Duplicate blank names and null names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {" ", null}, false),
|
||||
// Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {" ", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {" ", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {" ", null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {" ", null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {" ", null}, true),
|
||||
|
||||
// Duplicate non-empty and empty names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", "A", "", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "A", "", ""}, true),
|
||||
|
||||
// Non-duplicate non-empty and duplicate empty names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "B", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "B", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "B", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "B", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "B", "", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "B", "", ""}, true),
|
||||
|
||||
// Duplicate non-empty and blank names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", "A", " ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "A", " ", " "}, true),
|
||||
|
||||
// Duplicate non-empty and null names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", "A", null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "A", null, null}, true),
|
||||
|
||||
// Duplicate blank names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", "", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", "", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", "", ""}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", "", ""}, true),
|
||||
|
||||
// Duplicate null names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", null, null}, false),
|
||||
// Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", null, null}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", null, null}, true),
|
||||
|
||||
// Duplicate blank names (1+3 spaces)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, new String[] {"A", " ", " "}, false),
|
||||
// Arguments.of(DuplicateHeaderMode.DISALLOW, true, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, new String[] {"A", " ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, new String[] {"A", " ", " "}, true)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, false, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, false, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, false, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, false, new String[] {"A", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, false, new String[] {"A", " ", " "}, true),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, false, new String[] {"A", " ", " "}, true),
|
||||
|
||||
// Duplicate names (case insensitive)
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, true , new String[] {"A", "a"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, true , new String[] {"A", "a"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, true , new String[] {"A", "a"}, true),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, true , new String[] {"A", "a"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, true , new String[] {"A", "a"}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, true , new String[] {"A", "a"}, true),
|
||||
|
||||
// Duplicate non-empty (case insensitive) and empty names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, true, new String[] {"A", "a", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, true, new String[] {"A", "a", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, true, new String[] {"A", "a", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, true, new String[] {"A", "a", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, true, new String[] {"A", "a", "", ""}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, true, new String[] {"A", "a", "", ""}, true),
|
||||
|
||||
// Duplicate non-empty (case insensitive) and blank names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, true, new String[] {"A", "a", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, true, new String[] {"A", "a", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, true, new String[] {"A", "a", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, true, new String[] {"A", "a", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, true, new String[] {"A", "a", " ", " "}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, true, new String[] {"A", "a", " ", " "}, true),
|
||||
|
||||
// Duplicate non-empty (case insensitive) and null names
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, false, true, new String[] {"A", "a", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, false, true, new String[] {"A", "a", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, false, true, new String[] {"A", "a", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.DISALLOW, true, true, new String[] {"A", "a", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_EMPTY, true, true, new String[] {"A", "a", null, null}, false),
|
||||
Arguments.of(DuplicateHeaderMode.ALLOW_ALL, true, true, new String[] {"A", "a", null, null}, true)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -191,23 +228,33 @@ public class CSVDuplicateHeaderTest {
|
|||
* Return test cases for duplicate header data for use in CSVFormat.
|
||||
* <p>
|
||||
* This filters the parsing test data to all cases where the allow missing column
|
||||
* names flag is true. The allow missing column names is exclusively for parsing.
|
||||
* names flag is true and ignore header case is false: these flags are exclusively for parsing.
|
||||
* CSVFormat validation applies to both parsing and writing and thus validation
|
||||
* is less strict and behaves as if the missing column names constraint is absent.
|
||||
* The filtered data is then returned with the missing column names flag set to both
|
||||
* true and false for each test case.
|
||||
* is less strict and behaves as if the allow missing column names constraint and
|
||||
* the ignore header case behaviour are absent.
|
||||
* The filtered data is then returned with the parser flags set to both true and false
|
||||
* for each test case.
|
||||
* </p>
|
||||
*
|
||||
* @return the stream of arguments
|
||||
*/
|
||||
static Stream<Arguments> duplicateHeaderAllowsMissingColumnsNamesData() {
|
||||
return duplicateHeaderData()
|
||||
.filter(arg -> Boolean.TRUE.equals(arg.get()[1]))
|
||||
.filter(arg -> Boolean.TRUE.equals(arg.get()[1]) && Boolean.FALSE.equals(arg.get()[2]))
|
||||
.flatMap(arg -> {
|
||||
// Return test case with flag as both true and false
|
||||
final Object[] data = arg.get().clone();
|
||||
data[1] = Boolean.FALSE;
|
||||
return Stream.of(arg, Arguments.of(data));
|
||||
// Return test case with flags as all true/false combinations
|
||||
final Object[][] data = new Object[4][];
|
||||
final Boolean[] flags = {Boolean.TRUE, Boolean.FALSE};
|
||||
int i = 0;
|
||||
for (final Boolean a : flags) {
|
||||
for (final Boolean b : flags) {
|
||||
data[i] = arg.get().clone();
|
||||
data[i][1] = a;
|
||||
data[i][2] = b;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return Arrays.stream(data).map(Arguments::of);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -216,6 +263,7 @@ public class CSVDuplicateHeaderTest {
|
|||
*
|
||||
* @param duplicateHeaderMode the duplicate header mode
|
||||
* @param allowMissingColumnNames the allow missing column names flag (only used for parsing)
|
||||
* @param ignoreHeaderCase the ignore header case flag (only used for parsing)
|
||||
* @param headers the headers
|
||||
* @param valid true if the settings are expected to be valid, otherwise expect a IllegalArgumentException
|
||||
*/
|
||||
|
@ -223,12 +271,14 @@ public class CSVDuplicateHeaderTest {
|
|||
@MethodSource(value = {"duplicateHeaderAllowsMissingColumnsNamesData"})
|
||||
public void testCSVFormat(final DuplicateHeaderMode duplicateHeaderMode,
|
||||
final boolean allowMissingColumnNames,
|
||||
final boolean ignoreHeaderCase,
|
||||
final String[] headers,
|
||||
final boolean valid) {
|
||||
final CSVFormat.Builder builder =
|
||||
CSVFormat.DEFAULT.builder()
|
||||
.setDuplicateHeaderMode(duplicateHeaderMode)
|
||||
.setAllowMissingColumnNames(allowMissingColumnNames)
|
||||
.setIgnoreHeaderCase(ignoreHeaderCase)
|
||||
.setHeader(headers);
|
||||
if (valid) {
|
||||
final CSVFormat format = builder.build();
|
||||
|
@ -245,6 +295,7 @@ public class CSVDuplicateHeaderTest {
|
|||
*
|
||||
* @param duplicateHeaderMode the duplicate header mode
|
||||
* @param allowMissingColumnNames the allow missing column names flag (only used for parsing)
|
||||
* @param ignoreHeaderCase the ignore header case flag (only used for parsing)
|
||||
* @param headers the headers (joined with the CSVFormat delimiter to create a string input)
|
||||
* @param valid true if the settings are expected to be valid, otherwise expect a IllegalArgumentException
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
|
@ -253,17 +304,19 @@ public class CSVDuplicateHeaderTest {
|
|||
@MethodSource(value = {"duplicateHeaderData"})
|
||||
public void testCSVParser(final DuplicateHeaderMode duplicateHeaderMode,
|
||||
final boolean allowMissingColumnNames,
|
||||
final boolean ignoreHeaderCase,
|
||||
final String[] headers,
|
||||
final boolean valid) throws IOException {
|
||||
final CSVFormat format =
|
||||
CSVFormat.DEFAULT.builder()
|
||||
.setDuplicateHeaderMode(duplicateHeaderMode)
|
||||
.setAllowMissingColumnNames(allowMissingColumnNames)
|
||||
.setIgnoreHeaderCase(ignoreHeaderCase)
|
||||
.setNullString("NULL")
|
||||
.setHeader()
|
||||
.build();
|
||||
final String input = Arrays.stream(headers)
|
||||
.map(s -> s == null ? "NULL" : s)
|
||||
.map(s -> s == null ? format.getNullString() : s)
|
||||
.collect(Collectors.joining(format.getDelimiterString()));
|
||||
if (valid) {
|
||||
try(CSVParser parser = CSVParser.parse(input, format)) {
|
||||
|
|
Loading…
Reference in New Issue