1 /* 2 ** Copyright 2011, 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 <gtest/gtest.h> 18 19 #include <utils/BlobCache.h> 20 21 namespace android { 22 23 class BlobCacheTest : public ::testing::Test { 24 protected: 25 enum { 26 MAX_KEY_SIZE = 6, 27 MAX_VALUE_SIZE = 8, 28 MAX_TOTAL_SIZE = 13, 29 }; 30 31 virtual void SetUp() { 32 mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE); 33 } 34 35 virtual void TearDown() { 36 mBC.clear(); 37 } 38 39 sp<BlobCache> mBC; 40 }; 41 42 TEST_F(BlobCacheTest, CacheSingleValueSucceeds) { 43 char buf[4] = { 0xee, 0xee, 0xee, 0xee }; 44 mBC->set("abcd", 4, "efgh", 4); 45 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); 46 ASSERT_EQ('e', buf[0]); 47 ASSERT_EQ('f', buf[1]); 48 ASSERT_EQ('g', buf[2]); 49 ASSERT_EQ('h', buf[3]); 50 } 51 52 TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) { 53 char buf[2] = { 0xee, 0xee }; 54 mBC->set("ab", 2, "cd", 2); 55 mBC->set("ef", 2, "gh", 2); 56 ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2)); 57 ASSERT_EQ('c', buf[0]); 58 ASSERT_EQ('d', buf[1]); 59 ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2)); 60 ASSERT_EQ('g', buf[0]); 61 ASSERT_EQ('h', buf[1]); 62 } 63 64 TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) { 65 char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }; 66 mBC->set("abcd", 4, "efgh", 4); 67 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4)); 68 ASSERT_EQ(0xee, buf[0]); 69 ASSERT_EQ('e', buf[1]); 70 ASSERT_EQ('f', buf[2]); 71 ASSERT_EQ('g', buf[3]); 72 ASSERT_EQ('h', buf[4]); 73 ASSERT_EQ(0xee, buf[5]); 74 } 75 76 TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) { 77 char buf[3] = { 0xee, 0xee, 0xee }; 78 mBC->set("abcd", 4, "efgh", 4); 79 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3)); 80 ASSERT_EQ(0xee, buf[0]); 81 ASSERT_EQ(0xee, buf[1]); 82 ASSERT_EQ(0xee, buf[2]); 83 } 84 85 TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) { 86 mBC->set("abcd", 4, "efgh", 4); 87 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0)); 88 } 89 90 TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) { 91 char buf[4] = { 0xee, 0xee, 0xee, 0xee }; 92 mBC->set("abcd", 4, "efgh", 4); 93 mBC->set("abcd", 4, "ijkl", 4); 94 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); 95 ASSERT_EQ('i', buf[0]); 96 ASSERT_EQ('j', buf[1]); 97 ASSERT_EQ('k', buf[2]); 98 ASSERT_EQ('l', buf[3]); 99 } 100 101 TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) { 102 char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee }; 103 mBC->set("abcd", 4, "efgh", 4); 104 mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); 105 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); 106 ASSERT_EQ('e', buf[0]); 107 ASSERT_EQ('f', buf[1]); 108 ASSERT_EQ('g', buf[2]); 109 ASSERT_EQ('h', buf[3]); 110 } 111 112 TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) { 113 char key[MAX_KEY_SIZE+1]; 114 char buf[4] = { 0xee, 0xee, 0xee, 0xee }; 115 for (int i = 0; i < MAX_KEY_SIZE+1; i++) { 116 key[i] = 'a'; 117 } 118 mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4); 119 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4)); 120 ASSERT_EQ(0xee, buf[0]); 121 ASSERT_EQ(0xee, buf[1]); 122 ASSERT_EQ(0xee, buf[2]); 123 ASSERT_EQ(0xee, buf[3]); 124 } 125 126 TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) { 127 char buf[MAX_VALUE_SIZE+1]; 128 for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { 129 buf[i] = 'b'; 130 } 131 mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); 132 for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { 133 buf[i] = 0xee; 134 } 135 ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1)); 136 for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { 137 SCOPED_TRACE(i); 138 ASSERT_EQ(0xee, buf[i]); 139 } 140 } 141 142 TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) { 143 // Check a testing assumptions 144 ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE); 145 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); 146 147 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 }; 148 149 char key[MAX_KEY_SIZE]; 150 char buf[bufSize]; 151 for (int i = 0; i < MAX_KEY_SIZE; i++) { 152 key[i] = 'a'; 153 } 154 for (int i = 0; i < bufSize; i++) { 155 buf[i] = 'b'; 156 } 157 158 mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE); 159 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); 160 } 161 162 TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) { 163 char key[MAX_KEY_SIZE]; 164 char buf[4] = { 0xee, 0xee, 0xee, 0xee }; 165 for (int i = 0; i < MAX_KEY_SIZE; i++) { 166 key[i] = 'a'; 167 } 168 mBC->set(key, MAX_KEY_SIZE, "wxyz", 4); 169 ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4)); 170 ASSERT_EQ('w', buf[0]); 171 ASSERT_EQ('x', buf[1]); 172 ASSERT_EQ('y', buf[2]); 173 ASSERT_EQ('z', buf[3]); 174 } 175 176 TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) { 177 char buf[MAX_VALUE_SIZE]; 178 for (int i = 0; i < MAX_VALUE_SIZE; i++) { 179 buf[i] = 'b'; 180 } 181 mBC->set("abcd", 4, buf, MAX_VALUE_SIZE); 182 for (int i = 0; i < MAX_VALUE_SIZE; i++) { 183 buf[i] = 0xee; 184 } 185 ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf, 186 MAX_VALUE_SIZE)); 187 for (int i = 0; i < MAX_VALUE_SIZE; i++) { 188 SCOPED_TRACE(i); 189 ASSERT_EQ('b', buf[i]); 190 } 191 } 192 193 TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) { 194 // Check a testing assumption 195 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); 196 197 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE }; 198 199 char key[MAX_KEY_SIZE]; 200 char buf[bufSize]; 201 for (int i = 0; i < MAX_KEY_SIZE; i++) { 202 key[i] = 'a'; 203 } 204 for (int i = 0; i < bufSize; i++) { 205 buf[i] = 'b'; 206 } 207 208 mBC->set(key, MAX_KEY_SIZE, buf, bufSize); 209 ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); 210 } 211 212 TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { 213 char buf[1] = { 0xee }; 214 mBC->set("x", 1, "y", 1); 215 ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1)); 216 ASSERT_EQ('y', buf[0]); 217 } 218 219 TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) { 220 for (int i = 0; i < 256; i++) { 221 uint8_t k = i; 222 mBC->set(&k, 1, "x", 1); 223 } 224 int numCached = 0; 225 for (int i = 0; i < 256; i++) { 226 uint8_t k = i; 227 if (mBC->get(&k, 1, NULL, 0) == 1) { 228 numCached++; 229 } 230 } 231 ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached); 232 } 233 234 TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) { 235 // Fill up the entire cache with 1 char key/value pairs. 236 const int maxEntries = MAX_TOTAL_SIZE / 2; 237 for (int i = 0; i < maxEntries; i++) { 238 uint8_t k = i; 239 mBC->set(&k, 1, "x", 1); 240 } 241 // Insert one more entry, causing a cache overflow. 242 { 243 uint8_t k = maxEntries; 244 mBC->set(&k, 1, "x", 1); 245 } 246 // Count the number of entries in the cache. 247 int numCached = 0; 248 for (int i = 0; i < maxEntries+1; i++) { 249 uint8_t k = i; 250 if (mBC->get(&k, 1, NULL, 0) == 1) { 251 numCached++; 252 } 253 } 254 ASSERT_EQ(maxEntries/2 + 1, numCached); 255 } 256 257 } // namespace android 258