Chromium Code Reviews| Index: ui/gfx/geometry/r_tree_unittest.cc |
| diff --git a/ui/gfx/geometry/r_tree_unittest.cc b/ui/gfx/geometry/r_tree_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7e8a922c26830fcaebaec4350a479d1b24401049 |
| --- /dev/null |
| +++ b/ui/gfx/geometry/r_tree_unittest.cc |
| @@ -0,0 +1,214 @@ |
| +// Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <set> |
| + |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "ui/gfx/geometry/r_tree.h" |
| +#include "ui/gfx/geometry/rect.h" |
| + |
| +namespace gfx { |
|
piman
2014/04/21 23:59:31
I think we want to add several tests around all th
luken
2014/04/28 01:33:34
Done.
|
| + |
| +// Adds count squares stacked around the point (0,0) with key equal to width. |
| +void AddStackedSquares(RTree* rt, int count) { |
| + for (int i = 1; i <= count; ++i) { |
| + rt->Insert(Rect(0, 0, i, i), reinterpret_cast<void*>(i)); |
| + EXPECT_TRUE(rt->Validate()); |
| + } |
| +} |
| + |
| +// Given an unordered list of matching keys, verify that it contains all values |
| +// [1..length] for the length of that list. |
| +void VerifyAllKeys(const std::set<void*>& keys) { |
| + // Verify that each key was uniquely identified. |
| + int c = 1; |
| + for (std::set<void*>::const_iterator it = keys.begin(); |
| + it != keys.end(); |
| + it++) { |
| + // Verify that the keys are in values [1,count]. |
| + EXPECT_EQ(c, reinterpret_cast<int>((*it))); |
|
piman
2014/04/21 23:59:31
nit: extra () around *it
luken
2014/04/28 01:33:34
Done.
|
| + ++c; |
| + } |
| +} |
| + |
| +// An empty RTree should never return Query results, and RTrees should be empty |
| +// upon construction. |
| +TEST(RTreeTest, QueryEmptyTree) { |
| + RTree rt(2, 10); |
| + EXPECT_TRUE(rt.Validate()); |
| + std::set<void*> results; |
| + Rect test_rect(25, 25); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 0U); |
| + EXPECT_TRUE(rt.Validate()); |
| +} |
| + |
| +// Clear should empty the tree, meaning that all queries should not return |
| +// results after. |
| +TEST(RTreeTest, ClearEmptiesTreeOfSingleNode) { |
| + RTree rt(2, 5); |
| + rt.Insert(Rect(0, 0, 100, 100), reinterpret_cast<void*>(1)); |
| + rt.Clear(); |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 0U); |
| +} |
| + |
| +// Even with a complex internal structure, clear should empty the tree, meaning |
| +// that all queries should not return results after. |
| +TEST(RTreeTest, ClearEmptiesTreeOfManyNodes) { |
| + RTree rt(2, 5); |
| + AddStackedSquares(&rt, 100); |
| + rt.Clear(); |
| + EXPECT_TRUE(rt.Validate()); |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 0U); |
| +} |
| + |
| +// Duplicate inserts should overwrite previous inserts. |
| +TEST(RTreeTest, DuplicateInsertsOverwrite) { |
| + RTree rt(2, 5); |
| + // Add 100 stacked squares, but always with duplicate key of 1. |
| + for (int i = 1; i <= 100; ++i) { |
| + rt.Insert(Rect(0, 0, i, i), reinterpret_cast<void*>(1)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 1U); |
| + EXPECT_EQ(reinterpret_cast<int>(*(results.begin())), 1); |
| +} |
| + |
| +// Call Remove() once on something that's been inserted repeatedly. |
| +TEST(RTreeTest, DuplicateInsertRemove) { |
| + RTree rt(3, 9); |
| + AddStackedSquares(&rt, 25); |
| + for (int i = 1; i <= 100; ++i) { |
| + rt.Insert(Rect(0, 0, i, i), reinterpret_cast<void*>(26)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + rt.Remove(reinterpret_cast<void*>(26)); |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 25U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +// Call Remove() repeatedly on something that's been inserted once. |
| +TEST(RTreeTest, InsertDuplicateRemove) { |
| + RTree rt(7, 15); |
| + AddStackedSquares(&rt, 101); |
| + for (int i = 0; i < 100; ++i) { |
| + rt.Remove(reinterpret_cast<void*>(101)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 100U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +// Stacked rects should meet all matching queries regardless of nesting. |
| +TEST(RTreeTest, QueryStackedSquaresNestedHit) { |
| + RTree rt(2, 5); |
| + AddStackedSquares(&rt, 100); |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 100U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +// Stacked rects should meet all matching queries when contained completely by |
| +// the query rectangle. |
| +TEST(RTreeTest, QueryStackedSquaresContainedHit) { |
| + RTree rt(2, 10); |
| + AddStackedSquares(&rt, 100); |
| + std::set<void*> results; |
| + Rect test_rect(0, 0, 100, 100); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 100U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +// Stacked rects should miss a missing query when the query has no intersection |
| +// with the rects. |
| +TEST(RTreeTest, QueryStackedSquaresCompleteMiss) { |
| + RTree rt(2, 7); |
| + AddStackedSquares(&rt, 100); |
| + std::set<void*> results; |
| + Rect test_rect(150, 150, 100, 100); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 0U); |
| +} |
| + |
| +// Removing half the nodes after insertion should still result in a valid tree. |
| +TEST(RTreeTest, RemoveHalfStackedRects) { |
| + RTree rt(2, 11); |
| + AddStackedSquares(&rt, 200); |
| + for (int i = 101; i <= 200; ++i) { |
| + rt.Remove(reinterpret_cast<void*>(i)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + std::set<void*> results; |
| + Rect test_rect(1, 1); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 100U); |
| + VerifyAllKeys(results); |
| + // Add the nodes back in. |
| + for (int i = 101; i <= 200; ++i) { |
| + rt.Insert(Rect(0, 0, i, i), reinterpret_cast<void*>(i)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + results.clear(); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 200U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +TEST(RTreeTest, InsertNegativeCoordsRect) { |
| + RTree rt(5, 11); |
| + for (int i = 1; i <= 100; ++i) { |
| + rt.Insert(Rect(-i, -i, i, i), reinterpret_cast<void*>((i * 2) - 1)); |
| + EXPECT_TRUE(rt.Validate()); |
| + rt.Insert(Rect(0, 0, i, i), reinterpret_cast<void*>(i * 2)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + std::set<void*> results; |
| + Rect test_rect(-1, -1, 2, 2); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 200U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +TEST(RTreeTest, RemoveNegativeCoordsRect) { |
| + RTree rt(7, 21); |
| + // Add 100 positive stacked squares. |
| + AddStackedSquares(&rt, 100); |
| + // Now add 100 negative stacked squares. |
| + for (int i = 101; i <= 200; ++i) { |
| + rt.Insert(Rect(100 - i, 100 - i, i - 100, i - 100), |
| + reinterpret_cast<void*>(301 - i)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + // Now remove half of the negative squares. |
| + for (int i = 101; i <= 150; ++i) { |
| + rt.Remove(reinterpret_cast<void*>(301 - i)); |
| + EXPECT_TRUE(rt.Validate()); |
| + } |
| + // Queries should return 100 positive and 50 negative stacked squares. |
| + std::set<void*> results; |
| + Rect test_rect(-1, -1, 2, 2); |
| + rt.Query(test_rect, &results); |
| + EXPECT_EQ(results.size(), 150U); |
| + VerifyAllKeys(results); |
| +} |
| + |
| +} // namespace gfx |