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