001: /*
002: * Copyright 1999-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;
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: /**
025: * Tests base {@link java.util.Map} methods and contracts.
026: * <p>
027: * The forces at work here are similar to those in {@link TestCollection}.
028: * If your class implements the full Map interface, including optional
029: * operations, simply extend this class, and implement the {@link
030: * #makeEmptyMap()} method.
031: * <p>
032: * On the other hand, if your map implemenation is wierd, you may have to
033: * override one or more of the other protected methods. They're described
034: * below.<P>
035: *
036: * <B>Entry Population Methods</B><P>
037: *
038: * Override these methods if your map requires special entries:
039: *
040: * <UL>
041: * <LI>{@link #getSampleKeys()}
042: * <LI>{@link #getSampleValues()}
043: * <LI>{@link #getNewSampleValues()}
044: * <LI>{@link #getOtherKeys()}
045: * <LI>{@link #getOtherValues()}
046: * </UL>
047: *
048: * <B>Supported Operation Methods</B><P>
049: *
050: * Override these methods if your map doesn't support certain operations:
051: *
052: * <UL>
053: * <LI> {@link #useDuplicateValues()}
054: * <LI> {@link #useNullKey()}
055: * <LI> {@link #useNullValue()}
056: * <LI> {@link #isAddRemoveModifiable()}
057: * <LI> {@link #isChangeable()}
058: * </UL>
059: *
060: * <B>Fixture Methods</B><P>
061: *
062: * For tests on modification operations (puts and removes), fixtures are used
063: * to verify that that operation results in correct state for the map and its
064: * collection views. Basically, the modification is performed against your
065: * map implementation, and an identical modification is performed against
066: * a <I>confirmed</I> map implementation. A confirmed map implementation is
067: * something like <Code>java.util.HashMap</Code>, which is known to conform
068: * exactly to the {@link Map} contract. After the modification takes place
069: * on both your map implementation and the confirmed map implementation, the
070: * two maps are compared to see if their state is identical. The comparison
071: * also compares the collection views to make sure they're still the same.<P>
072: *
073: * The upshot of all that is that <I>any</I> test that modifies the map in
074: * <I>any</I> way will verify that <I>all</I> of the map's state is still
075: * correct, including the state of its collection views. So for instance
076: * if a key is removed by the map's key set's iterator, then the entry set
077: * is checked to make sure the key/value pair no longer appears.<P>
078: *
079: * The {@link #map} field holds an instance of your collection implementation.
080: * The {@link #entrySet}, {@link #keySet} and {@link #collectionValues} fields hold
081: * that map's collection views. And the {@link #confirmed} field holds
082: * an instance of the confirmed collection implementation. The
083: * {@link #resetEmpty()} and {@link #resetFull()} methods set these fields to
084: * empty or full maps, so that tests can proceed from a known state.<P>
085: *
086: * After a modification operation to both {@link #map} and {@link #confirmed},
087: * the {@link #verify()} method is invoked to compare the results. The {@link
088: * verify()} method calls separate methods to verify the map and its three
089: * collection views ({@link verifyMap(), {@link verifyEntrySet()}, {@link
090: * verifyKeySet()}, and {@link verifyValues()}). You may want to override one
091: * of the verification methodsto perform additional verifications. For
092: * instance, {@link TestDoubleOrderedMap} would want override its {@link
093: * #verifyValues()} method to verify that the values are unique and in
094: * ascending order.<P>
095: *
096: * <B>Other Notes</B><P>
097: *
098: * If your {@link Map} fails one of these tests by design, you may still use
099: * this base set of cases. Simply override the test case (method) your {@link
100: * Map} fails and/or the methods that define the assumptions used by the test
101: * cases. For example, if your map does not allow duplicate values, override
102: * {@link #useDuplicateValues()} and have it return <code>false</code>
103: *
104: * @author Michael Smith
105: * @author Rodney Waldhoff
106: * @author Paul Jack
107: * @version $Id: TestMap.java,v 1.20.2.1 2004/05/22 12:14:05 scolebourne Exp $
108: */
109: public abstract class TestMap extends TestObject {
110:
111: // These instance variables are initialized with the reset method.
112: // Tests for map methods that alter the map (put, putAll, remove)
113: // first call reset() to create the map and its views; then perform
114: // the modification on the map; perform the same modification on the
115: // confirmed; and then call verify() to ensure that the map is equal
116: // to the confirmed, that the already-constructed collection views
117: // are still equal to the confirmed's collection views.
118:
119: /** Map created by reset(). */
120: protected Map map;
121:
122: /** Entry set of map created by reset(). */
123: protected Set entrySet;
124:
125: /** Key set of map created by reset(). */
126: protected Set keySet;
127:
128: /** Values collection of map created by reset(). */
129: protected Collection collectionValues;
130:
131: /** HashMap created by reset(). */
132: protected Map confirmed;
133:
134: /**
135: * Override if your map does not allow a <code>null</code> key. The
136: * default implementation returns <code>true</code>
137: **/
138: protected boolean useNullKey() {
139: return true;
140: }
141:
142: /**
143: * Override if your map does not allow <code>null</code> values. The
144: * default implementation returns <code>true</code>.
145: **/
146: protected boolean useNullValue() {
147: return true;
148: }
149:
150: /**
151: * Override if your map does not allow duplicate values. The default
152: * implementation returns <code>true</code>.
153: **/
154: protected boolean useDuplicateValues() {
155: return true;
156: }
157:
158: /**
159: * Override if your map allows its mappings to be changed to new values.
160: * The default implementation returns <code>true</code>.
161: **/
162: protected boolean isChangeable() {
163: return true;
164: }
165:
166: /**
167: * Override if your map does not allow add/remove modifications. The
168: * default implementation returns <code>true</code>.
169: **/
170: protected boolean isAddRemoveModifiable() {
171: return true;
172: }
173:
174: /**
175: * Returns the set of keys in the mappings used to test the map. This
176: * method must return an array with the same length as {@link
177: * #getSampleValues()} and all array elements must be different. The
178: * default implementation constructs a set of String keys, and includes a
179: * single null key if {@link #useNullKey()} returns <code>true</code>.
180: **/
181: protected Object[] getSampleKeys() {
182: Object[] result = new Object[] { "blah", "foo", "bar", "baz",
183: "tmp", "gosh", "golly", "gee", "hello", "goodbye",
184: "we'll", "see", "you", "all", "again", "key", "key2",
185: (useNullKey()) ? null : "nonnullkey" };
186: return result;
187: }
188:
189: protected Object[] getOtherKeys() {
190: return TestCollection.getOtherNonNullStringElements();
191: }
192:
193: protected Object[] getOtherValues() {
194: return TestCollection.getOtherNonNullStringElements();
195: }
196:
197: /**
198: * Returns the set of values in the mappings used to test the map. This
199: * method must return an array with the same length as {@link
200: * #getSampleKeys()}. The default implementation contructs a set of
201: * String values and includes a single null value if {@link
202: * #useNullValue()} returns <code>true</code>, and includes two values
203: * that are the same if {@link #useDuplicateValues()} returns
204: * <code>true</code>.
205: **/
206: protected Object[] getSampleValues() {
207: Object[] result = new Object[] { "blahv", "foov", "barv",
208: "bazv", "tmpv", "goshv", "gollyv", "geev", "hellov",
209: "goodbyev", "we'llv", "seev", "youv", "allv", "againv",
210: (useNullValue()) ? null : "nonnullvalue", "value",
211: (useDuplicateValues()) ? "value" : "value2", };
212: return result;
213: }
214:
215: /**
216: * Returns a the set of values that can be used to replace the values
217: * returned from {@link #getSampleValues()}. This method must return an
218: * array with the same length as {@link #getSampleValues()}. The values
219: * returned from this method should not be the same as those returned from
220: * {@link #getSampleValues()}. The default implementation constructs a
221: * set of String values and includes a single null value if {@link
222: * #useNullValue()} returns <code>true</code>, and includes two values
223: * that are the same if {@link #useDuplicateValues()} returns
224: * <code>true</code>.
225: **/
226: protected Object[] getNewSampleValues() {
227: Object[] result = new Object[] {
228: (useNullValue()) ? null : "newnonnullvalue",
229: "newvalue",
230: (useDuplicateValues()) ? "newvalue" : "newvalue2",
231: "newblahv", "newfoov", "newbarv", "newbazv", "newtmpv",
232: "newgoshv", "newgollyv", "newgeev", "newhellov",
233: "newgoodbyev", "newwe'llv", "newseev", "newyouv",
234: "newallv", "newagainv", };
235: return result;
236: }
237:
238: /**
239: * Helper method to add all the mappings described by {@link
240: * #getSampleKeys()} and {@link #getSampleValues()}.
241: **/
242: protected void addSampleMappings(Map m) {
243:
244: Object[] keys = getSampleKeys();
245: Object[] values = getSampleValues();
246:
247: for (int i = 0; i < keys.length; i++) {
248: try {
249: m.put(keys[i], values[i]);
250: } catch (NullPointerException exception) {
251: assertTrue(
252: "NullPointerException only allowed to be thrown "
253: + "if either the key or value is null.",
254: keys[i] == null || values[i] == null);
255:
256: assertTrue(
257: "NullPointerException on null key, but "
258: + "useNullKey is not overridden to return false.",
259: keys[i] == null || !useNullKey());
260:
261: assertTrue(
262: "NullPointerException on null value, but "
263: + "useNullValue is not overridden to return false.",
264: values[i] == null || !useNullValue());
265:
266: assertTrue("Unknown reason for NullPointer.", false);
267: }
268: }
269: assertEquals("size must reflect number of mappings added.",
270: keys.length, m.size());
271: }
272:
273: /**
274: * Return a new, empty {@link Map} to be used for testing.
275: */
276: protected abstract Map makeEmptyMap();
277:
278: /**
279: * Return a new, populated map. The mappings in the map should match the
280: * keys and values returned from {@link #getSampleKeys()} and {@link
281: * #getSampleValues()}. The default implementation uses makeEmptyMap()
282: * and calls {@link #addSampleMappings()} to add all the mappings to the
283: * map.
284: **/
285: protected Map makeFullMap() {
286: Map m = makeEmptyMap();
287: addSampleMappings(m);
288: return m;
289: }
290:
291: public Object makeObject() {
292: return makeEmptyMap();
293: }
294:
295: /**
296: * Test to ensure the test setup is working properly. This method checks
297: * to ensure that the getSampleKeys and getSampleValues methods are
298: * returning results that look appropriate. That is, they both return a
299: * non-null array of equal length. The keys array must not have any
300: * duplicate values, and may only contain a (single) null key if
301: * useNullKey() returns true. The values array must only have a null
302: * value if useNullValue() is true and may only have duplicate values if
303: * useDuplicateValues() returns true.
304: **/
305: public void testSampleMappings() {
306: Object[] keys = getSampleKeys();
307: Object[] values = getSampleValues();
308: Object[] newValues = getNewSampleValues();
309:
310: assertTrue("failure in test: Must have keys returned from "
311: + "getSampleKeys.", keys != null);
312:
313: assertTrue("failure in test: Must have values returned from "
314: + "getSampleValues.", values != null);
315:
316: // verify keys and values have equivalent lengths (in case getSampleX are
317: // overridden)
318: assertEquals("failure in test: not the same number of sample "
319: + "keys and values.", keys.length, values.length);
320:
321: assertEquals(
322: "failure in test: not the same number of values and new values.",
323: values.length, newValues.length);
324:
325: // verify there aren't duplicate keys, and check values
326: for (int i = 0; i < keys.length - 1; i++) {
327: for (int j = i + 1; j < keys.length; j++) {
328: assertTrue("failure in test: duplicate null keys.",
329: (keys[i] != null || keys[j] != null));
330: assertTrue(
331: "failure in test: duplicate non-null key.",
332: (keys[i] == null || keys[j] == null || (!keys[i]
333: .equals(keys[j]) && !keys[j]
334: .equals(keys[i]))));
335: }
336: assertTrue(
337: "failure in test: found null key, but useNullKey "
338: + "is false.", keys[i] != null
339: || useNullKey());
340: assertTrue(
341: "failure in test: found null value, but useNullValue "
342: + "is false.", values[i] != null
343: || useNullValue());
344: assertTrue(
345: "failure in test: found null new value, but useNullValue "
346: + "is false.", newValues[i] != null
347: || useNullValue());
348: assertTrue(
349: "failure in test: values should not be the same as new value",
350: values[i] != newValues[i]
351: && (values[i] == null || !values[i]
352: .equals(newValues[i])));
353: }
354: }
355:
356: // tests begin here. Each test adds a little bit of tested functionality.
357: // Many methods assume previous methods passed. That is, they do not
358: // exhaustively recheck things that have already been checked in a previous
359: // test methods.
360:
361: /**
362: * Test to ensure that makeEmptyMap and makeFull returns a new non-null
363: * map with each invocation.
364: **/
365: public void testMakeMap() {
366: Map em = makeEmptyMap();
367: assertTrue(
368: "failure in test: makeEmptyMap must return a non-null map.",
369: em != null);
370:
371: Map em2 = makeEmptyMap();
372: assertTrue(
373: "failure in test: makeEmptyMap must return a non-null map.",
374: em != null);
375:
376: assertTrue(
377: "failure in test: makeEmptyMap must return a new map "
378: + "with each invocation.", em != em2);
379:
380: Map fm = makeFullMap();
381: assertTrue(
382: "failure in test: makeFullMap must return a non-null map.",
383: fm != null);
384:
385: Map fm2 = makeFullMap();
386: assertTrue(
387: "failure in test: makeFullMap must return a non-null map.",
388: fm != null);
389:
390: assertTrue(
391: "failure in test: makeFullMap must return a new map "
392: + "with each invocation.", fm != fm2);
393: }
394:
395: /**
396: * Tests Map.isEmpty()
397: **/
398: public void testMapIsEmpty() {
399:
400: resetEmpty();
401: assertEquals(
402: "Map.isEmpty() should return true with an empty map",
403: true, map.isEmpty());
404: verify();
405:
406: resetFull();
407: assertEquals(
408: "Map.isEmpty() should return false with a non-empty map",
409: false, map.isEmpty());
410: verify();
411: }
412:
413: /**
414: * Tests Map.size()
415: **/
416: public void testMapSize() {
417: resetEmpty();
418: assertEquals("Map.size() should be 0 with an empty map", 0, map
419: .size());
420: verify();
421:
422: resetFull();
423: assertEquals("Map.size() should equal the number of entries "
424: + "in the map", getSampleKeys().length, map.size());
425: verify();
426: }
427:
428: /**
429: * Tests {@link Map#clear()}. If the map {@link #isAddRemoveModifiable()
430: * can add and remove elements}, then {@link Map#size()} and {@link
431: * Map#isEmpty()} are used to ensure that map has no elements after a call
432: * to clear. If the map does not support adding and removing elements,
433: * this method checks to ensure clear throws an
434: * UnsupportedOperationException.
435: **/
436: public void testMapClear() {
437: if (!isAddRemoveModifiable())
438: return;
439:
440: resetEmpty();
441: map.clear();
442: confirmed.clear();
443: verify();
444:
445: resetFull();
446: map.clear();
447: confirmed.clear();
448: verify();
449: }
450:
451: /**
452: * Tests Map.containsKey(Object) by verifying it returns false for all
453: * sample keys on a map created using an empty map and returns true for
454: * all sample keys returned on a full map.
455: **/
456: public void testMapContainsKey() {
457: Object[] keys = getSampleKeys();
458:
459: resetEmpty();
460: for (int i = 0; i < keys.length; i++) {
461: assertTrue("Map must not contain key when map is empty",
462: !map.containsKey(keys[i]));
463: }
464: verify();
465:
466: resetFull();
467: for (int i = 0; i < keys.length; i++) {
468: assertTrue(
469: "Map must contain key for a mapping in the map. "
470: + "Missing: " + keys[i], map
471: .containsKey(keys[i]));
472: }
473: verify();
474: }
475:
476: /**
477: * Tests Map.containsValue(Object) by verifying it returns false for all
478: * sample values on an empty map and returns true for all sample values on
479: * a full map.
480: **/
481: public void testMapContainsValue() {
482: Object[] values = getSampleValues();
483:
484: resetEmpty();
485: for (int i = 0; i < values.length; i++) {
486: assertTrue("Empty map must not contain value", !map
487: .containsValue(values[i]));
488: }
489: verify();
490:
491: resetFull();
492: for (int i = 0; i < values.length; i++) {
493: assertTrue(
494: "Map must contain value for a mapping in the map.",
495: map.containsValue(values[i]));
496: }
497: verify();
498: }
499:
500: /**
501: * Tests Map.equals(Object)
502: **/
503: public void testMapEquals() {
504: resetEmpty();
505: assertTrue("Empty maps unequal.", map.equals(confirmed));
506: verify();
507:
508: resetFull();
509: assertTrue("Full maps unequal.", map.equals(confirmed));
510: verify();
511:
512: resetFull();
513: // modify the HashMap created from the full map and make sure this
514: // change results in map.equals() to return false.
515: Iterator iter = confirmed.keySet().iterator();
516: iter.next();
517: iter.remove();
518: assertTrue("Different maps equal.", !map.equals(confirmed));
519:
520: resetFull();
521: assertTrue("equals(null) returned true.", !map.equals(null));
522: assertTrue("equals(new Object()) returned true.", !map
523: .equals(new Object()));
524: verify();
525: }
526:
527: /**
528: * Tests Map.get(Object)
529: **/
530: public void testMapGet() {
531: resetEmpty();
532:
533: Object[] keys = getSampleKeys();
534: Object[] values = getSampleValues();
535:
536: for (int i = 0; i < keys.length; i++) {
537: assertTrue("Empty map.get() should return null.", map
538: .get(keys[i]) == null);
539: }
540: verify();
541:
542: resetFull();
543: for (int i = 0; i < keys.length; i++) {
544: assertEquals(
545: "Full map.get() should return value from mapping.",
546: values[i], map.get(keys[i]));
547: }
548: }
549:
550: /**
551: * Tests Map.hashCode()
552: **/
553: public void testMapHashCode() {
554: resetEmpty();
555: assertTrue("Empty maps have different hashCodes.", map
556: .hashCode() == confirmed.hashCode());
557:
558: resetFull();
559: assertTrue("Equal maps have different hashCodes.", map
560: .hashCode() == confirmed.hashCode());
561: }
562:
563: /**
564: * Tests Map.toString(). Since the format of the string returned by the
565: * toString() method is not defined in the Map interface, there is no
566: * common way to test the results of the toString() method. Thereforce,
567: * it is encouraged that Map implementations override this test with one
568: * that checks the format matches any format defined in its API. This
569: * default implementation just verifies that the toString() method does
570: * not return null.
571: **/
572: public void testMapToString() {
573: resetEmpty();
574: assertTrue("Empty map toString() should not return null", map
575: .toString() != null);
576: verify();
577:
578: resetFull();
579: assertTrue("Empty map toString() should not return null", map
580: .toString() != null);
581: verify();
582: }
583:
584: /**
585: * Tests Map.put(Object, Object)
586: **/
587: public void testMapPut() {
588: if (!isAddRemoveModifiable())
589: return;
590:
591: resetEmpty();
592:
593: Object[] keys = getSampleKeys();
594: Object[] values = getSampleValues();
595: Object[] newValues = getNewSampleValues();
596:
597: for (int i = 0; i < keys.length; i++) {
598: Object o = map.put(keys[i], values[i]);
599: confirmed.put(keys[i], values[i]);
600: verify();
601: assertTrue("First map.put should return null", o == null);
602: assertTrue("Map should contain key after put", map
603: .containsKey(keys[i]));
604: assertTrue("Map should contain value after put", map
605: .containsValue(values[i]));
606: }
607:
608: for (int i = 0; i < keys.length; i++) {
609: Object o = map.put(keys[i], newValues[i]);
610: confirmed.put(keys[i], newValues[i]);
611: verify();
612: assertEquals("Second map.put should return previous value",
613: values[i], o);
614: assertTrue("Map should still contain key after put", map
615: .containsKey(keys[i]));
616: assertTrue("Map should contain new value after put", map
617: .containsValue(newValues[i]));
618:
619: // if duplicates are allowed, we're not guarunteed that the value
620: // no longer exists, so don't try checking that.
621: if (!useDuplicateValues()) {
622: assertTrue(
623: "Map should not contain old value after second put",
624: !map.containsValue(values[i]));
625: }
626: }
627: }
628:
629: /**
630: * Tests Map.putAll(Collection)
631: **/
632: public void testMapPutAll() {
633: if (!isAddRemoveModifiable())
634: return;
635:
636: resetEmpty();
637:
638: Map m2 = makeFullMap();
639:
640: map.putAll(m2);
641: confirmed.putAll(m2);
642: verify();
643:
644: resetEmpty();
645:
646: m2 = new HashMap();
647: Object[] keys = getSampleKeys();
648: Object[] values = getSampleValues();
649: for (int i = 0; i < keys.length; i++) {
650: m2.put(keys[i], values[i]);
651: }
652:
653: map.putAll(m2);
654: confirmed.putAll(m2);
655: verify();
656: }
657:
658: /**
659: * Tests Map.remove(Object)
660: **/
661: public void testMapRemove() {
662: if (!isAddRemoveModifiable())
663: return;
664:
665: resetEmpty();
666:
667: Object[] keys = getSampleKeys();
668: Object[] values = getSampleValues();
669: for (int i = 0; i < keys.length; i++) {
670: Object o = map.remove(keys[i]);
671: assertTrue("First map.remove should return null", o == null);
672: }
673: verify();
674:
675: resetFull();
676:
677: for (int i = 0; i < keys.length; i++) {
678: Object o = map.remove(keys[i]);
679: confirmed.remove(keys[i]);
680: verify();
681:
682: assertEquals(
683: "map.remove with valid key should return value",
684: values[i], o);
685: }
686:
687: Object[] other = getOtherKeys();
688:
689: resetFull();
690: int size = map.size();
691: for (int i = 0; i < other.length; i++) {
692: Object o = map.remove(other[i]);
693: assertEquals(
694: "map.remove for nonexistent key should return null",
695: o, null);
696: assertEquals("map.remove for nonexistent key should not "
697: + "shrink map", size, map.size());
698: }
699: verify();
700: }
701:
702: /**
703: * Utility methods to create an array of Map.Entry objects
704: * out of the given key and value arrays.<P>
705: *
706: * @param keys the array of keys
707: * @param values the array of values
708: * @return an array of Map.Entry of those keys to those values
709: */
710: private Map.Entry[] makeEntryArray(Object[] keys, Object[] values) {
711: Map.Entry[] result = new Map.Entry[keys.length];
712: for (int i = 0; i < keys.length; i++) {
713: result[i] = new DefaultMapEntry(keys[i], values[i]);
714: }
715: return result;
716: }
717:
718: class TestMapEntrySet extends TestSet {
719: public TestMapEntrySet() {
720: super ("");
721: }
722:
723: // Have to implement manually; entrySet doesn't support addAll
724: protected Object[] getFullElements() {
725: Object[] k = getSampleKeys();
726: Object[] v = getSampleValues();
727: return makeEntryArray(k, v);
728: }
729:
730: // Have to implement manually; entrySet doesn't support addAll
731: protected Object[] getOtherElements() {
732: Object[] k = getOtherKeys();
733: Object[] v = getOtherValues();
734: return makeEntryArray(k, v);
735: }
736:
737: protected Set makeEmptySet() {
738: return makeEmptyMap().entrySet();
739: }
740:
741: protected Set makeFullSet() {
742: return makeFullMap().entrySet();
743: }
744:
745: protected boolean isAddSupported() {
746: // Collection views don't support add operations.
747: return false;
748: }
749:
750: protected boolean isRemoveSupported() {
751: // Entry set should only support remove if map does
752: return isAddRemoveModifiable();
753: }
754:
755: protected void resetFull() {
756: TestMap.this .resetFull();
757: collection = map.entrySet();
758: TestMapEntrySet.this .confirmed = TestMap.this .confirmed
759: .entrySet();
760: }
761:
762: protected void resetEmpty() {
763: TestMap.this .resetEmpty();
764: collection = map.entrySet();
765: TestMapEntrySet.this .confirmed = TestMap.this .confirmed
766: .entrySet();
767: }
768:
769: protected void verify() {
770: super .verify();
771: TestMap.this .verify();
772: }
773: }
774:
775: class TestMapKeySet extends TestSet {
776: public TestMapKeySet() {
777: super ("");
778: }
779:
780: protected Object[] getFullElements() {
781: return getSampleKeys();
782: }
783:
784: protected Object[] getOtherElements() {
785: return getOtherKeys();
786: }
787:
788: protected Set makeEmptySet() {
789: return makeEmptyMap().keySet();
790: }
791:
792: protected Set makeFullSet() {
793: return makeFullMap().keySet();
794: }
795:
796: protected boolean isAddSupported() {
797: return false;
798: }
799:
800: protected boolean isRemoveSupported() {
801: return isAddRemoveModifiable();
802: }
803:
804: protected void resetEmpty() {
805: TestMap.this .resetEmpty();
806: collection = map.keySet();
807: TestMapKeySet.this .confirmed = TestMap.this .confirmed
808: .keySet();
809: }
810:
811: protected void resetFull() {
812: TestMap.this .resetFull();
813: collection = map.keySet();
814: TestMapKeySet.this .confirmed = TestMap.this .confirmed
815: .keySet();
816: }
817:
818: protected void verify() {
819: super .verify();
820: TestMap.this .verify();
821: }
822: }
823:
824: class TestMapValues extends TestCollection {
825: public TestMapValues() {
826:
827: }
828:
829: protected Object[] getFullElements() {
830: return getSampleValues();
831: }
832:
833: protected Object[] getOtherElements() {
834: return getOtherValues();
835: }
836:
837: protected Collection makeCollection() {
838: return makeEmptyMap().values();
839: }
840:
841: protected Collection makeFullCollection() {
842: return makeFullMap().values();
843: }
844:
845: protected boolean isAddSupported() {
846: return false;
847: }
848:
849: protected boolean isRemoveSupported() {
850: return isAddRemoveModifiable();
851: }
852:
853: protected boolean areEqualElementsDistinguishable() {
854: // equal values are associated with different keys, so they are
855: // distinguishable.
856: return true;
857: }
858:
859: protected Collection makeConfirmedCollection() {
860: // never gets called, reset methods are overridden
861: return null;
862: }
863:
864: protected Collection makeConfirmedFullCollection() {
865: // never gets called, reset methods are overridden
866: return null;
867: }
868:
869: protected void resetFull() {
870: TestMap.this .resetFull();
871: collection = map.values();
872: TestMapValues.this .confirmed = TestMap.this .confirmed
873: .values();
874: }
875:
876: protected void resetEmpty() {
877: TestMap.this .resetEmpty();
878: collection = map.values();
879: TestMapValues.this .confirmed = TestMap.this .confirmed
880: .values();
881: }
882:
883: protected void verify() {
884: super .verify();
885: TestMap.this .verify();
886: }
887:
888: // TODO: should test that a remove on the values collection view
889: // removes the proper mapping and not just any mapping that may have
890: // the value equal to the value returned from the values iterator.
891: }
892:
893: /**
894: * Resets the {@link #map}, {@link #entrySet}, {@link #keySet},
895: * {@link #collectionValues} and {@link #confirmed} fields to empty.
896: */
897: protected void resetEmpty() {
898: this .map = makeEmptyMap();
899: views();
900: this .confirmed = new HashMap();
901: }
902:
903: /**
904: * Resets the {@link #map}, {@link #entrySet}, {@link #keySet},
905: * {@link #collectionValues} and {@link #confirmed} fields to full.
906: */
907: protected void resetFull() {
908: this .map = makeFullMap();
909: views();
910: this .confirmed = new HashMap();
911: Object[] k = getSampleKeys();
912: Object[] v = getSampleValues();
913: for (int i = 0; i < k.length; i++) {
914: confirmed.put(k[i], v[i]);
915: }
916: }
917:
918: /**
919: * Resets the collection view fields.
920: */
921: private void views() {
922: this .keySet = map.keySet();
923: this .collectionValues = map.values();
924: this .entrySet = map.entrySet();
925: }
926:
927: /**
928: * Verifies that {@link #map} is still equal to {@link #confirmed}.
929: * This method checks that the map is equal to the HashMap,
930: * <I>and</I> that the map's collection views are still equal to
931: * the HashMap's collection views. An <Code>equals</Code> test
932: * is done on the maps and their collection views; their size and
933: * <Code>isEmpty</Code> results are compared; their hashCodes are
934: * compared; and <Code>containsAll</Code> tests are run on the
935: * collection views.
936: */
937: protected void verify() {
938: verifyMap();
939: verifyEntrySet();
940: verifyKeySet();
941:
942: }
943:
944: protected void verifyMap() {
945: int size = confirmed.size();
946: boolean empty = confirmed.isEmpty();
947: assertEquals("Map should be same size as HashMap", size, map
948: .size());
949: assertEquals("Map should be empty if HashMap is", empty, map
950: .isEmpty());
951: assertEquals("hashCodes should be the same", confirmed
952: .hashCode(), map.hashCode());
953: // this fails for LRUMap because confirmed.equals() somehow modifies
954: // map, causing concurrent modification exceptions.
955: //assertEquals("Map should still equal HashMap", confirmed, map);
956: // this works though and performs the same verification:
957: assertTrue("Map should still equal HashMap", map
958: .equals(confirmed));
959: // TODO: this should really be rexamined to figure out why LRU map
960: // behaves like it does (the equals shouldn't modify since all accesses
961: // by the confirmed collection should be through an iterator, thus not
962: // causing LRUMap to change).
963: }
964:
965: protected void verifyEntrySet() {
966: int size = confirmed.size();
967: boolean empty = confirmed.isEmpty();
968: assertEquals("entrySet should be same size as HashMap's", size,
969: entrySet.size());
970: assertEquals("entrySet should be empty if HashMap is", empty,
971: entrySet.isEmpty());
972: assertTrue("entrySet should contain all HashMap's elements",
973: entrySet.containsAll(confirmed.entrySet()));
974: assertEquals("entrySet hashCodes should be the same", confirmed
975: .entrySet().hashCode(), entrySet.hashCode());
976: assertEquals("Map's entry set should still equal HashMap's",
977: confirmed.entrySet(), entrySet);
978: }
979:
980: protected void verifyKeySet() {
981: int size = confirmed.size();
982: boolean empty = confirmed.isEmpty();
983: assertEquals("keySet should be same size as HashMap's", size,
984: keySet.size());
985: assertEquals("keySet should be empty if HashMap is", empty,
986: keySet.isEmpty());
987: assertTrue("keySet should contain all HashMap's elements",
988: keySet.containsAll(confirmed.keySet()));
989: assertEquals("keySet hashCodes should be the same", confirmed
990: .keySet().hashCode(), keySet.hashCode());
991: assertEquals("Map's key set should still equal HashMap's",
992: confirmed.keySet(), keySet);
993: }
994:
995: }
|