/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available 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. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * 1Spatial PLC <http://www.1spatial.com> * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package com.onespatial.jrc.tns.oml_to_rif; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import org.geotools.filter.text.cql2.CQL; import org.geotools.filter.text.cql2.CQLException; import org.junit.BeforeClass; import org.junit.Test; import org.opengis.filter.Filter; import com.onespatial.jrc.tns.oml_to_rif.api.TranslationException; import com.onespatial.jrc.tns.oml_to_rif.api.Translator; import com.onespatial.jrc.tns.oml_to_rif.digest.CqlToMappingConditionTranslator; import com.onespatial.jrc.tns.oml_to_rif.model.alignment.ModelMappingCondition; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.FilterNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.comparison.AbstractComparisonNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.comparison.EqualToNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.comparison.GreaterThanNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.comparison.LessThanNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.geometric.UnitOfMeasureType; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.geometric.WithinNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.logical.AndNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.logical.NotNode; import com.onespatial.jrc.tns.oml_to_rif.model.rif.filter.nonterminal.logical.OrNode; /** * Tests for CQL to model RIF translator. * * @author Simon Payne (Simon.Payne@1spatial.com) / 1Spatial Group Ltd. * @author Richard Sunderland (Richard.Sunderland@1spatial.com) / 1Spatial Group Ltd. */ public class TestCqlToMappingConditionTranslator { private static Translator<Filter, ModelMappingCondition> digester; /** * Does class-wide setup (once-only). */ @BeforeClass public static void setUpClass() { digester = new CqlToMappingConditionTranslator(); } /** * Test that generates model RIF from a simple CQL query comprising an * equality test against a named property. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateSimpleEquality() throws CQLException, TranslationException { String cqlPredicate = "ATTR1='17'"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(EqualToNode.class))); EqualToNode node = (EqualToNode) result.getRoot(); assertNotNull(node.getLeft()); assertNotNull(node.getRight()); assertThat(node.getLeft().getPropertyName(), is(equalTo("ATTR1"))); //$NON-NLS-1$ assertThat(node.getRight().getLiteralValue().toString(), is(equalTo("17"))); //$NON-NLS-1$ } /** * Test that takes a simple logical expression comprising a parent logical * filter and for each child filter, an equality test. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateSimpleLogical() throws CQLException, TranslationException { String cqlPredicate = "ATTR1 < 10 AND ATTR2 < 2"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(AndNode.class))); assertNotNull(result.getRoot().getChildren()); assertThat(result.getRoot().getChildren().size(), is(equalTo(2))); FilterNode firstNode = result.getRoot().getChildren().get(0); assertThat(firstNode, is(instanceOf(LessThanNode.class))); LessThanNode less1 = (LessThanNode) firstNode; assertNotNull(less1.getLeft()); assertNotNull(less1.getLeft().getPropertyName()); assertThat(less1.getLeft().getPropertyName(), is(equalTo("ATTR1"))); //$NON-NLS-1$ assertNotNull(less1.getRight()); assertNotNull(less1.getRight().getLiteralValue()); assertThat(less1.getRight().getLiteralValue().toString(), is(equalTo("10"))); //$NON-NLS-1$ FilterNode secondNode = result.getRoot().getChildren().get(1); assertThat(secondNode, is(instanceOf(LessThanNode.class))); LessThanNode less2 = (LessThanNode) secondNode; assertNotNull(less2.getLeft()); assertNotNull(less2.getLeft().getPropertyName()); assertThat(less2.getLeft().getPropertyName(), is(equalTo("ATTR2"))); //$NON-NLS-1$ assertNotNull(less2.getRight()); assertNotNull(less2.getRight().getLiteralValue()); assertThat(less2.getRight().getLiteralValue().toString(), is(equalTo("2"))); //$NON-NLS-1$ } /** * Test that takes a slightly more complex logical expression comprising a * nested tree of predicates each comprising a comparison operation. Also it * tests the greater than and equals operations, and contains a mix of * string, floating-point and integer literals. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateMoreComplexLogical() throws CQLException, TranslationException { String cqlPredicate = "ATTR1 < 10.5 AND ATTR2 = 'chocolate' OR ATTR3 > 10"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(OrNode.class))); assertNotNull(result.getRoot().getChildren()); assertThat(result.getRoot().getChildren().size(), is(equalTo(2))); assertThat(result.getRoot().getChild(0), is(instanceOf(AndNode.class))); AndNode andNode = (AndNode) result.getRoot().getChild(0); assertNotNull(andNode.getChildren()); assertThat(andNode.getChildren().size(), is(equalTo(2))); assertThat(andNode.getChild(0), is(instanceOf(LessThanNode.class))); LessThanNode lessNode = (LessThanNode) andNode.getChild(0); checkComparisonRightLiteral(lessNode, "ATTR1", "10.5"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(andNode.getChild(1), is(instanceOf(EqualToNode.class))); EqualToNode equalNode = (EqualToNode) andNode.getChild(1); checkComparisonRightLiteral(equalNode, "ATTR2", "chocolate"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(result.getRoot().getChild(1), is(instanceOf(GreaterThanNode.class))); GreaterThanNode greaterNode = (GreaterThanNode) result.getRoot().getChild(1); checkComparisonRightLiteral(greaterNode, "ATTR3", "10"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Same as testTranslateSlightlyMoreComplexLogical but brackets around the * 'OR' express overrides the natural precedence of the 'AND' filter. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateLogicalPrecedenceOverridden() throws CQLException, TranslationException { String cqlPredicate = "ATTR1 < 10.5 AND (ATTR2 = 'chocolate' OR ATTR3 > 10)"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(AndNode.class))); AndNode andNode = (AndNode) result.getRoot(); assertNotNull(andNode.getChildren()); assertThat(andNode.getChildren().size(), is(equalTo(2))); assertThat(andNode.getChild(0), is(instanceOf(LessThanNode.class))); LessThanNode lessNode = (LessThanNode) andNode.getChild(0); checkComparisonRightLiteral(lessNode, "ATTR1", "10.5"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(andNode.getChild(1), is(instanceOf(OrNode.class))); OrNode orNode = (OrNode) andNode.getChild(1); assertThat(orNode.getChildren().size(), is(equalTo(2))); assertThat(orNode.getChild(0), is(instanceOf(EqualToNode.class))); EqualToNode equalNode = (EqualToNode) orNode.getChild(0); checkComparisonRightLiteral(equalNode, "ATTR2", "chocolate"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(orNode.getChild(1), is(instanceOf(GreaterThanNode.class))); GreaterThanNode greaterNode = (GreaterThanNode) orNode.getChild(1); checkComparisonRightLiteral(greaterNode, "ATTR3", "10"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Tests translating a CQL expression that negates the result of a simple * equality filter. * * @throws TranslationException * if any errors occurred during the translation * @throws CQLException * if any errors occurred parsing the CQL string */ @Test public void testTranslateNegatedEquality() throws CQLException, TranslationException { String cqlPredicate = "ATTR1 <> '17'"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(NotNode.class))); NotNode notNode = (NotNode) result.getRoot(); assertThat(notNode.getChildren().size(), is(equalTo(1))); assertThat(notNode.getChild(0), is(instanceOf(EqualToNode.class))); EqualToNode equalNode = (EqualToNode) notNode.getChild(0); assertThat(equalNode.getChildren().size(), is(equalTo(0))); checkComparisonRightLiteral(equalNode, "ATTR1", "17"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Tests translating a CQL expression where an 'AND' filter has three child * comparison operators. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateAndWithThreeChildren() throws CQLException, TranslationException { String cqlPredicate = "ATTR1 < 10.5 AND ATTR2 = 'chocolate' AND ATTR3 > 10"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), instanceOf(AndNode.class)); AndNode andNode = (AndNode) result.getRoot(); assertThat(andNode.getChildren().size(), is(equalTo(2))); assertThat(andNode.getChild(0), is(instanceOf(AndNode.class))); AndNode nestedAndNode = (AndNode) andNode.getChild(0); assertThat(nestedAndNode.getChild(0), is(instanceOf(LessThanNode.class))); LessThanNode lessNode = (LessThanNode) nestedAndNode.getChild(0); checkComparisonRightLiteral(lessNode, "ATTR1", "10.5"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(nestedAndNode.getChild(1), is(instanceOf(EqualToNode.class))); EqualToNode equalNode = (EqualToNode) nestedAndNode.getChild(1); checkComparisonRightLiteral(equalNode, "ATTR2", "chocolate"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(andNode.getChild(1), is(instanceOf(GreaterThanNode.class))); GreaterThanNode greaterNode = (GreaterThanNode) andNode.getChild(1); checkComparisonRightLiteral(greaterNode, "ATTR3", "10"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Tests translating a CQL expression that creates a simple equality filter * where both sides of the expression are property names. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateEqualityTwoProperties() throws CQLException, TranslationException { String cqlPredicate = "ATTR1 < ATTR2"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(LessThanNode.class))); LessThanNode lessNode = (LessThanNode) result.getRoot(); checkComparisonRightProperty(lessNode, "ATTR1", "ATTR2"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Tests translating a CQL expression which includes a geometric 'within' * predicate. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ // @Test public void testTranslateGeometricWithin() throws CQLException, TranslationException { String cqlPredicate = "DWITHIN(ATTR1, POINT(1 2), 10, kilometers)"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); assertThat(result.getRoot(), is(instanceOf(WithinNode.class))); WithinNode withinNode = (WithinNode) result.getRoot(); assertThat(withinNode.getLeaves().size(), is(equalTo(2))); assertNotNull(withinNode.getLeft()); assertThat(withinNode.getLeft().getPropertyName(), is(equalTo("ATTR1"))); //$NON-NLS-1$ assertNotNull(withinNode.getRight()); // CHECKSTYLE:OFF assertThat(withinNode.getDistance(), is(equalTo(10.0))); // CHECKSTYLE:ON assertThat(withinNode.getDistanceUnits(), is(equalTo(UnitOfMeasureType.kilometers))); } /** * Tests translating a CQL expression which includes a geometric 'contains' * predicate. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ // @Test public void testTranslateGeometricContains() throws CQLException, TranslationException { String cqlPredicate = "CONTAINS(ATTR1, ATTR2)"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); // TODO finish test assertions } /** * Tests the negation filter. * * @throws CQLException * if any errors occurred parsing the CQL string * @throws TranslationException * if any errors occurred during the translation */ @Test public void testTranslateNegation() throws CQLException, TranslationException { String cqlPredicate = "TEMA<>'RL_TUNNEL' OR TEMA<>'CL_RAIL' OR TEMA<>'UNSHOWN_RL'"; //$NON-NLS-1$ ModelMappingCondition result = digester.translate(CQL.toFilter(cqlPredicate)); assertNotNull(result); assertNotNull(result.getRoot()); // TODO finish test assertions } // =========================================== // TEST FIXTURE METHODS /** * Used for checking comparisons where left is a property name and right is * a literal. */ private void checkComparisonRightLiteral(AbstractComparisonNode node, String leftValue, String rightValue) { assertNotNull(node.getLeft()); assertThat(node.getChildren().size(), is(equalTo(0))); assertThat(node.getLeft().getPropertyName(), is(equalTo(leftValue))); assertNull(node.getLeft().getLiteralValue()); assertNotNull(node.getRight()); assertThat(node.getRight().getLiteralValue().toString(), is(equalTo(rightValue))); assertNull(node.getRight().getPropertyName()); } /** * Used for checking comparisons where left is a property name and right is * also a property name. */ private void checkComparisonRightProperty(AbstractComparisonNode node, String leftValue, String rightValue) { assertNotNull(node.getLeft()); assertThat(node.getChildren().size(), is(equalTo(0))); assertThat(node.getLeft().getPropertyName(), is(equalTo(leftValue))); assertNull(node.getLeft().getLiteralValue()); assertNotNull(node.getRight()); assertNull(node.getRight().getLiteralValue()); assertThat(node.getRight().getPropertyName().toString(), is(equalTo(rightValue))); } }