Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdlib.h>
     18 #include <utils/JenkinsHash.h>
     19 #include <utils/LruCache.h>
     20 #include <cutils/log.h>
     21 #include <gtest/gtest.h>
     22 
     23 namespace {
     24 
     25 typedef int SimpleKey;
     26 typedef const char* StringValue;
     27 
     28 struct ComplexKey {
     29     int k;
     30 
     31     explicit ComplexKey(int k) : k(k) {
     32         instanceCount += 1;
     33     }
     34 
     35     ComplexKey(const ComplexKey& other) : k(other.k) {
     36         instanceCount += 1;
     37     }
     38 
     39     ~ComplexKey() {
     40         instanceCount -= 1;
     41     }
     42 
     43     bool operator ==(const ComplexKey& other) const {
     44         return k == other.k;
     45     }
     46 
     47     bool operator !=(const ComplexKey& other) const {
     48         return k != other.k;
     49     }
     50 
     51     static ssize_t instanceCount;
     52 };
     53 
     54 ssize_t ComplexKey::instanceCount = 0;
     55 
     56 struct ComplexValue {
     57     int v;
     58 
     59     explicit ComplexValue(int v) : v(v) {
     60         instanceCount += 1;
     61     }
     62 
     63     ComplexValue(const ComplexValue& other) : v(other.v) {
     64         instanceCount += 1;
     65     }
     66 
     67     ~ComplexValue() {
     68         instanceCount -= 1;
     69     }
     70 
     71     static ssize_t instanceCount;
     72 };
     73 
     74 ssize_t ComplexValue::instanceCount = 0;
     75 
     76 struct KeyWithPointer {
     77     int *ptr;
     78     bool operator ==(const KeyWithPointer& other) const {
     79         return *ptr == *other.ptr;
     80     }
     81 };
     82 
     83 } // namespace
     84 
     85 
     86 namespace android {
     87 
     88 typedef LruCache<ComplexKey, ComplexValue> ComplexCache;
     89 
     90 template<> inline android::hash_t hash_type(const ComplexKey& value) {
     91     return hash_type(value.k);
     92 }
     93 
     94 template<> inline android::hash_t hash_type(const KeyWithPointer& value) {
     95     return hash_type(*value.ptr);
     96 }
     97 
     98 class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
     99 public:
    100     EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
    101     ~EntryRemovedCallback() {}
    102     void operator()(SimpleKey& k, StringValue& v) {
    103         callbackCount += 1;
    104         lastKey = k;
    105         lastValue = v;
    106     }
    107     ssize_t callbackCount;
    108     SimpleKey lastKey;
    109     StringValue lastValue;
    110 };
    111 
    112 class InvalidateKeyCallback : public OnEntryRemoved<KeyWithPointer, StringValue> {
    113 public:
    114     void operator()(KeyWithPointer& k, StringValue&) {
    115         delete k.ptr;
    116         k.ptr = nullptr;
    117     }
    118 };
    119 
    120 class LruCacheTest : public testing::Test {
    121 protected:
    122     virtual void SetUp() {
    123         ComplexKey::instanceCount = 0;
    124         ComplexValue::instanceCount = 0;
    125     }
    126 
    127     virtual void TearDown() {
    128         ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
    129     }
    130 
    131     void assertInstanceCount(ssize_t keys, ssize_t values) {
    132         if (keys != ComplexKey::instanceCount || values != ComplexValue::instanceCount) {
    133             FAIL() << "Expected " << keys << " keys and " << values << " values "
    134                     "but there were actually " << ComplexKey::instanceCount << " keys and "
    135                     << ComplexValue::instanceCount << " values";
    136         }
    137     }
    138 };
    139 
    140 TEST_F(LruCacheTest, Empty) {
    141     LruCache<SimpleKey, StringValue> cache(100);
    142 
    143     EXPECT_EQ(NULL, cache.get(0));
    144     EXPECT_EQ(0u, cache.size());
    145 }
    146 
    147 TEST_F(LruCacheTest, Simple) {
    148     LruCache<SimpleKey, StringValue> cache(100);
    149 
    150     cache.put(1, "one");
    151     cache.put(2, "two");
    152     cache.put(3, "three");
    153     EXPECT_STREQ("one", cache.get(1));
    154     EXPECT_STREQ("two", cache.get(2));
    155     EXPECT_STREQ("three", cache.get(3));
    156     EXPECT_EQ(3u, cache.size());
    157 }
    158 
    159 TEST_F(LruCacheTest, MaxCapacity) {
    160     LruCache<SimpleKey, StringValue> cache(2);
    161 
    162     cache.put(1, "one");
    163     cache.put(2, "two");
    164     cache.put(3, "three");
    165     EXPECT_EQ(NULL, cache.get(1));
    166     EXPECT_STREQ("two", cache.get(2));
    167     EXPECT_STREQ("three", cache.get(3));
    168     EXPECT_EQ(2u, cache.size());
    169 }
    170 
    171 TEST_F(LruCacheTest, RemoveLru) {
    172     LruCache<SimpleKey, StringValue> cache(100);
    173 
    174     cache.put(1, "one");
    175     cache.put(2, "two");
    176     cache.put(3, "three");
    177     cache.removeOldest();
    178     EXPECT_EQ(NULL, cache.get(1));
    179     EXPECT_STREQ("two", cache.get(2));
    180     EXPECT_STREQ("three", cache.get(3));
    181     EXPECT_EQ(2u, cache.size());
    182 }
    183 
    184 TEST_F(LruCacheTest, GetUpdatesLru) {
    185     LruCache<SimpleKey, StringValue> cache(100);
    186 
    187     cache.put(1, "one");
    188     cache.put(2, "two");
    189     cache.put(3, "three");
    190     EXPECT_STREQ("one", cache.get(1));
    191     cache.removeOldest();
    192     EXPECT_STREQ("one", cache.get(1));
    193     EXPECT_EQ(NULL, cache.get(2));
    194     EXPECT_STREQ("three", cache.get(3));
    195     EXPECT_EQ(2u, cache.size());
    196 }
    197 
    198 uint32_t hash_int(int x) {
    199     return JenkinsHashWhiten(JenkinsHashMix(0, x));
    200 }
    201 
    202 TEST_F(LruCacheTest, StressTest) {
    203     const size_t kCacheSize = 512;
    204     LruCache<SimpleKey, StringValue> cache(512);
    205     const size_t kNumKeys = 16 * 1024;
    206     const size_t kNumIters = 100000;
    207     char* strings[kNumKeys];
    208 
    209     for (size_t i = 0; i < kNumKeys; i++) {
    210         strings[i] = (char *)malloc(16);
    211         sprintf(strings[i], "%zu", i);
    212     }
    213 
    214     srandom(12345);
    215     int hitCount = 0;
    216     for (size_t i = 0; i < kNumIters; i++) {
    217         int index = random() % kNumKeys;
    218         uint32_t key = hash_int(index);
    219         const char *val = cache.get(key);
    220         if (val != NULL) {
    221             EXPECT_EQ(strings[index], val);
    222             hitCount++;
    223         } else {
    224             cache.put(key, strings[index]);
    225         }
    226     }
    227     size_t expectedHitCount = kNumIters * kCacheSize / kNumKeys;
    228     EXPECT_LT(int(expectedHitCount * 0.9), hitCount);
    229     EXPECT_GT(int(expectedHitCount * 1.1), hitCount);
    230     EXPECT_EQ(kCacheSize, cache.size());
    231 
    232     for (size_t i = 0; i < kNumKeys; i++) {
    233         free((void *)strings[i]);
    234     }
    235 }
    236 
    237 TEST_F(LruCacheTest, NoLeak) {
    238     ComplexCache cache(100);
    239 
    240     cache.put(ComplexKey(0), ComplexValue(0));
    241     cache.put(ComplexKey(1), ComplexValue(1));
    242     EXPECT_EQ(2U, cache.size());
    243     assertInstanceCount(2, 3);  // the member mNullValue counts as an instance
    244 }
    245 
    246 TEST_F(LruCacheTest, Clear) {
    247     ComplexCache cache(100);
    248 
    249     cache.put(ComplexKey(0), ComplexValue(0));
    250     cache.put(ComplexKey(1), ComplexValue(1));
    251     EXPECT_EQ(2U, cache.size());
    252     assertInstanceCount(2, 3);
    253     cache.clear();
    254     assertInstanceCount(0, 1);
    255 }
    256 
    257 TEST_F(LruCacheTest, ClearNoDoubleFree) {
    258     {
    259         ComplexCache cache(100);
    260 
    261         cache.put(ComplexKey(0), ComplexValue(0));
    262         cache.put(ComplexKey(1), ComplexValue(1));
    263         EXPECT_EQ(2U, cache.size());
    264         assertInstanceCount(2, 3);
    265         cache.removeOldest();
    266         cache.clear();
    267         assertInstanceCount(0, 1);
    268     }
    269     assertInstanceCount(0, 0);
    270 }
    271 
    272 TEST_F(LruCacheTest, ClearReuseOk) {
    273     ComplexCache cache(100);
    274 
    275     cache.put(ComplexKey(0), ComplexValue(0));
    276     cache.put(ComplexKey(1), ComplexValue(1));
    277     EXPECT_EQ(2U, cache.size());
    278     assertInstanceCount(2, 3);
    279     cache.clear();
    280     assertInstanceCount(0, 1);
    281     cache.put(ComplexKey(0), ComplexValue(0));
    282     cache.put(ComplexKey(1), ComplexValue(1));
    283     EXPECT_EQ(2U, cache.size());
    284     assertInstanceCount(2, 3);
    285 }
    286 
    287 TEST_F(LruCacheTest, Callback) {
    288     LruCache<SimpleKey, StringValue> cache(100);
    289     EntryRemovedCallback callback;
    290     cache.setOnEntryRemovedListener(&callback);
    291 
    292     cache.put(1, "one");
    293     cache.put(2, "two");
    294     cache.put(3, "three");
    295     EXPECT_EQ(3U, cache.size());
    296     cache.removeOldest();
    297     EXPECT_EQ(1, callback.callbackCount);
    298     EXPECT_EQ(1, callback.lastKey);
    299     EXPECT_STREQ("one", callback.lastValue);
    300 }
    301 
    302 TEST_F(LruCacheTest, CallbackOnClear) {
    303     LruCache<SimpleKey, StringValue> cache(100);
    304     EntryRemovedCallback callback;
    305     cache.setOnEntryRemovedListener(&callback);
    306 
    307     cache.put(1, "one");
    308     cache.put(2, "two");
    309     cache.put(3, "three");
    310     EXPECT_EQ(3U, cache.size());
    311     cache.clear();
    312     EXPECT_EQ(3, callback.callbackCount);
    313 }
    314 
    315 TEST_F(LruCacheTest, CallbackRemovesKeyWorksOK) {
    316     LruCache<KeyWithPointer, StringValue> cache(1);
    317     InvalidateKeyCallback callback;
    318     cache.setOnEntryRemovedListener(&callback);
    319     KeyWithPointer key1;
    320     key1.ptr = new int(1);
    321     KeyWithPointer key2;
    322     key2.ptr = new int(2);
    323 
    324     cache.put(key1, "one");
    325     // As the size of the cache is 1, the put will call the callback.
    326     // Make sure everything goes smoothly even if the callback invalidates
    327     // the key (b/24785286)
    328     cache.put(key2, "two");
    329     EXPECT_EQ(1U, cache.size());
    330     EXPECT_STREQ("two", cache.get(key2));
    331     cache.clear();
    332 }
    333 
    334 TEST_F(LruCacheTest, IteratorCheck) {
    335     LruCache<int, int> cache(100);
    336 
    337     cache.put(1, 4);
    338     cache.put(2, 5);
    339     cache.put(3, 6);
    340     EXPECT_EQ(3U, cache.size());
    341 
    342     LruCache<int, int>::Iterator it(cache);
    343     std::unordered_set<int> returnedValues;
    344     while (it.next()) {
    345         int v = it.value();
    346         // Check we haven't seen the value before.
    347         EXPECT_TRUE(returnedValues.find(v) == returnedValues.end());
    348         returnedValues.insert(v);
    349     }
    350     EXPECT_EQ(std::unordered_set<int>({4, 5, 6}), returnedValues);
    351 }
    352 
    353 TEST_F(LruCacheTest, EmptyCacheIterator) {
    354     // Check that nothing crashes...
    355     LruCache<int, int> cache(100);
    356 
    357     LruCache<int, int>::Iterator it(cache);
    358     std::unordered_set<int> returnedValues;
    359     while (it.next()) {
    360         returnedValues.insert(it.value());
    361     }
    362     EXPECT_EQ(std::unordered_set<int>(), returnedValues);
    363 }
    364 
    365 TEST_F(LruCacheTest, OneElementCacheIterator) {
    366     // Check that nothing crashes...
    367     LruCache<int, int> cache(100);
    368     cache.put(1, 2);
    369 
    370     LruCache<int, int>::Iterator it(cache);
    371     std::unordered_set<int> returnedValues;
    372     while (it.next()) {
    373         returnedValues.insert(it.value());
    374     }
    375     EXPECT_EQ(std::unordered_set<int>({ 2 }), returnedValues);
    376 }
    377 
    378 TEST_F(LruCacheTest, OneElementCacheRemove) {
    379     LruCache<int, int> cache(100);
    380     cache.put(1, 2);
    381 
    382     cache.remove(1);
    383 
    384     LruCache<int, int>::Iterator it(cache);
    385     std::unordered_set<int> returnedValues;
    386     while (it.next()) {
    387         returnedValues.insert(it.value());
    388     }
    389     EXPECT_EQ(std::unordered_set<int>({ }), returnedValues);
    390 }
    391 
    392 TEST_F(LruCacheTest, Remove) {
    393     LruCache<int, int> cache(100);
    394     cache.put(1, 4);
    395     cache.put(2, 5);
    396     cache.put(3, 6);
    397 
    398     cache.remove(2);
    399 
    400     LruCache<int, int>::Iterator it(cache);
    401     std::unordered_set<int> returnedValues;
    402     while (it.next()) {
    403         returnedValues.insert(it.value());
    404     }
    405     EXPECT_EQ(std::unordered_set<int>({ 4, 6 }), returnedValues);
    406 }
    407 
    408 TEST_F(LruCacheTest, RemoveYoungest) {
    409     LruCache<int, int> cache(100);
    410     cache.put(1, 4);
    411     cache.put(2, 5);
    412     cache.put(3, 6);
    413 
    414     cache.remove(3);
    415 
    416     LruCache<int, int>::Iterator it(cache);
    417     std::unordered_set<int> returnedValues;
    418     while (it.next()) {
    419         returnedValues.insert(it.value());
    420     }
    421     EXPECT_EQ(std::unordered_set<int>({ 4, 5 }), returnedValues);
    422 }
    423 
    424 TEST_F(LruCacheTest, RemoveNonMember) {
    425     LruCache<int, int> cache(100);
    426     cache.put(1, 4);
    427     cache.put(2, 5);
    428     cache.put(3, 6);
    429 
    430     cache.remove(7);
    431 
    432     LruCache<int, int>::Iterator it(cache);
    433     std::unordered_set<int> returnedValues;
    434     while (it.next()) {
    435         returnedValues.insert(it.value());
    436     }
    437     EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
    438 }
    439 
    440 }
    441