r2239 - in trunk/nuiton-csv/src: main/java/org/nuiton/util/csv test/java/org/nuiton/util test/java/org/nuiton/util/csv test/resources test/resources/org test/resources/org/nuiton test/resources/org/nuiton/util test/resources/org/nuiton/util/csv
Author: fdesbois Date: 2011-11-29 15:34:18 +0100 (Tue, 29 Nov 2011) New Revision: 2239 Url: http://nuiton.org/repositories/revision/nuiton-utils/2239 Log: #1818: Add unit tests for Import Added: trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java trunk/nuiton-csv/src/test/resources/log4j.properties trunk/nuiton-csv/src/test/resources/org/ trunk/nuiton-csv/src/test/resources/org/nuiton/ trunk/nuiton-csv/src/test/resources/org/nuiton/util/ trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/ trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/importTest.csv Modified: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java Modified: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java =================================================================== --- trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java 2011-11-28 22:21:43 UTC (rev 2238) +++ trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java 2011-11-29 14:34:18 UTC (rev 2239) @@ -24,11 +24,6 @@ */ package org.nuiton.util.csv; -import com.csvreader.CsvReader; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.nuiton.util.StringUtil; - import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -43,6 +38,11 @@ import java.util.NoSuchElementException; import java.util.Set; +import com.csvreader.CsvReader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; + import static org.nuiton.i18n.I18n._; /** @@ -52,7 +52,7 @@ * @author tchemit <chemit@codelutin.com> * @since 2.4 */ -public class Import<E> { +public class Import<E> implements Iterable<E> { /** Logger. */ private static final Log log = LogFactory.getLog(Import.class); @@ -136,17 +136,27 @@ } public Iterator<E> startImport() throws IOException { + validateHeaders(); + Iterator<E> result = iterator(); + return result; + } + public void validateHeaders() + throws IOException { + ValidationResult validationResult = validateCsv(); if (!validationResult.isSuccess()) { throw new IOException(validationResult.getMessage()); } + } + @Override + public Iterator<E> iterator() { + // XXX-fdesbois-2011-11-28 : it will be better to have a flag in ImportModel to know if headers are present or not readFirstLine(); + return new Iterator<E>() { - Iterator<E> result = new Iterator<E>() { - boolean hasNext = true; int lineNumber; @@ -159,7 +169,8 @@ } @Override - public E next() throws NoSuchElementException, ImportRuntimeException { + public E next() + throws NoSuchElementException, ImportRuntimeException { if (!hasNext) { throw new NoSuchElementException(); @@ -186,7 +197,7 @@ parsedValue = field.parseValue(value); } catch (Exception e) { String message = _("csv.import.error.unableToParseValue", value, field.getHeaderName(), lineNumber) - + "\n" + e.getMessage(); + + "\n" + e.getMessage(); throw new ImportRuntimeException(message, e); } @@ -195,9 +206,9 @@ field.setValue(element, parsedValue); } catch (Exception e) { String message = _("csv.import.error.unableToSetValue", - parsedValue, - element.toString(), - lineNumber, field.getHeaderName()); + parsedValue, + element.toString(), + lineNumber, field.getHeaderName()); if (log.isErrorEnabled()) { log.error(message); } @@ -222,8 +233,8 @@ public void remove() { throw new UnsupportedOperationException(); } + }; - return result; } public void stopImport() { Added: trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java =================================================================== --- trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java (rev 0) +++ trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java 2011-11-29 14:34:18 UTC (rev 2239) @@ -0,0 +1,371 @@ +/* + * #%L + * Nuiton Utils :: Nuiton Csv + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.util.csv; + +import java.io.IOException; +import java.io.InputStream; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.util.DateUtil; +import org.nuiton.util.csv.Common.BeanProperty; + +/** + * Created on 28/11/11 + * + * @author fdesbois <florian.desbois@wiztivi.com> + */ +public class ImportTest { + + private DateFormat dateFormat; + + @Before + public void setUp() { + dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + + /** + * Test with {@link SimpleImportModel} that directly implements necessary {@link ImportableColumn}. + * + * @throws Exception for errors + */ + @Test + public void testSimpleImport() + throws Exception { + execute(new SimpleImportModel(dateFormat)); + } + + /** + * Test with {@link ColumnImportModel} that uses {@link Column} and {@link Common} tools. + * + * @throws Exception for errors + */ + @Test + public void testColumnImport() + throws Exception { + execute(new ColumnImportModel(dateFormat)); + } + + private void execute(ImportModel<Row> model) + throws IOException { + + InputStream csvStream = getClass().getResourceAsStream("importTest.csv"); + Import<Row> rowImport = Import.newImport(model, csvStream); + try { + Iterator<Row> it = rowImport.startImport(); + List<Row> rows = newList(it); + Assert.assertEquals(3, rows.size()); + Row row1 = rows.get(0); + Assert.assertEquals(DateUtil.createDate(5, 12, 2011), row1.getDate()); + Assert.assertEquals(new Integer(18), row1.getNumber()); + Assert.assertEquals("1ère ligne", row1.getTitle()); + Row row2 = rows.get(1); + Assert.assertEquals(DateUtil.createDate(6, 12, 2011), row2.getDate()); + Assert.assertEquals(new Integer(19), row2.getNumber()); + Assert.assertEquals("2ème ligne", row2.getTitle()); + Row row3 = rows.get(2); + Assert.assertEquals(DateUtil.createDate(7, 12, 2011), row3.getDate()); + Assert.assertEquals(new Integer(21), row3.getNumber()); + Assert.assertEquals("3ème ligne", row3.getTitle()); + } finally { + rowImport.stopImport(); + } + } + + private static <T> List<T> newList(Iterator<T> iterator) { + List<T> result = new ArrayList<T>(); + while(iterator.hasNext()) { + result.add(iterator.next()); + } + return result; + } + + public static class Row { + + private Date date; + + private String title; + + private Integer number; + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + } + + private static class ColumnImportModel implements ImportModel<Row> { + + private DateFormat dateFormat; + + private ColumnImportModel(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public char getSeparator() { + return ';'; + } + + @Override + public void pushCsvHeaderNames(List<String> headerNames) { + } + + @Override + public Row newEmptyInstance() { + return new Row(); + } + + @SuppressWarnings({"unchecked"}) + @Override + public Collection<ImportableColumn<Row, Object>> getColumnsForImport() { + List<ImportableColumn<Row, Object>> result = new ArrayList<ImportableColumn<Row, Object>>(); + // Column types are not checked but safe because Object is necessary, and element type is always Row + result.add(getTitleColumn()); + result.add(getNumberColumn()); + result.add(getDateColumn()); + return result; + } + + private Column getTitleColumn() { + return Column.newImportableColumn( + "TITLE", + Common.STRING, + withBeanSetter("title", String.class), + false + ); + } + + private Column getDateColumn() { + return Column.newImportableColumn( + "DATE", + withDateParser(), + withBeanSetter("date", Date.class), + false + ); + } + + private Column getNumberColumn() { + return Column.newImportableColumn( + "NUMBER", + Common.INTEGER, + withBeanSetter("number", Integer.class), + false + ); + } + + @SuppressWarnings({"UnusedParameters"}) + private <T> ValueSetter<Row, T> withBeanSetter(String propertyName, Class<T> propertyClass) { + // propertyClass is not used but useful to check type + return new BeanProperty<Row, T>(propertyName); + } + + private ValueParser<Date> withDateParser() { + return new ValueParser<Date>() { + + @Override + public Date parse(String value) + throws ParseException { + return dateFormat.parse(value); + } + }; + } + } + + private static class SimpleImportModel implements ImportModel<Row> { + + private Log log = LogFactory.getLog(SimpleImportModel.class); + + private DateFormat dateFormat; + + private SimpleImportModel(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public char getSeparator() { + return ';'; + } + + @Override + public void pushCsvHeaderNames(List<String> headerNames) { + log.info("Headers are : " + headerNames); + } + + @Override + public Row newEmptyInstance() { + return new Row(); + } + + @Override + public Collection<ImportableColumn<Row, Object>> getColumnsForImport() { + List<ImportableColumn<Row, Object>> result = new ArrayList<ImportableColumn<Row, Object>>(); + result.add(getTitleImportable()); + result.add(getNumberImportable()); + result.add(getDateImportable()); + return result; + } + + private ImportableColumn<Row, Object> getTitleImportable() { + return new AbstractImportableColumn<Row, String>() { + + @Override + public String getHeaderName() { + return "TITLE"; + } + + @Override + public boolean isMandatory() { + return true; + } + + @Override + public boolean isIgnored() { + return false; + } + + @Override + public String parseValue(String value) + throws ParseException { + return value; + } + + @Override + public void update(Row object, + String value) + throws Exception { + object.setTitle(value); + } + }; + } + + private ImportableColumn<Row, Object> getDateImportable() { + return new AbstractImportableColumn<Row, Date>() { + + @Override + public String getHeaderName() { + return "DATE"; + } + + @Override + public boolean isMandatory() { + return true; + } + + @Override + public boolean isIgnored() { + return false; + } + + @Override + public Date parseValue(String value) + throws ParseException { + return dateFormat.parse(value); + } + + @Override + public void update(Row object, + Date value) + throws Exception { + object.setDate(value); + } + }; + } + + private ImportableColumn<Row, Object> getNumberImportable() { + return new AbstractImportableColumn<Row, Integer>() { + + @Override + public String getHeaderName() { + return "NUMBER"; + } + + @Override + public boolean isMandatory() { + return true; + } + + @Override + public boolean isIgnored() { + return false; + } + + @Override + public Integer parseValue(String value) + throws ParseException { + return Integer.parseInt(value); + } + + @Override + public void update(Row object, + Integer value) + throws Exception { + object.setNumber(value); + } + }; + } + } + + private static abstract class AbstractImportableColumn<E, F> implements ImportableColumn<E, Object> { + + @Override + public void setValue(E object, + Object value) + throws Exception { + update(object, (F) value); + } + + protected abstract void update(E object, F value) + throws Exception; + } + +} // $Id$ Copied: trunk/nuiton-csv/src/test/resources/log4j.properties (from rev 2237, trunk/nuiton-utils/src/test/resources/log4j.properties) =================================================================== --- trunk/nuiton-csv/src/test/resources/log4j.properties (rev 0) +++ trunk/nuiton-csv/src/test/resources/log4j.properties 2011-11-29 14:34:18 UTC (rev 2239) @@ -0,0 +1,34 @@ +### +# #%L +# Nuiton Utils +# +# $Id$ +# $HeadURL$ +# %% +# Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric +# %% +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Lesser Public License for more details. +# +# You should have received a copy of the GNU General Lesser Public +# License along with this program. If not, see +# <http://www.gnu.org/licenses/lgpl-3.0.html>. +# #L% +### +# Global logging configuration +log4j.rootLogger=ERROR, stdout + +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +# package level +log4j.logger.org.nuiton.util=INFO Added: trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/importTest.csv =================================================================== --- trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/importTest.csv (rev 0) +++ trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/importTest.csv 2011-11-29 14:34:18 UTC (rev 2239) @@ -0,0 +1,4 @@ +DATE;NUMBER;TITLE +2011-12-05;18;"1ère ligne" +2011-12-06;19;"2ème ligne" +2011-12-07;21;"3ème ligne" \ No newline at end of file
participants (1)
-
fdesbois@users.nuiton.org