1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.map;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertSame;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26 import static org.junit.jupiter.api.Assertions.fail;
27
28 import java.lang.ref.WeakReference;
29 import java.util.Iterator;
30 import java.util.Map;
31
32 import org.apache.commons.collections4.IterableMap;
33 import org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength;
34 import org.junit.jupiter.api.Test;
35
36
37
38
39 public class ReferenceIdentityMapTest<K, V> extends AbstractIterableMapTest<K, V> {
40
41 private static final Integer I1A = new Integer(1);
42 private static final Integer I1B = new Integer(1);
43 private static final Integer I2A = new Integer(2);
44 private static final Integer I2B = new Integer(2);
45
46 @SuppressWarnings("unused")
47 private static void gc() {
48 try {
49
50 final byte[][] tooLarge = new byte[1000000000][1000000000];
51 fail("you have too much RAM");
52 } catch (final OutOfMemoryError ex) {
53 System.gc();
54 }
55 }
56
57 WeakReference<K> keyReference;
58
59 WeakReference<V> valueReference;
60
61 public ReferenceIdentityMapTest() {
62 super(ReferenceIdentityMapTest.class.getSimpleName());
63 }
64
65 @SuppressWarnings("unchecked")
66 private Map<K, V> buildRefMap() {
67 final K key = (K) new Object();
68 final V value = (V) new Object();
69
70 keyReference = new WeakReference<>(key);
71 valueReference = new WeakReference<>(value);
72
73 final Map<K, V> testMap = new ReferenceIdentityMap<>(ReferenceStrength.WEAK, ReferenceStrength.HARD, true);
74 testMap.put(key, value);
75
76 assertEquals(value, testMap.get(key), "In map");
77 assertNotNull(keyReference.get(), "Weak reference released early (1)");
78 assertNotNull(valueReference.get(), "Weak reference released early (2)");
79 return testMap;
80 }
81
82 @Override
83 public String getCompatibilityVersion() {
84 return "4";
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98 @Override
99 public boolean isAllowNullKey() {
100 return false;
101 }
102
103 @Override
104 public boolean isAllowNullValue() {
105 return false;
106 }
107
108 @Override
109 public Map<K, V> makeConfirmedMap() {
110
111
112
113 return new IdentityMap<>();
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 @Override
230 public ReferenceIdentityMap<K, V> makeObject() {
231 return new ReferenceIdentityMap<>(ReferenceStrength.WEAK, ReferenceStrength.WEAK);
232 }
233
234 @Test
235 @SuppressWarnings("unchecked")
236 public void testBasics() {
237 final IterableMap<K, V> map = new ReferenceIdentityMap<>(ReferenceStrength.HARD, ReferenceStrength.HARD);
238 assertEquals(0, map.size());
239
240 map.put((K) I1A, (V) I2A);
241 assertEquals(1, map.size());
242 assertSame(I2A, map.get(I1A));
243 assertSame(null, map.get(I1B));
244 assertTrue(map.containsKey(I1A));
245 assertFalse(map.containsKey(I1B));
246 assertTrue(map.containsValue(I2A));
247 assertFalse(map.containsValue(I2B));
248
249 map.put((K) I1A, (V) I2B);
250 assertEquals(1, map.size());
251 assertSame(I2B, map.get(I1A));
252 assertSame(null, map.get(I1B));
253 assertTrue(map.containsKey(I1A));
254 assertFalse(map.containsKey(I1B));
255 assertFalse(map.containsValue(I2A));
256 assertTrue(map.containsValue(I2B));
257
258 map.put((K) I1B, (V) I2B);
259 assertEquals(2, map.size());
260 assertSame(I2B, map.get(I1A));
261 assertSame(I2B, map.get(I1B));
262 assertTrue(map.containsKey(I1A));
263 assertTrue(map.containsKey(I1B));
264 assertFalse(map.containsValue(I2A));
265 assertTrue(map.containsValue(I2B));
266 }
267
268 @Test
269 @SuppressWarnings("unchecked")
270 public void testHashEntry() {
271 final IterableMap<K, V> map = new ReferenceIdentityMap<>(ReferenceStrength.HARD, ReferenceStrength.HARD);
272
273 map.put((K) I1A, (V) I2A);
274 map.put((K) I1B, (V) I2A);
275
276 final Map.Entry<K, V> entry1 = map.entrySet().iterator().next();
277 final Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();
278 final Map.Entry<K, V> entry2 = it.next();
279 final Map.Entry<K, V> entry3 = it.next();
280
281 assertTrue(entry1.equals(entry2));
282 assertTrue(entry2.equals(entry1));
283 assertFalse(entry1.equals(entry3));
284 }
285
286 @Test
287 @SuppressWarnings("unchecked")
288 public void testNullHandling() {
289 resetFull();
290 assertNull(getMap().get(null));
291 assertFalse(getMap().containsKey(null));
292 assertFalse(getMap().containsValue(null));
293 assertNull(getMap().remove(null));
294 assertFalse(getMap().entrySet().contains(null));
295 assertFalse(getMap().containsKey(null));
296 assertFalse(getMap().containsValue(null));
297 assertThrows(NullPointerException.class, () -> getMap().put(null, null));
298 assertThrows(NullPointerException.class, () -> getMap().put((K) new Object(), null));
299 assertThrows(NullPointerException.class, () -> getMap().put(null, (V) new Object()));
300 }
301
302
303 @Test
304 public void testPurgeValues() throws Exception {
305
306 final Map<K, V> testMap = buildRefMap();
307
308 int iterations = 0;
309 int bytz = 2;
310 while (true) {
311 System.gc();
312 if (iterations++ > 50) {
313 fail("Max iterations reached before resource released.");
314 }
315 testMap.isEmpty();
316 if (
317 keyReference.get() == null &&
318 valueReference.get() == null) {
319 break;
320
321 }
322
323 @SuppressWarnings("unused")
324 final byte[] b = new byte[bytz];
325 bytz *= 2;
326 }
327 }
328
329 }