1e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson/* 2e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Copyright (C) 2011 The Android Open Source Project 3e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * 4e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * you may not use this file except in compliance with the License. 6e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * You may obtain a copy of the License at 7e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * 8e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * 10e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * See the License for the specific language governing permissions and 14e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * limitations under the License. 15e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson */ 16e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 17e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonpackage android.util; 18e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 19e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport java.util.ArrayList; 20e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport java.util.Arrays; 217db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilsonimport java.util.Collections; 22e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport java.util.List; 23e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport java.util.Map; 24e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport junit.framework.TestCase; 25e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 26e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonpublic final class LruCacheTest extends TestCase { 27e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private int expectedCreateCount; 28e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private int expectedPutCount; 29e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private int expectedHitCount; 30e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private int expectedMissCount; 31e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private int expectedEvictionCount; 32e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 33e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testStatistics() { 34e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3); 35e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 36e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 37e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(null, cache.put("a", "A")); 38e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedPutCount++; 39e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 40e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "a", "A"); 41e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "a", "A"); 42e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 43e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(null, cache.put("b", "B")); 44e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedPutCount++; 45e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 46e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "a", "A"); 47e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "b", "B"); 48e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "a", "A", "b", "B"); 49e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 50e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(null, cache.put("c", "C")); 51e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedPutCount++; 52e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 53e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "a", "A"); 54e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "b", "B"); 55e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "c", "C"); 56e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "a", "A", "b", "B", "c", "C"); 57e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 58e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(null, cache.put("d", "D")); 59e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedPutCount++; 60e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedEvictionCount++; // a should have been evicted 61e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 62e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertMiss(cache, "a"); 63e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "b", "B"); 64e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "c", "C"); 65e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "d", "D"); 66e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "b", "B"); 67e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "c", "C"); 68e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "d", "D", "b", "B", "c", "C"); 69e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 70e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(null, cache.put("e", "E")); 71e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedPutCount++; 72e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedEvictionCount++; // d should have been evicted 73e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 74e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertMiss(cache, "d"); 75e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertMiss(cache, "a"); 76e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "e", "E"); 77e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "b", "B"); 78e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "c", "C"); 79e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "e", "E", "b", "B", "c", "C"); 80e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 81e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 82e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testStatisticsWithCreate() { 83e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = newCreatingCache(); 84e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 85e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 86e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertCreated(cache, "aa", "created-aa"); 87e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertHit(cache, "aa", "created-aa"); 88e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "aa", "created-aa"); 89e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 90e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertCreated(cache, "bb", "created-bb"); 91e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertMiss(cache, "c"); 92e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb"); 93e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 94e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertCreated(cache, "cc", "created-cc"); 95e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb", "cc", "created-cc"); 96e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 97e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedEvictionCount++; // aa will be evicted 98e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertCreated(cache, "dd", "created-dd"); 99e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "bb", "created-bb", "cc", "created-cc", "dd", "created-dd"); 100e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 101e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedEvictionCount++; // bb will be evicted 102e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertCreated(cache, "aa", "created-aa"); 103e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa"); 104e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 105e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 106e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testCreateOnCacheMiss() { 107e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = newCreatingCache(); 108e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson String created = cache.get("aa"); 109e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("created-aa", created); 110e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 111e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 112e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testNoCreateOnCacheHit() { 113e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = newCreatingCache(); 114e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("aa", "put-aa"); 115e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("put-aa", cache.get("aa")); 116e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 117e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 118e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testConstructorDoesNotAllowZeroCacheSize() { 119e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson try { 120e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson new LruCache<String, String>(0); 121e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson fail(); 122e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } catch (IllegalArgumentException expected) { 123e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 124e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 125e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 126e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testCannotPutNullKey() { 127e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3); 128e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson try { 129e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put(null, "A"); 130e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson fail(); 131e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } catch (NullPointerException expected) { 132e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 133e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 134e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 135e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testCannotPutNullValue() { 136e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3); 137e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson try { 138e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", null); 139e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson fail(); 140e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } catch (NullPointerException expected) { 141e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 142e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 143e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 144e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testToString() { 145e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3); 146e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString()); 147e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 148e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 149e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B"); 150e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("c", "C"); 151e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("d", "D"); 152e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 153e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.get("a"); // miss 154e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.get("b"); // hit 155e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.get("c"); // hit 156e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.get("d"); // hit 157e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.get("e"); // miss 158e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 159e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString()); 160e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 161e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 162e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEvictionWithSingletonCache() { 163e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(1); 164e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 165e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B"); 166e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "b", "B"); 167e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 168e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 169e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEntryEvictedWhenFull() { 1707db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson List<String> log = new ArrayList<String>(); 1717db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = newRemovalLogCache(log); 172e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 173e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 174e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B"); 175e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("c", "C"); 1767db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Collections.<String>emptyList(), log); 177e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 178e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("d", "D"); 1797db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Arrays.asList("a=A"), log); 180e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 181e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 182e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson /** 183e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Replacing the value for a key doesn't cause an eviction but it does bring 184e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * the replaced entry to the front of the queue. 185e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson */ 186c4e6209c5294da5cbca75eafd0ba5d4c3ed9a5b1Jesse Wilson public void testPutCauseEviction() { 187c4e6209c5294da5cbca75eafd0ba5d4c3ed9a5b1Jesse Wilson List<String> log = new ArrayList<String>(); 188c4e6209c5294da5cbca75eafd0ba5d4c3ed9a5b1Jesse Wilson LruCache<String, String> cache = newRemovalLogCache(log); 189e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 190e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 191e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B"); 192e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("c", "C"); 193e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B2"); 194c4e6209c5294da5cbca75eafd0ba5d4c3ed9a5b1Jesse Wilson assertEquals(Arrays.asList("b=B>B2"), log); 195e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "a", "A", "c", "C", "b", "B2"); 196e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 197e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 198e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testCustomSizesImpactsSize() { 199e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(10) { 200e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected int sizeOf(String key, String value) { 201e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return key.length() + value.length(); 202e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 203e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 204e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 205e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(0, cache.size()); 206e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "AA"); 207e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(3, cache.size()); 208e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "BBBB"); 209e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(8, cache.size()); 210e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", ""); 211e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(6, cache.size()); 212e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 213e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 214e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEvictionWithCustomSizes() { 215e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(4) { 216e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected int sizeOf(String key, String value) { 217e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return value.length(); 218e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 219e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 220e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 221e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "AAAA"); 222e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "a", "AAAA"); 223e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "BBBB"); // should evict a 224e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "b", "BBBB"); 225e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("c", "CC"); // should evict b 226e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "c", "CC"); 227e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("d", "DD"); 228e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "c", "CC", "d", "DD"); 229e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("e", "E"); // should evict c 230e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "d", "DD", "e", "E"); 231e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("f", "F"); 232e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "d", "DD", "e", "E", "f", "F"); 233e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("g", "G"); // should evict d 234e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "e", "E", "f", "F", "g", "G"); 235e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("h", "H"); 236e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "e", "E", "f", "F", "g", "G", "h", "H"); 237e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("i", "III"); // should evict e, f, and g 238e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "h", "H", "i", "III"); 239e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("j", "JJJ"); // should evict h and i 240e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "j", "JJJ"); 241e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 242e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 243e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEvictionThrowsWhenSizesAreInconsistent() { 244e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, int[]> cache = new LruCache<String, int[]>(4) { 245e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected int sizeOf(String key, int[] value) { 246e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return value[0]; 247e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 248e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 249e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 250e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson int[] a = { 4 }; 251e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", a); 252e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 253e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson // get the cache size out of sync 254e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson a[0] = 1; 255e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(4, cache.size()); 256e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 257e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson // evict something 258e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson try { 259e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", new int[] { 2 }); 260e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson fail(); 261e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } catch (IllegalStateException expected) { 262e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 263e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 264e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 265e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEvictionThrowsWhenSizesAreNegative() { 266e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(4) { 267e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected int sizeOf(String key, String value) { 268e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return -1; 269e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 270e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 271e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 272e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson try { 273e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 274e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson fail(); 275e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } catch (IllegalStateException expected) { 276e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 277e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 278e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 279e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson /** 280e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Naive caches evict at most one element at a time. This is problematic 281e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * because evicting a small element may be insufficient to make room for a 282e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * large element. 283e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson */ 284e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testDifferentElementSizes() { 285e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(10) { 286e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected int sizeOf(String key, String value) { 287e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return value.length(); 288e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 289e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 290e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 291e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "1"); 292e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "12345678"); 293e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("c", "1"); 294e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "a", "1", "b", "12345678", "c", "1"); 295e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("d", "12345678"); // should evict a and b 296e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "c", "1", "d", "12345678"); 297e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("e", "12345678"); // should evict c and d 298e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache, "e", "12345678"); 299e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 300e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 301e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEvictAll() { 3027db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson List<String> log = new ArrayList<String>(); 3037db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = newRemovalLogCache(log); 304e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 305e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B"); 306e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("c", "C"); 307e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.evictAll(); 308e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(0, cache.size()); 3097db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Arrays.asList("a=A", "b=B", "c=C"), log); 310e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 311e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 312e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson public void testEvictAllEvictsSizeZeroElements() { 313e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(10) { 314e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected int sizeOf(String key, String value) { 315e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return 0; 316e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 317e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 318e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 319e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("a", "A"); 320e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.put("b", "B"); 321e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson cache.evictAll(); 322e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertSnapshot(cache); 323e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 324e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 32556b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson public void testRemoveWithCustomSizes() { 32656b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(10) { 32756b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson @Override protected int sizeOf(String key, String value) { 32856b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson return value.length(); 32956b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson } 33056b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson }; 33156b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson cache.put("a", "123456"); 33256b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson cache.put("b", "1234"); 33356b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson cache.remove("a"); 33456b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson assertEquals(4, cache.size()); 33556b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson } 33656b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson 33756b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson public void testRemoveAbsentElement() { 33856b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(10); 33956b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson cache.put("a", "A"); 34056b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson cache.put("b", "B"); 34156b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson assertEquals(null, cache.remove("c")); 34256b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson assertEquals(2, cache.size()); 34356b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson } 34456b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson 34556b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson public void testRemoveNullThrows() { 34656b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson LruCache<String, String> cache = new LruCache<String, String>(10); 34756b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson try { 34856b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson cache.remove(null); 34956b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson fail(); 35056b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson } catch (NullPointerException expected) { 35156b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson } 35256b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson } 35356b6ad3e28f9f86fb3186c96ddd8754e190afdf0Jesse Wilson 3547db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson public void testRemoveCallsEntryRemoved() { 3557db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson List<String> log = new ArrayList<String>(); 3567db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = newRemovalLogCache(log); 3577db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("a", "A"); 3587db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.remove("a"); 3597db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Arrays.asList("a=A>null"), log); 3607db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 3617db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 3627db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson public void testPutCallsEntryRemoved() { 3637db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson List<String> log = new ArrayList<String>(); 3647db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = newRemovalLogCache(log); 3657db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("a", "A"); 3667db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("a", "A2"); 3677db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Arrays.asList("a=A>A2"), log); 3687db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 3697db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 3707db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson public void testEntryRemovedIsCalledWithoutSynchronization() { 3717db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3) { 3727db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected void entryRemoved( 3737db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson boolean evicted, String key, String oldValue, String newValue) { 3747db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertFalse(Thread.holdsLock(this)); 3757db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 3767db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson }; 3777db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 3787db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("a", "A"); 3797db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("a", "A2"); // replaced 3807db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("b", "B"); 3817db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("c", "C"); 3827db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.put("d", "D"); // single eviction 3837db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.remove("a"); // removed 3847db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.evictAll(); // multiple eviction 3857db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 3867db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 3877db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson public void testCreateIsCalledWithoutSynchronization() { 3887db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3) { 3897db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected String create(String key) { 3907db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertFalse(Thread.holdsLock(this)); 3917db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson return null; 3927db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 3937db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson }; 3947db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 3957db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson cache.get("a"); 3967db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 3977db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 3987db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson /** 3997db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson * Test what happens when a value is added to the map while create is 4007db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson * working. The map value should be returned by get(), and the created value 4017db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson * should be released with entryRemoved(). 4027db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson */ 4037db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson public void testCreateWithConcurrentPut() { 4047db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson final List<String> log = new ArrayList<String>(); 4057db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, String> cache = new LruCache<String, String>(3) { 4067db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected String create(String key) { 4077db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson put(key, "B"); 4087db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson return "A"; 4097db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4107db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected void entryRemoved( 4117db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson boolean evicted, String key, String oldValue, String newValue) { 4127db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson log.add(key + "=" + oldValue + ">" + newValue); 4137db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4147db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson }; 4157db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 4167db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals("B", cache.get("a")); 4177db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Arrays.asList("a=A>B"), log); 4187db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4197db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 4207db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson /** 4217db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson * Test what happens when two creates happen concurrently. The result from 4227db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson * the first create to return is returned by both gets. The other created 4237db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson * values should be released with entryRemove(). 4247db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson */ 4257db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson public void testCreateWithConcurrentCreate() { 4267db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson final List<String> log = new ArrayList<String>(); 4277db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson LruCache<String, Integer> cache = new LruCache<String, Integer>(3) { 4287db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson int callCount = 0; 4297db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected Integer create(String key) { 4307db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson if (callCount++ == 0) { 4317db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(2, get(key).intValue()); 4327db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson return 1; 4337db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } else { 4347db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson return 2; 4357db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4367db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4377db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected void entryRemoved( 4387db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson boolean evicted, String key, Integer oldValue, Integer newValue) { 4397db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson log.add(key + "=" + oldValue + ">" + newValue); 4407db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4417db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson }; 4427db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 4437db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(2, cache.get("a").intValue()); 4447db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson assertEquals(Arrays.asList("a=1>2"), log); 4457db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4467db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 447e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private LruCache<String, String> newCreatingCache() { 448e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return new LruCache<String, String>(3) { 449e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson @Override protected String create(String key) { 450e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson return (key.length() > 1) ? ("created-" + key) : null; 451e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 452e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson }; 453e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 454e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 4557db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson private LruCache<String, String> newRemovalLogCache(final List<String> log) { 4567db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson return new LruCache<String, String>(3) { 4577db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson @Override protected void entryRemoved( 4587db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson boolean evicted, String key, String oldValue, String newValue) { 4597db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson String message = evicted 4607db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson ? (key + "=" + oldValue) 4617db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson : (key + "=" + oldValue + ">" + newValue); 4627db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson log.add(message); 4637db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4647db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson }; 4657db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson } 4667db1b40a03ff04ac8b49b3b53839b3c5d1c6f16aJesse Wilson 467e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private void assertHit(LruCache<String, String> cache, String key, String value) { 468e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(value, cache.get(key)); 469e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedHitCount++; 470e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 471e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 472e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 473e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private void assertMiss(LruCache<String, String> cache, String key) { 474e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(null, cache.get(key)); 475e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedMissCount++; 476e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 477e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 478e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 479e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private void assertCreated(LruCache<String, String> cache, String key, String value) { 480e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(value, cache.get(key)); 481e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedMissCount++; 482e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson expectedCreateCount++; 483e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertStatistics(cache); 484e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 485e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 486e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private void assertStatistics(LruCache<?, ?> cache) { 487e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("create count", expectedCreateCount, cache.createCount()); 488e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("put count", expectedPutCount, cache.putCount()); 489e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("hit count", expectedHitCount, cache.hitCount()); 490e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("miss count", expectedMissCount, cache.missCount()); 491e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals("eviction count", expectedEvictionCount, cache.evictionCount()); 492e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 493e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 494e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson private <T> void assertSnapshot(LruCache<T, T> cache, T... keysAndValues) { 495e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson List<T> actualKeysAndValues = new ArrayList<T>(); 496e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson for (Map.Entry<T, T> entry : cache.snapshot().entrySet()) { 497e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson actualKeysAndValues.add(entry.getKey()); 498e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson actualKeysAndValues.add(entry.getValue()); 499e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 500e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson 501e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson // assert using lists because order is important for LRUs 502e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson assertEquals(Arrays.asList(keysAndValues), actualKeysAndValues); 503e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson } 504e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson} 505