1 // Copyright (c) 2011 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.
5 #include "base/basictypes.h"
6 #include "base/containers/mru_cache.h"
7 #include "testing/gtest/include/gtest/gtest.h"
11 int cached_item_live_count
= 0;
14 CachedItem() : value(0) {
15 cached_item_live_count
++;
18 explicit CachedItem(int new_value
) : value(new_value
) {
19 cached_item_live_count
++;
22 explicit CachedItem(const CachedItem
& other
) : value(other
.value
) {
23 cached_item_live_count
++;
27 cached_item_live_count
--;
35 TEST(MRUCacheTest
, Basic
) {
36 typedef base::MRUCache
<int, CachedItem
> Cache
;
37 Cache
cache(Cache::NO_AUTO_EVICT
);
39 // Check failure conditions
42 EXPECT_TRUE(cache
.Get(0) == cache
.end());
43 EXPECT_TRUE(cache
.Peek(0) == cache
.end());
46 static const int kItem1Key
= 5;
48 Cache::iterator inserted_item
= cache
.Put(kItem1Key
, item1
);
49 EXPECT_EQ(1U, cache
.size());
51 // Check that item1 was properly inserted.
53 Cache::iterator found
= cache
.Get(kItem1Key
);
54 EXPECT_TRUE(inserted_item
== cache
.begin());
55 EXPECT_TRUE(found
!= cache
.end());
57 found
= cache
.Peek(kItem1Key
);
58 EXPECT_TRUE(found
!= cache
.end());
60 EXPECT_EQ(kItem1Key
, found
->first
);
61 EXPECT_EQ(item1
.value
, found
->second
.value
);
64 static const int kItem2Key
= 7;
66 cache
.Put(kItem2Key
, item2
);
67 EXPECT_EQ(2U, cache
.size());
69 // Check that item1 is the oldest since item2 was added afterwards.
71 Cache::reverse_iterator oldest
= cache
.rbegin();
72 ASSERT_TRUE(oldest
!= cache
.rend());
73 EXPECT_EQ(kItem1Key
, oldest
->first
);
74 EXPECT_EQ(item1
.value
, oldest
->second
.value
);
77 // Check that item1 is still accessible by key.
79 Cache::iterator test_item
= cache
.Get(kItem1Key
);
80 ASSERT_TRUE(test_item
!= cache
.end());
81 EXPECT_EQ(kItem1Key
, test_item
->first
);
82 EXPECT_EQ(item1
.value
, test_item
->second
.value
);
85 // Check that retrieving item1 pushed item2 to oldest.
87 Cache::reverse_iterator oldest
= cache
.rbegin();
88 ASSERT_TRUE(oldest
!= cache
.rend());
89 EXPECT_EQ(kItem2Key
, oldest
->first
);
90 EXPECT_EQ(item2
.value
, oldest
->second
.value
);
93 // Remove the oldest item and check that item1 is now the only member.
95 Cache::reverse_iterator next
= cache
.Erase(cache
.rbegin());
97 EXPECT_EQ(1U, cache
.size());
99 EXPECT_TRUE(next
== cache
.rbegin());
100 EXPECT_EQ(kItem1Key
, next
->first
);
101 EXPECT_EQ(item1
.value
, next
->second
.value
);
103 cache
.Erase(cache
.begin());
104 EXPECT_EQ(0U, cache
.size());
107 // Check that Clear() works properly.
108 cache
.Put(kItem1Key
, item1
);
109 cache
.Put(kItem2Key
, item2
);
110 EXPECT_EQ(2U, cache
.size());
112 EXPECT_EQ(0U, cache
.size());
115 TEST(MRUCacheTest
, GetVsPeek
) {
116 typedef base::MRUCache
<int, CachedItem
> Cache
;
117 Cache
cache(Cache::NO_AUTO_EVICT
);
119 static const int kItem1Key
= 1;
120 CachedItem
item1(10);
121 cache
.Put(kItem1Key
, item1
);
123 static const int kItem2Key
= 2;
124 CachedItem
item2(20);
125 cache
.Put(kItem2Key
, item2
);
127 // This should do nothing since the size is bigger than the number of items.
128 cache
.ShrinkToSize(100);
130 // Check that item1 starts out as oldest
132 Cache::reverse_iterator iter
= cache
.rbegin();
133 ASSERT_TRUE(iter
!= cache
.rend());
134 EXPECT_EQ(kItem1Key
, iter
->first
);
135 EXPECT_EQ(item1
.value
, iter
->second
.value
);
138 // Check that Peek doesn't change ordering
140 Cache::iterator peekiter
= cache
.Peek(kItem1Key
);
141 ASSERT_TRUE(peekiter
!= cache
.end());
143 Cache::reverse_iterator iter
= cache
.rbegin();
144 ASSERT_TRUE(iter
!= cache
.rend());
145 EXPECT_EQ(kItem1Key
, iter
->first
);
146 EXPECT_EQ(item1
.value
, iter
->second
.value
);
150 TEST(MRUCacheTest
, KeyReplacement
) {
151 typedef base::MRUCache
<int, CachedItem
> Cache
;
152 Cache
cache(Cache::NO_AUTO_EVICT
);
154 static const int kItem1Key
= 1;
155 CachedItem
item1(10);
156 cache
.Put(kItem1Key
, item1
);
158 static const int kItem2Key
= 2;
159 CachedItem
item2(20);
160 cache
.Put(kItem2Key
, item2
);
162 static const int kItem3Key
= 3;
163 CachedItem
item3(30);
164 cache
.Put(kItem3Key
, item3
);
166 static const int kItem4Key
= 4;
167 CachedItem
item4(40);
168 cache
.Put(kItem4Key
, item4
);
170 CachedItem
item5(50);
171 cache
.Put(kItem3Key
, item5
);
173 EXPECT_EQ(4U, cache
.size());
174 for (int i
= 0; i
< 3; ++i
) {
175 Cache::reverse_iterator iter
= cache
.rbegin();
176 ASSERT_TRUE(iter
!= cache
.rend());
179 // Make it so only the most important element is there.
180 cache
.ShrinkToSize(1);
182 Cache::iterator iter
= cache
.begin();
183 EXPECT_EQ(kItem3Key
, iter
->first
);
184 EXPECT_EQ(item5
.value
, iter
->second
.value
);
187 // Make sure that the owning version release its pointers properly.
188 TEST(MRUCacheTest
, Owning
) {
189 typedef base::OwningMRUCache
<int, CachedItem
*> Cache
;
190 Cache
cache(Cache::NO_AUTO_EVICT
);
192 int initial_count
= cached_item_live_count
;
194 // First insert and item and then overwrite it.
195 static const int kItem1Key
= 1;
196 cache
.Put(kItem1Key
, new CachedItem(20));
197 cache
.Put(kItem1Key
, new CachedItem(22));
199 // There should still be one item, and one extra live item.
200 Cache::iterator iter
= cache
.Get(kItem1Key
);
201 EXPECT_EQ(1U, cache
.size());
202 EXPECT_TRUE(iter
!= cache
.end());
203 EXPECT_EQ(initial_count
+ 1, cached_item_live_count
);
206 cache
.Erase(cache
.begin());
207 EXPECT_EQ(initial_count
, cached_item_live_count
);
209 // Now try another cache that goes out of scope to make sure its pointers
212 Cache
cache2(Cache::NO_AUTO_EVICT
);
213 cache2
.Put(1, new CachedItem(20));
214 cache2
.Put(2, new CachedItem(20));
217 // There should be no objects leaked.
218 EXPECT_EQ(initial_count
, cached_item_live_count
);
220 // Check that Clear() also frees things correctly.
222 Cache
cache2(Cache::NO_AUTO_EVICT
);
223 cache2
.Put(1, new CachedItem(20));
224 cache2
.Put(2, new CachedItem(20));
225 EXPECT_EQ(initial_count
+ 2, cached_item_live_count
);
227 EXPECT_EQ(initial_count
, cached_item_live_count
);
231 TEST(MRUCacheTest
, AutoEvict
) {
232 typedef base::OwningMRUCache
<int, CachedItem
*> Cache
;
233 static const Cache::size_type kMaxSize
= 3;
235 int initial_count
= cached_item_live_count
;
238 Cache
cache(kMaxSize
);
240 static const int kItem1Key
= 1, kItem2Key
= 2, kItem3Key
= 3, kItem4Key
= 4;
241 cache
.Put(kItem1Key
, new CachedItem(20));
242 cache
.Put(kItem2Key
, new CachedItem(21));
243 cache
.Put(kItem3Key
, new CachedItem(22));
244 cache
.Put(kItem4Key
, new CachedItem(23));
246 // The cache should only have kMaxSize items in it even though we inserted
248 EXPECT_EQ(kMaxSize
, cache
.size());
251 // There should be no objects leaked.
252 EXPECT_EQ(initial_count
, cached_item_live_count
);
255 TEST(MRUCacheTest
, HashingMRUCache
) {
256 // Very simple test to make sure that the hashing cache works correctly.
257 typedef base::HashingMRUCache
<std::string
, CachedItem
> Cache
;
258 Cache
cache(Cache::NO_AUTO_EVICT
);
261 cache
.Put("First", one
);
264 cache
.Put("Second", two
);
266 EXPECT_EQ(one
.value
, cache
.Get("First")->second
.value
);
267 EXPECT_EQ(two
.value
, cache
.Get("Second")->second
.value
);
268 cache
.ShrinkToSize(1);
269 EXPECT_EQ(two
.value
, cache
.Get("Second")->second
.value
);
270 EXPECT_TRUE(cache
.Get("First") == cache
.end());