package com.onthegomap.planetiler.expression; import static com.onthegomap.planetiler.TestUtils.newLineString; import static com.onthegomap.planetiler.TestUtils.newPoint; import static com.onthegomap.planetiler.TestUtils.rectangle; import static com.onthegomap.planetiler.expression.Expression.*; import static com.onthegomap.planetiler.expression.ExpressionTestUtil.featureWithTags; import static com.onthegomap.planetiler.expression.MultiExpression.entry; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import com.onthegomap.planetiler.expression.MultiExpression.Index; import com.onthegomap.planetiler.reader.SimpleFeature; import com.onthegomap.planetiler.reader.SourceFeature; import com.onthegomap.planetiler.reader.WithTags; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.Test; class MultiExpressionTest { @Test void testEmpty() { var index = MultiExpression.of(List.of()).index(); assertSameElements(List.of(), index.getMatches(featureWithTags())); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "value"))); } @Test void testSingleElement() { var index = MultiExpression.of(List.of( entry("a", matchAny("key", "value")) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testSingleElementBooleanTrue() { var index = MultiExpression.of(List.of( entry("a", matchAnyTyped("key", WithTags::getBoolean, true)) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "true"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "yes"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "true", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "true", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "false"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testSingleElementBooleanFalse() { var index = MultiExpression.of(List.of( entry("a", matchAnyTyped("key", WithTags::getBoolean, false)) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "false"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "0"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "false", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "false", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "true"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testSingleElementLong() { var index = MultiExpression.of(List.of( entry("a", matchAnyTyped("key", WithTags::getLong, 42)) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "42"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "42", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "42", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "99"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testSingleElementDirection() { var index = MultiExpression.of(List.of( entry("a", matchAnyTyped("key", WithTags::getDirection, 1)) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "yes"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "1", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "99"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testBlankStringTreatedAsNotMatch() { var index = MultiExpression.of(List.of( entry("a", matchAny("key", "value", "")) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", ""))); assertSameElements(List.of("a"), index.getMatches(featureWithTags())); assertSameElements(List.of("a"), index.getMatches(featureWithTags("otherkey", "othervalue"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "no"))); } @Test void testSingleMatchField() { var index = MultiExpression.of(List.of( entry("a", matchField("key")) )).index(); matchFieldCheck(index); } @Test void testDoubleInverseMatchField() { var index = MultiExpression.of(List.of( entry("a", not(not(matchField("key")))) )).index(); matchFieldCheck(index); } private void matchFieldCheck(Index index) { assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value2", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", ""))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", null))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testInverseMatchField() { var index = MultiExpression.of(List.of( entry("a", not(matchField("key"))) )).index(); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", ""))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", null))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "value2", "otherkey", "othervalue"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags())); } @Test void testStaticBooleanMatch() { var index = MultiExpression.of(List.of(entry("t", TRUE))).index(); assertTrue(index.matches(featureWithTags("key", "value"))); index = MultiExpression.of(List.of(entry("f", FALSE))).index(); assertFalse(index.matches(featureWithTags("key", "value"))); index = MultiExpression.of(List.of( entry("a", matchField("key")), entry("t", TRUE), entry("f", FALSE) )).index(); assertSameElements(List.of("a", "t"), index.getMatches(featureWithTags("key", "value"))); index = MultiExpression.of(List.of( entry("a", matchField("key")), entry("t1", TRUE), entry("t2", TRUE), entry("t3", TRUE), entry("f1", FALSE), entry("f2", FALSE), entry("f3", FALSE) )).index(); assertSameElements(List.of("a", "t1", "t2", "t3"), index.getMatches(featureWithTags("key", "value"))); index = MultiExpression.of(List.of( entry("t3", TRUE), entry("t2", TRUE), entry("t1", TRUE), entry("a", matchField("key")) )).index(); assertSameElements(List.of("t3", "t2", "t1", "a"), index.getMatches(featureWithTags("key", "value"))); } @Test void testWildcard() { var index = MultiExpression.of(List.of( entry("a", matchAny("key", "%value%")) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1value1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1value1", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testStartsWith() { var index = MultiExpression.of(List.of( entry("a", matchAny("key", "value%")) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "1value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "1value1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "1value1", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testEndsWith() { var index = MultiExpression.of(List.of( entry("a", matchAny("key", "%value")) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "value1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "1value1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "1value1", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testMultipleMatches() { var feature = featureWithTags("a", "b", "c", "d"); var index = MultiExpression.of(List.of( entry("a", matchAny("a", "b")), entry("b", matchAny("c", "d")) )).index(); var index2 = MultiExpression.of(List.of( entry("b", matchAny("c", "d")), entry("a", matchAny("a", "b")) )).index(); assertSameElements(List.of("a", "b"), index.getMatches(feature)); assertSameElements(List.of("b", "a"), index2.getMatches(feature)); assertEquals("a", index.getOrElse(feature, "miss")); assertEquals("b", index2.getOrElse(feature, "miss")); } @Test void testMultipleWildcardsMixedWithExacts() { var index = MultiExpression.of(List.of( entry("a", matchAny("key", "%value%", "other")) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1value1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "other"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "1value1", "otherkey", "othervalue"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "other", "otherkey", "othervalue"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value", "key3", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testAnd() { var index = MultiExpression.of(List.of( entry("a", and( matchAny("key1", "val1"), matchAny("key2", "val2") )) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2", "key3", "val3"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testAndConstant() { var index = MultiExpression.of(List.of( entry("a", and( Expression.TRUE, matchAny("key1", "val1") )) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); index = MultiExpression.of(List.of( entry("a", and( Expression.FALSE, matchAny("key1", "val1") )) )).index(); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testOr() { var index = MultiExpression.of(List.of( entry("a", or( matchAny("key1", "val1"), matchAny("key2", "val2") )) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2", "key3", "val3"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testMapResult() { var index = MultiExpression.of(List.of( entry("a", matchField("key")) )).mapResults(result -> result.toUpperCase(Locale.ROOT)).index(); assertSameElements(List.of("A"), index.getMatches(featureWithTags("key", "value"))); } @Test void testFilterResults() { var index = MultiExpression.of(List.of( entry("a", matchField("key")), entry("b", matchField("key")) )).filterResults(result -> !result.equals("b")).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "value"))); } @Test void testOrConstant() { var index = MultiExpression.of(List.of( entry("a", or( Expression.TRUE, matchAny("key1", "val1") )) )).indexAndWarn(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags())); index = MultiExpression.of(List.of( entry("a", or( Expression.FALSE, matchAny("key1", "val1") )) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testNot() { var index = MultiExpression.of(List.of( entry("a", and( matchAny("key1", "val1"), not( matchAny("key2", "val2") ) )) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val3"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key3", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testNor() { var index = MultiExpression.of(List.of( entry("a", not(or( matchAny("key1", "val1"), matchAny("key2", "val2") ))) )).index(); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2", "key3", "val3"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags())); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "no", "key2", "no"))); } @Test void testNand() { var index = MultiExpression.of(List.of( entry("a", not(and( matchAny("key1", "val1"), matchAny("key2", "val2") ))) )).index(); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2", "key3", "val3"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags())); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); } @Test void testXor() { var index = MultiExpression.of(List.of( entry("a", or( and( not(matchAny("key1", "val1")), matchAny("key2", "val2") ), and( matchAny("key1", "val1"), not(matchAny("key2", "val2")) )) ) )).index(); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "val2", "key3", "val3"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testXnor() { var index = MultiExpression.of(List.of( entry("a", or( and( not(matchAny("key1", "val1")), not(matchAny("key2", "val2")) ), and( matchAny("key1", "val1"), matchAny("key2", "val2") )) ) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1", "key2", "val2", "key3", "val3"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "no", "key2", "val2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1", "key2", "no"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "no", "key2", "no"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags())); } @Test void testMatchesMultiple() { var index = MultiExpression.of(List.of( entry("a", or( matchAny("key1", "val1"), matchAny("key2", "val2") )), entry("b", or( matchAny("key2", "val2"), matchAny("key3", "val3") )) )).index(); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "val1"))); assertSameElements(List.of("a", "b"), index.getMatches(featureWithTags("key2", "val2"))); assertSameElements(List.of("b"), index.getMatches(featureWithTags("key3", "val3"))); assertSameElements(List.of("a", "b"), index.getMatches(featureWithTags("key2", "val2", "key3", "val3"))); assertSameElements(List.of("a", "b"), index.getMatches(featureWithTags("key1", "val1", "key3", "val3"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); } @Test void testTracksMatchingKey() { var index = MultiExpression.of(List.of( entry("a", or( matchAny("key1", "val1"), matchAny("key2", "val2") )), entry("b", or( matchAny("key2", "val2"), matchAny("key3", "val3") )) )).index(); assertSameElements(List.of(new MultiExpression.Match<>( "a", List.of("key1"), 1 )), index.getMatchesWithTriggers(featureWithTags("key1", "val1"))); assertSameElements(List.of(new MultiExpression.Match<>( "a", List.of("key2"), 1 ), new MultiExpression.Match<>( "b", List.of("key2"), 2 )), index.getMatchesWithTriggers(featureWithTags("key2", "val2"))); assertSameElements(List.of(new MultiExpression.Match<>( "b", List.of("key3"), 2 )), index.getMatchesWithTriggers(featureWithTags("key3", "val3"))); } @Test void testTracksMatchingKeyFromCorrectPath() { var index = MultiExpression.of(List.of( entry("a", or( and( matchAny("key3", "val3"), matchAny("key2", "val2") ), and( matchAny("key1", "val1"), matchAny("key3", "val3") ) )) )).index(); assertSameElements(List.of(new MultiExpression.Match<>( "a", List.of("key1", "key3"), 1 )), index.getMatchesWithTriggers(featureWithTags("key1", "val1", "key3", "val3"))); } @Test void testMatchDifferentTypes() { Expression polygonExpression = and(matchType("polygon"), matchField("field")); Expression linestringExpression = and(matchType("linestring"), matchField("field")); Expression pointExpression = and(matchType("point"), matchField("field")); Expression otherExpression = matchField("field"); Map map = Map.of("field", "value"); SourceFeature point = SimpleFeature.create(newPoint(0, 0), map); SourceFeature linestring = SimpleFeature.create(newLineString(0, 0, 1, 1), map); SourceFeature polygon = SimpleFeature.create(rectangle(0, 1), map); WithTags other = WithTags.from(Map.of("field", "value")); var index = MultiExpression.of(List.of( entry("polygon", polygonExpression), entry("linestring", linestringExpression), entry("point", pointExpression), entry("other", otherExpression) )).index(); assertTrue(pointExpression.evaluate(point, new ArrayList<>())); assertTrue(linestringExpression.evaluate(linestring, new ArrayList<>())); assertTrue(polygonExpression.evaluate(polygon, new ArrayList<>())); assertTrue(otherExpression.evaluate(other, new ArrayList<>())); assertEquals("point", index.getOrElse(point, null)); assertEquals("linestring", index.getOrElse(linestring, null)); assertEquals("polygon", index.getOrElse(polygon, null)); assertEquals("other", index.getOrElse(other, null)); } @Test void testMatchMissing() { // Test logic: match if either key1 or key2 is missing var index1 = MultiExpression.of(List.of( entry("a", or( matchAny("key1", ""), matchAny("key2", "") )) )).index(); var index2 = MultiExpression.of(List.of( entry("a", not(and( matchField("key1"), matchField("key2") ))) )).index(); List.of(index1, index2).forEach(index -> { assertSameElements(List.of("a"), index.getMatches(featureWithTags())); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "value1"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key2", "value2"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key1", "value1", "key2", "value2"))); }); } @Test void testMatchNotMissing() { //Test logic: match if key1 is present (not missing) var index1 = MultiExpression.of(List.of( entry("a", matchField("key1")) )).index(); var index2 = MultiExpression.of(List.of( entry("a", not( matchAny("key1", "") )) )).index(); List.of(index1, index2).forEach(index -> { assertSameElements(List.of(), index.getMatches(featureWithTags())); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "value1"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key2", "value2"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key1", "value1", "key2", "value2"))); }); } @Test void testCustomExpression() { Expression dontEvaluate = new Expression() { @Override public boolean evaluate(WithTags input, List matchKeys) { throw new AssertionError("should not evaluate"); } @Override public String generateJavaCode() { return null; } }; Expression matchAbc = new Expression() { @Override public boolean evaluate(WithTags input, List matchKeys) { return input.hasTag("abc"); } @Override public String generateJavaCode() { return null; } }; var index = MultiExpression.of(List.of( entry("a", matchAbc), entry("b", and(matchField("def"), dontEvaluate)), entry("c", or(matchField("abc"), matchAbc)) )).index(); assertSameElements(List.of(), index.getMatches(featureWithTags())); assertSameElements(List.of(), index.getMatches(featureWithTags("a", "1"))); assertSameElements(List.of("a", "c"), index.getMatches(featureWithTags("abc", "123"))); var bad = featureWithTags("def", "123"); assertThrows(AssertionError.class, () -> index.getMatches(bad)); } @Test void testAndOrMatch() { var expr = and( or( matchAny("key", "val") ), TRUE ); var index = MultiExpression.of(List.of(entry("a", expr))).index(); //Ensure MultiExpression and regular Expression work the same assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "val"))); assertSameElements(List.of("a"), index.getMatches(featureWithTags("key", "val", "otherkey", "otherval"))); assertSameElements(List.of(), index.getMatches(featureWithTags("otherkey", "otherval"))); assertSameElements(List.of(), index.getMatches(featureWithTags("key", "otherval"))); assertSameElements(List.of(), index.getMatches(featureWithTags())); var list = new ArrayList(); assertTrue(expr.evaluate(featureWithTags("key", "val"), list)); assertTrue(expr.evaluate(featureWithTags("key", "val", "otherkey", "otherval"), list)); assertFalse(expr.evaluate(featureWithTags("otherkey", "otherval"), list)); assertFalse(expr.evaluate(featureWithTags("key", "otherval"), list)); assertFalse(expr.evaluate(featureWithTags(), list)); expr.simplify(); //Ensure Expression works the same after a simplify assertTrue(expr.evaluate(featureWithTags("key", "val"), list)); assertTrue(expr.evaluate(featureWithTags("key", "val", "otherkey", "otherval"), list)); assertFalse(expr.evaluate(featureWithTags("otherkey", "otherval"), list)); assertFalse(expr.evaluate(featureWithTags("key", "otherval"), list)); assertFalse(expr.evaluate(featureWithTags(), list)); } private static void assertSameElements(List a, List b) { assertEquals( a.stream().sorted(Comparator.comparing(Object::toString)).toList(), b.stream().sorted(Comparator.comparing(Object::toString)).toList() ); } }