| Index: chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc
|
| diff --git a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc b/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a9e48df8bc4036249670cf8f1300bf679ec06f4d
|
| --- /dev/null
|
| +++ b/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc
|
| @@ -0,0 +1,165 @@
|
| +// Copyright 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 <algorithm>
|
| +#include <vector>
|
| +
|
| +#include "base/memory/ref_counted.h"
|
| +#include "chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +#define MAX_CACHE_SIZE 5u
|
| +
|
| +namespace {
|
| +
|
| +unsigned int GenerateValue(unsigned int key) {
|
| + return (key * key * 127) % 133 + key * 23;
|
| +}
|
| +
|
| +class MockObject {
|
| + public:
|
| + static scoped_ptr<MockObject> Create(unsigned int key) {
|
| + return make_scoped_ptr(new MockObject(key));
|
| + }
|
| +
|
| + unsigned int value() const { return value_; }
|
| +
|
| + private:
|
| + explicit MockObject(unsigned int key) : value_(GenerateValue(key)) {}
|
| + unsigned int value_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MockObject);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +typedef testing::Test ScopedPtrExpiringCacheTest;
|
| +typedef ScopedPtrExpiringCache<unsigned int, MockObject>
|
| + TestScopedPtrExpiringCache;
|
| +
|
| +TEST_F(ScopedPtrExpiringCacheTest, SimplePutAndGet) {
|
| + TestScopedPtrExpiringCache cache(MAX_CACHE_SIZE);
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cache.MaximumCacheSize());
|
| + EXPECT_EQ(0u, cache.size());
|
| +
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
|
| + cache.Put(i, MockObject::Create(i).Pass());
|
| + }
|
| +
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cache.size());
|
| +
|
| + unsigned int next_key = MAX_CACHE_SIZE;
|
| +
|
| + // One cache entry should have been evicted.
|
| + cache.Put(next_key, MockObject::Create(next_key).Pass());
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cache.size());
|
| +
|
| + size_t cached_count = 0;
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) {
|
| + if (cache.Get(i)) {
|
| + EXPECT_EQ(GenerateValue(i), cache.Get(i)->value());
|
| + cached_count++;
|
| + }
|
| + }
|
| +
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cached_count);
|
| +
|
| + // Test Get as membership test.
|
| + cached_count = 0;
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) {
|
| + if (cache.Get(i))
|
| + cached_count++;
|
| + }
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cached_count);
|
| +
|
| + cache.Clear();
|
| + EXPECT_EQ(0u, cache.size());
|
| +
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) {
|
| + EXPECT_EQ(NULL, cache.Get(i));
|
| + }
|
| +}
|
| +
|
| +// The eviction policy is least-recently-used, where we define used as insertion
|
| +// into the cache. We test that the first to be evicted is the first entry
|
| +// inserted into the cache.
|
| +TEST_F(ScopedPtrExpiringCacheTest, EvictedEntry) {
|
| + TestScopedPtrExpiringCache cache(MAX_CACHE_SIZE);
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
|
| + cache.Put(i, MockObject::Create(i).Pass());
|
| + }
|
| +
|
| + unsigned int next_key = MAX_CACHE_SIZE;
|
| + cache.Put(next_key, MockObject::Create(next_key).Pass());
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cache.size());
|
| + EXPECT_EQ(GenerateValue(next_key), cache.Get(next_key)->value());
|
| +
|
| + // The first inserted entry should have been evicted.
|
| + EXPECT_EQ(NULL, cache.Get(0));
|
| +
|
| + // The rest of the content should be present.
|
| + for (unsigned int i = 1; i < MAX_CACHE_SIZE; i++) {
|
| + EXPECT_TRUE(cache.Get(i) != NULL);
|
| + }
|
| +
|
| + next_key++;
|
| +
|
| + // The first candidate to be evicted is the head of the iterator.
|
| + unsigned int head_key = cache.begin()->first;
|
| + EXPECT_TRUE(cache.Get(head_key) != NULL);
|
| + cache.Put(next_key, MockObject::Create(next_key).Pass());
|
| +
|
| + EXPECT_NE(cache.begin()->first, head_key);
|
| + EXPECT_EQ(NULL, cache.Get(head_key));
|
| +}
|
| +
|
| +TEST_F(ScopedPtrExpiringCacheTest, RetainedEntry) {
|
| + TestScopedPtrExpiringCache cache(MAX_CACHE_SIZE);
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
|
| + cache.Put(i, MockObject::Create(i).Pass());
|
| + }
|
| +
|
| + // Add (cache size - 1)-entries.
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
|
| + EXPECT_TRUE(cache.Get(i) != NULL);
|
| + }
|
| +
|
| + for (unsigned int i = MAX_CACHE_SIZE; i < 2 * MAX_CACHE_SIZE - 1; i++) {
|
| + cache.Put(i, MockObject::Create(i).Pass());
|
| + }
|
| +
|
| + EXPECT_EQ(MAX_CACHE_SIZE, cache.size());
|
| +
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE - 1; i++) {
|
| + EXPECT_EQ(NULL, cache.Get(i));
|
| + }
|
| +
|
| + // The only retained entry (from the first round of insertion) is the last to
|
| + // be inserted.
|
| + EXPECT_TRUE(cache.Get(MAX_CACHE_SIZE - 1) != NULL);
|
| +}
|
| +
|
| +// Test that the iterator order is the insertion order. The first element of
|
| +// the iterator is the oldest entry in the cache.
|
| +TEST_F(ScopedPtrExpiringCacheTest, Iterator) {
|
| + TestScopedPtrExpiringCache cache(MAX_CACHE_SIZE);
|
| + std::vector<unsigned int> test_keys;
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
|
| + test_keys.push_back(i);
|
| + }
|
| + std::random_shuffle(test_keys.begin(), test_keys.end());
|
| +
|
| + for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
|
| + cache.Put(test_keys[i], MockObject::Create(test_keys[i]).Pass());
|
| + }
|
| +
|
| + TestScopedPtrExpiringCache::iterator cache_iter = cache.begin();
|
| + std::vector<unsigned int>::iterator key_iter = test_keys.begin();
|
| + while (cache_iter != cache.end() && key_iter != test_keys.end()) {
|
| + EXPECT_EQ(cache_iter->first, *key_iter);
|
| + cache_iter++;
|
| + key_iter++;
|
| + }
|
| +}
|
|
|