1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.bidimap;
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.assertNull;
22 import static org.junit.jupiter.api.Assertions.assertSame;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.Set;
31
32 import org.apache.commons.collections4.BidiMap;
33 import org.apache.commons.collections4.BulkTest;
34 import org.apache.commons.collections4.MapIterator;
35 import org.apache.commons.collections4.collection.AbstractCollectionTest;
36 import org.apache.commons.collections4.iterators.AbstractMapIteratorTest;
37 import org.apache.commons.collections4.map.AbstractIterableMapTest;
38 import org.junit.jupiter.api.Assumptions;
39 import org.junit.jupiter.api.Test;
40
41
42
43
44
45
46
47 public abstract class AbstractBidiMapTest<K, V> extends AbstractIterableMapTest<K, V> {
48
49 public class TestBidiMapEntrySet extends TestMapEntrySet {
50
51 public TestBidiMapEntrySet() {
52 }
53
54 @Test
55 public void testMapEntrySetIteratorEntrySetValueCrossCheck() {
56 final K key1 = getSampleKeys()[0];
57 final K key2 = getSampleKeys()[1];
58 final V newValue1 = getNewSampleValues()[0];
59 final V newValue2 = getNewSampleValues()[1];
60
61 resetFull();
62
63
64 Iterator<Map.Entry<K, V>> it = TestBidiMapEntrySet.this.getCollection().iterator();
65 final Map.Entry<K, V> entry1 = getEntry(it, key1);
66 it = TestBidiMapEntrySet.this.getCollection().iterator();
67 final Map.Entry<K, V> entry2 = getEntry(it, key2);
68 Iterator<Map.Entry<K, V>> itConfirmed = TestBidiMapEntrySet.this.getConfirmed().iterator();
69 final Map.Entry<K, V> entryConfirmed1 = getEntry(itConfirmed, key1);
70 itConfirmed = TestBidiMapEntrySet.this.getConfirmed().iterator();
71 final Map.Entry<K, V> entryConfirmed2 = getEntry(itConfirmed, key2);
72 TestBidiMapEntrySet.this.verify();
73
74 if (!isSetValueSupported()) {
75 assertThrows(UnsupportedOperationException.class, () -> entry1.setValue(newValue1));
76 return;
77 }
78
79
80 entry1.setValue(newValue1);
81 entryConfirmed1.setValue(newValue1);
82 entry2.setValue(newValue2);
83 entryConfirmed2.setValue(newValue2);
84
85
86
87 try {
88 entry2.setValue(newValue1);
89 } catch (final IllegalArgumentException ex) {
90 return;
91 }
92 entryConfirmed2.setValue(newValue1);
93 AbstractBidiMapTest.this.getConfirmed().remove(key1);
94 assertEquals(newValue1, entry2.getValue());
95 assertTrue(AbstractBidiMapTest.this.getMap().containsKey(entry2.getKey()));
96 assertTrue(AbstractBidiMapTest.this.getMap().containsValue(newValue1));
97 assertEquals(newValue1, AbstractBidiMapTest.this.getMap().get(entry2.getKey()));
98 assertFalse(AbstractBidiMapTest.this.getMap().containsKey(key1));
99 assertFalse(AbstractBidiMapTest.this.getMap().containsValue(newValue2));
100 TestBidiMapEntrySet.this.verify();
101
102
103 it.next();
104 if (isRemoveSupported()) {
105 it.remove();
106 }
107 }
108
109 }
110
111 public class TestBidiMapIterator extends AbstractMapIteratorTest<K, V> {
112
113 @Override
114 public V[] addSetValues() {
115 return getNewSampleValues();
116 }
117
118 @Override
119 public Map<K, V> getConfirmedMap() {
120
121 return getConfirmed();
122 }
123
124 @Override
125 public BidiMap<K, V> getMap() {
126
127 return AbstractBidiMapTest.this.getMap();
128 }
129
130 @Override
131 public MapIterator<K, V> makeEmptyIterator() {
132 resetEmpty();
133 return AbstractBidiMapTest.this.getMap().mapIterator();
134 }
135
136 @Override
137 public MapIterator<K, V> makeObject() {
138 resetFull();
139 return AbstractBidiMapTest.this.getMap().mapIterator();
140 }
141
142 @Override
143 public boolean supportsRemove() {
144 return isRemoveSupported();
145 }
146
147 @Override
148 public boolean supportsSetValue() {
149 return isSetValueSupported();
150 }
151
152 @Override
153 public void verify() {
154 super.verify();
155 AbstractBidiMapTest.this.verify();
156 }
157
158 }
159
160 public class TestInverseBidiMap extends AbstractBidiMapTest<V, K> {
161
162 final AbstractBidiMapTest<K, V> main;
163
164 public TestInverseBidiMap(final AbstractBidiMapTest<K, V> main) {
165 this.main = main;
166 }
167
168 @Override
169 public String getCompatibilityVersion() {
170 return main.getCompatibilityVersion();
171 }
172
173 @Override
174 protected int getIterationBehaviour() {
175 return main.getIterationBehaviour();
176 }
177
178 @Override
179 public V[] getSampleKeys() {
180 return main.getSampleValues();
181 }
182
183 @Override
184 public K[] getSampleValues() {
185 return main.getSampleKeys();
186 }
187
188 @Override
189 public boolean isAllowNullKey() {
190 return main.isAllowNullKey();
191 }
192
193 @Override
194 public boolean isAllowNullValue() {
195 return main.isAllowNullValue();
196 }
197
198 @Override
199 public boolean isAllowNullValueGet() {
200 return main.isAllowNullValueGet();
201 }
202
203 @Override
204 public boolean isAllowNullValuePut() {
205 return main.isAllowNullValuePut();
206 }
207
208 @Override
209 public boolean isPutAddSupported() {
210 return main.isPutAddSupported();
211 }
212
213 @Override
214 public boolean isPutChangeSupported() {
215 return main.isPutChangeSupported();
216 }
217
218 @Override
219 public boolean isRemoveSupported() {
220 return main.isRemoveSupported();
221 }
222
223 @Override
224 public boolean isSetValueSupported() {
225 return main.isSetValueSupported();
226 }
227
228 @Override
229 public BidiMap<V, K> makeFullMap() {
230 return main.makeFullMap().inverseBidiMap();
231 }
232
233 @Override
234 public BidiMap<V, K> makeObject() {
235 return main.makeObject().inverseBidiMap();
236 }
237 }
238
239 public BulkTest bulkTestBidiMapIterator() {
240 return new TestBidiMapIterator();
241 }
242
243 public BulkTest bulkTestInverseMap() {
244 return new TestInverseBidiMap(this);
245 }
246
247 @Override
248 public BulkTest bulkTestMapEntrySet() {
249 return new TestBidiMapEntrySet();
250 }
251
252 private void doTestGetKey(final BidiMap<?, ?> map, final Object key, final Object value) {
253 assertEquals(value, map.get(key), "Value not found for key.");
254 assertEquals(key, map.getKey(value), "Key not found for value.");
255 }
256
257
258
259
260 @Override
261 public String getCompatibilityVersion() {
262 return "4";
263 }
264
265
266
267
268 @Override
269 public BidiMap<K, V> getMap() {
270 return (BidiMap<K, V>) super.getMap();
271 }
272
273
274
275
276 @Override
277 public boolean isAllowDuplicateValues() {
278 return false;
279 }
280
281
282
283
284
285
286 @Override
287 public BidiMap<K, V> makeFullMap() {
288 return (BidiMap<K, V>) super.makeFullMap();
289 }
290
291
292
293
294 @Override
295 public abstract BidiMap<K, V> makeObject();
296
297 @SuppressWarnings("unchecked")
298 private <T> void modifyEntrySet(final BidiMap<?, T> map) {
299
300 final Map.Entry<?, T> entry = map.entrySet().iterator().next();
301
302
303 final Object key = entry.getKey();
304 final Object oldValue = entry.getValue();
305
306
307 final Object newValue = "newValue";
308 entry.setValue((T) newValue);
309
310 assertEquals(
311 newValue,
312 map.get(key),
313 "Modifying entrySet did not affect underlying Map.");
314
315 assertNull(
316 map.getKey(oldValue),
317 "Modifying entrySet did not affect inverse Map.");
318 }
319
320 private void remove(final BidiMap<?, ?> map, final Object key) {
321 final Object value = map.remove(key);
322 assertFalse(map.containsKey(key), "Key was not removed.");
323 assertNull(map.getKey(value), "Value was not removed.");
324 }
325
326 private void removeByEntrySet(final BidiMap<?, ?> map, final Object key, final Object value) {
327 final Map<Object, Object> temp = new HashMap<>();
328 temp.put(key, value);
329 map.entrySet().remove(temp.entrySet().iterator().next());
330
331 assertFalse(map.containsKey(key), "Key was not removed.");
332 assertFalse(map.containsValue(value), "Value was not removed.");
333
334 assertFalse(map.inverseBidiMap().containsValue(key), "Key was not removed from inverse map.");
335 assertFalse(map.inverseBidiMap().containsKey(value), "Value was not removed from inverse map.");
336 }
337
338 private void removeByKeySet(final BidiMap<?, ?> map, final Object key, final Object value) {
339 map.remove(key);
340
341 assertFalse(map.containsKey(key), "Key was not removed.");
342 assertFalse(map.containsValue(value), "Value was not removed.");
343
344 assertFalse(map.inverseBidiMap().containsValue(key), "Key was not removed from inverse map.");
345 assertFalse(map.inverseBidiMap().containsKey(value), "Value was not removed from inverse map.");
346 }
347
348 private void removeValue(final BidiMap<?, ?> map, final Object value) {
349 final Object key = map.removeValue(value);
350 assertFalse(map.containsKey(key), "Key was not removed.");
351 assertNull(map.getKey(value), "Value was not removed.");
352 }
353
354 @Test
355 public void testBidiClear() {
356 if (!isRemoveSupported()) {
357 assertThrows(UnsupportedOperationException.class, () -> makeFullMap().clear());
358 return;
359 }
360
361 BidiMap<?, ?> map = makeFullMap();
362 map.clear();
363 assertTrue(map.isEmpty(), "Map was not cleared.");
364 assertTrue(map.inverseBidiMap().isEmpty(), "Inverse map was not cleared.");
365
366
367 map = makeFullMap().inverseBidiMap();
368 map.clear();
369 assertTrue(map.isEmpty(), "Map was not cleared.");
370 assertTrue(map.inverseBidiMap().isEmpty(), "Inverse map was not cleared.");
371 }
372
373
374 @Test
375 public void testBidiGetKey() {
376 doTestGetKey(makeFullMap(), getSampleKeys()[0], getSampleValues()[0]);
377 }
378
379 @Test
380 public void testBidiGetKeyInverse() {
381 doTestGetKey(
382 makeFullMap().inverseBidiMap(),
383 getSampleValues()[0],
384 getSampleKeys()[0]);
385 }
386
387
388 @Test
389 public void testBidiInverse() {
390 final BidiMap<K, V> map = makeFullMap();
391 final BidiMap<V, K> inverseMap = map.inverseBidiMap();
392
393 assertSame(
394 map,
395 inverseMap.inverseBidiMap(),
396 "Inverse of inverse is not equal to original.");
397
398 assertEquals(
399 getSampleKeys()[0],
400 inverseMap.get(getSampleValues()[0]),
401 "Value not found for key.");
402
403 assertEquals(
404 getSampleValues()[0],
405 inverseMap.getKey(getSampleKeys()[0]),
406 "Key not found for value.");
407 }
408
409 @Test
410 public void testBidiKeySetValuesOrder() {
411
412 Assumptions.assumeFalse((getIterationBehaviour() & AbstractCollectionTest.UNORDERED) != 0);
413 resetFull();
414 final Iterator<K> keys = map.keySet().iterator();
415 final Iterator<V> values = map.values().iterator();
416 while (keys.hasNext() && values.hasNext()) {
417 final K key = keys.next();
418 final V value = values.next();
419 assertSame(map.get(key), value);
420 }
421 assertFalse(keys.hasNext());
422 assertFalse(values.hasNext());
423 }
424
425 @Test
426 public void testBidiMapIteratorSet() {
427 final V newValue1 = getOtherValues()[0];
428 final V newValue2 = getOtherValues()[1];
429
430 resetFull();
431 final BidiMap<K, V> bidi = getMap();
432 final MapIterator<K, V> it = bidi.mapIterator();
433 assertTrue(it.hasNext());
434 final K key1 = it.next();
435
436 if (!isSetValueSupported()) {
437 assertThrows(UnsupportedOperationException.class, () -> it.setValue(newValue1));
438 return;
439 }
440
441 it.setValue(newValue1);
442 confirmed.put(key1, newValue1);
443 assertSame(key1, it.getKey());
444 assertSame(newValue1, it.getValue());
445 assertTrue(bidi.containsKey(key1));
446 assertTrue(bidi.containsValue(newValue1));
447 assertEquals(newValue1, bidi.get(key1));
448 verify();
449
450 it.setValue(newValue1);
451 confirmed.put(key1, newValue1);
452 assertSame(key1, it.getKey());
453 assertSame(newValue1, it.getValue());
454 assertTrue(bidi.containsKey(key1));
455 assertTrue(bidi.containsValue(newValue1));
456 assertEquals(newValue1, bidi.get(key1));
457 verify();
458
459 final K key2 = it.next();
460 it.setValue(newValue2);
461 confirmed.put(key2, newValue2);
462 assertSame(key2, it.getKey());
463 assertSame(newValue2, it.getValue());
464 assertTrue(bidi.containsKey(key2));
465 assertTrue(bidi.containsValue(newValue2));
466 assertEquals(newValue2, bidi.get(key2));
467 verify();
468
469
470
471 assertThrows(IllegalArgumentException.class, () -> it.setValue(newValue1));
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 }
489
490 @Test
491 public void testBidiModifyEntrySet() {
492 if (!isSetValueSupported()) {
493 return;
494 }
495
496 modifyEntrySet(makeFullMap());
497 modifyEntrySet(makeFullMap().inverseBidiMap());
498 }
499
500
501 @Test
502 @SuppressWarnings("unchecked")
503 public void testBidiPut() {
504 if (!isPutAddSupported() || !isPutChangeSupported()) {
505 return;
506 }
507
508 final BidiMap<K, V> map = makeObject();
509 final BidiMap<V, K> inverse = map.inverseBidiMap();
510 assertEquals(0, map.size());
511 assertEquals(map.size(), inverse.size());
512
513 map.put((K) "A", (V) "B");
514 assertEquals(1, map.size());
515 assertEquals(map.size(), inverse.size());
516 assertEquals("B", map.get("A"));
517 assertEquals("A", inverse.get("B"));
518
519 map.put((K) "A", (V) "C");
520 assertEquals(1, map.size());
521 assertEquals(map.size(), inverse.size());
522 assertEquals("C", map.get("A"));
523 assertEquals("A", inverse.get("C"));
524
525 map.put((K) "B", (V) "C");
526 assertEquals(1, map.size());
527 assertEquals(map.size(), inverse.size());
528 assertEquals("C", map.get("B"));
529 assertEquals("B", inverse.get("C"));
530
531 map.put((K) "E", (V) "F");
532 assertEquals(2, map.size());
533 assertEquals(map.size(), inverse.size());
534 assertEquals("F", map.get("E"));
535 assertEquals("E", inverse.get("F"));
536 }
537
538 @Test
539 public void testBidiRemove() {
540 if (!isRemoveSupported()) {
541 assertThrows(UnsupportedOperationException.class, () -> makeFullMap().remove(getSampleKeys()[0]));
542
543 assertThrows(UnsupportedOperationException.class, () -> makeFullMap().removeValue(getSampleValues()[0]));
544
545 return;
546 }
547
548 remove(makeFullMap(), getSampleKeys()[0]);
549 remove(makeFullMap().inverseBidiMap(), getSampleValues()[0]);
550
551 removeValue(makeFullMap(), getSampleValues()[0]);
552 removeValue(makeFullMap().inverseBidiMap(), getSampleKeys()[0]);
553
554 assertNull(makeFullMap().removeValue("NotPresent"));
555 }
556
557 @Test
558 public void testBidiRemoveByEntrySet() {
559 if (!isRemoveSupported()) {
560 return;
561 }
562
563 removeByEntrySet(makeFullMap(), getSampleKeys()[0], getSampleValues()[0]);
564 removeByEntrySet(makeFullMap().inverseBidiMap(), getSampleValues()[0], getSampleKeys()[0]);
565 }
566
567 @Test
568 public void testBidiRemoveByKeySet() {
569 if (!isRemoveSupported()) {
570 return;
571 }
572
573 removeByKeySet(makeFullMap(), getSampleKeys()[0], getSampleValues()[0]);
574 removeByKeySet(makeFullMap().inverseBidiMap(), getSampleValues()[0], getSampleKeys()[0]);
575 }
576
577
578
579
580
581
582 @Override
583 public void verify() {
584 verifyInverse();
585 super.verify();
586 }
587
588 public void verifyInverse() {
589 assertEquals(map.size(), ((BidiMap<K, V>) map).inverseBidiMap().size());
590 final Map<K, V> map1 = new HashMap<>(map);
591 final Map<V, K> map2 = new HashMap<>(((BidiMap<K, V>) map).inverseBidiMap());
592 final Set<K> keys1 = map1.keySet();
593 final Set<V> keys2 = map2.keySet();
594 final Collection<V> values1 = map1.values();
595 final Collection<K> values2 = map2.values();
596 assertTrue(keys1.containsAll(values2));
597 assertTrue(values2.containsAll(keys1));
598 assertTrue(values1.containsAll(keys2));
599 assertTrue(keys2.containsAll(values1));
600 }
601
602 }