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