Skip to content

Commit 0596491

Browse files
aherbertgarydgregory
authored andcommitted
CSV-247: CSVParser to check an empty header before checking duplicates. (apache#47)
This updates the issues test for CSV-247 and adds tests to the CSVParserTest.
1 parent dcc44cd commit 0596491

4 files changed

Lines changed: 47 additions & 25 deletions

File tree

src/main/java/org/apache/commons/csv/CSVParser.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -495,19 +495,18 @@ private Headers createHeaders() throws IOException {
495495
if (headerRecord != null) {
496496
for (int i = 0; i < headerRecord.length; i++) {
497497
final String header = headerRecord[i];
498-
final boolean containsHeader = header != null && hdrMap.containsKey(header);
499498
final boolean emptyHeader = header == null || header.trim().isEmpty();
500-
if (containsHeader) {
501-
if (!emptyHeader && !this.format.getAllowDuplicateHeaderNames()) {
502-
throw new IllegalArgumentException(
503-
String.format(
504-
"The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.withAllowDuplicateHeaderNames().",
505-
header, Arrays.toString(headerRecord)));
506-
}
507-
if (emptyHeader && !this.format.getAllowMissingColumnNames()) {
508-
throw new IllegalArgumentException(
509-
"A header name is missing in " + Arrays.toString(headerRecord));
510-
}
499+
if (emptyHeader && !this.format.getAllowMissingColumnNames()) {
500+
throw new IllegalArgumentException(
501+
"A header name is missing in " + Arrays.toString(headerRecord));
502+
}
503+
// Note: This will always allow a duplicate header if the header is empty
504+
final boolean containsHeader = header != null && hdrMap.containsKey(header);
505+
if (containsHeader && !emptyHeader && !this.format.getAllowDuplicateHeaderNames()) {
506+
throw new IllegalArgumentException(
507+
String.format(
508+
"The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.withAllowDuplicateHeaderNames().",
509+
header, Arrays.toString(headerRecord)));
511510
}
512511
if (header != null) {
513512
hdrMap.put(header, Integer.valueOf(i));

src/main/resources/checkstyle/checkstyle-suppressions.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
2020
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
2121
<suppressions>
22-
<suppress checks="LineLength" files="[\\/]CSVParser\.java$" lines="504"/>
22+
<suppress checks="LineLength" files="[\\/]CSVParser\.java$" lines="508"/>
2323
</suppressions>

src/test/java/org/apache/commons/csv/CSVParserTest.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ public void testHeaderComment() throws Exception {
688688
public void testHeaderMissing() throws Exception {
689689
final Reader in = new StringReader("a,,c\n1,2,3\nx,y,z");
690690

691-
final Iterator<CSVRecord> records = CSVFormat.DEFAULT.withHeader().parse(in).iterator();
691+
final Iterator<CSVRecord> records = CSVFormat.DEFAULT.withHeader().withAllowMissingColumnNames().parse(in).iterator();
692692

693693
for (int i = 0; i < 2; i++) {
694694
assertTrue(records.hasNext());
@@ -702,22 +702,28 @@ public void testHeaderMissing() throws Exception {
702702

703703
@Test
704704
public void testHeaderMissingWithNull() throws Exception {
705-
final Reader in = new StringReader("a,,c,,d\n1,2,3,4\nx,y,z,zz");
705+
final Reader in = new StringReader("a,,c,,e\n1,2,3,4,5\nv,w,x,y,z");
706706
CSVFormat.DEFAULT.withHeader().withNullString("").withAllowMissingColumnNames().parse(in).iterator();
707707
}
708708

709709
@Test
710710
public void testHeadersMissing() throws Exception {
711-
final Reader in = new StringReader("a,,c,,d\n1,2,3,4\nx,y,z,zz");
711+
final Reader in = new StringReader("a,,c,,e\n1,2,3,4,5\nv,w,x,y,z");
712712
CSVFormat.DEFAULT.withHeader().withAllowMissingColumnNames().parse(in).iterator();
713713
}
714714

715715
@Test
716716
public void testHeadersMissingException() {
717-
final Reader in = new StringReader("a,,c,,d\n1,2,3,4\nx,y,z,zz");
717+
final Reader in = new StringReader("a,,c,,e\n1,2,3,4,5\nv,w,x,y,z");
718718
assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
719719
}
720720

721+
@Test
722+
public void testHeadersMissingOneColumnException() throws Exception {
723+
final Reader in = new StringReader("a,,c,d,e\n1,2,3,4,5\nv,w,x,y,z");
724+
assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
725+
}
726+
721727
@Test
722728
public void testIgnoreCaseHeaderMapping() throws Exception {
723729
final Reader reader = new StringReader("1,2,3");

src/test/java/org/apache/commons/csv/issues/JiraCsv247Test.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
import static org.junit.jupiter.api.Assertions.assertEquals;
2121
import static org.junit.jupiter.api.Assertions.assertFalse;
22+
import static org.junit.jupiter.api.Assertions.assertThrows;
23+
import static org.junit.jupiter.api.Assertions.assertTrue;
24+
2225
import java.io.Reader;
2326
import java.io.StringReader;
2427
import java.util.Arrays;
@@ -32,9 +35,14 @@
3235
public class JiraCsv247Test {
3336

3437
@Test
35-
public void testHeadersMissingOneColumn() throws Exception {
38+
public void testHeadersMissingOneColumnWhenAllowingMissingColumnNames() throws Exception {
39+
final CSVFormat format = CSVFormat.DEFAULT.withHeader().withAllowMissingColumnNames(true);
40+
41+
assertTrue(format.getAllowMissingColumnNames(),
42+
"We should allow missing column names");
43+
3644
final Reader in = new StringReader("a,,c,d,e\n1,2,3,4,5\nv,w,x,y,z");
37-
try (final CSVParser parser = CSVFormat.DEFAULT.withHeader().parse(in)) {
45+
try (final CSVParser parser = format.parse(in)) {
3846
assertEquals(Arrays.asList("a", "", "c", "d", "e"), parser.getHeaderNames());
3947
final Iterator<CSVRecord> iterator = parser.iterator();
4048
CSVRecord record = iterator.next();
@@ -54,11 +62,20 @@ record = iterator.next();
5462
}
5563

5664
@Test
57-
public void testJiraDescription() throws Exception {
58-
final Reader in = new StringReader("a,,c,d\n1,2,3,4\nx,y,z,zz");
59-
try (final CSVParser parser = CSVFormat.DEFAULT.withHeader().parse(in)) {
60-
parser.iterator();
61-
}
62-
}
65+
public void testHeadersMissingThrowsWhenNotAllowingMissingColumnNames() throws Exception {
66+
final CSVFormat format = CSVFormat.DEFAULT.withHeader();
67+
68+
assertFalse(format.getAllowMissingColumnNames(),
69+
"By default we should not allow missing column names");
6370

71+
assertThrows(IllegalArgumentException.class, () -> {
72+
final Reader in = new StringReader("a,,c,d,e\n1,2,3,4,5\nv,w,x,y,z");
73+
format.parse(in);
74+
}, "1 missing column header is not allowed");
75+
76+
assertThrows(IllegalArgumentException.class, () -> {
77+
final Reader in = new StringReader("a,,c,d,\n1,2,3,4,5\nv,w,x,y,z");
78+
format.parse(in);
79+
}, "2+ missing column headers is not allowed!");
80+
}
6481
}

0 commit comments

Comments
 (0)