/*
* Copyright (C) 2011 The Guava Authors
*
* 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.google.common.collect;
import static com.google.common.collect.BoundType.CLOSED;
import static com.google.common.collect.BoundType.OPEN;
import static com.google.common.collect.BstSide.LEFT;
import static com.google.common.collect.BstSide.RIGHT;
import static com.google.common.collect.BstTesting.assertInOrderTraversalIs;
import static com.google.common.collect.BstTesting.balancePolicy;
import static com.google.common.collect.BstTesting.countAggregate;
import static com.google.common.collect.BstTesting.defaultNullPointerTester;
import static com.google.common.collect.BstTesting.nodeFactory;
import static com.google.common.collect.BstTesting.pathFactory;
import static com.google.common.collect.BstTesting.pathToList;
import static org.junit.contrib.truth.Truth.ASSERT;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.BstTesting.SimpleNode;
import junit.framework.TestCase;
import java.util.SortedSet;
/**
* Tests for {@code BSTRangeOps}.
*
* @author Louis Wasserman
*/
@GwtCompatible(emulated = true)
public class BstRangeOpsTest extends TestCase {
private static final SortedSet<Character> MODEL =
ImmutableSortedSet.of('a', 'b', 'c', 'd', 'e', 'f', 'g');
private static final SimpleNode ROOT;
static {
SimpleNode a = new SimpleNode('a', null, null);
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', a, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
ROOT = d;
}
public void testCountInRangeLowerBound() {
for (char c : "abcdefg".toCharArray()) {
for (BoundType type : BoundType.values()) {
long count = BstRangeOps.totalInRange(
countAggregate, GeneralRange.downTo(Ordering.natural(), c, type), ROOT);
char d = c;
if (type == BoundType.OPEN) {
d++;
}
assertEquals(MODEL.tailSet(d).size(), count);
}
}
}
public void testCountInRangeUpperBound() {
for (char c : "abcdefg".toCharArray()) {
for (BoundType type : BoundType.values()) {
long count = BstRangeOps.totalInRange(
countAggregate, GeneralRange.upTo(Ordering.natural(), c, type), ROOT);
char d = c;
if (type == BoundType.CLOSED) {
d++;
}
assertEquals(MODEL.headSet(d).size(), count);
}
}
}
public void testCountInRangeBothBounds() {
String chars = "abcdefg";
for (int i = 0; i < chars.length(); i++) {
for (BoundType lb : BoundType.values()) {
for (int j = i; j < chars.length(); j++) {
for (BoundType ub : BoundType.values()) {
if (i == j && lb == BoundType.OPEN && ub == BoundType.OPEN) {
continue;
}
long count = BstRangeOps.totalInRange(countAggregate, GeneralRange.range(
Ordering.natural(), chars.charAt(i), lb, chars.charAt(j), ub), ROOT);
char lo = chars.charAt(i);
if (lb == BoundType.OPEN) {
lo++;
}
char hi = chars.charAt(j);
if (ub == BoundType.CLOSED) {
hi++;
}
if (lo > hi) {
lo = hi;
}
assertEquals(MODEL.subSet(lo, hi).size(), count);
}
}
}
}
}
public void testCountInRangeAll() {
assertEquals(MODEL.size(), BstRangeOps.totalInRange(
countAggregate, GeneralRange.<Character>all(Ordering.natural()), ROOT));
}
public void testCountInRangeEmpty() {
SimpleNode empty = null;
GeneralRange<Character> range = GeneralRange.all(Ordering.natural());
assertEquals(0, BstRangeOps.totalInRange(countAggregate, range, empty));
}
public void testClearRangeLowerBound() {
// d
// / \
// b f
// / / \
// a e g
SimpleNode a = new SimpleNode('a', null, null);
SimpleNode b = new SimpleNode('b', a, null);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
assertInOrderTraversalIs(d, "abdefg");
GeneralRange<Character> range1 = GeneralRange.downTo(Ordering.natural(), 'f', CLOSED);
testTraversalAfterClearingRangeIs(d, range1, "abde");
GeneralRange<Character> range2 = GeneralRange.downTo(Ordering.natural(), 'f', OPEN);
testTraversalAfterClearingRangeIs(d, range2, "abdef");
GeneralRange<Character> range3 = GeneralRange.downTo(Ordering.natural(), 'a', CLOSED);
testTraversalAfterClearingRangeIs(d, range3, "");
GeneralRange<Character> range4 = GeneralRange.downTo(Ordering.natural(), 'a', OPEN);
testTraversalAfterClearingRangeIs(d, range4, "a");
GeneralRange<Character> range5 = GeneralRange.downTo(Ordering.natural(), 'c', OPEN);
testTraversalAfterClearingRangeIs(d, range5, "ab");
GeneralRange<Character> range6 = GeneralRange.downTo(Ordering.natural(), 'c', CLOSED);
testTraversalAfterClearingRangeIs(d, range6, "ab");
}
public void testClearRangeUpperBound() {
// d
// / \
// b f
// / / \
// a e g
SimpleNode a = new SimpleNode('a', null, null);
SimpleNode b = new SimpleNode('b', a, null);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
assertInOrderTraversalIs(d, "abdefg");
GeneralRange<Character> range1 = GeneralRange.upTo(Ordering.natural(), 'f', CLOSED);
testTraversalAfterClearingRangeIs(d, range1, "g");
GeneralRange<Character> range2 = GeneralRange.upTo(Ordering.natural(), 'f', OPEN);
testTraversalAfterClearingRangeIs(d, range2, "fg");
GeneralRange<Character> range3 = GeneralRange.upTo(Ordering.natural(), 'a', CLOSED);
testTraversalAfterClearingRangeIs(d, range3, "bdefg");
GeneralRange<Character> range4 = GeneralRange.upTo(Ordering.natural(), 'a', OPEN);
testTraversalAfterClearingRangeIs(d, range4, "abdefg");
GeneralRange<Character> range5 = GeneralRange.upTo(Ordering.natural(), 'c', OPEN);
testTraversalAfterClearingRangeIs(d, range5, "defg");
GeneralRange<Character> range6 = GeneralRange.upTo(Ordering.natural(), 'c', CLOSED);
testTraversalAfterClearingRangeIs(d, range6, "defg");
}
public void testClearRangeDoublyBounded() {
// d
// / \
// b f
// / \ / \
// a c e g
SimpleNode a = new SimpleNode('a', null, null);
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', a, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 =
GeneralRange.range(Ordering.natural(), 'c', OPEN, 'f', CLOSED);
testTraversalAfterClearingRangeIs(d, range1, "abcg");
GeneralRange<Character> range2 =
GeneralRange.range(Ordering.natural(), 'a', CLOSED, 'h', OPEN);
testTraversalAfterClearingRangeIs(d, range2, "");
}
public void testClearRangeAll() {
// d
// / \
// b f
// / \ / \
// a c e g
SimpleNode a = new SimpleNode('a', null, null);
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', a, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
testTraversalAfterClearingRangeIs(d, GeneralRange.<Character>all(Ordering.natural()), "");
}
private void testTraversalAfterClearingRangeIs(
SimpleNode d, GeneralRange<Character> range, String expected) {
assertInOrderTraversalIs(
BstRangeOps.minusRange(range, balancePolicy, nodeFactory, d), expected);
}
public void testLeftmostPathAll() {
// d
// / \
// b f
// \ / \
// c e g
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', null, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 = GeneralRange.all(Ordering.natural());
ASSERT.that(pathToList(BstRangeOps.furthestPath(range1, LEFT, pathFactory, d)))
.hasContentsInOrder(b, d);
assertNull(BstRangeOps.furthestPath(range1, LEFT, pathFactory, null));
}
public void testLeftmostPathDownTo() {
// d
// / \
// b f
// \ / \
// c e g
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', null, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 = GeneralRange.downTo(Ordering.natural(), 'd', OPEN);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range1, LEFT, pathFactory, d)))
.hasContentsInOrder(e, f, d);
GeneralRange<Character> range2 = GeneralRange.downTo(Ordering.natural(), 'd', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range2, LEFT, pathFactory, d)))
.hasContentsInOrder(d);
GeneralRange<Character> range3 = GeneralRange.downTo(Ordering.natural(), 'a', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range3, LEFT, pathFactory, d)))
.hasContentsInOrder(b, d);
GeneralRange<Character> range4 = GeneralRange.downTo(Ordering.natural(), 'h', CLOSED);
assertNull(BstRangeOps.furthestPath(range4, LEFT, pathFactory, d));
}
public void testLeftmostPathUpTo() {
// d
// / \
// b f
// \ / \
// c e g
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', null, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 = GeneralRange.upTo(Ordering.natural(), 'd', OPEN);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range1, LEFT, pathFactory, d)))
.hasContentsInOrder(b, d);
GeneralRange<Character> range2 = GeneralRange.upTo(Ordering.natural(), 'd', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range2, LEFT, pathFactory, d)))
.hasContentsInOrder(b, d);
GeneralRange<Character> range3 = GeneralRange.upTo(Ordering.natural(), 'a', CLOSED);
assertNull(BstRangeOps.furthestPath(range3, LEFT, pathFactory, d));
}
public void testRightmostPathAll() {
// d
// / \
// b f
// \ / \
// c e g
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', null, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 = GeneralRange.all(Ordering.natural());
ASSERT.that(pathToList(BstRangeOps.furthestPath(range1, RIGHT, pathFactory, d)))
.hasContentsInOrder(g, f, d);
assertNull(BstRangeOps.furthestPath(range1, RIGHT, pathFactory, null));
}
public void testRightmostPathDownTo() {
// d
// / \
// b f
// \ / \
// c e g
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', null, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 = GeneralRange.downTo(Ordering.natural(), 'd', OPEN);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range1, RIGHT, pathFactory, d)))
.hasContentsInOrder(g, f, d);
GeneralRange<Character> range2 = GeneralRange.downTo(Ordering.natural(), 'd', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range2, RIGHT, pathFactory, d)))
.hasContentsInOrder(g, f, d);
GeneralRange<Character> range3 = GeneralRange.downTo(Ordering.natural(), 'a', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range3, RIGHT, pathFactory, d)))
.hasContentsInOrder(g, f, d);
GeneralRange<Character> range4 = GeneralRange.downTo(Ordering.natural(), 'h', CLOSED);
assertNull(BstRangeOps.furthestPath(range4, RIGHT, pathFactory, d));
}
public void testRightmostPathUpTo() {
// d
// / \
// b f
// \ / \
// c e g
SimpleNode c = new SimpleNode('c', null, null);
SimpleNode b = new SimpleNode('b', null, c);
SimpleNode e = new SimpleNode('e', null, null);
SimpleNode g = new SimpleNode('g', null, null);
SimpleNode f = new SimpleNode('f', e, g);
SimpleNode d = new SimpleNode('d', b, f);
GeneralRange<Character> range1 = GeneralRange.upTo(Ordering.natural(), 'd', OPEN);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range1, RIGHT, pathFactory, d)))
.hasContentsInOrder(c, b, d);
GeneralRange<Character> range2 = GeneralRange.upTo(Ordering.natural(), 'd', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range2, RIGHT, pathFactory, d)))
.hasContentsInOrder(d);
GeneralRange<Character> range3 = GeneralRange.upTo(Ordering.natural(), 'a', CLOSED);
assertNull(BstRangeOps.furthestPath(range3, RIGHT, pathFactory, d));
GeneralRange<Character> range4 = GeneralRange.upTo(Ordering.natural(), 'h', CLOSED);
ASSERT.that(pathToList(BstRangeOps.furthestPath(range4, RIGHT, pathFactory, d)))
.hasContentsInOrder(g, f, d);
}
@GwtIncompatible("NullPointerTester")
public void testNullPointers() throws Exception {
defaultNullPointerTester().testAllPublicStaticMethods(BstRangeOps.class);
}
}