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