diff options
Diffstat (limited to 'predicate-search-core/src/test/java/com/yahoo/document')
16 files changed, 1542 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()); + } +} |