aboutsummaryrefslogtreecommitdiffstats
path: root/predicate-search-core/src/test/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'predicate-search-core/src/test/java/com')
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/BinaryFormatTest.java124
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/BooleanPredicateTest.java47
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/ConjunctionTest.java113
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/DisjunctionTest.java113
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureConjunctionTest.java52
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureRangeTest.java263
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureSetTest.java180
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/NegationTest.java89
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateHashTest.java102
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateOperatorTest.java17
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateParserTest.java155
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateTest.java110
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateValueTest.java17
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicatesTest.java38
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/RangeEdgePartitionTest.java62
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/document/predicate/RangePartitionTest.java60
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/search/predicate/PredicateQueryParserTest.java43
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/AndOrSimplifierTest.java134
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/BooleanSimplifierTest.java60
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/ComplexNodeTransformerTest.java604
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/NotNodeReordererTest.java55
-rw-r--r--predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/OrSimplifierTest.java98
22 files changed, 2536 insertions, 0 deletions
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/BinaryFormatTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/BinaryFormatTest.java
new file mode 100644
index 00000000000..44477423fdb
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/BinaryFormatTest.java
@@ -0,0 +1,124 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import com.yahoo.slime.Inspector;
+import com.yahoo.slime.Slime;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class BinaryFormatTest {
+
+ @Test
+ public void requireThatEncodeNullThrows() {
+ try {
+ BinaryFormat.encode(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("predicate", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatDecodeNullThrows() {
+ try {
+ BinaryFormat.decode(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("buf", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatDecodeEmptyThrows() {
+ try {
+ BinaryFormat.decode(new byte[0]);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ assertEquals("0", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatConjunctionCanBeSerialized() {
+ assertSerialize(new Conjunction(new FeatureSet("foo", "bar"), new FeatureSet("baz", "cox")));
+ }
+
+ @Test
+ public void requireThatDisjunctionCanBeSerialized() {
+ assertSerialize(new Disjunction(new FeatureSet("foo", "bar"), new FeatureSet("baz", "cox")));
+ }
+
+ @Test
+ public void requireThatFeatureRangeCanBeSerialized() {
+ assertSerialize(new FeatureRange("foo", null, null));
+ assertSerialize(new FeatureRange("foo", null, 9L));
+ assertSerialize(new FeatureRange("foo", 6L, null));
+ assertSerialize(new FeatureRange("foo", 6L, 9L));
+ }
+
+ @Test
+ public void requireThatPartitionedFeatureRangeCanBeSerialized() {
+ FeatureRange expected = new FeatureRange("foo", 8L, 20L);
+ FeatureRange f = new FeatureRange("foo", 8L, 20L);
+ f.addPartition(new RangeEdgePartition("foo=0", 0, 8, -1));
+ f.addPartition(new RangeEdgePartition("foo=20", 20, 0, 0));
+ f.addPartition(new RangePartition("foo", 10, 19, false));
+ assertSerializesTo(expected, f);
+ Slime slime = com.yahoo.slime.BinaryFormat.decode(BinaryFormat.encode(f));
+ assertEquals(BinaryFormat.TYPE_FEATURE_RANGE, slime.get().field(BinaryFormat.NODE_TYPE).asLong());
+ Inspector in1 = slime.get().field(BinaryFormat.HASHED_PARTITIONS);
+ assertEquals(1, in1.entries());
+ assertEquals(0xf2b6d1cc6322cb99L, in1.entry(0).asLong());
+ Inspector in2 = slime.get().field(BinaryFormat.HASHED_EDGE_PARTITIONS);
+ assertEquals(2, in2.entries());
+ Inspector obj1 = in2.entry(0);
+ assertEquals(0xb2b301e26efffdc2L, obj1.field(BinaryFormat.HASH).asLong());
+ assertEquals(0, obj1.field(BinaryFormat.VALUE).asLong());
+ assertEquals(0x80000008L, obj1.field(BinaryFormat.PAYLOAD).asLong());
+ Inspector obj2 = in2.entry(1);
+ assertEquals(0x22acb2ed72523c36L, obj2.field(BinaryFormat.HASH).asLong());
+ assertEquals(20, obj2.field(BinaryFormat.VALUE).asLong());
+ assertEquals(0x40000001L, obj2.field(BinaryFormat.PAYLOAD).asLong());
+ }
+
+ @Test
+ public void requireThatFeatureSetCanBeSerialized() {
+ assertSerialize(new FeatureSet("foo"));
+ assertSerialize(new FeatureSet("foo", "bar"));
+ assertSerialize(new FeatureSet("foo", "bar", "baz"));
+ }
+
+ @Test
+ public void requireThatNegationCanBeSerialized() {
+ assertSerialize(new Negation(new FeatureSet("foo", "bar")));
+ }
+
+ @Test
+ public void requireThatBooleanCanBeSerialized() {
+ assertSerialize(new BooleanPredicate(true));
+ assertSerialize(new BooleanPredicate(false));
+ }
+
+ @Test
+ public void requireThatUnknownNodeThrows() {
+ try {
+ BinaryFormat.encode(SimplePredicates.newString("foo"));
+ fail();
+ } catch (UnsupportedOperationException e) {
+
+ }
+ }
+
+ private static void assertSerializesTo(Predicate expected, Predicate predicate) {
+ assertEquals(expected, BinaryFormat.decode(BinaryFormat.encode(predicate)));
+ }
+
+ private static void assertSerialize(Predicate predicate) {
+ assertSerializesTo(predicate, predicate);
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/BooleanPredicateTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/BooleanPredicateTest.java
new file mode 100644
index 00000000000..7268b358889
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/BooleanPredicateTest.java
@@ -0,0 +1,47 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class BooleanPredicateTest {
+
+ @Test
+ public void requireThatFalseIsAValue() {
+ assertTrue(PredicateValue.class.isAssignableFrom(BooleanPredicate.class));
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ BooleanPredicate node1 = new BooleanPredicate(true);
+ BooleanPredicate node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new BooleanPredicate(true).hashCode(), new BooleanPredicate(true).hashCode());
+ assertEquals(new BooleanPredicate(false).hashCode(), new BooleanPredicate(false).hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ BooleanPredicate lhs = new BooleanPredicate(true);
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ BooleanPredicate rhs = new BooleanPredicate(false);
+ assertFalse(lhs.equals(rhs));
+ rhs.setValue(true);
+ assertTrue(lhs.equals(rhs));
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/ConjunctionTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/ConjunctionTest.java
new file mode 100644
index 00000000000..6e12a00ba4d
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/ConjunctionTest.java
@@ -0,0 +1,113 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class ConjunctionTest {
+
+ @Test
+ public void requireThatConjunctionIsAnOperator() {
+ assertTrue(PredicateOperator.class.isAssignableFrom(Conjunction.class));
+ }
+
+ @Test
+ public void requireThatAccessorsWork() {
+ Conjunction node = new Conjunction();
+ Predicate a = SimplePredicates.newString("a");
+ node.addOperand(a);
+ assertEquals(Arrays.asList(a), node.getOperands());
+ Predicate b = SimplePredicates.newString("b");
+ node.addOperand(b);
+ assertEquals(Arrays.asList(a, b), node.getOperands());
+ Predicate c = SimplePredicates.newString("c");
+ Predicate d = SimplePredicates.newString("d");
+ node.addOperands(Arrays.asList(c, d));
+ assertEquals(Arrays.asList(a, b, c, d), node.getOperands());
+ Predicate e = SimplePredicates.newString("e");
+ Predicate f = SimplePredicates.newString("f");
+ node.setOperands(Arrays.asList(e, f));
+ assertEquals(Arrays.asList(e, f), node.getOperands());
+ }
+
+ @Test
+ public void requireThatConstructorsWork() {
+ Predicate foo = SimplePredicates.newString("foo");
+ Predicate bar = SimplePredicates.newString("bar");
+ Conjunction node = new Conjunction(foo, bar);
+ assertEquals(Arrays.asList(foo, bar), node.getOperands());
+
+ node = new Conjunction(Arrays.asList(foo, bar));
+ assertEquals(Arrays.asList(foo, bar), node.getOperands());
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ Conjunction node1 = new Conjunction(SimplePredicates.newString("a"), SimplePredicates.newString("b"));
+ Conjunction node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ assertNotSame(node1.getOperands(), node2.getOperands());
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new Conjunction().hashCode(), new Conjunction().hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ Conjunction lhs = new Conjunction(SimplePredicates.newString("foo"),
+ SimplePredicates.newString("bar"));
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ Conjunction rhs = new Conjunction();
+ assertFalse(lhs.equals(rhs));
+ rhs.addOperand(SimplePredicates.newString("foo"));
+ assertFalse(lhs.equals(rhs));
+ rhs.addOperand(SimplePredicates.newString("bar"));
+ assertTrue(lhs.equals(rhs));
+ }
+
+ @Test
+ public void requireThatNodeDelimiterIsAND() {
+ assertEquals("", newConjunction().toString());
+ assertEquals("foo", newConjunction("foo").toString());
+ assertEquals("foo and bar", newConjunction("foo", "bar").toString());
+ assertEquals("foo and bar and baz", newConjunction("foo", "bar", "baz").toString());
+ }
+
+ @Test
+ public void requireThatSimpleConjunctionsArePrettyPrinted() {
+ assertEquals("foo and bar",
+ new Conjunction(SimplePredicates.newString("foo"),
+ SimplePredicates.newString("bar")).toString());
+ }
+
+ @Test
+ public void requireThatComplexConjunctionsArePrintedAsGroup() {
+ assertEquals("foo and bar and baz",
+ new Conjunction(SimplePredicates.newString("foo"),
+ new Conjunction(SimplePredicates.newString("bar"),
+ SimplePredicates.newString("baz"))).toString());
+ assertEquals("foo and (bar or baz)",
+ new Conjunction(SimplePredicates.newString("foo"),
+ new Disjunction(SimplePredicates.newString("bar"),
+ SimplePredicates.newString("baz"))).toString());
+ }
+
+ private static Conjunction newConjunction(String... operands) {
+ return new Conjunction(SimplePredicates.newStrings(operands));
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/DisjunctionTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/DisjunctionTest.java
new file mode 100644
index 00000000000..99dc46c4f5f
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/DisjunctionTest.java
@@ -0,0 +1,113 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class DisjunctionTest {
+
+ @Test
+ public void requireThatDisjunctionIsAnOperator() {
+ assertTrue(PredicateOperator.class.isAssignableFrom(Disjunction.class));
+ }
+
+ @Test
+ public void requireThatAccessorsWork() {
+ Disjunction node = new Disjunction();
+ Predicate a = SimplePredicates.newString("a");
+ node.addOperand(a);
+ assertEquals(Arrays.asList(a), node.getOperands());
+ Predicate b = SimplePredicates.newString("b");
+ node.addOperand(b);
+ assertEquals(Arrays.asList(a, b), node.getOperands());
+ Predicate c = SimplePredicates.newString("c");
+ Predicate d = SimplePredicates.newString("d");
+ node.addOperands(Arrays.asList(c, d));
+ assertEquals(Arrays.asList(a, b, c, d), node.getOperands());
+ Predicate e = SimplePredicates.newString("e");
+ Predicate f = SimplePredicates.newString("f");
+ node.setOperands(Arrays.asList(e, f));
+ assertEquals(Arrays.asList(e, f), node.getOperands());
+ }
+
+ @Test
+ public void requireThatConstructorsWork() {
+ Predicate foo = SimplePredicates.newString("foo");
+ Predicate bar = SimplePredicates.newString("bar");
+ Disjunction node = new Disjunction(foo, bar);
+ assertEquals(Arrays.asList(foo, bar), node.getOperands());
+
+ node = new Disjunction(Arrays.asList(foo, bar));
+ assertEquals(Arrays.asList(foo, bar), node.getOperands());
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ Disjunction node1 = new Disjunction(SimplePredicates.newString("a"), SimplePredicates.newString("b"));
+ Disjunction node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ assertNotSame(node1.getOperands(), node2.getOperands());
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new Disjunction().hashCode(), new Disjunction().hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ Disjunction lhs = new Disjunction(SimplePredicates.newString("foo"),
+ SimplePredicates.newString("bar"));
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ Disjunction rhs = new Disjunction();
+ assertFalse(lhs.equals(rhs));
+ rhs.addOperand(SimplePredicates.newString("foo"));
+ assertFalse(lhs.equals(rhs));
+ rhs.addOperand(SimplePredicates.newString("bar"));
+ assertTrue(lhs.equals(rhs));
+ }
+
+ @Test
+ public void requireThatNodeDelimiterIsOR() {
+ assertEquals("", newDisjunction().toString());
+ assertEquals("foo", newDisjunction("foo").toString());
+ assertEquals("foo or bar", newDisjunction("foo", "bar").toString());
+ assertEquals("foo or bar or baz", newDisjunction("foo", "bar", "baz").toString());
+ }
+
+ @Test
+ public void requireThatSimpleDisjunctionsArePrettyPrinted() {
+ assertEquals("foo or bar",
+ new Disjunction(SimplePredicates.newString("foo"),
+ SimplePredicates.newString("bar")).toString());
+ }
+
+ @Test
+ public void requireThatComplexDisjunctionsArePrintedAsGroup() {
+ assertEquals("foo or bar or baz",
+ new Disjunction(SimplePredicates.newString("foo"),
+ new Disjunction(SimplePredicates.newString("bar"),
+ SimplePredicates.newString("baz"))).toString());
+ assertEquals("foo or (bar and baz)",
+ new Disjunction(SimplePredicates.newString("foo"),
+ new Conjunction(SimplePredicates.newString("bar"),
+ SimplePredicates.newString("baz"))).toString());
+ }
+
+ private static Disjunction newDisjunction(String... operands) {
+ return new Disjunction(SimplePredicates.newStrings(operands));
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureConjunctionTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureConjunctionTest.java
new file mode 100644
index 00000000000..e98400e86fa
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureConjunctionTest.java
@@ -0,0 +1,52 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static com.yahoo.document.predicate.Predicates.feature;
+import static com.yahoo.document.predicate.Predicates.not;
+
+/**
+ * @author bjorncs
+ */
+public class FeatureConjunctionTest {
+
+ @Test
+ public void require_that_featureconjunction_with_valid_operands_can_be_constructed() {
+ new FeatureConjunction(Arrays.asList(
+ not(feature("a").inSet("1")),
+ feature("b").inSet("1")));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void require_that_constructor_throws_exception_if_all_operands_are_not_featuresets() {
+ new FeatureConjunction(Arrays.asList(
+ not(feature("a").inSet("1")),
+ feature("b").inRange(1, 2)));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void require_that_constructor_throws_exception_if_single_operand() {
+ new FeatureConjunction(Arrays.asList(feature("a").inSet("1")));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void require_that_constructor_throws_exception_if_no_operands() {
+ new FeatureConjunction(Collections.emptyList());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void require_that_contructor_throws_exception_if_featuresets_contain_multiple_values() {
+ new FeatureConjunction(Arrays.asList(feature("a").inSet("1"), feature("b").inSet("2", "3")));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void require_that_constructor_throws_exception_if_featureset_keys_are_not_unique() {
+ new FeatureConjunction(Arrays.asList(
+ not(feature("a").inSet("1")),
+ feature("a").inSet("2")));
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureRangeTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureRangeTest.java
new file mode 100644
index 00000000000..efcc0e5b64a
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureRangeTest.java
@@ -0,0 +1,263 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class FeatureRangeTest {
+
+ @Test
+ public void requireThatFeatureRangeIsAValue() {
+ assertTrue(PredicateValue.class.isAssignableFrom(FeatureRange.class));
+ }
+
+ @Test
+ public void requireThatAccessorsWork() {
+ FeatureRange node = new FeatureRange("foo");
+ assertEquals("foo", node.getKey());
+ node.setKey("bar");
+ assertEquals("bar", node.getKey());
+
+ node.setFromInclusive(69L);
+ assertEquals(69, node.getFromInclusive().intValue());
+ node.setFromInclusive(null);
+ assertNull(node.getFromInclusive());
+
+ node.setToInclusive(69L);
+ assertEquals(69, node.getToInclusive().intValue());
+ node.setToInclusive(null);
+ assertNull(node.getToInclusive());
+ }
+
+ @Test
+ public void requireThatConstructorsWork() {
+ FeatureRange node = new FeatureRange("foo");
+ assertEquals("foo", node.getKey());
+ assertNull(node.getFromInclusive());
+ assertNull(node.getToInclusive());
+
+ node = new FeatureRange("foo", null, null);
+ assertEquals("foo", node.getKey());
+ assertNull(node.getFromInclusive());
+ assertNull(node.getToInclusive());
+
+ node = new FeatureRange("foo", 69L, null);
+ assertEquals("foo", node.getKey());
+ assertEquals(69, node.getFromInclusive().intValue());
+ assertNull(node.getToInclusive());
+
+ node = new FeatureRange("foo", null, 69L);
+ assertEquals("foo", node.getKey());
+ assertNull(node.getFromInclusive());
+ assertEquals(69, node.getToInclusive().intValue());
+
+ node = new FeatureRange("foo", 6L, 9L);
+ assertEquals("foo", node.getKey());
+ assertEquals(6, node.getFromInclusive().intValue());
+ assertEquals(9, node.getToInclusive().intValue());
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ FeatureRange node1 = new FeatureRange("foo", 6L, 9L);
+ FeatureRange node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new FeatureRange("key").hashCode(), new FeatureRange("key").hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ FeatureRange lhs = new FeatureRange("foo", 6L, 9L);
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ FeatureRange rhs = new FeatureRange("bar");
+ assertFalse(lhs.equals(rhs));
+ rhs.setKey("foo");
+ assertFalse(lhs.equals(rhs));
+ rhs.setFromInclusive(6L);
+ assertFalse(lhs.equals(rhs));
+ rhs.setToInclusive(9L);
+ assertTrue(lhs.equals(rhs));
+ rhs.addPartition(new RangePartition("foo"));
+ assertFalse(lhs.equals(rhs));
+ lhs.addPartition(new RangePartition("foo"));
+ assertTrue(lhs.equals(rhs));
+ rhs.addPartition(new RangeEdgePartition("foo", 10, 0, 2));
+ assertFalse(lhs.equals(rhs));
+ lhs.addPartition(new RangeEdgePartition("foo", 10, 0, 2));
+ assertTrue(lhs.equals(rhs));
+ }
+
+ @Test
+ public void requireThatFeatureKeyIsMandatoryInConstructor() {
+ try {
+ new FeatureRange(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("key", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatFeatureKeyIsMandatoryInSetter() {
+ FeatureRange node = new FeatureRange("foo");
+ try {
+ node.setKey(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("key", e.getMessage());
+ }
+ assertEquals("foo", node.getKey());
+ }
+
+ @Test
+ public void requireThatRangeCanBeSingleValue() {
+ FeatureRange node = new FeatureRange("key", 6L, 6L);
+ assertEquals(6, node.getFromInclusive().intValue());
+ assertEquals(6, node.getToInclusive().intValue());
+ node.setToInclusive(9L);
+ node.setFromInclusive(9L);
+ assertEquals(9, node.getFromInclusive().intValue());
+ assertEquals(9, node.getToInclusive().intValue());
+ }
+
+ @Test
+ public void requireThatFromCanNotBeConstructedGreaterThanTo() {
+ try {
+ new FeatureRange("key", 9L, 6L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Expected 'to' greater than or equal to 9, got 6.", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatFromCanNotBeSetGreaterThanTo() {
+ FeatureRange node = new FeatureRange("key", null, 6L);
+ try {
+ node.setFromInclusive(9L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Expected 'from' less than or equal to 6, got 9.", e.getMessage());
+ }
+ assertNull(node.getFromInclusive());
+
+ node = new FeatureRange("key", 6L, 9L);
+ try {
+ node.setFromInclusive(69L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Expected 'from' less than or equal to 9, got 69.", e.getMessage());
+ }
+ assertEquals(6, node.getFromInclusive().intValue());
+ }
+
+ @Test
+ public void requireThatToCanNotBeSetLessThanFrom() {
+ FeatureRange node = new FeatureRange("key", 9L, null);
+ try {
+ node.setToInclusive(6L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Expected 'to' greater than or equal to 9, got 6.", e.getMessage());
+ }
+ assertNull(node.getToInclusive());
+
+ node = new FeatureRange("key", 6L, 9L);
+ try {
+ node.setToInclusive(1L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Expected 'to' greater than or equal to 6, got 1.", e.getMessage());
+ }
+ assertEquals(9, node.getToInclusive().intValue());
+ }
+
+ @Test
+ public void requireThatKeyIsEscapedInToString() {
+ assertEquals("foo in [6..9]",
+ new FeatureRange("foo", 6L, 9L).toString());
+ assertEquals("'\\foo' in [6..9]",
+ new FeatureRange("\foo", 6L, 9L).toString());
+ assertEquals("'\\x27foo\\x27' in [6..9]",
+ new FeatureRange("'foo'", 6L, 9L).toString());
+ }
+
+ @Test
+ public void requireThatToStringIncludesLimits() {
+ assertEquals("foo in [6..9]", new FeatureRange("foo", 6L, 9L).toString());
+ }
+
+ @Test
+ public void requireThatToStringAllowsNullLimits() {
+ assertEquals("foo in [..]", new FeatureRange("foo").toString());
+ }
+
+ @Test
+ public void requireThatToStringAllowsNullFromLimit() {
+ assertEquals("foo in [..69]", new FeatureRange("foo", null, 69L).toString());
+ }
+
+ @Test
+ public void requireThatToStringAllowsNullToLimit() {
+ assertEquals("foo in [69..]", new FeatureRange("foo", 69L, null).toString());
+ }
+
+ @Test
+ public void requireThatSimpleStringsArePrettyPrinted() {
+ assertEquals("foo in [6..9]",
+ new FeatureRange("foo", 6L, 9L).toString());
+ }
+
+ @Test
+ public void requireThatComplexStringsAreEscaped() {
+ assertEquals("'\\foo' in [6..9]",
+ new FeatureRange("\foo", 6L, 9L).toString());
+ }
+
+ @Test
+ public void requireThatRangePartitionsCanBeAdded() {
+ FeatureRange range = new FeatureRange("foo", 10L, 22L);
+ range.addPartition(new RangePartition("foo=10-19"));
+ range.addPartition(new RangePartition("foo", 0, 0x8000000000000000L, true));
+ range.addPartition(new RangeEdgePartition("foo=20", 20, 0, 2));
+ assertEquals("foo in [10..22 (foo=20+[..2],foo=10-19,foo=-9223372036854775808-0)]", range.toString());
+ }
+
+ @Test
+ public void requireThatRangePartitionsCanBeCleared() {
+ FeatureRange range = new FeatureRange("foo", 10L, 22L);
+ range.addPartition(new RangePartition("foo=10-19"));
+ range.addPartition(new RangeEdgePartition("foo=20", 20, 0, 2));
+ assertEquals("foo in [10..22 (foo=20+[..2],foo=10-19)]", range.toString());
+ range.clearPartitions();
+ assertEquals("foo in [10..22]", range.toString());
+ }
+
+ @Test
+ public void requireThatFeatureRangeCanBeBuiltFromMixedInNode() {
+ assertEquals(new FeatureRange("foo", 10L, 19L),
+ FeatureRange.buildFromMixedIn("foo", Arrays.asList("foo=10-19"), 10));
+ assertEquals(new FeatureRange("foo", -19L, -10L),
+ FeatureRange.buildFromMixedIn("foo", Arrays.asList("foo=-10-19"), 10));
+ assertEquals(new FeatureRange("foo", 10L, 19L),
+ FeatureRange.buildFromMixedIn("foo", Arrays.asList("foo=10,10,9"), 10));
+ assertEquals(new FeatureRange("foo", 10L, 19L),
+ FeatureRange.buildFromMixedIn("foo", Arrays.asList("foo=10,10,1073741833"), 10));
+ assertEquals(new FeatureRange("foo", 10L, 19L),
+ FeatureRange.buildFromMixedIn("foo", Arrays.asList("foo=10,10,2147483648"), 10));
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureSetTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureSetTest.java
new file mode 100644
index 00000000000..7bc9d5f2c04
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/FeatureSetTest.java
@@ -0,0 +1,180 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class FeatureSetTest {
+
+ @Test
+ public void requireThatFeatureSetIsAValue() {
+ assertTrue(PredicateValue.class.isAssignableFrom(FeatureSet.class));
+ }
+
+ @Test
+ public void requireThatAccessorsWork() {
+ FeatureSet node = new FeatureSet("key", "valueA", "valueB");
+ assertEquals("key", node.getKey());
+ assertValues(Arrays.asList("valueA", "valueB"), node);
+ node.addValue("valueC");
+ assertValues(Arrays.asList("valueA", "valueB", "valueC"), node);
+ node.addValues(Arrays.asList("valueD", "valueE"));
+ assertValues(Arrays.asList("valueA", "valueB", "valueC", "valueD", "valueE"), node);
+ node.setValues(Arrays.asList("valueF", "valueG"));
+ assertValues(Arrays.asList("valueF", "valueG"), node);
+ }
+
+ @Test
+ public void requireThatValueSetIsMutable() {
+ FeatureSet node = new FeatureSet("key");
+ node.getValues().add("valueA");
+ assertValues(Arrays.asList("valueA"), node);
+
+ node = new FeatureSet("key", "valueA");
+ node.getValues().add("valueB");
+ assertValues(Arrays.asList("valueA", "valueB"), node);
+ }
+
+ @Test
+ public void requireThatConstructorsWork() {
+ FeatureSet node = new FeatureSet("key", "valueA", "valueB");
+ assertEquals("key", node.getKey());
+ assertValues(Arrays.asList("valueA", "valueB"), node);
+
+ node = new FeatureSet("key", Arrays.asList("valueA", "valueB"));
+ assertEquals("key", node.getKey());
+ assertValues(Arrays.asList("valueA", "valueB"), node);
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ FeatureSet node1 = new FeatureSet("key", "valueA", "valueB");
+ FeatureSet node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ assertNotSame(node1.getValues(), node2.getValues());
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new FeatureSet("key").hashCode(), new FeatureSet("key").hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ FeatureSet lhs = new FeatureSet("keyA", "valueA", "valueB");
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ FeatureSet rhs = new FeatureSet("keyB");
+ assertFalse(lhs.equals(rhs));
+ rhs.setKey("keyA");
+ assertFalse(lhs.equals(rhs));
+ rhs.addValue("valueA");
+ assertFalse(lhs.equals(rhs));
+ rhs.addValue("valueB");
+ assertTrue(lhs.equals(rhs));
+ }
+
+ @Test
+ public void requireThatkeyIsMandatoryInConstructor() {
+ try {
+ new FeatureSet(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("key", e.getMessage());
+ }
+ try {
+ new FeatureSet(null, Collections.<String>emptyList());
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("key", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatkeyIsMandatoryInSetter() {
+ FeatureSet node = new FeatureSet("foo");
+ try {
+ node.setKey(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("key", e.getMessage());
+ }
+ assertEquals("foo", node.getKey());
+ }
+
+ @Test
+ public void requireThatValueIsMandatoryInSetter() {
+ FeatureSet node = new FeatureSet("foo", "bar");
+ try {
+ node.addValue(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("value", e.getMessage());
+ }
+ assertValues(Arrays.asList("bar"), node);
+ }
+
+ @Test
+ public void requireThatKeyIsEscapedInToString() {
+ assertEquals("foo in [val]",
+ new FeatureSet("foo", "val").toString());
+ assertEquals("'\\foo' in [val]",
+ new FeatureSet("\foo", "val").toString());
+ assertEquals("'\\x27foo\\x27' in [val]",
+ new FeatureSet("'foo'", "val").toString());
+ }
+
+ @Test
+ public void requireThatValuesAreEscapedInToString() {
+ assertEquals("key in [bar, foo]",
+ new FeatureSet("key", "foo", "bar").toString());
+ assertEquals("key in ['\\foo', 'ba\\r']",
+ new FeatureSet("key", "\foo", "ba\r").toString());
+ assertEquals("key in ['\\x27bar\\x27', '\\x27foo\\x27']",
+ new FeatureSet("key", "'foo'", "'bar'").toString());
+ }
+
+ @Test
+ public void requireThatSimpleStringsArePrettyPrinted() {
+ assertEquals("foo in [bar]",
+ new FeatureSet("foo", "bar").toString());
+ }
+
+ @Test
+ public void requireThatComplexStringsAreEscaped() {
+ assertEquals("'\\foo' in ['ba\\r']",
+ new FeatureSet("\foo", "ba\r").toString());
+ }
+
+ @Test
+ public void requireThatNegatedFeatureSetsArePrettyPrinted() {
+ assertEquals("country not in [no, se]",
+ new Negation(new FeatureSet("country", "no", "se")).toString());
+ }
+
+ private static void assertValues(Collection<String> expected, FeatureSet actual) {
+ List<String> tmp = new ArrayList<>(expected);
+ for (String value : actual.getValues()) {
+ assertNotNull(value, tmp.remove(value));
+ }
+ assertTrue(tmp.toString(), tmp.isEmpty());
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/NegationTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/NegationTest.java
new file mode 100644
index 00000000000..95666342152
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/NegationTest.java
@@ -0,0 +1,89 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class NegationTest {
+
+ @Test
+ public void requireThatNegationIsAnOperator() {
+ assertTrue(PredicateOperator.class.isAssignableFrom(Negation.class));
+ }
+
+ @Test
+ public void requireThatAccessorsWork() {
+ Predicate foo = SimplePredicates.newString("foo");
+ Negation node = new Negation(foo);
+ assertSame(foo, node.getOperand());
+
+ Predicate bar = SimplePredicates.newString("bar");
+ node.setOperand(bar);
+ assertSame(bar, node.getOperand());
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ Negation node1 = new Negation(SimplePredicates.newString("a"));
+ Negation node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ assertNotSame(node1.getOperand(), node2.getOperand());
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ Predicate predicate = SimplePredicates.newPredicate();
+ assertEquals(new Negation(predicate).hashCode(), new Negation(predicate).hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ Negation lhs = new Negation(SimplePredicates.newString("foo"));
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ Negation rhs = new Negation(SimplePredicates.newString("bar"));
+ assertFalse(lhs.equals(rhs));
+ rhs.setOperand(SimplePredicates.newString("foo"));
+ assertTrue(lhs.equals(rhs));
+ }
+
+ @Test
+ public void requireThatChildIsMandatoryInConstructor() {
+ try {
+ new Negation(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("operand", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatChildIsMandatoryInSetter() {
+ Predicate operand = SimplePredicates.newPredicate();
+ Negation negation = new Negation(operand);
+ try {
+ negation.setOperand(null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("operand", e.getMessage());
+ }
+ assertSame(operand, negation.getOperand());
+ }
+
+ @Test
+ public void requireThatChildIsIncludedInToString() {
+ assertEquals("not (foo)", new Negation(SimplePredicates.newString("foo")).toString());
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateHashTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateHashTest.java
new file mode 100644
index 00000000000..759bfe9f48f
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateHashTest.java
@@ -0,0 +1,102 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class PredicateHashTest{
+ @Test
+ public void requireThatShortStringsGetsHashes() {
+ assertHashesTo(0x82af3d1de65ec252L, "abcdefg");
+ assertHashesTo(0xdc50d922fb0e91d6L, "雅虎");
+ assertHashesTo(0x709bd6ff1a84dc14L, "country=日本");
+ assertHashesTo(0x28e8de732ab0e809L, "foo");
+
+ assertHashesTo(0x8db63936938575bfL, "");
+ assertHashesTo(0x1d48fd74d88633acL, "a");
+ assertHashesTo(0xd30019bef51f4a75L, "ab");
+ assertHashesTo(0x9cb12e2bfea87243L, "abc");
+ assertHashesTo(0x207e64432ec23f4bL, "abcd");
+ assertHashesTo(0xbb1277971caf7a56L, "abcde");
+ assertHashesTo(0xfde595baae539176L, "abcdef");
+ assertHashesTo(0x82af3d1de65ec252L, "abcdefg");
+ assertHashesTo(0x1cac1cd5db905a5fL, "abcdefgh");
+ assertHashesTo(0x1ce1c26a201525deL, "abcdefghi");
+ assertHashesTo(0x2237a417a20c1025L, "abcdefghij");
+ assertHashesTo(0xd98f47421abc3754L, "abcdefghijk");
+ assertHashesTo(0xb974917101764d3aL, "abcdefghijkl");
+ assertHashesTo(0xde3b7ffe3e6dd61fL, "abcdefghijklm");
+ assertHashesTo(0x31d95fa68634f482L, "abcdefghijklmn");
+ assertHashesTo(0xde99d87fdbeca8faL, "abcdefghijklmn1");
+ assertHashesTo(0x0afc8571f275c392L, "abcdefghijklmn12");
+ assertHashesTo(0xbd00379443b0606cL, "abcdefghijklmn123");
+ assertHashesTo(0x855c704c68e095c5L, "abcdefghijklmn1234");
+ assertHashesTo(0xe9233cb6e4fad097L, "abcdefghijklmn12345");
+ assertHashesTo(0x1103ca46bd6e8d2fL, "abcdefghijklmn123456");
+ assertHashesTo(0x0c7097be717354d1L, "abcdefghijklmn1234567");
+ assertHashesTo(0x3e75293210127583L, "abcdefghijklmn12345678");
+ assertHashesTo(0xa66286e1294d8197L, "abcdefghijklmn123456789");
+ assertHashesTo(0x79fac97d13f4cc84L, "abcdefghijklmn1234567890");
+ }
+
+ @Test
+ public void requireThatLongStringsGetsHashes() {
+ assertHashesTo(0x79fac97d13f4cc84L, "abcdefghijklmn1234567890");
+ assertHashesTo(0xd7af1798f1d5de44L, "abcdefghijklmn1234567890a");
+ assertHashesTo(0x5a259ad887478cccL, "abcdefghijklmn1234567890ab");
+ assertHashesTo(0x4e8d95bab8d64191L, "abcdefghijklmn1234567890abc");
+ assertHashesTo(0xf63b94d31db2fe1aL, "abcdefghijklmn1234567890abcd");
+ assertHashesTo(0x47a1977d65709aceL, "abcdefghijklmn1234567890abcde");
+ assertHashesTo(0x52e1fb6d6aff3aeeL, "abcdefghijklmn1234567890abcdef");
+ assertHashesTo(0xc16de639b6e69ad3L, "abcdefghijklmn1234567890abcdefg");
+ assertHashesTo(0x87c22dd1e285dd6fL, "abcdefghijklmn1234567890abcdefgh");
+ assertHashesTo(0x775a3542d88b4972L, "abcdefghijklmn1234567890abcdefghi");
+ assertHashesTo(0x7b0c82116edf338bL, "abcdefghijklmn1234567890abcdefghij");
+ assertHashesTo(0x0fe73b58f6b23cb6L, "abcdefghijklmn1234567890abcdefghijk");
+ assertHashesTo(0x27ab8d02387e64e0L, "abcdefghijklmn1234567890abcdefghijkl");
+ assertHashesTo(0xdd161af20b41be04L, "abcdefghijklmn1234567890abcdefghijklm");
+ assertHashesTo(0x67739554f61fffcbL, "abcdefghijklmn1234567890abcdefghijklmn");
+ assertHashesTo(0xa765cc6be247dfb2L, "abcdefghijklmn1234567890abcdefghijklmn1");
+ assertHashesTo(0x9e201896cc600501L, "abcdefghijklmn1234567890abcdefghijklmn12");
+ assertHashesTo(0xfc5077792bfed491L, "abcdefghijklmn1234567890abcdefghijklmn123");
+ assertHashesTo(0x96a7acb73fd13601L, "abcdefghijklmn1234567890abcdefghijklmn1234");
+ assertHashesTo(0x45de4237e48a0ba8L, "abcdefghijklmn1234567890abcdefghijklmn12345");
+ assertHashesTo(0x3b65da96300e107eL, "abcdefghijklmn1234567890abcdefghijklmn123456");
+ assertHashesTo(0xbd95c3591ee587bdL, "abcdefghijklmn1234567890abcdefghijklmn1234567");
+ assertHashesTo(0x2688cb2d10e8629bL, "abcdefghijklmn1234567890abcdefghijklmn12345678");
+ assertHashesTo(0xcd383d98f9483ef0L, "abcdefghijklmn1234567890abcdefghijklmn123456789");
+ assertHashesTo(0x220e374268970e84L, "abcdefghijklmn1234567890abcdefghijklmn1234567890");
+ assertHashesTo(0xd50ef002ed96bf0bL, "abcdefghijklmn1234567890abcdefghijklmn1234567890a");
+ assertHashesTo(0x5ec9b42099bb25c6L, "abcdefghijklmn1234567890abcdefghijklmn1234567890ab");
+ assertHashesTo(0x05c603997a19dbceL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abc");
+ assertHashesTo(0xcee3fce2a3e38762L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcd");
+ assertHashesTo(0xc0d9791b19897f0aL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcde");
+ assertHashesTo(0xde98d0f8250ec703L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdef");
+ assertHashesTo(0xa7688d5834fa7d2aL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefg");
+ assertHashesTo(0xad514e8250667cdeL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefgh");
+ assertHashesTo(0xf562662deca536c3L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghi");
+ assertHashesTo(0x9d1b8d2463cde877L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghij");
+ assertHashesTo(0x24840f21eeb30861L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijk");
+ assertHashesTo(0x40af2a3f14d31fdaL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijkl");
+ assertHashesTo(0x3514ad5e964b5c73L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklm");
+ assertHashesTo(0x7bd6243490571844L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn");
+ assertHashesTo(0x273de93a3bddd9e8L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn1");
+ assertHashesTo(0x18e6850c3e2f85beL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn12");
+ assertHashesTo(0x044968ddc534d822L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn123");
+ assertHashesTo(0x7430d9d503fe624dL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn1234");
+ assertHashesTo(0xf0bb1e5239c1d88cL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn12345");
+ assertHashesTo(0x2ee1ab348b7deaa0L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn123456");
+ assertHashesTo(0x18b6da5df76680dfL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn1234567");
+ assertHashesTo(0x06c95ee4ddc93743L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn12345678");
+ assertHashesTo(0x6406e477d8ca608dL, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn123456789");
+ assertHashesTo(0x203397a04178d470L, "abcdefghijklmn1234567890abcdefghijklmn1234567890abcdefghijklmn1234567890");
+ }
+
+ private void assertHashesTo(long hash, String key) {
+ assertEquals(hash, PredicateHash.hash64(key));
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateOperatorTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateOperatorTest.java
new file mode 100644
index 00000000000..b6de0bf3514
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateOperatorTest.java
@@ -0,0 +1,17 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class PredicateOperatorTest {
+
+ @Test
+ public void requireThatOperatorIsAPredicate() {
+ assertTrue(Predicate.class.isAssignableFrom(PredicateOperator.class));
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateParserTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateParserTest.java
new file mode 100644
index 00000000000..ee161c20feb
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateParserTest.java
@@ -0,0 +1,155 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+
+public class PredicateParserTest {
+
+ @Test
+ public void requireThatParseErrorThrowsException() {
+ try {
+ Predicate.fromString("a in b");
+ fail("Expected an exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("line 1:5 no viable alternative at input 'b'", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatLexerErrorThrowsException() {
+ try {
+ Predicate.fromString("a-b in [b]");
+ fail("Expected an exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("line 1:2 no viable alternative at character 'b'", e.getMessage());
+ }
+ }
+
+ @Test
+ public void requireThatSingleValueLeafNodesParse() {
+ assertParsesTo("a in [b]", "a in [b]");
+ assertParsesTo("0 in [1]", "0 in [1]");
+ assertParsesTo("in in [in]", "in in [in]");
+ assertParsesTo("and in [or]", "and in [or]");
+ assertParsesTo("not in [not]", "not in [not]");
+ assertParsesTo("'-234' in ['+200']", "'-234' in ['+200']");
+ assertParsesTo("string in ['!@#$%^&*()[]']", "'string' in ['!@#$%^&*()[]']");
+ assertParsesTo("a in [b]", "a in [b]");
+ assertParsesTo("string in ['foo\\\\_\"\\t\\n\\f\\rbar']",
+ "string in ['foo\\\\_\\x22\\t\\n\\f\\rbar']");
+ assertParsesTo("'\\xC3\\xB8' in [b]", "'ø' in [b]");
+ assertParsesTo("'\\xEF\\xBF\\xBD' in [b]", "'\\xf8' in [b]");
+ assertParsesTo("'\\xEF\\xBF\\xBD' in [b]", "'\\xef\\xbf\\xbd' in ['b']");
+ assertParsesTo("'\\xE4\\xB8\\x9C\\xE8\\xA5\\xBF' in ['\\xE8\\x87\\xAA\\xE8\\xA1\\x8C\\xE8\\xBD\\xA6']",
+ "'东西' in ['自行车']");
+ assertParsesTo("true in [false]", "true in [false]");
+ }
+
+ @Test
+ public void requireThatMultiValueLeafNodesParse() {
+ assertParsesTo("a in [b]", "a in [b]");
+ assertParsesTo("0 in [1]", "0 in [1]");
+ assertParsesTo("in in [and, in]", "in in [in, and]");
+ assertParsesTo("a in [b, c, d, e, f]", "'a' in ['b', 'c', 'd', 'e', 'f']");
+ }
+
+ @Test
+ public void requireThatBothSingleAndDoubleQuotesWork() {
+ assertParsesTo("a in [b]", "'a' in ['b']");
+ assertParsesTo("a in [b]", "\"a\" in [\"b\"]");
+ assertParsesTo("'a\\x27' in [b]", "'a\\'' in ['b']");
+ assertParsesTo("'a\"' in [b]", "\"a\\\"\" in [\"b\"]");
+ }
+
+ @Test
+ public void requireThatRangeLeafNodesParse() {
+ assertParsesTo("a in [0..100]", "a in [0..100]");
+ assertParsesTo("0 in [..100]", "0 in [..100]");
+ assertParsesTo("0 in [0..]", "0 in [0..]");
+ assertParsesTo("0 in [..]", "0 in [..]");
+ assertParsesTo("a in [-100..100]", "a in [-100..+100]");
+ assertParsesTo("a in [-9223372036854775808..9223372036854775807]",
+ "a in [-9223372036854775808..+9223372036854775807]");
+ }
+
+ @Test
+ public void requireThatRangePartitionsAreIgnored() {
+ assertParsesTo("a in [0..100]", "a in [0..100 (a=0-99,a=100+[..0])]");
+ assertParsesTo("a in [-100..0]", "a in [-100..0 (a=-0-99,a=-100+[..0])]");
+ assertParsesTo("a in [-9223372036854775808..0]", "a in [-9223372036854775808..0 (a=-0-9223372036854775808)]");
+ assertParsesTo("a in [2..8]", "a in [2..8 (a=0+[2..8])]");
+ assertParsesTo("a in [0..8]", "a in [0..8 (a=0+[..8])]");
+ assertParsesTo("a in [2..9]", "a in [2..9 (a=0+[2..])]");
+ }
+
+ @Test
+ public void requireThatNotInSetWorks() {
+ assertParsesTo("a not in [b]", "a not in [b]");
+ }
+
+ @Test
+ public void requireThatConjunctionWorks() {
+ assertParsesTo("a in [b] and c in [d]", "a in [b] and c in [d]");
+ assertParsesTo("a in [b] and c in [d] and e in [f]", "a in [b] and c in [d] and e in [f]");
+ }
+
+ @Test
+ public void requireThatDisjunctionWorks() {
+ assertParsesTo("a in [b] or c in [d]", "a in [b] or c in [d]");
+ assertParsesTo("a in [b] or c in [d] or e in [f]", "a in [b] or c in [d] or e in [f]");
+ }
+
+ @Test
+ public void requireThatParenthesesWorks() {
+ assertParsesTo("a in [b] or c in [d]",
+ "(a in [b]) or (c in [d])");
+ assertParsesTo("a in [b] or c in [d] or e in [f]",
+ "(((a in [b]) or c in [d]) or e in [f])");
+ assertParsesTo("(a in [b] and c in [d]) or e in [f]",
+ "a in [b] and c in [d] or e in [f]");
+ assertParsesTo("a in [b] and (c in [d] or e in [f])",
+ "a in [b] and (c in [d] or e in [f])");
+ assertParsesTo("a in [b] and (c in [d] or e in [f]) and g in [h]",
+ "a in [b] and (c in [d] or e in [f]) and g in [h]");
+ }
+
+ @Test
+ public void requireThatNotOutsideParenthesesWorks() {
+ assertParsesTo("a not in [b]", "not (a in [b])");
+ }
+
+ @Test
+ public void requireThatConjunctionsCanGetMoreThanTwoChildren() {
+ Predicate p = Predicate.fromString("a in [b] and c in [d] and e in [f] and g in [h]");
+ assertTrue(p instanceof Conjunction);
+ assertEquals(4, ((Conjunction)p).getOperands().size());
+ }
+
+ @Test
+ public void requireThatDisjunctionsCanGetMoreThanTwoChildren() {
+ Predicate p = Predicate.fromString("a in [b] or c in [d] or e in [f] or g in [h]");
+ assertTrue(p instanceof Disjunction);
+ assertEquals(4, ((Disjunction)p).getOperands().size());
+ }
+
+ @Test
+ public void requireThatBooleanCanBeParsed() {
+ assertParsesTo("true", "true");
+ assertParsesTo("false", "false");
+ assertParsesTo("true or false", "true or false");
+ assertParsesTo("false and true", "false and true");
+ }
+
+ private static void assertParsesTo(String expected, String predicate_str) {
+ assertEquals(expected, // TODO: Predicate.fromString(expected)
+ Predicate.fromString(predicate_str).toString());
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateTest.java
new file mode 100644
index 00000000000..621378f394b
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateTest.java
@@ -0,0 +1,110 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static com.yahoo.document.predicate.Predicates.and;
+import static com.yahoo.document.predicate.Predicates.feature;
+import static com.yahoo.document.predicate.Predicates.not;
+import static com.yahoo.document.predicate.Predicates.or;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class PredicateTest {
+
+ @Test
+ public void requireThatPredicateIsCloneable() {
+ assertTrue(Cloneable.class.isAssignableFrom(Predicate.class));
+ }
+
+ @Test
+ public void requireThatANDConstructsAConjunction() {
+ Predicate foo = SimplePredicates.newString("foo");
+ Predicate bar = SimplePredicates.newString("bar");
+ Predicate predicate = and(foo, bar);
+ assertEquals(Conjunction.class, predicate.getClass());
+ assertEquals(new Conjunction(foo, bar), predicate);
+ }
+
+ @Test
+ public void requireThatORConstructsADisjunction() {
+ Predicate foo = SimplePredicates.newString("foo");
+ Predicate bar = SimplePredicates.newString("bar");
+ Predicate predicate = or(foo, bar);
+ assertEquals(Disjunction.class, predicate.getClass());
+ assertEquals(new Disjunction(foo, bar), predicate);
+ }
+
+ @Test
+ public void requireThatNOTConstructsANegation() {
+ Predicate foo = SimplePredicates.newString("foo");
+ Predicate predicate = not(foo);
+ assertEquals(Negation.class, predicate.getClass());
+ assertEquals(new Negation(foo), predicate);
+ }
+
+ @Test
+ public void requireThatFeatureBuilderCanConstructFeatureRange() {
+ assertEquals(new FeatureRange("key", 6L, 9L),
+ feature("key").inRange(6, 9));
+ assertEquals(new Negation(new FeatureRange("key", 6L, 9L)),
+ feature("key").notInRange(6, 9));
+ assertEquals(new FeatureRange("key", 7L, null),
+ feature("key").greaterThan(6));
+ assertEquals(new FeatureRange("key", 6L, null),
+ feature("key").greaterThanOrEqualTo(6));
+ assertEquals(new FeatureRange("key", null, 5L),
+ feature("key").lessThan(6));
+ assertEquals(new FeatureRange("key", null, 9L),
+ feature("key").lessThanOrEqualTo(9));
+ }
+
+ @Test
+ public void requireThatFeatureBuilderCanConstructFeatureSet() {
+ assertEquals(new FeatureSet("key", "valueA", "valueB"),
+ feature("key").inSet("valueA", "valueB"));
+ assertEquals(new Negation(new FeatureSet("key", "valueA", "valueB")),
+ feature("key").notInSet("valueA", "valueB"));
+ }
+
+ @Test
+ public void requireThatPredicatesCanBeConstructedUsingConstructors() {
+ assertEquals("country in [no, se] and age in [20..30]",
+ new Conjunction(new FeatureSet("country", "no", "se"),
+ new FeatureRange("age", 20L, 30L)).toString());
+ assertEquals("country not in [no, se] or age in [20..] or height in [..160]",
+ new Disjunction(new Negation(new FeatureSet("country", "no", "se")),
+ new FeatureRange("age", 20L, null),
+ new FeatureRange("height", null, 160L)).toString());
+ }
+
+ @Test
+ public void requireThatPredicatesCanBeBuiltUsingChainedMethodCalls() {
+ assertEquals("country not in [no, se] or age in [20..] or height in [..160]",
+ new Disjunction()
+ .addOperand(new Negation(new FeatureSet("country").addValue("no").addValue("se")))
+ .addOperand(new FeatureRange("age").setFromInclusive(20L))
+ .addOperand(new FeatureRange("height").setToInclusive(160L))
+ .toString());
+ }
+
+ @Test
+ public void requireThatPredicatesCanBeBuiltUsingSeparateMethodCalls() {
+ Conjunction conjunction = new Conjunction();
+ FeatureSet countrySet = new FeatureSet("country");
+ countrySet.addValue("no");
+ countrySet.addValue("se");
+ conjunction.addOperand(countrySet);
+ FeatureRange ageRange = new FeatureRange("age");
+ ageRange.setFromInclusive(20L);
+ conjunction.addOperand(ageRange);
+ FeatureRange heightRange = new FeatureRange("height");
+ heightRange.setToInclusive(160L);
+ conjunction.addOperand(heightRange);
+ assertEquals("country in [no, se] and age in [20..] and height in [..160]",
+ conjunction.toString());
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateValueTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateValueTest.java
new file mode 100644
index 00000000000..810e9a8717c
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicateValueTest.java
@@ -0,0 +1,17 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class PredicateValueTest {
+
+ @Test
+ public void requireThatValueIsAPredicate() {
+ assertTrue(Predicate.class.isAssignableFrom(PredicateValue.class));
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicatesTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicatesTest.java
new file mode 100644
index 00000000000..22832eedeff
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/PredicatesTest.java
@@ -0,0 +1,38 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static com.yahoo.document.predicate.Predicates.and;
+import static com.yahoo.document.predicate.Predicates.feature;
+import static com.yahoo.document.predicate.Predicates.not;
+import static com.yahoo.document.predicate.Predicates.or;
+import static com.yahoo.document.predicate.Predicates.value;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class PredicatesTest {
+
+ @Test
+ public void requireThatApiIsUsable() {
+ assertEquals(
+ new Disjunction(
+ new Conjunction(new FeatureSet("country", "de", "no"),
+ new Negation(new FeatureSet("gender", "female")),
+ new FeatureRange("age", 6L, 9L)),
+ new Conjunction(new Negation(new FeatureSet("country", "se")),
+ new FeatureSet("gender", "female"),
+ new FeatureRange("age", 69L, null))),
+ or(and(feature("country").inSet("de", "no"),
+ feature("gender").notInSet("female"),
+ feature("age").inRange(6, 9)),
+ and(not(feature("country").inSet("se")),
+ feature("gender").inSet("female"),
+ feature("age").greaterThanOrEqualTo(69))));
+
+ assertEquals(new BooleanPredicate(true), value(true));
+ assertEquals(new BooleanPredicate(false), value(false));
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/RangeEdgePartitionTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/RangeEdgePartitionTest.java
new file mode 100644
index 00000000000..d9f6714d8c8
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/RangeEdgePartitionTest.java
@@ -0,0 +1,62 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class RangeEdgePartitionTest {
+
+ @Test
+ public void requireThatRangeEdgePartitionIsAValue() {
+ assertTrue(PredicateValue.class.isAssignableFrom(RangeEdgePartition.class));
+ }
+
+ @Test
+ public void requireThatConstructorsWork() {
+ RangeEdgePartition part = new RangeEdgePartition("foo=10", 10, 0, -1);
+ assertEquals("foo=10", part.getLabel());
+ assertEquals(0, part.getLowerBound());
+ assertEquals(-1, part.getUpperBound());
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ RangeEdgePartition node1 = new RangeEdgePartition("foo=10", 10, 0, 0);
+ RangeEdgePartition node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new RangeEdgePartition("foo=-10", 10, 2, 3).hashCode(),
+ new RangeEdgePartition("foo=-10", 10, 2, 3).hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ RangeEdgePartition lhs = new RangeEdgePartition("foo=10", 10, 5, 10);
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ RangeEdgePartition rhs = new RangeEdgePartition("foo=20", 20, 0, 0);
+ assertFalse(lhs.equals(rhs));
+ rhs = new RangeEdgePartition("foo=10", 10, 5, 10);
+ assertTrue(lhs.equals(rhs));
+ assertFalse(lhs.equals(new RangeEdgePartition("foo=10", 10, 5, 11)));
+ assertFalse(lhs.equals(new RangeEdgePartition("foo=10", 10, 6, 10)));
+ assertFalse(lhs.equals(new RangeEdgePartition("foo=10", 11, 5, 10)));
+ assertFalse(lhs.equals(new RangeEdgePartition("foo=11", 10, 5, 10)));
+ }
+
+ @Test
+ public void requireThatKeyIsEscapedInToString() {
+ assertEquals("foo=10+[2..3]", new RangeEdgePartition("foo=10", 10, 2, 3).toString());
+ assertEquals("'\\foo=10'+[2..3]", new RangeEdgePartition("\foo=10", 10, 2, 3).toString());
+ assertEquals("'\\x27foo\\x27=10'+[2..3]", new RangeEdgePartition("'foo'=10", 10, 2, 3).toString());
+ }}
diff --git a/predicate-search-core/src/test/java/com/yahoo/document/predicate/RangePartitionTest.java b/predicate-search-core/src/test/java/com/yahoo/document/predicate/RangePartitionTest.java
new file mode 100644
index 00000000000..b9d2c865e9b
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/document/predicate/RangePartitionTest.java
@@ -0,0 +1,60 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.predicate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class RangePartitionTest {
+
+ @Test
+ public void requireThatRangePartitionIsAValue() {
+ assertTrue(PredicateValue.class.isAssignableFrom(RangePartition.class));
+ }
+
+ @Test
+ public void requireThatConstructorsWork() {
+ RangePartition part = new RangePartition("foo=10-19");
+ assertEquals("foo=10-19", part.getLabel());
+ part = new RangePartition("foo", 10, 19, false);
+ assertEquals("foo=10-19", part.getLabel());
+ part = new RangePartition("foo", 10, 19, true);
+ assertEquals("foo=-19-10", part.getLabel());
+ }
+
+ @Test
+ public void requireThatCloneIsImplemented() throws CloneNotSupportedException {
+ RangePartition node1 = new RangePartition("foo=300-399");
+ RangePartition node2 = node1.clone();
+ assertEquals(node1, node2);
+ assertNotSame(node1, node2);
+ }
+
+ @Test
+ public void requireThatHashCodeIsImplemented() {
+ assertEquals(new RangePartition("foo=0-9").hashCode(), new RangePartition("foo=0-9").hashCode());
+ }
+
+ @Test
+ public void requireThatEqualsIsImplemented() {
+ RangePartition lhs = new RangePartition("foo=10-19");
+ assertTrue(lhs.equals(lhs));
+ assertFalse(lhs.equals(new Object()));
+
+ RangePartition rhs = new RangePartition("bar=1000-1999");
+ assertFalse(lhs.equals(rhs));
+ rhs = new RangePartition("foo=10-19");
+ assertTrue(lhs.equals(rhs));
+ }
+
+ @Test
+ public void requireThatKeyIsEscapedInToString() {
+ assertEquals("foo=10-19", new RangePartition("foo=10-19").toString());
+ assertEquals("'\\foo=10-19'", new RangePartition("\foo=10-19").toString());
+ assertEquals("'\\x27foo\\x27=10-19'", new RangePartition("'foo'=10-19").toString());
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/search/predicate/PredicateQueryParserTest.java b/predicate-search-core/src/test/java/com/yahoo/search/predicate/PredicateQueryParserTest.java
new file mode 100644
index 00000000000..dcee3a0c55d
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/search/predicate/PredicateQueryParserTest.java
@@ -0,0 +1,43 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.predicate;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author bjorncs
+ */
+public class PredicateQueryParserTest {
+
+ @Test
+ public void require_that_json_is_correctly_parsed() {
+ String json =
+ "{" +
+ " \"features\":[" +
+ " {\"k\":\"k1\",\"v\":\"value1\",\"s\":\"0x1\"}," +
+ " {\"k\":\"k2\",\"v\":\"value2\",\"s\":\"0x3\"}" +
+ " ],\"rangeFeatures\":[" +
+ " {\"k\":\"range1\",\"v\":123456789123,\"s\":\"0xffff\"}," +
+ " {\"k\":\"range2\",\"v\":0,\"s\":\"0xffffffffffffffff\"}" +
+ " ]" +
+ "}";
+
+ PredicateQueryParser parser = new PredicateQueryParser();
+ List<String> result = new ArrayList<>();
+ parser.parseJsonQuery(
+ json,
+ (k, v, s) -> result.add(String.format("%s:%s:%#x", k, v, s)),
+ (k, v, s) -> result.add(String.format("%s:%d:%#x", k, v, s)));
+
+ assertThat(result, is(Arrays.asList(
+ "k1:value1:0x1", "k2:value2:0x3",
+ "range1:123456789123:0xffff", "range2:0:0xffffffffffffffff")));
+ }
+
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/AndOrSimplifierTest.java b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/AndOrSimplifierTest.java
new file mode 100644
index 00000000000..4ec6c496e73
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/AndOrSimplifierTest.java
@@ -0,0 +1,134 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.predicate.optimization;
+
+import com.yahoo.document.predicate.Predicate;
+import org.junit.Test;
+
+import static com.yahoo.document.predicate.Predicates.and;
+import static com.yahoo.document.predicate.Predicates.feature;
+import static com.yahoo.document.predicate.Predicates.not;
+import static com.yahoo.document.predicate.Predicates.or;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class AndOrSimplifierTest {
+
+ @Test
+ public void requireThatNestedConjunctionsAreCollapsed() {
+ assertSimplified(and(feature("a").inSet("b"),
+ feature("c").inSet("d")),
+ and(and(feature("a").inSet("b"),
+ feature("c").inSet("d"))));
+ }
+
+ @Test
+ public void requireThatNestedConjuctionsAreCollapsedInPlace() {
+ assertSimplified(and(feature("a").inSet("b"),
+ feature("c").inSet("d"),
+ feature("e").inSet("f")),
+ and(feature("a").inSet("b"),
+ and(feature("c").inSet("d")),
+ feature("e").inSet("f")));
+ }
+
+ @Test
+ public void requireThatDeeplyNestedConjunctionsAreCollapsed() {
+ assertSimplified(and(feature("a").inSet("b"),
+ feature("c").inSet("d"),
+ feature("e").inSet("f"),
+ feature("g").inSet("h"),
+ feature("i").inSet("j")),
+ and(feature("a").inSet("b"),
+ and(feature("c").inSet("d")),
+ feature("e").inSet("f"),
+ and(and(feature("g").inSet("h"),
+ feature("i").inSet("j")))));
+ }
+
+ @Test
+ public void requireThatNestedDisjunctionsAreCollapsed() {
+ assertSimplified(or(feature("a").inSet("b"),
+ feature("c").inSet("d")),
+ or(or(feature("a").inSet("b"),
+ feature("c").inSet("d"))));
+ }
+
+ @Test
+ public void requireThatNestedDisjuctionsAreCollapsedInPlace() {
+ assertSimplified(or(feature("a").inSet("b"),
+ feature("c").inSet("d"),
+ feature("e").inSet("f")),
+ or(feature("a").inSet("b"),
+ or(feature("c").inSet("d")),
+ feature("e").inSet("f")));
+ }
+
+ @Test
+ public void requireThatDeeplyNestedDisjunctionsAreCollapsed() {
+ assertSimplified(or(feature("a").inSet("b"),
+ feature("c").inSet("d"),
+ feature("e").inSet("f"),
+ feature("g").inSet("h"),
+ feature("i").inSet("j")),
+ or(feature("a").inSet("b"),
+ or(feature("c").inSet("d")),
+ feature("e").inSet("f"),
+ or(or(feature("g").inSet("h"),
+ feature("i").inSet("j")))));
+ }
+
+ @Test
+ public void requireThatConjunctionsAndDisjunctionsAreNotCollapsed() {
+ assertSimplified(and(or(feature("a").inSet("b"),
+ feature("c").inSet("d"))),
+ and(or(feature("a").inSet("b"),
+ feature("c").inSet("d"))));
+ }
+
+ @Test
+ public void requireThatNotOrIsTranslatedToAndNot() {
+ assertSimplified(
+ and(feature("a").notInSet("b"), feature("c").inSet("d")),
+ not(or(feature("a").inSet("b"), feature("c").notInSet("d"))));
+ }
+
+ @Test
+ public void requireThatNotAndIsTranslatedToOrNot() {
+ assertSimplified(
+ or(feature("a").notInSet("b"), feature("c").inSet("d")),
+ not(and(feature("a").inSet("b"), feature("c").notInSet("d"))));
+ }
+
+ @Test
+ public void requireThatTreeWithoutNotIsNotAffected() {
+ assertSimplified(
+ and(feature("a").inSet("b"), feature("c").notInSet("d")),
+ and(feature("a").inSet("b"), feature("c").notInSet("d")));
+ assertSimplified(
+ or(feature("a").inSet("b"), feature("c").notInSet("d")),
+ or(feature("a").inSet("b"), feature("c").notInSet("d")));
+ assertSimplified(feature("a").inSet("b"), feature("a").inSet("b"));
+ }
+
+ @Test
+ public void requireThatNotOfNotIsRemoved() {
+ assertSimplified(feature("a").inSet("b"), not(not(feature("a").inSet("b"))));
+ assertSimplified(feature("a").inSet("b"), not(feature("a").notInSet("b")));
+ assertSimplified(feature("a").notInSet("b"), not(not(feature("a").notInSet("b"))));
+ }
+
+ @Test
+ public void requireThatNotBeneathAndIsTranslated() {
+ assertSimplified(
+ and(feature("a").notInSet("b"), feature("c").inSet("d"), feature("b").inSet("c")),
+ and(not(or(feature("a").inSet("b"), feature("c").notInSet("d"))), feature("b").inSet("c")));
+ }
+
+ private static void assertSimplified(Predicate expected, Predicate input) {
+ AndOrSimplifier simplifier = new AndOrSimplifier();
+ Predicate actual = simplifier.process(input, new PredicateOptions(10));
+ assertEquals(expected, actual);
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/BooleanSimplifierTest.java b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/BooleanSimplifierTest.java
new file mode 100644
index 00000000000..37d2352df57
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/BooleanSimplifierTest.java
@@ -0,0 +1,60 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.predicate.optimization;
+
+import com.yahoo.document.predicate.Predicate;
+import org.junit.Test;
+
+import static com.yahoo.document.predicate.Predicates.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class BooleanSimplifierTest {
+
+ @Test
+ public void requireThatOrOfTrueIsTrue() {
+ assertSimplifiedTo(value(true), or(feature("a").inSet("b"), value(true)));
+ }
+
+ @Test
+ public void requireThatFalseChildrenOfOrAreRemoved() {
+ assertSimplifiedTo(feature("a").inSet("b"), or(feature("a").inSet("b"), value(false)));
+ }
+
+ @Test
+ public void requireThatAndOfFalseIsFalse() {
+ assertSimplifiedTo(value(false), and(feature("a").inSet("b"), value(false)));
+ }
+
+ @Test
+ public void requireThatTrueChildrenOfAndAreRemoved() {
+ assertSimplifiedTo(feature("a").inSet("b"), and(feature("a").inSet("b"), value(true)));
+ }
+
+ @Test
+ public void requireThatSingleChildAndOrAreRemoved() {
+ assertSimplifiedTo(feature("a").inSet("b"), and(or(and(feature("a").inSet("b")))));
+ }
+
+ @Test
+ public void requireThatValueChildrenOfNotAreInverted() {
+ assertSimplifiedTo(value(true), not(value(false)));
+ assertSimplifiedTo(value(false), not(value(true)));
+ assertSimplifiedTo(value(true), not(not(not(value(false)))));
+ assertSimplifiedTo(value(true), not(not(not(and(feature("a").inSet("b"), value(false))))));
+ }
+
+ @Test
+ public void requireThatComplexExpressionIsSimplified() {
+ assertSimplifiedTo(
+ Predicate.fromString("'pub_entity' not in [301951]"),
+ Predicate.fromString("true and true and true and true and true and 'pub_entity' not in [301951] and ((true and true and true and true) or (true and true and true and true) or (true and true and true and true and 'pub_entity' in [86271]))"));
+ }
+
+ private void assertSimplifiedTo(Predicate expected, Predicate input) {
+ BooleanSimplifier simplifier = new BooleanSimplifier();
+ Predicate actual = simplifier.process(input, new PredicateOptions(10));
+ assertEquals(expected, actual);
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/ComplexNodeTransformerTest.java b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/ComplexNodeTransformerTest.java
new file mode 100644
index 00000000000..45cdabfb4f2
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/ComplexNodeTransformerTest.java
@@ -0,0 +1,604 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.predicate.optimization;
+
+import com.yahoo.document.predicate.FeatureRange;
+import com.yahoo.document.predicate.Predicate;
+import com.yahoo.document.predicate.RangePartition;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class ComplexNodeTransformerTest {
+
+ private long lowerBound = 0x8000000000000000L;
+ private long upperBound = 0x7fffffffffffffffL;
+
+ private void testConvert(String predicate, String expected) {
+ int defaultArity = 10;
+ testConvert(predicate, expected, defaultArity);
+ }
+
+ private void testConvert(String predicate, String expected, int arity) {
+ Predicate p = Predicate.fromString(predicate);
+ ComplexNodeTransformer transformer = new ComplexNodeTransformer();
+ Predicate converted = transformer.process(p, new PredicateOptions(arity, lowerBound, upperBound));
+ assertEquals(expected, converted.toString());
+ }
+
+ @Test
+ public void requireThatSingleValueRangesAreConverted() {
+ testConvert("foo in [0..0]", "foo in [0..0 (foo=0+[..0])]");
+ testConvert("foo in [5..5]", "foo in [5..5 (foo=0+[5..5])]");
+ testConvert("foo in [9..9]", "foo in [9..9 (foo=0+[9..])]");
+ testConvert("foo in [10..10]", "foo in [10..10 (foo=10+[..0])]");
+ testConvert("foo in [-5..-5]", "foo in [-5..-5 (foo=-0+[5..5])]");
+ testConvert("foo in [-9..-9]", "foo in [-9..-9 (foo=-0+[9..])]");
+ testConvert("foo in [-10..-10]", "foo in [-10..-10 (foo=-10+[..0])]");
+ }
+
+ @Test
+ public void requireThatVeryShortRangesAreConverted() {
+ testConvert("foo in [10..17]", "foo in [10..17 (foo=10+[..7])]");
+ testConvert("foo in [12..19]", "foo in [12..19 (foo=10+[2..])]");
+ testConvert("foo in [11..18]", "foo in [11..18 (foo=10+[1..8])]");
+ testConvert("foo in [7..13]", "foo in [7..13 (foo=0+[7..],foo=10+[..3])]");
+ testConvert("foo in [-17..-10]", "foo in [-17..-10 (foo=-10+[..7])]");
+ testConvert("foo in [-19..-12]", "foo in [-19..-12 (foo=-10+[2..])]");
+ testConvert("foo in [-18..-11]", "foo in [-18..-11 (foo=-10+[1..8])]");
+ testConvert("foo in [-13..-7]", "foo in [-13..-7 (foo=-0+[7..],foo=-10+[..3])]");
+ testConvert("foo in [-5..4]", "foo in [-5..4 (foo=-0+[..5],foo=0+[..4])]");
+ }
+
+ @Test
+ public void requireThatShortRangeIsConverted() {
+ testConvert("foo in [9..19]", "foo in [9..19 (foo=0+[9..],foo=10-19)]");
+ testConvert("foo in [10..19]", "foo in [10..19 (foo=10-19)]");
+ testConvert("foo in [10..20]", "foo in [10..20 (foo=20+[..0],foo=10-19)]");
+ testConvert("foo in [12..21]", "foo in [12..21 (foo=10+[2..],foo=20+[..1])]");
+ testConvert("foo in [-19..-9]", "foo in [-19..-9 (foo=-0+[9..],foo=-19-10)]");
+ testConvert("foo in [-19..-10]", "foo in [-19..-10 (foo=-19-10)]");
+ testConvert("foo in [-20..-10]", "foo in [-20..-10 (foo=-20+[..0],foo=-19-10)]");
+ testConvert("foo in [-21..-12]", "foo in [-21..-12 (foo=-10+[2..],foo=-20+[..1])]");
+ testConvert("foo in [-9..9]", "foo in [-9..9 (foo=-9-0,foo=0-9)]");
+ testConvert("foo in [-10..10]", "foo in [-10..10 (foo=-10+[..0],foo=10+[..0],foo=-9-0,foo=0-9)]");
+ }
+
+ @Test
+ public void requireThatMediumRangeIsConverted() {
+ testConvert("foo in [10..39]", "foo in [10..39 (foo=10-19,foo=20-29,foo=30-39)]");
+ testConvert("foo in [10..38]", "foo in [10..38 (foo=30+[..8],foo=10-19,foo=20-29)]");
+ testConvert("foo in [18..39]", "foo in [18..39 (foo=10+[8..],foo=20-29,foo=30-39)]");
+ testConvert("foo in [8..38]", "foo in [8..38 (foo=0+[8..],foo=30+[..8],foo=10-19,foo=20-29)]");
+ testConvert("foo in [-39..-10]", "foo in [-39..-10 (foo=-19-10,foo=-29-20,foo=-39-30)]");
+ testConvert("foo in [-38..-10]", "foo in [-38..-10 (foo=-30+[..8],foo=-19-10,foo=-29-20)]");
+ testConvert("foo in [-39..-18]", "foo in [-39..-18 (foo=-10+[8..],foo=-29-20,foo=-39-30)]");
+ testConvert("foo in [-38..-8]", "foo in [-38..-8 (foo=-0+[8..],foo=-30+[..8],foo=-19-10,foo=-29-20)]");
+ testConvert("foo in [-19..19]", "foo in [-19..19 (foo=-9-0,foo=-19-10,foo=0-9,foo=10-19)]");
+ }
+
+ @Test
+ public void requireThatLargeRangeIsConverted() {
+ testConvert("foo in [10..199]", "foo in [10..199 (foo=10-19,foo=20-29,foo=30-39,foo=40-49,foo=50-59,foo=60-69,foo=70-79,foo=80-89,foo=90-99,foo=100-199)]");
+ testConvert("foo in [8..207]", "foo in [8..207 (foo=0+[8..],foo=200+[..7],foo=10-19,foo=20-29,foo=30-39,foo=40-49,foo=50-59,foo=60-69,foo=70-79,foo=80-89,foo=90-99,foo=100-199)]");
+ testConvert("foo in [999..2001]", "foo in [999..2001 (foo=990+[9..],foo=2000+[..1],foo=1000-1999)]");
+ testConvert("foo in [999..2009]", "foo in [999..2009 (foo=990+[9..],foo=2000-2009,foo=1000-1999)]");
+ testConvert("foo in [999..2099]", "foo in [999..2099 (foo=990+[9..],foo=2000-2099,foo=1000-1999)]");
+ testConvert("foo in [999..2999]", "foo in [999..2999 (foo=990+[9..],foo=1000-1999,foo=2000-2999)]");
+ testConvert("foo in [-199..-10]", "foo in [-199..-10 (foo=-19-10,foo=-29-20,foo=-39-30,foo=-49-40,foo=-59-50,foo=-69-60,foo=-79-70,foo=-89-80,foo=-99-90,foo=-199-100)]");
+ testConvert("foo in [-207..-8]", "foo in [-207..-8 (foo=-0+[8..],foo=-200+[..7],foo=-19-10,foo=-29-20,foo=-39-30,foo=-49-40,foo=-59-50,foo=-69-60,foo=-79-70,foo=-89-80,foo=-99-90,foo=-199-100)]");
+ testConvert("foo in [-2001..-999]", "foo in [-2001..-999 (foo=-990+[9..],foo=-2000+[..1],foo=-1999-1000)]");
+ testConvert("foo in [-999..999]", "foo in [-999..999 (foo=-999-0,foo=0-999)]");
+ }
+
+ @Test
+ public void requireThatLongMaxIsConverted() {
+ testConvert("foo in [0..9223372036854775807]",
+ "foo in [0..9223372036854775807 (" +
+ "foo=9223372036854775800+[..7]," +
+ "foo=9223372036854775000-9223372036854775099," +
+ "foo=9223372036854775100-9223372036854775199," +
+ "foo=9223372036854775200-9223372036854775299," +
+ "foo=9223372036854775300-9223372036854775399," +
+ "foo=9223372036854775400-9223372036854775499," +
+ "foo=9223372036854775500-9223372036854775599," +
+ "foo=9223372036854775600-9223372036854775699," +
+ "foo=9223372036854775700-9223372036854775799," +
+ "foo=9223372036854770000-9223372036854770999," +
+ "foo=9223372036854771000-9223372036854771999," +
+ "foo=9223372036854772000-9223372036854772999," +
+ "foo=9223372036854773000-9223372036854773999," +
+ "foo=9223372036854774000-9223372036854774999," +
+ "foo=9223372036854700000-9223372036854709999," +
+ "foo=9223372036854710000-9223372036854719999," +
+ "foo=9223372036854720000-9223372036854729999," +
+ "foo=9223372036854730000-9223372036854739999," +
+ "foo=9223372036854740000-9223372036854749999," +
+ "foo=9223372036854750000-9223372036854759999," +
+ "foo=9223372036854760000-9223372036854769999," +
+ "foo=9223372036854000000-9223372036854099999," +
+ "foo=9223372036854100000-9223372036854199999," +
+ "foo=9223372036854200000-9223372036854299999," +
+ "foo=9223372036854300000-9223372036854399999," +
+ "foo=9223372036854400000-9223372036854499999," +
+ "foo=9223372036854500000-9223372036854599999," +
+ "foo=9223372036854600000-9223372036854699999," +
+ "foo=9223372036850000000-9223372036850999999," +
+ "foo=9223372036851000000-9223372036851999999," +
+ "foo=9223372036852000000-9223372036852999999," +
+ "foo=9223372036853000000-9223372036853999999," +
+ "foo=9223372036800000000-9223372036809999999," +
+ "foo=9223372036810000000-9223372036819999999," +
+ "foo=9223372036820000000-9223372036829999999," +
+ "foo=9223372036830000000-9223372036839999999," +
+ "foo=9223372036840000000-9223372036849999999," +
+ "foo=9223372036000000000-9223372036099999999," +
+ "foo=9223372036100000000-9223372036199999999," +
+ "foo=9223372036200000000-9223372036299999999," +
+ "foo=9223372036300000000-9223372036399999999," +
+ "foo=9223372036400000000-9223372036499999999," +
+ "foo=9223372036500000000-9223372036599999999," +
+ "foo=9223372036600000000-9223372036699999999," +
+ "foo=9223372036700000000-9223372036799999999," +
+ "foo=9223372030000000000-9223372030999999999," +
+ "foo=9223372031000000000-9223372031999999999," +
+ "foo=9223372032000000000-9223372032999999999," +
+ "foo=9223372033000000000-9223372033999999999," +
+ "foo=9223372034000000000-9223372034999999999," +
+ "foo=9223372035000000000-9223372035999999999," +
+ "foo=9223372000000000000-9223372009999999999," +
+ "foo=9223372010000000000-9223372019999999999," +
+ "foo=9223372020000000000-9223372029999999999," +
+ "foo=9223370000000000000-9223370999999999999," +
+ "foo=9223371000000000000-9223371999999999999," +
+ "foo=9223300000000000000-9223309999999999999," +
+ "foo=9223310000000000000-9223319999999999999," +
+ "foo=9223320000000000000-9223329999999999999," +
+ "foo=9223330000000000000-9223339999999999999," +
+ "foo=9223340000000000000-9223349999999999999," +
+ "foo=9223350000000000000-9223359999999999999," +
+ "foo=9223360000000000000-9223369999999999999," +
+ "foo=9223000000000000000-9223099999999999999," +
+ "foo=9223100000000000000-9223199999999999999," +
+ "foo=9223200000000000000-9223299999999999999," +
+ "foo=9220000000000000000-9220999999999999999," +
+ "foo=9221000000000000000-9221999999999999999," +
+ "foo=9222000000000000000-9222999999999999999," +
+ "foo=9200000000000000000-9209999999999999999," +
+ "foo=9210000000000000000-9219999999999999999," +
+ "foo=9000000000000000000-9099999999999999999," +
+ "foo=9100000000000000000-9199999999999999999," +
+ "foo=0-999999999999999999," +
+ "foo=1000000000000000000-1999999999999999999," +
+ "foo=2000000000000000000-2999999999999999999," +
+ "foo=3000000000000000000-3999999999999999999," +
+ "foo=4000000000000000000-4999999999999999999," +
+ "foo=5000000000000000000-5999999999999999999," +
+ "foo=6000000000000000000-6999999999999999999," +
+ "foo=7000000000000000000-7999999999999999999," +
+ "foo=8000000000000000000-8999999999999999999)]");
+
+ testConvert("foo in [9223372036854775807..9223372036854775807]", "foo in [9223372036854775807..9223372036854775807 (foo=9223372036854775800+[7..7])]");
+ }
+
+ @Test
+ public void requireThatLongMinIsConverted() {
+ testConvert("foo in [-9223372036854775808..-1]",
+ "foo in [-9223372036854775808..-1 (" +
+ "foo=-9223372036854775800+[..8]," +
+ "foo=-9223372036854775099-9223372036854775000," +
+ "foo=-9223372036854775199-9223372036854775100," +
+ "foo=-9223372036854775299-9223372036854775200," +
+ "foo=-9223372036854775399-9223372036854775300," +
+ "foo=-9223372036854775499-9223372036854775400," +
+ "foo=-9223372036854775599-9223372036854775500," +
+ "foo=-9223372036854775699-9223372036854775600," +
+ "foo=-9223372036854775799-9223372036854775700," +
+ "foo=-9223372036854770999-9223372036854770000," +
+ "foo=-9223372036854771999-9223372036854771000," +
+ "foo=-9223372036854772999-9223372036854772000," +
+ "foo=-9223372036854773999-9223372036854773000," +
+ "foo=-9223372036854774999-9223372036854774000," +
+ "foo=-9223372036854709999-9223372036854700000," +
+ "foo=-9223372036854719999-9223372036854710000," +
+ "foo=-9223372036854729999-9223372036854720000," +
+ "foo=-9223372036854739999-9223372036854730000," +
+ "foo=-9223372036854749999-9223372036854740000," +
+ "foo=-9223372036854759999-9223372036854750000," +
+ "foo=-9223372036854769999-9223372036854760000," +
+ "foo=-9223372036854099999-9223372036854000000," +
+ "foo=-9223372036854199999-9223372036854100000," +
+ "foo=-9223372036854299999-9223372036854200000," +
+ "foo=-9223372036854399999-9223372036854300000," +
+ "foo=-9223372036854499999-9223372036854400000," +
+ "foo=-9223372036854599999-9223372036854500000," +
+ "foo=-9223372036854699999-9223372036854600000," +
+ "foo=-9223372036850999999-9223372036850000000," +
+ "foo=-9223372036851999999-9223372036851000000," +
+ "foo=-9223372036852999999-9223372036852000000," +
+ "foo=-9223372036853999999-9223372036853000000," +
+ "foo=-9223372036809999999-9223372036800000000," +
+ "foo=-9223372036819999999-9223372036810000000," +
+ "foo=-9223372036829999999-9223372036820000000," +
+ "foo=-9223372036839999999-9223372036830000000," +
+ "foo=-9223372036849999999-9223372036840000000," +
+ "foo=-9223372036099999999-9223372036000000000," +
+ "foo=-9223372036199999999-9223372036100000000," +
+ "foo=-9223372036299999999-9223372036200000000," +
+ "foo=-9223372036399999999-9223372036300000000," +
+ "foo=-9223372036499999999-9223372036400000000," +
+ "foo=-9223372036599999999-9223372036500000000," +
+ "foo=-9223372036699999999-9223372036600000000," +
+ "foo=-9223372036799999999-9223372036700000000," +
+ "foo=-9223372030999999999-9223372030000000000," +
+ "foo=-9223372031999999999-9223372031000000000," +
+ "foo=-9223372032999999999-9223372032000000000," +
+ "foo=-9223372033999999999-9223372033000000000," +
+ "foo=-9223372034999999999-9223372034000000000," +
+ "foo=-9223372035999999999-9223372035000000000," +
+ "foo=-9223372009999999999-9223372000000000000," +
+ "foo=-9223372019999999999-9223372010000000000," +
+ "foo=-9223372029999999999-9223372020000000000," +
+ "foo=-9223370999999999999-9223370000000000000," +
+ "foo=-9223371999999999999-9223371000000000000," +
+ "foo=-9223309999999999999-9223300000000000000," +
+ "foo=-9223319999999999999-9223310000000000000," +
+ "foo=-9223329999999999999-9223320000000000000," +
+ "foo=-9223339999999999999-9223330000000000000," +
+ "foo=-9223349999999999999-9223340000000000000," +
+ "foo=-9223359999999999999-9223350000000000000," +
+ "foo=-9223369999999999999-9223360000000000000," +
+ "foo=-9223099999999999999-9223000000000000000," +
+ "foo=-9223199999999999999-9223100000000000000," +
+ "foo=-9223299999999999999-9223200000000000000," +
+ "foo=-9220999999999999999-9220000000000000000," +
+ "foo=-9221999999999999999-9221000000000000000," +
+ "foo=-9222999999999999999-9222000000000000000," +
+ "foo=-9209999999999999999-9200000000000000000," +
+ "foo=-9219999999999999999-9210000000000000000," +
+ "foo=-9099999999999999999-9000000000000000000," +
+ "foo=-9199999999999999999-9100000000000000000," +
+ "foo=-999999999999999999-0," +
+ "foo=-1999999999999999999-1000000000000000000," +
+ "foo=-2999999999999999999-2000000000000000000," +
+ "foo=-3999999999999999999-3000000000000000000," +
+ "foo=-4999999999999999999-4000000000000000000," +
+ "foo=-5999999999999999999-5000000000000000000," +
+ "foo=-6999999999999999999-6000000000000000000," +
+ "foo=-7999999999999999999-7000000000000000000," +
+ "foo=-8999999999999999999-8000000000000000000)]");
+ testConvert("foo in [-9223372036854775808..-9223372036854775808]", "foo in [-9223372036854775808..-9223372036854775808 (foo=-9223372036854775800+[8..8])]");
+ }
+
+ @Test
+ public void requireThatLowAritiesWork() {
+ testConvert("foo in [10..39]", "foo in [10..39 (foo=10-11,foo=12-15,foo=32-39,foo=16-31)]", 2);
+ testConvert("foo in [2..32]", "foo in [2..32 (foo=32+[..0],foo=2-3,foo=4-7,foo=8-15,foo=16-31)]", 2);
+ testConvert("foo in [-31..63]", "foo in [-31..63 (foo=-31-0,foo=0-63)]", 2);
+ testConvert("foo in [0..9223372036854775807]", "foo in [0..9223372036854775807 (foo=0-9223372036854775807)]", 2);
+ testConvert("foo in [9223372036854775807..9223372036854775807]", "foo in [9223372036854775807..9223372036854775807 (foo=9223372036854775806+[1..])]", 2);
+ testConvert("foo in [-9223372036854775808..-1]", "foo in [-9223372036854775808..-1 (foo=-9223372036854775808+[..0],foo=-9223372036854775807-0)]", 2);
+ testConvert("foo in [-9223372036854775808..-9223372036854775808]", "foo in [-9223372036854775808..-9223372036854775808 (foo=-9223372036854775808+[..0])]", 2);
+ testConvert("foo in [-9223372036854775808..9223372036854775807]", "foo in [-9223372036854775808..9223372036854775807 (foo=-9223372036854775808+[..0],foo=-9223372036854775807-0,foo=0-9223372036854775807)]", 2);
+
+ testConvert("foo in [9223372036854775807..9223372036854775807]", "foo in [9223372036854775807..9223372036854775807 (foo=9223372036854775806+[1..1])]", 3);
+ testConvert("foo in [-9223372036854775808..-9223372036854775808]", "foo in [-9223372036854775808..-9223372036854775808 (foo=-9223372036854775806+[2..])]", 3);
+ testConvert("foo in [-9223372036854775808..-1]",
+ "foo in [-9223372036854775808..-1 (" +
+ "foo=-9223372036854775808-9223372036854775782," +
+ "foo=-9223372036854775700-9223372036854775620," +
+ "foo=-9223372036854775781-9223372036854775701," +
+ "foo=-9223372036854775376-9223372036854775134," +
+ "foo=-9223372036854775619-9223372036854775377," +
+ "foo=-9223372036854775133-9223372036854774405," +
+ "foo=-9223372036854774404-9223372036854767844," +
+ "foo=-9223372036854708794-9223372036854649746," +
+ "foo=-9223372036854767843-9223372036854708795," +
+ "foo=-9223372036854472598-9223372036854295452," +
+ "foo=-9223372036854649745-9223372036854472599," +
+ "foo=-9223372036854295451-9223372036853764011," +
+ "foo=-9223372036852169687-9223372036850575365," +
+ "foo=-9223372036853764010-9223372036852169688," +
+ "foo=-9223372036850575364-9223372036807528644," +
+ "foo=-9223372036420108154-9223372036032687666," +
+ "foo=-9223372036807528643-9223372036420108155," +
+ "foo=-9223372036032687665-9223372032545903265," +
+ "foo=-9223372022085550061-9223372011625196859," +
+ "foo=-9223372032545903264-9223372022085550062," +
+ "foo=-9223372011625196858-9223371980244137250," +
+ "foo=-9223371980244137249-9223371132955527807," +
+ "foo=-9223368591089699477-9223366049223871149," +
+ "foo=-9223371132955527806-9223368591089699478," +
+ "foo=-9223358423626386161-9223350798028901175," +
+ "foo=-9223366049223871148-9223358423626386162," +
+ "foo=-9223327921236446213-9223305044443991253," +
+ "foo=-9223350798028901174-9223327921236446214," +
+ "foo=-9223305044443991252-9223099153311896604," +
+ "foo=-9223099153311896603-9222481479915612657," +
+ "foo=-9222481479915612656-9205804298215946088," +
+ "foo=-9205804298215946087-9155772753116946381," +
+ "foo=-9155772753116946380-9005678117819947260," +
+ "foo=-8555394211928949896-8105110306037952534," +
+ "foo=-9005678117819947259-8555394211928949897," +
+ "foo=-4052555153018976266-0," +
+ "foo=-8105110306037952533-4052555153018976267)]", 3);
+ }
+
+ @Test
+ public void requireThatHighAritiesWork() {
+ testConvert("foo in [10..39]", "foo in [10..39 (foo=0+[10..39])]", 1000);
+ testConvert("foo in [9000..11000]", "foo in [9000..11000 (foo=0+[9000..],foo=10000+[..1000])]", 10000);
+ testConvert("foo in [10..39]", "foo in [10..39 (foo=0+[10..39])]", 16384);
+ testConvert("foo in [10..32768]", "foo in [10..32768 (foo=0+[10..],foo=32768+[..0],foo=16384-32767)]", 16384);
+
+ testConvert("foo in [9223372036854775807..9223372036854775807]", "foo in [9223372036854775807..9223372036854775807 (foo=9223372036854759424+[16383..])]", 16384);
+ testConvert("foo in [-9223372036854775808..-9223372036854775808]", "foo in [-9223372036854775808..-9223372036854775808 (foo=-9223372036854775808+[..0])]", 16384);
+ }
+
+ @Test
+ public void requireThatOpenRangesWork() {
+ testConvert("foo in [-7..]", "foo in [-7.. (foo=-7-0,foo=0-9223372036854775807)]", 2);
+ testConvert("foo in [..7]", "foo in [..7 (foo=-9223372036854775808+[..0],foo=-9223372036854775807-0,foo=0-7)]", 2);
+ }
+
+ @Test
+ public void requireThatUpperAndLowerBoundsWork() {
+ lowerBound = -999;
+ upperBound = 999;
+ testConvert("foo in [-9..]", "foo in [-9.. (foo=-9-0,foo=0-999)]", 10);
+ testConvert("foo in [..9]", "foo in [..9 (foo=-999-0,foo=0-9)]", 10);
+ testConvert("foo in [..]", "foo in [.. (foo=-999-0,foo=0-999)]", 10);
+ }
+
+ @Test
+ public void requireThatUpperAndLowerBoundsPruneClosedRanges() {
+ lowerBound = -999;
+ upperBound = 999;
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-999)]", 10);
+ lowerBound = 888;
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-999)]", 10);
+ lowerBound = 900;
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-999)]", 10);
+ }
+
+ @Test
+ public void requireThatRangesOutsideBoundsAreSimplifiedToOneImpossibleRange() {
+ lowerBound = 900;
+ upperBound = 999;
+ testConvert("foo in [0..100]", "foo in [0..100 (foo=-9223372036854775799-9223372036854775790)]", 10);
+ testConvert("foo in [1000..1100]", "foo in [1000..1100 (foo=9223372036854775790-9223372036854775799)]", 10);
+ lowerBound = -999;
+ upperBound = -900;
+ testConvert("foo in [-2000..-1000]", "foo in [-2000..-1000 (foo=-9223372036854775799-9223372036854775790)]", 10);
+ testConvert("foo in [0..100]", "foo in [0..100 (foo=9223372036854775790-9223372036854775799)]", 10);
+ lowerBound = -9223372036854775790L;
+ upperBound = 9223372036854775790L;
+ testConvert("foo in [9223372036854775791..9223372036854775792]", "foo in [9223372036854775791..9223372036854775792 (foo=9223372036854775790+[1..1])]", 10);
+ testConvert("foo in [-9223372036854775792..-9223372036854775791]", "foo in [-9223372036854775792..-9223372036854775791 (foo=-9223372036854775790+[1..1])]", 10);
+ }
+
+ @Test
+ public void requireThatUpperAndLowerBoundsAreAdjustedWithArity() {
+ lowerBound = -999;
+ upperBound = 999;
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-999)]", 10);
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-1023)]", 2);
+ testConvert("foo in [-10000..10000]", "foo in [-10000..10000 (foo=-999-0,foo=0-999)]", 10);
+ testConvert("foo in [-10000..10000]", "foo in [-10000..10000 (foo=-1023-0,foo=0-1023)]", 2);
+
+ upperBound = 1000;
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-9999)]", 10);
+
+ lowerBound = 100;
+ upperBound = 999;
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-999)]", 10);
+ testConvert("foo in [0..10000]", "foo in [0..10000 (foo=0-1023)]", 2);
+
+ lowerBound = -999;
+ upperBound = -100;
+ testConvert("foo in [-10000..10000]", "foo in [-10000..10000 (foo=-999-0)]", 10);
+ testConvert("foo in [-10000..10000]", "foo in [-10000..10000 (foo=-1023-0)]", 2);
+
+ lowerBound = -9223372036854775790L;
+ upperBound = 9223372036854775790L;
+ testConvert("foo in [-9223372036854775791..9223372036854775792]",
+ "foo in [-9223372036854775791..9223372036854775792 (" +
+ "foo=-9223372036854775790+[..0],foo=9223372036854775790+[..0]," +
+ "foo=-9223372036854775709-9223372036854775700," +
+ "foo=-9223372036854775719-9223372036854775710," +
+ "foo=-9223372036854775729-9223372036854775720," +
+ "foo=-9223372036854775739-9223372036854775730," +
+ "foo=-9223372036854775749-9223372036854775740," +
+ "foo=-9223372036854775759-9223372036854775750," +
+ "foo=-9223372036854775769-9223372036854775760," +
+ "foo=-9223372036854775779-9223372036854775770," +
+ "foo=-9223372036854775789-9223372036854775780," +
+ "foo=-9223372036854775099-9223372036854775000," +
+ "foo=-9223372036854775199-9223372036854775100," +
+ "foo=-9223372036854775299-9223372036854775200," +
+ "foo=-9223372036854775399-9223372036854775300," +
+ "foo=-9223372036854775499-9223372036854775400," +
+ "foo=-9223372036854775599-9223372036854775500," +
+ "foo=-9223372036854775699-9223372036854775600," +
+ "foo=-9223372036854770999-9223372036854770000," +
+ "foo=-9223372036854771999-9223372036854771000," +
+ "foo=-9223372036854772999-9223372036854772000," +
+ "foo=-9223372036854773999-9223372036854773000," +
+ "foo=-9223372036854774999-9223372036854774000," +
+ "foo=-9223372036854709999-9223372036854700000," +
+ "foo=-9223372036854719999-9223372036854710000," +
+ "foo=-9223372036854729999-9223372036854720000," +
+ "foo=-9223372036854739999-9223372036854730000," +
+ "foo=-9223372036854749999-9223372036854740000," +
+ "foo=-9223372036854759999-9223372036854750000," +
+ "foo=-9223372036854769999-9223372036854760000," +
+ "foo=-9223372036854099999-9223372036854000000," +
+ "foo=-9223372036854199999-9223372036854100000," +
+ "foo=-9223372036854299999-9223372036854200000," +
+ "foo=-9223372036854399999-9223372036854300000," +
+ "foo=-9223372036854499999-9223372036854400000," +
+ "foo=-9223372036854599999-9223372036854500000," +
+ "foo=-9223372036854699999-9223372036854600000," +
+ "foo=-9223372036850999999-9223372036850000000," +
+ "foo=-9223372036851999999-9223372036851000000," +
+ "foo=-9223372036852999999-9223372036852000000," +
+ "foo=-9223372036853999999-9223372036853000000," +
+ "foo=-9223372036809999999-9223372036800000000," +
+ "foo=-9223372036819999999-9223372036810000000," +
+ "foo=-9223372036829999999-9223372036820000000," +
+ "foo=-9223372036839999999-9223372036830000000," +
+ "foo=-9223372036849999999-9223372036840000000," +
+ "foo=-9223372036099999999-9223372036000000000," +
+ "foo=-9223372036199999999-9223372036100000000," +
+ "foo=-9223372036299999999-9223372036200000000," +
+ "foo=-9223372036399999999-9223372036300000000," +
+ "foo=-9223372036499999999-9223372036400000000," +
+ "foo=-9223372036599999999-9223372036500000000," +
+ "foo=-9223372036699999999-9223372036600000000," +
+ "foo=-9223372036799999999-9223372036700000000," +
+ "foo=-9223372030999999999-9223372030000000000," +
+ "foo=-9223372031999999999-9223372031000000000," +
+ "foo=-9223372032999999999-9223372032000000000," +
+ "foo=-9223372033999999999-9223372033000000000," +
+ "foo=-9223372034999999999-9223372034000000000," +
+ "foo=-9223372035999999999-9223372035000000000," +
+ "foo=-9223372009999999999-9223372000000000000," +
+ "foo=-9223372019999999999-9223372010000000000," +
+ "foo=-9223372029999999999-9223372020000000000," +
+ "foo=-9223370999999999999-9223370000000000000," +
+ "foo=-9223371999999999999-9223371000000000000," +
+ "foo=-9223309999999999999-9223300000000000000," +
+ "foo=-9223319999999999999-9223310000000000000," +
+ "foo=-9223329999999999999-9223320000000000000," +
+ "foo=-9223339999999999999-9223330000000000000," +
+ "foo=-9223349999999999999-9223340000000000000," +
+ "foo=-9223359999999999999-9223350000000000000," +
+ "foo=-9223369999999999999-9223360000000000000," +
+ "foo=-9223099999999999999-9223000000000000000," +
+ "foo=-9223199999999999999-9223100000000000000," +
+ "foo=-9223299999999999999-9223200000000000000," +
+ "foo=-9220999999999999999-9220000000000000000," +
+ "foo=-9221999999999999999-9221000000000000000," +
+ "foo=-9222999999999999999-9222000000000000000," +
+ "foo=-9209999999999999999-9200000000000000000," +
+ "foo=-9219999999999999999-9210000000000000000," +
+ "foo=-9099999999999999999-9000000000000000000," +
+ "foo=-9199999999999999999-9100000000000000000," +
+ "foo=-999999999999999999-0," +
+ "foo=-1999999999999999999-1000000000000000000," +
+ "foo=-2999999999999999999-2000000000000000000," +
+ "foo=-3999999999999999999-3000000000000000000," +
+ "foo=-4999999999999999999-4000000000000000000," +
+ "foo=-5999999999999999999-5000000000000000000," +
+ "foo=-6999999999999999999-6000000000000000000," +
+ "foo=-7999999999999999999-7000000000000000000," +
+ "foo=-8999999999999999999-8000000000000000000," +
+ "foo=9223372036854775700-9223372036854775709," +
+ "foo=9223372036854775710-9223372036854775719," +
+ "foo=9223372036854775720-9223372036854775729," +
+ "foo=9223372036854775730-9223372036854775739," +
+ "foo=9223372036854775740-9223372036854775749," +
+ "foo=9223372036854775750-9223372036854775759," +
+ "foo=9223372036854775760-9223372036854775769," +
+ "foo=9223372036854775770-9223372036854775779," +
+ "foo=9223372036854775780-9223372036854775789," +
+ "foo=9223372036854775000-9223372036854775099," +
+ "foo=9223372036854775100-9223372036854775199," +
+ "foo=9223372036854775200-9223372036854775299," +
+ "foo=9223372036854775300-9223372036854775399," +
+ "foo=9223372036854775400-9223372036854775499," +
+ "foo=9223372036854775500-9223372036854775599," +
+ "foo=9223372036854775600-9223372036854775699," +
+ "foo=9223372036854770000-9223372036854770999," +
+ "foo=9223372036854771000-9223372036854771999," +
+ "foo=9223372036854772000-9223372036854772999," +
+ "foo=9223372036854773000-9223372036854773999," +
+ "foo=9223372036854774000-9223372036854774999," +
+ "foo=9223372036854700000-9223372036854709999," +
+ "foo=9223372036854710000-9223372036854719999," +
+ "foo=9223372036854720000-9223372036854729999," +
+ "foo=9223372036854730000-9223372036854739999," +
+ "foo=9223372036854740000-9223372036854749999," +
+ "foo=9223372036854750000-9223372036854759999," +
+ "foo=9223372036854760000-9223372036854769999," +
+ "foo=9223372036854000000-9223372036854099999," +
+ "foo=9223372036854100000-9223372036854199999," +
+ "foo=9223372036854200000-9223372036854299999," +
+ "foo=9223372036854300000-9223372036854399999," +
+ "foo=9223372036854400000-9223372036854499999," +
+ "foo=9223372036854500000-9223372036854599999," +
+ "foo=9223372036854600000-9223372036854699999," +
+ "foo=9223372036850000000-9223372036850999999," +
+ "foo=9223372036851000000-9223372036851999999," +
+ "foo=9223372036852000000-9223372036852999999," +
+ "foo=9223372036853000000-9223372036853999999," +
+ "foo=9223372036800000000-9223372036809999999," +
+ "foo=9223372036810000000-9223372036819999999," +
+ "foo=9223372036820000000-9223372036829999999," +
+ "foo=9223372036830000000-9223372036839999999," +
+ "foo=9223372036840000000-9223372036849999999," +
+ "foo=9223372036000000000-9223372036099999999," +
+ "foo=9223372036100000000-9223372036199999999," +
+ "foo=9223372036200000000-9223372036299999999," +
+ "foo=9223372036300000000-9223372036399999999," +
+ "foo=9223372036400000000-9223372036499999999," +
+ "foo=9223372036500000000-9223372036599999999," +
+ "foo=9223372036600000000-9223372036699999999," +
+ "foo=9223372036700000000-9223372036799999999," +
+ "foo=9223372030000000000-9223372030999999999," +
+ "foo=9223372031000000000-9223372031999999999," +
+ "foo=9223372032000000000-9223372032999999999," +
+ "foo=9223372033000000000-9223372033999999999," +
+ "foo=9223372034000000000-9223372034999999999," +
+ "foo=9223372035000000000-9223372035999999999," +
+ "foo=9223372000000000000-9223372009999999999," +
+ "foo=9223372010000000000-9223372019999999999," +
+ "foo=9223372020000000000-9223372029999999999," +
+ "foo=9223370000000000000-9223370999999999999," +
+ "foo=9223371000000000000-9223371999999999999," +
+ "foo=9223300000000000000-9223309999999999999," +
+ "foo=9223310000000000000-9223319999999999999," +
+ "foo=9223320000000000000-9223329999999999999," +
+ "foo=9223330000000000000-9223339999999999999," +
+ "foo=9223340000000000000-9223349999999999999," +
+ "foo=9223350000000000000-9223359999999999999," +
+ "foo=9223360000000000000-9223369999999999999," +
+ "foo=9223000000000000000-9223099999999999999," +
+ "foo=9223100000000000000-9223199999999999999," +
+ "foo=9223200000000000000-9223299999999999999," +
+ "foo=9220000000000000000-9220999999999999999," +
+ "foo=9221000000000000000-9221999999999999999," +
+ "foo=9222000000000000000-9222999999999999999," +
+ "foo=9200000000000000000-9209999999999999999," +
+ "foo=9210000000000000000-9219999999999999999," +
+ "foo=9000000000000000000-9099999999999999999," +
+ "foo=9100000000000000000-9199999999999999999," +
+ "foo=0-999999999999999999," +
+ "foo=1000000000000000000-1999999999999999999," +
+ "foo=2000000000000000000-2999999999999999999," +
+ "foo=3000000000000000000-3999999999999999999," +
+ "foo=4000000000000000000-4999999999999999999," +
+ "foo=5000000000000000000-5999999999999999999," +
+ "foo=6000000000000000000-6999999999999999999," +
+ "foo=7000000000000000000-7999999999999999999," +
+ "foo=8000000000000000000-8999999999999999999)]");
+
+ lowerBound = -922337203685477579L;
+ upperBound = 922337203685477579L;
+ testConvert("foo in [-9223372036854775791..9223372036854775792]",
+ "foo in [-9223372036854775791..9223372036854775792 (foo=-999999999999999999-0,foo=0-999999999999999999)]");
+ }
+
+ @Test
+ public void requireThatExistingPartitionsAreCleared() {
+ testConvert("foo in [10..19]", "foo in [10..19 (foo=10-19)]");
+ Predicate p = Predicate.fromString("foo in [10..19]");
+ ((FeatureRange)p).addPartition(new RangePartition("foo", 10000L, 20000L, false));
+ ComplexNodeTransformer tranformer = new ComplexNodeTransformer();
+ Predicate converted = tranformer.process(p, new PredicateOptions(10, lowerBound, upperBound));
+ assertEquals("foo in [10..19 (foo=10-19)]", converted.toString());
+
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/NotNodeReordererTest.java b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/NotNodeReordererTest.java
new file mode 100644
index 00000000000..de61c3e04c6
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/NotNodeReordererTest.java
@@ -0,0 +1,55 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.predicate.optimization;
+
+import com.yahoo.document.predicate.Predicate;
+import org.junit.Test;
+
+import static com.yahoo.document.predicate.Predicates.and;
+import static com.yahoo.document.predicate.Predicates.feature;
+import static com.yahoo.document.predicate.Predicates.or;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ */
+public class NotNodeReordererTest {
+ @Test
+ public void requireThatNotChildrenAreMovedAwayFromLastAndChild() {
+ checkReorder(
+ and(feature("a").inSet("b"), feature("c").notInSet("d")),
+ and(feature("c").notInSet("d"), feature("a").inSet("b")));
+
+ checkReorder(
+ and(feature("a").inSet("b"), feature("c").notInSet("d"), feature("e").notInSet("f")),
+ and(feature("c").notInSet("d"), feature("e").notInSet("f"), feature("a").inSet("b")));
+ }
+
+ @Test
+ public void requireThatNotChildrenAreMovedToLastOrChild() {
+ checkReorder(
+ or(feature("c").notInSet("d"), feature("a").inSet("b")),
+ or(feature("a").inSet("b"), feature("c").notInSet("d")));
+
+ checkReorder(
+ or(feature("c").notInSet("d"), feature("e").notInSet("f"), feature("a").inSet("b")),
+ or(feature("a").inSet("b"), feature("c").notInSet("d"), feature("e").notInSet("f")));
+ }
+
+ @Test
+ public void requireThatComplexReorderingWork() {
+ checkReorder(and(feature("g").inSet("h"),
+ or(and(feature("a").notInSet("b"),
+ feature("c").notInSet("d")),
+ feature("e").inSet("f"))),
+ and(or(feature("e").inSet("f"),
+ and(feature("a").notInSet("b"),
+ feature("c").notInSet("d"))),
+ feature("g").inSet("h")));
+ }
+
+ private static void checkReorder(Predicate input, Predicate expected) {
+ NotNodeReorderer reorderer = new NotNodeReorderer();
+ Predicate actual = reorderer.process(input, new PredicateOptions(10));
+ assertEquals(expected, actual);
+ }
+}
diff --git a/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/OrSimplifierTest.java b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/OrSimplifierTest.java
new file mode 100644
index 00000000000..6db02c5be57
--- /dev/null
+++ b/predicate-search-core/src/test/java/com/yahoo/search/predicate/optimization/OrSimplifierTest.java
@@ -0,0 +1,98 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.predicate.optimization;
+
+import com.yahoo.document.predicate.Predicate;
+import org.junit.Test;
+
+import static com.yahoo.document.predicate.Predicates.and;
+import static com.yahoo.document.predicate.Predicates.feature;
+import static com.yahoo.document.predicate.Predicates.not;
+import static com.yahoo.document.predicate.Predicates.or;
+import static org.junit.Assert.assertEquals;
+
+public class OrSimplifierTest {
+
+ @Test
+ public void require_that_or_with_feature_sets_of_same_key_is_simplified_to_single_feature_set() {
+ Predicate p =
+ or(
+ feature("key1").inSet("value1", "value4"),
+ feature("key1").inSet("value2", "value3"),
+ feature("key1").inSet("value1", "value4"));
+ Predicate expected = feature("key1").inSet("value1", "value2", "value3", "value4");
+ assertConvertedPredicateEquals(expected, p);
+ }
+
+ @Test
+ public void require_that_or_with_feature_sets_of_different_keys_is_simplified() {
+ Predicate p =
+ or(
+ feature("key1").inSet("value1", "value3"),
+ feature("key1").inSet("value2"),
+ feature("key2").inSet("value1"),
+ feature("key2").inSet("value2", "value3"));
+ Predicate expected =
+ or(
+ feature("key1").inSet("value1", "value2", "value3"),
+ feature("key2").inSet("value1", "value2", "value3"));
+ assertConvertedPredicateEquals(expected, p);
+ }
+
+ @Test
+ public void require_that_conversion_is_recursive_and_cascades() {
+ Predicate p =
+ or(
+ feature("key1").inSet("value1", "value4"),
+ feature("key1").inSet("value2", "value3"),
+ or(
+ feature("key1").inSet("value1"),
+ feature("key1").inSet("value4")));
+ Predicate expected = feature("key1").inSet("value1", "value2", "value3", "value4");
+ assertConvertedPredicateEquals(expected, p);
+ }
+
+ @Test
+ public void require_that_or_below_and_is_converted() {
+ Predicate p =
+ and(
+ or(
+ feature("key1").inSet("value1"),
+ feature("key1").inSet("value2")),
+ feature("key2").inSet("value2"));
+ Predicate expected =
+ and(
+ feature("key1").inSet("value1", "value2"),
+ feature("key2").inSet("value2"));
+ assertConvertedPredicateEquals(expected, p);
+ }
+
+ @Test
+ public void require_that_or_below_not_is_converted() {
+ Predicate p =
+ not(
+ or(
+ feature("key1").inSet("value1"),
+ feature("key1").inSet("value2")));
+ Predicate expected = not(feature("key1").inSet("value1", "value2"));
+ assertConvertedPredicateEquals(expected, p);
+ }
+
+ @Test
+ public void require_that_non_feature_set_nodes_are_left_untouched() {
+ Predicate p =
+ or(
+ feature("key1").inSet("value1"),
+ feature("key1").inSet("value2"),
+ not(feature("key1").inSet("value3")));
+ Predicate expected =
+ or(
+ not(feature("key1").inSet("value3")),
+ feature("key1").inSet("value1", "value2"));
+ assertConvertedPredicateEquals(expected, p);
+ }
+
+ private static void assertConvertedPredicateEquals(Predicate expected, Predicate predicate) {
+ OrSimplifier simplifier = new OrSimplifier();
+ assertEquals(expected, simplifier.simplifyTree(predicate));
+ }
+}