/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.commons.collections.map; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import junit.framework.Test; import junit.textui.TestRunner; import org.apache.commons.collections.BulkTest; import org.apache.commons.collections.OrderedMap; import org.apache.commons.collections.ResettableIterator; /** * JUnit tests. * * @version $Revision: 646780 $ $Date: 2008-04-10 13:48:07 +0100 (Thu, 10 Apr 2008) $ * * @author Stephen Colebourne */ public class TestLRUMap extends AbstractTestOrderedMap { public TestLRUMap(String testName) { super(testName); } public static void main(String[] args) { TestRunner.run(suite()); } public static Test suite() { return BulkTest.makeSuite(TestLRUMap.class); } public Map makeEmptyMap() { return new LRUMap(); } public boolean isGetStructuralModify() { return true; } public String getCompatibilityVersion() { return "3"; } //----------------------------------------------------------------------- public void testLRU() { if (isPutAddSupported() == false || isPutChangeSupported() == false) return; Object[] keys = getSampleKeys(); Object[] values = getSampleValues(); Iterator it = null; LRUMap map = new LRUMap(2); assertEquals(0, map.size()); assertEquals(false, map.isFull()); assertEquals(2, map.maxSize()); map.put(keys[0], values[0]); assertEquals(1, map.size()); assertEquals(false, map.isFull()); assertEquals(2, map.maxSize()); map.put(keys[1], values[1]); assertEquals(2, map.size()); assertEquals(true, map.isFull()); assertEquals(2, map.maxSize()); it = map.keySet().iterator(); assertSame(keys[0], it.next()); assertSame(keys[1], it.next()); it = map.values().iterator(); assertSame(values[0], it.next()); assertSame(values[1], it.next()); map.put(keys[2], values[2]); assertEquals(2, map.size()); assertEquals(true, map.isFull()); assertEquals(2, map.maxSize()); it = map.keySet().iterator(); assertSame(keys[1], it.next()); assertSame(keys[2], it.next()); it = map.values().iterator(); assertSame(values[1], it.next()); assertSame(values[2], it.next()); map.put(keys[2], values[0]); assertEquals(2, map.size()); assertEquals(true, map.isFull()); assertEquals(2, map.maxSize()); it = map.keySet().iterator(); assertSame(keys[1], it.next()); assertSame(keys[2], it.next()); it = map.values().iterator(); assertSame(values[1], it.next()); assertSame(values[0], it.next()); map.put(keys[1], values[3]); assertEquals(2, map.size()); assertEquals(true, map.isFull()); assertEquals(2, map.maxSize()); it = map.keySet().iterator(); assertSame(keys[2], it.next()); assertSame(keys[1], it.next()); it = map.values().iterator(); assertSame(values[0], it.next()); assertSame(values[3], it.next()); } //----------------------------------------------------------------------- public void testReset() { resetEmpty(); OrderedMap ordered = (OrderedMap) map; ((ResettableIterator) ordered.mapIterator()).reset(); resetFull(); ordered = (OrderedMap) map; List list = new ArrayList(ordered.keySet()); ResettableIterator it = (ResettableIterator) ordered.mapIterator(); assertSame(list.get(0), it.next()); assertSame(list.get(1), it.next()); it.reset(); assertSame(list.get(0), it.next()); } //----------------------------------------------------------------------- public void testAccessOrder() { if (isPutAddSupported() == false || isPutChangeSupported() == false) return; Object[] keys = getSampleKeys(); Object[] values = getSampleValues(); Iterator it = null; resetEmpty(); map.put(keys[0], values[0]); map.put(keys[1], values[1]); it = map.keySet().iterator(); assertSame(keys[0], it.next()); assertSame(keys[1], it.next()); it = map.values().iterator(); assertSame(values[0], it.next()); assertSame(values[1], it.next()); // no change to order map.put(keys[1], values[1]); it = map.keySet().iterator(); assertSame(keys[0], it.next()); assertSame(keys[1], it.next()); it = map.values().iterator(); assertSame(values[0], it.next()); assertSame(values[1], it.next()); // no change to order map.put(keys[1], values[2]); it = map.keySet().iterator(); assertSame(keys[0], it.next()); assertSame(keys[1], it.next()); it = map.values().iterator(); assertSame(values[0], it.next()); assertSame(values[2], it.next()); // change to order map.put(keys[0], values[3]); it = map.keySet().iterator(); assertSame(keys[1], it.next()); assertSame(keys[0], it.next()); it = map.values().iterator(); assertSame(values[2], it.next()); assertSame(values[3], it.next()); // change to order map.get(keys[1]); it = map.keySet().iterator(); assertSame(keys[0], it.next()); assertSame(keys[1], it.next()); it = map.values().iterator(); assertSame(values[3], it.next()); assertSame(values[2], it.next()); // change to order map.get(keys[0]); it = map.keySet().iterator(); assertSame(keys[1], it.next()); assertSame(keys[0], it.next()); it = map.values().iterator(); assertSame(values[2], it.next()); assertSame(values[3], it.next()); // no change to order map.get(keys[0]); it = map.keySet().iterator(); assertSame(keys[1], it.next()); assertSame(keys[0], it.next()); it = map.values().iterator(); assertSame(values[2], it.next()); assertSame(values[3], it.next()); } public void testClone() { LRUMap map = new LRUMap(10); map.put("1", "1"); Map cloned = (Map) map.clone(); assertEquals(map.size(), cloned.size()); assertSame(map.get("1"), cloned.get("1")); } public void testRemoveLRU() { MockLRUMapSubclass map = new MockLRUMapSubclass(2); assertNull(map.entry); map.put("A", "a"); assertNull(map.entry); map.put("B", "b"); assertNull(map.entry); map.put("C", "c"); // removes oldest, which is A=a assertNotNull(map.entry); assertEquals("A", map.key); assertEquals("a", map.value); assertEquals("C", map.entry.getKey()); // entry is reused assertEquals("c", map.entry.getValue()); // entry is reused assertEquals(false, map.containsKey("A")); assertEquals(true, map.containsKey("B")); assertEquals(true, map.containsKey("C")); } static class MockLRUMapSubclass extends LRUMap { LinkEntry entry; Object key; Object value; MockLRUMapSubclass(int size) { super(size); } protected boolean removeLRU(LinkEntry entry) { this.entry = entry; this.key = entry.getKey(); this.value = entry.getValue(); return true; } } public void testRemoveLRUBlocksRemove() { MockLRUMapSubclassBlocksRemove map = new MockLRUMapSubclassBlocksRemove(2, false); assertEquals(0, map.size()); map.put("A", "a"); assertEquals(1, map.size()); map.put("B", "b"); assertEquals(2, map.size()); map.put("C", "c"); // should remove oldest, which is A=a, but this is blocked assertEquals(3, map.size()); assertEquals(2, map.maxSize()); assertEquals(true, map.containsKey("A")); assertEquals(true, map.containsKey("B")); assertEquals(true, map.containsKey("C")); } public void testRemoveLRUBlocksRemoveScan() { MockLRUMapSubclassBlocksRemove map = new MockLRUMapSubclassBlocksRemove(2, true); assertEquals(0, map.size()); map.put("A", "a"); assertEquals(1, map.size()); map.put("B", "b"); assertEquals(2, map.size()); map.put("C", "c"); // should remove oldest, which is A=a, but this is blocked assertEquals(3, map.size()); assertEquals(2, map.maxSize()); assertEquals(true, map.containsKey("A")); assertEquals(true, map.containsKey("B")); assertEquals(true, map.containsKey("C")); } static class MockLRUMapSubclassBlocksRemove extends LRUMap { MockLRUMapSubclassBlocksRemove(int size, boolean scanUntilRemove) { super(size, scanUntilRemove); } protected boolean removeLRU(LinkEntry entry) { return false; } } public void testRemoveLRUFirstBlocksRemove() { MockLRUMapSubclassFirstBlocksRemove map = new MockLRUMapSubclassFirstBlocksRemove(2); assertEquals(0, map.size()); map.put("A", "a"); assertEquals(1, map.size()); map.put("B", "b"); assertEquals(2, map.size()); map.put("C", "c"); // should remove oldest, which is A=a but this is blocked - so advance to B=b assertEquals(2, map.size()); assertEquals(2, map.maxSize()); assertEquals(true, map.containsKey("A")); assertEquals(false, map.containsKey("B")); assertEquals(true, map.containsKey("C")); } static class MockLRUMapSubclassFirstBlocksRemove extends LRUMap { MockLRUMapSubclassFirstBlocksRemove(int size) { super(size, true); } protected boolean removeLRU(LinkEntry entry) { if ("a".equals(entry.getValue())) { return false; } else { return true; } } } //----------------------------------------------------------------------- static class SingleHashCode { private final String code; SingleHashCode(String code) { this.code = code; } public int hashCode() { // always return the same hashcode // that way, it will end up in the same bucket return 12; } public String toString() { return "SingleHashCode:" + code; } } public void testInternalState_Buckets() { if (isPutAddSupported() == false || isPutChangeSupported() == false) return; SingleHashCode one = new SingleHashCode("1"); SingleHashCode two = new SingleHashCode("2"); SingleHashCode three = new SingleHashCode("3"); SingleHashCode four = new SingleHashCode("4"); SingleHashCode five = new SingleHashCode("5"); SingleHashCode six = new SingleHashCode("6"); LRUMap map = new LRUMap(3, 1.0f); int hashIndex = map.hashIndex(map.hash(one), 4); map.put(one, "A"); map.put(two, "B"); map.put(three, "C"); assertEquals(4, map.data.length); assertEquals(3, map.size); assertEquals(null, map.header.next); assertEquals(one, map.header.after.key); // LRU assertEquals(two, map.header.after.after.key); assertEquals(three, map.header.after.after.after.key); // MRU assertEquals(three, map.data[hashIndex].key); assertEquals(two, map.data[hashIndex].next.key); assertEquals(one, map.data[hashIndex].next.next.key); map.put(four, "D"); // reuses last in next list assertEquals(4, map.data.length); assertEquals(3, map.size); assertEquals(null, map.header.next); assertEquals(two, map.header.after.key); // LRU assertEquals(three, map.header.after.after.key); assertEquals(four, map.header.after.after.after.key); // MRU assertEquals(four, map.data[hashIndex].key); assertEquals(three, map.data[hashIndex].next.key); assertEquals(two, map.data[hashIndex].next.next.key); map.get(three); assertEquals(4, map.data.length); assertEquals(3, map.size); assertEquals(null, map.header.next); assertEquals(two, map.header.after.key); // LRU assertEquals(four, map.header.after.after.key); assertEquals(three, map.header.after.after.after.key); // MRU assertEquals(four, map.data[hashIndex].key); assertEquals(three, map.data[hashIndex].next.key); assertEquals(two, map.data[hashIndex].next.next.key); map.put(five, "E"); // reuses last in next list assertEquals(4, map.data.length); assertEquals(3, map.size); assertEquals(null, map.header.next); assertEquals(four, map.header.after.key); // LRU assertEquals(three, map.header.after.after.key); assertEquals(five, map.header.after.after.after.key); // MRU assertEquals(five, map.data[hashIndex].key); assertEquals(four, map.data[hashIndex].next.key); assertEquals(three, map.data[hashIndex].next.next.key); map.get(three); map.get(five); assertEquals(4, map.data.length); assertEquals(3, map.size); assertEquals(null, map.header.next); assertEquals(four, map.header.after.key); // LRU assertEquals(three, map.header.after.after.key); assertEquals(five, map.header.after.after.after.key); // MRU assertEquals(five, map.data[hashIndex].key); assertEquals(four, map.data[hashIndex].next.key); assertEquals(three, map.data[hashIndex].next.next.key); map.put(six, "F"); // reuses middle in next list assertEquals(4, map.data.length); assertEquals(3, map.size); assertEquals(null, map.header.next); assertEquals(three, map.header.after.key); // LRU assertEquals(five, map.header.after.after.key); assertEquals(six, map.header.after.after.after.key); // MRU assertEquals(six, map.data[hashIndex].key); assertEquals(five, map.data[hashIndex].next.key); assertEquals(three, map.data[hashIndex].next.next.key); } public void testInternalState_getEntry_int() { if (isPutAddSupported() == false || isPutChangeSupported() == false) return; SingleHashCode one = new SingleHashCode("1"); SingleHashCode two = new SingleHashCode("2"); SingleHashCode three = new SingleHashCode("3"); SingleHashCode four = new SingleHashCode("4"); SingleHashCode five = new SingleHashCode("5"); SingleHashCode six = new SingleHashCode("6"); LRUMap map = new LRUMap(3, 1.0f); int hashIndex = map.hashIndex(map.hash(one), 4); map.put(one, "A"); map.put(two, "B"); map.put(three, "C"); assertEquals(one, map.getEntry(0).key); assertEquals(two, map.getEntry(1).key); assertEquals(three, map.getEntry(2).key); try { map.getEntry(-1); fail(); } catch (IndexOutOfBoundsException ex) {} try { map.getEntry(3); fail(); } catch (IndexOutOfBoundsException ex) {} } // public void testCreate() throws Exception { // resetEmpty(); // writeExternalFormToDisk((java.io.Serializable) map, "D:/dev/collections/data/test/LRUMap.emptyCollection.version3.obj"); // resetFull(); // writeExternalFormToDisk((java.io.Serializable) map, "D:/dev/collections/data/test/LRUMap.fullCollection.version3.obj"); // } }