/*
* Copyright 2016 Ben Manes. All Rights Reserved.
*
* 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.github.benmanes.caffeine.cache;
import static com.github.benmanes.caffeine.cache.Caffeine.UNSET_INT;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import com.github.benmanes.caffeine.cache.Caffeine.Strength;
import com.github.benmanes.caffeine.cache.testing.CacheContext;
import com.github.benmanes.caffeine.cache.testing.CacheProvider;
import com.github.benmanes.caffeine.cache.testing.CacheSpec;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Compute;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Expire;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Implementation;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.InitialCapacity;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Listener;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Maximum;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Population;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Writer;
import com.github.benmanes.caffeine.cache.testing.CacheValidationListener;
import com.google.common.base.Joiner;
/**
* A test for the specification parser.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
@Listeners(CacheValidationListener.class)
@Test(dataProviderClass = CacheProvider.class)
public final class CaffeineSpecTest {
static final long UNSET_LONG = UNSET_INT;
@Test(dataProvider = "caches")
@CacheSpec(population = Population.EMPTY, compute = Compute.SYNC, writer = Writer.DISABLED,
removalListener = Listener.DEFAULT, implementation = Implementation.Caffeine)
public void specifications(CacheContext context) {
CaffeineSpec spec = toSpec(context);
Caffeine<Object, Object> builder = Caffeine.from(spec);
checkInitialCapacity(spec, context, builder);
checkMaximumWeight(spec, context, builder);
checkMaximumSize(spec, context, builder);
checkWeakKeys(spec, context, builder);
checkValueStrength(spec, context, builder);
checkExpireAfterAccess(spec, context, builder);
checkExpireAfterWrite(spec, context, builder);
checkRefreshAfterWrite(spec, context, builder);
assertThat(spec, is(equalTo(CaffeineSpec.parse(spec.toParsableString()))));
}
static CaffeineSpec toSpec(CacheContext context) {
List<String> options = new ArrayList<>();
if (context.initialCapacity() != InitialCapacity.DEFAULT) {
options.add("initialCapacity=" + context.initialCapacity().size());
}
if (context.maximum() != Maximum.DISABLED) {
String key = context.isWeighted() ? "maximumWeight" : "maximumSize";
options.add(key + "=" + context.maximum().max());
}
if (context.isWeakKeys()) {
options.add("weakKeys");
}
if (context.isWeakValues()) {
options.add("weakValues");
}
if (context.isSoftValues()) {
options.add("softValues");
}
if (context.expireAfterAccess() != Expire.DISABLED) {
long durationMin = TimeUnit.NANOSECONDS.toMinutes(context.expireAfterAccess().timeNanos());
options.add("expireAfterAccess=" + durationMin + "m");
}
if (context.expireAfterWrite() != Expire.DISABLED) {
long durationMin = TimeUnit.NANOSECONDS.toMinutes(context.expireAfterWrite().timeNanos());
options.add("expireAfterWrite=" + durationMin + "m");
}
if (context.refreshAfterWrite() != Expire.DISABLED) {
long durationMin = TimeUnit.NANOSECONDS.toMinutes(context.refreshAfterWrite().timeNanos());
options.add("refreshAfterWrite=" + durationMin + "m");
}
if (context.isRecordingStats()) {
options.add("recordStats");
}
Collections.shuffle(options);
String specString = Joiner.on(',').join(options);
return CaffeineSpec.parse(specString);
}
static void checkInitialCapacity(CaffeineSpec spec,
CacheContext context, Caffeine<?, ?> builder) {
if (context.initialCapacity() == InitialCapacity.DEFAULT) {
assertThat(spec.initialCapacity, is(UNSET_INT));
assertThat(builder.initialCapacity, is(UNSET_INT));
} else {
assertThat(spec.initialCapacity, is(context.initialCapacity().size()));
assertThat(builder.initialCapacity, is(context.initialCapacity().size()));
}
}
static void checkMaximumSize(CaffeineSpec spec, CacheContext context, Caffeine<?, ?> builder) {
if (context.isWeighted()) {
assertThat(spec.maximumSize, is(UNSET_LONG));
assertThat(builder.maximumSize, is(UNSET_LONG));
return;
}
if (context.maximum() == Maximum.DISABLED) {
assertThat(spec.maximumSize, is(UNSET_LONG));
assertThat(builder.maximumSize, is(UNSET_LONG));
} else {
assertThat(spec.maximumSize, is(context.maximum().max()));
assertThat(builder.maximumSize, is(context.maximum().max()));
}
}
static void checkMaximumWeight(CaffeineSpec spec, CacheContext context, Caffeine<?, ?> builder) {
if (!context.isWeighted()) {
assertThat(spec.maximumWeight, is(UNSET_LONG));
assertThat(builder.maximumWeight, is(UNSET_LONG));
return;
}
if (context.maximum() == Maximum.DISABLED) {
assertThat(spec.maximumWeight, is(UNSET_LONG));
assertThat(builder.maximumWeight, is(UNSET_LONG));
} else {
assertThat(spec.maximumWeight, is(context.maximum().max()));
assertThat(builder.maximumWeight, is(context.maximum().max()));
}
}
static void checkWeakKeys(CaffeineSpec spec, CacheContext context, Caffeine<?, ?> builder) {
if (context.isWeakKeys()) {
assertThat(spec.keyStrength, is(Strength.WEAK));
assertThat(builder.keyStrength, is(Strength.WEAK));
} else {
assertThat(spec.keyStrength, is(nullValue()));
assertThat(builder.keyStrength, is(nullValue()));
}
}
static void checkValueStrength(CaffeineSpec spec, CacheContext context, Caffeine<?, ?> builder) {
if (context.isWeakValues()) {
assertThat(spec.valueStrength, is(Strength.WEAK));
assertThat(builder.valueStrength, is(Strength.WEAK));
} else if (context.isSoftValues()) {
assertThat(spec.valueStrength, is(Strength.SOFT));
assertThat(builder.valueStrength, is(Strength.SOFT));
} else {
assertThat(spec.valueStrength, is(nullValue()));
assertThat(builder.valueStrength, is(nullValue()));
}
}
static void checkExpireAfterAccess(CaffeineSpec spec,
CacheContext context, Caffeine<?, ?> builder) {
if (context.expireAfterAccess() == Expire.DISABLED) {
assertThat(spec.expireAfterAccessDuration, is(UNSET_LONG));
assertThat(spec.expireAfterAccessTimeUnit, is(nullValue()));
assertThat(builder.expireAfterAccessNanos, is(UNSET_LONG));
} else {
long durationMin = TimeUnit.NANOSECONDS.toMinutes(context.expireAfterAccess().timeNanos());
assertThat(spec.expireAfterAccessDuration, is(durationMin));
assertThat(spec.expireAfterAccessTimeUnit, is(TimeUnit.MINUTES));
assertThat(builder.expireAfterAccessNanos, is(TimeUnit.MINUTES.toNanos(durationMin)));
}
}
static void checkExpireAfterWrite(CaffeineSpec spec,
CacheContext context, Caffeine<?, ?> builder) {
if (context.expireAfterWrite() == Expire.DISABLED) {
assertThat(spec.expireAfterWriteDuration, is(UNSET_LONG));
assertThat(spec.expireAfterWriteTimeUnit, is(nullValue()));
assertThat(builder.expireAfterWriteNanos, is(UNSET_LONG));
} else {
long durationMin = TimeUnit.NANOSECONDS.toMinutes(context.expireAfterWrite().timeNanos());
assertThat(spec.expireAfterWriteDuration, is(durationMin));
assertThat(spec.expireAfterWriteTimeUnit, is(TimeUnit.MINUTES));
assertThat(builder.expireAfterWriteNanos, is(TimeUnit.MINUTES.toNanos(durationMin)));
}
}
static void checkRefreshAfterWrite(CaffeineSpec spec,
CacheContext context, Caffeine<?, ?> builder) {
if (context.refreshAfterWrite() == Expire.DISABLED) {
assertThat(spec.refreshAfterWriteDuration, is(UNSET_LONG));
assertThat(spec.refreshAfterWriteTimeUnit, is(nullValue()));
assertThat(builder.refreshNanos, is(UNSET_LONG));
} else {
long durationMin = TimeUnit.NANOSECONDS.toMinutes(context.refreshAfterWrite().timeNanos());
assertThat(spec.refreshAfterWriteDuration, is(durationMin));
assertThat(spec.refreshAfterWriteTimeUnit, is(TimeUnit.MINUTES));
assertThat(builder.refreshNanos, is(TimeUnit.MINUTES.toNanos(durationMin)));
}
}
}