OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <algorithm> |
| 6 #include <vector> |
| 7 |
| 8 #include "base/memory/ref_counted.h" |
| 9 #include "chrome/browser/android/thumbnail/lru_expiring_cache.h" |
| 10 #include "testing/gmock/include/gmock/gmock.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 |
| 13 #define MAX_CACHE_SIZE 5u |
| 14 |
| 15 namespace { |
| 16 |
| 17 class MockObject { |
| 18 public: |
| 19 MockObject() : value_(0) {} |
| 20 explicit MockObject(int key) : value_((key * 127) % 13 + 23) {} |
| 21 bool operator==(const MockObject& object) const { |
| 22 return value_ == object.value_; |
| 23 } |
| 24 bool operator!=(const MockObject& object) const { return !(*this == object); } |
| 25 |
| 26 private: |
| 27 int value_; |
| 28 }; |
| 29 |
| 30 const MockObject kInvalidValue; |
| 31 |
| 32 } // namespace |
| 33 |
| 34 typedef testing::Test ThumbnailCache_LRUExpiringCacheTest; |
| 35 typedef LRUExpiringCache<int, MockObject> TestLRUExpiringCache; |
| 36 |
| 37 TEST_F(ThumbnailCache_LRUExpiringCacheTest, SimplePutAndGet) { |
| 38 TestLRUExpiringCache cache(MAX_CACHE_SIZE); |
| 39 EXPECT_EQ(cache.MaximumCacheSize(), MAX_CACHE_SIZE); |
| 40 EXPECT_EQ(cache.size(), 0u); |
| 41 |
| 42 for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) { |
| 43 cache.Put(i, MockObject(i)); |
| 44 } |
| 45 |
| 46 EXPECT_EQ(cache.size(), MAX_CACHE_SIZE); |
| 47 |
| 48 int next_key = MAX_CACHE_SIZE; |
| 49 |
| 50 // One cache entry should have been evicted. |
| 51 cache.Put(next_key, MockObject(next_key)); |
| 52 EXPECT_EQ(cache.size(), MAX_CACHE_SIZE); |
| 53 |
| 54 size_t cached_count = 0; |
| 55 for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) { |
| 56 if (cache.Get(i) != kInvalidValue) { |
| 57 EXPECT_EQ(cache.Get(i), MockObject(i)); |
| 58 cached_count++; |
| 59 } |
| 60 } |
| 61 |
| 62 EXPECT_EQ(cached_count, MAX_CACHE_SIZE); |
| 63 |
| 64 // Test Contains() |
| 65 cached_count = 0; |
| 66 for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) { |
| 67 if (cache.Contains(i)) |
| 68 cached_count++; |
| 69 } |
| 70 EXPECT_EQ(cached_count, MAX_CACHE_SIZE); |
| 71 |
| 72 cache.Clear(); |
| 73 EXPECT_EQ(cache.size(), 0u); |
| 74 |
| 75 for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) { |
| 76 EXPECT_FALSE(cache.Contains(i)); |
| 77 EXPECT_EQ(cache.Get(i), kInvalidValue); |
| 78 } |
| 79 } |
| 80 |
| 81 // The eviction policy is least-recently-used, where we define used as insertion |
| 82 // into the cache. We test that the first to be evicted is the first entry |
| 83 // inserted into the cache. |
| 84 TEST_F(ThumbnailCache_LRUExpiringCacheTest, EvictedEntry) { |
| 85 TestLRUExpiringCache cache(MAX_CACHE_SIZE); |
| 86 for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) { |
| 87 cache.Put(i, MockObject(i)); |
| 88 } |
| 89 |
| 90 int next_key = MAX_CACHE_SIZE; |
| 91 cache.Put(next_key, MockObject(next_key)); |
| 92 EXPECT_EQ(cache.size(), MAX_CACHE_SIZE); |
| 93 EXPECT_EQ(cache.Get(next_key), MockObject(next_key)); |
| 94 |
| 95 // The first inserted entry should have been evicted. |
| 96 EXPECT_FALSE(cache.Contains(0)); |
| 97 |
| 98 // The rest of the content should be present. |
| 99 for (unsigned int i = 1; i < MAX_CACHE_SIZE; i++) { |
| 100 EXPECT_TRUE(cache.Contains(i)); |
| 101 } |
| 102 |
| 103 next_key++; |
| 104 |
| 105 // The first candidate to be evicted is the head of the iterator. |
| 106 int head_key = cache.begin()->first; |
| 107 EXPECT_TRUE(cache.Contains(head_key)); |
| 108 cache.Put(next_key, MockObject(next_key)); |
| 109 |
| 110 EXPECT_NE(cache.begin()->first, head_key); |
| 111 EXPECT_FALSE(cache.Contains(head_key)); |
| 112 } |
| 113 |
| 114 TEST_F(ThumbnailCache_LRUExpiringCacheTest, RetainedEntry) { |
| 115 TestLRUExpiringCache cache(MAX_CACHE_SIZE); |
| 116 for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) { |
| 117 cache.Put(i, MockObject(i)); |
| 118 } |
| 119 |
| 120 // Add (cache size - 1)-entries. |
| 121 for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) { |
| 122 EXPECT_TRUE(cache.Contains(i)); |
| 123 } |
| 124 |
| 125 for (unsigned int i = MAX_CACHE_SIZE; i < 2 * MAX_CACHE_SIZE - 1; i++) { |
| 126 cache.Put(i, MockObject(i)); |
| 127 } |
| 128 |
| 129 EXPECT_EQ(cache.size(), MAX_CACHE_SIZE); |
| 130 |
| 131 for (unsigned int i = 0; i < MAX_CACHE_SIZE - 1; i++) { |
| 132 EXPECT_FALSE(cache.Contains(i)); |
| 133 } |
| 134 |
| 135 // The only retained entry (from the first round of insertion) is the last to |
| 136 // be inserted. |
| 137 EXPECT_TRUE(cache.Contains(MAX_CACHE_SIZE - 1)); |
| 138 } |
| 139 |
| 140 // Test that the iterator order is the insertion order. The first element of |
| 141 // the iterator is the oldest entry in the cache. |
| 142 TEST_F(ThumbnailCache_LRUExpiringCacheTest, Iterator) { |
| 143 TestLRUExpiringCache cache(MAX_CACHE_SIZE); |
| 144 std::vector<unsigned int> test_keys; |
| 145 for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) { |
| 146 test_keys.push_back(i); |
| 147 } |
| 148 std::random_shuffle(test_keys.begin(), test_keys.end()); |
| 149 |
| 150 for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) { |
| 151 cache.Put(test_keys[i], MockObject(test_keys[i])); |
| 152 } |
| 153 |
| 154 TestLRUExpiringCache::iterator cache_iter = cache.begin(); |
| 155 std::vector<unsigned int>::iterator key_iter = test_keys.begin(); |
| 156 while (cache_iter != cache.end() && key_iter != test_keys.end()) { |
| 157 EXPECT_EQ(cache_iter->first, *key_iter); |
| 158 cache_iter++; |
| 159 key_iter++; |
| 160 } |
| 161 } |
OLD | NEW |