001: /*
002: * Copyright 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.Iterator;
020: import java.util.Map;
021:
022: import junit.framework.Test;
023:
024: import org.apache.commons.collections.BulkTest;
025: import org.apache.commons.collections.IterableMap;
026:
027: /**
028: * Tests for ReferenceIdentityMap.
029: *
030: * @version $Revision: 169101 $
031: *
032: * @author Paul Jack
033: * @author Stephen Colebourne
034: * @author Guilhem Lavaux
035: */
036: public class TestReferenceIdentityMap extends AbstractTestIterableMap {
037:
038: private static final Integer I1A = new Integer(1);
039: private static final Integer I1B = new Integer(1);
040: private static final Integer I2A = new Integer(2);
041: private static final Integer I2B = new Integer(2);
042:
043: public TestReferenceIdentityMap(String testName) {
044: super (testName);
045: }
046:
047: public static Test suite() {
048: return BulkTest.makeSuite(TestReferenceIdentityMap.class);
049: }
050:
051: public static void main(String args[]) {
052: String[] testCaseName = { TestReferenceIdentityMap.class
053: .getName() };
054: junit.textui.TestRunner.main(testCaseName);
055: }
056:
057: public Map makeEmptyMap() {
058: ReferenceIdentityMap map = new ReferenceIdentityMap(
059: ReferenceIdentityMap.WEAK, ReferenceIdentityMap.WEAK);
060: return map;
061: }
062:
063: public Map makeConfirmedMap() {
064: // Testing against another [collections] class generally isn't a good idea,
065: // but the alternative is a JDK1.4 dependency in the tests
066: return new IdentityMap();
067: }
068:
069: public boolean isAllowNullKey() {
070: return false;
071: }
072:
073: public boolean isAllowNullValue() {
074: return false;
075: }
076:
077: public String getCompatibilityVersion() {
078: return "3.1";
079: }
080:
081: //-----------------------------------------------------------------------
082: public void testBasics() {
083: IterableMap map = new ReferenceIdentityMap(
084: ReferenceIdentityMap.HARD, ReferenceIdentityMap.HARD);
085: assertEquals(0, map.size());
086:
087: map.put(I1A, I2A);
088: assertEquals(1, map.size());
089: assertSame(I2A, map.get(I1A));
090: assertSame(null, map.get(I1B));
091: assertEquals(true, map.containsKey(I1A));
092: assertEquals(false, map.containsKey(I1B));
093: assertEquals(true, map.containsValue(I2A));
094: assertEquals(false, map.containsValue(I2B));
095:
096: map.put(I1A, I2B);
097: assertEquals(1, map.size());
098: assertSame(I2B, map.get(I1A));
099: assertSame(null, map.get(I1B));
100: assertEquals(true, map.containsKey(I1A));
101: assertEquals(false, map.containsKey(I1B));
102: assertEquals(false, map.containsValue(I2A));
103: assertEquals(true, map.containsValue(I2B));
104:
105: map.put(I1B, I2B);
106: assertEquals(2, map.size());
107: assertSame(I2B, map.get(I1A));
108: assertSame(I2B, map.get(I1B));
109: assertEquals(true, map.containsKey(I1A));
110: assertEquals(true, map.containsKey(I1B));
111: assertEquals(false, map.containsValue(I2A));
112: assertEquals(true, map.containsValue(I2B));
113: }
114:
115: //-----------------------------------------------------------------------
116: public void testHashEntry() {
117: IterableMap map = new ReferenceIdentityMap(
118: ReferenceIdentityMap.HARD, ReferenceIdentityMap.HARD);
119:
120: map.put(I1A, I2A);
121: map.put(I1B, I2A);
122:
123: Map.Entry entry1 = (Map.Entry) map.entrySet().iterator().next();
124: Iterator it = map.entrySet().iterator();
125: Map.Entry entry2 = (Map.Entry) it.next();
126: Map.Entry entry3 = (Map.Entry) it.next();
127:
128: assertEquals(true, entry1.equals(entry2));
129: assertEquals(true, entry2.equals(entry1));
130: assertEquals(false, entry1.equals(entry3));
131: }
132:
133: //-----------------------------------------------------------------------
134: public void testNullHandling() {
135: resetFull();
136: assertEquals(null, map.get(null));
137: assertEquals(false, map.containsKey(null));
138: assertEquals(false, map.containsValue(null));
139: assertEquals(null, map.remove(null));
140: assertEquals(false, map.entrySet().contains(null));
141: assertEquals(false, map.keySet().contains(null));
142: assertEquals(false, map.values().contains(null));
143: try {
144: map.put(null, null);
145: fail();
146: } catch (NullPointerException ex) {
147: }
148: try {
149: map.put(new Object(), null);
150: fail();
151: } catch (NullPointerException ex) {
152: }
153: try {
154: map.put(null, new Object());
155: fail();
156: } catch (NullPointerException ex) {
157: }
158: }
159:
160: //-----------------------------------------------------------------------
161: /*
162: // Tests often fail because gc is uncontrollable
163:
164: public void testPurge() {
165: ReferenceIdentityMap map = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.WEAK);
166: Object[] hard = new Object[10];
167: for (int i = 0; i < hard.length; i++) {
168: hard[i] = new Object();
169: map.put(hard[i], new Object());
170: }
171: gc();
172: assertTrue("map should be empty after purge of weak values", map.isEmpty());
173:
174: for (int i = 0; i < hard.length; i++) {
175: map.put(new Object(), hard[i]);
176: }
177: gc();
178: assertTrue("map should be empty after purge of weak keys", map.isEmpty());
179:
180: for (int i = 0; i < hard.length; i++) {
181: map.put(new Object(), hard[i]);
182: map.put(hard[i], new Object());
183: }
184:
185: gc();
186: assertTrue("map should be empty after purge of weak keys and values", map.isEmpty());
187: }
188:
189:
190: public void testGetAfterGC() {
191: ReferenceIdentityMap map = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.WEAK);
192: for (int i = 0; i < 10; i++) {
193: map.put(new Integer(i), new Integer(i));
194: }
195:
196: gc();
197: for (int i = 0; i < 10; i++) {
198: Integer I = new Integer(i);
199: assertTrue("map.containsKey should return false for GC'd element", !map.containsKey(I));
200: assertTrue("map.get should return null for GC'd element", map.get(I) == null);
201: }
202: }
203:
204:
205: public void testEntrySetIteratorAfterGC() {
206: ReferenceIdentityMap map = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.WEAK);
207: Object[] hard = new Object[10];
208: for (int i = 0; i < 10; i++) {
209: hard[i] = new Integer(10 + i);
210: map.put(new Integer(i), new Integer(i));
211: map.put(hard[i], hard[i]);
212: }
213:
214: gc();
215: Iterator iterator = map.entrySet().iterator();
216: while (iterator.hasNext()) {
217: Map.Entry entry = (Map.Entry)iterator.next();
218: Integer key = (Integer)entry.getKey();
219: Integer value = (Integer)entry.getValue();
220: assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
221: assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
222: }
223:
224: }
225:
226: public void testMapIteratorAfterGC() {
227: ReferenceIdentityMap map = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.WEAK);
228: Object[] hard = new Object[10];
229: for (int i = 0; i < 10; i++) {
230: hard[i] = new Integer(10 + i);
231: map.put(new Integer(i), new Integer(i));
232: map.put(hard[i], hard[i]);
233: }
234:
235: gc();
236: MapIterator iterator = map.mapIterator();
237: while (iterator.hasNext()) {
238: Object key1 = iterator.next();
239: Integer key = (Integer) iterator.getKey();
240: Integer value = (Integer) iterator.getValue();
241: assertTrue("iterator keys should match", key == key1);
242: assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
243: assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
244: }
245:
246: }
247:
248: public void testMapIteratorAfterGC2() {
249: ReferenceIdentityMap map = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.WEAK);
250: Object[] hard = new Object[10];
251: for (int i = 0; i < 10; i++) {
252: hard[i] = new Integer(10 + i);
253: map.put(new Integer(i), new Integer(i));
254: map.put(hard[i], hard[i]);
255: }
256:
257: MapIterator iterator = map.mapIterator();
258: while (iterator.hasNext()) {
259: Object key1 = iterator.next();
260: gc();
261: Integer key = (Integer) iterator.getKey();
262: Integer value = (Integer) iterator.getValue();
263: assertTrue("iterator keys should match", key == key1);
264: assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
265: assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
266: }
267:
268: }
269: */
270:
271: WeakReference keyReference;
272: WeakReference valueReference;
273:
274: public Map buildRefMap() {
275: Object key = new Object();
276: Object value = new Object();
277:
278: keyReference = new WeakReference(key);
279: valueReference = new WeakReference(value);
280:
281: Map testMap = new ReferenceIdentityMap(ReferenceMap.WEAK,
282: ReferenceMap.HARD, true);
283: testMap.put(key, value);
284:
285: assertEquals("In map", value, testMap.get(key));
286: assertNotNull("Weak reference released early (1)", keyReference
287: .get());
288: assertNotNull("Weak reference released early (2)",
289: valueReference.get());
290: return testMap;
291: }
292:
293: /** Tests whether purge values setting works */
294: public void testPurgeValues() throws Exception {
295: // many thanks to Juozas Baliuka for suggesting this method
296: Map testMap = buildRefMap();
297:
298: int iterations = 0;
299: int bytz = 2;
300: while (true) {
301: System.gc();
302: if (iterations++ > 50) {
303: fail("Max iterations reached before resource released.");
304: }
305: testMap.isEmpty();
306: if (keyReference.get() == null
307: && valueReference.get() == null) {
308: break;
309:
310: } else {
311: // create garbage:
312: byte[] b = new byte[bytz];
313: bytz = bytz * 2;
314: }
315: }
316: }
317:
318: private static void gc() {
319: try {
320: // trigger GC
321: byte[][] tooLarge = new byte[1000000000][1000000000];
322: fail("you have too much RAM");
323: } catch (OutOfMemoryError ex) {
324: System.gc(); // ignore
325: }
326: }
327:
328: }
|