001: /*
002: * Copyright 2001-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.collections.map;
017:
018: import java.lang.ref.WeakReference;
019: import java.util.Map;
020:
021: import junit.framework.Test;
022:
023: import org.apache.commons.collections.BulkTest;
024:
025: /**
026: * Tests for ReferenceMap.
027: *
028: * @version $Revision: 169101 $ $Date: 2005-05-07 18:26:58 +0100 (Sat, 07 May 2005) $
029: *
030: * @author Paul Jack
031: * @author Guilhem Lavaux
032: */
033: public class TestReferenceMap extends AbstractTestIterableMap {
034:
035: public TestReferenceMap(String testName) {
036: super (testName);
037: }
038:
039: public static Test suite() {
040: return BulkTest.makeSuite(TestReferenceMap.class);
041: }
042:
043: public static void main(String args[]) {
044: String[] testCaseName = { TestReferenceMap.class.getName() };
045: junit.textui.TestRunner.main(testCaseName);
046: }
047:
048: public Map makeEmptyMap() {
049: ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK,
050: ReferenceMap.WEAK);
051: return map;
052: }
053:
054: public boolean isAllowNullKey() {
055: return false;
056: }
057:
058: public boolean isAllowNullValue() {
059: return false;
060: }
061:
062: public String getCompatibilityVersion() {
063: return "3.1";
064: }
065:
066: //-----------------------------------------------------------------------
067: public void testNullHandling() {
068: resetFull();
069: assertEquals(null, map.get(null));
070: assertEquals(false, map.containsKey(null));
071: assertEquals(false, map.containsValue(null));
072: assertEquals(null, map.remove(null));
073: assertEquals(false, map.entrySet().contains(null));
074: assertEquals(false, map.keySet().contains(null));
075: assertEquals(false, map.values().contains(null));
076: try {
077: map.put(null, null);
078: fail();
079: } catch (NullPointerException ex) {
080: }
081: try {
082: map.put(new Object(), null);
083: fail();
084: } catch (NullPointerException ex) {
085: }
086: try {
087: map.put(null, new Object());
088: fail();
089: } catch (NullPointerException ex) {
090: }
091: }
092:
093: //-----------------------------------------------------------------------
094: /*
095: // Tests often fail because gc is uncontrollable
096:
097: public void testPurge() {
098: ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
099: Object[] hard = new Object[10];
100: for (int i = 0; i < hard.length; i++) {
101: hard[i] = new Object();
102: map.put(hard[i], new Object());
103: }
104: gc();
105: assertTrue("map should be empty after purge of weak values", map.isEmpty());
106:
107: for (int i = 0; i < hard.length; i++) {
108: map.put(new Object(), hard[i]);
109: }
110: gc();
111: assertTrue("map should be empty after purge of weak keys", map.isEmpty());
112:
113: for (int i = 0; i < hard.length; i++) {
114: map.put(new Object(), hard[i]);
115: map.put(hard[i], new Object());
116: }
117:
118: gc();
119: assertTrue("map should be empty after purge of weak keys and values", map.isEmpty());
120: }
121:
122:
123: public void testGetAfterGC() {
124: ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
125: for (int i = 0; i < 10; i++) {
126: map.put(new Integer(i), new Integer(i));
127: }
128:
129: gc();
130: for (int i = 0; i < 10; i++) {
131: Integer I = new Integer(i);
132: assertTrue("map.containsKey should return false for GC'd element", !map.containsKey(I));
133: assertTrue("map.get should return null for GC'd element", map.get(I) == null);
134: }
135: }
136:
137:
138: public void testEntrySetIteratorAfterGC() {
139: ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
140: Object[] hard = new Object[10];
141: for (int i = 0; i < 10; i++) {
142: hard[i] = new Integer(10 + i);
143: map.put(new Integer(i), new Integer(i));
144: map.put(hard[i], hard[i]);
145: }
146:
147: gc();
148: Iterator iterator = map.entrySet().iterator();
149: while (iterator.hasNext()) {
150: Map.Entry entry = (Map.Entry)iterator.next();
151: Integer key = (Integer)entry.getKey();
152: Integer value = (Integer)entry.getValue();
153: assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
154: assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
155: }
156:
157: }
158:
159: public void testMapIteratorAfterGC() {
160: ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
161: Object[] hard = new Object[10];
162: for (int i = 0; i < 10; i++) {
163: hard[i] = new Integer(10 + i);
164: map.put(new Integer(i), new Integer(i));
165: map.put(hard[i], hard[i]);
166: }
167:
168: gc();
169: MapIterator iterator = map.mapIterator();
170: while (iterator.hasNext()) {
171: Object key1 = iterator.next();
172: Integer key = (Integer) iterator.getKey();
173: Integer value = (Integer) iterator.getValue();
174: assertTrue("iterator keys should match", key == key1);
175: assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
176: assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
177: }
178:
179: }
180:
181: public void testMapIteratorAfterGC2() {
182: ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
183: Object[] hard = new Object[10];
184: for (int i = 0; i < 10; i++) {
185: hard[i] = new Integer(10 + i);
186: map.put(new Integer(i), new Integer(i));
187: map.put(hard[i], hard[i]);
188: }
189:
190: MapIterator iterator = map.mapIterator();
191: while (iterator.hasNext()) {
192: Object key1 = iterator.next();
193: gc();
194: Integer key = (Integer) iterator.getKey();
195: Integer value = (Integer) iterator.getValue();
196: assertTrue("iterator keys should match", key == key1);
197: assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
198: assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
199: }
200:
201: }
202: */
203:
204: WeakReference keyReference;
205: WeakReference valueReference;
206:
207: public Map buildRefMap() {
208: Object key = new Object();
209: Object value = new Object();
210:
211: keyReference = new WeakReference(key);
212: valueReference = new WeakReference(value);
213:
214: Map testMap = new ReferenceMap(ReferenceMap.WEAK,
215: ReferenceMap.HARD, true);
216: testMap.put(key, value);
217:
218: assertEquals("In map", value, testMap.get(key));
219: assertNotNull("Weak reference released early (1)", keyReference
220: .get());
221: assertNotNull("Weak reference released early (2)",
222: valueReference.get());
223: return testMap;
224: }
225:
226: /** Tests whether purge values setting works */
227: public void testPurgeValues() throws Exception {
228: // many thanks to Juozas Baliuka for suggesting this method
229: Map testMap = buildRefMap();
230:
231: int iterations = 0;
232: int bytz = 2;
233: while (true) {
234: System.gc();
235: if (iterations++ > 50) {
236: fail("Max iterations reached before resource released.");
237: }
238: testMap.isEmpty();
239: if (keyReference.get() == null
240: && valueReference.get() == null) {
241: break;
242:
243: } else {
244: // create garbage:
245: byte[] b = new byte[bytz];
246: bytz = bytz * 2;
247: }
248: }
249: }
250:
251: private static void gc() {
252: try {
253: // trigger GC
254: byte[][] tooLarge = new byte[1000000000][1000000000];
255: fail("you have too much RAM");
256: } catch (OutOfMemoryError ex) {
257: System.gc(); // ignore
258: }
259: }
260:
261: }
|