diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2022-03-23 15:33:04 +0100 |
---|---|---|
committer | jonmv <venstad@gmail.com> | 2022-10-26 12:07:17 +0200 |
commit | d92c5a98abe7f05efed896a93d47695ea76215f3 (patch) | |
tree | 938ca88a4d559a8da5f9dee57b54dce3ef0bd2b5 /container-search | |
parent | 2e727510f09094faf433172f060b4f4d0f6a4cb2 (diff) |
Add test that fails now
Diffstat (limited to 'container-search')
-rw-r--r-- | container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java | 25 | ||||
-rw-r--r-- | container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java | 256 |
2 files changed, 278 insertions, 3 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java b/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java index fb77f010df2..24d4623b2b8 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/MultiRangeItem.java @@ -46,6 +46,8 @@ import static java.util.Objects.requireNonNull; * Adding ranges in ascending order is much faster than not; ascending order here has the rather lax * requirement that each added interval is not completely before the current last interval. * + * todo: cover all three cases of single index + ranges, dual index + ranges, dual index + points + * * @author jonmv */ public class MultiRangeItem extends MultiTermItem { @@ -80,9 +82,17 @@ public class MultiRangeItem extends MultiTermItem { return Objects.hash(start, end); } + @Override + public String toString() { + return "(" + start + ", " + end + ")"; + } + } - private static final Comparator<Number> comparator = comparingDouble(Number::doubleValue); + static final Comparator<Number> comparator = (a, b) -> { + double u = a.doubleValue(), v = b.doubleValue(); + return u < v ? -1 : u > v ? 1 : 0; + }; private final String startIndex; private final String endIndex; @@ -113,8 +123,17 @@ public class MultiRangeItem extends MultiTermItem { return overRanges(index, startInclusive, index, endInclusive); } + /** Adds the given point to this item. More efficient when each added point is not completely before the current last one. */ + public MultiRangeItem addPoint(Number point) { + return addRange(point, point); + } + /** Adds the given range to this item. More efficient when each added range is not completely before the current last one. */ - public MultiRangeItem add(Number start, Number end) { + public MultiRangeItem addRange(Number start, Number end) { + if (Double.isNaN(start.doubleValue())) + throw new IllegalArgumentException("range start cannot be NaN"); + if (Double.isNaN(end.doubleValue())) + throw new IllegalArgumentException("range end cannot be NaN"); if (comparator.compare(start, end) > 0) throw new IllegalArgumentException("ranges must satisfy start <= end, but got " + start + " > " + end); @@ -154,7 +173,7 @@ public class MultiRangeItem extends MultiTermItem { return comparator.compare(a, b) >= 0 ? a : b; } - private List<Range> sortedRanges() { + List<Range> sortedRanges() { if (sorted) return ranges; diff --git a/container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java b/container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java new file mode 100644 index 00000000000..b6227c9969d --- /dev/null +++ b/container-search/src/test/java/com/yahoo/prelude/query/MultiRangeItemTestCase.java @@ -0,0 +1,256 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.prelude.query; + +import com.yahoo.prelude.query.MultiRangeItem.Range; +import org.junit.Test; + +import java.nio.ByteBuffer; +import java.util.List; + +import static com.yahoo.prelude.query.MultiRangeItem.Limit.EXCLUSIVE; +import static com.yahoo.prelude.query.MultiRangeItem.Limit.INCLUSIVE; +import static java.lang.Double.NEGATIVE_INFINITY; +import static java.lang.Double.NaN; +import static java.lang.Double.POSITIVE_INFINITY; +import static java.util.Comparator.comparingDouble; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author jonmv + */ +public class MultiRangeItemTestCase { + + // We'll add ranges (0, 0), (0, 2), (2, 2), (3, 4), (5, 8), (6, 6), (7, 9), (9, 9), (1, 8), in that order, and in "random" order. + final List<Range> ranges = List.of(new Range(1, 8), // Make it "unordered", so sorting is delayed. + new Range(0, 0), + new Range(0, 2), + new Range(2, 2), + new Range(3, 4), + new Range(5, 8), + new Range(6, 6), + new Range(9, 9), + new Range(7, 9)); + + @Test + public void testNanIsDisallowed() { + try { + MultiRangeItem.overPoints("i", INCLUSIVE, EXCLUSIVE).addPoint(NaN); + fail("NaN should be disallowed"); + } + catch (IllegalArgumentException e) { + assertEquals("range start cannot be NaN", e.getMessage()); + } + } + + @Test + public void testSpecialValuesWithClosedIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE); + item.addPoint(0.0); + item.addPoint(-0.0); + assertEquals(List.of(new Range(0.0, 0.0)), + item.sortedRanges()); + + item.addRange(NEGATIVE_INFINITY, 0); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)), + item.sortedRanges()); + + item.addRange(0, POSITIVE_INFINITY); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)), + item.sortedRanges()); + + try { + item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY); + fail("negative ranges should be disallowed"); + } + catch (IllegalArgumentException e) { + assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage()); + } + } + + @Test + public void testSpecialValuesWithClosedOpenIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, EXCLUSIVE); + item.addPoint( 0.0); + item.addPoint(-0.0); + assertEquals(List.of(new Range(0.0, 0.0)), + item.sortedRanges()); + + item.addRange(NEGATIVE_INFINITY, 0); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)), + item.sortedRanges()); + + item.addRange(0, POSITIVE_INFINITY); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)), + item.sortedRanges()); + + try { + item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY); + fail("negative ranges should be disallowed"); + } + catch (IllegalArgumentException e) { + assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage()); + } + } + + @Test + public void testSpecialValuesWithOpenClosedIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, INCLUSIVE); + item.addPoint( 0.0); + item.addPoint(-0.0); + assertEquals(List.of(new Range(0.0, 0.0)), + item.sortedRanges()); + + item.addRange(NEGATIVE_INFINITY, 0); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)), + item.sortedRanges()); + + item.addRange(0, POSITIVE_INFINITY); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)), + item.sortedRanges()); + + try { + item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY); + fail("negative ranges should be disallowed"); + } + catch (IllegalArgumentException e) { + assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage()); + } + } + + @Test + public void testSpecialValuesWithOpenIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE); + item.addPoint( 0.0); + item.addPoint(-0.0); + assertEquals(List.of(new Range(0.0, 0.0)), + item.sortedRanges()); + + item.addRange(NEGATIVE_INFINITY, 0); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, 0.0)), + item.sortedRanges()); + + item.addRange(0, POSITIVE_INFINITY); + assertEquals(List.of(new Range(NEGATIVE_INFINITY, POSITIVE_INFINITY)), + item.sortedRanges()); + + try { + item.addRange(POSITIVE_INFINITY, NEGATIVE_INFINITY); + fail("negative ranges should be disallowed"); + } + catch (IllegalArgumentException e) { + assertEquals("ranges must satisfy start <= end, but got Infinity > -Infinity", e.getMessage()); + } + } + + @Test + public void testAddingRangesOrderedByStartWithClosedIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE); + ranges.stream().sorted(comparingDouble(range -> range.start.doubleValue())) + .forEach(range -> item.addRange(range.start, range.end)); + + assertEquals(List.of(new Range(0, 9)), + item.sortedRanges()); + } + + @Test + public void testAddingRangesOrderedByStartWithOpenIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE); + ranges.stream().sorted(comparingDouble(range -> range.start.doubleValue())) + .forEach(range -> item.addRange(range.start, range.end)); + + assertEquals(List.of(new Range(0, 9)), + item.sortedRanges()); + } + + @Test + public void testAddingRangesOrderedByEndWithClosedIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE); + ranges.stream().sorted(comparingDouble(range -> range.end.doubleValue())) + .forEach(range -> item.addRange(range.start, range.end)); + + assertEquals(List.of(new Range(0, 9)), + item.sortedRanges()); + } + + @Test + public void testAddingRangesOrderedByEndWithOpenIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE); + ranges.stream().sorted(comparingDouble(range -> range.end.doubleValue())) + .forEach(range -> item.addRange(range.start, range.end)); + + assertEquals(List.of(new Range(0, 9)), + item.sortedRanges()); + } + + @Test + public void testAddingRangesUnorderedWithClosedIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", INCLUSIVE, INCLUSIVE); + for (Range range : ranges) + item.addRange(range.start, range.end); + + assertEquals(List.of(new Range(0, 9)), + item.sortedRanges()); + } + + @Test + public void testAddingRangesUnorderedWithOpenIntervals() { + MultiRangeItem item = MultiRangeItem.overPoints("i", EXCLUSIVE, EXCLUSIVE); + for (Range range : ranges) + item.addRange(range.start, range.end); + + assertEquals(List.of(new Range(0, 9)), + item.sortedRanges()); + } + + @Test + public void testSerialization() { + ByteBuffer pointsBuffer = ByteBuffer.allocate(25); + MultiRangeItem pointsItem = MultiRangeItem.overPoints("i", EXCLUSIVE, INCLUSIVE) + .addRange(NEGATIVE_INFINITY, POSITIVE_INFINITY); + pointsItem.encode(pointsBuffer); + + ByteBuffer expected = ByteBuffer.allocate(25); + expected.put((byte) 0b00000111); // ItemType.MULTI_TERM + expected.put((byte) 0b00100000); // OR << 5, RANGES + expected.putInt(1); // term count + expected.put((byte) 0b00000101); // end inclusive, same index + expected.put((byte) 1); // index name length + expected.put((byte) 'i'); // index name bytes + expected.putDouble(NEGATIVE_INFINITY); + expected.putDouble(POSITIVE_INFINITY); + + pointsBuffer.flip(); + expected.flip(); + assertEquals(expected, pointsBuffer); + + ByteBuffer rangesBuffer = ByteBuffer.allocate(59); + MultiRangeItem rangesItem = MultiRangeItem.overRanges("i", INCLUSIVE, "j", EXCLUSIVE) + .addPoint( -0.0) + .addRange( 1, 2.0) + .addRange(-1, -0.5); + rangesItem.encode(rangesBuffer); + + expected = ByteBuffer.allocate(59); + expected.put((byte) 0b00000111); // ItemType.MULTI_TERM + expected.put((byte) 0b00100000); // OR << 5, RANGES + expected.putInt(3); // term count + expected.put((byte) 0b00000010); // end inclusive, same index + expected.put((byte) 1); // index name length + expected.put((byte) 'i'); // index name bytes + expected.put((byte) 1); // index name length + expected.put((byte) 'j'); // index name bytes + expected.putDouble(-1.0); + expected.putDouble(-0.5); + expected.putDouble(-0.0); + expected.putDouble(-0.0); + expected.putDouble( 1.0); + expected.putDouble( 2.0); + + rangesBuffer.flip(); + expected.flip(); + assertEquals(expected, rangesBuffer); + } + +} |