/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2017, 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.mbstyle.parse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Set;
import org.geotools.filter.text.ecql.ECQL;
import org.json.simple.JSONArray;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.Test;
import org.opengis.filter.Filter;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.style.SemanticType;
public class MBFilterTest {
/**
* Parse JSONArray ' rather than " for faster test case writing.
* @param json
* @return parsed JSONArray
* @throws ParseException
*/
private JSONArray array(String json) throws ParseException{
JSONParser parser = new JSONParser();
String text = json.replace('\'', '\"');
Object object = parser.parse(text);
return (JSONArray) object;
}
@Test
public void mixed() throws ParseException {
JSONArray json = array(
"['all',['==', 'class', 'street_limited'],['>=', 'admin_level', 3],['!in', '$type', 'Polygon']]"
);
MBFilter mbfilter = new MBFilter(json);
Set<SemanticType> types = mbfilter.semanticTypeIdentifiers();
assertTrue(!types.contains(SemanticType.POLYGON));
Filter filter = mbfilter.filter();
assertEquals("class = 'street_limited' AND admin_level >= 3 AND NOT ((dimension(geometry()) = 2 AND NOT (isCoverage() = 'true')))", ECQL.toCQL(filter) );
}
@Test
public void type() throws ParseException {
JSONArray json;
MBFilter mbfilter;
Filter filter;
Set<SemanticType> types;
// common $type examples
json = array("['in', '$type','LineString']");
mbfilter = new MBFilter(json);
types = mbfilter.semanticTypeIdentifiers();
assertTrue( types.contains(SemanticType.LINE) && types.size()==1);
filter = mbfilter.filter();
assertEquals("dimension(geometry()) IN (1)", ECQL.toCQL(filter) );
json = array("['in', '$type','Polygon']");
mbfilter = new MBFilter(json);
types = mbfilter.semanticTypeIdentifiers();
assertTrue( types.contains(SemanticType.POLYGON) && types.size()==1);
filter = mbfilter.filter();
assertEquals("(dimension(geometry()) = 2 AND NOT (isCoverage() = 'true'))", ECQL.toCQL(filter) );
json = array("['==', '$type','Point']");
mbfilter = new MBFilter(json);
types = mbfilter.semanticTypeIdentifiers();
assertTrue( types.contains(SemanticType.POINT) && types.size()==1);
filter = mbfilter.filter();
assertEquals("dimension(geometry()) = 0", ECQL.toCQL(filter) );
json = array("['in', '$type','Point', 'LineString']");
mbfilter = new MBFilter(json, null );
types = mbfilter.semanticTypeIdentifiers();
assertTrue(types.contains(SemanticType.POINT) && types.contains(SemanticType.LINE)
&& types.size() == 2);
filter = mbfilter.filter();
assertEquals("dimension(geometry()) IN (0,1)", ECQL.toCQL(filter) );
try {
json = array("['==', '$type','Point', 'LineString']");
mbfilter = new MBFilter(json, null );
types = mbfilter.semanticTypeIdentifiers();
fail("expected format exception due to '==' having too many arguments above");
}
catch (MBFormatException expected){
}
// not
json = array("['!in', '$type','Point', 'LineString']");
mbfilter = new MBFilter(json, null );
types = mbfilter.semanticTypeIdentifiers();
assertTrue(types.contains(SemanticType.POLYGON) && !types.contains(SemanticType.LINE));
filter = mbfilter.filter();
assertEquals("NOT (dimension(geometry()) IN (0,1))", ECQL.toCQL(filter) );
// test default handling
json = array("['==', 'key', 'value']");
mbfilter = new MBFilter(json);
types = mbfilter.semanticTypeIdentifiers();
assertTrue( types.isEmpty() );
json = array("['!=', 'key', 'value']");
mbfilter = new MBFilter(json, null, SemanticType.LINE);
types = mbfilter.semanticTypeIdentifiers();
assertTrue( types.contains(SemanticType.LINE) && types.size()==1);
}
@Test
public void id() throws ParseException {
JSONArray json;
MBFilter mbfilter;
Filter filter;
json = array("['has', '$id','foo.1']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("IN ('foo.1')", ECQL.toCQL(filter) );
json = array("['in', '$id','foo.1','foo.2']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("IN ('foo.1','foo.2')", ECQL.toCQL(filter) );
json = array("['!has', '$id','foo.1']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("NOT (IN ('foo.1'))", ECQL.toCQL(filter) );
json = array("['!in', '$id','foo.1','foo.2']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("NOT (IN ('foo.1','foo.2'))", ECQL.toCQL(filter) );
}
@Test
public void existential() throws ParseException {
JSONArray json = array("['has', 'key']");
MBFilter mbfilter = new MBFilter(json);
Filter filter = mbfilter.filter();
assertEquals("key IS NULL", ECQL.toCQL(filter) );
json = array("['!has', 'key', 'value']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("NOT (key IS NULL)", ECQL.toCQL(filter) );
}
@Test
public void comparisonFilters() throws ParseException {
JSONArray json;
MBFilter mbfilter;
// being really quick here, no need to check null / instanceof if we just cast
json = array("['==', 'key', 'value']");
mbfilter = new MBFilter(json);
PropertyIsEqualTo equal = (PropertyIsEqualTo) mbfilter.filter();
assertEquals( "key", ((PropertyName)equal.getExpression1()).getPropertyName() );
assertEquals( "value", ((Literal)equal.getExpression2()).getValue() );
// okay that takes too long just check ECQL
assertEquals("key = 'value'", ECQL.toCQL(equal));
json = array("['!=', 'key', 'value']");
mbfilter = new MBFilter(json);
Filter filter = mbfilter.filter();
assertEquals("key <> 'value'", ECQL.toCQL(filter));
json = array("['>', 'key', 'value']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("key > 'value'", ECQL.toCQL(filter));
json = array("['<', 'key', 'value']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("key < 'value'", ECQL.toCQL(filter));
json = array("['>=', 'key', 'value']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("key >= 'value'", ECQL.toCQL(filter));
json = array("['<=', 'key', 'value']");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("key <= 'value'", ECQL.toCQL(filter));
}
@Test
public void membership() throws ParseException {
JSONArray json = array("['in', 'a', 1, 2, 3]");
MBFilter mbfilter = new MBFilter(json);
Filter filter = mbfilter.filter();
assertEquals("EQUALS(in(a,1,2,3), 'true')", ECQL.toCQL(filter) );
json = array("['!in', 'a', 1, 2, 3]");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("EQUALS(in(a,1,2,3), 'false')", ECQL.toCQL(filter) );
}
@Test
public void combining() throws ParseException {
JSONArray json = array("['all', ['==','a',1],['==','b',2]]");
MBFilter mbfilter = new MBFilter(json);
Filter filter = mbfilter.filter();
assertEquals("a = 1 AND b = 2", ECQL.toCQL(filter) );
json = array("['any', ['==','a',1],['==','b',2]]");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("a = 1 OR b = 2", ECQL.toCQL(filter) );
json = array("['none', ['==','a',1],['==','b',2]]");
mbfilter = new MBFilter(json);
filter = mbfilter.filter();
assertEquals("NOT (a = 1) AND NOT (b = 2)", ECQL.toCQL(filter) );
}
}