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