/* * Copyright Terracotta, Inc. * * 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 org.ehcache.core.collections; import org.ehcache.core.collections.ConcurrentWeakIdentityHashMap; import org.junit.Test; import java.util.AbstractMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; /** * @author Alex Snaps */ public class ConcurrentWeakIdentityHashMapTest { @Test public void testBasicOperations() { final ConcurrentWeakIdentityHashMap<Integer, String> map = new ConcurrentWeakIdentityHashMap<Integer, String>(); final Integer key = 1; final String firstValue = "foo"; final String otherValue = "bar"; assertThat(map.containsKey(key), is(false)); assertThat(map.get(key), nullValue()); assertThat(map.put(key, firstValue), nullValue()); assertThat(map.containsKey(key), is(true)); assertThat(map.putIfAbsent(key, otherValue), is(firstValue)); assertThat(map.replace(key, otherValue, firstValue), is(false)); assertThat(map.get(key), is(firstValue)); assertThat(map.replace(key, firstValue, otherValue), is(true)); assertThat(map.get(key), is(otherValue)); assertThat(map.remove(key, firstValue), is(false)); assertThat(map.get(key), is(otherValue)); assertThat(map.containsKey(key), is(true)); assertThat(map.remove(key, otherValue), is(true)); assertThat(map.containsKey(key), is(false)); assertThat(map.get(key), nullValue()); assertThat(map.putIfAbsent(key, otherValue), nullValue()); assertThat(map.get(key), is(otherValue)); assertThat(map.remove(key), is(otherValue)); assertThat(map.containsKey(key), is(false)); assertThat(map.get(key), nullValue()); } @Test public void testSizeAccountsForGCedKeys() { final ConcurrentWeakIdentityHashMap<Object, String> map = new ConcurrentWeakIdentityHashMap<Object, String>(); final String v = "present"; addToMap(map, "gone"); map.put(1, v); while(map.size() > 1) { System.gc(); } assertThat(map.values().size(), is(1)); assertThat(map.values().iterator().next(), is(v)); } @Test public void testRemoveAccountsForReference() { final ConcurrentWeakIdentityHashMap<Object, String> map = new ConcurrentWeakIdentityHashMap<Object, String>(); final Integer key = 1; final String v = "present"; map.put(key, v); assertThat(map.remove(key), is(v)); } @Test public void testIteration() throws InterruptedException { final ConcurrentWeakIdentityHashMap<Object, Integer> map = new ConcurrentWeakIdentityHashMap<Object, Integer>(); int i = 0; while(i < 10240) { if (i % 1024 == 0) { map.put(i++, i); } else { addToMap(map, i++); } } System.gc(); System.gc(); Thread.sleep(500); System.gc(); int size = 0; // This relies on the entrySet keeping a hard ref to all keys in the map at invocation time for (Map.Entry<Object, Integer> entry : map.entrySet()) { i--; size = map.size(); assertThat(entry.getKey(), notNullValue()); } assertThat(i, not(is(0))); assertThat(size, not(is(0))); } <V> Object addToMap(final ConcurrentMap<Object, V> map, final V v) { final Object key = new Object(); map.put(key, v); return key; } @Test public void testKeySetSize() throws Exception { ConcurrentWeakIdentityHashMap<String, String> map = new ConcurrentWeakIdentityHashMap<String, String>(); Set<String> keys = map.keySet(); String key1 = "key1"; String key2 = "key2"; String key3 = "key3"; map.put(key1, "value1"); map.put(key2, "value2"); map.put(key3, "value3"); assertThat(keys.size(), is(3)); } @Test public void testKeySetContainsReflectsMapChanges() throws Exception { ConcurrentWeakIdentityHashMap<String, String> map = new ConcurrentWeakIdentityHashMap<String, String>(); Set<String> keys = map.keySet(); String key1 = "key1"; String key2 = "key2"; String key3 = "key3"; map.put(key1, "value1"); map.put(key2, "value2"); map.put(key3, "value3"); assertThat(keys.contains(key1), is(true)); assertThat(keys.contains(key2), is(true)); assertThat(keys.contains(key3), is(true)); } @Test public void testKeySetIteratorReflectsMapChanges() { ConcurrentWeakIdentityHashMap<String, String> map = new ConcurrentWeakIdentityHashMap<String, String>(); Set<String> keys = map.keySet(); String key1 = "key1"; String key2 = "key2"; String key3 = "key3"; map.put(key1, "value1"); map.put(key2, "value2"); map.put(key3, "value3"); Iterator<String> iterator = keys.iterator(); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next(), startsWith("key")); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next(), startsWith("key")); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next(), startsWith("key")); assertThat(iterator.hasNext(), is(false)); } @Test public void testEntrySetSize() throws Exception { ConcurrentWeakIdentityHashMap<String, String> map = new ConcurrentWeakIdentityHashMap<String, String>(); Set<Map.Entry<String, String>> entries = map.entrySet(); String key1 = "key1"; String key2 = "key2"; String key3 = "key3"; map.put(key1, "value1"); map.put(key2, "value2"); map.put(key3, "value3"); assertThat(entries.size(), is(3)); } @Test public void testEntrySetContainsReflectsMapChanges() throws Exception { ConcurrentWeakIdentityHashMap<String, String> map = new ConcurrentWeakIdentityHashMap<String, String>(); Set<Map.Entry<String, String>> entries = map.entrySet(); String key1 = "key1"; String key2 = "key2"; String key3 = "key3"; map.put(key1, "value1"); map.put(key2, "value2"); map.put(key3, "value3"); assertThat(entries.contains(new AbstractMap.SimpleEntry<String, String>("key1", "value1")), is(true)); assertThat(entries.contains(new AbstractMap.SimpleEntry<String, String>("key1", "value1")), is(true)); assertThat(entries.contains(new AbstractMap.SimpleEntry<String, String>("key1", "value1")), is(true)); } @Test public void testEntrySetIteratorReflectsMapChanges() { ConcurrentWeakIdentityHashMap<String, String> map = new ConcurrentWeakIdentityHashMap<String, String>(); Set<Map.Entry<String, String>> entries = map.entrySet(); String key1 = "key1"; String key2 = "key2"; String key3 = "key3"; map.put(key1, "value1"); map.put(key2, "value2"); map.put(key3, "value3"); Iterator<Map.Entry<String, String>> iterator = entries.iterator(); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next().getKey(), startsWith("key")); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next().getKey(), startsWith("key")); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next().getKey(), startsWith("key")); assertThat(iterator.hasNext(), is(false)); } }