/*
* Copyright 2011 Google Inc. 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.googlecode.concurrentlinkedhashmap;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.Builder;
import org.mockito.Mock;
import org.testng.annotations.Test;
import static com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.MAXIMUM_CAPACITY;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static java.util.Collections.singletonMap;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import static org.testng.Assert.fail;
/**
* A unit-test for the weigher algorithms and that the map keeps track of the
* weighted sizes.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
@Test(groups = "development")
public final class WeigherTest extends AbstractTest {
@Mock Iterable<Integer> iterable;
@Test(expectedExceptions = AssertionError.class)
public void constructor() throws Throwable {
try {
Constructor<?> constructors[] = Weighers.class.getDeclaredConstructors();
assertThat(constructors.length, is(1));
constructors[0].setAccessible(true);
constructors[0].newInstance((Object[]) null);
fail("Expected a failure to instantiate");
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
@Test(dataProvider = "collectionWeigher")
public void asEntryWeigher(Weigher<Collection<?>> weigher) {
EntryWeigher<Collection<?>, Collection<?>> entryWeigher =
Weighers.asEntryWeigher(weigher);
assertThat(entryWeigher.weightOf(emptyList(), emptyList()), is(0));
assertThat(entryWeigher.weightOf(asList(1), asList(1)), is(1));
assertThat(entryWeigher.weightOf(asList(1, 2, 3), asList(1, 2, 3)), is(3));
}
@Test(dataProvider = "singletonEntryWeigher")
public void singleton_entry(EntryWeigher<Object, Object> weigher) {
assertThat(weigher.weightOf(new Object(), new Object()), is(1));
assertThat(weigher.weightOf(emptyList(), emptyList()), is(1));
assertThat(weigher.weightOf(asList(1, 2, 3), asList(1, 2, 3)), is(1));
}
@Test(dataProvider = "singletonWeigher")
public void singleton(Weigher<Object> weigher) {
assertThat(weigher.weightOf(new Object()), is(1));
assertThat(weigher.weightOf(emptyList()), is(1));
assertThat(weigher.weightOf(asList(1, 2, 3)), is(1));
}
@Test(dataProvider = "byteArrayWeigher")
public void byteArray(Weigher<byte[]> weigher) {
assertThat(weigher.weightOf(new byte[] {}), is(0));
assertThat(weigher.weightOf(new byte[] {1}), is(1));
assertThat(weigher.weightOf(new byte[] {1, 2, 3}), is(3));
}
@Test(dataProvider = "iterableWeigher")
public void iterable(Weigher<Iterable<?>> weigher) {
when(iterable.iterator())
.thenReturn(ImmutableList.<Integer>of().iterator())
.thenReturn(ImmutableList.<Integer>of(1, 2, 3).iterator());
assertThat(weigher.weightOf(emptyList()), is(0));
assertThat(weigher.weightOf(iterable), is(0));
assertThat(weigher.weightOf(asList(1)), is(1));
assertThat(weigher.weightOf(asList(1, 2, 3)), is(3));
assertThat(weigher.weightOf(iterable), is(3));
}
@Test(dataProvider = "collectionWeigher")
public void collection(Weigher<Collection<?>> weigher) {
assertThat(weigher.weightOf(emptyList()), is(0));
assertThat(weigher.weightOf(asList(1)), is(1));
assertThat(weigher.weightOf(asList(1, 2, 3)), is(3));
}
@Test(dataProvider = "listWeigher")
public void list(Weigher<List<?>> weigher) {
assertThat(weigher.weightOf(emptyList()), is(0));
assertThat(weigher.weightOf(asList(1)), is(1));
assertThat(weigher.weightOf(asList(1, 2, 3)), is(3));
}
@Test(dataProvider = "setWeigher")
public void set(Weigher<Set<?>> weigher) {
assertThat(weigher.weightOf(emptySet()), is(0));
assertThat(weigher.weightOf(ImmutableSet.of(1)), is(1));
assertThat(weigher.weightOf(ImmutableSet.of(1, 2, 3)), is(3));
}
@Test(dataProvider = "mapWeigher")
public void map(Weigher<Map<?, ?>> weigher) {
assertThat(weigher.weightOf(emptyMap()), is(0));
assertThat(weigher.weightOf(singletonMap(1, 2)), is(1));
assertThat(weigher.weightOf(ImmutableMap.of(1, 2, 2, 3, 3, 4)), is(3));
}
@Test(dataProvider = "builder", expectedExceptions = IllegalArgumentException.class)
public void put_withNegativeWeight(Builder<Integer, Integer> builder) {
ConcurrentLinkedHashMap<Integer, Integer> map = builder
.maximumWeightedCapacity(capacity())
.weigher(weigher).build();
when(weigher.weightOf(anyInt())).thenReturn(-1);
map.put(1, 2);
}
@Test(dataProvider = "builder", expectedExceptions = IllegalArgumentException.class)
public void put_withZeroWeight(Builder<Integer, Integer> builder) {
ConcurrentLinkedHashMap<Integer, Integer> map = builder
.maximumWeightedCapacity(capacity())
.weigher(weigher).build();
doReturn(0).when(weigher).weightOf(anyInt());
map.put(1, 2);
}
@Test(dataProvider = "builder")
public void put_withNoOverflow(Builder<Integer, Integer> builder) {
ConcurrentLinkedHashMap<Integer, Integer> map = builder
.maximumWeightedCapacity(MAXIMUM_CAPACITY)
.weigher(weigher)
.build();
doReturn(Integer.MAX_VALUE).when(weigher).weightOf(anyInt());
map.putAll(ImmutableMap.of(1, 1, 2, 2));
map.weightedSize.set(MAXIMUM_CAPACITY);
map.put(3, 3);
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(MAXIMUM_CAPACITY));
}
@Test(dataProvider = "guardedWeightedMap")
public void put(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.put("a", asList(1, 2, 3));
assertThat(map.size(), is(1));
assertThat(map.weightedSize(), is(3L));
}
@Test(dataProvider = "guardedWeightedMap")
public void put_sameWeight(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
map.put("a", asList(-1, -2, -3));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(4L));
}
@Test(dataProvider = "guardedWeightedMap")
public void put_changeWeight(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
map.put("a", asList(-1, -2, -3, -4));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(5L));
}
@Test(dataProvider = "guardedWeightedMap")
public void replace_sameWeight(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
map.replace("a", asList(-1, -2, -3));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(4L));
}
@Test(dataProvider = "guardedWeightedMap")
public void replace_changeWeight(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
map.replace("a", asList(-1, -2, -3, -4));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(5L));
}
@Test(dataProvider = "guardedWeightedMap")
public void replaceConditionally_sameWeight(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
assertThat(map.replace("a", asList(1, 2, 3), asList(4, 5, 6)), is(true));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(4L));
}
@Test(dataProvider = "guardedWeightedMap")
public void replaceConditionally_changeWeight(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
map.replace("a", asList(1, 2, 3), asList(-1, -2, -3, -4));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(5L));
}
@Test(dataProvider = "guardedWeightedMap")
public void replaceConditionally_fails(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
assertThat(map.replace("a", asList(1), asList(4, 5)), is(false));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(4L));
}
@Test(dataProvider = "guardedWeightedMap")
public void remove(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
assertThat(map.remove("a"), is(asList(1, 2, 3)));
assertThat(map.size(), is(1));
assertThat(map.weightedSize(), is(1L));
}
@Test(dataProvider = "guardedWeightedMap")
public void removeConditionally(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
assertThat(map.remove("a", asList(1, 2, 3)), is(true));
assertThat(map.size(), is(1));
assertThat(map.weightedSize(), is(1L));
}
@Test(dataProvider = "guardedWeightedMap")
public void removeConditionally_fails(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
assertThat(map.remove("a", asList(-1, -2, -3)), is(false));
assertThat(map.size(), is(2));
assertThat(map.weightedSize(), is(4L));
}
@Test(dataProvider = "guardedWeightedMap")
public void clear(ConcurrentLinkedHashMap<String, List<Integer>> map) {
map.putAll(ImmutableMap.of("a", asList(1, 2, 3), "b", asList(1)));
map.clear();
assertThat(map.size(), is(0));
assertThat(map.weightedSize(), is(0L));
}
}