0001: /*
0002: * Copyright 2001-2004 The Apache Software Foundation
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.apache.commons.collections.map;
0017:
0018: import java.io.Serializable;
0019: import java.util.ArrayList;
0020: import java.util.Collection;
0021: import java.util.HashMap;
0022: import java.util.Iterator;
0023: import java.util.List;
0024: import java.util.Map;
0025: import java.util.Set;
0026:
0027: import org.apache.commons.collections.AbstractTestObject;
0028: import org.apache.commons.collections.BulkTest;
0029: import org.apache.commons.collections.collection.AbstractTestCollection;
0030: import org.apache.commons.collections.set.AbstractTestSet;
0031:
0032: /**
0033: * Abstract test class for {@link java.util.Map} methods and contracts.
0034: * <p>
0035: * The forces at work here are similar to those in {@link AbstractTestCollection}.
0036: * If your class implements the full Map interface, including optional
0037: * operations, simply extend this class, and implement the
0038: * {@link #makeEmptyMap()} method.
0039: * <p>
0040: * On the other hand, if your map implementation is weird, you may have to
0041: * override one or more of the other protected methods. They're described
0042: * below.
0043: * <p>
0044: * <b>Entry Population Methods</b>
0045: * <p>
0046: * Override these methods if your map requires special entries:
0047: *
0048: * <ul>
0049: * <li>{@link #getSampleKeys()}
0050: * <li>{@link #getSampleValues()}
0051: * <li>{@link #getNewSampleValues()}
0052: * <li>{@link #getOtherKeys()}
0053: * <li>{@link #getOtherValues()}
0054: * </ul>
0055: *
0056: * <b>Supported Operation Methods</b>
0057: * <p>
0058: * Override these methods if your map doesn't support certain operations:
0059: *
0060: * <ul>
0061: * <li> {@link #isPutAddSupported()}
0062: * <li> {@link #isPutChangeSupported()}
0063: * <li> {@link #isSetValueSupported()}
0064: * <li> {@link #isRemoveSupported()}
0065: * <li> {@link #isGetStructuralModify()}
0066: * <li> {@link #isAllowDuplicateValues()}
0067: * <li> {@link #isAllowNullKey()}
0068: * <li> {@link #isAllowNullValue()}
0069: * </ul>
0070: *
0071: * <b>Fixture Methods</b>
0072: * <p>
0073: * For tests on modification operations (puts and removes), fixtures are used
0074: * to verify that that operation results in correct state for the map and its
0075: * collection views. Basically, the modification is performed against your
0076: * map implementation, and an identical modification is performed against
0077: * a <I>confirmed</I> map implementation. A confirmed map implementation is
0078: * something like <Code>java.util.HashMap</Code>, which is known to conform
0079: * exactly to the {@link Map} contract. After the modification takes place
0080: * on both your map implementation and the confirmed map implementation, the
0081: * two maps are compared to see if their state is identical. The comparison
0082: * also compares the collection views to make sure they're still the same.<P>
0083: *
0084: * The upshot of all that is that <I>any</I> test that modifies the map in
0085: * <I>any</I> way will verify that <I>all</I> of the map's state is still
0086: * correct, including the state of its collection views. So for instance
0087: * if a key is removed by the map's key set's iterator, then the entry set
0088: * is checked to make sure the key/value pair no longer appears.<P>
0089: *
0090: * The {@link #map} field holds an instance of your collection implementation.
0091: * The {@link #entrySet}, {@link #keySet} and {@link #values} fields hold
0092: * that map's collection views. And the {@link #confirmed} field holds
0093: * an instance of the confirmed collection implementation. The
0094: * {@link #resetEmpty()} and {@link #resetFull()} methods set these fields to
0095: * empty or full maps, so that tests can proceed from a known state.<P>
0096: *
0097: * After a modification operation to both {@link #map} and {@link #confirmed},
0098: * the {@link #verify()} method is invoked to compare the results. The
0099: * {@link #verify} method calls separate methods to verify the map and its three
0100: * collection views ({@link #verifyMap}, {@link #verifyEntrySet},
0101: * {@link #verifyKeySet}, and {@link #verifyValues}). You may want to override
0102: * one of the verification methodsto perform additional verifications. For
0103: * instance, TestDoubleOrderedMap would want override its
0104: * {@link #verifyValues()} method to verify that the values are unique and in
0105: * ascending order.<P>
0106: *
0107: * <b>Other Notes</b>
0108: * <p>
0109: * If your {@link Map} fails one of these tests by design, you may still use
0110: * this base set of cases. Simply override the test case (method) your map
0111: * fails and/or the methods that define the assumptions used by the test
0112: * cases. For example, if your map does not allow duplicate values, override
0113: * {@link #isAllowDuplicateValues()} and have it return <code>false</code>
0114: *
0115: * @author Michael Smith
0116: * @author Rodney Waldhoff
0117: * @author Paul Jack
0118: * @author Stephen Colebourne
0119: * @version $Revision: 169097 $ $Date: 2005-05-07 18:13:40 +0100 (Sat, 07 May 2005) $
0120: */
0121: public abstract class AbstractTestMap extends AbstractTestObject {
0122:
0123: /**
0124: * JDK1.2 has bugs in null handling of Maps, especially HashMap.Entry.toString
0125: * This avoids nulls for JDK1.2
0126: */
0127: private static final boolean JDK12;
0128: static {
0129: String str = System.getProperty("java.version");
0130: JDK12 = str.startsWith("1.2");
0131: }
0132:
0133: // These instance variables are initialized with the reset method.
0134: // Tests for map methods that alter the map (put, putAll, remove)
0135: // first call reset() to create the map and its views; then perform
0136: // the modification on the map; perform the same modification on the
0137: // confirmed; and then call verify() to ensure that the map is equal
0138: // to the confirmed, that the already-constructed collection views
0139: // are still equal to the confirmed's collection views.
0140:
0141: /** Map created by reset(). */
0142: protected Map map;
0143:
0144: /** Entry set of map created by reset(). */
0145: protected Set entrySet;
0146:
0147: /** Key set of map created by reset(). */
0148: protected Set keySet;
0149:
0150: /** Values collection of map created by reset(). */
0151: protected Collection values;
0152:
0153: /** HashMap created by reset(). */
0154: protected Map confirmed;
0155:
0156: /**
0157: * JUnit constructor.
0158: *
0159: * @param testName the test name
0160: */
0161: public AbstractTestMap(String testName) {
0162: super (testName);
0163: }
0164:
0165: /**
0166: * Returns true if the maps produced by
0167: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0168: * support the <code>put</code> and <code>putAll</code> operations
0169: * adding new mappings.
0170: * <p>
0171: * Default implementation returns true.
0172: * Override if your collection class does not support put adding.
0173: */
0174: public boolean isPutAddSupported() {
0175: return true;
0176: }
0177:
0178: /**
0179: * Returns true if the maps produced by
0180: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0181: * support the <code>put</code> and <code>putAll</code> operations
0182: * changing existing mappings.
0183: * <p>
0184: * Default implementation returns true.
0185: * Override if your collection class does not support put changing.
0186: */
0187: public boolean isPutChangeSupported() {
0188: return true;
0189: }
0190:
0191: /**
0192: * Returns true if the maps produced by
0193: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0194: * support the <code>setValue</code> operation on entrySet entries.
0195: * <p>
0196: * Default implementation returns isPutChangeSupported().
0197: * Override if your collection class does not support setValue but does
0198: * support put changing.
0199: */
0200: public boolean isSetValueSupported() {
0201: return isPutChangeSupported();
0202: }
0203:
0204: /**
0205: * Returns true if the maps produced by
0206: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0207: * support the <code>remove</code> and <code>clear</code> operations.
0208: * <p>
0209: * Default implementation returns true.
0210: * Override if your collection class does not support removal operations.
0211: */
0212: public boolean isRemoveSupported() {
0213: return true;
0214: }
0215:
0216: /**
0217: * Returns true if the maps produced by
0218: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0219: * can cause structural modification on a get(). The example is LRUMap.
0220: * <p>
0221: * Default implementation returns false.
0222: * Override if your map class structurally modifies on get.
0223: */
0224: public boolean isGetStructuralModify() {
0225: return false;
0226: }
0227:
0228: /**
0229: * Returns whether the sub map views of SortedMap are serializable.
0230: * If the class being tested is based around a TreeMap then you should
0231: * override and return false as TreeMap has a bug in deserialization.
0232: *
0233: * @return false
0234: */
0235: public boolean isSubMapViewsSerializable() {
0236: return true;
0237: }
0238:
0239: /**
0240: * Returns true if the maps produced by
0241: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0242: * supports null keys.
0243: * <p>
0244: * Default implementation returns true.
0245: * Override if your collection class does not support null keys.
0246: */
0247: public boolean isAllowNullKey() {
0248: return true;
0249: }
0250:
0251: /**
0252: * Returns true if the maps produced by
0253: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0254: * supports null values.
0255: * <p>
0256: * Default implementation returns true.
0257: * Override if your collection class does not support null values.
0258: */
0259: public boolean isAllowNullValue() {
0260: return true;
0261: }
0262:
0263: /**
0264: * Returns true if the maps produced by
0265: * {@link #makeEmptyMap()} and {@link #makeFullMap()}
0266: * supports duplicate values.
0267: * <p>
0268: * Default implementation returns true.
0269: * Override if your collection class does not support duplicate values.
0270: */
0271: public boolean isAllowDuplicateValues() {
0272: return true;
0273: }
0274:
0275: /**
0276: * Returns the set of keys in the mappings used to test the map. This
0277: * method must return an array with the same length as {@link
0278: * #getSampleValues()} and all array elements must be different. The
0279: * default implementation constructs a set of String keys, and includes a
0280: * single null key if {@link #isAllowNullKey()} returns <code>true</code>.
0281: */
0282: public Object[] getSampleKeys() {
0283: Object[] result = new Object[] { "blah", "foo", "bar", "baz",
0284: "tmp", "gosh", "golly", "gee", "hello", "goodbye",
0285: "we'll", "see", "you", "all", "again", "key", "key2",
0286: (isAllowNullKey() && !JDK12) ? null : "nonnullkey" };
0287: return result;
0288: }
0289:
0290: public Object[] getOtherKeys() {
0291: return getOtherNonNullStringElements();
0292: }
0293:
0294: public Object[] getOtherValues() {
0295: return getOtherNonNullStringElements();
0296: }
0297:
0298: /**
0299: * Returns a list of string elements suitable for return by
0300: * {@link #getOtherKeys()} or {@link #getOtherValues}.
0301: *
0302: * <p>Override getOtherElements to returnthe results of this method if your
0303: * collection does not support heterogenous elements or the null element.
0304: * </p>
0305: */
0306: public Object[] getOtherNonNullStringElements() {
0307: return new Object[] { "For", "then", "despite",/* of */
0308: "space", "I", "would", "be", "brought", "From",
0309: "limits", "far", "remote", "where", "thou", "dost",
0310: "stay" };
0311: }
0312:
0313: /**
0314: * Returns the set of values in the mappings used to test the map. This
0315: * method must return an array with the same length as
0316: * {@link #getSampleKeys()}. The default implementation constructs a set of
0317: * String values and includes a single null value if
0318: * {@link #isAllowNullValue()} returns <code>true</code>, and includes
0319: * two values that are the same if {@link #isAllowDuplicateValues()} returns
0320: * <code>true</code>.
0321: */
0322: public Object[] getSampleValues() {
0323: Object[] result = new Object[] { "blahv", "foov", "barv",
0324: "bazv", "tmpv", "goshv", "gollyv", "geev", "hellov",
0325: "goodbyev", "we'llv", "seev", "youv", "allv", "againv",
0326: (isAllowNullValue() && !JDK12) ? null : "nonnullvalue",
0327: "value",
0328: (isAllowDuplicateValues()) ? "value" : "value2", };
0329: return result;
0330: }
0331:
0332: /**
0333: * Returns a the set of values that can be used to replace the values
0334: * returned from {@link #getSampleValues()}. This method must return an
0335: * array with the same length as {@link #getSampleValues()}. The values
0336: * returned from this method should not be the same as those returned from
0337: * {@link #getSampleValues()}. The default implementation constructs a
0338: * set of String values and includes a single null value if
0339: * {@link #isAllowNullValue()} returns <code>true</code>, and includes two values
0340: * that are the same if {@link #isAllowDuplicateValues()} returns
0341: * <code>true</code>.
0342: */
0343: public Object[] getNewSampleValues() {
0344: Object[] result = new Object[] {
0345: (isAllowNullValue() && !JDK12 && isAllowDuplicateValues()) ? null
0346: : "newnonnullvalue", "newvalue",
0347: (isAllowDuplicateValues()) ? "newvalue" : "newvalue2",
0348: "newblahv", "newfoov", "newbarv", "newbazv", "newtmpv",
0349: "newgoshv", "newgollyv", "newgeev", "newhellov",
0350: "newgoodbyev", "newwe'llv", "newseev", "newyouv",
0351: "newallv", "newagainv", };
0352: return result;
0353: }
0354:
0355: /**
0356: * Helper method to add all the mappings described by
0357: * {@link #getSampleKeys()} and {@link #getSampleValues()}.
0358: */
0359: public void addSampleMappings(Map m) {
0360:
0361: Object[] keys = getSampleKeys();
0362: Object[] values = getSampleValues();
0363:
0364: for (int i = 0; i < keys.length; i++) {
0365: try {
0366: m.put(keys[i], values[i]);
0367: } catch (NullPointerException exception) {
0368: assertTrue(
0369: "NullPointerException only allowed to be thrown "
0370: + "if either the key or value is null.",
0371: keys[i] == null || values[i] == null);
0372:
0373: assertTrue(
0374: "NullPointerException on null key, but "
0375: + "isAllowNullKey is not overridden to return false.",
0376: keys[i] == null || !isAllowNullKey());
0377:
0378: assertTrue(
0379: "NullPointerException on null value, but "
0380: + "isAllowNullValue is not overridden to return false.",
0381: values[i] == null || !isAllowNullValue());
0382:
0383: assertTrue("Unknown reason for NullPointer.", false);
0384: }
0385: }
0386: assertEquals("size must reflect number of mappings added.",
0387: keys.length, m.size());
0388: }
0389:
0390: //-----------------------------------------------------------------------
0391: /**
0392: * Return a new, empty {@link Map} to be used for testing.
0393: *
0394: * @return the map to be tested
0395: */
0396: public abstract Map makeEmptyMap();
0397:
0398: /**
0399: * Return a new, populated map. The mappings in the map should match the
0400: * keys and values returned from {@link #getSampleKeys()} and
0401: * {@link #getSampleValues()}. The default implementation uses makeEmptyMap()
0402: * and calls {@link #addSampleMappings} to add all the mappings to the
0403: * map.
0404: *
0405: * @return the map to be tested
0406: */
0407: public Map makeFullMap() {
0408: Map m = makeEmptyMap();
0409: addSampleMappings(m);
0410: return m;
0411: }
0412:
0413: /**
0414: * Implements the superclass method to return the map to be tested.
0415: *
0416: * @return the map to be tested
0417: */
0418: public Object makeObject() {
0419: return makeEmptyMap();
0420: }
0421:
0422: /**
0423: * Override to return a map other than HashMap as the confirmed map.
0424: *
0425: * @return a map that is known to be valid
0426: */
0427: public Map makeConfirmedMap() {
0428: return new HashMap();
0429: }
0430:
0431: /**
0432: * Creates a new Map Entry that is independent of the first and the map.
0433: */
0434: public Map.Entry cloneMapEntry(Map.Entry entry) {
0435: HashMap map = new HashMap();
0436: map.put(entry.getKey(), entry.getValue());
0437: return (Map.Entry) map.entrySet().iterator().next();
0438: }
0439:
0440: /**
0441: * Gets the compatability version, needed for package access.
0442: */
0443: public String getCompatibilityVersion() {
0444: return super .getCompatibilityVersion();
0445: }
0446:
0447: //-----------------------------------------------------------------------
0448: /**
0449: * Test to ensure the test setup is working properly. This method checks
0450: * to ensure that the getSampleKeys and getSampleValues methods are
0451: * returning results that look appropriate. That is, they both return a
0452: * non-null array of equal length. The keys array must not have any
0453: * duplicate values, and may only contain a (single) null key if
0454: * isNullKeySupported() returns true. The values array must only have a null
0455: * value if useNullValue() is true and may only have duplicate values if
0456: * isAllowDuplicateValues() returns true.
0457: */
0458: public void testSampleMappings() {
0459: Object[] keys = getSampleKeys();
0460: Object[] values = getSampleValues();
0461: Object[] newValues = getNewSampleValues();
0462:
0463: assertTrue("failure in test: Must have keys returned from "
0464: + "getSampleKeys.", keys != null);
0465:
0466: assertTrue("failure in test: Must have values returned from "
0467: + "getSampleValues.", values != null);
0468:
0469: // verify keys and values have equivalent lengths (in case getSampleX are
0470: // overridden)
0471: assertEquals("failure in test: not the same number of sample "
0472: + "keys and values.", keys.length, values.length);
0473:
0474: assertEquals(
0475: "failure in test: not the same number of values and new values.",
0476: values.length, newValues.length);
0477:
0478: // verify there aren't duplicate keys, and check values
0479: for (int i = 0; i < keys.length - 1; i++) {
0480: for (int j = i + 1; j < keys.length; j++) {
0481: assertTrue("failure in test: duplicate null keys.",
0482: (keys[i] != null || keys[j] != null));
0483: assertTrue(
0484: "failure in test: duplicate non-null key.",
0485: (keys[i] == null || keys[j] == null || (!keys[i]
0486: .equals(keys[j]) && !keys[j]
0487: .equals(keys[i]))));
0488: }
0489: assertTrue(
0490: "failure in test: found null key, but isNullKeySupported "
0491: + "is false.", keys[i] != null
0492: || isAllowNullKey());
0493: assertTrue(
0494: "failure in test: found null value, but isNullValueSupported "
0495: + "is false.", values[i] != null
0496: || isAllowNullValue());
0497: assertTrue(
0498: "failure in test: found null new value, but isNullValueSupported "
0499: + "is false.", newValues[i] != null
0500: || isAllowNullValue());
0501: assertTrue(
0502: "failure in test: values should not be the same as new value",
0503: values[i] != newValues[i]
0504: && (values[i] == null || !values[i]
0505: .equals(newValues[i])));
0506: }
0507: }
0508:
0509: // tests begin here. Each test adds a little bit of tested functionality.
0510: // Many methods assume previous methods passed. That is, they do not
0511: // exhaustively recheck things that have already been checked in a previous
0512: // test methods.
0513:
0514: /**
0515: * Test to ensure that makeEmptyMap and makeFull returns a new non-null
0516: * map with each invocation.
0517: */
0518: public void testMakeMap() {
0519: Map em = makeEmptyMap();
0520: assertTrue(
0521: "failure in test: makeEmptyMap must return a non-null map.",
0522: em != null);
0523:
0524: Map em2 = makeEmptyMap();
0525: assertTrue(
0526: "failure in test: makeEmptyMap must return a non-null map.",
0527: em != null);
0528:
0529: assertTrue(
0530: "failure in test: makeEmptyMap must return a new map "
0531: + "with each invocation.", em != em2);
0532:
0533: Map fm = makeFullMap();
0534: assertTrue(
0535: "failure in test: makeFullMap must return a non-null map.",
0536: fm != null);
0537:
0538: Map fm2 = makeFullMap();
0539: assertTrue(
0540: "failure in test: makeFullMap must return a non-null map.",
0541: fm != null);
0542:
0543: assertTrue(
0544: "failure in test: makeFullMap must return a new map "
0545: + "with each invocation.", fm != fm2);
0546: }
0547:
0548: /**
0549: * Tests Map.isEmpty()
0550: */
0551: public void testMapIsEmpty() {
0552: resetEmpty();
0553: assertEquals(
0554: "Map.isEmpty() should return true with an empty map",
0555: true, map.isEmpty());
0556: verify();
0557:
0558: resetFull();
0559: assertEquals(
0560: "Map.isEmpty() should return false with a non-empty map",
0561: false, map.isEmpty());
0562: verify();
0563: }
0564:
0565: /**
0566: * Tests Map.size()
0567: */
0568: public void testMapSize() {
0569: resetEmpty();
0570: assertEquals("Map.size() should be 0 with an empty map", 0, map
0571: .size());
0572: verify();
0573:
0574: resetFull();
0575: assertEquals("Map.size() should equal the number of entries "
0576: + "in the map", getSampleKeys().length, map.size());
0577: verify();
0578: }
0579:
0580: /**
0581: * Tests {@link Map#clear()}. If the map {@link #isRemoveSupported()}
0582: * can add and remove elements}, then {@link Map#size()} and
0583: * {@link Map#isEmpty()} are used to ensure that map has no elements after
0584: * a call to clear. If the map does not support adding and removing
0585: * elements, this method checks to ensure clear throws an
0586: * UnsupportedOperationException.
0587: */
0588: public void testMapClear() {
0589: if (!isRemoveSupported()) {
0590: try {
0591: resetFull();
0592: map.clear();
0593: fail("Expected UnsupportedOperationException on clear");
0594: } catch (UnsupportedOperationException ex) {
0595: }
0596: return;
0597: }
0598:
0599: resetEmpty();
0600: map.clear();
0601: confirmed.clear();
0602: verify();
0603:
0604: resetFull();
0605: map.clear();
0606: confirmed.clear();
0607: verify();
0608: }
0609:
0610: /**
0611: * Tests Map.containsKey(Object) by verifying it returns false for all
0612: * sample keys on a map created using an empty map and returns true for
0613: * all sample keys returned on a full map.
0614: */
0615: public void testMapContainsKey() {
0616: Object[] keys = getSampleKeys();
0617:
0618: resetEmpty();
0619: for (int i = 0; i < keys.length; i++) {
0620: assertTrue("Map must not contain key when map is empty",
0621: !map.containsKey(keys[i]));
0622: }
0623: verify();
0624:
0625: resetFull();
0626: for (int i = 0; i < keys.length; i++) {
0627: assertTrue(
0628: "Map must contain key for a mapping in the map. "
0629: + "Missing: " + keys[i], map
0630: .containsKey(keys[i]));
0631: }
0632: verify();
0633: }
0634:
0635: /**
0636: * Tests Map.containsValue(Object) by verifying it returns false for all
0637: * sample values on an empty map and returns true for all sample values on
0638: * a full map.
0639: */
0640: public void testMapContainsValue() {
0641: Object[] values = getSampleValues();
0642:
0643: resetEmpty();
0644: for (int i = 0; i < values.length; i++) {
0645: assertTrue("Empty map must not contain value", !map
0646: .containsValue(values[i]));
0647: }
0648: verify();
0649:
0650: resetFull();
0651: for (int i = 0; i < values.length; i++) {
0652: assertTrue(
0653: "Map must contain value for a mapping in the map.",
0654: map.containsValue(values[i]));
0655: }
0656: verify();
0657: }
0658:
0659: /**
0660: * Tests Map.equals(Object)
0661: */
0662: public void testMapEquals() {
0663: resetEmpty();
0664: assertTrue("Empty maps unequal.", map.equals(confirmed));
0665: verify();
0666:
0667: resetFull();
0668: assertTrue("Full maps unequal.", map.equals(confirmed));
0669: verify();
0670:
0671: resetFull();
0672: // modify the HashMap created from the full map and make sure this
0673: // change results in map.equals() to return false.
0674: Iterator iter = confirmed.keySet().iterator();
0675: iter.next();
0676: iter.remove();
0677: assertTrue("Different maps equal.", !map.equals(confirmed));
0678:
0679: resetFull();
0680: assertTrue("equals(null) returned true.", !map.equals(null));
0681: assertTrue("equals(new Object()) returned true.", !map
0682: .equals(new Object()));
0683: verify();
0684: }
0685:
0686: /**
0687: * Tests Map.get(Object)
0688: */
0689: public void testMapGet() {
0690: resetEmpty();
0691:
0692: Object[] keys = getSampleKeys();
0693: Object[] values = getSampleValues();
0694:
0695: for (int i = 0; i < keys.length; i++) {
0696: assertTrue("Empty map.get() should return null.", map
0697: .get(keys[i]) == null);
0698: }
0699: verify();
0700:
0701: resetFull();
0702: for (int i = 0; i < keys.length; i++) {
0703: assertEquals(
0704: "Full map.get() should return value from mapping.",
0705: values[i], map.get(keys[i]));
0706: }
0707: }
0708:
0709: /**
0710: * Tests Map.hashCode()
0711: */
0712: public void testMapHashCode() {
0713: resetEmpty();
0714: assertTrue("Empty maps have different hashCodes.", map
0715: .hashCode() == confirmed.hashCode());
0716:
0717: resetFull();
0718: assertTrue("Equal maps have different hashCodes.", map
0719: .hashCode() == confirmed.hashCode());
0720: }
0721:
0722: /**
0723: * Tests Map.toString(). Since the format of the string returned by the
0724: * toString() method is not defined in the Map interface, there is no
0725: * common way to test the results of the toString() method. Thereforce,
0726: * it is encouraged that Map implementations override this test with one
0727: * that checks the format matches any format defined in its API. This
0728: * default implementation just verifies that the toString() method does
0729: * not return null.
0730: */
0731: public void testMapToString() {
0732: resetEmpty();
0733: assertTrue("Empty map toString() should not return null", map
0734: .toString() != null);
0735: verify();
0736:
0737: resetFull();
0738: assertTrue("Empty map toString() should not return null", map
0739: .toString() != null);
0740: verify();
0741: }
0742:
0743: /**
0744: * Compare the current serialized form of the Map
0745: * against the canonical version in CVS.
0746: */
0747: public void testEmptyMapCompatibility() throws Exception {
0748: /**
0749: * Create canonical objects with this code
0750: Map map = makeEmptyMap();
0751: if (!(map instanceof Serializable)) return;
0752:
0753: writeExternalFormToDisk((Serializable) map, getCanonicalEmptyCollectionName(map));
0754: */
0755:
0756: // test to make sure the canonical form has been preserved
0757: Map map = makeEmptyMap();
0758: if (map instanceof Serializable
0759: && !skipSerializedCanonicalTests()
0760: && isTestSerialization()) {
0761: Map map2 = (Map) readExternalFormFromDisk(getCanonicalEmptyCollectionName(map));
0762: assertEquals("Map is empty", 0, map2.size());
0763: }
0764: }
0765:
0766: /**
0767: * Compare the current serialized form of the Map
0768: * against the canonical version in CVS.
0769: */
0770: public void testFullMapCompatibility() throws Exception {
0771: /**
0772: * Create canonical objects with this code
0773: Map map = makeFullMap();
0774: if (!(map instanceof Serializable)) return;
0775:
0776: writeExternalFormToDisk((Serializable) map, getCanonicalFullCollectionName(map));
0777: */
0778:
0779: // test to make sure the canonical form has been preserved
0780: Map map = makeFullMap();
0781: if (map instanceof Serializable
0782: && !skipSerializedCanonicalTests()
0783: && isTestSerialization()) {
0784: Map map2 = (Map) readExternalFormFromDisk(getCanonicalFullCollectionName(map));
0785: assertEquals("Map is the right size",
0786: getSampleKeys().length, map2.size());
0787: }
0788: }
0789:
0790: /**
0791: * Tests Map.put(Object, Object)
0792: */
0793: public void testMapPut() {
0794: resetEmpty();
0795: Object[] keys = getSampleKeys();
0796: Object[] values = getSampleValues();
0797: Object[] newValues = getNewSampleValues();
0798:
0799: if (isPutAddSupported()) {
0800: for (int i = 0; i < keys.length; i++) {
0801: Object o = map.put(keys[i], values[i]);
0802: confirmed.put(keys[i], values[i]);
0803: verify();
0804: assertTrue("First map.put should return null",
0805: o == null);
0806: assertTrue("Map should contain key after put", map
0807: .containsKey(keys[i]));
0808: assertTrue("Map should contain value after put", map
0809: .containsValue(values[i]));
0810: }
0811: if (isPutChangeSupported()) {
0812: for (int i = 0; i < keys.length; i++) {
0813: Object o = map.put(keys[i], newValues[i]);
0814: confirmed.put(keys[i], newValues[i]);
0815: verify();
0816: assertEquals(
0817: "Map.put should return previous value when changed",
0818: values[i], o);
0819: assertTrue(
0820: "Map should still contain key after put when changed",
0821: map.containsKey(keys[i]));
0822: assertTrue(
0823: "Map should contain new value after put when changed",
0824: map.containsValue(newValues[i]));
0825:
0826: // if duplicates are allowed, we're not guaranteed that the value
0827: // no longer exists, so don't try checking that.
0828: if (!isAllowDuplicateValues()) {
0829: assertTrue(
0830: "Map should not contain old value after put when changed",
0831: !map.containsValue(values[i]));
0832: }
0833: }
0834: } else {
0835: try {
0836: // two possible exception here, either valid
0837: map.put(keys[0], newValues[0]);
0838: fail("Expected IllegalArgumentException or UnsupportedOperationException on put (change)");
0839: } catch (IllegalArgumentException ex) {
0840: } catch (UnsupportedOperationException ex) {
0841: }
0842: }
0843:
0844: } else if (isPutChangeSupported()) {
0845: resetEmpty();
0846: try {
0847: map.put(keys[0], values[0]);
0848: fail("Expected UnsupportedOperationException or IllegalArgumentException on put (add) when fixed size");
0849: } catch (IllegalArgumentException ex) {
0850: } catch (UnsupportedOperationException ex) {
0851: }
0852:
0853: resetFull();
0854: int i = 0;
0855: for (Iterator it = map.keySet().iterator(); it.hasNext()
0856: && i < newValues.length; i++) {
0857: Object key = it.next();
0858: Object o = map.put(key, newValues[i]);
0859: Object value = confirmed.put(key, newValues[i]);
0860: verify();
0861: assertEquals(
0862: "Map.put should return previous value when changed",
0863: value, o);
0864: assertTrue(
0865: "Map should still contain key after put when changed",
0866: map.containsKey(key));
0867: assertTrue(
0868: "Map should contain new value after put when changed",
0869: map.containsValue(newValues[i]));
0870:
0871: // if duplicates are allowed, we're not guaranteed that the value
0872: // no longer exists, so don't try checking that.
0873: if (!isAllowDuplicateValues()) {
0874: assertTrue(
0875: "Map should not contain old value after put when changed",
0876: !map.containsValue(values[i]));
0877: }
0878: }
0879: } else {
0880: try {
0881: map.put(keys[0], values[0]);
0882: fail("Expected UnsupportedOperationException on put (add)");
0883: } catch (UnsupportedOperationException ex) {
0884: }
0885: }
0886: }
0887:
0888: /**
0889: * Tests Map.put(null, value)
0890: */
0891: public void testMapPutNullKey() {
0892: resetFull();
0893: Object[] values = getSampleValues();
0894:
0895: if (isPutAddSupported()) {
0896: if (isAllowNullKey()) {
0897: map.put(null, values[0]);
0898: } else {
0899: try {
0900: map.put(null, values[0]);
0901: fail("put(null, value) should throw NPE/IAE");
0902: } catch (NullPointerException ex) {
0903: } catch (IllegalArgumentException ex) {
0904: }
0905: }
0906: }
0907: }
0908:
0909: /**
0910: * Tests Map.put(null, value)
0911: */
0912: public void testMapPutNullValue() {
0913: resetFull();
0914: Object[] keys = getSampleKeys();
0915:
0916: if (isPutAddSupported()) {
0917: if (isAllowNullValue()) {
0918: map.put(keys[0], null);
0919: } else {
0920: try {
0921: map.put(keys[0], null);
0922: fail("put(key, null) should throw NPE/IAE");
0923: } catch (NullPointerException ex) {
0924: } catch (IllegalArgumentException ex) {
0925: }
0926: }
0927: }
0928: }
0929:
0930: /**
0931: * Tests Map.putAll(map)
0932: */
0933: public void testMapPutAll() {
0934: if (!isPutAddSupported()) {
0935: if (!isPutChangeSupported()) {
0936: Map temp = makeFullMap();
0937: resetEmpty();
0938: try {
0939: map.putAll(temp);
0940: fail("Expected UnsupportedOperationException on putAll");
0941: } catch (UnsupportedOperationException ex) {
0942: }
0943: }
0944: return;
0945: }
0946:
0947: // check putAll OK adding empty map to empty map
0948: resetEmpty();
0949: assertEquals(0, map.size());
0950: map.putAll(new HashMap());
0951: assertEquals(0, map.size());
0952:
0953: // check putAll OK adding empty map to non-empty map
0954: resetFull();
0955: int size = map.size();
0956: map.putAll(new HashMap());
0957: assertEquals(size, map.size());
0958:
0959: // check putAll OK adding non-empty map to empty map
0960: resetEmpty();
0961: Map m2 = makeFullMap();
0962: map.putAll(m2);
0963: confirmed.putAll(m2);
0964: verify();
0965:
0966: // check putAll OK adding non-empty JDK map to empty map
0967: resetEmpty();
0968: m2 = makeConfirmedMap();
0969: Object[] keys = getSampleKeys();
0970: Object[] values = getSampleValues();
0971: for (int i = 0; i < keys.length; i++) {
0972: m2.put(keys[i], values[i]);
0973: }
0974: map.putAll(m2);
0975: confirmed.putAll(m2);
0976: verify();
0977:
0978: // check putAll OK adding non-empty JDK map to non-empty map
0979: resetEmpty();
0980: m2 = makeConfirmedMap();
0981: map.put(keys[0], values[0]);
0982: confirmed.put(keys[0], values[0]);
0983: verify();
0984: for (int i = 1; i < keys.length; i++) {
0985: m2.put(keys[i], values[i]);
0986: }
0987: map.putAll(m2);
0988: confirmed.putAll(m2);
0989: verify();
0990: }
0991:
0992: /**
0993: * Tests Map.remove(Object)
0994: */
0995: public void testMapRemove() {
0996: if (!isRemoveSupported()) {
0997: try {
0998: resetFull();
0999: map.remove(map.keySet().iterator().next());
1000: fail("Expected UnsupportedOperationException on remove");
1001: } catch (UnsupportedOperationException ex) {
1002: }
1003: return;
1004: }
1005:
1006: resetEmpty();
1007:
1008: Object[] keys = getSampleKeys();
1009: Object[] values = getSampleValues();
1010: for (int i = 0; i < keys.length; i++) {
1011: Object o = map.remove(keys[i]);
1012: assertTrue("First map.remove should return null", o == null);
1013: }
1014: verify();
1015:
1016: resetFull();
1017:
1018: for (int i = 0; i < keys.length; i++) {
1019: Object o = map.remove(keys[i]);
1020: confirmed.remove(keys[i]);
1021: verify();
1022:
1023: assertEquals(
1024: "map.remove with valid key should return value",
1025: values[i], o);
1026: }
1027:
1028: Object[] other = getOtherKeys();
1029:
1030: resetFull();
1031: int size = map.size();
1032: for (int i = 0; i < other.length; i++) {
1033: Object o = map.remove(other[i]);
1034: assertEquals(
1035: "map.remove for nonexistent key should return null",
1036: o, null);
1037: assertEquals("map.remove for nonexistent key should not "
1038: + "shrink map", size, map.size());
1039: }
1040: verify();
1041: }
1042:
1043: //-----------------------------------------------------------------------
1044: /**
1045: * Tests that the {@link Map#values} collection is backed by
1046: * the underlying map for clear().
1047: */
1048: public void testValuesClearChangesMap() {
1049: if (!isRemoveSupported())
1050: return;
1051:
1052: // clear values, reflected in map
1053: resetFull();
1054: Collection values = map.values();
1055: assertTrue(map.size() > 0);
1056: assertTrue(values.size() > 0);
1057: values.clear();
1058: assertTrue(map.size() == 0);
1059: assertTrue(values.size() == 0);
1060:
1061: // clear map, reflected in values
1062: resetFull();
1063: values = map.values();
1064: assertTrue(map.size() > 0);
1065: assertTrue(values.size() > 0);
1066: map.clear();
1067: assertTrue(map.size() == 0);
1068: assertTrue(values.size() == 0);
1069: }
1070:
1071: /**
1072: * Tests that the {@link Map#keySet} collection is backed by
1073: * the underlying map for clear().
1074: */
1075: public void testKeySetClearChangesMap() {
1076: if (!isRemoveSupported())
1077: return;
1078:
1079: // clear values, reflected in map
1080: resetFull();
1081: Set keySet = map.keySet();
1082: assertTrue(map.size() > 0);
1083: assertTrue(keySet.size() > 0);
1084: keySet.clear();
1085: assertTrue(map.size() == 0);
1086: assertTrue(keySet.size() == 0);
1087:
1088: // clear map, reflected in values
1089: resetFull();
1090: keySet = map.keySet();
1091: assertTrue(map.size() > 0);
1092: assertTrue(keySet.size() > 0);
1093: map.clear();
1094: assertTrue(map.size() == 0);
1095: assertTrue(keySet.size() == 0);
1096: }
1097:
1098: /**
1099: * Tests that the {@link Map#entrySet()} collection is backed by
1100: * the underlying map for clear().
1101: */
1102: public void testEntrySetClearChangesMap() {
1103: if (!isRemoveSupported())
1104: return;
1105:
1106: // clear values, reflected in map
1107: resetFull();
1108: Set entrySet = map.entrySet();
1109: assertTrue(map.size() > 0);
1110: assertTrue(entrySet.size() > 0);
1111: entrySet.clear();
1112: assertTrue(map.size() == 0);
1113: assertTrue(entrySet.size() == 0);
1114:
1115: // clear map, reflected in values
1116: resetFull();
1117: entrySet = map.entrySet();
1118: assertTrue(map.size() > 0);
1119: assertTrue(entrySet.size() > 0);
1120: map.clear();
1121: assertTrue(map.size() == 0);
1122: assertTrue(entrySet.size() == 0);
1123: }
1124:
1125: //-----------------------------------------------------------------------
1126: public void testEntrySetContains1() {
1127: resetFull();
1128: Set entrySet = map.entrySet();
1129: Map.Entry entry = (Map.Entry) entrySet.iterator().next();
1130: assertEquals(true, entrySet.contains(entry));
1131: }
1132:
1133: public void testEntrySetContains2() {
1134: resetFull();
1135: Set entrySet = map.entrySet();
1136: Map.Entry entry = (Map.Entry) entrySet.iterator().next();
1137: Map.Entry test = cloneMapEntry(entry);
1138: assertEquals(true, entrySet.contains(test));
1139: }
1140:
1141: public void testEntrySetContains3() {
1142: resetFull();
1143: Set entrySet = map.entrySet();
1144: Map.Entry entry = (Map.Entry) entrySet.iterator().next();
1145: HashMap temp = new HashMap();
1146: temp.put(entry.getKey(), "A VERY DIFFERENT VALUE");
1147: Map.Entry test = (Map.Entry) temp.entrySet().iterator().next();
1148: assertEquals(false, entrySet.contains(test));
1149: }
1150:
1151: public void testEntrySetRemove1() {
1152: if (!isRemoveSupported())
1153: return;
1154: resetFull();
1155: int size = map.size();
1156: Set entrySet = map.entrySet();
1157: Map.Entry entry = (Map.Entry) entrySet.iterator().next();
1158: Object key = entry.getKey();
1159:
1160: assertEquals(true, entrySet.remove(entry));
1161: assertEquals(false, map.containsKey(key));
1162: assertEquals(size - 1, map.size());
1163: }
1164:
1165: public void testEntrySetRemove2() {
1166: if (!isRemoveSupported())
1167: return;
1168: resetFull();
1169: int size = map.size();
1170: Set entrySet = map.entrySet();
1171: Map.Entry entry = (Map.Entry) entrySet.iterator().next();
1172: Object key = entry.getKey();
1173: Map.Entry test = cloneMapEntry(entry);
1174:
1175: assertEquals(true, entrySet.remove(test));
1176: assertEquals(false, map.containsKey(key));
1177: assertEquals(size - 1, map.size());
1178: }
1179:
1180: public void testEntrySetRemove3() {
1181: if (!isRemoveSupported())
1182: return;
1183: resetFull();
1184: int size = map.size();
1185: Set entrySet = map.entrySet();
1186: Map.Entry entry = (Map.Entry) entrySet.iterator().next();
1187: Object key = entry.getKey();
1188: HashMap temp = new HashMap();
1189: temp.put(entry.getKey(), "A VERY DIFFERENT VALUE");
1190: Map.Entry test = (Map.Entry) temp.entrySet().iterator().next();
1191:
1192: assertEquals(false, entrySet.remove(test));
1193: assertEquals(true, map.containsKey(key));
1194: assertEquals(size, map.size());
1195: }
1196:
1197: //-----------------------------------------------------------------------
1198: /**
1199: * Tests that the {@link Map#values} collection is backed by
1200: * the underlying map by removing from the values collection
1201: * and testing if the value was removed from the map.
1202: * <p>
1203: * We should really test the "vice versa" case--that values removed
1204: * from the map are removed from the values collection--also,
1205: * but that's a more difficult test to construct (lacking a
1206: * "removeValue" method.)
1207: * </p>
1208: * <p>
1209: * See bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=9573">
1210: * 9573</a>.
1211: * </p>
1212: */
1213: public void testValuesRemoveChangesMap() {
1214: resetFull();
1215: Object[] sampleValues = getSampleValues();
1216: Collection values = map.values();
1217: for (int i = 0; i < sampleValues.length; i++) {
1218: if (map.containsValue(sampleValues[i])) {
1219: int j = 0; // loop counter prevents infinite loops when remove is broken
1220: while (values.contains(sampleValues[i]) && j < 10000) {
1221: try {
1222: values.remove(sampleValues[i]);
1223: } catch (UnsupportedOperationException e) {
1224: // if values.remove is unsupported, just skip this test
1225: return;
1226: }
1227: j++;
1228: }
1229: assertTrue("values().remove(obj) is broken", j < 10000);
1230: assertTrue(
1231: "Value should have been removed from the underlying map.",
1232: !map.containsValue(sampleValues[i]));
1233: }
1234: }
1235: }
1236:
1237: /**
1238: * Tests that the {@link Map#keySet} set is backed by
1239: * the underlying map by removing from the keySet set
1240: * and testing if the key was removed from the map.
1241: */
1242: public void testKeySetRemoveChangesMap() {
1243: resetFull();
1244: Object[] sampleKeys = getSampleKeys();
1245: Set keys = map.keySet();
1246: for (int i = 0; i < sampleKeys.length; i++) {
1247: try {
1248: keys.remove(sampleKeys[i]);
1249: } catch (UnsupportedOperationException e) {
1250: // if key.remove is unsupported, just skip this test
1251: return;
1252: }
1253: assertTrue(
1254: "Key should have been removed from the underlying map.",
1255: !map.containsKey(sampleKeys[i]));
1256: }
1257: }
1258:
1259: // TODO: Need:
1260: // testValuesRemovedFromEntrySetAreRemovedFromMap
1261: // same for EntrySet/KeySet/values's
1262: // Iterator.remove, removeAll, retainAll
1263:
1264: /**
1265: * Utility methods to create an array of Map.Entry objects
1266: * out of the given key and value arrays.<P>
1267: *
1268: * @param keys the array of keys
1269: * @param values the array of values
1270: * @return an array of Map.Entry of those keys to those values
1271: */
1272: private Map.Entry[] makeEntryArray(Object[] keys, Object[] values) {
1273: Map.Entry[] result = new Map.Entry[keys.length];
1274: for (int i = 0; i < keys.length; i++) {
1275: Map map = makeConfirmedMap();
1276: map.put(keys[i], values[i]);
1277: result[i] = (Map.Entry) map.entrySet().iterator().next();
1278: }
1279: return result;
1280: }
1281:
1282: /**
1283: * Bulk test {@link Map#entrySet()}. This method runs through all of
1284: * the tests in {@link AbstractTestSet}.
1285: * After modification operations, {@link #verify()} is invoked to ensure
1286: * that the map and the other collection views are still valid.
1287: *
1288: * @return a {@link AbstractTestSet} instance for testing the map's entry set
1289: */
1290: public BulkTest bulkTestMapEntrySet() {
1291: return new TestMapEntrySet();
1292: }
1293:
1294: public class TestMapEntrySet extends AbstractTestSet {
1295: public TestMapEntrySet() {
1296: super ("MapEntrySet");
1297: }
1298:
1299: // Have to implement manually; entrySet doesn't support addAll
1300: public Object[] getFullElements() {
1301: Object[] k = getSampleKeys();
1302: Object[] v = getSampleValues();
1303: return makeEntryArray(k, v);
1304: }
1305:
1306: // Have to implement manually; entrySet doesn't support addAll
1307: public Object[] getOtherElements() {
1308: Object[] k = getOtherKeys();
1309: Object[] v = getOtherValues();
1310: return makeEntryArray(k, v);
1311: }
1312:
1313: public Set makeEmptySet() {
1314: return makeEmptyMap().entrySet();
1315: }
1316:
1317: public Set makeFullSet() {
1318: return makeFullMap().entrySet();
1319: }
1320:
1321: public boolean isAddSupported() {
1322: // Collection views don't support add operations.
1323: return false;
1324: }
1325:
1326: public boolean isRemoveSupported() {
1327: // Entry set should only support remove if map does
1328: return AbstractTestMap.this .isRemoveSupported();
1329: }
1330:
1331: public boolean isGetStructuralModify() {
1332: return AbstractTestMap.this .isGetStructuralModify();
1333: }
1334:
1335: public boolean isTestSerialization() {
1336: return false;
1337: }
1338:
1339: public void resetFull() {
1340: AbstractTestMap.this .resetFull();
1341: collection = map.entrySet();
1342: TestMapEntrySet.this .confirmed = AbstractTestMap.this .confirmed
1343: .entrySet();
1344: }
1345:
1346: public void resetEmpty() {
1347: AbstractTestMap.this .resetEmpty();
1348: collection = map.entrySet();
1349: TestMapEntrySet.this .confirmed = AbstractTestMap.this .confirmed
1350: .entrySet();
1351: }
1352:
1353: public void testMapEntrySetIteratorEntry() {
1354: resetFull();
1355: Iterator it = collection.iterator();
1356: int count = 0;
1357: while (it.hasNext()) {
1358: Map.Entry entry = (Map.Entry) it.next();
1359: assertEquals(true, AbstractTestMap.this .map
1360: .containsKey(entry.getKey()));
1361: assertEquals(true, AbstractTestMap.this .map
1362: .containsValue(entry.getValue()));
1363: if (isGetStructuralModify() == false) {
1364: assertEquals(AbstractTestMap.this .map.get(entry
1365: .getKey()), entry.getValue());
1366: }
1367: count++;
1368: }
1369: assertEquals(collection.size(), count);
1370: }
1371:
1372: public void testMapEntrySetIteratorEntrySetValue() {
1373: Object key1 = getSampleKeys()[0];
1374: Object key2 = (getSampleKeys().length == 1 ? getSampleKeys()[0]
1375: : getSampleKeys()[1]);
1376: Object newValue1 = getNewSampleValues()[0];
1377: Object newValue2 = (getNewSampleValues().length == 1 ? getNewSampleValues()[0]
1378: : getNewSampleValues()[1]);
1379:
1380: resetFull();
1381: // explicitly get entries as sample values/keys are connected for some maps
1382: // such as BeanMap
1383: Iterator it = TestMapEntrySet.this .collection.iterator();
1384: Map.Entry entry1 = getEntry(it, key1);
1385: it = TestMapEntrySet.this .collection.iterator();
1386: Map.Entry entry2 = getEntry(it, key2);
1387: Iterator itConfirmed = TestMapEntrySet.this .confirmed
1388: .iterator();
1389: Map.Entry entryConfirmed1 = getEntry(itConfirmed, key1);
1390: itConfirmed = TestMapEntrySet.this .confirmed.iterator();
1391: Map.Entry entryConfirmed2 = getEntry(itConfirmed, key2);
1392: verify();
1393:
1394: if (isSetValueSupported() == false) {
1395: try {
1396: entry1.setValue(newValue1);
1397: } catch (UnsupportedOperationException ex) {
1398: }
1399: return;
1400: }
1401:
1402: entry1.setValue(newValue1);
1403: entryConfirmed1.setValue(newValue1);
1404: assertEquals(newValue1, entry1.getValue());
1405: assertEquals(true, AbstractTestMap.this .map
1406: .containsKey(entry1.getKey()));
1407: assertEquals(true, AbstractTestMap.this .map
1408: .containsValue(newValue1));
1409: assertEquals(newValue1, AbstractTestMap.this .map.get(entry1
1410: .getKey()));
1411: verify();
1412:
1413: entry1.setValue(newValue1);
1414: entryConfirmed1.setValue(newValue1);
1415: assertEquals(newValue1, entry1.getValue());
1416: assertEquals(true, AbstractTestMap.this .map
1417: .containsKey(entry1.getKey()));
1418: assertEquals(true, AbstractTestMap.this .map
1419: .containsValue(newValue1));
1420: assertEquals(newValue1, AbstractTestMap.this .map.get(entry1
1421: .getKey()));
1422: verify();
1423:
1424: entry2.setValue(newValue2);
1425: entryConfirmed2.setValue(newValue2);
1426: assertEquals(newValue2, entry2.getValue());
1427: assertEquals(true, AbstractTestMap.this .map
1428: .containsKey(entry2.getKey()));
1429: assertEquals(true, AbstractTestMap.this .map
1430: .containsValue(newValue2));
1431: assertEquals(newValue2, AbstractTestMap.this .map.get(entry2
1432: .getKey()));
1433: verify();
1434: }
1435:
1436: public Map.Entry getEntry(Iterator itConfirmed, Object key) {
1437: Map.Entry entry = null;
1438: while (itConfirmed.hasNext()) {
1439: Map.Entry temp = (Map.Entry) itConfirmed.next();
1440: if (temp.getKey() == null) {
1441: if (key == null) {
1442: entry = temp;
1443: break;
1444: }
1445: } else if (temp.getKey().equals(key)) {
1446: entry = temp;
1447: break;
1448: }
1449: }
1450: assertNotNull("No matching entry in map for key '" + key
1451: + "'", entry);
1452: return entry;
1453: }
1454:
1455: public void testMapEntrySetRemoveNonMapEntry() {
1456: if (isRemoveSupported() == false)
1457: return;
1458: resetFull();
1459: assertEquals(false, getSet().remove(null));
1460: assertEquals(false, getSet().remove(new Object()));
1461: }
1462:
1463: public void verify() {
1464: super .verify();
1465: AbstractTestMap.this .verify();
1466: }
1467: }
1468:
1469: /**
1470: * Bulk test {@link Map#keySet()}. This method runs through all of
1471: * the tests in {@link AbstractTestSet}.
1472: * After modification operations, {@link #verify()} is invoked to ensure
1473: * that the map and the other collection views are still valid.
1474: *
1475: * @return a {@link AbstractTestSet} instance for testing the map's key set
1476: */
1477: public BulkTest bulkTestMapKeySet() {
1478: return new TestMapKeySet();
1479: }
1480:
1481: public class TestMapKeySet extends AbstractTestSet {
1482: public TestMapKeySet() {
1483: super ("");
1484: }
1485:
1486: public Object[] getFullElements() {
1487: return getSampleKeys();
1488: }
1489:
1490: public Object[] getOtherElements() {
1491: return getOtherKeys();
1492: }
1493:
1494: public Set makeEmptySet() {
1495: return makeEmptyMap().keySet();
1496: }
1497:
1498: public Set makeFullSet() {
1499: return makeFullMap().keySet();
1500: }
1501:
1502: public boolean isNullSupported() {
1503: return AbstractTestMap.this .isAllowNullKey();
1504: }
1505:
1506: public boolean isAddSupported() {
1507: return false;
1508: }
1509:
1510: public boolean isRemoveSupported() {
1511: return AbstractTestMap.this .isRemoveSupported();
1512: }
1513:
1514: public boolean isTestSerialization() {
1515: return false;
1516: }
1517:
1518: public void resetEmpty() {
1519: AbstractTestMap.this .resetEmpty();
1520: collection = map.keySet();
1521: TestMapKeySet.this .confirmed = AbstractTestMap.this .confirmed
1522: .keySet();
1523: }
1524:
1525: public void resetFull() {
1526: AbstractTestMap.this .resetFull();
1527: collection = map.keySet();
1528: TestMapKeySet.this .confirmed = AbstractTestMap.this .confirmed
1529: .keySet();
1530: }
1531:
1532: public void verify() {
1533: super .verify();
1534: AbstractTestMap.this .verify();
1535: }
1536: }
1537:
1538: /**
1539: * Bulk test {@link Map#values()}. This method runs through all of
1540: * the tests in {@link AbstractTestCollection}.
1541: * After modification operations, {@link #verify()} is invoked to ensure
1542: * that the map and the other collection views are still valid.
1543: *
1544: * @return a {@link AbstractTestCollection} instance for testing the map's
1545: * values collection
1546: */
1547: public BulkTest bulkTestMapValues() {
1548: return new TestMapValues();
1549: }
1550:
1551: public class TestMapValues extends AbstractTestCollection {
1552: public TestMapValues() {
1553: super ("");
1554: }
1555:
1556: public Object[] getFullElements() {
1557: return getSampleValues();
1558: }
1559:
1560: public Object[] getOtherElements() {
1561: return getOtherValues();
1562: }
1563:
1564: public Collection makeCollection() {
1565: return makeEmptyMap().values();
1566: }
1567:
1568: public Collection makeFullCollection() {
1569: return makeFullMap().values();
1570: }
1571:
1572: public boolean isNullSupported() {
1573: return AbstractTestMap.this .isAllowNullKey();
1574: }
1575:
1576: public boolean isAddSupported() {
1577: return false;
1578: }
1579:
1580: public boolean isRemoveSupported() {
1581: return AbstractTestMap.this .isRemoveSupported();
1582: }
1583:
1584: public boolean isTestSerialization() {
1585: return false;
1586: }
1587:
1588: public boolean areEqualElementsDistinguishable() {
1589: // equal values are associated with different keys, so they are
1590: // distinguishable.
1591: return true;
1592: }
1593:
1594: public Collection makeConfirmedCollection() {
1595: // never gets called, reset methods are overridden
1596: return null;
1597: }
1598:
1599: public Collection makeConfirmedFullCollection() {
1600: // never gets called, reset methods are overridden
1601: return null;
1602: }
1603:
1604: public void resetFull() {
1605: AbstractTestMap.this .resetFull();
1606: collection = map.values();
1607: TestMapValues.this .confirmed = AbstractTestMap.this .confirmed
1608: .values();
1609: }
1610:
1611: public void resetEmpty() {
1612: AbstractTestMap.this .resetEmpty();
1613: collection = map.values();
1614: TestMapValues.this .confirmed = AbstractTestMap.this .confirmed
1615: .values();
1616: }
1617:
1618: public void verify() {
1619: super .verify();
1620: AbstractTestMap.this .verify();
1621: }
1622:
1623: // TODO: should test that a remove on the values collection view
1624: // removes the proper mapping and not just any mapping that may have
1625: // the value equal to the value returned from the values iterator.
1626: }
1627:
1628: /**
1629: * Resets the {@link #map}, {@link #entrySet}, {@link #keySet},
1630: * {@link #values} and {@link #confirmed} fields to empty.
1631: */
1632: public void resetEmpty() {
1633: this .map = makeEmptyMap();
1634: views();
1635: this .confirmed = makeConfirmedMap();
1636: }
1637:
1638: /**
1639: * Resets the {@link #map}, {@link #entrySet}, {@link #keySet},
1640: * {@link #values} and {@link #confirmed} fields to full.
1641: */
1642: public void resetFull() {
1643: this .map = makeFullMap();
1644: views();
1645: this .confirmed = makeConfirmedMap();
1646: Object[] k = getSampleKeys();
1647: Object[] v = getSampleValues();
1648: for (int i = 0; i < k.length; i++) {
1649: confirmed.put(k[i], v[i]);
1650: }
1651: }
1652:
1653: /**
1654: * Resets the collection view fields.
1655: */
1656: private void views() {
1657: this .keySet = map.keySet();
1658: this .values = map.values();
1659: this .entrySet = map.entrySet();
1660: }
1661:
1662: /**
1663: * Verifies that {@link #map} is still equal to {@link #confirmed}.
1664: * This method checks that the map is equal to the HashMap,
1665: * <I>and</I> that the map's collection views are still equal to
1666: * the HashMap's collection views. An <Code>equals</Code> test
1667: * is done on the maps and their collection views; their size and
1668: * <Code>isEmpty</Code> results are compared; their hashCodes are
1669: * compared; and <Code>containsAll</Code> tests are run on the
1670: * collection views.
1671: */
1672: public void verify() {
1673: verifyMap();
1674: verifyEntrySet();
1675: verifyKeySet();
1676: verifyValues();
1677: }
1678:
1679: public void verifyMap() {
1680: int size = confirmed.size();
1681: boolean empty = confirmed.isEmpty();
1682: assertEquals("Map should be same size as HashMap", size, map
1683: .size());
1684: assertEquals("Map should be empty if HashMap is", empty, map
1685: .isEmpty());
1686: assertEquals("hashCodes should be the same", confirmed
1687: .hashCode(), map.hashCode());
1688: // this fails for LRUMap because confirmed.equals() somehow modifies
1689: // map, causing concurrent modification exceptions.
1690: //assertEquals("Map should still equal HashMap", confirmed, map);
1691: // this works though and performs the same verification:
1692: assertTrue("Map should still equal HashMap", map
1693: .equals(confirmed));
1694: // TODO: this should really be reexamined to figure out why LRU map
1695: // behaves like it does (the equals shouldn't modify since all accesses
1696: // by the confirmed collection should be through an iterator, thus not
1697: // causing LRUMap to change).
1698: }
1699:
1700: public void verifyEntrySet() {
1701: int size = confirmed.size();
1702: boolean empty = confirmed.isEmpty();
1703: assertEquals("entrySet should be same size as HashMap's"
1704: + "\nTest: " + entrySet + "\nReal: "
1705: + confirmed.entrySet(), size, entrySet.size());
1706: assertEquals("entrySet should be empty if HashMap is"
1707: + "\nTest: " + entrySet + "\nReal: "
1708: + confirmed.entrySet(), empty, entrySet.isEmpty());
1709: assertTrue("entrySet should contain all HashMap's elements"
1710: + "\nTest: " + entrySet + "\nReal: "
1711: + confirmed.entrySet(), entrySet.containsAll(confirmed
1712: .entrySet()));
1713: assertEquals("entrySet hashCodes should be the same"
1714: + "\nTest: " + entrySet + "\nReal: "
1715: + confirmed.entrySet(),
1716: confirmed.entrySet().hashCode(), entrySet.hashCode());
1717: assertEquals("Map's entry set should still equal HashMap's",
1718: confirmed.entrySet(), entrySet);
1719: }
1720:
1721: public void verifyKeySet() {
1722: int size = confirmed.size();
1723: boolean empty = confirmed.isEmpty();
1724: assertEquals(
1725: "keySet should be same size as HashMap's" + "\nTest: "
1726: + keySet + "\nReal: " + confirmed.keySet(),
1727: size, keySet.size());
1728: assertEquals(
1729: "keySet should be empty if HashMap is" + "\nTest: "
1730: + keySet + "\nReal: " + confirmed.keySet(),
1731: empty, keySet.isEmpty());
1732: assertTrue(
1733: "keySet should contain all HashMap's elements"
1734: + "\nTest: " + keySet + "\nReal: "
1735: + confirmed.keySet(), keySet
1736: .containsAll(confirmed.keySet()));
1737: assertEquals("keySet hashCodes should be the same" + "\nTest: "
1738: + keySet + "\nReal: " + confirmed.keySet(), confirmed
1739: .keySet().hashCode(), keySet.hashCode());
1740: assertEquals("Map's key set should still equal HashMap's",
1741: confirmed.keySet(), keySet);
1742: }
1743:
1744: public void verifyValues() {
1745: List known = new ArrayList(confirmed.values());
1746: List test = new ArrayList(values);
1747:
1748: int size = confirmed.size();
1749: boolean empty = confirmed.isEmpty();
1750: assertEquals("values should be same size as HashMap's"
1751: + "\nTest: " + test + "\nReal: " + known, size, values
1752: .size());
1753: assertEquals("values should be empty if HashMap is"
1754: + "\nTest: " + test + "\nReal: " + known, empty, values
1755: .isEmpty());
1756: assertTrue("values should contain all HashMap's elements"
1757: + "\nTest: " + test + "\nReal: " + known, test
1758: .containsAll(known));
1759: assertTrue("values should contain all HashMap's elements"
1760: + "\nTest: " + test + "\nReal: " + known, known
1761: .containsAll(test));
1762: // originally coded to use a HashBag, but now separate jar so...
1763: for (Iterator it = known.iterator(); it.hasNext();) {
1764: boolean removed = test.remove(it.next());
1765: assertTrue("Map's values should still equal HashMap's",
1766: removed);
1767: }
1768: assertTrue("Map's values should still equal HashMap's", test
1769: .isEmpty());
1770: }
1771:
1772: /**
1773: * Erases any leftover instance variables by setting them to null.
1774: */
1775: public void tearDown() throws Exception {
1776: map = null;
1777: keySet = null;
1778: entrySet = null;
1779: values = null;
1780: confirmed = null;
1781: }
1782:
1783: }
|