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.collection;
0017:
0018: import java.io.ByteArrayInputStream;
0019: import java.io.ByteArrayOutputStream;
0020: import java.io.ObjectInputStream;
0021: import java.io.ObjectOutputStream;
0022: import java.io.Serializable;
0023: import java.lang.reflect.Array;
0024: import java.util.ArrayList;
0025: import java.util.Arrays;
0026: import java.util.Collection;
0027: import java.util.Collections;
0028: import java.util.ConcurrentModificationException;
0029: import java.util.HashMap;
0030: import java.util.HashSet;
0031: import java.util.Iterator;
0032: import java.util.List;
0033: import java.util.Map;
0034: import java.util.NoSuchElementException;
0035:
0036: import org.apache.commons.collections.AbstractTestObject;
0037:
0038: /**
0039: * Abstract test class for {@link java.util.Collection} methods and contracts.
0040: * <p>
0041: * You should create a concrete subclass of this class to test any custom
0042: * {@link Collection} implementation. At minimum, you'll have to
0043: * implement the {@link #makeCollection()} method. You might want to
0044: * override some of the additional public methods as well:
0045: * <p>
0046: * <b>Element Population Methods</b>
0047: * <p>
0048: * Override these if your collection restricts what kind of elements are
0049: * allowed (for instance, if <code>null</code> is not permitted):
0050: * <ul>
0051: * <li>{@link #getFullElements()}
0052: * <li>{@link #getOtherElements()}
0053: * </ul>
0054: * <p>
0055: * <b>Supported Operation Methods</b>
0056: * <p>
0057: * Override these if your collection doesn't support certain operations:
0058: * <ul>
0059: * <li>{@link #isAddSupported()}
0060: * <li>{@link #isRemoveSupported()}
0061: * <li>{@link #areEqualElementsDistinguishable()}
0062: * <li>{@link #isNullSupported()}
0063: * <li>{@link #isFailFastSupported()}
0064: * </ul>
0065: * <p>
0066: * <b>Fixture Methods</b>
0067: * <p>
0068: * Fixtures are used to verify that the the operation results in correct state
0069: * for the collection. Basically, the operation is performed against your
0070: * collection implementation, and an identical operation is performed against a
0071: * <i>confirmed</i> collection implementation. A confirmed collection
0072: * implementation is something like <code>java.util.ArrayList</code>, which is
0073: * known to conform exactly to its collection interface's contract. After the
0074: * operation takes place on both your collection implementation and the
0075: * confirmed collection implementation, the two collections are compared to see
0076: * if their state is identical. The comparison is usually much more involved
0077: * than a simple <code>equals</code> test. This verification is used to ensure
0078: * proper modifications are made along with ensuring that the collection does
0079: * not change when read-only modifications are made.
0080: * <p>
0081: * The {@link #collection} field holds an instance of your collection
0082: * implementation; the {@link #confirmed} field holds an instance of the
0083: * confirmed collection implementation. The {@link #resetEmpty()} and
0084: * {@link #resetFull()} methods set these fields to empty or full collections,
0085: * so that tests can proceed from a known state.
0086: * <p>
0087: * After a modification operation to both {@link #collection} and
0088: * {@link #confirmed}, the {@link #verify()} method is invoked to compare
0089: * the results. You may want to override {@link #verify()} to perform
0090: * additional verifications. For instance, when testing the collection
0091: * views of a map, {@link AbstractTestMap} would override {@link #verify()} to make
0092: * sure the map is changed after the collection view is changed.
0093: * <p>
0094: * If you're extending this class directly, you will have to provide
0095: * implementations for the following:
0096: * <ul>
0097: * <li>{@link #makeConfirmedCollection()}
0098: * <li>{@link #makeConfirmedFullCollection()}
0099: * </ul>
0100: * <p>
0101: * Those methods should provide a confirmed collection implementation
0102: * that's compatible with your collection implementation.
0103: * <p>
0104: * If you're extending {@link AbstractTestList}, {@link AbstractTestSet},
0105: * or {@link AbstractTestBag}, you probably don't have to worry about the
0106: * above methods, because those three classes already override the methods
0107: * to provide standard JDK confirmed collections.<P>
0108: * <p>
0109: * <b>Other notes</b>
0110: * <p>
0111: * If your {@link Collection} fails one of these tests by design,
0112: * you may still use this base set of cases. Simply override the
0113: * test case (method) your {@link Collection} fails.
0114: *
0115: * @version $Revision: 155406 $ $Date: 2005-02-26 12:55:26 +0000 (Sat, 26 Feb 2005) $
0116: *
0117: * @author Rodney Waldhoff
0118: * @author Paul Jack
0119: * @author Michael A. Smith
0120: * @author Neil O'Toole
0121: * @author Stephen Colebourne
0122: */
0123: public abstract class AbstractTestCollection extends AbstractTestObject {
0124:
0125: //
0126: // NOTE:
0127: //
0128: // Collection doesn't define any semantics for equals, and recommends you
0129: // use reference-based default behavior of Object.equals. (And a test for
0130: // that already exists in AbstractTestObject). Tests for equality of lists, sets
0131: // and bags will have to be written in test subclasses. Thus, there is no
0132: // tests on Collection.equals nor any for Collection.hashCode.
0133: //
0134:
0135: // These fields are used by reset() and verify(), and any test
0136: // method that tests a modification.
0137:
0138: /**
0139: * A collection instance that will be used for testing.
0140: */
0141: public Collection collection;
0142:
0143: /**
0144: * Confirmed collection. This is an instance of a collection that is
0145: * confirmed to conform exactly to the java.util.Collection contract.
0146: * Modification operations are tested by performing a mod on your
0147: * collection, performing the exact same mod on an equivalent confirmed
0148: * collection, and then calling verify() to make sure your collection
0149: * still matches the confirmed collection.
0150: */
0151: public Collection confirmed;
0152:
0153: /**
0154: * JUnit constructor.
0155: *
0156: * @param testName the test class name
0157: */
0158: public AbstractTestCollection(String testName) {
0159: super (testName);
0160: }
0161:
0162: //-----------------------------------------------------------------------
0163: /**
0164: * Specifies whether equal elements in the collection are, in fact,
0165: * distinguishable with information not readily available. That is, if a
0166: * particular value is to be removed from the collection, then there is
0167: * one and only one value that can be removed, even if there are other
0168: * elements which are equal to it.
0169: *
0170: * <P>In most collection cases, elements are not distinguishable (equal is
0171: * equal), thus this method defaults to return false. In some cases,
0172: * however, they are. For example, the collection returned from the map's
0173: * values() collection view are backed by the map, so while there may be
0174: * two values that are equal, their associated keys are not. Since the
0175: * keys are distinguishable, the values are.
0176: *
0177: * <P>This flag is used to skip some verifications for iterator.remove()
0178: * where it is impossible to perform an equivalent modification on the
0179: * confirmed collection because it is not possible to determine which
0180: * value in the confirmed collection to actually remove. Tests that
0181: * override the default (i.e. where equal elements are distinguishable),
0182: * should provide additional tests on iterator.remove() to make sure the
0183: * proper elements are removed when remove() is called on the iterator.
0184: **/
0185: public boolean areEqualElementsDistinguishable() {
0186: return false;
0187: }
0188:
0189: /**
0190: * Returns true if the collections produced by
0191: * {@link #makeCollection()} and {@link #makeFullCollection()}
0192: * support the <code>add</code> and <code>addAll</code>
0193: * operations.<P>
0194: * Default implementation returns true. Override if your collection
0195: * class does not support add or addAll.
0196: */
0197: public boolean isAddSupported() {
0198: return true;
0199: }
0200:
0201: /**
0202: * Returns true if the collections produced by
0203: * {@link #makeCollection()} and {@link #makeFullCollection()}
0204: * support the <code>remove</code>, <code>removeAll</code>,
0205: * <code>retainAll</code>, <code>clear</code> and
0206: * <code>iterator().remove()</code> methods.
0207: * Default implementation returns true. Override if your collection
0208: * class does not support removal operations.
0209: */
0210: public boolean isRemoveSupported() {
0211: return true;
0212: }
0213:
0214: /**
0215: * Returns true to indicate that the collection supports holding null.
0216: * The default implementation returns true;
0217: */
0218: public boolean isNullSupported() {
0219: return true;
0220: }
0221:
0222: /**
0223: * Returns true to indicate that the collection supports fail fast iterators.
0224: * The default implementation returns true;
0225: */
0226: public boolean isFailFastSupported() {
0227: return false;
0228: }
0229:
0230: /**
0231: * Returns true to indicate that the collection supports equals() comparisons.
0232: * This implementation returns false;
0233: */
0234: public boolean isEqualsCheckable() {
0235: return false;
0236: }
0237:
0238: //-----------------------------------------------------------------------
0239: /**
0240: * Verifies that {@link #collection} and {@link #confirmed} have
0241: * identical state.
0242: */
0243: public void verify() {
0244: int confirmedSize = confirmed.size();
0245: assertEquals(
0246: "Collection size should match confirmed collection's",
0247: confirmedSize, collection.size());
0248: assertEquals(
0249: "Collection isEmpty() result should match confirmed "
0250: + " collection's", confirmed.isEmpty(),
0251: collection.isEmpty());
0252:
0253: // verify the collections are the same by attempting to match each
0254: // object in the collection and confirmed collection. To account for
0255: // duplicates and differing orders, each confirmed element is copied
0256: // into an array and a flag is maintained for each element to determine
0257: // whether it has been matched once and only once. If all elements in
0258: // the confirmed collection are matched once and only once and there
0259: // aren't any elements left to be matched in the collection,
0260: // verification is a success.
0261:
0262: // copy each collection value into an array
0263: Object[] confirmedValues = new Object[confirmedSize];
0264:
0265: Iterator iter;
0266:
0267: iter = confirmed.iterator();
0268: int pos = 0;
0269: while (iter.hasNext()) {
0270: confirmedValues[pos++] = iter.next();
0271: }
0272:
0273: // allocate an array of boolean flags for tracking values that have
0274: // been matched once and only once.
0275: boolean[] matched = new boolean[confirmedSize];
0276:
0277: // now iterate through the values of the collection and try to match
0278: // the value with one in the confirmed array.
0279: iter = collection.iterator();
0280: while (iter.hasNext()) {
0281: Object o = iter.next();
0282: boolean match = false;
0283: for (int i = 0; i < confirmedSize; i++) {
0284: if (matched[i]) {
0285: // skip values already matched
0286: continue;
0287: }
0288: if (o == confirmedValues[i]
0289: || (o != null && o.equals(confirmedValues[i]))) {
0290: // values matched
0291: matched[i] = true;
0292: match = true;
0293: break;
0294: }
0295: }
0296: // no match found!
0297: if (!match) {
0298: fail("Collection should not contain a value that the "
0299: + "confirmed collection does not have: " + o
0300: + "\nTest: " + collection + "\nReal: "
0301: + confirmed);
0302: }
0303: }
0304:
0305: // make sure there aren't any unmatched values
0306: for (int i = 0; i < confirmedSize; i++) {
0307: if (!matched[i]) {
0308: // the collection didn't match all the confirmed values
0309: fail("Collection should contain all values that are in the confirmed collection"
0310: + "\nTest: "
0311: + collection
0312: + "\nReal: "
0313: + confirmed);
0314: }
0315: }
0316: }
0317:
0318: //-----------------------------------------------------------------------
0319: /**
0320: * Resets the {@link #collection} and {@link #confirmed} fields to empty
0321: * collections. Invoke this method before performing a modification
0322: * test.
0323: */
0324: public void resetEmpty() {
0325: this .collection = makeCollection();
0326: this .confirmed = makeConfirmedCollection();
0327: }
0328:
0329: /**
0330: * Resets the {@link #collection} and {@link #confirmed} fields to full
0331: * collections. Invoke this method before performing a modification
0332: * test.
0333: */
0334: public void resetFull() {
0335: this .collection = makeFullCollection();
0336: this .confirmed = makeConfirmedFullCollection();
0337: }
0338:
0339: //-----------------------------------------------------------------------
0340: /**
0341: * Returns a confirmed empty collection.
0342: * For instance, an {@link java.util.ArrayList} for lists or a
0343: * {@link java.util.HashSet} for sets.
0344: *
0345: * @return a confirmed empty collection
0346: */
0347: public abstract Collection makeConfirmedCollection();
0348:
0349: /**
0350: * Returns a confirmed full collection.
0351: * For instance, an {@link java.util.ArrayList} for lists or a
0352: * {@link java.util.HashSet} for sets. The returned collection
0353: * should contain the elements returned by {@link #getFullElements()}.
0354: *
0355: * @return a confirmed full collection
0356: */
0357: public abstract Collection makeConfirmedFullCollection();
0358:
0359: /**
0360: * Return a new, empty {@link Collection} to be used for testing.
0361: */
0362: public abstract Collection makeCollection();
0363:
0364: /**
0365: * Returns a full collection to be used for testing. The collection
0366: * returned by this method should contain every element returned by
0367: * {@link #getFullElements()}. The default implementation, in fact,
0368: * simply invokes <code>addAll</code> on an empty collection with
0369: * the results of {@link #getFullElements()}. Override this default
0370: * if your collection doesn't support addAll.
0371: */
0372: public Collection makeFullCollection() {
0373: Collection c = makeCollection();
0374: c.addAll(Arrays.asList(getFullElements()));
0375: return c;
0376: }
0377:
0378: /**
0379: * Returns an empty collection for Object tests.
0380: */
0381: public Object makeObject() {
0382: return makeCollection();
0383: }
0384:
0385: /**
0386: * Creates a new Map Entry that is independent of the first and the map.
0387: */
0388: public Map.Entry cloneMapEntry(Map.Entry entry) {
0389: HashMap map = new HashMap();
0390: map.put(entry.getKey(), entry.getValue());
0391: return (Map.Entry) map.entrySet().iterator().next();
0392: }
0393:
0394: //-----------------------------------------------------------------------
0395: /**
0396: * Returns an array of objects that are contained in a collection
0397: * produced by {@link #makeFullCollection()}. Every element in the
0398: * returned array <I>must</I> be an element in a full collection.<P>
0399: * The default implementation returns a heterogenous array of
0400: * objects with some duplicates. null is added if allowed.
0401: * Override if you require specific testing elements. Note that if you
0402: * override {@link #makeFullCollection()}, you <I>must</I> override
0403: * this method to reflect the contents of a full collection.
0404: */
0405: public Object[] getFullElements() {
0406: if (isNullSupported()) {
0407: ArrayList list = new ArrayList();
0408: list.addAll(Arrays.asList(getFullNonNullElements()));
0409: list.add(4, null);
0410: return list.toArray();
0411: } else {
0412: return (Object[]) getFullNonNullElements().clone();
0413: }
0414: }
0415:
0416: /**
0417: * Returns an array of elements that are <I>not</I> contained in a
0418: * full collection. Every element in the returned array must
0419: * not exist in a collection returned by {@link #makeFullCollection()}.
0420: * The default implementation returns a heterogenous array of elements
0421: * without null. Note that some of the tests add these elements
0422: * to an empty or full collection, so if your collection restricts
0423: * certain kinds of elements, you should override this method.
0424: */
0425: public Object[] getOtherElements() {
0426: return getOtherNonNullElements();
0427: }
0428:
0429: //-----------------------------------------------------------------------
0430: /**
0431: * Returns a list of elements suitable for return by
0432: * {@link #getFullElements()}. The array returned by this method
0433: * does not include null, but does include a variety of objects
0434: * of different types. Override getFullElements to return
0435: * the results of this method if your collection does not support
0436: * the null element.
0437: */
0438: public Object[] getFullNonNullElements() {
0439: return new Object[] { new String(""), new String("One"),
0440: new Integer(2), "Three", new Integer(4), "One",
0441: new Double(5), new Float(6), "Seven", "Eight",
0442: new String("Nine"), new Integer(10),
0443: new Short((short) 11), new Long(12), "Thirteen", "14",
0444: "15", new Byte((byte) 16) };
0445: }
0446:
0447: /**
0448: * Returns the default list of objects returned by
0449: * {@link #getOtherElements()}. Includes many objects
0450: * of different types.
0451: */
0452: public Object[] getOtherNonNullElements() {
0453: return new Object[] { new Integer(0), new Float(0),
0454: new Double(0), "Zero", new Short((short) 0),
0455: new Byte((byte) 0), new Long(0),
0456: new Character('\u0000'), "0" };
0457: }
0458:
0459: /**
0460: * Returns a list of string elements suitable for return by
0461: * {@link #getFullElements()}. Override getFullElements to return
0462: * the results of this method if your collection does not support
0463: * heterogenous elements or the null element.
0464: */
0465: public Object[] getFullNonNullStringElements() {
0466: return new Object[] { "If", "the", "dull", "substance", "of",
0467: "my", "flesh", "were", "thought", "Injurious",
0468: "distance", "could", "not", "stop", "my", "way", };
0469: }
0470:
0471: /**
0472: * Returns a list of string elements suitable for return by
0473: * {@link #getOtherElements()}. Override getOtherElements to return
0474: * the results of this method if your collection does not support
0475: * heterogenous elements or the null element.
0476: */
0477: public Object[] getOtherNonNullStringElements() {
0478: return new Object[] { "For", "then", "despite",/* of */
0479: "space", "I", "would", "be", "brought", "From",
0480: "limits", "far", "remote", "where", "thou", "dost",
0481: "stay" };
0482: }
0483:
0484: // Tests
0485: //-----------------------------------------------------------------------
0486: /**
0487: * Tests {@link Collection#add(Object)}.
0488: */
0489: public void testCollectionAdd() {
0490: if (!isAddSupported())
0491: return;
0492:
0493: Object[] elements = getFullElements();
0494: for (int i = 0; i < elements.length; i++) {
0495: resetEmpty();
0496: boolean r = collection.add(elements[i]);
0497: confirmed.add(elements[i]);
0498: verify();
0499: assertTrue("Empty collection changed after add", r);
0500: assertEquals("Collection size is 1 after first add", 1,
0501: collection.size());
0502: }
0503:
0504: resetEmpty();
0505: int size = 0;
0506: for (int i = 0; i < elements.length; i++) {
0507: boolean r = collection.add(elements[i]);
0508: confirmed.add(elements[i]);
0509: verify();
0510: if (r)
0511: size++;
0512: assertEquals("Collection size should grow after add", size,
0513: collection.size());
0514: assertTrue("Collection should contain added element",
0515: collection.contains(elements[i]));
0516: }
0517: }
0518:
0519: /**
0520: * Tests {@link Collection#addAll(Collection)}.
0521: */
0522: public void testCollectionAddAll() {
0523: if (!isAddSupported())
0524: return;
0525:
0526: resetEmpty();
0527: Object[] elements = getFullElements();
0528: boolean r = collection.addAll(Arrays.asList(elements));
0529: confirmed.addAll(Arrays.asList(elements));
0530: verify();
0531: assertTrue("Empty collection should change after addAll", r);
0532: for (int i = 0; i < elements.length; i++) {
0533: assertTrue("Collection should contain added element",
0534: collection.contains(elements[i]));
0535: }
0536:
0537: resetFull();
0538: int size = collection.size();
0539: elements = getOtherElements();
0540: r = collection.addAll(Arrays.asList(elements));
0541: confirmed.addAll(Arrays.asList(elements));
0542: verify();
0543: assertTrue("Full collection should change after addAll", r);
0544: for (int i = 0; i < elements.length; i++) {
0545: assertTrue("Full collection should contain added element",
0546: collection.contains(elements[i]));
0547: }
0548: assertEquals("Size should increase after addAll", size
0549: + elements.length, collection.size());
0550:
0551: resetFull();
0552: size = collection.size();
0553: r = collection.addAll(Arrays.asList(getFullElements()));
0554: confirmed.addAll(Arrays.asList(getFullElements()));
0555: verify();
0556: if (r) {
0557: assertTrue("Size should increase if addAll returns true",
0558: size < collection.size());
0559: } else {
0560: assertEquals(
0561: "Size should not change if addAll returns false",
0562: size, collection.size());
0563: }
0564: }
0565:
0566: /**
0567: * If {@link #isAddSupported()} returns false, tests that add operations
0568: * raise <code>UnsupportedOperationException.
0569: */
0570: public void testUnsupportedAdd() {
0571: if (isAddSupported())
0572: return;
0573:
0574: resetEmpty();
0575: try {
0576: collection.add(new Object());
0577: fail("Emtpy collection should not support add.");
0578: } catch (UnsupportedOperationException e) {
0579: // expected
0580: }
0581: // make sure things didn't change even if the expected exception was
0582: // thrown.
0583: verify();
0584:
0585: try {
0586: collection.addAll(Arrays.asList(getFullElements()));
0587: fail("Emtpy collection should not support addAll.");
0588: } catch (UnsupportedOperationException e) {
0589: // expected
0590: }
0591: // make sure things didn't change even if the expected exception was
0592: // thrown.
0593: verify();
0594:
0595: resetFull();
0596: try {
0597: collection.add(new Object());
0598: fail("Full collection should not support add.");
0599: } catch (UnsupportedOperationException e) {
0600: // expected
0601: }
0602: // make sure things didn't change even if the expected exception was
0603: // thrown.
0604: verify();
0605:
0606: try {
0607: collection.addAll(Arrays.asList(getOtherElements()));
0608: fail("Full collection should not support addAll.");
0609: } catch (UnsupportedOperationException e) {
0610: // expected
0611: }
0612: // make sure things didn't change even if the expected exception was
0613: // thrown.
0614: verify();
0615: }
0616:
0617: /**
0618: * Test {@link Collection#clear()}.
0619: */
0620: public void testCollectionClear() {
0621: if (!isRemoveSupported())
0622: return;
0623:
0624: resetEmpty();
0625: collection.clear(); // just to make sure it doesn't raise anything
0626: verify();
0627:
0628: resetFull();
0629: collection.clear();
0630: confirmed.clear();
0631: verify();
0632: }
0633:
0634: /**
0635: * Tests {@link Collection#contains(Object)}.
0636: */
0637: public void testCollectionContains() {
0638: Object[] elements;
0639:
0640: resetEmpty();
0641: elements = getFullElements();
0642: for (int i = 0; i < elements.length; i++) {
0643: assertTrue("Empty collection shouldn't contain element["
0644: + i + "]", !collection.contains(elements[i]));
0645: }
0646: // make sure calls to "contains" don't change anything
0647: verify();
0648:
0649: elements = getOtherElements();
0650: for (int i = 0; i < elements.length; i++) {
0651: assertTrue("Empty collection shouldn't contain element["
0652: + i + "]", !collection.contains(elements[i]));
0653: }
0654: // make sure calls to "contains" don't change anything
0655: verify();
0656:
0657: resetFull();
0658: elements = getFullElements();
0659: for (int i = 0; i < elements.length; i++) {
0660: assertTrue("Full collection should contain element[" + i
0661: + "]", collection.contains(elements[i]));
0662: }
0663: // make sure calls to "contains" don't change anything
0664: verify();
0665:
0666: resetFull();
0667: elements = getOtherElements();
0668: for (int i = 0; i < elements.length; i++) {
0669: assertTrue("Full collection shouldn't contain element",
0670: !collection.contains(elements[i]));
0671: }
0672: }
0673:
0674: /**
0675: * Tests {@link Collection#containsAll(Collection)}.
0676: */
0677: public void testCollectionContainsAll() {
0678: resetEmpty();
0679: Collection col = new HashSet();
0680: assertTrue(
0681: "Every Collection should contain all elements of an "
0682: + "empty Collection.", collection
0683: .containsAll(col));
0684: col.addAll(Arrays.asList(getOtherElements()));
0685: assertTrue(
0686: "Empty Collection shouldn't contain all elements of "
0687: + "a non-empty Collection.", !collection
0688: .containsAll(col));
0689: // make sure calls to "containsAll" don't change anything
0690: verify();
0691:
0692: resetFull();
0693: assertTrue("Full collection shouldn't contain other elements",
0694: !collection.containsAll(col));
0695:
0696: col.clear();
0697: col.addAll(Arrays.asList(getFullElements()));
0698: assertTrue("Full collection should containAll full elements",
0699: collection.containsAll(col));
0700: // make sure calls to "containsAll" don't change anything
0701: verify();
0702:
0703: int min = (getFullElements().length < 2 ? 0 : 2);
0704: int max = (getFullElements().length == 1 ? 1
0705: : (getFullElements().length <= 5 ? getFullElements().length - 1
0706: : 5));
0707: col = Arrays.asList(getFullElements()).subList(min, max);
0708: assertTrue("Full collection should containAll partial full "
0709: + "elements", collection.containsAll(col));
0710: assertTrue("Full collection should containAll itself",
0711: collection.containsAll(collection));
0712: // make sure calls to "containsAll" don't change anything
0713: verify();
0714:
0715: col = new ArrayList();
0716: col.addAll(Arrays.asList(getFullElements()));
0717: col.addAll(Arrays.asList(getFullElements()));
0718: assertTrue("Full collection should containAll duplicate full "
0719: + "elements", collection.containsAll(col));
0720:
0721: // make sure calls to "containsAll" don't change anything
0722: verify();
0723: }
0724:
0725: /**
0726: * Tests {@link Collection#isEmpty()}.
0727: */
0728: public void testCollectionIsEmpty() {
0729: resetEmpty();
0730: assertEquals("New Collection should be empty.", true,
0731: collection.isEmpty());
0732: // make sure calls to "isEmpty() don't change anything
0733: verify();
0734:
0735: resetFull();
0736: assertEquals("Full collection shouldn't be empty", false,
0737: collection.isEmpty());
0738: // make sure calls to "isEmpty() don't change anything
0739: verify();
0740: }
0741:
0742: /**
0743: * Tests the read-only functionality of {@link Collection#iterator()}.
0744: */
0745: public void testCollectionIterator() {
0746: resetEmpty();
0747: Iterator it1 = collection.iterator();
0748: assertEquals(
0749: "Iterator for empty Collection shouldn't have next.",
0750: false, it1.hasNext());
0751: try {
0752: it1.next();
0753: fail("Iterator at end of Collection should throw "
0754: + "NoSuchElementException when next is called.");
0755: } catch (NoSuchElementException e) {
0756: // expected
0757: }
0758: // make sure nothing has changed after non-modification
0759: verify();
0760:
0761: resetFull();
0762: it1 = collection.iterator();
0763: for (int i = 0; i < collection.size(); i++) {
0764: assertTrue("Iterator for full collection should haveNext",
0765: it1.hasNext());
0766: it1.next();
0767: }
0768: assertTrue("Iterator should be finished", !it1.hasNext());
0769:
0770: ArrayList list = new ArrayList();
0771: it1 = collection.iterator();
0772: for (int i = 0; i < collection.size(); i++) {
0773: Object next = it1.next();
0774: assertTrue("Collection should contain element returned by "
0775: + "its iterator", collection.contains(next));
0776: list.add(next);
0777: }
0778: try {
0779: it1.next();
0780: fail("iterator.next() should raise NoSuchElementException "
0781: + "after it finishes");
0782: } catch (NoSuchElementException e) {
0783: // expected
0784: }
0785: // make sure nothing has changed after non-modification
0786: verify();
0787: }
0788:
0789: /**
0790: * Tests removals from {@link Collection#iterator()}.
0791: */
0792: public void testCollectionIteratorRemove() {
0793: if (!isRemoveSupported())
0794: return;
0795:
0796: resetEmpty();
0797: try {
0798: collection.iterator().remove();
0799: fail("New iterator.remove should raise IllegalState");
0800: } catch (IllegalStateException e) {
0801: // expected
0802: }
0803: verify();
0804:
0805: try {
0806: Iterator iter = collection.iterator();
0807: iter.hasNext();
0808: iter.remove();
0809: fail("New iterator.remove should raise IllegalState "
0810: + "even after hasNext");
0811: } catch (IllegalStateException e) {
0812: // expected
0813: }
0814: verify();
0815:
0816: resetFull();
0817: int size = collection.size();
0818: Iterator iter = collection.iterator();
0819: while (iter.hasNext()) {
0820: Object o = iter.next();
0821: // TreeMap reuses the Map Entry, so the verify below fails
0822: // Clone it here if necessary
0823: if (o instanceof Map.Entry) {
0824: o = cloneMapEntry((Map.Entry) o);
0825: }
0826: iter.remove();
0827:
0828: // if the elements aren't distinguishable, we can just remove a
0829: // matching element from the confirmed collection and verify
0830: // contents are still the same. Otherwise, we don't have the
0831: // ability to distinguish the elements and determine which to
0832: // remove from the confirmed collection (in which case, we don't
0833: // verify because we don't know how).
0834: //
0835: // see areEqualElementsDistinguishable()
0836: if (!areEqualElementsDistinguishable()) {
0837: confirmed.remove(o);
0838: verify();
0839: }
0840:
0841: size--;
0842: assertEquals("Collection should shrink by one after "
0843: + "iterator.remove", size, collection.size());
0844: }
0845: assertTrue("Collection should be empty after iterator purge",
0846: collection.isEmpty());
0847:
0848: resetFull();
0849: iter = collection.iterator();
0850: iter.next();
0851: iter.remove();
0852: try {
0853: iter.remove();
0854: fail("Second iter.remove should raise IllegalState");
0855: } catch (IllegalStateException e) {
0856: // expected
0857: }
0858: }
0859:
0860: /**
0861: * Tests {@link Collection#remove(Object)}.
0862: */
0863: public void testCollectionRemove() {
0864: if (!isRemoveSupported())
0865: return;
0866:
0867: resetEmpty();
0868: Object[] elements = getFullElements();
0869: for (int i = 0; i < elements.length; i++) {
0870: assertTrue("Shouldn't remove nonexistent element",
0871: !collection.remove(elements[i]));
0872: verify();
0873: }
0874:
0875: Object[] other = getOtherElements();
0876:
0877: resetFull();
0878: for (int i = 0; i < other.length; i++) {
0879: assertTrue("Shouldn't remove nonexistent other element",
0880: !collection.remove(other[i]));
0881: verify();
0882: }
0883:
0884: int size = collection.size();
0885: for (int i = 0; i < elements.length; i++) {
0886: resetFull();
0887: assertTrue("Collection should remove extant element: "
0888: + elements[i], collection.remove(elements[i]));
0889:
0890: // if the elements aren't distinguishable, we can just remove a
0891: // matching element from the confirmed collection and verify
0892: // contents are still the same. Otherwise, we don't have the
0893: // ability to distinguish the elements and determine which to
0894: // remove from the confirmed collection (in which case, we don't
0895: // verify because we don't know how).
0896: //
0897: // see areEqualElementsDistinguishable()
0898: if (!areEqualElementsDistinguishable()) {
0899: confirmed.remove(elements[i]);
0900: verify();
0901: }
0902:
0903: assertEquals("Collection should shrink after remove",
0904: size - 1, collection.size());
0905: }
0906: }
0907:
0908: /**
0909: * Tests {@link Collection#removeAll(Collection)}.
0910: */
0911: public void testCollectionRemoveAll() {
0912: if (!isRemoveSupported())
0913: return;
0914:
0915: resetEmpty();
0916: assertTrue(
0917: "Emtpy collection removeAll should return false for "
0918: + "empty input", !collection
0919: .removeAll(Collections.EMPTY_SET));
0920: verify();
0921:
0922: assertTrue(
0923: "Emtpy collection removeAll should return false for "
0924: + "nonempty input", !collection
0925: .removeAll(new ArrayList(collection)));
0926: verify();
0927:
0928: resetFull();
0929: assertTrue("Full collection removeAll should return false for "
0930: + "empty input", !collection
0931: .removeAll(Collections.EMPTY_SET));
0932: verify();
0933:
0934: assertTrue(
0935: "Full collection removeAll should return false for other elements",
0936: !collection
0937: .removeAll(Arrays.asList(getOtherElements())));
0938: verify();
0939:
0940: assertTrue(
0941: "Full collection removeAll should return true for full elements",
0942: collection.removeAll(new HashSet(collection)));
0943: confirmed.removeAll(new HashSet(confirmed));
0944: verify();
0945:
0946: resetFull();
0947: int size = collection.size();
0948: int min = (getFullElements().length < 2 ? 0 : 2);
0949: int max = (getFullElements().length == 1 ? 1
0950: : (getFullElements().length <= 5 ? getFullElements().length - 1
0951: : 5));
0952: Collection all = Arrays.asList(getFullElements()).subList(min,
0953: max);
0954: assertTrue("Full collection removeAll should work", collection
0955: .removeAll(all));
0956: confirmed.removeAll(all);
0957: verify();
0958:
0959: assertTrue("Collection should shrink after removeAll",
0960: collection.size() < size);
0961: Iterator iter = all.iterator();
0962: while (iter.hasNext()) {
0963: assertTrue("Collection shouldn't contain removed element",
0964: !collection.contains(iter.next()));
0965: }
0966: }
0967:
0968: /**
0969: * Tests {@link Collection#retainAll(Collection)}.
0970: */
0971: public void testCollectionRetainAll() {
0972: if (!isRemoveSupported())
0973: return;
0974:
0975: resetEmpty();
0976: List elements = Arrays.asList(getFullElements());
0977: List other = Arrays.asList(getOtherElements());
0978:
0979: assertTrue("Empty retainAll() should return false", !collection
0980: .retainAll(Collections.EMPTY_SET));
0981: verify();
0982:
0983: assertTrue("Empty retainAll() should return false", !collection
0984: .retainAll(elements));
0985: verify();
0986:
0987: resetFull();
0988: assertTrue("Collection should change from retainAll empty",
0989: collection.retainAll(Collections.EMPTY_SET));
0990: confirmed.retainAll(Collections.EMPTY_SET);
0991: verify();
0992:
0993: resetFull();
0994: assertTrue("Collection changed from retainAll other",
0995: collection.retainAll(other));
0996: confirmed.retainAll(other);
0997: verify();
0998:
0999: resetFull();
1000: int size = collection.size();
1001: assertTrue(
1002: "Collection shouldn't change from retainAll elements",
1003: !collection.retainAll(elements));
1004: verify();
1005: assertEquals("Collection size shouldn't change", size,
1006: collection.size());
1007:
1008: if (getFullElements().length > 1) {
1009: resetFull();
1010: size = collection.size();
1011: int min = (getFullElements().length < 2 ? 0 : 2);
1012: int max = (getFullElements().length <= 5 ? getFullElements().length - 1
1013: : 5);
1014: assertTrue(
1015: "Collection should changed by partial retainAll",
1016: collection.retainAll(elements.subList(min, max)));
1017: confirmed.retainAll(elements.subList(min, max));
1018: verify();
1019:
1020: Iterator iter = collection.iterator();
1021: while (iter.hasNext()) {
1022: assertTrue("Collection only contains retained element",
1023: elements.subList(min, max)
1024: .contains(iter.next()));
1025: }
1026: }
1027:
1028: resetFull();
1029: HashSet set = new HashSet(elements);
1030: size = collection.size();
1031: assertTrue(
1032: "Collection shouldn't change from retainAll without "
1033: + "duplicate elements", !collection
1034: .retainAll(set));
1035: verify();
1036: assertEquals("Collection size didn't change from nonduplicate "
1037: + "retainAll", size, collection.size());
1038: }
1039:
1040: /**
1041: * Tests {@link Collection#size()}.
1042: */
1043: public void testCollectionSize() {
1044: resetEmpty();
1045: assertEquals("Size of new Collection is 0.", 0, collection
1046: .size());
1047:
1048: resetFull();
1049: assertTrue(
1050: "Size of full collection should be greater than zero",
1051: collection.size() > 0);
1052: }
1053:
1054: /**
1055: * Tests {@link Collection#toArray()}.
1056: */
1057: public void testCollectionToArray() {
1058: resetEmpty();
1059: assertEquals(
1060: "Empty Collection should return empty array for toArray",
1061: 0, collection.toArray().length);
1062:
1063: resetFull();
1064: Object[] array = collection.toArray();
1065: assertEquals("Full collection toArray should be same size as "
1066: + "collection", array.length, collection.size());
1067: Object[] confirmedArray = confirmed.toArray();
1068: assertEquals(
1069: "length of array from confirmed collection should "
1070: + "match the length of the collection's array",
1071: confirmedArray.length, array.length);
1072: boolean[] matched = new boolean[array.length];
1073:
1074: for (int i = 0; i < array.length; i++) {
1075: assertTrue("Collection should contain element in toArray",
1076: collection.contains(array[i]));
1077:
1078: boolean match = false;
1079: // find a match in the confirmed array
1080: for (int j = 0; j < array.length; j++) {
1081: // skip already matched
1082: if (matched[j])
1083: continue;
1084: if (array[i] == confirmedArray[j]
1085: || (array[i] != null && array[i]
1086: .equals(confirmedArray[j]))) {
1087: matched[j] = true;
1088: match = true;
1089: break;
1090: }
1091: }
1092: if (!match) {
1093: fail("element " + i
1094: + " in returned array should be found "
1095: + "in the confirmed collection's array");
1096: }
1097: }
1098: for (int i = 0; i < matched.length; i++) {
1099: assertEquals(
1100: "Collection should return all its elements in "
1101: + "toArray", true, matched[i]);
1102: }
1103: }
1104:
1105: /**
1106: * Tests {@link Collection#toArray(Object[])}.
1107: */
1108: public void testCollectionToArray2() {
1109: resetEmpty();
1110: Object[] a = new Object[] { new Object(), null, null };
1111: Object[] array = collection.toArray(a);
1112: assertEquals("Given array shouldn't shrink", array, a);
1113: assertEquals("Last element should be set to null", a[0], null);
1114: verify();
1115:
1116: resetFull();
1117: try {
1118: array = collection.toArray(new Void[0]);
1119: fail("toArray(new Void[0]) should raise ArrayStore");
1120: } catch (ArrayStoreException e) {
1121: // expected
1122: }
1123: verify();
1124:
1125: try {
1126: array = collection.toArray(null);
1127: fail("toArray(null) should raise NPE");
1128: } catch (NullPointerException e) {
1129: // expected
1130: }
1131: verify();
1132:
1133: array = collection.toArray(new Object[0]);
1134: a = collection.toArray();
1135: assertEquals("toArrays should be equal", Arrays.asList(array),
1136: Arrays.asList(a));
1137:
1138: // Figure out if they're all the same class
1139: // TODO: It'd be nicer to detect a common superclass
1140: HashSet classes = new HashSet();
1141: for (int i = 0; i < array.length; i++) {
1142: classes
1143: .add((array[i] == null) ? null : array[i]
1144: .getClass());
1145: }
1146: if (classes.size() > 1)
1147: return;
1148:
1149: Class cl = (Class) classes.iterator().next();
1150: if (Map.Entry.class.isAssignableFrom(cl)) { // check needed for protective cases like Predicated/Unmod map entrySet
1151: cl = Map.Entry.class;
1152: }
1153: a = (Object[]) Array.newInstance(cl, 0);
1154: array = collection.toArray(a);
1155: assertEquals(
1156: "toArray(Object[]) should return correct array type", a
1157: .getClass(), array.getClass());
1158: assertEquals("type-specific toArrays should be equal", Arrays
1159: .asList(array), Arrays.asList(collection.toArray()));
1160: verify();
1161: }
1162:
1163: /**
1164: * Tests <code>toString</code> on a collection.
1165: */
1166: public void testCollectionToString() {
1167: resetEmpty();
1168: assertTrue("toString shouldn't return null", collection
1169: .toString() != null);
1170:
1171: resetFull();
1172: assertTrue("toString shouldn't return null", collection
1173: .toString() != null);
1174: }
1175:
1176: /**
1177: * If isRemoveSupported() returns false, tests to see that remove
1178: * operations raise an UnsupportedOperationException.
1179: */
1180: public void testUnsupportedRemove() {
1181: if (isRemoveSupported())
1182: return;
1183:
1184: resetEmpty();
1185: try {
1186: collection.clear();
1187: fail("clear should raise UnsupportedOperationException");
1188: } catch (UnsupportedOperationException e) {
1189: // expected
1190: }
1191: verify();
1192:
1193: try {
1194: collection.remove(null);
1195: fail("remove should raise UnsupportedOperationException");
1196: } catch (UnsupportedOperationException e) {
1197: // expected
1198: }
1199: verify();
1200:
1201: try {
1202: collection.removeAll(null);
1203: fail("removeAll should raise UnsupportedOperationException");
1204: } catch (UnsupportedOperationException e) {
1205: // expected
1206: }
1207: verify();
1208:
1209: try {
1210: collection.retainAll(null);
1211: fail("removeAll should raise UnsupportedOperationException");
1212: } catch (UnsupportedOperationException e) {
1213: // expected
1214: }
1215: verify();
1216:
1217: resetFull();
1218: try {
1219: Iterator iterator = collection.iterator();
1220: iterator.next();
1221: iterator.remove();
1222: fail("iterator.remove should raise UnsupportedOperationException");
1223: } catch (UnsupportedOperationException e) {
1224: // expected
1225: }
1226: verify();
1227:
1228: }
1229:
1230: /**
1231: * Tests that the collection's iterator is fail-fast.
1232: */
1233: public void testCollectionIteratorFailFast() {
1234: if (!isFailFastSupported())
1235: return;
1236:
1237: if (isAddSupported()) {
1238: resetFull();
1239: try {
1240: Iterator iter = collection.iterator();
1241: Object o = getOtherElements()[0];
1242: collection.add(o);
1243: confirmed.add(o);
1244: iter.next();
1245: fail("next after add should raise ConcurrentModification");
1246: } catch (ConcurrentModificationException e) {
1247: // expected
1248: }
1249: verify();
1250:
1251: resetFull();
1252: try {
1253: Iterator iter = collection.iterator();
1254: collection.addAll(Arrays.asList(getOtherElements()));
1255: confirmed.addAll(Arrays.asList(getOtherElements()));
1256: iter.next();
1257: fail("next after addAll should raise ConcurrentModification");
1258: } catch (ConcurrentModificationException e) {
1259: // expected
1260: }
1261: verify();
1262: }
1263:
1264: if (!isRemoveSupported())
1265: return;
1266:
1267: resetFull();
1268: try {
1269: Iterator iter = collection.iterator();
1270: collection.clear();
1271: iter.next();
1272: fail("next after clear should raise ConcurrentModification");
1273: } catch (ConcurrentModificationException e) {
1274: // expected
1275: } catch (NoSuchElementException e) {
1276: // (also legal given spec)
1277: }
1278:
1279: resetFull();
1280: try {
1281: Iterator iter = collection.iterator();
1282: collection.remove(getFullElements()[0]);
1283: iter.next();
1284: fail("next after remove should raise ConcurrentModification");
1285: } catch (ConcurrentModificationException e) {
1286: // expected
1287: }
1288:
1289: resetFull();
1290: try {
1291: Iterator iter = collection.iterator();
1292: List sublist = Arrays.asList(getFullElements()).subList(2,
1293: 5);
1294: collection.removeAll(sublist);
1295: iter.next();
1296: fail("next after removeAll should raise ConcurrentModification");
1297: } catch (ConcurrentModificationException e) {
1298: // expected
1299: }
1300:
1301: resetFull();
1302: try {
1303: Iterator iter = collection.iterator();
1304: List sublist = Arrays.asList(getFullElements()).subList(2,
1305: 5);
1306: collection.retainAll(sublist);
1307: iter.next();
1308: fail("next after retainAll should raise ConcurrentModification");
1309: } catch (ConcurrentModificationException e) {
1310: // expected
1311: }
1312: }
1313:
1314: public void testSerializeDeserializeThenCompare() throws Exception {
1315: Object obj = makeCollection();
1316: if (obj instanceof Serializable && isTestSerialization()) {
1317: ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1318: ObjectOutputStream out = new ObjectOutputStream(buffer);
1319: out.writeObject(obj);
1320: out.close();
1321:
1322: ObjectInputStream in = new ObjectInputStream(
1323: new ByteArrayInputStream(buffer.toByteArray()));
1324: Object dest = in.readObject();
1325: in.close();
1326: if (isEqualsCheckable()) {
1327: assertEquals(
1328: "obj != deserialize(serialize(obj)) - EMPTY Collection",
1329: obj, dest);
1330: }
1331: }
1332: obj = makeFullCollection();
1333: if (obj instanceof Serializable && isTestSerialization()) {
1334: ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1335: ObjectOutputStream out = new ObjectOutputStream(buffer);
1336: out.writeObject(obj);
1337: out.close();
1338:
1339: ObjectInputStream in = new ObjectInputStream(
1340: new ByteArrayInputStream(buffer.toByteArray()));
1341: Object dest = in.readObject();
1342: in.close();
1343: if (isEqualsCheckable()) {
1344: assertEquals(
1345: "obj != deserialize(serialize(obj)) - FULL Collection",
1346: obj, dest);
1347: }
1348: }
1349: }
1350:
1351: }
|