/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotools.filter.text.cql2;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.opengis.filter.ExcludeFilter;
import org.opengis.filter.Filter;
import org.opengis.filter.IncludeFilter;
import org.opengis.filter.PropertyIsBetween;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.PropertyIsGreaterThan;
import org.opengis.filter.PropertyIsLessThan;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
/**
* Test the extensions in CQL.
*
* <p>
* We adds some extension to Common CQL thinking in convenient uses.
* In the future we could have different dialects of CQL. That will
* required extend the interface to allow selecting the dialect to use.
* </p>
*
* @author Mauricio Pazos (Axios Engineering)
* @since 2.5
*
*
* @source $URL$
* @version Revision: 1.9
*/
public class CQLExtensionTest{
private static final String DELIMITER = ";";
/**
* An INCLUDE token is parsed as {@link Filter#INCLUDE}
*
* @throws Exception
*/
@Test
public void testIncludeFilter() throws Exception {
Filter filter = CQL.toFilter("INCLUDE");
Assert.assertNotNull(filter);
Assert.assertTrue(Filter.INCLUDE.equals(filter));
filter = CQL.toFilter("INCLUDE and a < 1");
Assert.assertNotNull(filter);
Assert.assertTrue(filter instanceof PropertyIsLessThan);
filter = CQL.toFilter("INCLUDE or a < 1");
Assert.assertNotNull(filter);
Assert.assertTrue(Filter.INCLUDE.equals(filter));
}
/**
* An EXCLUDE token is parsed as {@link Filter#EXCLUDE}
*
* @throws Exception
*/
@Test
public void testExcludeFilter() throws Exception {
Filter filter = CQL.toFilter("EXCLUDE");
Assert.assertNotNull(filter);
Assert.assertTrue(Filter.EXCLUDE.equals(filter));
filter = CQL.toFilter("EXCLUDE and a < 1");
Assert.assertNotNull(filter);
Assert.assertTrue(Filter.EXCLUDE.equals(filter));
filter = CQL.toFilter("EXCLUDE or a < 1");
Assert.assertNotNull(filter);
Assert.assertTrue(filter instanceof PropertyIsLessThan);
}
/**
* Simple test for sequence of search conditions with only one filter [*]
* <p>
* <pre>
* <SequenceOfSearchConditions > ::=
* <search condition> [*]
* | <SequenceOfSearchConditions> ; <search condition>
*
* </pre>
* <p>
*
* @throws Exception
*/
@Test
public void testSequenceOfSearchConditionsWithOneFilter() throws Exception {
String valueWithDelimiter = "text" + DELIMITER + "with" + DELIMITER + "delimiter";
final String singleFilterStr = "attr3 = '" + valueWithDelimiter + "'";
List<Filter> filters = CQL.toFilterList(singleFilterStr);
Assert.assertNotNull(filters);
Assert.assertEquals(1, filters.size());
Assert.assertTrue(filters.get(0) instanceof PropertyIsEqualTo);
PropertyIsEqualTo filter = (PropertyIsEqualTo) filters.get(0);
Assert.assertEquals("attr3", ((PropertyName) filter.getExpression1()).getPropertyName());
Assert.assertEquals(valueWithDelimiter, ((Literal) filter.getExpression2()).getValue());
}
/**
* Simple test for sequence of search conditions with only one filter [*]
* <p>
* <pre>
* <SequenceOfSearchConditions > ::=
* <search condition>
* | <SequenceOfSearchConditions> ; <search condition> [*]
*
* </pre>
* <p>
* Sample: attr1 > 5;attr2 between 1 and 7;attr3
*
* @throws Exception
*/
@Test
public void testSequenceOfSearchConditionsWithManyFilters() throws Exception {
String valueWithDelimiter = "text" + DELIMITER + "with" + DELIMITER + "delimiter";
// "attr1 > 5; attr2 between 1 and 7; attr3 = 'text;with;delimiter
final String filterListStr =
"attr1 > 5" + DELIMITER +
"attr2 between 1 and 7" + DELIMITER +
"attr3 = '" + valueWithDelimiter + "'";
List<Filter> filters = CQL.toFilterList(filterListStr);
Assert.assertNotNull(filters);
Assert.assertEquals(3, filters.size());
Assert.assertTrue(filters.get(0) instanceof PropertyIsGreaterThan);
Assert.assertTrue(filters.get(1) instanceof PropertyIsBetween);
Assert.assertTrue(filters.get(2) instanceof PropertyIsEqualTo);
PropertyIsGreaterThan gt = (PropertyIsGreaterThan) filters.get(0);
Assert.assertEquals("attr1", ((PropertyName) gt.getExpression1()).getPropertyName());
Assert.assertEquals(new Long(5), ((Literal) gt.getExpression2()).getValue());
PropertyIsBetween btw = (PropertyIsBetween) filters.get(1);
Assert.assertEquals("attr2", ((PropertyName) btw.getExpression()).getPropertyName());
Assert.assertEquals(new Long(1), ((Literal) btw.getLowerBoundary()).getValue());
Assert.assertEquals(new Long(7), ((Literal) btw.getUpperBoundary()).getValue());
PropertyIsEqualTo equals = (PropertyIsEqualTo) filters.get(2);
Assert.assertEquals("attr3", ((PropertyName) equals.getExpression1()).getPropertyName());
Assert.assertEquals(valueWithDelimiter, ((Literal) equals.getExpression2()).getValue());
}
/**
* An empty filter int the constraints list shall be parsed as
* {@link Filter#INCLUDE}
*
* @throws Exception
*/
@Test
public void testParseFilterListWithEmptyFilter() throws Exception {
String valueWithDelimiter = "text" + DELIMITER + "with" + DELIMITER + "delimiter";
// "attr1 > 5;INCLUDE;attr3 = 'text;with;delimiter'"
String filterListStr = "attr1 > 5" + DELIMITER + "INCLUDE" + DELIMITER + " attr3 = '"
+ valueWithDelimiter + "'";
List<Filter> filters = CQL.toFilterList(filterListStr);
Assert.assertNotNull(filters);
Assert.assertEquals(3, filters.size());
Assert.assertTrue(filters.get(0) instanceof PropertyIsGreaterThan);
Assert.assertTrue(filters.get(1) instanceof IncludeFilter);
Assert.assertTrue(filters.get(2) instanceof PropertyIsEqualTo);
PropertyIsGreaterThan gt = (PropertyIsGreaterThan) filters.get(0);
Assert.assertEquals("attr1", ((PropertyName) gt.getExpression1()).getPropertyName());
Assert.assertEquals(new Long(5), ((Literal) gt.getExpression2()).getValue());
PropertyIsEqualTo equals = (PropertyIsEqualTo) filters.get(2);
Assert.assertEquals("attr3", ((PropertyName) equals.getExpression1()).getPropertyName());
Assert.assertEquals(valueWithDelimiter, ((Literal) equals.getExpression2()).getValue());
filterListStr = "EXCLUDE" + DELIMITER + "INCLUDE" + DELIMITER + "attr3 = '"
+ valueWithDelimiter + "'";
filters = CQL.toFilterList(filterListStr);
Assert.assertTrue(filters.get(0) instanceof ExcludeFilter);
Assert.assertTrue(filters.get(1) instanceof IncludeFilter);
Assert.assertTrue(filters.get(2) instanceof PropertyIsEqualTo);
}
/**
* Tests null factory as parameter.
*
* @throws Exception
*/
@Test
public void testNullFilterFactory() throws Exception {
CQL.toFilter( "attName > 20", null );
CQL.toExpression( "2+2", null);
}
/**
* Test Function Expression
*
* Note: this solves the bug GEOT-1167
*
* @throws Exception
*/
@Test
public void testFuncitionExpression() throws Exception {
Expression arg1;
Expression arg2;
Expression resultExpr;
final String cqlExpression = "strConcat(A, B)";
// simple attribute as argument
resultExpr = CQL.toExpression(cqlExpression);
Assert.assertNotNull(resultExpr);
Assert.assertTrue(resultExpr instanceof Function);
Function function1 = (Function) resultExpr;
Assert.assertEquals(2, function1.getParameters().size());
arg1 = (Expression) function1.getParameters().get(0);
Assert.assertTrue(arg1 instanceof PropertyName);
Assert.assertEquals("A", ((PropertyName) arg1).getPropertyName());
arg2 = (Expression) function1.getParameters().get(1);
Assert.assertTrue(arg2 instanceof PropertyName);
Assert.assertEquals("B", ((PropertyName) arg2).getPropertyName());
// compound attribute as argument
final String arg1Name = "gmd:aa:bb.gmd:cc.gmd:dd";
final String arg2Name = "gmd:ee:ff.gmd:gg.gmd:hh";
final String cqlExpression2 = "strConcat(" + arg1Name + ", " + arg2Name + ")";
resultExpr = CQL.toExpression(cqlExpression2);
Assert.assertNotNull(resultExpr);
Assert.assertTrue(resultExpr instanceof Function);
Function function = (Function) resultExpr;
Assert.assertEquals(2, function.getParameters().size());
arg1 = (Expression) function.getParameters().get(0);
Assert.assertTrue(arg1 instanceof PropertyName);
final String arg1Expected = arg1Name.replace('.', '/');
Assert.assertEquals(arg1Expected, ((PropertyName) arg1).getPropertyName());
arg2 = (Expression) function.getParameters().get(1);
Assert.assertTrue(arg2 instanceof PropertyName);
final String arg2Expected = arg2Name.replace('.', '/');
Assert.assertEquals(arg2Expected, ((PropertyName) arg2).getPropertyName());
}
/**
* This test the following improvement: GEOT-1169 This is an extension the
* CQL specification.
*
* <pre>
* <function> ::= <routine name > <argument list > [*]
* <argument list> ::= [*]
* <left paren> [<positional arguments>] <right paren>
* <positional arguments> ::=
* <argument> [ { <comma> <argument> }... ]
* <argument> ::=
* <literal>
* | <attribute name>
* | <function> [*]
* | <binary expression> [*]
* </pre>
*
* @throws Exception
*/
@Test
public void testFunctionComposition()
throws Exception {
String cqlExpression;
Expression expression;
// Test 1
cqlExpression = "strConcat(A, abs(B))";
expression = CQL.toExpression(cqlExpression);
// Test 2
cqlExpression = "strConcat(A, strConcat(B, strConcat(C, '.')))";
expression = CQL.toExpression(cqlExpression);
Assert.assertNotNull(expression);
Assert.assertTrue(expression instanceof Function);
Function function = (Function) expression;
Assert.assertEquals(2, function.getParameters().size());
Expression propertyName = (Expression) function.getParameters().get(0);
Assert.assertTrue(propertyName instanceof PropertyName);
Assert.assertEquals("A", ((PropertyName) propertyName).getPropertyName());
Expression arg2 = (Expression) function.getParameters().get(1);
Assert.assertTrue(arg2 instanceof Function);
function = (Function) arg2;
propertyName = (Expression) function.getParameters().get(0);
Assert.assertTrue(propertyName instanceof PropertyName);
Assert.assertEquals("B", ((PropertyName) propertyName).getPropertyName());
arg2 = (Expression) function.getParameters().get(1);
Assert.assertTrue(arg2 instanceof Function);
function = (Function) arg2;
propertyName = (Expression) function.getParameters().get(0);
Assert.assertTrue(propertyName instanceof PropertyName);
Assert.assertEquals("C", ((PropertyName) propertyName).getPropertyName());
arg2 = (Expression) function.getParameters().get(1);
Assert.assertTrue(arg2 instanceof Literal);
Assert.assertEquals(".", ((Literal) arg2).getValue());
}
/**
* complex case
* Created to analyze http://jira.codehaus.org/browse/GEOT-1655
* @throws Exception
*/
@Test
public void testFunctionCompositionComplexCase() throws Exception {
Expression result = CQL.toExpression("strConcat( strConcat(QS, strConcat('/', RT)), strConcat(strConcat('/', NUMB), strConcat('/', BSUFF)) )");
assertFunctionCompositionComplex(result);
}
@Test
public void testFunctionCompositionComplexCaseInFilter() throws Exception {
final String propName = "A";
Filter result = CQL.toFilter(propName + " = strConcat( strConcat(QS, strConcat('/', RT)), strConcat(strConcat('/', NUMB), strConcat('/', BSUFF)) )");
Assert.assertTrue( result instanceof PropertyIsEqualTo);
PropertyIsEqualTo eq = (PropertyIsEqualTo) result;
Expression expr1 = eq.getExpression1();
Assert.assertTrue(expr1 instanceof PropertyName);
PropertyName prop = (PropertyName)expr1;
Assert.assertEquals(propName, prop.getPropertyName());
Expression expr2 = eq.getExpression2();
assertFunctionCompositionComplex(expr2);
}
/**
* @param result strConcat( strConcat(QS, strConcat('/', RT)), strConcat(strConcat('/', NUMB), strConcat('/', BSUFF)) )")
*/
private void assertFunctionCompositionComplex(final Expression result){
Assert.assertTrue(result instanceof Function);
Function function = (Function) result;
Assert.assertEquals(2, function.getParameters().size());
// asserts for strConcat(QS, strConcat('/', RT))
Expression arg1 = (Expression) function.getParameters().get(0);
Assert.assertTrue(arg1 instanceof Function);
Function function1 = (Function) arg1;
Assert.assertEquals(2, function1.getParameters().size());
Expression funcion1Arg1 = function1.getParameters().get(0);
Assert.assertTrue(funcion1Arg1 instanceof PropertyName);
Assert.assertEquals("QS", ((PropertyName)funcion1Arg1).getPropertyName() );
Expression arg11 = (Expression) function1.getParameters().get(1);
Assert.assertTrue(arg11 instanceof Function);
Function function11 = (Function) arg11;
Expression funcion11Arg1 = (Expression)function11.getParameters().get(0);
Assert.assertTrue(funcion11Arg1 instanceof Literal);
Assert.assertEquals("/", ((Literal) funcion11Arg1).getValue());
// asserts for strConcat(strConcat('/', NUMB), strConcat('/', BSUFF)) )"
Expression arg2 = (Expression) function.getParameters().get(1);
Assert.assertTrue(arg2 instanceof Function);
}
/**
* Test for Function Unary Expressions with functions in CQL.
* <p>
*
* <pre>
* <unary expression > ::=
* <Literal >
* | <Function > [*]
* | <Attribute >
* | ( <Expression >)
* | [ <Expression >]
* </pre>
*
* </p>
*/
@Test
public void testUnaryExpressionFunction() throws Exception {
Filter result;
Filter expected;
String cqlUnaryExp;
cqlUnaryExp = FilterCQLSample.FILTER_WITH_FUNCTION_ABS;
result = CQL.toFilter(cqlUnaryExp);
Assert.assertNotNull("filter expected", result);
expected = FilterCQLSample.getSample(cqlUnaryExp);
Assert.assertEquals( "Equals Functions is expected", expected,result);
// Key: GEOT-1167 type: BUG
cqlUnaryExp = FilterCQLSample.FILTER__WITH_FUNCTION_STR_CONCAT;
result = CQL.toFilter(cqlUnaryExp);
Assert.assertNotNull("filter expected", result);
expected = FilterCQLSample.getSample(cqlUnaryExp);
// TODO BUG There is a bug in function "equals"' strConcat
// assertEquals( "Functions", expected, result);
// test for improvement Key: GEOT-1168
cqlUnaryExp = "A = strConcat(B, 'testParam')";
result = CQL.toFilter(cqlUnaryExp);
Assert.assertTrue(result instanceof PropertyIsEqualTo);
Expression expression = ((PropertyIsEqualTo) result).getExpression2();
Assert.assertNotNull(expression);
Assert.assertTrue(expression instanceof Function);
Function function = (Function) expression;
Assert.assertEquals(2, function.getParameters().size());
Expression arg1 = (Expression) function.getParameters().get(0);
Expression arg2 = (Expression) function.getParameters().get(1);
Assert.assertTrue(arg1 instanceof PropertyName);
Assert.assertTrue(arg2 instanceof Literal);
Assert.assertEquals("B", ((PropertyName) arg1).getPropertyName());
Assert.assertEquals("testParam", ((Literal) arg2).getValue());
}
}