summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/test/java/com/amazon/carbonado/cursor/EmptyCursorFactory.java30
-rw-r--r--src/test/java/com/amazon/carbonado/cursor/TestCursors.java389
-rw-r--r--src/test/java/com/amazon/carbonado/cursor/TestGroupedCursor.java184
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java57
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java746
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java725
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java517
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java108
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java195
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java84
-rw-r--r--src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java75
-rw-r--r--src/test/java/com/amazon/carbonado/spi/TestConversionComparator.java179
-rw-r--r--src/test/java/com/amazon/carbonado/spi/TestCursorList.java224
-rw-r--r--src/test/java/com/amazon/carbonado/spi/TestTriggerManager.java334
-rw-r--r--src/test/java/com/amazon/carbonado/stored/Address.java64
-rw-r--r--src/test/java/com/amazon/carbonado/stored/Dummy.java145
-rw-r--r--src/test/java/com/amazon/carbonado/stored/StorableTestBasic.java114
-rw-r--r--src/test/java/com/amazon/carbonado/stored/StorableTestMinimal.java32
-rw-r--r--src/test/java/com/amazon/carbonado/util/TestBelatedCreator.java244
-rw-r--r--src/test/java/com/amazon/carbonado/util/TestQuickConstructorGenerator.java102
-rw-r--r--src/test/java/com/amazon/carbonado/util/TestThrowUnchecked.java54
21 files changed, 4602 insertions, 0 deletions
diff --git a/src/test/java/com/amazon/carbonado/cursor/EmptyCursorFactory.java b/src/test/java/com/amazon/carbonado/cursor/EmptyCursorFactory.java
new file mode 100644
index 0000000..fa27350
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/cursor/EmptyCursorFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.cursor;
+
+/**
+ * Creates new EmptyCursor instances, for tests in other packages.
+ *
+ * @author Brian S O'Neill
+ */
+public class EmptyCursorFactory {
+ public static EmptyCursor newEmptyCursor() {
+ return new EmptyCursor();
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/cursor/TestCursors.java b/src/test/java/com/amazon/carbonado/cursor/TestCursors.java
new file mode 100644
index 0000000..f063a59
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/cursor/TestCursors.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.cursor;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Cursor;
+import com.amazon.carbonado.FetchException;
+
+import com.amazon.carbonado.stored.Dummy;
+import com.amazon.carbonado.stored.StorableTestMinimal;
+
+/**
+ *
+ * @author Brian S O'Neill
+ */
+public class TestCursors extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestCursors.class);
+ }
+
+ public TestCursors(String name) {
+ super(name);
+ }
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void testUnion() throws Exception {
+ Cursor<Element> left, right, union;
+
+ // Two empty sets.
+ left = createElements();
+ right = createElements();
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union);
+
+ // Right set empty.
+ left = createElements(1, 2, 3, 4);
+ right = createElements();
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 2, 3, 4);
+
+ // Left set empty.
+ left = createElements();
+ right = createElements(3, 4, 5, 6);
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 3, 4, 5, 6);
+
+ // No overlap.
+ left = createElements(1, 2, 3 );
+ right = createElements( 4, 5, 6);
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 2, 3, 4, 5, 6);
+
+ // Overlap.
+ left = createElements(1, 2, 3, 4 );
+ right = createElements( 3, 4, 5, 6);
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 2, 3, 4, 5, 6);
+
+ // Swapped overlap.
+ left = createElements( 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4 );
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 2, 3, 4, 5, 6);
+
+ // Equivalent.
+ left = createElements(1, 2, 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4, 5, 6);
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 2, 3, 4, 5, 6);
+
+ // Complex.
+ left = createElements(1, 2, 3, 5, 6, 7, 11, 12, 13, 17, 18, 19);
+ right = createElements(1, 2, 4, 5, 6, 9, 10, 13, 14, 17, 18 );
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 17, 18, 19);
+
+ // Dups.
+ left = createElements(1, 2, 2, 3, 3, 3, 3 );
+ right = createElements(1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4);
+ union = new UnionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(union, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4);
+ }
+
+ public void testIntersection() throws Exception {
+ Cursor<Element> left, right, inter;
+
+ // Two empty sets.
+ left = createElements();
+ right = createElements();
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter);
+
+ // Right set empty.
+ left = createElements(1, 2, 3, 4);
+ right = createElements();
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter);
+
+ // Left set empty.
+ left = createElements();
+ right = createElements(3, 4, 5, 6);
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter);
+
+ // No overlap.
+ left = createElements(1, 2, 3 );
+ right = createElements( 4, 5, 6);
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter);
+
+ // Overlap.
+ left = createElements(1, 2, 3, 4 );
+ right = createElements( 3, 4, 5, 6);
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter, 3, 4);
+
+ // Swapped overlap.
+ left = createElements( 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4 );
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter, 3, 4);
+
+ // Equivalent.
+ left = createElements(1, 2, 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4, 5, 6);
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter, 1, 2, 3, 4, 5, 6);
+
+ // Complex.
+ left = createElements(1, 2, 3, 5, 6, 7, 11, 12, 13, 17, 18, 19);
+ right = createElements(1, 2, 4, 5, 6, 9, 10, 13, 14, 17, 18 );
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter, 1, 2, 5, 6, 13, 17, 18);
+
+ // Dups.
+ left = createElements(1, 2, 2, 3, 3, 3, 3 );
+ right = createElements(1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4);
+ inter = new IntersectionCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(inter, 1, 2, 2);
+ }
+
+ public void testDifference() throws Exception {
+ Cursor<Element> left, right, diff;
+
+ // Two empty sets.
+ left = createElements();
+ right = createElements();
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff);
+
+ // Right set empty.
+ left = createElements(1, 2, 3, 4);
+ right = createElements();
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2, 3, 4);
+
+ // Left set empty.
+ left = createElements();
+ right = createElements(3, 4, 5, 6);
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff);
+
+ // No overlap.
+ left = createElements(1, 2, 3 );
+ right = createElements( 4, 5, 6);
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2, 3);
+
+ // Overlap.
+ left = createElements(1, 2, 3, 4 );
+ right = createElements( 3, 4, 5, 6);
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2);
+
+ // Swapped overlap.
+ left = createElements( 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4 );
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 5, 6);
+
+ // Equivalent.
+ left = createElements(1, 2, 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4, 5, 6);
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff);
+
+ // Complex.
+ left = createElements(1, 2, 3, 5, 6, 7, 11, 12, 13, 17, 18, 19);
+ right = createElements(1, 2, 4, 5, 6, 9, 10, 13, 14, 17, 18 );
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 3, 7, 11, 12, 19);
+
+ // Dups.
+ left = createElements(1, 2, 2, 3, 3, 3, 3 );
+ right = createElements(1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4);
+ diff = new DifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 3, 3, 3, 3);
+ }
+
+ public void testSymmetricDifference() throws Exception {
+ Cursor<Element> left, right, diff;
+
+ // Two empty sets.
+ left = createElements();
+ right = createElements();
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff);
+
+ // Right set empty.
+ left = createElements(1, 2, 3, 4);
+ right = createElements();
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2, 3, 4);
+
+ // Left set empty.
+ left = createElements();
+ right = createElements(3, 4, 5, 6);
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 3, 4, 5, 6);
+
+ // No overlap.
+ left = createElements(1, 2, 3 );
+ right = createElements( 4, 5, 6);
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2, 3, 4, 5, 6);
+
+ // Overlap.
+ left = createElements(1, 2, 3, 4 );
+ right = createElements( 3, 4, 5, 6);
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2, 5, 6);
+
+ // Swapped overlap.
+ left = createElements( 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4 );
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 2, 5, 6);
+
+ // Equivalent.
+ left = createElements(1, 2, 3, 4, 5, 6);
+ right = createElements(1, 2, 3, 4, 5, 6);
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff);
+
+ // Complex.
+ left = createElements(1, 2, 3, 5, 6, 7, 11, 12, 13, 17, 18, 19);
+ right = createElements(1, 2, 4, 5, 6, 9, 10, 13, 14, 17, 18 );
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 3, 4, 7, 9, 10, 11, 12, 14, 19);
+
+ // Dups.
+ left = createElements(1, 2, 2, 3, 3, 3, 3 );
+ right = createElements(1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4);
+ diff = new SymmetricDifferenceCursor<Element>(left, right, new ElementComparator());
+
+ compareElements(diff, 1, 1, 1, 1, 2, 3, 3, 3, 3, 4, 4, 4);
+ }
+
+ private Cursor<Element> createElements(int... ids) {
+ Arrays.sort(ids);
+ Element[] elements = new Element[ids.length];
+ for (int i=0; i<ids.length; i++) {
+ elements[i] = new Element(ids[i]);
+ }
+ return new IteratorCursor<Element>(Arrays.asList(elements));
+ }
+
+ private void compareElements(Cursor<Element> elements, int... expectedIDs)
+ throws FetchException
+ {
+ for (int id : expectedIDs) {
+ if (elements.hasNext()) {
+ Element e = elements.next();
+ if (e.getId() != id) {
+ fail("Element mismatch: expected=" + id + ", actual=" + e.getId());
+ elements.close();
+ return;
+ }
+ } else {
+ fail("Too few elements in cursor");
+ return;
+ }
+ }
+
+ if (elements.hasNext()) {
+ Element e = elements.next();
+ fail("Too many elements in cursor: " + e.getId());
+ elements.close();
+ }
+ }
+
+ private static class Element extends Dummy implements StorableTestMinimal {
+ private int mID;
+
+ Element(int id) {
+ mID = id;
+ }
+
+ public int getId() {
+ return mID;
+ }
+
+ public void setId(int id) {
+ mID = id;
+ }
+
+ public String toString() {
+ return "element " + mID;
+ }
+ }
+
+ private static class ElementComparator implements Comparator<Element> {
+ public int compare(Element a, Element b) {
+ int ai = a.getId();
+ int bi = b.getId();
+ if (ai < bi) {
+ return -1;
+ } else if (ai > bi) {
+ return 1;
+ }
+ return 0;
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/cursor/TestGroupedCursor.java b/src/test/java/com/amazon/carbonado/cursor/TestGroupedCursor.java
new file mode 100644
index 0000000..3d5e42f
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/cursor/TestGroupedCursor.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.cursor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Cursor;
+import com.amazon.carbonado.FetchException;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestGroupedCursor extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestGroupedCursor.class);
+ }
+
+ public TestGroupedCursor(String name) {
+ super(name);
+ }
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void testGrouping() throws Exception {
+ List<Triple> triples = new ArrayList<Triple>();
+ triples.add(new Triple(1, 1, 1));
+ triples.add(new Triple(1, 1, 2));
+ triples.add(new Triple(1, 1, 3));
+ triples.add(new Triple(1, 2, 5));
+ triples.add(new Triple(1, 2, 9));
+ triples.add(new Triple(3, 1, 10));
+ triples.add(new Triple(3, 2, 16));
+ triples.add(new Triple(3, 2, 100));
+
+ // Should already be sorted, but no harm done
+ Collections.sort(triples);
+
+ Cursor<Pair> cursor = new GroupedCursor<Triple, Pair>
+ (new IteratorCursor<Triple>(triples), Triple.class, "a", "b")
+ {
+ private Pair aggregate;
+
+ protected void beginGroup(Triple groupLeader) {
+ aggregate = new Pair(groupLeader.getA(), groupLeader.getB());
+ aggregate.add(groupLeader.getC());
+ }
+
+ protected void addToGroup(Triple groupMember) {
+ aggregate.add(groupMember.getC());
+ }
+
+ protected Pair finishGroup() {
+ return aggregate;
+ }
+ };
+
+ List<Pair> pairs = new ArrayList<Pair>();
+
+ while (cursor.hasNext()) {
+ pairs.add(cursor.next());
+ }
+
+ assertEquals(4, pairs.size());
+
+ assertEquals(1, pairs.get(0).getA());
+ assertEquals(1, pairs.get(0).getB());
+ assertEquals(6, pairs.get(0).sum);
+
+ assertEquals(1, pairs.get(1).getA());
+ assertEquals(2, pairs.get(1).getB());
+ assertEquals(14, pairs.get(1).sum);
+
+ assertEquals(3, pairs.get(2).getA());
+ assertEquals(1, pairs.get(2).getB());
+ assertEquals(10, pairs.get(2).sum);
+
+ assertEquals(3, pairs.get(3).getA());
+ assertEquals(2, pairs.get(3).getB());
+ assertEquals(116, pairs.get(3).sum);
+ }
+
+ static int compare(int x, int y) {
+ if (x < y) {
+ return -1;
+ } else if (x > y) {
+ return 1;
+ }
+ return 0;
+ }
+
+ public static class Pair implements Comparable {
+ final int a;
+ final int b;
+
+ int sum;
+
+ Pair(int a, int b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void add(int x) {
+ sum += x;
+ }
+
+ public int compareTo(Object obj) {
+ Pair other = (Pair) obj;
+ int result = compare(a, other.a);
+ if (result == 0) {
+ result = compare(b, other.b);
+ }
+ return result;
+ }
+
+ public String toString() {
+ return "a=" + a + ", b=" + b + ", sum=" + sum;
+ }
+ }
+
+ public static class Triple extends Pair {
+ final int c;
+
+ Triple(int a, int b, int c) {
+ super(a, b);
+ this.c = c;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public int compareTo(Object obj) {
+ int result = super.compareTo(obj);
+ if (result == 0) {
+ Triple other = (Triple) obj;
+ result = compare(c, other.c);
+ }
+ return result;
+ }
+
+ public String toString() {
+ return "a=" + a + ", b=" + b + ", c=" + c;
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java
new file mode 100644
index 0000000..76ea081
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestFilteredQueryExecutor extends TestQueryExecutor {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestFilteredQueryExecutor.class);
+ }
+
+ public void testBasicFiltering() throws Exception {
+ QueryExecutor<Address> unfiltered = createExecutor(1, 2, 3, 4);
+ Filter<Address> filter = Filter.filterFor(Address.class, "addressCountry > ?");
+ FilterValues<Address> values = filter.initialFilterValues();
+
+ QueryExecutor<Address> executor = new FilteredQueryExecutor<Address>(unfiltered, filter);
+
+ assertEquals(values.getFilter(), executor.getFilter());
+
+ assertEquals(2, executor.count(values.with("country_2")));
+
+ assertEquals(0, executor.getOrdering().size());
+
+ compareElements(executor.openCursor(values.with("country_2")), 3, 4);
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java b/src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java
new file mode 100644
index 0000000..e6b4374
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java
@@ -0,0 +1,746 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.util.Comparator;
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.info.Direction;
+import static com.amazon.carbonado.info.Direction.*;
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableIndex;
+import com.amazon.carbonado.info.StorableInfo;
+import com.amazon.carbonado.info.StorableIntrospector;
+import com.amazon.carbonado.info.StorableProperty;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.PropertyFilter;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestFilteringScore extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestFilteringScore.class);
+ }
+
+ static <S extends Storable> StorableIndex<S> makeIndex(Class<S> type, String... props) {
+ return TestOrderingScore.makeIndex(type, props);
+ }
+
+ public TestFilteringScore(String name) {
+ super(name);
+ }
+
+ public void testNoFilter() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+ Filter<StorableTestBasic> filter = Filter.getOpenFilter(StorableTestBasic.class);
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ }
+
+ public void testSimpleIndexMisses() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "intProp");
+ // Filter by a property not in index.
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilters().get(0));
+ assertEquals(filter, score.getRemainderFilter());
+
+ // Try again with matching property, but with an operator that cannot be used by index.
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp != ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilters().get(0));
+ assertEquals(filter, score.getRemainderFilter());
+ }
+
+ public void testSimpleIndexMatches() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+ // Filter by a property in index.
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getArrangementScore());
+ assertEquals(filter, score.getIdentityFilters().get(0));
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ // Try again with open ranges.
+ for (int i=0; i<4; i++) {
+ String expr;
+ switch (i) {
+ default: expr = "id > ?"; break;
+ case 1: expr = "id >= ?"; break;
+ case 2: expr = "id < ?"; break;
+ case 3: expr = "id <= ?"; break;
+ }
+
+ filter = Filter.filterFor(StorableTestBasic.class, expr);
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ if (i < 2) {
+ assertTrue(score.hasRangeStart());
+ assertEquals(1, score.getRangeStartFilters().size());
+ assertEquals(filter, score.getRangeStartFilters().get(0));
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ } else {
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(filter, score.getRangeEndFilters().get(0));
+ }
+ }
+
+ // Try with duplicate open ranges.
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & id > ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ assertTrue(score.hasRangeStart());
+ assertEquals(2, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(1));
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+
+ // Try with duplicate end ranges and slightly different operator.
+ filter = Filter.filterFor(StorableTestBasic.class, "id < ? & id <= ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertTrue(score.hasRangeEnd());
+ assertEquals(2, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"),
+ score.getRangeEndFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id <= ?"),
+ score.getRangeEndFilters().get(1));
+
+ // Try with complete range.
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & id < ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertTrue(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ assertTrue(score.hasRangeStart());
+ assertEquals(1, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(0));
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"),
+ score.getRangeEndFilters().get(0));
+
+ // Try with an identity filter consuming others.
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & id = ? & id = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getIdentityFilters().size());
+ assertEquals(1, score.getArrangementScore());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id = ?"),
+ score.getIdentityFilters().get(0));
+
+ assertFalse(score.hasRangeStart());
+ assertFalse(score.hasRangeEnd());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ // Order of properties in filter accounts for sorting by PropertyFilterList.
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id = ? & id > ?"),
+ score.getRemainderFilter());
+
+ // Try with complex mix of non-identity matches.
+ filter = Filter.filterFor
+ (StorableTestBasic.class,
+ "id > ? & id != ? & id <= ? & id >= ? & id != ? & id > ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+
+ assertTrue(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+
+ assertTrue(score.hasRangeStart());
+ assertEquals(3, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id >= ?"),
+ score.getRangeStartFilters().get(1));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(2));
+
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id <= ?"),
+ score.getRangeEndFilters().get(0));
+
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id != ? & id != ?"),
+ score.getRemainderFilter());
+ }
+
+ public void testCompositeIndexMatches() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class,
+ "id", "intProp", "stringProp");
+ // Filter by a property in index.
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(3, score.getIndexPropertyCount());
+
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getArrangementScore());
+ assertEquals(filter, score.getIdentityFilters().get(0));
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ // Filter by a property with a gap. (filter must include "id" to use index)
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilter());
+
+ // Filter by a property with a gap and a range operator. (index still cannot be used)
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ? & stringProp < ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilter());
+
+ // Filter with range match before identity match. Identity cannot be used.
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ? & id < ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertTrue(score.hasAnyMatches());
+
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"),
+ score.getRangeEndFilters().get(0));
+
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp = ?"),
+ score.getRemainderFilter());
+
+ // Filter with fully specified identity match, but a few remaining.
+ filter = Filter.filterFor
+ (StorableTestBasic.class,
+ "intProp = ? & id = ? & stringProp = ? & stringProp > ? & doubleProp = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.hasAnyMatches());
+ assertEquals(3, score.getIdentityCount());
+ assertEquals(2, score.getArrangementScore());
+
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id = ?"),
+ score.getIdentityFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp = ?"),
+ score.getIdentityFilters().get(1));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp = ?"),
+ score.getIdentityFilters().get(2));
+
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ // Order of remainder properties accounts for sorting by PropertyFilterList.
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "doubleProp = ?"),
+ score.getRemainderFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp > ?"),
+ score.getRemainderFilters().get(1));
+
+ // Filter with identity and range matches.
+ filter = Filter.filterFor
+ (StorableTestBasic.class,
+ "intProp > ? & id = ? & stringProp = ? & intProp <= ? & " +
+ "stringProp < ? & doubleProp = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.hasAnyMatches());
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getArrangementScore());
+
+ assertEquals(3, score.getRemainderCount());
+ assertEquals(3, score.getRemainderFilters().size());
+ // Order of remainder properties accounts for sorting by PropertyFilterList.
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp = ?"),
+ score.getRemainderFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "doubleProp = ?"),
+ score.getRemainderFilters().get(1));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp < ?"),
+ score.getRemainderFilters().get(2));
+
+ assertTrue(score.hasRangeMatch());
+ assertTrue(score.hasRangeStart());
+ assertEquals(1, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp > ?"),
+ score.getRangeStartFilters().get(0));
+
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp <= ?"),
+ score.getRangeEndFilters().get(0));
+
+ // Filter with fully specified identity match, with backwards arrangement.
+ filter = Filter.filterFor
+ (StorableTestBasic.class, "stringProp = ? & intProp = ? & id = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.hasAnyMatches());
+ assertEquals(3, score.getIdentityCount());
+ // Arrangement score is always at least one if identity count is not zero.
+ assertEquals(1, score.getArrangementScore());
+ }
+
+ public void testReverseRange() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class,
+ "id", "intProp");
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ? & intProp > ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.shouldReverseRange());
+
+ ix = makeIndex(StorableTestBasic.class, "id", "-intProp");
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.shouldReverseRange());
+ }
+
+ public void testRangeComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ Filter<StorableTestBasic> filter;
+ FilteringScore score_1, score_2;
+ Comparator<FilteringScore<?>> comp = FilteringScore.rangeComparator();
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "id", "stringProp", "intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp != ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Both indexes are as good, since range is open.
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Test range match with tie resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2.clustered(true), filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Test open range match with tie still not resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2.clustered(true), filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+ }
+
+ public void testFullComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ Filter<StorableTestBasic> filter;
+ FilteringScore score_1, score_2;
+ Comparator<FilteringScore<?>> comp = FilteringScore.fullComparator();
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "id", "stringProp", "intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Although no property matches, second is better just because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Although no property matches, first is better just because it is clustered.
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp != ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Second index is better since the open range matches.
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Test range match with tie resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // First is better because it is clusted.
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Test range match with tie resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2.clustered(true), filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+ }
+
+ public void testArrangementFullComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ Filter<StorableTestBasic> filter;
+ FilteringScore score_1, score_2;
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "id", "stringProp", "intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & stringProp = ?");
+
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ Comparator<FilteringScore<?>> comp = FilteringScore.rangeComparator();
+
+ // With just range comparison, either index works.
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ comp = FilteringScore.fullComparator();
+
+ // First index is better because property arrangement matches.
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+ }
+
+ public void testRangeFilterSubset() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+ Filter<StorableTestBasic> filter;
+ FilteringScore score;
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id >= ? & id < ? & id <= ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(2, score.getRangeStartFilters().size());
+
+ List<PropertyFilter<?>> exStart = score.getExclusiveRangeStartFilters();
+ assertEquals(0, exStart.size());
+
+ List<PropertyFilter<?>> inStart = score.getInclusiveRangeStartFilters();
+ assertEquals(2, inStart.size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id >= ?"), inStart.get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id >= ?"), inStart.get(1));
+
+ assertEquals(2, score.getRangeEndFilters().size());
+
+ List<PropertyFilter<?>> exEnd = score.getExclusiveRangeEndFilters();
+ assertEquals(1, exEnd.size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"), exEnd.get(0));
+
+ List<PropertyFilter<?>> inEnd = score.getInclusiveRangeEndFilters();
+ assertEquals(1, inEnd.size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id <= ?"), inEnd.get(0));
+ }
+
+ public void testKeyMatch() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id", "intProp");
+ ix = ix.unique(true);
+ Filter<StorableTestBasic> filter;
+ FilteringScore score;
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertFalse(score.isKeyMatch());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp > ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertFalse(score.isKeyMatch());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertTrue(score.isKeyMatch());
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & doubleProp = ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertTrue(score.isKeyMatch());
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java
new file mode 100644
index 0000000..a039e63
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java
@@ -0,0 +1,725 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Cursor;
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.cursor.IteratorCursor;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableIndex;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestIndexedQueryExecutor extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestIndexedQueryExecutor.class);
+ }
+
+ static <S extends Storable> StorableIndex<S> makeIndex(Class<S> type, String... props) {
+ return TestOrderingScore.makeIndex(type, props);
+ }
+
+ static <S extends Storable> OrderedProperty<S>[] makeOrderings(Class<S> type, String... props)
+ {
+ return TestOrderingScore.makeOrderings(type, props);
+ }
+
+ public TestIndexedQueryExecutor(String name) {
+ super(name);
+ }
+
+ public void testIdentityMatch() throws Exception {
+ StorableIndex<StorableTestBasic> index =
+ makeIndex(StorableTestBasic.class, "id", "-intProp", "doubleProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(1, executor.mIdentityValues.length);
+ assertEquals(100, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(5));
+
+ assertEquals(2, executor.mIdentityValues.length);
+ assertEquals(100, executor.mIdentityValues[0]);
+ assertEquals(5, executor.mIdentityValues[1]);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(200));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+ }
+
+ public void testOpenRangeStartMatch() throws Exception {
+ StorableIndex<StorableTestBasic> index = makeIndex(StorableTestBasic.class, "intProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(10, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(30).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ ///////
+ index = makeIndex(StorableTestBasic.class, "-intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+ }
+
+ public void testOpenRangeEndMatch() throws Exception {
+ StorableIndex<StorableTestBasic> index = makeIndex(StorableTestBasic.class, "intProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(30).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(30, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ ///////
+ index = makeIndex(StorableTestBasic.class, "-intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+ }
+
+ public void testClosedRangeMatch() throws Exception {
+ // These tests are not as exhaustive, as I don't expect the combination
+ // of start and end ranges to interfere with each other.
+
+ StorableIndex<StorableTestBasic> index = makeIndex(StorableTestBasic.class, "intProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "intProp > ? & intProp < ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(200));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp <= ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "intProp > ? & intProp < ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(100).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+ }
+
+ public void testIdentityAndRangeMatch() throws Exception {
+ // These tests are not as exhaustive, as I don't expect the combination
+ // of identity and ranges to interfere with each other.
+
+ StorableIndex<StorableTestBasic> index;
+ Filter<StorableTestBasic> filter;
+ FilterValues<StorableTestBasic> values;
+ CompositeScore<StorableTestBasic> score;
+ Mock<StorableTestBasic> executor;
+
+ index = makeIndex(StorableTestBasic.class, "intProp", "-doubleProp", "stringProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "intProp = ? & doubleProp > ? & doubleProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with(200.2));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(56.5, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200.2, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "doubleProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with(200.2));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(56.5, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200.2, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ ///////
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "stringProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with(200.2));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(56.5, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200.2, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "intProp = ? & doubleProp = ? & stringProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-stringProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with("foo"));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(56.5, executor.mIdentityValues[1]);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals("foo", executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ assertEquals(values.getFilter(), executor.getFilter());
+ OrderedProperty<StorableTestBasic>[] expectedOrdering =
+ makeOrderings(StorableTestBasic.class, "intProp", "-doubleProp", "stringProp");
+ assertEquals(Arrays.asList(expectedOrdering), executor.getOrdering());
+ }
+
+ /**
+ * Mock object doesn't really open a cursor -- it just captures the passed
+ * parameters.
+ */
+ static class Mock<S extends Storable> extends IndexedQueryExecutor<S> {
+ Object[] mIdentityValues;
+ BoundaryType mRangeStartBoundary;
+ Object mRangeStartValue;
+ BoundaryType mRangeEndBoundary;
+ Object mRangeEndValue;
+ boolean mReverseRange;
+ boolean mReverseOrder;
+
+ public Mock(StorableIndex<S> index, CompositeScore<S> score) {
+ super(index, score);
+ }
+
+ protected Cursor<S> openCursor(StorableIndex<S> index,
+ Object[] identityValues,
+ BoundaryType rangeStartBoundary,
+ Object rangeStartValue,
+ BoundaryType rangeEndBoundary,
+ Object rangeEndValue,
+ boolean reverseRange,
+ boolean reverseOrder)
+ {
+ mIdentityValues = identityValues;
+ mRangeStartBoundary = rangeStartBoundary;
+ mRangeStartValue = rangeStartValue;
+ mRangeEndBoundary = rangeEndBoundary;
+ mRangeEndValue = rangeEndValue;
+ mReverseRange = reverseRange;
+ mReverseOrder = reverseOrder;
+
+ Collection<S> empty = Collections.emptyList();
+ return new IteratorCursor<S>(empty);
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java b/src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java
new file mode 100644
index 0000000..3929f59
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.util.Comparator;
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.info.Direction;
+import static com.amazon.carbonado.info.Direction.*;
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableIndex;
+import com.amazon.carbonado.info.StorableInfo;
+import com.amazon.carbonado.info.StorableIntrospector;
+import com.amazon.carbonado.info.StorableProperty;
+
+import com.amazon.carbonado.filter.Filter;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestOrderingScore extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestOrderingScore.class);
+ }
+
+ static <S extends Storable> StorableIndex<S> makeIndex(Class<S> type, String... props) {
+ return new StorableIndex<S>(makeOrderings(type, props), UNSPECIFIED);
+ }
+
+ static <S extends Storable> OrderedProperty<S>[] makeOrderings(Class<S> type, String... props)
+ {
+ StorableInfo<S> info = StorableIntrospector.examine(type);
+ OrderedProperty<S>[] ops = new OrderedProperty[props.length];
+ for (int i=0; i<props.length; i++) {
+ ops[i] = OrderedProperty.parse(info, props[i]);
+ }
+ return ops;
+ }
+
+ public TestOrderingScore(String name) {
+ super(name);
+ }
+
+ public void testEmpty() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+
+ OrderingScore score = OrderingScore.evaluate(ix, null);
+
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+
+ public void testOneProp() throws Exception {
+ StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore<StorableTestBasic> score;
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "id");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "+id");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "-id");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "intProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(0, score.getHandledCount());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+id", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+
+ public void testMultipleProps() throws Exception {
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore<StorableTestBasic> score;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "-intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals("-intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "+intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id", "-intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Gap is allowed if identity filtered.
+
+ Filter<StorableTestBasic> filter;
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp", "id");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ // Since "id" is filtered, don't count as remainder.
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-intProp", "id");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-intProp", score.getHandledOrderings().get(0).toString());
+ // Since "id" is filtered, don't count as remainder.
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp", "doubleProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+doubleProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp", "-doubleProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-doubleProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & doubleProp = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "doubleProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp = ? & id = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "doubleProp", "-intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+ }
+
+ public void testMidGap() throws Exception {
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score;
+ Filter<StorableTestBasic> filter;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(4, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals("+doubleProp", score.getHandledOrderings().get(2).toString());
+ assertEquals("-stringProp", score.getHandledOrderings().get(3).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Now ignore mid index properties, creating a gap.
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Gap can be bridged if property is filtered out. First test with
+ // incomplete bridges.
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp = ? & intProp > ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp >= ? & intProp = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Now a complete bridge.
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp = ? & intProp = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("-stringProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Again in reverse.
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+stringProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ // Failed double reverse.
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(true, score.shouldReverseOrder());
+ }
+
+ public void testComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score_1, score_2;
+ Filter<StorableTestBasic> filter;
+ Comparator<OrderingScore<?>> comp = OrderingScore.fullComparator();
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "intProp", "doubleProp", "id");
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "-intProp");
+ score_1 = OrderingScore.evaluate(ix_1, null, ops);
+ score_2 = OrderingScore.evaluate(ix_2, null, ops);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ // Index 2 has less properties, so it is better.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Keep ix_2 slightly better by matching desired order.
+ ix_2 = makeIndex(StorableTestBasic.class, "-intProp", "doubleProp", "id", "stringProp");
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Make ix_1 slightly better by making it clustered.
+ ix_1 = ix_1.clustered(true);
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Make ix_2 better when clustered.
+ ix_2 = ix_2.clustered(true);
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Make ix_1 same by reversing order.
+ ix_1 = ix_1.reverse();
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+ }
+
+ public void testIndexNotNeeded() throws Exception {
+ // Test an index which matches desired orderings, but ordering
+ // properties are filtered out. Thus the index is not needed.
+
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score;
+ Filter<StorableTestBasic> filter;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "intProp", "doubleProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(3, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals("+doubleProp", score.getHandledOrderings().get(2).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+doubleProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ? & doubleProp =?");
+
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+
+ public void testUniqueIndexNotNeeded() throws Exception {
+ // Test a unique index which has been fully specified. Ordering is not
+ // needed at all.
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score;
+ Filter<StorableTestBasic> filter;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp").unique(true);
+ ops = makeOrderings(StorableTestBasic.class, "stringProp", "doubleProp");
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ? & doubleProp =?");
+
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java b/src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java
new file mode 100644
index 0000000..b0af52f
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.PropertyFilter;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestPropertyFilterList extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestPropertyFilterList.class);
+ }
+
+ public TestPropertyFilterList(String name) {
+ super(name);
+ }
+
+ public void testNull() throws Exception {
+ assertEquals(0, PropertyFilterList.get(null).size());
+ }
+
+ public void testOpen() throws Exception {
+ Filter<StorableTestBasic> filter = Filter.getOpenFilter(StorableTestBasic.class);
+ assertEquals(0, PropertyFilterList.get(filter).size());
+ }
+
+ public void testClosed() throws Exception {
+ Filter<StorableTestBasic> filter = Filter.getClosedFilter(StorableTestBasic.class);
+ assertEquals(0, PropertyFilterList.get(filter).size());
+ }
+
+ public void testSingleton() throws Exception {
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ List<PropertyFilter<StorableTestBasic>> list = PropertyFilterList.get(filter);
+
+ assertEquals(1, list.size());
+ assertEquals(filter, list.get(0));
+
+ List<PropertyFilter<StorableTestBasic>> list2 = PropertyFilterList.get(filter);
+
+ assertTrue(list == list2);
+ }
+
+ public void testMultiple() throws Exception {
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ? & intProp > ?");
+
+ List<PropertyFilter<StorableTestBasic>> list = PropertyFilterList.get(filter);
+
+ assertEquals(2, list.size());
+
+ Filter<StorableTestBasic> subFilter =
+ Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ assertEquals(subFilter, list.get(0));
+
+ subFilter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+
+ assertEquals(subFilter, list.get(1));
+
+ List<PropertyFilter<StorableTestBasic>> list2 = PropertyFilterList.get(filter);
+
+ assertTrue(list == list2);
+ }
+
+ public void testIllegal() throws Exception {
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ? | intProp > ?");
+
+ try {
+ List<PropertyFilter<StorableTestBasic>> list = PropertyFilterList.get(filter);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java
new file mode 100644
index 0000000..4727a56
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import com.amazon.carbonado.Cursor;
+import com.amazon.carbonado.FetchException;
+
+import com.amazon.carbonado.info.Direction;
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableInfo;
+import com.amazon.carbonado.info.StorableIntrospector;
+import com.amazon.carbonado.info.StorableProperty;
+
+import com.amazon.carbonado.stored.Dummy;
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public abstract class TestQueryExecutor extends TestCase {
+
+ protected QueryExecutor<Address> createExecutor(int... ids) {
+ return new IterableQueryExecutor<Address>(Address.class, createCollection(ids));
+ }
+
+ protected Collection<Address> createCollection(int... ids) {
+ Collection<Address> elements = new ArrayList<Address>(ids.length);
+ for (int i=0; i<ids.length; i++) {
+ elements.add(new DummyAddress(ids[i]));
+ }
+ return elements;
+ }
+
+ protected void compareElements(Cursor<Address> elements, int... expectedIDs)
+ throws FetchException
+ {
+ for (int id : expectedIDs) {
+ if (elements.hasNext()) {
+ Address e = elements.next();
+ if (e.getAddressID() != id) {
+ fail("Element mismatch: expected=" + id + ", actual=" + e.getAddressID());
+ elements.close();
+ return;
+ }
+ } else {
+ fail("Too few elements in cursor");
+ return;
+ }
+ }
+
+ if (elements.hasNext()) {
+ Address e = elements.next();
+ fail("Too many elements in cursor: " + e.getAddressID());
+ elements.close();
+ }
+ }
+
+ protected List<OrderedProperty<Address>> createOrdering(String... properties) {
+ StorableInfo<Address> info = StorableIntrospector.examine(Address.class);
+ Map<String, ? extends StorableProperty<Address>> props = info.getAllProperties();
+
+ List<OrderedProperty<Address>> ordered = new ArrayList<OrderedProperty<Address>>();
+
+ for (String prop : properties) {
+ ordered.add(OrderedProperty.get(props.get(prop), Direction.ASCENDING));
+ }
+
+ return ordered;
+ }
+
+ static void printPlan(QueryExecutor executor) {
+ try {
+ executor.printPlan(System.out, 0, null);
+ } catch (IOException e) {
+ }
+ }
+
+ private static class DummyAddress extends Dummy implements Address {
+ private long mID;
+ private String mLine1;
+ private String mLine2;
+ private String mCity;
+ private String mState;
+ private String mZip;
+ private String mCountry;
+ private String mData;
+
+ DummyAddress(long id) {
+ mID = id;
+ mLine1 = "line1_" + id;
+ mLine2 = "line2_" + id;
+ mCity = "city_" + id;
+ mState = "state_" + id;
+ mZip = "zip_" + id;
+ mCountry = "country_" + id;
+ mData = "data_" + id;
+ }
+
+ public long getAddressID() {
+ return mID;
+ }
+
+ public void setAddressID(long id) {
+ mID = id;
+ }
+
+ public String getAddressLine1() {
+ return mLine1;
+ }
+
+ public void setAddressLine1(String value) {
+ mLine1 = value;
+ }
+
+ public String getAddressLine2() {
+ return mLine2;
+ }
+
+ public void setAddressLine2(String value) {
+ mLine2 = value;
+ }
+
+ public String getAddressCity() {
+ return mCity;
+ }
+
+ public void setAddressCity(String value) {
+ mCity = value;
+ }
+
+ public String getAddressState() {
+ return mState;
+ }
+
+ public void setAddressState(String value) {
+ mState = value;
+ }
+
+ public String getAddressZip() {
+ return mZip;
+ }
+
+ public void setAddressZip(String value) {
+ mZip = value;
+ }
+
+ public String getAddressCountry() {
+ return mCountry;
+ }
+
+ public void setAddressCountry(String value) {
+ mCountry = value;
+ }
+
+ public String getCustomData() {
+ return mData;
+ }
+
+ public void setCustomData(String str) {
+ mData = str;
+ }
+
+ public String toString() {
+ return "address " + mID;
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java
new file mode 100644
index 0000000..0972e94
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.util.List;
+
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.info.OrderedProperty;
+
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestSortedQueryExecutor extends TestQueryExecutor {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestSortedQueryExecutor.class);
+ }
+
+ public void testBasicSorting() throws Exception {
+ QueryExecutor<Address> unsorted = createExecutor(4, 2, 3, 1);
+ Filter<Address> filter = Filter.getOpenFilter(Address.class);
+ FilterValues<Address> values = filter.initialFilterValues();
+ List<OrderedProperty<Address>> ordered = createOrdering("addressCountry");
+
+ QueryExecutor<Address> executor =
+ new ArraySortedQueryExecutor<Address>(unsorted, null, ordered);
+
+ assertEquals(filter, executor.getFilter());
+
+ assertEquals(4, executor.count(values));
+
+ assertEquals(ordered, executor.getOrdering());
+
+ compareElements(executor.openCursor(values), 1, 2, 3, 4);
+ }
+
+ public void testBasicFinisherSorting() throws Exception {
+ QueryExecutor<Address> unsorted = createExecutor(1, 2, 3, 4);
+ Filter<Address> filter = Filter.getOpenFilter(Address.class);
+ FilterValues<Address> values = filter.initialFilterValues();
+ List<OrderedProperty<Address>> handled = createOrdering("addressCountry");
+ List<OrderedProperty<Address>> finisher = createOrdering("addressState");
+
+ QueryExecutor<Address> executor =
+ new ArraySortedQueryExecutor<Address>(unsorted, handled, finisher);
+
+ assertEquals(filter, executor.getFilter());
+
+ assertEquals(4, executor.count(values));
+
+ assertEquals(2, executor.getOrdering().size());
+ assertEquals(handled.get(0), executor.getOrdering().get(0));
+ assertEquals(finisher.get(0), executor.getOrdering().get(1));
+
+ compareElements(executor.openCursor(values), 1, 2, 3, 4);
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java
new file mode 100644
index 0000000..639176c
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.qe;
+
+import java.util.List;
+
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.info.OrderedProperty;
+
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestUnionQueryExecutor extends TestQueryExecutor {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestUnionQueryExecutor.class);
+ }
+
+ public void testBasicUnion() throws Exception {
+ QueryExecutor<Address> primary = new ArraySortedQueryExecutor<Address>
+ (createExecutor(1, 2, 3, 4, 5, 6, 7, 8), null, createOrdering("addressID"));
+
+ Filter<Address> filter_1 = Filter.filterFor(Address.class, "addressCountry > ?");
+ FilterValues<Address> values_1 = filter_1.initialFilterValues();
+ QueryExecutor<Address> executor_1 = new FilteredQueryExecutor<Address>(primary, filter_1);
+
+ Filter<Address> filter_2 = Filter.filterFor(Address.class, "addressState <= ?");
+ FilterValues<Address> values_2 = filter_2.initialFilterValues();
+ QueryExecutor<Address> executor_2 = new FilteredQueryExecutor<Address>(primary, filter_2);
+
+ QueryExecutor<Address> union = new UnionQueryExecutor<Address>(executor_1, executor_2);
+
+ Filter<Address> filter = Filter
+ .filterFor(Address.class, "addressCountry > ? | addressState <= ?");
+ FilterValues<Address> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ assertEquals(filter, union.getFilter());
+
+ values = values.with("country_6").with("state_3");
+
+ assertEquals(5, union.count(values));
+
+ assertEquals(primary.getOrdering(), union.getOrdering());
+
+ compareElements(union.openCursor(values), 1, 2, 3, 7, 8);
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/spi/TestConversionComparator.java b/src/test/java/com/amazon/carbonado/spi/TestConversionComparator.java
new file mode 100644
index 0000000..5cd7caa
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/spi/TestConversionComparator.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.spi;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.spi.ConversionComparator;
+
+/**
+ * Test cases for {@link ConversionComparator}.
+ *
+ * @author Brian S O'Neill
+ */
+public class TestConversionComparator extends TestCase {
+ private static final int BOOLEAN_CODE = 0;
+ private static final int BYTE_CODE = 1;
+ private static final int SHORT_CODE = 2;
+ private static final int CHAR_CODE = 3;
+ private static final int INT_CODE = 4;
+ private static final int FLOAT_CODE = 5;
+ private static final int LONG_CODE = 6;
+ private static final int DOUBLE_CODE = 7;
+
+ private static final Class[] PRIMITIVE_CLASSES = {
+ boolean.class, byte.class, short.class, char.class,
+ int.class, float.class, long.class, double.class
+ };
+
+ private static final Class[] BOXED_PRIMITIVE_CLASSES = {
+ Boolean.class, Byte.class, Short.class, Character.class,
+ Integer.class, Float.class, Long.class, Double.class
+ };
+
+ // States which primitive conversions are allowed.
+ private static final boolean[][] PRIMITIVE_MATRIX = {
+ // from...
+ // boolean byte short char int float long double
+ { true, false, false, false, false, false, false, false }, // to boolean
+ { false, true, false, false, false, false, false, false }, // to byte
+ { false, true, true, false, false, false, false, false }, // to short
+ { false, false, false, true, false, false, false, false }, // to char
+ { false, true, true, false, true, false, false, false }, // to int
+ { false, true, true, false, false, true, false, false }, // to float
+ { false, true, true, false, true, false, true, false }, // to long
+ { false, true, true, false, true, true, false, true }, // to double
+ };
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestConversionComparator.class);
+ }
+
+ public TestConversionComparator(String name) {
+ super(name);
+ }
+
+ public void test_isConversionPossible_basics() {
+ ConversionComparator cc = new ConversionComparator(Object.class);
+ assertEquals(true, cc.isConversionPossible(Object.class));
+ assertEquals(false, cc.isConversionPossible(String.class));
+ assertEquals(false, cc.isConversionPossible(boolean.class));
+ assertEquals(false, cc.isConversionPossible(Integer.class));
+ assertEquals(false, cc.isConversionPossible(int.class));
+
+ cc = new ConversionComparator(String.class);
+ assertEquals(true, cc.isConversionPossible(Object.class));
+ assertEquals(true, cc.isConversionPossible(String.class));
+ assertEquals(false, cc.isConversionPossible(boolean.class));
+ assertEquals(false, cc.isConversionPossible(Integer.class));
+ assertEquals(false, cc.isConversionPossible(int.class));
+
+ cc = new ConversionComparator(boolean.class);
+ assertEquals(true, cc.isConversionPossible(Object.class));
+ assertEquals(false, cc.isConversionPossible(String.class));
+ assertEquals(true, cc.isConversionPossible(boolean.class));
+ assertEquals(false, cc.isConversionPossible(Integer.class));
+ assertEquals(false, cc.isConversionPossible(int.class));
+
+ cc = new ConversionComparator(Integer.class);
+ assertEquals(true, cc.isConversionPossible(Object.class));
+ assertEquals(false, cc.isConversionPossible(String.class));
+ assertEquals(false, cc.isConversionPossible(boolean.class));
+ assertEquals(true, cc.isConversionPossible(Integer.class));
+ assertEquals(true, cc.isConversionPossible(int.class));
+
+ cc = new ConversionComparator(int.class);
+ assertEquals(true, cc.isConversionPossible(Object.class));
+ assertEquals(false, cc.isConversionPossible(String.class));
+ assertEquals(false, cc.isConversionPossible(boolean.class));
+ assertEquals(true, cc.isConversionPossible(Integer.class));
+ assertEquals(true, cc.isConversionPossible(int.class));
+ }
+
+ public void test_isConversionPossible_primitives() {
+ test_isConversionPossible_primitives(false, false);
+ test_isConversionPossible_primitives(false, true);
+ test_isConversionPossible_primitives(true, false);
+ test_isConversionPossible_primitives(true, true);
+ }
+
+ private void test_isConversionPossible_primitives(boolean fromBoxed, boolean toBoxed) {
+ for (int fromCode = BOOLEAN_CODE; fromCode <= DOUBLE_CODE; fromCode++) {
+ ConversionComparator cc = new ConversionComparator
+ (fromBoxed ? BOXED_PRIMITIVE_CLASSES[fromCode] : PRIMITIVE_CLASSES[fromCode]);
+ for (int toCode = BOOLEAN_CODE; toCode <= DOUBLE_CODE; toCode++) {
+ boolean expected = PRIMITIVE_MATRIX[toCode][fromCode];
+ Class toType = toBoxed ? BOXED_PRIMITIVE_CLASSES[toCode] : PRIMITIVE_CLASSES[toCode];
+ assertEquals(expected, cc.isConversionPossible(toType));
+ }
+ }
+ }
+
+ public void test_compare() {
+ ConversionComparator cc = new ConversionComparator(Object.class);
+ assertEquals(true, cc.compare(Object.class, String.class) < 0);
+ assertEquals(true, cc.compare(String.class, Object.class) > 0);
+ assertEquals(0, cc.compare(Object.class, Object.class));
+ assertEquals(0, cc.compare(String.class, String.class));
+ assertEquals(0, cc.compare(String.class, String.class));
+ assertEquals(0, cc.compare(int.class, Number.class));
+
+ cc = new ConversionComparator(String.class);
+ assertEquals(true, cc.compare(String.class, Object.class) < 0);
+ assertEquals(true, cc.compare(Object.class, String.class) > 0);
+ assertEquals(0, cc.compare(String.class, String.class));
+ assertEquals(true, cc.compare(int.class, String.class) > 0);
+
+ cc = new ConversionComparator(Integer.class);
+ assertEquals(true, cc.compare(String.class, Object.class) > 0);
+ assertEquals(true, cc.compare(Object.class, String.class) < 0);
+ assertEquals(true, cc.compare(Object.class, Number.class) > 0);
+ assertEquals(true, cc.compare(Integer.class, Number.class) < 0);
+ assertEquals(true, cc.compare(int.class, Number.class) > 0);
+ assertEquals(true, cc.compare(long.class, Number.class) > 0);
+ assertEquals(true, cc.compare(long.class, Long.class) < 0);
+
+ cc = new ConversionComparator(int.class);
+ assertEquals(true, cc.compare(String.class, Object.class) > 0);
+ assertEquals(true, cc.compare(Object.class, String.class) < 0);
+ assertEquals(true, cc.compare(Object.class, Number.class) > 0);
+ assertEquals(true, cc.compare(Integer.class, Number.class) < 0);
+ assertEquals(true, cc.compare(int.class, Number.class) < 0);
+ assertEquals(true, cc.compare(long.class, Number.class) < 0);
+ assertEquals(true, cc.compare(long.class, Long.class) < 0);
+
+ cc = new ConversionComparator(Byte.class);
+ assertEquals(true, cc.compare(int.class, Number.class) > 0);
+ assertEquals(true, cc.compare(long.class, Number.class) > 0);
+ assertEquals(true, cc.compare(long.class, Integer.class) < 0);
+
+ cc = new ConversionComparator(byte.class);
+ assertEquals(true, cc.compare(short.class, int.class) < 0);
+ assertEquals(true, cc.compare(long.class, int.class) > 0);
+
+ cc = new ConversionComparator(java.util.Date.class);
+ assertEquals(true, cc.compare(Object.class, Comparable.class) > 0);
+ assertEquals(0, cc.compare(java.io.Serializable.class, Comparable.class));
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/spi/TestCursorList.java b/src/test/java/com/amazon/carbonado/spi/TestCursorList.java
new file mode 100644
index 0000000..605e981
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/spi/TestCursorList.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.spi;
+
+import com.amazon.carbonado.Cursor;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.cursor.EmptyCursorFactory;
+
+/**
+ * Test case for TransactionManager.CursorList.
+ *
+ * @author Brian S O'Neill
+ */
+public class TestCursorList extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestCursorList.class);
+ }
+
+ TransactionManager.CursorList mList;
+
+ public TestCursorList(String name) {
+ super(name);
+ }
+
+ protected void setUp() {
+ mList = new TransactionManager.CursorList();
+ }
+
+ public void testRegisterFew() {
+ assertEquals(0, mList.size());
+
+ {
+ Cursor cursor = EmptyCursorFactory.newEmptyCursor();
+ mList.register(cursor, null);
+ assertEquals(1, mList.size());
+ assertEquals(cursor, mList.getCursor(0));
+ assertEquals(null, mList.getValue(0));
+ Object value = mList.unregister(cursor);
+ assertEquals(0, mList.size());
+ assertEquals(null, value);
+ }
+
+ {
+ Cursor cursor_1 = EmptyCursorFactory.newEmptyCursor();
+ Cursor cursor_2 = EmptyCursorFactory.newEmptyCursor();
+ mList.register(cursor_1, null);
+ assertEquals(1, mList.size());
+ mList.register(cursor_2, null);
+ assertEquals(2, mList.size());
+ assertEquals(cursor_1, mList.getCursor(0));
+ assertEquals(cursor_2, mList.getCursor(1));
+ assertEquals(null, mList.getValue(0));
+ assertEquals(null, mList.getValue(1));
+
+ Object value = mList.unregister(cursor_2);
+ assertEquals(1, mList.size());
+ assertEquals(cursor_1, mList.getCursor(0));
+ assertEquals(null, value);
+ mList.unregister(cursor_2);
+ assertEquals(1, mList.size());
+ mList.unregister(cursor_1);
+ assertEquals(0, mList.size());
+ }
+
+ // unregister in reverse
+ {
+ Cursor cursor_1 = EmptyCursorFactory.newEmptyCursor();
+ Cursor cursor_2 = EmptyCursorFactory.newEmptyCursor();
+ mList.register(cursor_1, null);
+ mList.register(cursor_2, null);
+
+ mList.unregister(cursor_1);
+ assertEquals(1, mList.size());
+ assertEquals(cursor_2, mList.getCursor(0));
+
+ mList.unregister(cursor_1);
+ assertEquals(1, mList.size());
+ mList.unregister(cursor_2);
+ assertEquals(0, mList.size());
+ }
+ }
+
+ public void testRegisterFewValue() {
+ Cursor cursor_1 = EmptyCursorFactory.newEmptyCursor();
+ Cursor cursor_2 = EmptyCursorFactory.newEmptyCursor();
+ String value_1 = "1";
+ String value_2 = "2";
+
+ mList.register(cursor_1, value_1);
+ assertEquals(1, mList.size());
+ assertEquals(cursor_1, mList.getCursor(0));
+ assertEquals(value_1, mList.getValue(0));
+
+ mList.register(cursor_2, value_2);
+ assertEquals(2, mList.size());
+ assertEquals(cursor_1, mList.getCursor(0));
+ assertEquals(value_1, mList.getValue(0));
+ assertEquals(cursor_2, mList.getCursor(1));
+ assertEquals(value_2, mList.getValue(1));
+
+ Object value = mList.unregister(cursor_2);
+ assertEquals(1, mList.size());
+ assertEquals(cursor_1, mList.getCursor(0));
+ assertEquals(value_1, mList.getValue(0));
+ assertEquals(value_2, value);
+
+ value = mList.unregister(cursor_2);
+ assertEquals(1, mList.size());
+ assertEquals(null, value);
+ value = mList.unregister(cursor_1);
+ assertEquals(0, mList.size());
+ assertEquals(value_1, value);
+ }
+
+ // Tests that the array expands properly.
+ public void testRegisterMany() {
+ final int count = 50;
+ Cursor[] cursors = new Cursor[count];
+ for (int i=0; i<count; i++) {
+ cursors[i] = EmptyCursorFactory.newEmptyCursor();
+ mList.register(cursors[i], null);
+ assertEquals(i + 1, mList.size());
+ }
+
+ for (int i=0; i<count; i++) {
+ assertEquals(cursors[i], mList.getCursor(i));
+ assertEquals(null, mList.getValue(i));
+ }
+
+ for (int i=0; i<count; i++) {
+ mList.unregister(cursors[i]);
+ assertEquals(count - i - 1, mList.size());
+ }
+ }
+
+ // Tests that the arrays expand properly and store values.
+ public void testRegisterManyValues() {
+ final int count = 50;
+ Cursor[] cursors = new Cursor[count];
+ Integer[] values = new Integer[count];
+ for (int i=0; i<count; i++) {
+ cursors[i] = EmptyCursorFactory.newEmptyCursor();
+ values[i] = i;
+ mList.register(cursors[i], values[i]);
+ assertEquals(i + 1, mList.size());
+ }
+
+ for (int i=0; i<count; i++) {
+ assertEquals(cursors[i], mList.getCursor(i));
+ assertEquals(values[i], mList.getValue(i));
+ }
+
+ for (int i=0; i<count; i++) {
+ Object value = mList.unregister(cursors[i]);
+ assertEquals(count - i - 1, mList.size());
+ assertEquals(values[i], value);
+ }
+ }
+
+ public void testCloseCursors() throws Exception {
+ final int count = 50;
+
+ // Without values
+ {
+ Cursor[] cursors = new Cursor[count];
+ for (int i=0; i<count; i++) {
+ cursors[i] = EmptyCursorFactory.newEmptyCursor();
+ mList.register(cursors[i], null);
+ }
+
+ mList.closeCursors();
+ assertEquals(0, mList.size());
+
+ /*
+ for (int i=0; i<count; i++) {
+ assertEquals(true, cursors[i].isClosed());
+ }
+ */
+ }
+
+ // With values
+ {
+ Cursor[] cursors = new Cursor[count];
+ Integer[] values = new Integer[count];
+ for (int i=0; i<count; i++) {
+ cursors[i] = EmptyCursorFactory.newEmptyCursor();
+ values[i] = i;
+ mList.register(cursors[i], values[i]);
+ }
+
+ mList.closeCursors();
+ assertEquals(0, mList.size());
+
+ /*
+ for (int i=0; i<count; i++) {
+ assertEquals(true, cursors[i].isClosed());
+ }
+ */
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/spi/TestTriggerManager.java b/src/test/java/com/amazon/carbonado/spi/TestTriggerManager.java
new file mode 100644
index 0000000..62456ab
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/spi/TestTriggerManager.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.spi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.Trigger;
+
+import com.amazon.carbonado.stored.Dummy;
+
+/**
+ * Tests for TriggerManager.
+ *
+ * @author Brian S O'Neill
+ */
+public class TestTriggerManager extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestTriggerManager.class);
+ }
+
+ public TestTriggerManager(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() {
+ beforeTriggers = new ArrayList<TestTrigger>();
+ afterTriggers = new ArrayList<TestTrigger>();
+ failedTriggers = new ArrayList<TestTrigger>();
+ }
+
+ @Override
+ protected void tearDown() {
+ }
+
+ List<TestTrigger> beforeTriggers;
+ List<TestTrigger> afterTriggers;
+ List<TestTrigger> failedTriggers;
+
+ public void testAddAndRemove() {
+ TriggerManager<Dummy> set = new TriggerManager<Dummy>();
+ Trigger<Dummy> trigger = new TestTrigger<Dummy>();
+
+ assertNull(set.getInsertTrigger());
+ assertNull(set.getUpdateTrigger());
+ assertNull(set.getDeleteTrigger());
+
+ assertTrue(set.addTrigger(trigger));
+ assertNotNull(set.getInsertTrigger());
+ assertNotNull(set.getUpdateTrigger());
+ assertNotNull(set.getDeleteTrigger());
+
+ assertFalse(set.addTrigger(trigger));
+ assertNotNull(set.getInsertTrigger());
+ assertNotNull(set.getUpdateTrigger());
+ assertNotNull(set.getDeleteTrigger());
+
+ assertTrue(set.removeTrigger(trigger));
+ assertNull(set.getInsertTrigger());
+ assertNull(set.getUpdateTrigger());
+ assertNull(set.getDeleteTrigger());
+
+ assertFalse(set.removeTrigger(trigger));
+ assertNull(set.getInsertTrigger());
+ assertNull(set.getUpdateTrigger());
+ assertNull(set.getDeleteTrigger());
+
+ Trigger<Dummy> trigger2 = new TestTrigger<Dummy>();
+ assertTrue(set.addTrigger(trigger));
+ assertTrue(set.addTrigger(trigger2));
+ assertNotNull(set.getInsertTrigger());
+ assertNotNull(set.getUpdateTrigger());
+ assertNotNull(set.getDeleteTrigger());
+
+ assertTrue(set.removeTrigger(trigger));
+ assertNotNull(set.getInsertTrigger());
+ assertNotNull(set.getUpdateTrigger());
+ assertNotNull(set.getDeleteTrigger());
+ assertTrue(set.removeTrigger(trigger2));
+ assertNull(set.getInsertTrigger());
+ assertNull(set.getUpdateTrigger());
+ assertNull(set.getDeleteTrigger());
+ }
+
+ public void testBeforeAndAfterOps() throws Exception {
+ TriggerManager<Dummy> set = new TriggerManager<Dummy>();
+ TestTrigger<Dummy> trigger = new TestTrigger<Dummy>();
+ set.addTrigger(trigger);
+ Dummy d = new Dummy();
+
+ Object state = set.getInsertTrigger().beforeInsert(d);
+ assertEquals(1, trigger.beforeInsertCount);
+ assertEquals(0, trigger.beforeUpdateCount);
+ assertEquals(0, trigger.beforeDeleteCount);
+
+ set.getInsertTrigger().afterInsert(d, state);
+ assertEquals(1, trigger.afterInsertCount);
+ assertEquals(0, trigger.afterUpdateCount);
+ assertEquals(0, trigger.afterDeleteCount);
+
+ state = set.getUpdateTrigger().beforeUpdate(d);
+ assertEquals(1, trigger.beforeUpdateCount);
+ assertEquals(0, trigger.beforeDeleteCount);
+
+ set.getUpdateTrigger().afterUpdate(d, state);
+ assertEquals(1, trigger.afterUpdateCount);
+ assertEquals(0, trigger.afterDeleteCount);
+
+ state = set.getDeleteTrigger().beforeDelete(d);
+ assertEquals(1, trigger.beforeDeleteCount);
+
+ set.getDeleteTrigger().afterDelete(d, state);
+ assertEquals(1, trigger.afterDeleteCount);
+ }
+
+ public void testBeforeAndFailedOps() throws Exception {
+ TriggerManager<Dummy> set = new TriggerManager<Dummy>();
+ TestTrigger<Dummy> trigger = new TestTrigger<Dummy>();
+ set.addTrigger(trigger);
+ Dummy d = new Dummy();
+
+ Object state = set.getInsertTrigger().beforeInsert(d);
+ assertEquals(1, trigger.beforeInsertCount);
+ assertEquals(0, trigger.beforeUpdateCount);
+ assertEquals(0, trigger.beforeDeleteCount);
+
+ set.getInsertTrigger().failedInsert(d, state);
+ assertEquals(1, trigger.failedInsertCount);
+ assertEquals(0, trigger.failedUpdateCount);
+ assertEquals(0, trigger.failedDeleteCount);
+
+ state = set.getUpdateTrigger().beforeUpdate(d);
+ assertEquals(1, trigger.beforeUpdateCount);
+ assertEquals(0, trigger.beforeDeleteCount);
+
+ set.getUpdateTrigger().failedUpdate(d, state);
+ assertEquals(1, trigger.failedUpdateCount);
+ assertEquals(0, trigger.failedDeleteCount);
+
+ state = set.getDeleteTrigger().beforeDelete(d);
+ assertEquals(1, trigger.beforeDeleteCount);
+
+ set.getDeleteTrigger().failedDelete(d, state);
+ assertEquals(1, trigger.failedDeleteCount);
+ }
+
+ public void testExecutionOrder() throws Exception {
+ TriggerManager<Dummy> set = new TriggerManager<Dummy>();
+ TestTrigger<Dummy> trigger = new TestTrigger<Dummy>(null);
+ TestTrigger<Dummy> trigger2 = new TestTrigger<Dummy>();
+ set.addTrigger(trigger);
+ set.addTrigger(trigger2);
+ Dummy d = new Dummy();
+
+ // Insert
+ {
+ Object state = set.getInsertTrigger().beforeInsert(d);
+ assertEquals(2, beforeTriggers.size());
+ assertEquals(trigger2, beforeTriggers.get(0));
+ assertEquals(trigger, beforeTriggers.get(1));
+
+ set.getInsertTrigger().afterInsert(d, state);
+ assertEquals(2, afterTriggers.size());
+ assertEquals(trigger, afterTriggers.get(0));
+ assertEquals(trigger2, afterTriggers.get(1));
+
+ state = set.getInsertTrigger().beforeInsert(d);
+ set.getInsertTrigger().failedInsert(d, state);
+ assertEquals(2, failedTriggers.size());
+ assertEquals(trigger, failedTriggers.get(0));
+ assertEquals(trigger2, failedTriggers.get(1));
+ }
+
+ beforeTriggers.clear();
+ afterTriggers.clear();
+ failedTriggers.clear();
+
+ // Update
+ {
+ Object state = set.getUpdateTrigger().beforeUpdate(d);
+ assertEquals(2, beforeTriggers.size());
+ assertEquals(trigger2, beforeTriggers.get(0));
+ assertEquals(trigger, beforeTriggers.get(1));
+
+ set.getUpdateTrigger().afterUpdate(d, state);
+ assertEquals(2, afterTriggers.size());
+ assertEquals(trigger, afterTriggers.get(0));
+ assertEquals(trigger2, afterTriggers.get(1));
+
+ state = set.getUpdateTrigger().beforeUpdate(d);
+ set.getUpdateTrigger().failedUpdate(d, state);
+ assertEquals(2, failedTriggers.size());
+ assertEquals(trigger, failedTriggers.get(0));
+ assertEquals(trigger2, failedTriggers.get(1));
+ }
+
+ beforeTriggers.clear();
+ afterTriggers.clear();
+ failedTriggers.clear();
+
+ // Delete
+ {
+ Object state = set.getDeleteTrigger().beforeDelete(d);
+ assertEquals(2, beforeTriggers.size());
+ assertEquals(trigger2, beforeTriggers.get(0));
+ assertEquals(trigger, beforeTriggers.get(1));
+
+ set.getDeleteTrigger().afterDelete(d, state);
+ assertEquals(2, afterTriggers.size());
+ assertEquals(trigger, afterTriggers.get(0));
+ assertEquals(trigger2, afterTriggers.get(1));
+
+ state = set.getDeleteTrigger().beforeDelete(d);
+ set.getDeleteTrigger().failedDelete(d, state);
+ assertEquals(2, failedTriggers.size());
+ assertEquals(trigger, failedTriggers.get(0));
+ assertEquals(trigger2, failedTriggers.get(1));
+ }
+ }
+
+ class TestTrigger<S extends Storable> extends Trigger<S> {
+ final Object stateObj;
+
+ int beforeInsertCount;
+ int afterInsertCount;
+ int failedInsertCount;
+
+ int beforeUpdateCount;
+ int afterUpdateCount;
+ int failedUpdateCount;
+
+ int beforeDeleteCount;
+ int afterDeleteCount;
+ int failedDeleteCount;
+
+ TestTrigger() {
+ this.stateObj = new Object();
+ }
+
+ TestTrigger(Object stateObj) {
+ this.stateObj = stateObj;
+ }
+
+ @Override
+ public Object beforeInsert(S storable) {
+ beforeInsertCount++;
+ beforeTriggers.add(this);
+ return stateObj;
+ }
+
+ @Override
+ public void afterInsert(S storable, Object state) {
+ Assert.assertEquals(stateObj, state);
+ afterTriggers.add(this);
+ afterInsertCount++;
+ }
+
+ @Override
+ public void failedInsert(S storable, Object state) {
+ Assert.assertEquals(stateObj, state);
+ failedTriggers.add(this);
+ failedInsertCount++;
+ }
+
+ @Override
+ public Object beforeUpdate(S storable) {
+ beforeUpdateCount++;
+ beforeTriggers.add(this);
+ return stateObj;
+ }
+
+ @Override
+ public void afterUpdate(S storable, Object state) {
+ Assert.assertEquals(stateObj, state);
+ afterTriggers.add(this);
+ afterUpdateCount++;
+ }
+
+ @Override
+ public void failedUpdate(S storable, Object state) {
+ Assert.assertEquals(stateObj, state);
+ failedTriggers.add(this);
+ failedUpdateCount++;
+ }
+
+ @Override
+ public Object beforeDelete(S storable) {
+ beforeDeleteCount++;
+ beforeTriggers.add(this);
+ return stateObj;
+ }
+
+ @Override
+ public void afterDelete(S storable, Object state) {
+ Assert.assertEquals(stateObj, state);
+ afterTriggers.add(this);
+ afterDeleteCount++;
+ }
+
+ @Override
+ public void failedDelete(S storable, Object state) {
+ Assert.assertEquals(stateObj, state);
+ failedTriggers.add(this);
+ failedDeleteCount++;
+ }
+
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/stored/Address.java b/src/test/java/com/amazon/carbonado/stored/Address.java
new file mode 100644
index 0000000..3043e54
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/stored/Address.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.stored;
+
+import com.amazon.carbonado.Alias;
+import com.amazon.carbonado.Independent;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.Nullable;
+import com.amazon.carbonado.PrimaryKey;
+import com.amazon.carbonado.Sequence;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+@Alias("TEST_ADDRESS")
+@PrimaryKey("addressID")
+public interface Address extends Storable {
+ @Sequence("TEST_ADDRESS_ID_SEQ")
+ long getAddressID();
+ void setAddressID(long id);
+
+ String getAddressLine1();
+ void setAddressLine1(String value);
+
+ @Nullable
+ String getAddressLine2();
+ void setAddressLine2(String value);
+
+ String getAddressCity();
+ void setAddressCity(String value);
+
+ @Nullable
+ String getAddressState();
+ void setAddressState(String value);
+
+ String getAddressZip();
+ void setAddressZip(String value);
+
+ String getAddressCountry();
+ void setAddressCountry(String value);
+
+ @Independent
+ String getCustomData();
+ void setCustomData(String str);
+}
+
diff --git a/src/test/java/com/amazon/carbonado/stored/Dummy.java b/src/test/java/com/amazon/carbonado/stored/Dummy.java
new file mode 100644
index 0000000..980c718
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/stored/Dummy.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.stored;
+
+import com.amazon.carbonado.*;
+
+/**
+ * Implements all the Storable methods, but each throws
+ * UnsupportedOperationException. Methods defined in Object are left alone.
+ *
+ * @author Brian S O'Neill
+ */
+public class Dummy implements Storable {
+ public void load() throws FetchException {
+ throw error();
+ }
+
+ public boolean tryLoad() throws FetchException {
+ throw error();
+ }
+
+ public void insert() throws PersistException {
+ throw error();
+ }
+
+ public boolean tryInsert() throws PersistException {
+ throw error();
+ }
+
+ public void update() throws PersistException {
+ throw error();
+ }
+
+ public boolean tryUpdate() throws PersistException {
+ throw error();
+ }
+
+ public void delete() throws PersistException {
+ throw error();
+ }
+
+ public boolean tryDelete() throws PersistException {
+ throw error();
+ }
+
+ public Storage storage() {
+ throw error();
+ }
+
+ public Class storableType() {
+ throw error();
+ }
+
+ public void copyAllProperties(Storable target) {
+ throw error();
+ }
+
+ public void copyPrimaryKeyProperties(Storable target) {
+ throw error();
+ }
+
+ public void copyVersionProperty(Storable target) {
+ throw error();
+ }
+
+ public void copyUnequalProperties(Storable target) {
+ throw error();
+ }
+
+ public void copyDirtyProperties(Storable target) {
+ throw error();
+ }
+
+ public boolean hasDirtyProperties() {
+ throw error();
+ }
+
+ public void markPropertiesClean() {
+ throw error();
+ }
+
+ public void markAllPropertiesClean() {
+ throw error();
+ }
+
+ public void markPropertiesDirty() {
+ throw error();
+ }
+
+ public void markAllPropertiesDirty() {
+ throw error();
+ }
+
+ public boolean isPropertyUninitialized(String propertyName) {
+ throw error();
+ }
+
+ public boolean isPropertyDirty(String propertyName) {
+ throw error();
+ }
+
+ public boolean isPropertyClean(String propertyName) {
+ throw error();
+ }
+
+ public boolean isPropertySupported(String propertyName) {
+ throw error();
+ }
+
+ public Storable copy() {
+ throw error();
+ }
+
+ public boolean equalPrimaryKeys(Object obj) {
+ throw error();
+ }
+
+ public boolean equalProperties(Object obj) {
+ throw error();
+ }
+
+ public String toStringKeyOnly() {
+ throw error();
+ }
+
+ protected UnsupportedOperationException error() {
+ return new UnsupportedOperationException();
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/stored/StorableTestBasic.java b/src/test/java/com/amazon/carbonado/stored/StorableTestBasic.java
new file mode 100644
index 0000000..0857518
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/stored/StorableTestBasic.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.amazon.carbonado.stored;
+
+import java.util.Random;
+
+import org.joda.time.DateTime;
+
+import com.amazon.carbonado.Nullable;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.PrimaryKey;
+import com.amazon.carbonado.Storage;
+import com.amazon.carbonado.Repository;
+import com.amazon.carbonado.RepositoryException;
+
+/**
+ * StorableTestBasic
+ *
+ * @author Don Schneider
+ */
+@PrimaryKey("id")
+public abstract class StorableTestBasic implements Storable {
+ public abstract int getId();
+ public abstract void setId(int id);
+
+ // Basic coverage of the primitives
+ public abstract String getStringProp();
+ public abstract void setStringProp(String aStringThing);
+
+ public abstract int getIntProp();
+ public abstract void setIntProp(int anInt);
+
+ public abstract long getLongProp();
+ public abstract void setLongProp(long aLong);
+
+ public abstract double getDoubleProp();
+ public abstract void setDoubleProp(double aDouble);
+
+ @Nullable
+ public abstract DateTime getDate();
+ public abstract void setDate(DateTime aDate);
+
+ public void initPrimaryKeyProperties() {
+ setId(10);
+ }
+
+ public void initBasicProperties() {
+ setStringProp("foo");
+ setIntProp(10);
+ setLongProp(120);
+ setDoubleProp(1.2);
+ }
+
+ public void initPropertiesRandomly(int id) {
+ setId(id);
+
+ Random random = new Random(1000);
+
+ setIntProp(random.nextInt());
+ setLongProp(random.nextLong());
+ setDoubleProp(random.nextDouble());
+ setStringProp("imaString_" + id % 10);
+ }
+
+ public void initPropertiesPredictably(int id) {
+ setId(id);
+
+ setIntProp(id*10);
+ setLongProp(id*10);
+ setDoubleProp(id/2.0);
+ setStringProp("string-" + id % 100);
+ }
+
+ public static void insertBunches(Repository repository, int count)
+ throws RepositoryException
+ {
+ insertBunches(repository, count, 0, true);
+ }
+
+
+ public static void insertBunches(Repository repository,
+ int count, int startId,
+ boolean doRandom)
+ throws RepositoryException
+ {
+ Storage<StorableTestBasic> storage = repository.storageFor(StorableTestBasic.class);
+ StorableTestBasic s;
+
+ for (int i = 0; i < count; i ++) {
+ s = storage.prepare();
+ if (doRandom) {
+ s.initPropertiesRandomly(i);
+ } else {
+ s.initPropertiesPredictably(i+startId);
+ }
+ s.insert();
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/stored/StorableTestMinimal.java b/src/test/java/com/amazon/carbonado/stored/StorableTestMinimal.java
new file mode 100644
index 0000000..a1aae70
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/stored/StorableTestMinimal.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.amazon.carbonado.stored;
+
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.PrimaryKey;
+
+/**
+ * StorableTestBasic
+ *
+ * @author Don Schneider
+ */
+@PrimaryKey("id")
+public interface StorableTestMinimal extends Storable {
+ int getId();
+ void setId(int id);
+}
diff --git a/src/test/java/com/amazon/carbonado/util/TestBelatedCreator.java b/src/test/java/com/amazon/carbonado/util/TestBelatedCreator.java
new file mode 100644
index 0000000..99e927f
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/util/TestBelatedCreator.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.util;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestBelatedCreator extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestBelatedCreator.class);
+ }
+
+ public TestBelatedCreator(String name) {
+ super(name);
+ }
+
+ public void test_noProblems() {
+ Creator c = new Creator(0, 0, false);
+ TheObject obj = c.get(1000);
+ assertTrue(obj.isReal());
+ assertEquals("real", obj.toString());
+
+ obj.doSomething();
+ assertEquals(100, obj.getValue());
+ assertEquals("12a", obj.doSomething(1, 2, "a"));
+
+ assertEquals(0, c.mTimedOutCount);
+ assertEquals(1, c.mCreatedCount);
+ }
+
+ public void test_immediateFailure() {
+ Creator c = new Creator(60000, 0, true);
+ TheObject obj = c.get(1000);
+ assertFalse(obj.isReal());
+ assertEquals("bogus", obj.toString());
+
+ try {
+ obj.doSomething();
+ fail();
+ } catch (RuntimeException e) {
+ }
+ assertEquals(-1, obj.getValue());
+ assertNull(obj.doSomething(1, 2, "a"));
+
+ assertEquals(0, c.mTimedOutCount);
+ assertEquals(0, c.mCreatedCount);
+
+ assertTrue(obj == c.get(1000));
+ assertTrue(obj.equals(c.get(1000)));
+ }
+
+ public void test_longDelay() {
+ Creator c = new Creator(60000, 5000, false);
+
+ long start, end;
+ TheObject obj;
+
+ start = System.nanoTime();
+ obj = c.get(1000);
+ end = System.nanoTime();
+ assertFalse(obj.isReal());
+ assertEquals("bogus", obj.toString());
+ assertTrue((end - start) >= 1000L * 1000000);
+
+ start = System.nanoTime();
+ obj = c.get(1000);
+ end = System.nanoTime();
+ assertFalse(obj.isReal());
+ assertEquals("bogus", obj.toString());
+ assertTrue((end - start) >= 1000L * 1000000);
+
+ assertEquals(-1, obj.getValue());
+ assertNull(obj.doSomething(1, 2, "a"));
+
+ assertEquals(2, c.mTimedOutCount);
+ assertEquals(0, c.mCreatedCount);
+
+ start = System.nanoTime();
+ TheObject obj2 = c.get(5000);
+ end = System.nanoTime();
+ assertTrue(obj2.isReal());
+ assertEquals("real", obj.toString());
+ assertTrue((end - start) <= 5000L * 1000000);
+
+ assertFalse(obj == obj2);
+ assertTrue(obj.isReal());
+ assertEquals("real", obj.toString());
+
+ assertEquals(100, obj.getValue());
+ assertEquals("12a", obj.doSomething(1, 2, "a"));
+ assertEquals(100, obj2.getValue());
+ assertEquals("23b", obj2.doSomething(2, 3, "b"));
+
+ assertEquals(2, c.mTimedOutCount);
+ assertEquals(1, c.mCreatedCount);
+
+ start = System.nanoTime();
+ TheObject obj3 = c.get(1000);
+ end = System.nanoTime();
+ assertTrue(obj3.isReal());
+ assertEquals("real", obj3.toString());
+ assertTrue((end - start) <= 1000L * 1000000);
+
+ assertTrue(obj2 == obj3);
+ assertEquals(2, c.mTimedOutCount);
+ assertEquals(1, c.mCreatedCount);
+ }
+
+ public void test_retry() throws Exception {
+ Creator c = new Creator(5000, 0, true);
+ TheObject obj = c.get(1000);
+ assertFalse(obj.isReal());
+ assertEquals("bogus", obj.toString());
+
+ Thread.sleep(6000);
+
+ assertTrue(obj.isReal());
+ assertEquals("real", obj.toString());
+ obj = c.get(1000);
+ assertTrue(obj.isReal());
+ assertEquals("real", obj.toString());
+ }
+
+ public interface TheObject {
+ public boolean isReal();
+
+ public void doSomething();
+
+ public int getValue();
+
+ public String doSomething(int a, long b, Object q);
+
+ public String toString();
+ }
+
+ private class Creator extends BelatedCreator<TheObject, RuntimeException> {
+ final int mCreateDelay;
+ boolean mFailOnce;
+
+ int mTimedOutCount;
+ int mCreatedCount;
+
+ Creator(int retryMillis, int createDelay, boolean failOnce) {
+ super(TheObject.class, retryMillis);
+ mCreateDelay = createDelay;
+ mFailOnce = failOnce;
+ }
+
+ protected TheObject createReal() {
+ assertTrue(mCreatedCount == 0);
+ try {
+ Thread.sleep(mCreateDelay);
+ } catch (InterruptedException e) {
+ }
+
+ if (mFailOnce) {
+ mFailOnce = false;
+ return null;
+ }
+
+ return new TheObject() {
+ public boolean isReal() {
+ return true;
+ }
+
+ public void doSomething() {
+ }
+
+ public int getValue() {
+ return 100;
+ }
+
+ public String doSomething(int a, long b, Object q) {
+ return "" + a + b + q;
+ }
+
+ public String toString() {
+ return "real";
+ }
+ };
+ }
+
+ protected TheObject createBogus() {
+ return new TheObject() {
+ public boolean isReal() {
+ return false;
+ }
+
+ public void doSomething() {
+ throw new RuntimeException();
+ }
+
+ public int getValue() {
+ return -1;
+ }
+
+ public String doSomething(int a, long b, Object q) {
+ return null;
+ }
+
+ public String toString() {
+ return "bogus";
+ }
+ };
+ }
+
+ protected void timedOutNotification(long timedOutMillis) {
+ assertTrue(timedOutMillis >= 0);
+ mTimedOutCount++;
+ }
+
+ @Override
+ protected void createdNotification(TheObject object) {
+ assertNotNull(object);
+ mCreatedCount++;
+ }
+ }
+}
+
diff --git a/src/test/java/com/amazon/carbonado/util/TestQuickConstructorGenerator.java b/src/test/java/com/amazon/carbonado/util/TestQuickConstructorGenerator.java
new file mode 100644
index 0000000..c9ba833
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/util/TestQuickConstructorGenerator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.util;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestQuickConstructorGenerator extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestQuickConstructorGenerator.class);
+ }
+
+ public TestQuickConstructorGenerator(String name) {
+ super(name);
+ }
+
+ public void testStringMaker() throws Exception {
+ StringMaker maker = QuickConstructorGenerator.getInstance(String.class, StringMaker.class);
+ assertEquals("", maker.newEmptyString());
+ assertEquals("hello", maker.newStringFromChars(new char[] {'h', 'e', 'l', 'l', 'o'}));
+ assertEquals("hello",
+ maker.newStringFromBytes(new byte[] {'h', 'e', 'l', 'l', 'o'}, "US-ASCII"));
+ }
+
+ public void testIllegalArgs() {
+ try {
+ QuickConstructorGenerator.getInstance(String.class, String.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ QuickConstructorGenerator.getInstance(String.class, BadStringMaker.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ QuickConstructorGenerator.getInstance(String.class, BadStringMaker2.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ QuickConstructorGenerator.getInstance(String.class, BadStringMaker3.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ QuickConstructorGenerator.getInstance(byte[].class, StringMaker.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public static interface StringMaker {
+ Object newEmptyString();
+
+ String newStringFromChars(char[] chars);
+
+ String newStringFromBytes(byte[] bytes, String charsetName)
+ throws java.io.UnsupportedEncodingException;
+ }
+
+ public static interface BadStringMaker {
+ String newStringFromBytes(byte[] bytes, String charsetName);
+ }
+
+ public static interface BadStringMaker2 {
+ String newStringFromClass(Class clazz);
+ }
+
+ public static interface BadStringMaker3 {
+ Class newEmptyString();
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/util/TestThrowUnchecked.java b/src/test/java/com/amazon/carbonado/util/TestThrowUnchecked.java
new file mode 100644
index 0000000..739a709
--- /dev/null
+++ b/src/test/java/com/amazon/carbonado/util/TestThrowUnchecked.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.util;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestThrowUnchecked extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestThrowUnchecked.class);
+ }
+
+ public TestThrowUnchecked(String name) {
+ super(name);
+ }
+
+ public void test() {
+ ThrowUnchecked.fire(null);
+
+ Exception e = new java.io.IOException();
+
+ try {
+ ThrowUnchecked.fire(e);
+ fail();
+ } catch (Exception e2) {
+ assertEquals(e, e2);
+ }
+ }
+}