/* * Copyright 2006-2012 The Scriptella Project Team. * * Licensed 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 scriptella.driver.csv; import scriptella.AbstractTestCase; import scriptella.configuration.MockConnectionEl; import scriptella.configuration.StringResource; import scriptella.driver.text.AbstractTextConnection; import scriptella.spi.ConnectionParameters; import scriptella.spi.MockConnectionParameters; import scriptella.spi.MockDriverContext; import scriptella.spi.MockParametersCallbacks; import scriptella.spi.ParametersCallback; import scriptella.spi.QueryCallback; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.HashMap; import java.util.Map; /** * Tests for {@link CsvConnection}. * * @author Fyodor Kupolov * @version 1.0 */ public class CsvConnectionTest extends AbstractTestCase { private int rows; private ByteArrayOutputStream out; private String testCsvInput; protected void setUp() throws Exception { super.setUp(); testCsvInput = "c1;c2;c3\nc4;'c''5';c6\u0394"; testURLHandler = new TestURLHandler() { public InputStream getInputStream(final URL u) { try { return new ByteArrayInputStream(testCsvInput.getBytes("UTF8")); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e.getMessage(), e); } } public OutputStream getOutputStream(final URL u) { out = new ByteArrayOutputStream(); return out; } public int getContentLength(final URL u) { return -1; } }; } public void testQuery() { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.ENCODING, "UTF8"); props.put(CsvConnection.EOL, "\r\n"); props.put(CsvConnection.HEADERS, "false"); props.put(CsvConnection.QUOTE, "'"); props.put(CsvConnection.ESCAPE, "\\"); props.put(CsvConnection.SEPARATOR, ";"); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); //register handler for tst url rows = 0; con.executeQuery(new StringResource(""), MockParametersCallbacks.UNSUPPORTED, new QueryCallback() { public void processRow(final ParametersCallback parameters) { rows++; switch (rows) { case 1: assertEquals("c1", parameters.getParameter("1")); assertEquals("c2", parameters.getParameter("2")); assertEquals("c3", parameters.getParameter("3")); break; case 2: assertEquals("c4", parameters.getParameter("1")); assertEquals("c'5", parameters.getParameter("2")); assertEquals("c6\u0394", parameters.getParameter("3")); break; default: fail("unexpected row " + rows); } } }); assertEquals(2, rows); assertNull("No output should be produced by a query", out); } public void testScript() throws UnsupportedEncodingException { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.ENCODING, "UTF8"); props.put(CsvConnection.EOL, "\r\n"); props.put(CsvConnection.QUOTE, ""); props.put(CsvConnection.SEPARATOR, ";"); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); //register handler for tst url rows = 0; con.executeScript(new StringResource(" $row1,\"value\",val${'ue'}\n$row2,,value\u0394"), MockParametersCallbacks.SIMPLE); con.close(); String expected = "*row1*;value;value\r\n*row2*;;value\u0394\r\n"; String actual = out.toString("UTF8"); assertEquals(expected, actual); } public void testEscape() throws UnsupportedEncodingException { Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.ESCAPE, "'"); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); //register handler for tst url rows = 0; con.executeScript(new StringResource(" $row1,\"value\",val${'ue'}\n$row2,'value',va'l'ue\n"), MockParametersCallbacks.SIMPLE); con.close(); String expected = "\"*row1*\",\"value\",\"value\"\n\"*row2*\",\"''value''\",\"va''l''ue\"\n"; String actual = out.toString("UTF8"); assertEquals(expected, actual); } public void testQuoteall() throws UnsupportedEncodingException { Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.QUOTEALL, "false"); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); //register handler for tst url rows = 0; con.executeScript(new StringResource(" $row1,va\"l\"ue,val${'ue'}\n$row2,'value',va\"l\"ue\n"), MockParametersCallbacks.SIMPLE); con.close(); String expected = "*row1*,\"va\"\"l\"\"ue\",value\n*row2*,'value',\"va\"\"l\"\"ue\"\n"; String actual = out.toString("UTF8"); assertEquals(expected, actual); } /** * Tests CSV processing with trim mode switched off. */ public void testNoTrim() { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.TRIM, "no"); props.put(CsvConnection.QUOTE, ""); props.put(CsvConnection.EOL, "\r\n"); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); rows = 0; CsvConnection con = new CsvConnection(cp); con.executeQuery(new StringResource(" c4.*"), //extra leading whitespace MockParametersCallbacks.SIMPLE, new QueryCallback() { public void processRow(final ParametersCallback parameters) { rows++; } }); con.executeScript(new StringResource(" $a,$b , $c "), MockParametersCallbacks.SIMPLE); con.close(); String expected = " *a*,*b* , *c* \r\n"; String actual = out.toString(); assertEquals(expected, actual); assertEquals(1, rows); } public void testAutoFlush() { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.FLUSH, "true"); props.put(CsvConnection.QUOTE, ""); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); String str = "-test-"; con.executeScript(new StringResource(str), MockParametersCallbacks.NULL); assertNotNull(out); assertEquals(str + "\n", new String(out.toByteArray())); } public void testNullStringScript() { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(AbstractTextConnection.NULL_STRING, ""); props.put(CsvConnection.QUOTE, ""); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); String str = "$a,$b,$c"; props = new HashMap<String, String>(); props.put("a", "1"); props.put("c", "2"); con.executeScript(new StringResource(str), MockParametersCallbacks.fromMap(props)); con.close(); assertEquals("1,,2\n", new String(out.toByteArray())); } public void testNullStringQuery() { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(AbstractTextConnection.NULL_STRING, ""); props.put(CsvConnection.HEADERS, "false"); ConnectionParameters cp = new MockConnectionParameters(props, "tst://file"); CsvConnection con = new CsvConnection(cp); testCsvInput= "a,,c"; final Map<String, Object> map = new HashMap<String, Object>(); con.executeQuery(new StringResource(""), MockParametersCallbacks.SIMPLE, new QueryCallback() { @Override public void processRow(ParametersCallback parameters) { map.put("1", parameters.getParameter("1")); map.put("2", parameters.getParameter("2")); map.put("3", parameters.getParameter("3")); map.put("4", parameters.getParameter("4")); } }); con.close(); assertEquals("a", map.get("1")); assertNull("Null must be returned for a value=null_string", map.get("2")); assertEquals("c", map.get("3")); assertEquals("getParameter must delegate to the parent callback if parameter was not found", "*4*", map.get("4")); } /** * Tests if skip_lines is working. */ public void testSkipLines() { //Create a configuration with non default values Map<String, String> props = new HashMap<String, String>(); props.put(CsvConnection.SKIP_LINES, "2"); ConnectionParameters cp = new ConnectionParameters(new MockConnectionEl(props, "tst://file"), MockDriverContext.INSTANCE); CsvConnection con = new CsvConnection(cp); testCsvInput = "-skipped---,--\n-skipped---,--\nc1,c2\n11,12"; rows = 0; con.executeQuery(new StringResource(""), MockParametersCallbacks.NULL, new QueryCallback() { public void processRow(final ParametersCallback parameters) { rows++; assertEquals("11", parameters.getParameter("1")); assertEquals("11", parameters.getParameter("c1")); assertEquals("12", parameters.getParameter("2")); assertEquals("12", parameters.getParameter("c2")); } }); assertEquals(1, rows); //Now test if the number of lines to skip exceeds the file size testCsvInput = "v1,v2\nv3,v4"; rows = 0; con.executeQuery(new StringResource(""), MockParametersCallbacks.NULL, new QueryCallback() { public void processRow(final ParametersCallback parameters) { rows++; } }); assertEquals(0, rows); } }