11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License. 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License. 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.collect; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly; 203ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport static java.util.concurrent.TimeUnit.HOURS; 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 220888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.annotations.GwtCompatible; 230888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.annotations.GwtIncompatible; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Function; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.MapMaker.RemovalNotification; 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.MapMakerInternalMapTest.QueuingRemovalListener; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.NullPointerTester; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 290888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestCase; 300888a09821a98ac0680fad765217302858e70fa4Paul Duffin 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Map; 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Set; 330888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.ConcurrentHashMap; 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ConcurrentMap; 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch; 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutorService; 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executors; 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicInteger; 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Charles Fry 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 430888a09821a98ac0680fad765217302858e70fa4Paul Duffin@GwtCompatible(emulated = true) 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class MapMakerTest extends TestCase { 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 460888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GwtIncompatible("NullPointerTester") 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testNullParameters() throws Exception { 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NullPointerTester tester = new NullPointerTester(); 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert tester.testAllPublicInstanceMethods(new MapMaker()); 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 520888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GwtIncompatible("threads") 530888a09821a98ac0680fad765217302858e70fa4Paul Duffin 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testRemovalNotification_clear() throws InterruptedException { 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If a clear() happens while a computation is pending, we should not get a removal 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // notification. 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final CountDownLatch computingLatch = new CountDownLatch(1); 590888a09821a98ac0680fad765217302858e70fa4Paul Duffin Function<String, String> computingFunction = new DelayingIdentityLoader<String>(computingLatch); 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert QueuingRemovalListener<String, String> listener = new QueuingRemovalListener<String, String>(); 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @SuppressWarnings("deprecation") // test of deprecated code 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final ConcurrentMap<String, String> map = new MapMaker() 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .concurrencyLevel(1) 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .removalListener(listener) 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .makeComputingMap(computingFunction); 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // seed the map, so its segment's count > 0 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.put("a", "a"); 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final CountDownLatch computationStarted = new CountDownLatch(1); 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final CountDownLatch computationComplete = new CountDownLatch(1); 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert new Thread(new Runnable() { 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computationStarted.countDown(); 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.get("b"); 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computationComplete.countDown(); 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }).start(); 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // wait for the computingEntry to be created 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computationStarted.await(); 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.clear(); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // let the computation proceed 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computingLatch.countDown(); 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // don't check map.size() until we know the get("b") call is complete 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computationComplete.await(); 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // At this point, the listener should be holding the seed value (a -> a), and the map should 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // contain the computed value (b -> b), since the clear() happened before the computation 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // completed. 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, listener.size()); 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert RemovalNotification<String, String> notification = listener.remove(); 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals("a", notification.getKey()); 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals("a", notification.getValue()); 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, map.size()); 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals("b", map.get("b")); 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // "Basher tests", where we throw a bunch of stuff at a Cache and check basic invariants. 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This is a less carefully-controlled version of {@link #testRemovalNotification_clear} - this is 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * a black-box test that tries to create lots of different thread-interleavings, and asserts that 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * each computation is affected by a call to {@code clear()} (and therefore gets passed to the 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * removal listener), or else is not affected by the {@code clear()} (and therefore exists in the 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * map afterward). 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1090888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GwtIncompatible("threads") 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testRemovalNotification_clear_basher() throws InterruptedException { 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If a clear() happens close to the end of computation, one of two things should happen: 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // - computation ends first: the removal listener is called, and the map does not contain the 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // key/value pair 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // - clear() happens first: the removal listener is not called, and the map contains the pair 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountDownLatch computationLatch = new CountDownLatch(1); 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert QueuingRemovalListener<String, String> listener = new QueuingRemovalListener<String, String>(); 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @SuppressWarnings("deprecation") // test of deprecated code 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final Map<String, String> map = new MapMaker() 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .removalListener(listener) 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .concurrencyLevel(20) 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .makeComputingMap(new DelayingIdentityLoader<String>(computationLatch)); 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int nThreads = 100; 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int nTasks = 1000; 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int nSeededEntries = 100; 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Set<String> expectedKeys = Sets.newHashSetWithExpectedSize(nTasks + nSeededEntries); 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // seed the map, so its segments have a count>0; otherwise, clear() won't visit the in-progress 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // entries 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < nSeededEntries; i++) { 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String s = "b" + i; 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.put(s, s); 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert expectedKeys.add(s); 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final AtomicInteger computedCount = new AtomicInteger(); 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ExecutorService threadPool = Executors.newFixedThreadPool(nThreads); 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final CountDownLatch tasksFinished = new CountDownLatch(nTasks); 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < nTasks; i++) { 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final String s = "a" + i; 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert threadPool.submit(new Runnable() { 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.get(s); 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computedCount.incrementAndGet(); 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert tasksFinished.countDown(); 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert expectedKeys.add(s); 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert computationLatch.countDown(); 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // let some computations complete 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert while (computedCount.get() < nThreads) { 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Thread.yield(); 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.clear(); 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert tasksFinished.await(); 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Check all of the removal notifications we received: they should have had correctly-associated 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // keys and values. (An earlier bug saw removal notifications for in-progress computations, 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // which had real keys with null values.) 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Map<String, String> removalNotifications = Maps.newHashMap(); 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (RemovalNotification<String, String> notification : listener) { 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert removalNotifications.put(notification.getKey(), notification.getValue()); 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals("Unexpected key/value pair passed to removalListener", 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notification.getKey(), notification.getValue()); 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // All of the seed values should have been visible, so we should have gotten removal 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // notifications for all of them. 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < nSeededEntries; i++) { 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals("b" + i, removalNotifications.get("b" + i)); 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Each of the values added to the map should either still be there, or have seen a removal 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // notification. 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(expectedKeys, Sets.union(map.keySet(), removalNotifications.keySet())); 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(Sets.intersection(map.keySet(), removalNotifications.keySet()).isEmpty()); 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1820888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GwtIncompatible("threads") 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert static final class DelayingIdentityLoader<T> implements Function<T, T> { 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final CountDownLatch delayLatch; 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert DelayingIdentityLoader(CountDownLatch delayLatch) { 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.delayLatch = delayLatch; 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public T apply(T key) { 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert awaitUninterruptibly(delayLatch); 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return key; 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1950888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1960888a09821a98ac0680fad765217302858e70fa4Paul Duffin /* 1970888a09821a98ac0680fad765217302858e70fa4Paul Duffin * TODO(cpovirk): eliminate duplication between these tests and those in LegacyMapMakerTests and 1980888a09821a98ac0680fad765217302858e70fa4Paul Duffin * anywhere else 1990888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 2000888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2010888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** Tests for the builder. */ 2020888a09821a98ac0680fad765217302858e70fa4Paul Duffin public static class MakerTest extends TestCase { 2030888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testInitialCapacity_negative() { 2040888a09821a98ac0680fad765217302858e70fa4Paul Duffin MapMaker maker = new MapMaker(); 2050888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 2060888a09821a98ac0680fad765217302858e70fa4Paul Duffin maker.initialCapacity(-1); 2070888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 2080888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalArgumentException expected) { 2090888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2100888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2110888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2120888a09821a98ac0680fad765217302858e70fa4Paul Duffin // TODO(cpovirk): enable when ready 2130888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void xtestInitialCapacity_setTwice() { 2140888a09821a98ac0680fad765217302858e70fa4Paul Duffin MapMaker maker = new MapMaker().initialCapacity(16); 2150888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 2160888a09821a98ac0680fad765217302858e70fa4Paul Duffin // even to the same value is not allowed 2170888a09821a98ac0680fad765217302858e70fa4Paul Duffin maker.initialCapacity(16); 2180888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 2190888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalArgumentException expected) { 2200888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2210888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2220888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2230888a09821a98ac0680fad765217302858e70fa4Paul Duffin @SuppressWarnings("deprecation") // test of deprecated method 2240888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testExpiration_setTwice() { 2253ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin MapMaker maker = new MapMaker().expireAfterWrite(1, HOURS); 2260888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 2270888a09821a98ac0680fad765217302858e70fa4Paul Duffin // even to the same value is not allowed 2283ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin maker.expireAfterWrite(1, HOURS); 2290888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 2300888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) { 2310888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2320888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2330888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2340888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testMaximumSize_setTwice() { 2350888a09821a98ac0680fad765217302858e70fa4Paul Duffin MapMaker maker = new MapMaker().maximumSize(16); 2360888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 2370888a09821a98ac0680fad765217302858e70fa4Paul Duffin // even to the same value is not allowed 2380888a09821a98ac0680fad765217302858e70fa4Paul Duffin maker.maximumSize(16); 2390888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 2400888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) { 2410888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2420888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2430888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2440888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testReturnsPlainConcurrentHashMapWhenPossible() { 2450888a09821a98ac0680fad765217302858e70fa4Paul Duffin Map<?, ?> map = new MapMaker() 2460888a09821a98ac0680fad765217302858e70fa4Paul Duffin .initialCapacity(5) 2470888a09821a98ac0680fad765217302858e70fa4Paul Duffin .makeMap(); 2480888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(map instanceof ConcurrentHashMap); 2490888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2500888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2510888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2520888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** Tests of the built map with maximumSize. */ 2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin public static class MaximumSizeTest extends TestCase { 2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testPut_sizeIsZero() { 2550888a09821a98ac0680fad765217302858e70fa4Paul Duffin ConcurrentMap<Object, Object> map = 2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin new MapMaker().maximumSize(0).makeMap(); 2570888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(0, map.size()); 2580888a09821a98ac0680fad765217302858e70fa4Paul Duffin map.put(new Object(), new Object()); 2590888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(0, map.size()); 2600888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2610888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2620888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testSizeBasedEviction() { 2630888a09821a98ac0680fad765217302858e70fa4Paul Duffin int numKeys = 10; 2640888a09821a98ac0680fad765217302858e70fa4Paul Duffin int mapSize = 5; 2650888a09821a98ac0680fad765217302858e70fa4Paul Duffin ConcurrentMap<Object, Object> map = 2660888a09821a98ac0680fad765217302858e70fa4Paul Duffin new MapMaker().maximumSize(mapSize).makeMap(); 2670888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < numKeys; i++) { 2680888a09821a98ac0680fad765217302858e70fa4Paul Duffin map.put(i, i); 2690888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2700888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(mapSize, map.size()); 2710888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = numKeys - mapSize; i < mapSize; i++) { 2720888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(map.containsKey(i)); 2730888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2740888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2750888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2760888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2770888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** Tests for recursive computation. */ 2780888a09821a98ac0680fad765217302858e70fa4Paul Duffin public static class RecursiveComputationTest extends TestCase { 2790888a09821a98ac0680fad765217302858e70fa4Paul Duffin Function<Integer, String> recursiveComputer 2800888a09821a98ac0680fad765217302858e70fa4Paul Duffin = new Function<Integer, String>() { 2810888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 2820888a09821a98ac0680fad765217302858e70fa4Paul Duffin public String apply(Integer key) { 2830888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (key > 0) { 2840888a09821a98ac0680fad765217302858e70fa4Paul Duffin return key + ", " + recursiveMap.get(key - 1); 2850888a09821a98ac0680fad765217302858e70fa4Paul Duffin } else { 2860888a09821a98ac0680fad765217302858e70fa4Paul Duffin return "0"; 2870888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2880888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2890888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 2900888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2910888a09821a98ac0680fad765217302858e70fa4Paul Duffin ConcurrentMap<Integer, String> recursiveMap = new MapMaker() 2920888a09821a98ac0680fad765217302858e70fa4Paul Duffin .makeComputingMap(recursiveComputer); 2930888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2940888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testRecursiveComputation() { 2950888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("3, 2, 1, 0", recursiveMap.get(3)); 2960888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2970888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2980888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2990888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 3000888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Tests for computing functionality. 3010888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 3020888a09821a98ac0680fad765217302858e70fa4Paul Duffin public static class ComputingTest extends TestCase { 3030888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testComputerThatReturnsNull() { 3040888a09821a98ac0680fad765217302858e70fa4Paul Duffin ConcurrentMap<Integer, String> map = new MapMaker() 3050888a09821a98ac0680fad765217302858e70fa4Paul Duffin .makeComputingMap(new Function<Integer, String>() { 3060888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 3070888a09821a98ac0680fad765217302858e70fa4Paul Duffin public String apply(Integer key) { 3080888a09821a98ac0680fad765217302858e70fa4Paul Duffin return null; 3090888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3100888a09821a98ac0680fad765217302858e70fa4Paul Duffin }); 3110888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 3120888a09821a98ac0680fad765217302858e70fa4Paul Duffin map.get(1); 3130888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 3140888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (NullPointerException e) { /* expected */ } 3150888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3160888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3170888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testRuntimeException() { 3180888a09821a98ac0680fad765217302858e70fa4Paul Duffin final RuntimeException e = new RuntimeException(); 3190888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3200888a09821a98ac0680fad765217302858e70fa4Paul Duffin ConcurrentMap<Object, Object> map = new MapMaker().makeComputingMap( 3210888a09821a98ac0680fad765217302858e70fa4Paul Duffin new Function<Object, Object>() { 3220888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 3230888a09821a98ac0680fad765217302858e70fa4Paul Duffin public Object apply(Object from) { 3240888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw e; 3250888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3260888a09821a98ac0680fad765217302858e70fa4Paul Duffin }); 3270888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3280888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 3290888a09821a98ac0680fad765217302858e70fa4Paul Duffin map.get(new Object()); 3300888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 3310888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (ComputationException ce) { 3320888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertSame(e, ce.getCause()); 3330888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3340888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3350888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 337