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.bidimap;
017:
018: import java.util.Collection;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022: import java.util.Set;
023:
024: import org.apache.commons.collections.BidiMap;
025: import org.apache.commons.collections.BulkTest;
026: import org.apache.commons.collections.MapIterator;
027: import org.apache.commons.collections.iterators.AbstractTestMapIterator;
028: import org.apache.commons.collections.map.AbstractTestMap;
029:
030: /**
031: * Abstract test class for {@link BidiMap} methods and contracts.
032: *
033: * @version $Revision: 155406 $ $Date: 2005-02-26 12:55:26 +0000 (Sat, 26 Feb 2005) $
034: *
035: * @author Matthew Hawthorne
036: * @author Stephen Colebourne
037: */
038: public abstract class AbstractTestBidiMap extends AbstractTestMap {
039:
040: // Test data.
041: private static final Object[][] entriesKV = new Object[][] {
042: new Object[] { "key1", "value1" },
043: new Object[] { "key2", "value2" },
044: new Object[] { "key3", "value3" } };
045: private static final Object[][] entriesVK = new Object[][] {
046: new Object[] { "value1", "key1" },
047: new Object[] { "value2", "key2" },
048: new Object[] { "value3", "key3" } };
049: protected final Object[][] entries;
050:
051: public AbstractTestBidiMap(String testName) {
052: super (testName);
053: entries = entriesKV;
054: }
055:
056: public AbstractTestBidiMap() {
057: super ("Inverse");
058: entries = entriesVK;
059: }
060:
061: //-----------------------------------------------------------------------
062: /**
063: * Implement to create an empty <code>BidiMap</code>.
064: *
065: * @return an empty <code>BidiMap</code> implementation.
066: */
067: public abstract BidiMap makeEmptyBidiMap();
068:
069: /**
070: * Override to create a full <code>BidiMap</code> other than the default.
071: *
072: * @return a full <code>BidiMap</code> implementation.
073: */
074: public BidiMap makeFullBidiMap() {
075: final BidiMap map = makeEmptyBidiMap();
076: for (int i = 0; i < entries.length; i++) {
077: map.put(entries[i][0], entries[i][1]);
078: }
079: return map;
080: }
081:
082: /**
083: * Override to return the empty BidiMap.
084: */
085: public final Map makeEmptyMap() {
086: return makeEmptyBidiMap();
087: }
088:
089: /**
090: * Override to indicate to AbstractTestMap this is a BidiMap.
091: */
092: public boolean isAllowDuplicateValues() {
093: return false;
094: }
095:
096: /**
097: * Override as DualHashBidiMap didn't exist until version 3.
098: */
099: public String getCompatibilityVersion() {
100: return "3";
101: }
102:
103: // BidiPut
104: //-----------------------------------------------------------------------
105: public void testBidiPut() {
106: if (isPutAddSupported() == false
107: || isPutChangeSupported() == false)
108: return;
109:
110: BidiMap map = makeEmptyBidiMap();
111: BidiMap inverse = map.inverseBidiMap();
112: assertEquals(0, map.size());
113: assertEquals(map.size(), inverse.size());
114:
115: map.put("A", "B");
116: assertEquals(1, map.size());
117: assertEquals(map.size(), inverse.size());
118: assertEquals("B", map.get("A"));
119: assertEquals("A", inverse.get("B"));
120:
121: map.put("A", "C");
122: assertEquals(1, map.size());
123: assertEquals(map.size(), inverse.size());
124: assertEquals("C", map.get("A"));
125: assertEquals("A", inverse.get("C"));
126:
127: map.put("B", "C");
128: assertEquals(1, map.size());
129: assertEquals(map.size(), inverse.size());
130: assertEquals("C", map.get("B"));
131: assertEquals("B", inverse.get("C"));
132:
133: map.put("E", "F");
134: assertEquals(2, map.size());
135: assertEquals(map.size(), inverse.size());
136: assertEquals("F", map.get("E"));
137: assertEquals("E", inverse.get("F"));
138: }
139:
140: /**
141: * Verifies that {@link #map} is still equal to {@link #confirmed}.
142: * <p>
143: * This implementation checks the inverse map as well.
144: */
145: public void verify() {
146: verifyInverse();
147: super .verify();
148: }
149:
150: public void verifyInverse() {
151: assertEquals(map.size(), ((BidiMap) map).inverseBidiMap()
152: .size());
153: Map map1 = new HashMap(map);
154: Map map2 = new HashMap(((BidiMap) map).inverseBidiMap());
155: Set keys1 = map1.keySet();
156: Set keys2 = map2.keySet();
157: Collection values1 = map1.values();
158: Collection values2 = map2.values();
159: assertEquals(true, keys1.containsAll(values2));
160: assertEquals(true, values2.containsAll(keys1));
161: assertEquals(true, values1.containsAll(keys2));
162: assertEquals(true, keys2.containsAll(values1));
163: }
164:
165: // testGetKey
166: //-----------------------------------------------------------------------
167: public void testBidiGetKey() {
168: doTestGetKey(makeFullBidiMap(), entries[0][0], entries[0][1]);
169: }
170:
171: public void testBidiGetKeyInverse() {
172: doTestGetKey(makeFullBidiMap().inverseBidiMap(), entries[0][1],
173: entries[0][0]);
174: }
175:
176: private final void doTestGetKey(BidiMap map, Object key,
177: Object value) {
178: assertEquals("Value not found for key.", value, map.get(key));
179: assertEquals("Key not found for value.", key, map.getKey(value));
180: }
181:
182: // testInverse
183: //-----------------------------------------------------------------------
184: public void testBidiInverse() {
185: final BidiMap map = makeFullBidiMap();
186: final BidiMap inverseMap = map.inverseBidiMap();
187:
188: assertSame("Inverse of inverse is not equal to original.", map,
189: inverseMap.inverseBidiMap());
190:
191: assertEquals("Value not found for key.", entries[0][0],
192: inverseMap.get(entries[0][1]));
193:
194: assertEquals("Key not found for value.", entries[0][1],
195: inverseMap.getKey(entries[0][0]));
196: }
197:
198: //-----------------------------------------------------------------------
199: public void testBidiModifyEntrySet() {
200: if (isSetValueSupported() == false)
201: return;
202:
203: modifyEntrySet(makeFullBidiMap());
204: modifyEntrySet(makeFullBidiMap().inverseBidiMap());
205: }
206:
207: private final void modifyEntrySet(BidiMap map) {
208: // Gets first entry
209: final Map.Entry entry = (Map.Entry) map.entrySet().iterator()
210: .next();
211:
212: // Gets key and value
213: final Object key = entry.getKey();
214: final Object oldValue = entry.getValue();
215:
216: // Sets new value
217: final Object newValue = "newValue";
218: entry.setValue(newValue);
219:
220: assertEquals(
221: "Modifying entrySet did not affect underlying Map.",
222: newValue, map.get(key));
223:
224: assertNull("Modifying entrySet did not affect inverse Map.",
225: map.getKey(oldValue));
226: }
227:
228: //-----------------------------------------------------------------------
229: public void testBidiClear() {
230: if (isRemoveSupported() == false) {
231: try {
232: makeFullBidiMap().clear();
233: fail();
234: } catch (UnsupportedOperationException ex) {
235: }
236: return;
237: }
238:
239: BidiMap map = makeFullBidiMap();
240: map.clear();
241: assertTrue("Map was not cleared.", map.isEmpty());
242: assertTrue("Inverse map was not cleared.", map.inverseBidiMap()
243: .isEmpty());
244:
245: // Tests clear on inverse
246: map = makeFullBidiMap().inverseBidiMap();
247: map.clear();
248: assertTrue("Map was not cleared.", map.isEmpty());
249: assertTrue("Inverse map was not cleared.", map.inverseBidiMap()
250: .isEmpty());
251:
252: }
253:
254: //-----------------------------------------------------------------------
255: public void testBidiRemove() {
256: if (isRemoveSupported() == false) {
257: try {
258: makeFullBidiMap().remove(entries[0][0]);
259: fail();
260: } catch (UnsupportedOperationException ex) {
261: }
262: try {
263: makeFullBidiMap().removeValue(entries[0][1]);
264: fail();
265: } catch (UnsupportedOperationException ex) {
266: }
267: return;
268: }
269:
270: remove(makeFullBidiMap(), entries[0][0]);
271: remove(makeFullBidiMap().inverseBidiMap(), entries[0][1]);
272:
273: removeValue(makeFullBidiMap(), entries[0][1]);
274: removeValue(makeFullBidiMap().inverseBidiMap(), entries[0][0]);
275:
276: assertEquals(null, makeFullBidiMap().removeValue("NotPresent"));
277: }
278:
279: private final void remove(BidiMap map, Object key) {
280: final Object value = map.remove(key);
281: assertTrue("Key was not removed.", !map.containsKey(key));
282: assertNull("Value was not removed.", map.getKey(value));
283: }
284:
285: private final void removeValue(BidiMap map, Object value) {
286: final Object key = map.removeValue(value);
287: assertTrue("Key was not removed.", !map.containsKey(key));
288: assertNull("Value was not removed.", map.getKey(value));
289: }
290:
291: //-----------------------------------------------------------------------
292: public void testBidiKeySetValuesOrder() {
293: resetFull();
294: Iterator keys = map.keySet().iterator();
295: Iterator values = map.values().iterator();
296: for (; keys.hasNext() && values.hasNext();) {
297: Object key = keys.next();
298: Object value = values.next();
299: assertSame(map.get(key), value);
300: }
301: assertEquals(false, keys.hasNext());
302: assertEquals(false, values.hasNext());
303: }
304:
305: //-----------------------------------------------------------------------
306: public void testBidiRemoveByKeySet() {
307: if (isRemoveSupported() == false)
308: return;
309:
310: removeByKeySet(makeFullBidiMap(), entries[0][0], entries[0][1]);
311: removeByKeySet(makeFullBidiMap().inverseBidiMap(),
312: entries[0][1], entries[0][0]);
313: }
314:
315: private final void removeByKeySet(BidiMap map, Object key,
316: Object value) {
317: map.keySet().remove(key);
318:
319: assertTrue("Key was not removed.", !map.containsKey(key));
320: assertTrue("Value was not removed.", !map.containsValue(value));
321:
322: assertTrue("Key was not removed from inverse map.", !map
323: .inverseBidiMap().containsValue(key));
324: assertTrue("Value was not removed from inverse map.", !map
325: .inverseBidiMap().containsKey(value));
326: }
327:
328: //-----------------------------------------------------------------------
329: public void testBidiRemoveByEntrySet() {
330: if (isRemoveSupported() == false)
331: return;
332:
333: removeByEntrySet(makeFullBidiMap(), entries[0][0],
334: entries[0][1]);
335: removeByEntrySet(makeFullBidiMap().inverseBidiMap(),
336: entries[0][1], entries[0][0]);
337: }
338:
339: private final void removeByEntrySet(BidiMap map, Object key,
340: Object value) {
341: Map temp = new HashMap();
342: temp.put(key, value);
343: map.entrySet().remove(temp.entrySet().iterator().next());
344:
345: assertTrue("Key was not removed.", !map.containsKey(key));
346: assertTrue("Value was not removed.", !map.containsValue(value));
347:
348: assertTrue("Key was not removed from inverse map.", !map
349: .inverseBidiMap().containsValue(key));
350: assertTrue("Value was not removed from inverse map.", !map
351: .inverseBidiMap().containsKey(value));
352: }
353:
354: //-----------------------------------------------------------------------
355: public BulkTest bulkTestMapEntrySet() {
356: return new TestBidiMapEntrySet();
357: }
358:
359: public class TestBidiMapEntrySet extends TestMapEntrySet {
360: public TestBidiMapEntrySet() {
361: super ();
362: }
363:
364: public void testMapEntrySetIteratorEntrySetValueCrossCheck() {
365: Object key1 = getSampleKeys()[0];
366: Object key2 = getSampleKeys()[1];
367: Object newValue1 = getNewSampleValues()[0];
368: Object newValue2 = getNewSampleValues()[1];
369:
370: resetFull();
371: // explicitly get entries as sample values/keys are connected for some maps
372: // such as BeanMap
373: Iterator it = TestBidiMapEntrySet.this .collection
374: .iterator();
375: Map.Entry entry1 = getEntry(it, key1);
376: it = TestBidiMapEntrySet.this .collection.iterator();
377: Map.Entry entry2 = getEntry(it, key2);
378: Iterator itConfirmed = TestBidiMapEntrySet.this .confirmed
379: .iterator();
380: Map.Entry entryConfirmed1 = getEntry(itConfirmed, key1);
381: itConfirmed = TestBidiMapEntrySet.this .confirmed.iterator();
382: Map.Entry entryConfirmed2 = getEntry(itConfirmed, key2);
383: TestBidiMapEntrySet.this .verify();
384:
385: if (isSetValueSupported() == false) {
386: try {
387: entry1.setValue(newValue1);
388: } catch (UnsupportedOperationException ex) {
389: }
390: return;
391: }
392:
393: // these checked in superclass
394: entry1.setValue(newValue1);
395: entryConfirmed1.setValue(newValue1);
396: entry2.setValue(newValue2);
397: entryConfirmed2.setValue(newValue2);
398:
399: // at this point
400: // key1=newValue1, key2=newValue2
401: try {
402: entry2.setValue(newValue1); // should remove key1
403: } catch (IllegalArgumentException ex) {
404: return; // simplest way of dealing with tricky situation
405: }
406: entryConfirmed2.setValue(newValue1);
407: AbstractTestBidiMap.this .confirmed.remove(key1);
408: assertEquals(newValue1, entry2.getValue());
409: assertEquals(true, AbstractTestBidiMap.this .map
410: .containsKey(entry2.getKey()));
411: assertEquals(true, AbstractTestBidiMap.this .map
412: .containsValue(newValue1));
413: assertEquals(newValue1, AbstractTestBidiMap.this .map
414: .get(entry2.getKey()));
415: assertEquals(false, AbstractTestBidiMap.this .map
416: .containsKey(key1));
417: assertEquals(false, AbstractTestBidiMap.this .map
418: .containsValue(newValue2));
419: TestBidiMapEntrySet.this .verify();
420:
421: // check for ConcurrentModification
422: it.next(); // if you fail here, maybe you should be throwing an IAE, see above
423: if (isRemoveSupported()) {
424: it.remove();
425: }
426: }
427: }
428:
429: public BulkTest bulkTestInverseMap() {
430: return new TestInverseBidiMap(this );
431: }
432:
433: public class TestInverseBidiMap extends AbstractTestBidiMap {
434: final AbstractTestBidiMap main;
435:
436: public TestInverseBidiMap(AbstractTestBidiMap main) {
437: super ();
438: this .main = main;
439: }
440:
441: public BidiMap makeEmptyBidiMap() {
442: return main.makeEmptyBidiMap().inverseBidiMap();
443: }
444:
445: public BidiMap makeFullBidiMap() {
446: return main.makeFullBidiMap().inverseBidiMap();
447: }
448:
449: public Map makeFullMap() {
450: return ((BidiMap) main.makeFullMap()).inverseBidiMap();
451: }
452:
453: public Object[] getSampleKeys() {
454: return main.getSampleValues();
455: }
456:
457: public Object[] getSampleValues() {
458: return main.getSampleKeys();
459: }
460:
461: public String getCompatibilityVersion() {
462: return main.getCompatibilityVersion();
463: }
464:
465: public boolean isAllowNullKey() {
466: return main.isAllowNullKey();
467: }
468:
469: public boolean isAllowNullValue() {
470: return main.isAllowNullValue();
471: }
472:
473: public boolean isPutAddSupported() {
474: return main.isPutAddSupported();
475: }
476:
477: public boolean isPutChangeSupported() {
478: return main.isPutChangeSupported();
479: }
480:
481: public boolean isSetValueSupported() {
482: return main.isSetValueSupported();
483: }
484:
485: public boolean isRemoveSupported() {
486: return main.isRemoveSupported();
487: }
488:
489: }
490:
491: //-----------------------------------------------------------------------
492: public BulkTest bulkTestBidiMapIterator() {
493: return new TestBidiMapIterator();
494: }
495:
496: public class TestBidiMapIterator extends AbstractTestMapIterator {
497: public TestBidiMapIterator() {
498: super ("TestBidiMapIterator");
499: }
500:
501: public Object[] addSetValues() {
502: return AbstractTestBidiMap.this .getNewSampleValues();
503: }
504:
505: public boolean supportsRemove() {
506: return AbstractTestBidiMap.this .isRemoveSupported();
507: }
508:
509: public boolean supportsSetValue() {
510: return AbstractTestBidiMap.this .isSetValueSupported();
511: }
512:
513: public MapIterator makeEmptyMapIterator() {
514: resetEmpty();
515: return ((BidiMap) AbstractTestBidiMap.this .map)
516: .mapIterator();
517: }
518:
519: public MapIterator makeFullMapIterator() {
520: resetFull();
521: return ((BidiMap) AbstractTestBidiMap.this .map)
522: .mapIterator();
523: }
524:
525: public Map getMap() {
526: // assumes makeFullMapIterator() called first
527: return AbstractTestBidiMap.this .map;
528: }
529:
530: public Map getConfirmedMap() {
531: // assumes makeFullMapIterator() called first
532: return AbstractTestBidiMap.this .confirmed;
533: }
534:
535: public void verify() {
536: super .verify();
537: AbstractTestBidiMap.this .verify();
538: }
539: }
540:
541: //-----------------------------------------------------------------------
542: public void testBidiMapIteratorSet() {
543: Object newValue1 = getOtherValues()[0];
544: Object newValue2 = getOtherValues()[1];
545:
546: resetFull();
547: BidiMap bidi = (BidiMap) map;
548: MapIterator it = bidi.mapIterator();
549: assertEquals(true, it.hasNext());
550: Object key1 = it.next();
551:
552: if (isSetValueSupported() == false) {
553: try {
554: it.setValue(newValue1);
555: fail();
556: } catch (UnsupportedOperationException ex) {
557: }
558: return;
559: }
560:
561: it.setValue(newValue1);
562: confirmed.put(key1, newValue1);
563: assertSame(key1, it.getKey());
564: assertSame(newValue1, it.getValue());
565: assertEquals(true, bidi.containsKey(key1));
566: assertEquals(true, bidi.containsValue(newValue1));
567: assertEquals(newValue1, bidi.get(key1));
568: verify();
569:
570: it.setValue(newValue1); // same value - should be OK
571: confirmed.put(key1, newValue1);
572: assertSame(key1, it.getKey());
573: assertSame(newValue1, it.getValue());
574: assertEquals(true, bidi.containsKey(key1));
575: assertEquals(true, bidi.containsValue(newValue1));
576: assertEquals(newValue1, bidi.get(key1));
577: verify();
578:
579: Object key2 = it.next();
580: it.setValue(newValue2);
581: confirmed.put(key2, newValue2);
582: assertSame(key2, it.getKey());
583: assertSame(newValue2, it.getValue());
584: assertEquals(true, bidi.containsKey(key2));
585: assertEquals(true, bidi.containsValue(newValue2));
586: assertEquals(newValue2, bidi.get(key2));
587: verify();
588:
589: // at this point
590: // key1=newValue1, key2=newValue2
591: try {
592: it.setValue(newValue1); // should remove key1
593: fail();
594: } catch (IllegalArgumentException ex) {
595: return; // simplest way of dealing with tricky situation
596: }
597: confirmed.put(key2, newValue1);
598: AbstractTestBidiMap.this .confirmed.remove(key1);
599: assertEquals(newValue1, it.getValue());
600: assertEquals(true, bidi.containsKey(it.getKey()));
601: assertEquals(true, bidi.containsValue(newValue1));
602: assertEquals(newValue1, bidi.get(it.getKey()));
603: assertEquals(false, bidi.containsKey(key1));
604: assertEquals(false, bidi.containsValue(newValue2));
605: verify();
606:
607: // check for ConcurrentModification
608: it.next(); // if you fail here, maybe you should be throwing an IAE, see above
609: if (isRemoveSupported()) {
610: it.remove();
611: }
612: }
613:
614: }
|