379 lines
12 KiB
Java
379 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2011 The Guava Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
* in compliance with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
|
|
package com.google.common.cache;
|
|
|
|
import static com.google.common.cache.CacheTesting.checkEmpty;
|
|
import static com.google.common.cache.TestingCacheLoaders.identityLoader;
|
|
import static java.util.Arrays.asList;
|
|
import static java.util.concurrent.TimeUnit.DAYS;
|
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
|
|
import com.google.common.base.Function;
|
|
import com.google.common.cache.CacheBuilderFactory.DurationSpec;
|
|
import com.google.common.cache.LocalCache.Strength;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import com.google.common.collect.Iterables;
|
|
import com.google.common.collect.Maps;
|
|
import com.google.common.testing.EqualsTester;
|
|
import java.util.Collection;
|
|
import java.util.Map.Entry;
|
|
import java.util.Set;
|
|
import java.util.concurrent.ExecutionException;
|
|
import junit.framework.TestCase;
|
|
|
|
/**
|
|
* {@link LoadingCache} tests that deal with empty caches.
|
|
*
|
|
* @author mike nonemacher
|
|
*/
|
|
|
|
public class EmptyCachesTest extends TestCase {
|
|
|
|
public void testEmpty() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
|
|
public void testInvalidate_empty() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
cache.getUnchecked("a");
|
|
cache.getUnchecked("b");
|
|
cache.invalidate("a");
|
|
cache.invalidate("b");
|
|
cache.invalidate(0);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testInvalidateAll_empty() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
cache.getUnchecked("a");
|
|
cache.getUnchecked("b");
|
|
cache.getUnchecked("c");
|
|
cache.invalidateAll();
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
|
|
public void testEquals_null() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
assertFalse(cache.equals(null));
|
|
}
|
|
}
|
|
|
|
public void testEqualsAndHashCode_different() {
|
|
for (CacheBuilder<Object, Object> builder : cacheFactory().buildAllPermutations()) {
|
|
// all caches should be different: instance equality
|
|
new EqualsTester()
|
|
.addEqualityGroup(builder.build(identityLoader()))
|
|
.addEqualityGroup(builder.build(identityLoader()))
|
|
.addEqualityGroup(builder.build(identityLoader()))
|
|
.testEquals();
|
|
}
|
|
}
|
|
|
|
public void testGet_null() throws ExecutionException {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
try {
|
|
cache.get(null);
|
|
fail("Expected NullPointerException");
|
|
} catch (NullPointerException expected) {
|
|
}
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testGetUnchecked_null() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
try {
|
|
cache.getUnchecked(null);
|
|
fail("Expected NullPointerException");
|
|
} catch (NullPointerException expected) {
|
|
}
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
/* ---------------- Key Set -------------- */
|
|
|
|
public void testKeySet_nullToArray() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
Set<Object> keys = cache.asMap().keySet();
|
|
try {
|
|
keys.toArray((Object[]) null);
|
|
fail();
|
|
} catch (NullPointerException expected) {
|
|
}
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testKeySet_addNotSupported() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
try {
|
|
cache.asMap().keySet().add(1);
|
|
fail();
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
|
|
try {
|
|
cache.asMap().keySet().addAll(asList(1, 2));
|
|
fail();
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void testKeySet_clear() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
warmUp(cache, 0, 100);
|
|
|
|
Set<Object> keys = cache.asMap().keySet();
|
|
keys.clear();
|
|
checkEmpty(keys);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testKeySet_empty_remove() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
Set<Object> keys = cache.asMap().keySet();
|
|
assertFalse(keys.remove(null));
|
|
assertFalse(keys.remove(6));
|
|
assertFalse(keys.remove(-6));
|
|
assertFalse(keys.removeAll(asList(null, 0, 15, 1500)));
|
|
assertFalse(keys.retainAll(asList(null, 0, 15, 1500)));
|
|
checkEmpty(keys);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testKeySet_remove() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
cache.getUnchecked(1);
|
|
cache.getUnchecked(2);
|
|
|
|
Set<Object> keys = cache.asMap().keySet();
|
|
// We don't know whether these are still in the cache, so we can't assert on the return
|
|
// values of these removes, but the cache should be empty after the removes, regardless.
|
|
keys.remove(1);
|
|
keys.remove(2);
|
|
assertFalse(keys.remove(null));
|
|
assertFalse(keys.remove(6));
|
|
assertFalse(keys.remove(-6));
|
|
assertFalse(keys.removeAll(asList(null, 0, 15, 1500)));
|
|
assertFalse(keys.retainAll(asList(null, 0, 15, 1500)));
|
|
checkEmpty(keys);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
/* ---------------- Values -------------- */
|
|
|
|
public void testValues_nullToArray() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
Collection<Object> values = cache.asMap().values();
|
|
try {
|
|
values.toArray((Object[]) null);
|
|
fail();
|
|
} catch (NullPointerException expected) {
|
|
}
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testValues_addNotSupported() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
try {
|
|
cache.asMap().values().add(1);
|
|
fail();
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
|
|
try {
|
|
cache.asMap().values().addAll(asList(1, 2));
|
|
fail();
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void testValues_clear() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
warmUp(cache, 0, 100);
|
|
|
|
Collection<Object> values = cache.asMap().values();
|
|
values.clear();
|
|
checkEmpty(values);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testValues_empty_remove() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
Collection<Object> values = cache.asMap().values();
|
|
assertFalse(values.remove(null));
|
|
assertFalse(values.remove(6));
|
|
assertFalse(values.remove(-6));
|
|
assertFalse(values.removeAll(asList(null, 0, 15, 1500)));
|
|
assertFalse(values.retainAll(asList(null, 0, 15, 1500)));
|
|
checkEmpty(values);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testValues_remove() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
cache.getUnchecked(1);
|
|
cache.getUnchecked(2);
|
|
|
|
Collection<Object> values = cache.asMap().keySet();
|
|
// We don't know whether these are still in the cache, so we can't assert on the return
|
|
// values of these removes, but the cache should be empty after the removes, regardless.
|
|
values.remove(1);
|
|
values.remove(2);
|
|
assertFalse(values.remove(null));
|
|
assertFalse(values.remove(6));
|
|
assertFalse(values.remove(-6));
|
|
assertFalse(values.removeAll(asList(null, 0, 15, 1500)));
|
|
assertFalse(values.retainAll(asList(null, 0, 15, 1500)));
|
|
checkEmpty(values);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
/* ---------------- Entry Set -------------- */
|
|
|
|
public void testEntrySet_nullToArray() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
Set<Entry<Object, Object>> entries = cache.asMap().entrySet();
|
|
try {
|
|
entries.toArray((Entry<Object, Object>[]) null);
|
|
fail();
|
|
} catch (NullPointerException expected) {
|
|
}
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testEntrySet_addNotSupported() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
try {
|
|
cache.asMap().entrySet().add(entryOf(1, 1));
|
|
fail();
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
|
|
try {
|
|
cache.asMap().values().addAll(asList(entryOf(1, 1), entryOf(2, 2)));
|
|
fail();
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void testEntrySet_clear() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
warmUp(cache, 0, 100);
|
|
|
|
Set<Entry<Object, Object>> entrySet = cache.asMap().entrySet();
|
|
entrySet.clear();
|
|
checkEmpty(entrySet);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testEntrySet_empty_remove() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
Set<Entry<Object, Object>> entrySet = cache.asMap().entrySet();
|
|
assertFalse(entrySet.remove(null));
|
|
assertFalse(entrySet.remove(entryOf(6, 6)));
|
|
assertFalse(entrySet.remove(entryOf(-6, -6)));
|
|
assertFalse(entrySet.removeAll(asList(null, entryOf(0, 0), entryOf(15, 15))));
|
|
assertFalse(entrySet.retainAll(asList(null, entryOf(0, 0), entryOf(15, 15))));
|
|
checkEmpty(entrySet);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
public void testEntrySet_remove() {
|
|
for (LoadingCache<Object, Object> cache : caches()) {
|
|
cache.getUnchecked(1);
|
|
cache.getUnchecked(2);
|
|
|
|
Set<Entry<Object, Object>> entrySet = cache.asMap().entrySet();
|
|
// We don't know whether these are still in the cache, so we can't assert on the return
|
|
// values of these removes, but the cache should be empty after the removes, regardless.
|
|
entrySet.remove(entryOf(1, 1));
|
|
entrySet.remove(entryOf(2, 2));
|
|
assertFalse(entrySet.remove(null));
|
|
assertFalse(entrySet.remove(entryOf(1, 1)));
|
|
assertFalse(entrySet.remove(entryOf(6, 6)));
|
|
assertFalse(entrySet.removeAll(asList(null, entryOf(1, 1), entryOf(15, 15))));
|
|
assertFalse(entrySet.retainAll(asList(null, entryOf(1, 1), entryOf(15, 15))));
|
|
checkEmpty(entrySet);
|
|
checkEmpty(cache);
|
|
}
|
|
}
|
|
|
|
/* ---------------- Local utilities -------------- */
|
|
|
|
/** Most of the tests in this class run against every one of these caches. */
|
|
private Iterable<LoadingCache<Object, Object>> caches() {
|
|
// lots of different ways to configure a LoadingCache
|
|
CacheBuilderFactory factory = cacheFactory();
|
|
return Iterables.transform(
|
|
factory.buildAllPermutations(),
|
|
new Function<CacheBuilder<Object, Object>, LoadingCache<Object, Object>>() {
|
|
@Override
|
|
public LoadingCache<Object, Object> apply(CacheBuilder<Object, Object> builder) {
|
|
return builder.build(identityLoader());
|
|
}
|
|
});
|
|
}
|
|
|
|
private CacheBuilderFactory cacheFactory() {
|
|
return new CacheBuilderFactory()
|
|
.withKeyStrengths(ImmutableSet.of(Strength.STRONG, Strength.WEAK))
|
|
.withValueStrengths(ImmutableSet.copyOf(Strength.values()))
|
|
.withConcurrencyLevels(ImmutableSet.of(1, 4, 16, 64))
|
|
.withMaximumSizes(ImmutableSet.of(0, 1, 10, 100, 1000))
|
|
.withInitialCapacities(ImmutableSet.of(0, 1, 10, 100, 1000))
|
|
.withExpireAfterWrites(
|
|
ImmutableSet.of(
|
|
DurationSpec.of(0, SECONDS), DurationSpec.of(1, SECONDS), DurationSpec.of(1, DAYS)))
|
|
.withExpireAfterAccesses(
|
|
ImmutableSet.of(
|
|
DurationSpec.of(0, SECONDS), DurationSpec.of(1, SECONDS), DurationSpec.of(1, DAYS)))
|
|
.withRefreshes(ImmutableSet.of(DurationSpec.of(1, SECONDS), DurationSpec.of(1, DAYS)));
|
|
}
|
|
|
|
private static void warmUp(LoadingCache<Object, Object> cache, int minimum, int maximum) {
|
|
for (int i = minimum; i < maximum; i++) {
|
|
cache.getUnchecked(i);
|
|
}
|
|
}
|
|
|
|
private Entry<Object, Object> entryOf(Object key, Object value) {
|
|
return Maps.immutableEntry(key, value);
|
|
}
|
|
}
|