1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.cache; 16 17 import static com.google.common.cache.CacheTesting.checkEmpty; 18 import static com.google.common.cache.TestingCacheLoaders.identityLoader; 19 import static java.util.Arrays.asList; 20 import static java.util.concurrent.TimeUnit.DAYS; 21 import static java.util.concurrent.TimeUnit.SECONDS; 22 import static org.junit.Assert.assertThrows; 23 24 import com.google.common.base.Function; 25 import com.google.common.cache.CacheBuilderFactory.DurationSpec; 26 import com.google.common.cache.LocalCache.Strength; 27 import com.google.common.collect.ImmutableSet; 28 import com.google.common.collect.Iterables; 29 import com.google.common.collect.Maps; 30 import com.google.common.testing.EqualsTester; 31 import java.util.Collection; 32 import java.util.Map.Entry; 33 import java.util.Set; 34 import java.util.concurrent.ExecutionException; 35 import junit.framework.TestCase; 36 37 /** 38 * {@link LoadingCache} tests that deal with empty caches. 39 * 40 * @author mike nonemacher 41 */ 42 43 public class EmptyCachesTest extends TestCase { 44 testEmpty()45 public void testEmpty() { 46 for (LoadingCache<Object, Object> cache : caches()) { 47 checkEmpty(cache); 48 } 49 } 50 51 testInvalidate_empty()52 public void testInvalidate_empty() { 53 for (LoadingCache<Object, Object> cache : caches()) { 54 cache.getUnchecked("a"); 55 cache.getUnchecked("b"); 56 cache.invalidate("a"); 57 cache.invalidate("b"); 58 cache.invalidate(0); 59 checkEmpty(cache); 60 } 61 } 62 testInvalidateAll_empty()63 public void testInvalidateAll_empty() { 64 for (LoadingCache<Object, Object> cache : caches()) { 65 cache.getUnchecked("a"); 66 cache.getUnchecked("b"); 67 cache.getUnchecked("c"); 68 cache.invalidateAll(); 69 checkEmpty(cache); 70 } 71 } 72 73 testEquals_null()74 public void testEquals_null() { 75 for (LoadingCache<Object, Object> cache : caches()) { 76 assertFalse(cache.equals(null)); 77 } 78 } 79 testEqualsAndHashCode_different()80 public void testEqualsAndHashCode_different() { 81 for (CacheBuilder<Object, Object> builder : cacheFactory().buildAllPermutations()) { 82 // all caches should be different: instance equality 83 new EqualsTester() 84 .addEqualityGroup(builder.build(identityLoader())) 85 .addEqualityGroup(builder.build(identityLoader())) 86 .addEqualityGroup(builder.build(identityLoader())) 87 .testEquals(); 88 } 89 } 90 testGet_null()91 public void testGet_null() throws ExecutionException { 92 for (LoadingCache<Object, Object> cache : caches()) { 93 assertThrows(NullPointerException.class, () -> cache.get(null)); 94 checkEmpty(cache); 95 } 96 } 97 testGetUnchecked_null()98 public void testGetUnchecked_null() { 99 for (LoadingCache<Object, Object> cache : caches()) { 100 assertThrows(NullPointerException.class, () -> cache.getUnchecked(null)); 101 checkEmpty(cache); 102 } 103 } 104 105 /* ---------------- Key Set -------------- */ 106 testKeySet_nullToArray()107 public void testKeySet_nullToArray() { 108 for (LoadingCache<Object, Object> cache : caches()) { 109 Set<Object> keys = cache.asMap().keySet(); 110 assertThrows(NullPointerException.class, () -> keys.toArray((Object[]) null)); 111 checkEmpty(cache); 112 } 113 } 114 testKeySet_addNotSupported()115 public void testKeySet_addNotSupported() { 116 for (LoadingCache<Object, Object> cache : caches()) { 117 assertThrows(UnsupportedOperationException.class, () -> cache.asMap().keySet().add(1)); 118 119 assertThrows( 120 UnsupportedOperationException.class, () -> cache.asMap().keySet().addAll(asList(1, 2))); 121 } 122 } 123 124 testKeySet_clear()125 public void testKeySet_clear() { 126 for (LoadingCache<Object, Object> cache : caches()) { 127 warmUp(cache, 0, 100); 128 129 Set<Object> keys = cache.asMap().keySet(); 130 keys.clear(); 131 checkEmpty(keys); 132 checkEmpty(cache); 133 } 134 } 135 testKeySet_empty_remove()136 public void testKeySet_empty_remove() { 137 for (LoadingCache<Object, Object> cache : caches()) { 138 Set<Object> keys = cache.asMap().keySet(); 139 assertFalse(keys.remove(null)); 140 assertFalse(keys.remove(6)); 141 assertFalse(keys.remove(-6)); 142 assertFalse(keys.removeAll(asList(null, 0, 15, 1500))); 143 assertFalse(keys.retainAll(asList(null, 0, 15, 1500))); 144 checkEmpty(keys); 145 checkEmpty(cache); 146 } 147 } 148 testKeySet_remove()149 public void testKeySet_remove() { 150 for (LoadingCache<Object, Object> cache : caches()) { 151 cache.getUnchecked(1); 152 cache.getUnchecked(2); 153 154 Set<Object> keys = cache.asMap().keySet(); 155 // We don't know whether these are still in the cache, so we can't assert on the return 156 // values of these removes, but the cache should be empty after the removes, regardless. 157 keys.remove(1); 158 keys.remove(2); 159 assertFalse(keys.remove(null)); 160 assertFalse(keys.remove(6)); 161 assertFalse(keys.remove(-6)); 162 assertFalse(keys.removeAll(asList(null, 0, 15, 1500))); 163 assertFalse(keys.retainAll(asList(null, 0, 15, 1500))); 164 checkEmpty(keys); 165 checkEmpty(cache); 166 } 167 } 168 169 /* ---------------- Values -------------- */ 170 testValues_nullToArray()171 public void testValues_nullToArray() { 172 for (LoadingCache<Object, Object> cache : caches()) { 173 Collection<Object> values = cache.asMap().values(); 174 assertThrows(NullPointerException.class, () -> values.toArray((Object[]) null)); 175 checkEmpty(cache); 176 } 177 } 178 testValues_addNotSupported()179 public void testValues_addNotSupported() { 180 for (LoadingCache<Object, Object> cache : caches()) { 181 assertThrows(UnsupportedOperationException.class, () -> cache.asMap().values().add(1)); 182 183 assertThrows( 184 UnsupportedOperationException.class, () -> cache.asMap().values().addAll(asList(1, 2))); 185 } 186 } 187 188 testValues_clear()189 public void testValues_clear() { 190 for (LoadingCache<Object, Object> cache : caches()) { 191 warmUp(cache, 0, 100); 192 193 Collection<Object> values = cache.asMap().values(); 194 values.clear(); 195 checkEmpty(values); 196 checkEmpty(cache); 197 } 198 } 199 testValues_empty_remove()200 public void testValues_empty_remove() { 201 for (LoadingCache<Object, Object> cache : caches()) { 202 Collection<Object> values = cache.asMap().values(); 203 assertFalse(values.remove(null)); 204 assertFalse(values.remove(6)); 205 assertFalse(values.remove(-6)); 206 assertFalse(values.removeAll(asList(null, 0, 15, 1500))); 207 assertFalse(values.retainAll(asList(null, 0, 15, 1500))); 208 checkEmpty(values); 209 checkEmpty(cache); 210 } 211 } 212 testValues_remove()213 public void testValues_remove() { 214 for (LoadingCache<Object, Object> cache : caches()) { 215 cache.getUnchecked(1); 216 cache.getUnchecked(2); 217 218 Collection<Object> values = cache.asMap().keySet(); 219 // We don't know whether these are still in the cache, so we can't assert on the return 220 // values of these removes, but the cache should be empty after the removes, regardless. 221 values.remove(1); 222 values.remove(2); 223 assertFalse(values.remove(null)); 224 assertFalse(values.remove(6)); 225 assertFalse(values.remove(-6)); 226 assertFalse(values.removeAll(asList(null, 0, 15, 1500))); 227 assertFalse(values.retainAll(asList(null, 0, 15, 1500))); 228 checkEmpty(values); 229 checkEmpty(cache); 230 } 231 } 232 233 /* ---------------- Entry Set -------------- */ 234 testEntrySet_nullToArray()235 public void testEntrySet_nullToArray() { 236 for (LoadingCache<Object, Object> cache : caches()) { 237 Set<Entry<Object, Object>> entries = cache.asMap().entrySet(); 238 assertThrows( 239 NullPointerException.class, () -> entries.toArray((Entry<Object, Object>[]) null)); 240 checkEmpty(cache); 241 } 242 } 243 testEntrySet_addNotSupported()244 public void testEntrySet_addNotSupported() { 245 for (LoadingCache<Object, Object> cache : caches()) { 246 assertThrows( 247 UnsupportedOperationException.class, () -> cache.asMap().entrySet().add(entryOf(1, 1))); 248 249 assertThrows( 250 UnsupportedOperationException.class, 251 () -> cache.asMap().values().addAll(asList(entryOf(1, 1), entryOf(2, 2)))); 252 } 253 } 254 255 testEntrySet_clear()256 public void testEntrySet_clear() { 257 for (LoadingCache<Object, Object> cache : caches()) { 258 warmUp(cache, 0, 100); 259 260 Set<Entry<Object, Object>> entrySet = cache.asMap().entrySet(); 261 entrySet.clear(); 262 checkEmpty(entrySet); 263 checkEmpty(cache); 264 } 265 } 266 testEntrySet_empty_remove()267 public void testEntrySet_empty_remove() { 268 for (LoadingCache<Object, Object> cache : caches()) { 269 Set<Entry<Object, Object>> entrySet = cache.asMap().entrySet(); 270 assertFalse(entrySet.remove(null)); 271 assertFalse(entrySet.remove(entryOf(6, 6))); 272 assertFalse(entrySet.remove(entryOf(-6, -6))); 273 assertFalse(entrySet.removeAll(asList(null, entryOf(0, 0), entryOf(15, 15)))); 274 assertFalse(entrySet.retainAll(asList(null, entryOf(0, 0), entryOf(15, 15)))); 275 checkEmpty(entrySet); 276 checkEmpty(cache); 277 } 278 } 279 testEntrySet_remove()280 public void testEntrySet_remove() { 281 for (LoadingCache<Object, Object> cache : caches()) { 282 cache.getUnchecked(1); 283 cache.getUnchecked(2); 284 285 Set<Entry<Object, Object>> entrySet = cache.asMap().entrySet(); 286 // We don't know whether these are still in the cache, so we can't assert on the return 287 // values of these removes, but the cache should be empty after the removes, regardless. 288 entrySet.remove(entryOf(1, 1)); 289 entrySet.remove(entryOf(2, 2)); 290 assertFalse(entrySet.remove(null)); 291 assertFalse(entrySet.remove(entryOf(1, 1))); 292 assertFalse(entrySet.remove(entryOf(6, 6))); 293 assertFalse(entrySet.removeAll(asList(null, entryOf(1, 1), entryOf(15, 15)))); 294 assertFalse(entrySet.retainAll(asList(null, entryOf(1, 1), entryOf(15, 15)))); 295 checkEmpty(entrySet); 296 checkEmpty(cache); 297 } 298 } 299 300 /* ---------------- Local utilities -------------- */ 301 302 /** Most of the tests in this class run against every one of these caches. */ caches()303 private Iterable<LoadingCache<Object, Object>> caches() { 304 // lots of different ways to configure a LoadingCache 305 CacheBuilderFactory factory = cacheFactory(); 306 return Iterables.transform( 307 factory.buildAllPermutations(), 308 new Function<CacheBuilder<Object, Object>, LoadingCache<Object, Object>>() { 309 @Override 310 public LoadingCache<Object, Object> apply(CacheBuilder<Object, Object> builder) { 311 return builder.build(identityLoader()); 312 } 313 }); 314 } 315 316 private CacheBuilderFactory cacheFactory() { 317 return new CacheBuilderFactory() 318 .withKeyStrengths(ImmutableSet.of(Strength.STRONG, Strength.WEAK)) 319 .withValueStrengths(ImmutableSet.copyOf(Strength.values())) 320 .withConcurrencyLevels(ImmutableSet.of(1, 4, 16, 64)) 321 .withMaximumSizes(ImmutableSet.of(0, 1, 10, 100, 1000)) 322 .withInitialCapacities(ImmutableSet.of(0, 1, 10, 100, 1000)) 323 .withExpireAfterWrites( 324 ImmutableSet.of( 325 DurationSpec.of(0, SECONDS), DurationSpec.of(1, SECONDS), DurationSpec.of(1, DAYS))) 326 .withExpireAfterAccesses( 327 ImmutableSet.of( 328 DurationSpec.of(0, SECONDS), DurationSpec.of(1, SECONDS), DurationSpec.of(1, DAYS))) 329 .withRefreshes(ImmutableSet.of(DurationSpec.of(1, SECONDS), DurationSpec.of(1, DAYS))); 330 } 331 332 private static void warmUp(LoadingCache<Object, Object> cache, int minimum, int maximum) { 333 for (int i = minimum; i < maximum; i++) { 334 cache.getUnchecked(i); 335 } 336 } 337 338 private Entry<Object, Object> entryOf(Object key, Object value) { 339 return Maps.immutableEntry(key, value); 340 } 341 } 342