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