diff --git a/src/test/org/apache/commons/collections/TestCollection.java b/src/test/org/apache/commons/collections/TestCollection.java index 093e19ecd..452b39e13 100644 --- a/src/test/org/apache/commons/collections/TestCollection.java +++ b/src/test/org/apache/commons/collections/TestCollection.java @@ -1,7 +1,7 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/Attic/TestCollection.java,v 1.6 2002/06/18 01:14:23 mas Exp $ - * $Revision: 1.6 $ - * $Date: 2002/06/18 01:14:23 $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/Attic/TestCollection.java,v 1.7 2002/06/18 02:51:12 mas Exp $ + * $Revision: 1.7 $ + * $Date: 2002/06/18 02:51:12 $ * * ==================================================================== * @@ -80,7 +80,7 @@ import java.util.Set; *
* You should create a concrete subclass of this class to test any custom * {@link Collection} implementation. At minimum, you'll have to - * implement the {@link #makeCollection} method. You might want to + * implement the {@link #makeCollection()} method. You might want to * override some of the additional protected methods as well:
* * Element Population Methods
@@ -88,45 +88,46 @@ import java.util.Set;
* Override these if your collection restricts what kind of elements are
* allowed (for instance, if null
is not permitted):
*
* * Override these if your collection doesn't support certain operations: *
*
- * For tests on modification operations (adds and removes), fixtures are
- * used to verify that the the operation results in correct state for the
- * collection. Basically, the modification is performed against your
- * collection implementation, and an identical modification is performed
- * against a confirmed collection implementation. A confirmed
- * collection implementation is something like
- * java.util.ArrayList
, which is known to conform exactly to
- * its collection interface's contract. After the modification takes
- * place on both your collection implementation and the confirmed
- * collection implementation, the two collections are compared to see if
- * their state is identical. The comparison is usually much more
- * involved than a simple equals
test.
+ * Fixtures are used to verify that the the operation results in correct state
+ * for the collection. Basically, the operation is performed against your
+ * collection implementation, and an identical operation is performed against a
+ * confirmed collection implementation. A confirmed collection
+ * implementation is something like java.util.ArrayList
, which is
+ * known to conform exactly to its collection interface's contract. After the
+ * operation takes place on both your collection implementation and the
+ * confirmed collection implementation, the two collections are compared to see
+ * if their state is identical. The comparison is usually much more involved
+ * than a simple equals
test. This verification is used to ensure
+ * proper modifications are made along with ensuring that the collection does
+ * not change when read-only modifications are made.
* * The {@link #collection} field holds an instance of your collection * implementation; the {@link #confirmed} field holds an instance of the - * confirmed collection implementation. The {@link #resetEmpty} and - * {@link #resetFull} methods set these fields to empty or full collections, + * confirmed collection implementation. The {@link #resetEmpty()} and + * {@link #resetFull()} methods set these fields to empty or full collections, * so that tests can proceed from a known state.
* * After a modification operation to both {@link #collection} and - * {@link #confirmed}, the {@link #verify} method is invoked to compare - * the results. You may want to override {@link #verify} to perform + * {@link #confirmed}, the {@link #verify()} method is invoked to compare + * the results. You may want to override {@link #verify()} to perform * additional verifications. For instance, when testing the collection - * views of a map, {@link TestMap} overrides {@link #verify} to make sure - * the map is changed after the collection view is changed. + * views of a map, {@link TestMap} would override {@link #verify()} to make + * sure the map is changed after the collection view is changed. * * If you're extending this class directly, you will have to provide * implementations for the following: @@ -148,17 +149,29 @@ import java.util.Set; * If your {@link Collection} fails one of these tests by design, * you may still use this base set of cases. Simply override the * test case (method) your {@link Collection} fails. For instance, the - * {@link #testIteratorFailFast} method is provided since most collections + * {@link #testIteratorFailFast()} method is provided since most collections * have fail-fast iterators; however, that's not strictly required by the * collection contract, so you may want to override that method to do * nothing.
* * @author Rodney Waldhoff * @author Paul Jack - * @version $Id: TestCollection.java,v 1.6 2002/06/18 01:14:23 mas Exp $ + * @author Michael A. Smith + * @version $Id: TestCollection.java,v 1.7 2002/06/18 02:51:12 mas Exp $ */ public abstract class TestCollection extends TestObject { + // + // NOTE: + // + // Collection doesn't define any semantics for equals, and recommends you + // use reference-based default behavior of Object.equals. (And a test for + // that already exists in TestObject). Tests for equality of lists, sets + // and bags will have to be written in test subclasses. Thus, there is no + // tests on Collection.equals nor any for Collection.hashCode. + // + + // These fields are used by reset() and verify(), and any test // method that tests a modification. @@ -195,7 +208,7 @@ public abstract class TestCollection extends TestObject { /** - * Resets the {@link #collection} and {@link #confirmed} fields to empty + * Resets the {@link #collection} and {@link #confirmed} fields to full * collections. Invoke this method before performing a modification * test. */ @@ -204,21 +217,102 @@ public abstract class TestCollection extends TestObject { this.confirmed = makeConfirmedFullCollection(); } + /** + * Specifies whether equal elements in the collection are, in fact, + * distinguishable with information not readily available. That is, if a + * particular value is to be removed from the collection, then there is + * one and only one value that can be removed, even if there are other + * elements which are equal to it. + * + *
In most collection cases, elements are not distinguishable (equal is + * equal), thus this method defaults to return false. In some cases, + * however, they are. For example, the collection returned from the map's + * values() collection view are backed by the map, so while there may be + * two values that are equal, their associated keys are not. Since the + * keys are distinguishable, the values are. + * + *
This flag is used to skip some verifications for iterator.remove()
+ * where it is impossible to perform an equivalent modification on the
+ * confirmed collection because it is not possible to determine which
+ * value in the confirmed collection to actually remove. Tests that
+ * override the default (i.e. where equal elements are distinguishable),
+ * should provide additional tests on iterator.remove() to make sure the
+ * proper elements are removed when remove() is called on the iterator.
+ **/
+ protected boolean areEqualElementsDistinguishable() {
+ return false;
+ }
/**
* Verifies that {@link #collection} and {@link #confirmed} have
* identical state.
*/
protected void verify() {
+ int confirmedSize = confirmed.size();
assertEquals("Collection size should match confirmed collection's",
- confirmed.size(), collection.size());
+ confirmedSize, collection.size());
assertEquals("Collection isEmpty() result should match confirmed " +
" collection's",
confirmed.isEmpty(), collection.isEmpty());
- Bag bag1 = new HashBag(confirmed);
- Bag bag2 = new HashBag(collection);
- assertEquals("Collections should contain same elements with " +
- " the same cardinality", bag1, bag2);
+
+ // verify the collections are the same by attempting to match each
+ // object in the collection and confirmed collection. To account for
+ // duplicates and differing orders, each confirmed element is copied
+ // into an array and a flag is maintained for each element to determine
+ // whether it has been matched once and only once. If all elements in
+ // the confirmed collection are matched once and only once and there
+ // aren't any elements left to be matched in the collection,
+ // verification is a success.
+
+ // copy each collection value into an array
+ Object[] confirmedValues = new Object[confirmedSize];
+
+ Iterator iter;
+
+ iter = confirmed.iterator();
+ int pos = 0;
+ while(iter.hasNext()) {
+ confirmedValues[pos++] = iter.next();
+ }
+
+ // allocate an array of boolean flags for tracking values that have
+ // been matched once and only once.
+ boolean[] matched = new boolean[confirmedSize];
+
+ // now iterate through the values of the collection and try to match
+ // the value with one in the confirmed array.
+ iter = collection.iterator();
+ while(iter.hasNext()) {
+ Object o = iter.next();
+ boolean match = false;
+ for(int i = 0; i < confirmedSize; i++) {
+ if(matched[i]) {
+ // skip values already matched
+ continue;
+ }
+ if(o == confirmedValues[i] ||
+ (o != null && o.equals(confirmedValues[i]))) {
+ // values matched
+ matched[i] = true;
+ match = true;
+ break;
+ }
+ }
+ // no match found!
+ if(!match) {
+ fail("Collection should not contain a value that the " +
+ "confirmed collection does not have.");
+ }
+ }
+
+ // make sure there aren't any unmatched values
+ for(int i = 0; i < confirmedSize; i++) {
+ if(!matched[i]) {
+ // the collection didn't match all the confirmed values
+ fail("Collection should contain all values that are in the " +
+ "confirmed collection");
+ }
+ }
}
@@ -237,7 +331,7 @@ public abstract class TestCollection extends TestObject {
* Returns a confirmed full collection.
* For instance, an {@link java.util.ArrayList} for lists or a
* {@link java.util.HashSet} for sets. The returned collection
- * should contain the elements returned by {@link #getFullElements}.
+ * should contain the elements returned by {@link #getFullElements()}.
*
* @return a confirmed full collection
*/
@@ -246,39 +340,39 @@ public abstract class TestCollection extends TestObject {
/**
* Returns true if the collections produced by
- * {@link #makeCollection} and {@link #makeFullCollection}
+ * {@link #makeCollection()} and {@link #makeFullCollection()}
* support the add
and addAll
* operations.
* Default implementation returns true. Override if your collection
* class does not support add or addAll.
*/
- protected boolean supportsAdd() {
+ protected boolean isAddSupported() {
return true;
}
/**
* Returns true if the collections produced by
- * {@link #makeCollection} and {@link #makeFullCollection}
+ * {@link #makeCollection()} and {@link #makeFullCollection()}
* support the remove
, removeAll
,
* retainAll
, clear
and
- * iterator().remove
methods.
+ * iterator().remove()
methods.
* Default implementation returns true. Override if your collection
* class does not support removal operations.
*/
- protected boolean supportsRemove() {
+ protected boolean isRemoveSupported() {
return true;
}
/**
* Returns an array of objects that are contained in a collection
- * produced by {@link #makeFullCollection}. Every element in the
+ * produced by {@link #makeFullCollection()}. Every element in the
* returned array must be an element in a full collection.
* The default implementation returns a heterogenous array of
* objects with some duplicates and with the null element.
* Override if you require specific testing elements. Note that if you
- * override {@link #makeFullCollection}, you must override
+ * override {@link #makeFullCollection()}, you must override
* this method to reflect the contents of a full collection.
*/
protected Object[] getFullElements() {
@@ -292,7 +386,7 @@ public abstract class TestCollection extends TestObject {
/**
* Returns an array of elements that are not contained in a
* full collection. Every element in the returned array must
- * not exist in a collection returned by {@link #makeFullCollection}.
+ * not exist in a collection returned by {@link #makeFullCollection()}.
* The default implementation returns a heterogenous array of elements
* without null. Note that some of the tests add these elements
* to an empty or full collection, so if your collection restricts
@@ -312,9 +406,9 @@ public abstract class TestCollection extends TestObject {
/**
* Returns a full collection to be used for testing. The collection
* returned by this method should contain every element returned by
- * {@link #getFullElements}. The default implementation, in fact,
+ * {@link #getFullElements()}. The default implementation, in fact,
* simply invokes addAll
on an empty collection with
- * the results of {@link #getFullElements}. Override this default
+ * the results of {@link #getFullElements()}. Override this default
* if your collection doesn't support addAll.
*/
protected Collection makeFullCollection() {
@@ -333,10 +427,10 @@ public abstract class TestCollection extends TestObject {
/**
- * Tests {@link Collection#add}.
+ * Tests {@link Collection#add(Object)}.
*/
public void testCollectionAdd() {
- if (!supportsAdd()) return;
+ if (!isAddSupported()) return;
Object[] elements = getFullElements();
for (int i = 0; i < elements.length; i++) {
@@ -365,10 +459,10 @@ public abstract class TestCollection extends TestObject {
/**
- * Tests {@link Collection#addAll}.
+ * Tests {@link Collection#addAll(Collection)}.
*/
public void testCollectionAddAll() {
- if (!supportsAdd()) return;
+ if (!isAddSupported()) return;
resetEmpty();
Object[] elements = getFullElements();
@@ -394,7 +488,7 @@ public abstract class TestCollection extends TestObject {
}
assertEquals("Size should increase after addAll",
size + elements.length, collection.size());
-
+
resetFull();
size = collection.size();
r = collection.addAll(Arrays.asList(getFullElements()));
@@ -404,54 +498,68 @@ public abstract class TestCollection extends TestObject {
assertTrue("Size should increase if addAll returns true",
size < collection.size());
} else {
- assertTrue("Size should not change if addAll returns false",
- size == collection.size());
+ assertEquals("Size should not change if addAll returns false",
+ size, collection.size());
}
}
/**
- * If {@link #supportsAdd} returns false, tests that add operations
+ * If {@link #isAddSupported()} returns false, tests that add operations
* raise UnsupportedOperationException.
*/
public void testUnsupportedAdd() {
- if (supportsAdd()) return;
+ if (isAddSupported()) return;
+ resetEmpty();
try {
- makeCollection().add(new Object());
+ collection.add(new Object());
fail("Emtpy collection should not support add.");
} catch (UnsupportedOperationException e) {
// expected
}
+ // make sure things didn't change even if the expected exception was
+ // thrown.
+ verify();
try {
- makeCollection().addAll(Arrays.asList(getFullElements()));
+ collection.addAll(Arrays.asList(getFullElements()));
fail("Emtpy collection should not support addAll.");
} catch (UnsupportedOperationException e) {
// expected
}
+ // make sure things didn't change even if the expected exception was
+ // thrown.
+ verify();
+ resetFull();
try {
- makeFullCollection().add(new Object());
+ collection.add(new Object());
fail("Full collection should not support add.");
} catch (UnsupportedOperationException e) {
// expected
}
-
+ // make sure things didn't change even if the expected exception was
+ // thrown.
+ verify();
+
try {
- makeFullCollection().addAll(Arrays.asList(getOtherElements()));
+ collection.addAll(Arrays.asList(getOtherElements()));
fail("Full collection should not support addAll.");
} catch (UnsupportedOperationException e) {
// expected
}
+ // make sure things didn't change even if the expected exception was
+ // thrown.
+ verify();
}
/**
- * Test {@link Collection#clear}.
+ * Test {@link Collection#clear()}.
*/
public void testCollectionClear() {
- if (!supportsRemove()) return;
+ if (!isRemoveSupported()) return;
resetEmpty();
collection.clear(); // just to make sure it doesn't raise anything
@@ -465,158 +573,116 @@ public abstract class TestCollection extends TestObject {
/**
- * Tests {@link Collection#contains}.
+ * Tests {@link Collection#contains(Object)}.
*/
public void testCollectionContains() {
- Collection c = makeCollection();
- ArrayList elements = new ArrayList();
- elements.addAll(Arrays.asList(getFullElements()));
- elements.addAll(Arrays.asList(getOtherElements()));
- Iterator iter = elements.iterator();
- while (iter.hasNext()) {
- assertTrue("Empty collection shouldn't contain element",
- !c.contains(iter.next()));
+ Object[] elements;
+
+ resetEmpty();
+ elements = getFullElements();
+ for(int i = 0; i < elements.length; i++) {
+ assertTrue("Empty collection shouldn'y contain element",
+ !collection.contains(elements[i]));
}
-
- elements.clear();
- elements.addAll(Arrays.asList(getFullElements()));
- c = makeFullCollection();
- iter = elements.iterator();
- while (iter.hasNext()) {
- Object o = iter.next();
- assertTrue("Full collection should contain element " + o,
- c.contains(o));
+ // make sure calls to "contains" don't change anything
+ verify();
+
+ elements = getOtherElements();
+ for(int i = 0; i < elements.length; i++) {
+ assertTrue("Empty collection shouldn'y contain element",
+ !collection.contains(elements[i]));
}
-
- elements.clear();
- elements.addAll(Arrays.asList(getOtherElements()));
- iter = elements.iterator();
- while (iter.hasNext()) {
+ // make sure calls to "contains" don't change anything
+ verify();
+
+ resetFull();
+ elements = getFullElements();
+ for(int i = 0; i < elements.length; i++) {
+ assertTrue("Full collection should contain element.",
+ collection.contains(elements[i]));
+ }
+ // make sure calls to "contains" don't change anything
+ verify();
+
+ resetFull();
+ elements = getOtherElements();
+ for(int i = 0; i < elements.length; i++) {
assertTrue("Full collection shouldn't contain element",
- !c.contains(iter.next()));
+ !collection.contains(elements[i]));
}
}
/**
- * Tests {@link Collection#containsAll}.
+ * Tests {@link Collection#containsAll(Collection)}.
*/
public void testCollectionContainsAll() {
- Collection c = makeCollection();
+ resetEmpty();
Collection col = new HashSet();
assertTrue("Every Collection should contain all elements of an " +
- "empty Collection.",c.containsAll(col));
+ "empty Collection.", collection.containsAll(col));
col.addAll(Arrays.asList(getOtherElements()));
assertTrue("Empty Collection shouldn't contain all elements of " +
- "a non-empty Collection.",!c.containsAll(col));
-
- c = makeFullCollection();
+ "a non-empty Collection.", !collection.containsAll(col));
+ // make sure calls to "containsAll" don't change anything
+ verify();
+
+ resetFull();
assertTrue("Full collection shouldn't contain other elements",
- !c.containsAll(col));
+ !collection.containsAll(col));
col.clear();
col.addAll(Arrays.asList(getFullElements()));
- assertTrue("Full collection should containAll full elements " +
- c + " " + col, c.containsAll(col));
+ assertTrue("Full collection should containAll full elements",
+ collection.containsAll(col));
+ // make sure calls to "containsAll" don't change anything
+ verify();
+
col = Arrays.asList(getFullElements()).subList(2, 5);
assertTrue("Full collection should containAll partial full " +
- "elements", c.containsAll(col));
+ "elements", collection.containsAll(col));
assertTrue("Full collection should containAll itself",
- c.containsAll(c));
+ collection.containsAll(collection));
+
+ // make sure calls to "containsAll" don't change anything
+ verify();
col = new ArrayList();
col.addAll(Arrays.asList(getFullElements()));
col.addAll(Arrays.asList(getFullElements()));
assertTrue("Full collection should containAll duplicate full " +
- "elements", c.containsAll(col));
+ "elements", collection.containsAll(col));
+
+ // make sure calls to "containsAll" don't change anything
+ verify();
}
-
- /* ---------------------------------
-
- // Got rid of the equals() tests -- Collection doesn't define
- // any semantics for equals, and recommends you use reference-based
- // default behavior of Object.equals. (And a test for that already
- // exists in TestObject). Tests for equality of lists,
- // sets and bags will have to be written in test subclasses.
-
- public void testCollectionEqualsSelf() {
- Collection c = makeCollection();
- assertEquals("A Collection should equal itself",c,c);
- tryToAdd(c,"element1");
- assertEquals("A Collection should equal itself",c,c);
- tryToAdd(c,"element1");
- tryToAdd(c,"element2");
- assertEquals("A Collection should equal itself",c,c);
- }
-
- public void testCollectionEquals() {
- Collection c1 = makeCollection();
- Collection c2 = makeCollection();
- assertEquals("Empty Collections are equal.",c1,c2);
-
- boolean added1_1 = tryToAdd(c1,"element1");
- if(added1_1) {
- assertTrue("Empty Collection not equal to non-empty Collection.",!c2.equals(c1));
- assertTrue("Non-empty Collection not equal to empty Collection.",!c1.equals(c2));
- }
-
- boolean added1_2 = tryToAdd(c2,"element1");
- assertEquals("After duplicate adds, Collections should be equal.",c1,c2);
-
- boolean added2_1 = tryToAdd(c1,"element2");
- boolean added3_2 = tryToAdd(c2,"element3");
- if(added2_1 || added3_2) {
- assertTrue("Should not be equal.",!c1.equals(c2));
- }
- }
-
- public void testCollectionHashCodeEqualsSelfHashCode() {
- Collection c = makeCollection();
- assertEquals("hashCode should be repeatable",c.hashCode(),c.hashCode());
- tryToAdd(c,"element1");
- assertEquals("after add, hashCode should be repeatable",c.hashCode(),c.hashCode());
- }
-
- public void testCollectionHashCodeEqualsContract() {
- Collection c1 = makeCollection();
- if(c1.equals(c1)) {
- assertEquals("[1] When two objects are equal, their hashCodes should be also.",c1.hashCode(),c1.hashCode());
- }
- Collection c2 = makeCollection();
- if(c1.equals(c2)) {
- assertEquals("[2] When two objects are equal, their hashCodes should be also.",c1.hashCode(),c2.hashCode());
- }
- tryToAdd(c1,"element1");
- tryToAdd(c2,"element1");
- if(c1.equals(c2)) {
- assertEquals("[3] When two objects are equal, their hashCodes should be also.",c1.hashCode(),c2.hashCode());
- }
- }
-
- -------------------------- */
-
-
/**
- * Tests {@link Collection#isEmpty}.
+ * Tests {@link Collection#isEmpty()}.
*/
public void testCollectionIsEmpty() {
- Collection c = makeCollection();
- assertTrue("New Collection should be empty.",c.isEmpty());
+ resetEmpty();
+ assertEquals("New Collection should be empty.",
+ true, collection.isEmpty());
+ // make sure calls to "isEmpty() don't change anything
+ verify();
- c = makeFullCollection();
- assertTrue("Full collection shouldn't be empty", !c.isEmpty());
+ resetFull();
+ assertEquals("Full collection shouldn't be empty",
+ false, collection.isEmpty());
+ // make sure calls to "isEmpty() don't change anything
+ verify();
}
/**
- * Tests the read-only functionality of {@link Collection#iterator}.
+ * Tests the read-only functionality of {@link Collection#iterator()}.
*/
public void testCollectionIterator() {
- Collection c = makeCollection();
- Iterator it1 = c.iterator();
- assertTrue("Iterator for empty Collection shouldn't have next.",
- !it1.hasNext());
+ resetEmpty();
+ Iterator it1 = collection.iterator();
+ assertEquals("Iterator for empty Collection shouldn't have next.",
+ false, it1.hasNext());
try {
it1.next();
fail("Iterator at end of Collection should throw " +
@@ -624,10 +690,12 @@ public abstract class TestCollection extends TestObject {
} catch(NoSuchElementException e) {
// expected
}
-
- c = makeFullCollection();
- it1 = c.iterator();
- for (int i = 0; i < c.size(); i++) {
+ // make sure nothing has changed after non-modification
+ verify();
+
+ resetFull();
+ it1 = collection.iterator();
+ for (int i = 0; i < collection.size(); i++) {
assertTrue("Iterator for full collection should haveNext",
it1.hasNext());
it1.next();
@@ -635,11 +703,11 @@ public abstract class TestCollection extends TestObject {
assertTrue("Iterator should be finished", !it1.hasNext());
ArrayList list = new ArrayList();
- it1 = c.iterator();
- for (int i = 0; i < c.size(); i++) {
+ it1 = collection.iterator();
+ for (int i = 0; i < collection.size(); i++) {
Object next = it1.next();
assertTrue("Collection should contain element returned by " +
- "its iterator", c.contains(next));
+ "its iterator", collection.contains(next));
list.add(next);
}
try {
@@ -649,32 +717,16 @@ public abstract class TestCollection extends TestObject {
} catch (NoSuchElementException e) {
// expected
}
-
- /*
- Removed -- TestSet, TestBag and TestList should do this
- Collection elements = Arrays.asList(getFullElements());
- if (c instanceof Set) {
- assertTrue("Iterator should return unique elements",
- new HashSet(list).equals(new HashSet(elements)));
- }
- if (c instanceof List) {
- assertTrue("Iterator should return sequenced elements",
- list.equals(elements));
- }
- if (c instanceof Bag) {
- assertTrue("Iterator should return duplicate elements",
- new HashBag(list).equals(new HashBag(elements)));
- }
-
- */
+ // make sure nothing has changed after non-modification
+ verify();
}
/**
- * Tests removals from {@link Collection#iterator}.
+ * Tests removals from {@link Collection#iterator()}.
*/
public void testCollectionIteratorRemove() {
- if (!supportsRemove()) return;
+ if (!isRemoveSupported()) return;
resetEmpty();
try {
@@ -683,6 +735,7 @@ public abstract class TestCollection extends TestObject {
} catch (IllegalStateException e) {
// expected
}
+ verify();
try {
Iterator iter = collection.iterator();
@@ -693,33 +746,31 @@ public abstract class TestCollection extends TestObject {
} catch (IllegalStateException e) {
// expected
}
+ verify();
resetFull();
int size = collection.size();
- HashBag bag = new HashBag(collection);
Iterator iter = collection.iterator();
while (iter.hasNext()) {
Object o = iter.next();
- bag.remove(o, 1);
iter.remove();
- if ((collection instanceof Set) || (collection instanceof List) ||
- (collection instanceof Bag)) {
- // Unfortunately, we can't get away with this for a straight
- // collection that might have unordered duplicate elements,
- // but it works for Bag, Set and List.
+
+ // if the elements aren't distinguishable, we can just remove a
+ // matching element from the confirmed collection and verify
+ // contents are still the same. Otherwise, we don't have the
+ // ability to distinguish the elements and determine which to
+ // remove from the confirmed collection (in which case, we don't
+ // verify because we don't know how).
+ //
+ // see areEqualElementsDistinguishable()
+ if(!areEqualElementsDistinguishable()) {
confirmed.remove(o);
verify();
}
+
size--;
- assertEquals("Collection should shrink after iterator.remove",
- collection.size(), size);
- if (bag.getCount(o) == 0) {
- assertTrue("Collection shouldn't contain element after " +
- "iterator.remove", !collection.contains(o));
- } else {
- assertTrue("Collection should still contain element after " +
- "iterator.remove", collection.contains(o));
- }
+ assertEquals("Collection should shrink by one after " +
+ "iterator.remove", size, collection.size());
}
assertTrue("Collection should be empty after iterator purge",
collection.isEmpty());
@@ -738,10 +789,10 @@ public abstract class TestCollection extends TestObject {
/**
- * Tests {@link Collection#remove}.
+ * Tests {@link Collection#remove(Object)}.
*/
public void testCollectionRemove() {
- if (!supportsRemove()) return;
+ if (!isRemoveSupported()) return;
resetEmpty();
Object[] elements = getFullElements();
@@ -763,34 +814,33 @@ public abstract class TestCollection extends TestObject {
int size = collection.size();
for (int i = 0; i < elements.length; i++) {
resetFull();
- HashBag bag = new HashBag(collection);
assertTrue("Collection should remove extant element",
collection.remove(elements[i]));
- if ((collection instanceof Set) || (collection instanceof List) ||
- (collection instanceof Bag)) {
- // Can't do this for unordered straight collection...
+
+ // if the elements aren't distinguishable, we can just remove a
+ // matching element from the confirmed collection and verify
+ // contents are still the same. Otherwise, we don't have the
+ // ability to distinguish the elements and determine which to
+ // remove from the confirmed collection (in which case, we don't
+ // verify because we don't know how).
+ //
+ // see areEqualElementsDistinguishable()
+ if(!areEqualElementsDistinguishable()) {
confirmed.remove(elements[i]);
verify();
}
+
assertEquals("Collection should shrink after remove",
size - 1, collection.size());
- bag.remove(elements[i], 1);
- if (bag.getCount(elements[i]) == 0) {
- assertTrue("Collection shouldn't contain removed element",
- !collection.contains(elements[i]));
- } else {
- assertTrue("Collection should still contain removed element",
- collection.contains(elements[i]));
- }
}
}
/**
- * Tests {@link Collection#removeAll}.
+ * Tests {@link Collection#removeAll(Collection)}.
*/
public void testCollectionRemoveAll() {
- if (!supportsRemove()) return;
+ if (!isRemoveSupported()) return;
resetEmpty();
assertTrue("Emtpy collection removeAll should return false for " +
@@ -802,7 +852,7 @@ public abstract class TestCollection extends TestObject {
"nonempty input",
!collection.removeAll(new ArrayList(collection)));
verify();
-
+
resetFull();
assertTrue("Full collection removeAll should return false for " +
"empty input",
@@ -839,10 +889,10 @@ public abstract class TestCollection extends TestObject {
/**
- * Tests {@link Collection#retainAll}.
+ * Tests {@link Collection#retainAll(Collection)}.
*/
public void testCollectionRetainAll() {
- if (!supportsRemove()) return;
+ if (!isRemoveSupported()) return;
resetEmpty();
List elements = Arrays.asList(getFullElements());
@@ -901,14 +951,15 @@ public abstract class TestCollection extends TestObject {
/**
- * Tests {@link Collection#size}.
+ * Tests {@link Collection#size()}.
*/
public void testCollectionSize() {
- Collection c = makeCollection();
- assertEquals("Size of new Collection is 0.",0,c.size());
+ resetEmpty();
+ assertEquals("Size of new Collection is 0.", 0, collection.size());
- c = makeFullCollection();
- assertTrue("Size of full collection should be nonzero", c.size() != 0);
+ resetFull();
+ assertTrue("Size of full collection should be greater than zero",
+ collection.size() > 0);
}
@@ -916,22 +967,45 @@ public abstract class TestCollection extends TestObject {
* Tests {@link Collection#toArray()}.
*/
public void testCollectionToArray() {
- Collection c = makeCollection();
+ resetEmpty();
assertEquals("Empty Collection should return empty array for toArray",
- 0, c.toArray().length);
+ 0, collection.toArray().length);
- c = makeFullCollection();
- HashBag bag = new HashBag(c);
- Object[] array = c.toArray();
+ resetFull();
+ Object[] array = collection.toArray();
assertEquals("Full collection toArray should be same size as " +
- "collection", array.length, c.size());
+ "collection", array.length, collection.size());
+ Object[] confirmedArray = confirmed.toArray();
+ assertEquals("length of array from confirmed collection should " +
+ "match the length of the collection's array",
+ confirmedArray.length, array.length);
+ boolean[] matched = new boolean[array.length];
+
for (int i = 0; i < array.length; i++) {
assertTrue("Collection should contain element in toArray",
- c.contains(array[i]));
- bag.remove(array[i], 1);
+ collection.contains(array[i]));
+
+ boolean match = false;
+ // find a match in the confirmed array
+ for(int j = 0; j < array.length; j++) {
+ // skip already matched
+ if(matched[j]) continue;
+ if(array[i] == confirmedArray[j] ||
+ (array[i] != null && array[i].equals(confirmedArray[j]))) {
+ matched[j] = true;
+ match = true;
+ break;
+ }
+ }
+ if(!match) {
+ fail("element " + i + " in returned array should be found " +
+ "in the confirmed collection's array");
+ }
+ }
+ for(int i = 0; i < matched.length; i++) {
+ assertEquals("Collection should return all its elements in " +
+ "toArray", true, matched[i]);
}
- assertTrue("Collection should return all its elements in toArray",
- bag.isEmpty());
}
@@ -939,29 +1013,32 @@ public abstract class TestCollection extends TestObject {
* Tests {@link Collection.toArray(Object[])}.
*/
public void testCollectionToArray2() {
- Collection c = makeCollection();
+ resetEmpty();
Object[] a = new Object[] { new Object(), null, null };
- Object[] array = c.toArray(a);
+ Object[] array = collection.toArray(a);
assertEquals("Given array shouldn't shrink", array, a);
assertEquals("Last element should be set to null", a[0], null);
-
- c = makeFullCollection();
+ verify();
+
+ resetFull();
try {
- array = c.toArray(new Void[0]);
+ array = collection.toArray(new Void[0]);
fail("toArray(new Void[0]) should raise ArrayStore");
} catch (ArrayStoreException e) {
// expected
}
+ verify();
try {
- array = c.toArray(null);
+ array = collection.toArray(null);
fail("toArray(null) should raise NPE");
} catch (NullPointerException e) {
// expected
}
+ verify();
- array = c.toArray(new Object[0]);
- a = c.toArray();
+ array = collection.toArray(new Object[0]);
+ a = collection.toArray();
assertEquals("toArrays should be equal",
Arrays.asList(array), Arrays.asList(a));
@@ -975,11 +1052,13 @@ public abstract class TestCollection extends TestObject {
Class cl = (Class)classes.iterator().next();
a = (Object[])Array.newInstance(cl, 0);
- array = c.toArray(a);
+ array = collection.toArray(a);
assertEquals("toArray(Object[]) should return correct array type",
a.getClass(), array.getClass());
assertEquals("type-specific toArrays should be equal",
- Arrays.asList(array), Arrays.asList(c.toArray()));
+ Arrays.asList(array),
+ Arrays.asList(collection.toArray()));
+ verify();
}
@@ -987,58 +1066,66 @@ public abstract class TestCollection extends TestObject {
* Tests
toString
on a collection.
*/
public void testCollectionToString() {
- Collection c = makeCollection();
- assertTrue("toString shouldn't return null", c.toString() != null);
+ resetEmpty();
+ assertTrue("toString shouldn't return null",
+ collection.toString() != null);
- c = makeFullCollection();
- assertTrue("toString shouldn't return null", c.toString() != null);
+ resetFull();
+ assertTrue("toString shouldn't return null",
+ collection.toString() != null);
}
/**
- * If supportsRemove() returns false, tests to see that remove
+ * If isRemoveSupported() returns false, tests to see that remove
* operations raise an UnsupportedOperationException.
*/
public void testUnsupportedRemove() {
- if (supportsRemove()) return;
+ if (isRemoveSupported()) return;
+ resetEmpty();
try {
- makeCollection().clear();
+ collection.clear();
fail("clear should raise UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
// expected
}
+ verify();
try {
- makeCollection().remove(null);
+ collection.remove(null);
fail("remove should raise UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
// expected
}
+ verify();
try {
- makeCollection().removeAll(null);
+ collection.removeAll(null);
fail("removeAll should raise UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
// expected
}
+ verify();
try {
- makeCollection().retainAll(null);
+ collection.retainAll(null);
fail("removeAll should raise UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
// expected
}
+ verify();
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iterator = c.iterator();
+ Iterator iterator = collection.iterator();
iterator.next();
iterator.remove();
fail("iterator.remove should raise UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
// expected
}
+ verify();
}
@@ -1047,34 +1134,39 @@ public abstract class TestCollection extends TestObject {
* Tests that the collection's iterator is fail-fast.
*/
public void testCollectionIteratorFailFast() {
- if (supportsAdd()) {
+ if (isAddSupported()) {
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iter = c.iterator();
- c.add(getOtherElements()[0]);
+ Iterator iter = collection.iterator();
+ Object o = getOtherElements()[0];
+ collection.add(o);
+ confirmed.add(o);
iter.next();
fail("next after add should raise ConcurrentModification");
} catch (ConcurrentModificationException e) {
// expected
}
+ verify();
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iter = c.iterator();
- c.addAll(Arrays.asList(getOtherElements()));
+ Iterator iter = collection.iterator();
+ collection.addAll(Arrays.asList(getOtherElements()));
+ confirmed.addAll(Arrays.asList(getOtherElements()));
iter.next();
fail("next after addAll should raise ConcurrentModification");
} catch (ConcurrentModificationException e) {
// expected
}
+ verify();
}
- if (!supportsRemove()) return;
+ if (!isRemoveSupported()) return;
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iter = c.iterator();
- c.clear();
+ Iterator iter = collection.iterator();
+ collection.clear();
iter.next();
fail("next after clear should raise ConcurrentModification");
} catch (ConcurrentModificationException e) {
@@ -1083,30 +1175,32 @@ public abstract class TestCollection extends TestObject {
// (also legal given spec)
}
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iter = c.iterator();
- c.remove(getFullElements()[0]);
+ Iterator iter = collection.iterator();
+ collection.remove(getFullElements()[0]);
iter.next();
fail("next after remove should raise ConcurrentModification");
} catch (ConcurrentModificationException e) {
// expected
}
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iter = c.iterator();
- c.removeAll(Arrays.asList(getFullElements()).subList(2,5));
+ Iterator iter = collection.iterator();
+ List sublist = Arrays.asList(getFullElements()).subList(2,5);
+ collection.removeAll(sublist);
iter.next();
fail("next after removeAll should raise ConcurrentModification");
} catch (ConcurrentModificationException e) {
// expected
}
+ resetFull();
try {
- Collection c = makeFullCollection();
- Iterator iter = c.iterator();
- c.retainAll(Arrays.asList(getFullElements()).subList(2,5));
+ Iterator iter = collection.iterator();
+ List sublist = Arrays.asList(getFullElements()).subList(2,5);
+ collection.retainAll(sublist);
iter.next();
fail("next after retainAll should raise ConcurrentModification");
} catch (ConcurrentModificationException e) {
@@ -1122,6 +1216,10 @@ public abstract class TestCollection extends TestObject {
*
* Fails any Throwable except UnsupportedOperationException,
* ClassCastException, or IllegalArgumentException is thrown.
+ *
+ * @deprecated explicitly check for allowed exceptions rather than using
+ * this method to assume any of UnsupportedOperationException,
+ * ClassCaseException, or IllegalArgumentException are allowed.
*/
protected boolean tryToAdd(Collection c,Object obj) {
// FIXME: Delete this method after TestList is patched
@@ -1144,7 +1242,7 @@ public abstract class TestCollection extends TestObject {
/**
* Returns a list of elements suitable for return by
- * {@link getFullElements}. The array returned by this method
+ * {@link getFullElements()}. The array returned by this method
* does not include null, but does include a variety of objects
* of different types. Override getFullElements to return
* the results of this method if your collection does not support
@@ -1176,7 +1274,7 @@ public abstract class TestCollection extends TestObject {
/**
* Returns the default list of objects returned by
- * {@link getOtherElements}. Includes many objects
+ * {@link getOtherElements()}. Includes many objects
* of different types.
*/
public static Object[] getOtherNonNullElements() {
@@ -1197,7 +1295,7 @@ public abstract class TestCollection extends TestObject {
/**
* Returns a list of string elements suitable for return by
- * {@link getFullElements}. Override getFullElements to return
+ * {@link getFullElements()}. Override getFullElements to return
* the results of this method if your collection does not support
* heterogenous elements or the null element.
*/
@@ -1211,7 +1309,7 @@ public abstract class TestCollection extends TestObject {
/**
* Returns a list of string elements suitable for return by
- * {@link getOtherElements}. Override getOtherElements to return
+ * {@link getOtherElements()}. Override getOtherElements to return
* the results of this method if your collection does not support
* heterogenous elements or the null element.
*/