View Javadoc
1   /*
2    * Copyright 2007 Kasper B. Graversen
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.supercsv.io;
17  
18  import static org.junit.Assert.assertEquals;
19  import static org.junit.Assert.assertFalse;
20  import static org.junit.Assert.assertNull;
21  import static org.junit.Assert.assertTrue;
22  import static org.junit.Assert.fail;
23  
24  import java.io.IOException;
25  import java.io.Reader;
26  import java.io.StringReader;
27  import java.util.Arrays;
28  import java.util.List;
29  
30  import org.junit.After;
31  import org.junit.Before;
32  import org.junit.Test;
33  import org.supercsv.exception.SuperCsvException;
34  import org.supercsv.prefs.CsvPreference;
35  
36  /**
37   * Tests AbstractCsvReader.
38   * 
39   * @author Kasper B. Graversen
40   * @author James Bassett
41   */
42  public class AbstractCsvReaderTest {
43  	
44  	private static final CsvPreference PREFS = CsvPreference.STANDARD_PREFERENCE;
45  	
46  	private static final CsvPreference SURROUNDING_SPACES_NEED_QUOTES_PREFS = new CsvPreference.Builder(
47  		CsvPreference.STANDARD_PREFERENCE).surroundingSpacesNeedQuotes(true).build();
48  	
49  	private Reader reader;
50  	
51  	private Reader surroundingSpacesNeedQuotesReader;
52  	
53  	private AbstractCsvReader abstractReader;
54  	
55  	private AbstractCsvReader tokenizerAbstractReader;
56  	
57  	private AbstractCsvReader surroundingSpacesNeedQuotesAbstractReader;
58  	
59  	private ITokenizer tokenizer;
60  	
61  	/**
62  	 * Implementation of AbstractCsvReader for testing.
63  	 */
64  	private static class MockCsvReader extends AbstractCsvReader {
65  		
66  		public MockCsvReader(ITokenizer tokenizer, CsvPreference preferences) {
67  			super(tokenizer, preferences);
68  		}
69  		
70  		public MockCsvReader(Reader reader, CsvPreference preferences) {
71  			super(reader, preferences);
72  		}
73  		
74  	}
75  	
76  	/**
77  	 * Sets up the reader for the tests.
78  	 */
79  	@Before
80  	public void setUp() {
81  		reader = new StringReader("firstName,lastName,age,address\n" + "John,Smith,23,\n"
82  			+ "Harry,Potter,,\"Gryffindor\nHogwarts Castle\nUK\"");
83  		abstractReader = new MockCsvReader(reader, PREFS);
84  		
85  		tokenizer = new Tokenizer(reader, PREFS);
86  		tokenizerAbstractReader = new MockCsvReader(tokenizer, PREFS);
87  		
88  		surroundingSpacesNeedQuotesReader = new StringReader("firstName, lastName, age, address\n"
89  			+ " John , Smith, 23 , \n" + "Harry, Potter, , \"Gryffindor\nHogwarts Castle\nUK\" ");
90  		surroundingSpacesNeedQuotesAbstractReader = new MockCsvReader(surroundingSpacesNeedQuotesReader,
91  			SURROUNDING_SPACES_NEED_QUOTES_PREFS);
92  	}
93  	
94  	/**
95  	 * Closes the readers after the test.
96  	 */
97  	@After
98  	public void tearDown() throws IOException {
99  		abstractReader.close();
100 		tokenizerAbstractReader.close();
101 		surroundingSpacesNeedQuotesAbstractReader.close();
102 	}
103 	
104 	/**
105 	 * Tests a normal reading scenario, asserting all of the properties available each time.
106 	 */
107 	@Test
108 	public void testReadingWithNormalReader() throws IOException {
109 		assertReading(abstractReader);
110 	}
111 	
112 	/**
113 	 * Tests a normal reading scenario (with the custom tokenizer reader), asserting all of the properties available
114 	 * each time.
115 	 */
116 	@Test
117 	public void testReadingWithTokenizerReader() throws IOException {
118 		assertReading(tokenizerAbstractReader);
119 	}
120 	
121 	/**
122 	 * Reusable method to test a normal reading scenario, asserting all of the properties are available each time.
123 	 */
124 	private void assertReading(final AbstractCsvReader csvReader) throws IOException {
125 		
126 		assertEquals(PREFS, csvReader.getPreferences());
127 		
128 		assertEquals(0, csvReader.getLineNumber());
129 		assertEquals(0, csvReader.getRowNumber());
130 		assertEquals("", csvReader.getUntokenizedRow());
131 		assertEquals(0, csvReader.length());
132 		
133 		// read the header
134 		final String[] header = csvReader.getHeader(true);
135 		assertEquals(4, header.length);
136 		assertEquals("firstName", header[0]);
137 		assertEquals("lastName", header[1]);
138 		assertEquals("age", header[2]);
139 		assertEquals("address", header[3]);
140 		
141 		assertEquals(1, csvReader.getLineNumber());
142 		assertEquals(1, csvReader.getRowNumber());
143 		assertEquals("firstName,lastName,age,address", csvReader.getUntokenizedRow());
144 		assertEquals(4, csvReader.length());
145 		
146 		// read the first data row
147 		assertTrue(csvReader.readRow());
148 		List<String> line = csvReader.getColumns(); // John,Smith,23,\"1 Sesame St\nNew York\"
149 		assertEquals(4, csvReader.length());
150 		assertEquals("John", line.get(0));
151 		assertEquals("Smith", line.get(1));
152 		assertEquals("23", line.get(2));
153 		assertNull(line.get(3));
154 		
155 		// get() should return the same values as the List from read()
156 		assertTrue(Arrays.equals(line.toArray(), new Object[] { csvReader.get(1), csvReader.get(2), csvReader.get(3),
157 			csvReader.get(4) }));
158 		
159 		assertEquals(2, csvReader.getLineNumber());
160 		assertEquals(2, csvReader.getRowNumber());
161 		assertEquals("John,Smith,23,", csvReader.getUntokenizedRow());
162 		assertEquals(4, csvReader.length());
163 		
164 		// read the second data row
165 		assertTrue(csvReader.readRow());
166 		line = csvReader.getColumns(); // Harry,Potter,13,\"Gryffindor\nHogwarts Castle\nUK\"
167 		assertEquals(4, csvReader.length());
168 		assertEquals("Harry", line.get(0));
169 		assertEquals("Potter", line.get(1));
170 		assertNull(line.get(2));
171 		assertEquals("Gryffindor\nHogwarts Castle\nUK", line.get(3));
172 		
173 		// get() should return the same values as the List from read()
174 		assertTrue(Arrays.equals(line.toArray(), new Object[] { csvReader.get(1), csvReader.get(2), csvReader.get(3),
175 			csvReader.get(4) }));
176 		
177 		assertEquals(5, csvReader.getLineNumber()); // 2 newlines in harry's address
178 		assertEquals(3, csvReader.getRowNumber());
179 		assertEquals("Harry,Potter,,\"Gryffindor\nHogwarts Castle\nUK\"", csvReader.getUntokenizedRow());
180 		assertEquals(4, csvReader.length());
181 		
182 		// read again (should be EOF)
183 		assertFalse(csvReader.readRow());
184 		assertEquals(5, csvReader.getLineNumber());
185 		assertEquals(3, csvReader.getRowNumber());
186 		assertEquals("", csvReader.getUntokenizedRow());
187 		assertEquals(0, csvReader.length());
188 		
189 	}
190 	
191 	/**
192 	 * Tests a normal reading scenario (with surroundingSpacesNeedQuotes enabled), asserting all of the properties available
193 	 * each time.
194 	 */
195 	@Test
196 	public void testReadingWithSurroundingSpacesNeedQuotesReader() throws IOException {
197 		assertReadingWithSurroundingSpacesNeedQuotesEnabled(surroundingSpacesNeedQuotesAbstractReader);
198 	}
199 	
200 	/**
201 	 * Reusable method to test a reading scenario (with surroundingSpacesNeedQuotes enabled), asserting all of the
202 	 * properties are available each time.
203 	 */
204 	private void assertReadingWithSurroundingSpacesNeedQuotesEnabled(final AbstractCsvReader csvReader) throws IOException {
205 		
206 		assertEquals(SURROUNDING_SPACES_NEED_QUOTES_PREFS, csvReader.getPreferences());
207 		
208 		assertEquals(0, csvReader.getLineNumber());
209 		assertEquals(0, csvReader.getRowNumber());
210 		assertEquals("", csvReader.getUntokenizedRow());
211 		assertEquals(0, csvReader.length());
212 		
213 		// read the header
214 		final String[] header = csvReader.getHeader(true);
215 		assertEquals(4, header.length);
216 		assertEquals("firstName", header[0]);
217 		assertEquals("lastName", header[1]);
218 		assertEquals("age", header[2]);
219 		assertEquals("address", header[3]);
220 		
221 		assertEquals(1, csvReader.getLineNumber());
222 		assertEquals(1, csvReader.getRowNumber());
223 		assertEquals("firstName, lastName, age, address", csvReader.getUntokenizedRow());
224 		assertEquals(4, csvReader.length());
225 		
226 		// read the first data row
227 		assertTrue(csvReader.readRow());
228 		List<String> line = csvReader.getColumns(); // John , Smith, 23 , \"1 Sesame St\nNew York\"
229 		assertEquals(4, csvReader.length());
230 		assertEquals("John", line.get(0));
231 		assertEquals("Smith", line.get(1));
232 		assertEquals("23", line.get(2));
233 		assertNull(line.get(3));
234 		
235 		// get() should return the same values as the List from read()
236 		assertTrue(Arrays.equals(line.toArray(), new Object[] { csvReader.get(1), csvReader.get(2), csvReader.get(3),
237 			csvReader.get(4) }));
238 		
239 		assertEquals(2, csvReader.getLineNumber());
240 		assertEquals(2, csvReader.getRowNumber());
241 		assertEquals(" John , Smith, 23 , ", csvReader.getUntokenizedRow());
242 		assertEquals(4, csvReader.length());
243 		
244 		// read the second data row
245 		assertTrue(csvReader.readRow());
246 		line = csvReader.getColumns(); // Harry, Potter, 13, \"Gryffindor\nHogwarts Castle\nUK\"
247 		assertEquals(4, csvReader.length());
248 		assertEquals("Harry", line.get(0));
249 		assertEquals("Potter", line.get(1));
250 		assertNull(line.get(2));
251 		assertEquals("Gryffindor\nHogwarts Castle\nUK", line.get(3));
252 		
253 		// get() should return the same values as the List from read()
254 		assertTrue(Arrays.equals(line.toArray(), new Object[] { csvReader.get(1), csvReader.get(2), csvReader.get(3),
255 			csvReader.get(4) }));
256 		
257 		assertEquals(5, csvReader.getLineNumber()); // 2 newlines in harry's address
258 		assertEquals(3, csvReader.getRowNumber());
259 		assertEquals("Harry, Potter, , \"Gryffindor\nHogwarts Castle\nUK\" ", csvReader.getUntokenizedRow());
260 		assertEquals(4, csvReader.length());
261 		
262 		// read again (should be EOF)
263 		assertFalse(csvReader.readRow());
264 		assertEquals(5, csvReader.getLineNumber());
265 		assertEquals(3, csvReader.getRowNumber());
266 		assertEquals("", csvReader.getUntokenizedRow());
267 		assertEquals(0, csvReader.length());
268 		
269 	}
270 	
271 	/**
272 	 * Tests the getCsvHeader(true) can't be called when a line has already been read.
273 	 */
274 	@Test
275 	public void testIllegalGetHeader() throws IOException {
276 		
277 		abstractReader.getHeader(true);
278 		
279 		try {
280 			abstractReader.getHeader(true);
281 			fail("should have thrown SuperCsvException");
282 		}
283 		catch(SuperCsvException e) {
284 			assertEquals("CSV header must be fetched as the first read operation, but 1 lines have already been read",
285 				e.getMessage());
286 		}
287 		
288 	}
289 	
290 	/**
291 	 * Tests getCsvHeader(false).
292 	 */
293 	@Test
294 	public void testGetHeaderNoCheck() throws IOException {
295 		assertEquals(4, abstractReader.getHeader(false).length);
296 		assertEquals(4, abstractReader.getHeader(false).length);
297 		assertEquals(4, abstractReader.getHeader(false).length);
298 		assertNull(abstractReader.getHeader(false)); // should be EOF
299 	}
300 	
301 	/**
302 	 * Tests the Reader constructor with a null Reader.
303 	 */
304 	@SuppressWarnings("resource")
305 	@Test(expected = NullPointerException.class)
306 	public void testReaderConstructorWithNullReader() {
307 		new CsvListReader((Reader) null, PREFS);
308 	}
309 	
310 	/**
311 	 * Tests the Reader constructor with a null preference.
312 	 */
313 	@SuppressWarnings("resource")
314 	@Test(expected = NullPointerException.class)
315 	public void testReaderConstructorWithNullPreferences() {
316 		new CsvListReader(reader, null);
317 	}
318 	
319 	/**
320 	 * Tests the Tokenizer constructor with a null Reader.
321 	 */
322 	@SuppressWarnings("resource")
323 	@Test(expected = NullPointerException.class)
324 	public void testTokenizerConstructorWithNullReader() {
325 		new CsvListReader((Tokenizer) null, PREFS);
326 	}
327 	
328 	/**
329 	 * Tests the Tokenizer constructor with a null preference.
330 	 */
331 	@SuppressWarnings("resource")
332 	@Test(expected = NullPointerException.class)
333 	public void testTokenizerConstructorWithNullPreferences() {
334 		new CsvListReader(tokenizer, null);
335 	}
336 	
337 }