Skip to content

Commit dc8147e

Browse files
committed
Revert "26"
This reverts commit 75aa4cb.
1 parent 75aa4cb commit dc8147e

22 files changed

Lines changed: 11152 additions & 0 deletions

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

Lines changed: 3116 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 497 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 1496 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 1685 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 1820 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.csv;
18+
19+
import static org.junit.jupiter.api.Assertions.assertAll;
20+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertNotNull;
24+
import static org.junit.jupiter.api.Assertions.assertNull;
25+
import static org.junit.jupiter.api.Assertions.assertThrows;
26+
import static org.junit.jupiter.api.Assertions.assertTrue;
27+
28+
import java.io.ByteArrayInputStream;
29+
import java.io.ByteArrayOutputStream;
30+
import java.io.IOException;
31+
import java.io.ObjectInputStream;
32+
import java.io.ObjectOutputStream;
33+
import java.io.StringReader;
34+
import java.util.ArrayList;
35+
import java.util.List;
36+
import java.util.Map;
37+
import java.util.TreeMap;
38+
import java.util.concurrent.ConcurrentHashMap;
39+
import java.util.concurrent.atomic.AtomicInteger;
40+
41+
import org.apache.commons.lang3.StringUtils;
42+
import org.junit.jupiter.api.BeforeEach;
43+
import org.junit.jupiter.api.Test;
44+
45+
public class CSVRecordTest {
46+
47+
private enum EnumFixture {
48+
UNKNOWN_COLUMN
49+
}
50+
51+
/** This enum overrides toString() but it's the names that matter. */
52+
public enum EnumHeader {
53+
FIRST("first"), SECOND("second"), THIRD("third");
54+
55+
private final String number;
56+
57+
EnumHeader(final String number) {
58+
this.number = number;
59+
}
60+
61+
@Override
62+
public String toString() {
63+
return number;
64+
}
65+
}
66+
67+
private Map<String, Integer> headerMap;
68+
private CSVRecord record, recordWithHeader;
69+
private String[] values;
70+
71+
@BeforeEach
72+
public void setUp() throws Exception {
73+
values = new String[] { "A", "B", "C" };
74+
final String rowData = StringUtils.join(values, ',');
75+
try (final CSVParser parser = CSVFormat.DEFAULT.parse(new StringReader(rowData))) {
76+
record = parser.iterator().next();
77+
}
78+
try (final CSVParser parser = CSVFormat.DEFAULT.builder().setHeader(EnumHeader.class).build().parse(new StringReader(rowData))) {
79+
recordWithHeader = parser.iterator().next();
80+
headerMap = parser.getHeaderMap();
81+
}
82+
}
83+
84+
@Test
85+
public void testCSVRecordNULLValues() throws IOException {
86+
final CSVParser parser = CSVParser.parse("A,B\r\nONE,TWO", CSVFormat.DEFAULT.withHeader());
87+
final CSVRecord csvRecord = new CSVRecord(parser, null, null, 0L, 0L);
88+
assertEquals(0, csvRecord.size());
89+
assertThrows(IllegalArgumentException.class, () -> csvRecord.get("B"));
90+
}
91+
92+
@Test
93+
public void testDuplicateHeaderGet() throws IOException {
94+
final String csv = "A,A,B,B\n1,2,5,6\n";
95+
final CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().build();
96+
97+
try (final CSVParser parser = CSVParser.parse(csv, format)) {
98+
final CSVRecord record = parser.nextRecord();
99+
100+
assertAll("Test that it gets the last instance of a column when there are duplicate headings",
101+
() -> assertEquals("2", record.get("A")),
102+
() -> assertEquals("6", record.get("B"))
103+
);
104+
}
105+
}
106+
107+
@Test
108+
public void testDuplicateHeaderToMap() throws IOException {
109+
final String csv = "A,A,B,B\n1,2,5,6\n";
110+
final CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().build();
111+
112+
try (final CSVParser parser = CSVParser.parse(csv, format)) {
113+
final CSVRecord record = parser.nextRecord();
114+
final Map<String, String> map = record.toMap();
115+
116+
assertAll("Test that it gets the last instance of a column when there are duplicate headings",
117+
() -> assertEquals("2", map.get("A")),
118+
() -> assertEquals("6", map.get("B"))
119+
);
120+
}
121+
}
122+
123+
@Test
124+
public void testGetInt() {
125+
assertEquals(values[0], record.get(0));
126+
assertEquals(values[1], record.get(1));
127+
assertEquals(values[2], record.get(2));
128+
}
129+
130+
@Test
131+
public void testGetNullEnum() {
132+
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get((Enum<?>) null));
133+
}
134+
135+
@Test
136+
public void testGetString() {
137+
assertEquals(values[0], recordWithHeader.get(EnumHeader.FIRST.name()));
138+
assertEquals(values[1], recordWithHeader.get(EnumHeader.SECOND.name()));
139+
assertEquals(values[2], recordWithHeader.get(EnumHeader.THIRD.name()));
140+
}
141+
142+
@Test
143+
public void testGetStringInconsistentRecord() {
144+
headerMap.put("fourth", Integer.valueOf(4));
145+
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get("fourth"));
146+
}
147+
148+
@Test
149+
public void testGetStringNoHeader() {
150+
assertThrows(IllegalStateException.class, () -> record.get("first"));
151+
}
152+
153+
@Test
154+
public void testGetUnmappedEnum() {
155+
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
156+
}
157+
158+
@Test
159+
public void testGetUnmappedName() {
160+
assertThrows(IllegalArgumentException.class, () -> assertNull(recordWithHeader.get("fourth")));
161+
}
162+
163+
@Test
164+
public void testGetUnmappedNegativeInt() {
165+
assertThrows(ArrayIndexOutOfBoundsException.class, () -> recordWithHeader.get(Integer.MIN_VALUE));
166+
}
167+
168+
@Test
169+
public void testGetUnmappedPositiveInt() {
170+
assertThrows(ArrayIndexOutOfBoundsException.class, () -> recordWithHeader.get(Integer.MAX_VALUE));
171+
}
172+
173+
@Test
174+
public void testGetWithEnum() {
175+
assertEquals(recordWithHeader.get("FIRST"), recordWithHeader.get(EnumHeader.FIRST));
176+
assertEquals(recordWithHeader.get("SECOND"), recordWithHeader.get(EnumHeader.SECOND));
177+
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
178+
}
179+
180+
@Test
181+
public void testIsConsistent() {
182+
assertTrue(record.isConsistent());
183+
assertTrue(recordWithHeader.isConsistent());
184+
final Map<String, Integer> map = recordWithHeader.getParser().getHeaderMap();
185+
map.put("fourth", Integer.valueOf(4));
186+
// We are working on a copy of the map, so the record should still be OK.
187+
assertTrue(recordWithHeader.isConsistent());
188+
}
189+
190+
@Test
191+
public void testIsInconsistent() throws IOException {
192+
final String[] headers = { "first", "second", "third" };
193+
final String rowData = StringUtils.join(values, ',');
194+
try (final CSVParser parser = CSVFormat.DEFAULT.withHeader(headers).parse(new StringReader(rowData))) {
195+
final Map<String, Integer> map = parser.getHeaderMapRaw();
196+
final CSVRecord record1 = parser.iterator().next();
197+
map.put("fourth", Integer.valueOf(4));
198+
assertFalse(record1.isConsistent());
199+
}
200+
}
201+
202+
@Test
203+
public void testIsMapped() {
204+
assertFalse(record.isMapped("first"));
205+
assertTrue(recordWithHeader.isMapped(EnumHeader.FIRST.name()));
206+
assertFalse(recordWithHeader.isMapped("fourth"));
207+
}
208+
209+
@Test
210+
public void testIsSetInt() {
211+
assertFalse(record.isSet(-1));
212+
assertTrue(record.isSet(0));
213+
assertTrue(record.isSet(2));
214+
assertFalse(record.isSet(3));
215+
assertTrue(recordWithHeader.isSet(1));
216+
assertFalse(recordWithHeader.isSet(1000));
217+
}
218+
219+
@Test
220+
public void testIsSetString() {
221+
assertFalse(record.isSet("first"));
222+
assertTrue(recordWithHeader.isSet(EnumHeader.FIRST.name()));
223+
assertFalse(recordWithHeader.isSet("DOES NOT EXIST"));
224+
}
225+
226+
@Test
227+
public void testIterator() {
228+
int i = 0;
229+
for (final String value : record) {
230+
assertEquals(values[i], value);
231+
i++;
232+
}
233+
}
234+
235+
@Test
236+
public void testPutInMap() {
237+
final Map<String, String> map = new ConcurrentHashMap<>();
238+
this.recordWithHeader.putIn(map);
239+
this.validateMap(map, false);
240+
// Test that we can compile with assignment to the same map as the param.
241+
final TreeMap<String, String> map2 = recordWithHeader.putIn(new TreeMap<>());
242+
this.validateMap(map2, false);
243+
}
244+
245+
@Test
246+
public void testRemoveAndAddColumns() throws IOException {
247+
// do:
248+
try (final CSVPrinter printer = new CSVPrinter(new StringBuilder(), CSVFormat.DEFAULT)) {
249+
final Map<String, String> map = recordWithHeader.toMap();
250+
map.remove("OldColumn");
251+
map.put("ZColumn", "NewValue");
252+
// check:
253+
final ArrayList<String> list = new ArrayList<>(map.values());
254+
list.sort(null);
255+
printer.printRecord(list);
256+
assertEquals("A,B,C,NewValue" + CSVFormat.DEFAULT.getRecordSeparator(), printer.getOut().toString());
257+
}
258+
}
259+
260+
@Test
261+
public void testSerialization() throws IOException, ClassNotFoundException {
262+
final CSVRecord shortRec;
263+
try (final CSVParser parser = CSVParser.parse("A,B\n#my comment\nOne,Two", CSVFormat.DEFAULT.withHeader().withCommentMarker('#'))) {
264+
shortRec = parser.iterator().next();
265+
}
266+
final ByteArrayOutputStream out = new ByteArrayOutputStream();
267+
try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
268+
oos.writeObject(shortRec);
269+
}
270+
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
271+
try (ObjectInputStream ois = new ObjectInputStream(in)) {
272+
final Object object = ois.readObject();
273+
assertTrue(object instanceof CSVRecord);
274+
final CSVRecord rec = (CSVRecord) object;
275+
assertEquals(1L, rec.getRecordNumber());
276+
assertEquals("One", rec.get(0));
277+
assertEquals("Two", rec.get(1));
278+
assertEquals(2, rec.size());
279+
assertEquals(shortRec.getCharacterPosition(), rec.getCharacterPosition());
280+
assertEquals("my comment", rec.getComment());
281+
// The parser is not serialized
282+
assertNull(rec.getParser());
283+
// Check all header map functionality is absent
284+
assertTrue(rec.isConsistent());
285+
assertFalse(rec.isMapped("A"));
286+
assertFalse(rec.isSet("A"));
287+
assertEquals(0, rec.toMap().size());
288+
// This will throw
289+
assertThrows(IllegalStateException.class, () -> rec.get("A"));
290+
}
291+
}
292+
293+
@Test
294+
public void testStream() {
295+
final AtomicInteger i = new AtomicInteger();
296+
record.stream().forEach(value -> {
297+
assertEquals(values[i.get()], value);
298+
i.incrementAndGet();
299+
});
300+
}
301+
302+
@Test
303+
public void testToListAdd() {
304+
final String[] expected = values.clone();
305+
final List<String> list = record.toList();
306+
list.add("Last");
307+
assertEquals("Last", list.get(list.size() - 1));
308+
assertEquals(list.size(), values.length + 1);
309+
assertArrayEquals(expected, values);
310+
}
311+
312+
@Test
313+
public void testToListFor() {
314+
int i = 0;
315+
for (final String value : record.toList()) {
316+
assertEquals(values[i], value);
317+
i++;
318+
}
319+
}
320+
321+
@Test
322+
public void testToListForEach() {
323+
final AtomicInteger i = new AtomicInteger();
324+
record.toList().forEach(e -> {
325+
assertEquals(values[i.getAndIncrement()], e);
326+
});
327+
}
328+
329+
@Test
330+
public void testToListSet() {
331+
final String[] expected = values.clone();
332+
final List<String> list = record.toList();
333+
list.set(list.size() - 1, "Last");
334+
assertEquals("Last", list.get(list.size() - 1));
335+
assertEquals(list.size(), values.length);
336+
assertArrayEquals(expected, values);
337+
}
338+
339+
@Test
340+
public void testToMap() {
341+
final Map<String, String> map = this.recordWithHeader.toMap();
342+
this.validateMap(map, true);
343+
}
344+
345+
@Test
346+
public void testToMapWithNoHeader() throws Exception {
347+
try (final CSVParser parser = CSVParser.parse("a,b", CSVFormat.newFormat(','))) {
348+
final CSVRecord shortRec = parser.iterator().next();
349+
final Map<String, String> map = shortRec.toMap();
350+
assertNotNull(map, "Map is not null.");
351+
assertTrue(map.isEmpty(), "Map is empty.");
352+
}
353+
}
354+
355+
@Test
356+
public void testToMapWithShortRecord() throws Exception {
357+
try (final CSVParser parser = CSVParser.parse("a,b", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
358+
final CSVRecord shortRec = parser.iterator().next();
359+
shortRec.toMap();
360+
}
361+
}
362+
363+
@Test
364+
public void testToString() {
365+
assertNotNull(recordWithHeader.toString());
366+
assertTrue(recordWithHeader.toString().contains("comment="));
367+
assertTrue(recordWithHeader.toString().contains("recordNumber="));
368+
assertTrue(recordWithHeader.toString().contains("values="));
369+
}
370+
371+
private void validateMap(final Map<String, String> map, final boolean allowsNulls) {
372+
assertTrue(map.containsKey(EnumHeader.FIRST.name()));
373+
assertTrue(map.containsKey(EnumHeader.SECOND.name()));
374+
assertTrue(map.containsKey(EnumHeader.THIRD.name()));
375+
assertFalse(map.containsKey("fourth"));
376+
if (allowsNulls) {
377+
assertFalse(map.containsKey(null));
378+
}
379+
assertEquals("A", map.get(EnumHeader.FIRST.name()));
380+
assertEquals("B", map.get(EnumHeader.SECOND.name()));
381+
assertEquals("C", map.get(EnumHeader.THIRD.name()));
382+
assertNull(map.get("fourth"));
383+
}
384+
}

0 commit comments

Comments
 (0)