/* * This file is part of the GeoLatte project. * * GeoLatte 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. * * GeoLatte 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GeoLatte. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2010 - 2010 and Ownership of code is shared by: * Qmino bvba - Romeinsestraat 18 - 3001 Heverlee (http://www.qmino.com) * Geovise bvba - Generaal Eisenhowerlei 9 - 2140 Antwerpen (http://www.geovise.com) */ package org.geolatte.common.transformer; import org.geolatte.common.transformer.testutil.LoggingTransformerEventListener; import org.geolatte.common.transformer.testutil.LoggingTransformerSourceEventListener; import org.geolatte.testobjects.*; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; /** * <p> * Tests the TransformerChainFactory. * <p> * <i>Creation-Date</i>: 19-Apr-2010<br> * <i>Creation-Time</i>: 11:17:20<br> * </p> * * @author Bert Vanhooff * @author <a href="http://www.qmino.com">Qmino bvba</a> * @since SDK1.5 */ public class TransformerChainFactoryTest { private Transformation<Double, String> numberTransformation; private Transformation<String, String> capitalizeTransformation; private Transformation<String, Integer> countTransformation; private Transformer<Double, String> numberTransformer; private Transformer<String, String> capitalizeTransformer; private Transformer<String, Integer> countTransformer; @Before public void setUp() throws Exception { numberTransformation = new CharacterNumberTransformation(); capitalizeTransformation = new CapitalizeTransformation(); countTransformation = new CharacterCountTransformation(); numberTransformer = new DefaultTransformer<Double, String>(numberTransformation); capitalizeTransformer = new DefaultTransformer<String, String>(capitalizeTransformation); countTransformer = new DefaultTransformer<String, Integer>(countTransformation); } @After public void tearDown() throws Exception { } /** * Verifies whether a transformer chain cannot be constructed with 'null' transformers. */ @Test public void test_CompositionErrors() { // Try to add a null transformer at several places in the chain try { TransformerChainFactory.<Double, Integer>newChain().add((Transformer<Double, Object>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(numberTransformer) .add((Transformer<String,String>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(numberTransformer) .last((Transformer<String, Integer>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(numberTransformer) .last((Transformation<String, Integer>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add((TransformerSource<Double>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(new DummyTransformerSource<Double>(new ArrayList<Double>(Arrays.asList(2.2)))) .add((Transformer<Double, Integer>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(new DummyTransformerSource<Double>(new ArrayList<Double>(Arrays.asList(2.2)))) .add((Transformation<Double, Integer>)null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(new DummyTransformerSource<Double>(new ArrayList<Double>(Arrays.asList(2.2)))) .last((Transformer<? super Double,Integer>) null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } try { TransformerChainFactory.<Double, Integer>newChain().add(new DummyTransformerSource<Double>(new ArrayList<Double>(Arrays.asList(2.2)))) .last((TransformerSink<Integer>) null); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); // this should happen } } /** * Checks whether a transformer chain can be constructed and executed without a source. */ @Test public void test_Composition() { ArrayList<Double> input = new ArrayList<Double>(Arrays.asList(88.0, 754.8, 0.0, 123456.2)); ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList(4, 5, 3, 8)); Transformer<Double, Integer> compositeTransformer = TransformerChainFactory.<Double, Integer>newChain().add(numberTransformer) .add(capitalizeTransformer) .last(countTransformer); compositeTransformer.setInput(input); int count = 0; for (Integer i : compositeTransformer.output()) { Assert.assertEquals(expectedResults.get(count), i); count++; } } /** * Checks whether a transformer chain can be constructed using Transformations (who should be wrapped into Transformers automatically). */ @Test public void test_TransformationComposition() { ArrayList<Double> input = new ArrayList<Double>(Arrays.asList(88.0, 754.8, 0.0, 123456.2)); ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList(4, 5, 3, 8)); Transformer<Double, Integer> compositeTransformer = TransformerChainFactory.<Double, Integer>newChain().add(numberTransformation) .add(capitalizeTransformation) .last(countTransformation); compositeTransformer.setInput(input); int count = 0; for (Integer i : compositeTransformer.output()) { Assert.assertEquals(expectedResults.get(count), i); count++; } } /** * Checks whether a transformer chain can be constructed and executed without a source and with filters. */ @Test public void test_CompositionWithFilters() { // invocation count (as seen by the first stage) 1 2 3 4 5 6 // invocation count (as seen by the second stage) 1 2 3 4 ArrayList<Double> input = new ArrayList<Double>(Arrays.asList(88.0, 754.8, 0.0, 123456.2, 321.3, 3210.5)); Integer[] filteredOutFirstStage = new Integer[] {2, 4}; Integer[] filteredOutSecondStage = new Integer[] {4}; ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList(4, 3, 5)); ProgrammableFilter<Double> firstFilterTransformation = new ProgrammableFilter<Double>(filteredOutFirstStage); DefaultFilter<Double> firstFilter = new DefaultFilter<Double>(firstFilterTransformation); ProgrammableFilter<String> secondFilterTransformation = new ProgrammableFilter<String>(filteredOutSecondStage); DefaultFilter<String> secondFilter = new DefaultFilter<String>(secondFilterTransformation); Transformer<Double, Integer> compositeTransformer = TransformerChainFactory.<Double, Integer>newChain().add(firstFilter) .add(numberTransformer) .add(secondFilter) .add(capitalizeTransformer) .last(countTransformer); compositeTransformer.setInput(input); int count = 0; for (Integer i : compositeTransformer.output()) { Assert.assertEquals(expectedResults.get(count), i); count++; } } /** * Checks whether a transformer chain can be constructed using Transformations and Filters (who should be wrapped into Transformers automatically). */ @Test public void test_TransformationCompositionWithFilters() { // invocation count (as seen by the first stage) 1 2 3 4 5 6 // invocation count (as seen by the second stage) 1 2 3 4 ArrayList<Double> input = new ArrayList<Double>(Arrays.asList(88.0, 754.8, 0.0, 123456.2, 321.3, 3210.5)); Integer[] filteredOutFirstStage = new Integer[] {2, 4}; Integer[] filteredOutSecondStage = new Integer[] {4}; ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList(4, 3, 5)); ProgrammableFilter<Double> firstFilterTransformation = new ProgrammableFilter<Double>(filteredOutFirstStage); ProgrammableFilter<String> secondFilterTransformation = new ProgrammableFilter<String>(filteredOutSecondStage); Transformer<Double, Integer> compositeTransformer = TransformerChainFactory.<Double, Integer>newChain().addFilter(firstFilterTransformation) .add(numberTransformer) .addFilter(secondFilterTransformation) .add(capitalizeTransformer) .last(countTransformer); compositeTransformer.setInput(input); int count = 0; for (Integer i : compositeTransformer.output()) { Assert.assertEquals(expectedResults.get(count), i); count++; } } /** * Checks whether a transformer chain can be constructed and executed with an initial TransformationSource. */ @Test public void test_CompositionWithSource() { ArrayList<Double> input = new ArrayList<Double>(Arrays.asList(88.0, 754.8, 0.0, 123456.2)); ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList(4, 5, 3, 8)); // With transformer source TransformerSource<Double> initialSource = new DummyTransformerSource<Double>(input); OpenTransformerChain<Integer> chain = TransformerChainFactory.<Double, Integer>newChain().add(initialSource) .add(numberTransformer) .add(capitalizeTransformer) .last(countTransformer); int count = 0; for (Integer i : chain) { Assert.assertEquals(expectedResults.get(count), i); count++; } } /** * Checks whether a closed transformer chain can be constructed and executed with a TransformationSource, a Sink and * no transformers in between. */ @Test public void test_CompositionWithSourceAndTargetNoTransformers() { ArrayList<Double> input = new ArrayList<Double>(Arrays.asList(88.0, 754.8, 0.0, 123456.2)); // With transformer source TransformerSource<Double> initialSource = new DummyTransformerSource<Double>(input); ArrayList<Double> results = new ArrayList<Double>(); DummyTransformerSink<Double> sink = new DummyTransformerSink<Double>(results); ClosedTransformerChain chain = TransformerChainFactory.<Double, Double>newChain() .add(initialSource) .last(sink); chain.run(); int count = 0; for (Double i : results) { Assert.assertEquals(input.get(count), i); count++; } } /** * Tests whether error events are correctly fired for an open transformer chain. */ @Test public void test_OpenTransformerChainErrorReporting() { // Invocation number : 1 2 3 4 5 6 7 8 9 10 ArrayList<Double> input = new ArrayList<Double>( Arrays.asList(1.2, 1.23, 1.234, 1.2345, 1.23456, 1.234567, 1.2345678, 1.23456789, 1.234567891, 1.2345678912)); ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList( 3, 5, 6, 8, 9, 11)); // Output element num 0 1 2 3 4 5 // Transformer error on 5th and 8th invocation (source fails on 2, so the transformation never gets the 2nd element, therefore 5->4 and 8->7 ExceptionThrowingTransformation<String> tf = new ExceptionThrowingTransformation<String>(4, 7); DefaultTransformer<String, String> errorTransformer = new DefaultTransformer<String, String>(tf); // Transformer source error on 2nd and 9th invocation TransformerSource<Double> initialSource = new DummyTransformerSource<Double>(input, 2, 10); // Create an OpenTransformerChain OpenTransformerChain<Integer> chain = TransformerChainFactory.<Double, Integer>newChain().add(initialSource) .add(numberTransformer) .add(capitalizeTransformer) .add(errorTransformer) .last(countTransformer); // Listen to Transformer Error events LoggingTransformerEventListener loggingTransformerEventListener = new LoggingTransformerEventListener(); chain.addTransformerEventListener(loggingTransformerEventListener); // Listen to Transformer Source Error events LoggingTransformerSourceEventListener loggingTransformerSourceEventListener = new LoggingTransformerSourceEventListener(); chain.addSourceEventListener(loggingTransformerSourceEventListener); ArrayList<Integer> actualOutput = new ArrayList<Integer>(); for (Integer i : chain) { actualOutput.add(i); } // Verify that failed inputs are skipped Assert.assertEquals(expectedResults, actualOutput); // Verify that each failed transformations are reported Assert.assertEquals(2, loggingTransformerEventListener.errorsReported); // Verify that each failed source is reported Assert.assertEquals(2, loggingTransformerSourceEventListener.errorsReported); // Verify that the ErrorEvent reports the expected correct object and exception type // Verify whether the source of the error is the correct transformer Assert.assertEquals(errorTransformer, loggingTransformerEventListener.eventsOccurred.get(0).getSource()); Assert.assertEquals(errorTransformer, loggingTransformerEventListener.eventsOccurred.get(1).getSource()); Assert.assertTrue(loggingTransformerEventListener.eventsOccurred.get(0).getException() instanceof TransformationException); Assert.assertTrue(loggingTransformerEventListener.eventsOccurred.get(1).getException() instanceof TransformationException); // TODO : Error should contain the first //Assert.assertEquals(input.get(4), loggingTransformerEventListener.eventsOccurred.get(0).getFailedObject()); //Assert.assertEquals(input.get(7), loggingTransformerEventListener.eventsOccurred.get(1).getFailedObject()); Assert.assertNotNull(loggingTransformerSourceEventListener.eventsOccurred.get(0)); Assert.assertNotNull(loggingTransformerSourceEventListener.eventsOccurred.get(1)); } /** * Tests whether error events are correctly fired for a closed transformer chain. */ @Test public void test_ClosedTransformerChainErrorReporting() { // Invocation number : 1 2 3 4 5 6 7 8 9 10 ArrayList<Double> input = new ArrayList<Double>( Arrays.asList(1.2, 1.23, 1.234, 1.2345, 1.23456, 1.234567, 1.2345678, 1.23456789, 1.234567891, 1.2345678912)); ArrayList<Integer> expectedResults = new ArrayList<Integer>(Arrays.asList( 3, 5, 6, 8, 9, 11)); // Output element num 0 1 2 3 4 5 ArrayList<Integer> actualResults = new ArrayList<Integer>(); // Create an OpenTransformerChain TransformerSource<Double> initialSource = new DummyTransformerSource<Double>(input); TransformerSink<Integer> sink = new DummyTransformerSink<Integer>(actualResults, 2, 5, 8, 10); ClosedTransformerChain chain = TransformerChainFactory.<Double, Integer>newChain().add(initialSource) .add(numberTransformer) .add(capitalizeTransformer) .add(countTransformer) .last(sink); // Listen to Transformer Error events LoggingTransformerEventListener loggingTransformerEventListener = new LoggingTransformerEventListener(); chain.addTransformerEventListener(loggingTransformerEventListener); // Listen to Transformer Source Error events LoggingTransformerSourceEventListener loggingTransformerSourceEventListener = new LoggingTransformerSourceEventListener(); chain.addSourceEventListener(loggingTransformerSourceEventListener); // execute the closed chain chain.run(); // Verify that failed inputs are skipped Assert.assertEquals(expectedResults, actualResults); // Verify that no failed transformations are reported Assert.assertEquals(0, loggingTransformerEventListener.errorsReported); // Verify that no failed source is reported Assert.assertEquals(0, loggingTransformerSourceEventListener.errorsReported); // Verify that the ErrorEvent reports the expected correct object and exception type } }