/*
* 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.base.Preconditions.checkNotNull;
import static com.google.common.collect.BstSide.LEFT;
import static com.google.common.collect.BstSide.RIGHT;
import static junit.framework.Assert.assertEquals;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Objects;
import com.google.common.testing.NullPointerTester;
import java.util.List;
import javax.annotation.Nullable;
/**
* Testing classes and utilities to be used in tests of the binary search tree framework.
*
* @author Louis Wasserman
*/
@GwtCompatible(emulated = true)
public class BstTesting {
static final class SimpleNode extends BstNode<Character, SimpleNode> {
SimpleNode(Character key, @Nullable SimpleNode left, @Nullable SimpleNode right) {
super(key, left, right);
}
@Override
public String toString() {
return getKey().toString();
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj instanceof SimpleNode) {
SimpleNode node = (SimpleNode) obj;
return getKey().equals(node.getKey())
&& Objects.equal(childOrNull(LEFT), node.childOrNull(LEFT))
&& Objects.equal(childOrNull(RIGHT), node.childOrNull(RIGHT));
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), childOrNull(LEFT), childOrNull(RIGHT));
}
}
static final BstNodeFactory<SimpleNode> nodeFactory = new BstNodeFactory<SimpleNode>() {
@Override
public SimpleNode createNode(
SimpleNode source, @Nullable SimpleNode left, @Nullable SimpleNode right) {
return new SimpleNode(source.getKey(), left, right);
}
};
static final BstBalancePolicy<SimpleNode> balancePolicy = new BstBalancePolicy<SimpleNode>() {
@Override
public SimpleNode balance(BstNodeFactory<SimpleNode> nodeFactory, SimpleNode source,
@Nullable SimpleNode left, @Nullable SimpleNode right) {
return checkNotNull(nodeFactory).createNode(source, left, right);
}
@Nullable
@Override
public SimpleNode combine(BstNodeFactory<SimpleNode> nodeFactory, @Nullable SimpleNode left,
@Nullable SimpleNode right) {
// Shove right into the rightmost position in the left tree.
if (left == null) {
return right;
} else if (right == null) {
return left;
} else if (left.hasChild(RIGHT)) {
return nodeFactory.createNode(
left, left.childOrNull(LEFT), combine(nodeFactory, left.childOrNull(RIGHT), right));
} else {
return nodeFactory.createNode(left, left.childOrNull(LEFT), right);
}
}
};
static final BstPathFactory<SimpleNode, BstInOrderPath<SimpleNode>> pathFactory =
BstInOrderPath.inOrderFactory();
// A direct, if dumb, way to count total nodes in a tree.
static final BstAggregate<SimpleNode> countAggregate = new BstAggregate<SimpleNode>() {
@Override
public int entryValue(SimpleNode entry) {
return 1;
}
@Override
public long treeValue(@Nullable SimpleNode tree) {
if (tree == null) {
return 0;
} else {
return 1 + treeValue(tree.childOrNull(LEFT)) + treeValue(tree.childOrNull(RIGHT));
}
}
};
static <P extends BstPath<SimpleNode, P>> List<SimpleNode> pathToList(P path) {
List<SimpleNode> list = Lists.newArrayList();
for (; path != null; path = path.prefixOrNull()) {
list.add(path.getTip());
}
return list;
}
static <N extends BstNode<?, N>, P extends BstPath<N, P>> P extension(
BstPathFactory<N, P> factory, N root, BstSide... sides) {
P path = factory.initialPath(root);
for (BstSide side : sides) {
path = factory.extension(path, side);
}
return path;
}
static void assertInOrderTraversalIs(@Nullable SimpleNode root, String order) {
if (root == null) {
assertEquals("", order);
} else {
BstInOrderPath<SimpleNode> path = pathFactory.initialPath(root);
while (path.getTip().hasChild(LEFT)) {
path = pathFactory.extension(path, LEFT);
}
assertEquals(order.charAt(0), path
.getTip()
.getKey()
.charValue());
int i;
for (i = 1; path.hasNext(RIGHT); i++) {
path = path.next(RIGHT);
assertEquals(order.charAt(i), path
.getTip()
.getKey()
.charValue());
}
assertEquals(i, order.length());
}
}
@GwtIncompatible("NullPointerTester")
static NullPointerTester defaultNullPointerTester() {
NullPointerTester tester = new NullPointerTester();
SimpleNode node = new SimpleNode('a', null, null);
tester.setDefault(BstNode.class, node);
tester.setDefault(BstSide.class, LEFT);
tester.setDefault(BstNodeFactory.class, nodeFactory);
tester.setDefault(BstBalancePolicy.class, balancePolicy);
tester.setDefault(BstPathFactory.class, pathFactory);
tester.setDefault(BstPath.class, pathFactory.initialPath(node));
tester.setDefault(BstInOrderPath.class, pathFactory.initialPath(node));
tester.setDefault(Object.class, 'a');
tester.setDefault(GeneralRange.class, GeneralRange.all(Ordering.natural()));
tester.setDefault(BstAggregate.class, countAggregate);
BstModifier<Character, SimpleNode> modifier = new BstModifier<Character, SimpleNode>() {
@Nullable
@Override
public BstModificationResult<SimpleNode> modify(
Character key, @Nullable SimpleNode originalEntry) {
return BstModificationResult.identity(originalEntry);
}
};
tester.setDefault(
BstModificationResult.class, BstModificationResult.<SimpleNode>identity(null));
tester.setDefault(BstModifier.class, modifier);
tester.setDefault(
BstMutationRule.class, BstMutationRule.createRule(modifier, balancePolicy, nodeFactory));
return tester;
}
}