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