/* * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Tests for the red-black tree class. #include "config.h" #include "PODRedBlackTree.h" #include "ArenaTestHelpers.h" #include "TreeTestHelpers.h" #include <gtest/gtest.h> #include <wtf/Vector.h> namespace WebCore { using ArenaTestHelpers::TrackedAllocator; using TreeTestHelpers::generateSeed; using TreeTestHelpers::initRandom; using TreeTestHelpers::nextRandom; TEST(PODRedBlackTreeTest, TestTreeAllocatesFromArena) { RefPtr<TrackedAllocator> allocator = TrackedAllocator::create(); { RefPtr<PODArena> arena = PODArena::create(allocator); PODRedBlackTree<int> tree(arena); int numAdditions = 2 * PODArena::DefaultChunkSize / sizeof(int); for (int i = 0; i < numAdditions; ++i) tree.add(i); EXPECT_GT(allocator->numRegions(), 1); } EXPECT_EQ(allocator->numRegions(), 0); } TEST(PODRedBlackTreeTest, TestSingleElementInsertion) { PODRedBlackTree<int> tree; tree.add(5); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(5)); } TEST(PODRedBlackTreeTest, TestMultipleElementInsertion) { PODRedBlackTree<int> tree; tree.add(4); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(4)); tree.add(3); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(3)); tree.add(5); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(5)); EXPECT_TRUE(tree.contains(4)); EXPECT_TRUE(tree.contains(3)); } TEST(PODRedBlackTreeTest, TestDuplicateElementInsertion) { PODRedBlackTree<int> tree; tree.add(3); ASSERT_TRUE(tree.checkInvariants()); tree.add(3); ASSERT_TRUE(tree.checkInvariants()); tree.add(3); ASSERT_TRUE(tree.checkInvariants()); EXPECT_EQ(3, tree.size()); EXPECT_TRUE(tree.contains(3)); } TEST(PODRedBlackTreeTest, TestSingleElementInsertionAndDeletion) { PODRedBlackTree<int> tree; tree.add(5); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(5)); tree.remove(5); ASSERT_TRUE(tree.checkInvariants()); EXPECT_FALSE(tree.contains(5)); } TEST(PODRedBlackTreeTest, TestMultipleElementInsertionAndDeletion) { PODRedBlackTree<int> tree; tree.add(4); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(4)); tree.add(3); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(3)); tree.add(5); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(5)); EXPECT_TRUE(tree.contains(4)); EXPECT_TRUE(tree.contains(3)); tree.remove(4); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(3)); EXPECT_FALSE(tree.contains(4)); EXPECT_TRUE(tree.contains(5)); tree.remove(5); ASSERT_TRUE(tree.checkInvariants()); EXPECT_TRUE(tree.contains(3)); EXPECT_FALSE(tree.contains(4)); EXPECT_FALSE(tree.contains(5)); EXPECT_EQ(1, tree.size()); } TEST(PODRedBlackTreeTest, TestDuplicateElementInsertionAndDeletion) { PODRedBlackTree<int> tree; tree.add(3); ASSERT_TRUE(tree.checkInvariants()); tree.add(3); ASSERT_TRUE(tree.checkInvariants()); tree.add(3); ASSERT_TRUE(tree.checkInvariants()); EXPECT_EQ(3, tree.size()); EXPECT_TRUE(tree.contains(3)); tree.remove(3); ASSERT_TRUE(tree.checkInvariants()); tree.remove(3); ASSERT_TRUE(tree.checkInvariants()); EXPECT_EQ(1, tree.size()); EXPECT_TRUE(tree.contains(3)); tree.remove(3); ASSERT_TRUE(tree.checkInvariants()); EXPECT_EQ(0, tree.size()); EXPECT_FALSE(tree.contains(3)); } TEST(PODRedBlackTreeTest, FailingInsertionRegressionTest1) { // These numbers came from a previously-failing randomized test run. PODRedBlackTree<int> tree; tree.add(5113); ASSERT_TRUE(tree.checkInvariants()); tree.add(4517); ASSERT_TRUE(tree.checkInvariants()); tree.add(3373); ASSERT_TRUE(tree.checkInvariants()); tree.add(9307); ASSERT_TRUE(tree.checkInvariants()); tree.add(7077); ASSERT_TRUE(tree.checkInvariants()); } namespace { void InsertionAndDeletionTest(const int32_t seed, const int treeSize) { initRandom(seed); const int maximumValue = treeSize; // Build the tree. PODRedBlackTree<int> tree; Vector<int> values; for (int i = 0; i < treeSize; i++) { int value = nextRandom(maximumValue); tree.add(value); ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; values.append(value); } // Churn the tree's contents. for (int i = 0; i < treeSize; i++) { // Pick a random value to remove. int index = nextRandom(treeSize); int value = values[index]; // Remove this value. tree.remove(value); ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; // Replace it with a new one. value = nextRandom(maximumValue); values[index] = value; tree.add(value); ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; } } } // anonymous namespace TEST(PODRedBlackTreeTest, RandomDeletionAndInsertionRegressionTest1) { InsertionAndDeletionTest(12311, 100); } TEST(PODRedBlackTreeTest, TestRandomDeletionAndInsertion) { InsertionAndDeletionTest(generateSeed(), 100); } } // namespace WebCore