1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.collections.map; 18 19 import java.lang.ref.WeakReference; 20 import java.util.Map; 21 22 import junit.framework.Test; 23 24 import org.apache.commons.collections.BulkTest; 25 26 /** 27 * Tests for ReferenceMap. 28 * 29 * @version $Revision: 646780 $ $Date: 2008-04-10 14:48:07 +0200 (Thu, 10 Apr 2008) $ 30 * 31 * @author Paul Jack 32 * @author Guilhem Lavaux 33 */ 34 public class TestReferenceMap extends AbstractTestIterableMap { 35 TestReferenceMap(String testName)36 public TestReferenceMap(String testName) { 37 super(testName); 38 } 39 suite()40 public static Test suite() { 41 return BulkTest.makeSuite(TestReferenceMap.class); 42 } 43 main(String args[])44 public static void main(String args[]) { 45 String[] testCaseName = { TestReferenceMap.class.getName() }; 46 junit.textui.TestRunner.main(testCaseName); 47 } 48 makeEmptyMap()49 public Map makeEmptyMap() { 50 ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 51 return map; 52 } 53 isAllowNullKey()54 public boolean isAllowNullKey() { 55 return false; 56 } 57 isAllowNullValue()58 public boolean isAllowNullValue() { 59 return false; 60 } 61 getCompatibilityVersion()62 public String getCompatibilityVersion() { 63 return "3.1"; 64 } 65 66 //----------------------------------------------------------------------- testNullHandling()67 public void testNullHandling() { 68 resetFull(); 69 assertEquals(null, map.get(null)); 70 assertEquals(false, map.containsKey(null)); 71 assertEquals(false, map.containsValue(null)); 72 assertEquals(null, map.remove(null)); 73 assertEquals(false, map.entrySet().contains(null)); 74 assertEquals(false, map.keySet().contains(null)); 75 assertEquals(false, map.values().contains(null)); 76 try { 77 map.put(null, null); 78 fail(); 79 } catch (NullPointerException ex) {} 80 try { 81 map.put(new Object(), null); 82 fail(); 83 } catch (NullPointerException ex) {} 84 try { 85 map.put(null, new Object()); 86 fail(); 87 } catch (NullPointerException ex) {} 88 } 89 90 //----------------------------------------------------------------------- 91 /* 92 // Tests often fail because gc is uncontrollable 93 94 public void testPurge() { 95 ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 96 Object[] hard = new Object[10]; 97 for (int i = 0; i < hard.length; i++) { 98 hard[i] = new Object(); 99 map.put(hard[i], new Object()); 100 } 101 gc(); 102 assertTrue("map should be empty after purge of weak values", map.isEmpty()); 103 104 for (int i = 0; i < hard.length; i++) { 105 map.put(new Object(), hard[i]); 106 } 107 gc(); 108 assertTrue("map should be empty after purge of weak keys", map.isEmpty()); 109 110 for (int i = 0; i < hard.length; i++) { 111 map.put(new Object(), hard[i]); 112 map.put(hard[i], new Object()); 113 } 114 115 gc(); 116 assertTrue("map should be empty after purge of weak keys and values", map.isEmpty()); 117 } 118 119 120 public void testGetAfterGC() { 121 ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 122 for (int i = 0; i < 10; i++) { 123 map.put(new Integer(i), new Integer(i)); 124 } 125 126 gc(); 127 for (int i = 0; i < 10; i++) { 128 Integer I = new Integer(i); 129 assertTrue("map.containsKey should return false for GC'd element", !map.containsKey(I)); 130 assertTrue("map.get should return null for GC'd element", map.get(I) == null); 131 } 132 } 133 134 135 public void testEntrySetIteratorAfterGC() { 136 ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 137 Object[] hard = new Object[10]; 138 for (int i = 0; i < 10; i++) { 139 hard[i] = new Integer(10 + i); 140 map.put(new Integer(i), new Integer(i)); 141 map.put(hard[i], hard[i]); 142 } 143 144 gc(); 145 Iterator iterator = map.entrySet().iterator(); 146 while (iterator.hasNext()) { 147 Map.Entry entry = (Map.Entry)iterator.next(); 148 Integer key = (Integer)entry.getKey(); 149 Integer value = (Integer)entry.getValue(); 150 assertTrue("iterator should skip GC'd keys", key.intValue() >= 10); 151 assertTrue("iterator should skip GC'd values", value.intValue() >= 10); 152 } 153 154 } 155 156 public void testMapIteratorAfterGC() { 157 ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 158 Object[] hard = new Object[10]; 159 for (int i = 0; i < 10; i++) { 160 hard[i] = new Integer(10 + i); 161 map.put(new Integer(i), new Integer(i)); 162 map.put(hard[i], hard[i]); 163 } 164 165 gc(); 166 MapIterator iterator = map.mapIterator(); 167 while (iterator.hasNext()) { 168 Object key1 = iterator.next(); 169 Integer key = (Integer) iterator.getKey(); 170 Integer value = (Integer) iterator.getValue(); 171 assertTrue("iterator keys should match", key == key1); 172 assertTrue("iterator should skip GC'd keys", key.intValue() >= 10); 173 assertTrue("iterator should skip GC'd values", value.intValue() >= 10); 174 } 175 176 } 177 178 public void testMapIteratorAfterGC2() { 179 ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 180 Object[] hard = new Object[10]; 181 for (int i = 0; i < 10; i++) { 182 hard[i] = new Integer(10 + i); 183 map.put(new Integer(i), new Integer(i)); 184 map.put(hard[i], hard[i]); 185 } 186 187 MapIterator iterator = map.mapIterator(); 188 while (iterator.hasNext()) { 189 Object key1 = iterator.next(); 190 gc(); 191 Integer key = (Integer) iterator.getKey(); 192 Integer value = (Integer) iterator.getValue(); 193 assertTrue("iterator keys should match", key == key1); 194 assertTrue("iterator should skip GC'd keys", key.intValue() >= 10); 195 assertTrue("iterator should skip GC'd values", value.intValue() >= 10); 196 } 197 198 } 199 */ 200 201 WeakReference keyReference; 202 WeakReference valueReference; 203 buildRefMap()204 public Map buildRefMap() { 205 Object key = new Object(); 206 Object value = new Object(); 207 208 keyReference = new WeakReference(key); 209 valueReference = new WeakReference(value); 210 211 Map testMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD, true); 212 testMap.put(key, value); 213 214 assertEquals("In map", value, testMap.get(key)); 215 assertNotNull("Weak reference released early (1)", keyReference.get()); 216 assertNotNull("Weak reference released early (2)", valueReference.get()); 217 return testMap; 218 } 219 220 /** Tests whether purge values setting works */ testPurgeValues()221 public void testPurgeValues() throws Exception { 222 // many thanks to Juozas Baliuka for suggesting this method 223 Map testMap = buildRefMap(); 224 225 int iterations = 0; 226 int bytz = 2; 227 while(true) { 228 System.gc(); 229 if(iterations++ > 50){ 230 fail("Max iterations reached before resource released."); 231 } 232 testMap.isEmpty(); 233 if( 234 keyReference.get() == null && 235 valueReference.get() == null) { 236 break; 237 238 } else { 239 // create garbage: 240 byte[] b = new byte[bytz]; 241 bytz = bytz * 2; 242 } 243 } 244 } 245 gc()246 private static void gc() { 247 try { 248 // trigger GC 249 byte[][] tooLarge = new byte[1000000000][1000000000]; 250 fail("you have too much RAM"); 251 } catch (OutOfMemoryError ex) { 252 System.gc(); // ignore 253 } 254 } 255 256 } 257