| /* | |
| * Copyright 1999-2004 The Apache Software Foundation | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package org.apache.commons.collections; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.Collections; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.NoSuchElementException; | |
| import java.util.Set; | |
| /** | |
| * Tests base {@link java.util.Collection} methods and contracts. | |
| * <p> | |
| * 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 | |
| * override some of the additional protected methods as well:<P> | |
| * | |
| * <B>Element Population Methods</B><P> | |
| * | |
| * Override these if your collection restricts what kind of elements are | |
| * allowed (for instance, if <Code>null</Code> is not permitted): | |
| * <UL> | |
| * <Li>{@link #getFullElements()} | |
| * <Li>{@link #getOtherElements()} | |
| * </UL> | |
| * | |
| * <B>Supported Operation Methods</B><P> | |
| * | |
| * Override these if your collection doesn't support certain operations: | |
| * <UL> | |
| * <LI>{@link #isAddSuppoted()} | |
| * <LI>{@link #isRemoveSupported()} | |
| * <li>{@link #areEqualElementsDistinguishable()} | |
| * </UL> | |
| * | |
| * <B>Fixture Methods</B><P> | |
| * | |
| * 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 | |
| * <I>confirmed</I> collection implementation. A confirmed collection | |
| * implementation is something like <Code>java.util.ArrayList</Code>, 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 <Code>equals</Code> 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.<P> | |
| * | |
| * 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, | |
| * so that tests can proceed from a known state.<P> | |
| * | |
| * 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 | |
| * additional verifications. For instance, when testing the collection | |
| * 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: | |
| * <UL> | |
| * <LI>{@link #makeConfirmedCollection()} | |
| * <LI>{@link #makeConfirmedFullCollection()} | |
| * </UL> | |
| * | |
| * Those methods should provide a confirmed collection implementation | |
| * that's compatible with your collection implementation.<P> | |
| * | |
| * If you're extending {@link TestList}, {@link TestSet}, | |
| * or {@link TestBag}, you probably don't have to worry about the | |
| * above methods, because those three classes already override the methods | |
| * to provide standard JDK confirmed collections.<P> | |
| * | |
| * <B>Other notes</B><P> | |
| * | |
| * 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 | |
| * 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.<P> | |
| * | |
| * @author Rodney Waldhoff | |
| * @author Paul Jack | |
| * @author <a href="mailto:mas@apache.org">Michael A. Smith</a> | |
| * @version $Id: TestCollection.java,v 1.9.2.1 2004/05/22 12:14:05 scolebourne 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. | |
| /** | |
| * A collection instance that will be used for testing. | |
| */ | |
| protected Collection collection; | |
| /** | |
| * Confirmed collection. This is an instance of a collection that is | |
| * confirmed to conform exactly to the java.util.Collection contract. | |
| * Modification operations are tested by performing a mod on your | |
| * collection, performing the exact same mod on an equivalent confirmed | |
| * collection, and then calling verify() to make sure your collection | |
| * still matches the confirmed collection. | |
| */ | |
| protected Collection confirmed; | |
| /** | |
| * Resets the {@link #collection} and {@link #confirmed} fields to empty | |
| * collections. Invoke this method before performing a modification | |
| * test. | |
| */ | |
| protected void resetEmpty() { | |
| this.collection = makeCollection(); | |
| this.confirmed = makeConfirmedCollection(); | |
| } | |
| /** | |
| * Resets the {@link #collection} and {@link #confirmed} fields to full | |
| * collections. Invoke this method before performing a modification | |
| * test. | |
| */ | |
| protected void resetFull() { | |
| this.collection = makeFullCollection(); | |
| 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. | |
| * | |
| * <P>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. | |
| * | |
| * <P>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", | |
| confirmedSize, collection.size()); | |
| assertEquals("Collection isEmpty() result should match confirmed " + | |
| " collection's", | |
| confirmed.isEmpty(), collection.isEmpty()); | |
| // 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"); | |
| } | |
| } | |
| } | |
| /** | |
| * Returns a confirmed empty collection. | |
| * For instance, a {@link java.util.ArrayList} for lists or a | |
| * {@link java.util.HashSet} for sets. | |
| * | |
| * @return a confirmed empty collection | |
| */ | |
| protected abstract Collection makeConfirmedCollection(); | |
| /** | |
| * Returns a confirmed full collection. | |
| * For instance, a {@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()}. | |
| * | |
| * @return a confirmed full collection | |
| */ | |
| protected abstract Collection makeConfirmedFullCollection(); | |
| /** | |
| * Returns true if the collections produced by | |
| * {@link #makeCollection()} and {@link #makeFullCollection()} | |
| * support the <Code>add</Code> and <Code>addAll</Code> | |
| * operations.<P> | |
| * Default implementation returns true. Override if your collection | |
| * class does not support add or addAll. | |
| */ | |
| protected boolean isAddSupported() { | |
| return true; | |
| } | |
| /** | |
| * Returns true if the collections produced by | |
| * {@link #makeCollection()} and {@link #makeFullCollection()} | |
| * support the <Code>remove</Code>, <Code>removeAll</Code>, | |
| * <Code>retainAll</Code>, <Code>clear</Code> and | |
| * <Code>iterator().remove()</Code> methods. | |
| * Default implementation returns true. Override if your collection | |
| * class does not support removal operations. | |
| */ | |
| protected boolean isRemoveSupported() { | |
| return true; | |
| } | |
| /** | |
| * Returns an array of objects that are contained in a collection | |
| * produced by {@link #makeFullCollection()}. Every element in the | |
| * returned array <I>must</I> be an element in a full collection.<P> | |
| * 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 <I>must</I> override | |
| * this method to reflect the contents of a full collection. | |
| */ | |
| protected Object[] getFullElements() { | |
| ArrayList list = new ArrayList(); | |
| list.addAll(Arrays.asList(getFullNonNullElements())); | |
| list.add(4, null); | |
| return list.toArray(); | |
| } | |
| /** | |
| * Returns an array of elements that are <I>not</I> contained in a | |
| * full collection. Every element in the returned array must | |
| * 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 | |
| * certain kinds of elements, you should override this method. | |
| */ | |
| protected Object[] getOtherElements() { | |
| return getOtherNonNullElements(); | |
| } | |
| /** | |
| * Returns a new, empty {@link Collection} to be used for testing. | |
| */ | |
| protected abstract Collection makeCollection(); | |
| /** | |
| * 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, | |
| * simply invokes <Code>addAll</Code> on an empty collection with | |
| * the results of {@link #getFullElements()}. Override this default | |
| * if your collection doesn't support addAll. | |
| */ | |
| protected Collection makeFullCollection() { | |
| Collection c = makeCollection(); | |
| c.addAll(Arrays.asList(getFullElements())); | |
| return c; | |
| } | |
| /** | |
| * Returns an empty collection for Object tests. | |
| */ | |
| public Object makeObject() { | |
| return makeCollection(); | |
| } | |
| /** | |
| * Tests {@link Collection#add(Object)}. | |
| */ | |
| public void testCollectionAdd() { | |
| if (!isAddSupported()) return; | |
| Object[] elements = getFullElements(); | |
| for (int i = 0; i < elements.length; i++) { | |
| resetEmpty(); | |
| boolean r = collection.add(elements[i]); | |
| confirmed.add(elements[i]); | |
| verify(); | |
| assertTrue("Empty collection changed after add", r); | |
| assertTrue("Collection size is 1 after first add", | |
| collection.size() == 1); | |
| } | |
| resetEmpty(); | |
| int size = 0; | |
| for (int i = 0; i < elements.length; i++) { | |
| boolean r = collection.add(elements[i]); | |
| confirmed.add(elements[i]); | |
| verify(); | |
| if (r) size++; | |
| assertEquals("Collection size should grow after add", | |
| size, collection.size()); | |
| assertTrue("Collection should contain added element", | |
| collection.contains(elements[i])); | |
| } | |
| } | |
| /** | |
| * Tests {@link Collection#addAll(Collection)}. | |
| */ | |
| public void testCollectionAddAll() { | |
| if (!isAddSupported()) return; | |
| resetEmpty(); | |
| Object[] elements = getFullElements(); | |
| boolean r = collection.addAll(Arrays.asList(elements)); | |
| confirmed.addAll(Arrays.asList(elements)); | |
| verify(); | |
| assertTrue("Empty collection should change after addAll", r); | |
| for (int i = 0; i < elements.length; i++) { | |
| assertTrue("Collection should contain added element", | |
| collection.contains(elements[i])); | |
| } | |
| resetFull(); | |
| int size = collection.size(); | |
| elements = getOtherElements(); | |
| r = collection.addAll(Arrays.asList(elements)); | |
| confirmed.addAll(Arrays.asList(elements)); | |
| verify(); | |
| assertTrue("Full collection should change after addAll", r); | |
| for (int i = 0; i < elements.length; i++) { | |
| assertTrue("Full collection should contain added element", | |
| collection.contains(elements[i])); | |
| } | |
| assertEquals("Size should increase after addAll", | |
| size + elements.length, collection.size()); | |
| resetFull(); | |
| size = collection.size(); | |
| r = collection.addAll(Arrays.asList(getFullElements())); | |
| confirmed.addAll(Arrays.asList(getFullElements())); | |
| verify(); | |
| if (r) { | |
| assertTrue("Size should increase if addAll returns true", | |
| size < collection.size()); | |
| } else { | |
| assertEquals("Size should not change if addAll returns false", | |
| size, collection.size()); | |
| } | |
| } | |
| /** | |
| * If {@link #isAddSupported()} returns false, tests that add operations | |
| * raise <Code>UnsupportedOperationException. | |
| */ | |
| public void testUnsupportedAdd() { | |
| if (isAddSupported()) return; | |
| resetEmpty(); | |
| try { | |
| 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 { | |
| 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 { | |
| 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 { | |
| 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()}. | |
| */ | |
| public void testCollectionClear() { | |
| if (!isRemoveSupported()) return; | |
| resetEmpty(); | |
| collection.clear(); // just to make sure it doesn't raise anything | |
| verify(); | |
| resetFull(); | |
| collection.clear(); | |
| confirmed.clear(); | |
| verify(); | |
| } | |
| /** | |
| * Tests {@link Collection#contains(Object)}. | |
| */ | |
| public void testCollectionContains() { | |
| Object[] elements; | |
| resetEmpty(); | |
| elements = getFullElements(); | |
| for(int i = 0; i < elements.length; i++) { | |
| assertTrue("Empty collection shouldn'y contain element", | |
| !collection.contains(elements[i])); | |
| } | |
| // 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])); | |
| } | |
| // 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", | |
| !collection.contains(elements[i])); | |
| } | |
| } | |
| /** | |
| * Tests {@link Collection#containsAll(Collection)}. | |
| */ | |
| public void testCollectionContainsAll() { | |
| resetEmpty(); | |
| Collection col = new HashSet(); | |
| assertTrue("Every Collection should contain all elements of an " + | |
| "empty Collection.", collection.containsAll(col)); | |
| col.addAll(Arrays.asList(getOtherElements())); | |
| assertTrue("Empty Collection shouldn't contain all elements of " + | |
| "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", | |
| !collection.containsAll(col)); | |
| col.clear(); | |
| col.addAll(Arrays.asList(getFullElements())); | |
| assertTrue("Full collection should containAll full elements", | |
| collection.containsAll(col)); | |
| // make sure calls to "containsAll" don't change anything | |
| verify(); | |
| assertTrue("Full collection should containAll itself", | |
| 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", collection.containsAll(col)); | |
| // make sure calls to "containsAll" don't change anything | |
| verify(); | |
| } | |
| /** | |
| * Tests {@link Collection#isEmpty()}. | |
| */ | |
| public void testCollectionIsEmpty() { | |
| resetEmpty(); | |
| assertEquals("New Collection should be empty.", | |
| true, collection.isEmpty()); | |
| // make sure calls to "isEmpty() don't change anything | |
| verify(); | |
| 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()}. | |
| */ | |
| public void testCollectionIterator() { | |
| 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 " + | |
| "NoSuchElementException when next is called."); | |
| } catch(NoSuchElementException e) { | |
| // expected | |
| } | |
| // 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(); | |
| } | |
| assertTrue("Iterator should be finished", !it1.hasNext()); | |
| ArrayList list = new ArrayList(); | |
| it1 = collection.iterator(); | |
| for (int i = 0; i < collection.size(); i++) { | |
| Object next = it1.next(); | |
| assertTrue("Collection should contain element returned by " + | |
| "its iterator", collection.contains(next)); | |
| list.add(next); | |
| } | |
| try { | |
| it1.next(); | |
| fail("iterator.next() should raise NoSuchElementException " + | |
| "after it finishes"); | |
| } catch (NoSuchElementException e) { | |
| // expected | |
| } | |
| // make sure nothing has changed after non-modification | |
| verify(); | |
| } | |
| /** | |
| * Tests removals from {@link Collection#iterator()}. | |
| */ | |
| public void testCollectionIteratorRemove() { | |
| if (!isRemoveSupported()) return; | |
| resetEmpty(); | |
| try { | |
| collection.iterator().remove(); | |
| fail("New iterator.remove should raise IllegalState"); | |
| } catch (IllegalStateException e) { | |
| // expected | |
| } | |
| verify(); | |
| try { | |
| Iterator iter = collection.iterator(); | |
| iter.hasNext(); | |
| iter.remove(); | |
| fail("New iterator.remove should raise IllegalState " + | |
| "even after hasNext"); | |
| } catch (IllegalStateException e) { | |
| // expected | |
| } | |
| verify(); | |
| resetFull(); | |
| int size = collection.size(); | |
| Iterator iter = collection.iterator(); | |
| while (iter.hasNext()) { | |
| Object o = iter.next(); | |
| iter.remove(); | |
| // 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 by one after " + | |
| "iterator.remove", size, collection.size()); | |
| } | |
| assertTrue("Collection should be empty after iterator purge", | |
| collection.isEmpty()); | |
| resetFull(); | |
| iter = collection.iterator(); | |
| iter.next(); | |
| iter.remove(); | |
| try { | |
| iter.remove(); | |
| fail("Second iter.remove should raise IllegalState"); | |
| } catch (IllegalStateException e) { | |
| // expected | |
| } | |
| } | |
| /** | |
| * Tests {@link Collection#remove(Object)}. | |
| */ | |
| public void testCollectionRemove() { | |
| if (!isRemoveSupported()) return; | |
| resetEmpty(); | |
| Object[] elements = getFullElements(); | |
| for (int i = 0; i < elements.length; i++) { | |
| assertTrue("Shouldn't remove nonexistent element", | |
| !collection.remove(elements[i])); | |
| verify(); | |
| } | |
| Object[] other = getOtherElements(); | |
| resetFull(); | |
| for (int i = 0; i < other.length; i++) { | |
| assertTrue("Shouldn't remove nonexistent other element", | |
| !collection.remove(other[i])); | |
| verify(); | |
| } | |
| int size = collection.size(); | |
| for (int i = 0; i < elements.length; i++) { | |
| resetFull(); | |
| assertTrue("Collection should remove extant element", | |
| collection.remove(elements[i])); | |
| // 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()); | |
| } | |
| } | |
| /** | |
| * Tests {@link Collection#removeAll(Collection)}. | |
| */ | |
| public void testCollectionRemoveAll() { | |
| if (!isRemoveSupported()) return; | |
| resetEmpty(); | |
| assertTrue("Emtpy collection removeAll should return false for " + | |
| "empty input", | |
| !collection.removeAll(Collections.EMPTY_SET)); | |
| verify(); | |
| assertTrue("Emtpy collection removeAll should return false for " + | |
| "nonempty input", | |
| !collection.removeAll(new ArrayList(collection))); | |
| verify(); | |
| resetFull(); | |
| assertTrue("Full collection removeAll should return false for " + | |
| "empty input", | |
| !collection.removeAll(Collections.EMPTY_SET)); | |
| verify(); | |
| assertTrue("Full collection removeAll should return false for " + | |
| "other elements", | |
| !collection.removeAll(Arrays.asList(getOtherElements()))); | |
| verify(); | |
| assertTrue("Full collection removeAll should return true for " + | |
| "full elements", | |
| collection.removeAll(new HashSet(collection))); | |
| confirmed.removeAll(new HashSet(confirmed)); | |
| verify(); | |
| resetFull(); | |
| int size = collection.size(); | |
| Object[] s = getFullElements(); | |
| List l = new ArrayList(); | |
| l.add(s[2]); l.add(s[3]); l.add(s[3]); | |
| assertTrue("Full collection removeAll should work", | |
| collection.removeAll(l)); | |
| confirmed.removeAll(l); | |
| verify(); | |
| assertTrue("Collection should shrink after removeAll", | |
| collection.size() < size); | |
| Iterator iter = l.iterator(); | |
| while (iter.hasNext()) { | |
| assertTrue("Collection shouldn't contain removed element", | |
| !collection.contains(iter.next())); | |
| } | |
| } | |
| /** | |
| * Tests {@link Collection#retainAll(Collection)}. | |
| */ | |
| public void testCollectionRetainAll() { | |
| if (!isRemoveSupported()) return; | |
| resetEmpty(); | |
| List elements = Arrays.asList(getFullElements()); | |
| List other = Arrays.asList(getOtherElements()); | |
| Set empty = new HashSet(); | |
| assertTrue("Empty retainAll() should return false", | |
| !collection.retainAll(empty)); | |
| verify(); | |
| assertTrue("Empty retainAll() should return false", | |
| !collection.retainAll(elements)); | |
| verify(); | |
| resetFull(); | |
| assertTrue("Collection should change from retainAll empty", | |
| collection.retainAll(empty)); | |
| confirmed.retainAll(empty); | |
| verify(); | |
| resetFull(); | |
| assertTrue("Collection changed from retainAll other", | |
| collection.retainAll(other)); | |
| confirmed.retainAll(other); | |
| verify(); | |
| resetFull(); | |
| int size = collection.size(); | |
| assertTrue("Collection shouldn't change from retainAll elements", | |
| !collection.retainAll(elements)); | |
| verify(); | |
| assertEquals("Collection size shouldn't change", size, | |
| collection.size()); | |
| resetFull(); | |
| HashSet set = new HashSet(elements); | |
| size = collection.size(); | |
| assertTrue("Collection shouldn't change from retainAll without " + | |
| "duplicate elements", !collection.retainAll(set)); | |
| verify(); | |
| assertEquals("Collection size didn't change from nonduplicate " + | |
| "retainAll", size, collection.size()); | |
| } | |
| /** | |
| * Tests {@link Collection#size()}. | |
| */ | |
| public void testCollectionSize() { | |
| resetEmpty(); | |
| assertEquals("Size of new Collection is 0.", 0, collection.size()); | |
| resetFull(); | |
| assertTrue("Size of full collection should be greater than zero", | |
| collection.size() > 0); | |
| } | |
| /** | |
| * Tests <Code>toString</Code> on a collection. | |
| */ | |
| public void testCollectionToString() { | |
| resetEmpty(); | |
| assertTrue("toString shouldn't return null", | |
| collection.toString() != null); | |
| resetFull(); | |
| assertTrue("toString shouldn't return null", | |
| collection.toString() != null); | |
| } | |
| /** | |
| * If isRemoveSupported() returns false, tests to see that remove | |
| * operations raise an UnsupportedOperationException. | |
| */ | |
| public void testUnsupportedRemove() { | |
| if (isRemoveSupported()) return; | |
| resetEmpty(); | |
| try { | |
| collection.clear(); | |
| fail("clear should raise UnsupportedOperationException"); | |
| } catch (UnsupportedOperationException e) { | |
| // expected | |
| } | |
| verify(); | |
| try { | |
| collection.remove(null); | |
| fail("remove should raise UnsupportedOperationException"); | |
| } catch (UnsupportedOperationException e) { | |
| // expected | |
| } | |
| verify(); | |
| try { | |
| collection.removeAll(null); | |
| fail("removeAll should raise UnsupportedOperationException"); | |
| } catch (UnsupportedOperationException e) { | |
| // expected | |
| } | |
| verify(); | |
| try { | |
| collection.retainAll(null); | |
| fail("removeAll should raise UnsupportedOperationException"); | |
| } catch (UnsupportedOperationException e) { | |
| // expected | |
| } | |
| verify(); | |
| resetFull(); | |
| try { | |
| Iterator iterator = collection.iterator(); | |
| iterator.next(); | |
| iterator.remove(); | |
| fail("iterator.remove should raise UnsupportedOperationException"); | |
| } catch (UnsupportedOperationException e) { | |
| // expected | |
| } | |
| verify(); | |
| } | |
| /** | |
| * Returns a list of elements suitable for return by | |
| * {@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 | |
| * the null element. | |
| */ | |
| public static Object[] getFullNonNullElements() { | |
| return new Object[] { | |
| new String(""), | |
| new String("One"), | |
| new Integer(2), | |
| "Three", | |
| new Integer(4), | |
| "One", | |
| new Double(5), | |
| new Float(6), | |
| "Seven", | |
| "Eight", | |
| new String("Nine"), | |
| new Integer(10), | |
| new Short((short)11), | |
| new Long(12), | |
| "Thirteen", | |
| "14", | |
| "15", | |
| new Byte((byte)16) | |
| }; | |
| } | |
| /** | |
| * Returns the default list of objects returned by | |
| * {@link #getOtherElements()}. Includes many objects | |
| * of different types. | |
| */ | |
| public static Object[] getOtherNonNullElements() { | |
| return new Object[] { | |
| new Integer(0), | |
| new Float(0), | |
| new Double(0), | |
| "Zero", | |
| new Short((short)0), | |
| new Byte((byte)0), | |
| new Long(0), | |
| new Character('\u0000'), | |
| "0" | |
| }; | |
| } | |
| /** | |
| * Returns a list of string elements suitable for return by | |
| * {@link #getFullElements()}. Override getFullElements to return | |
| * the results of this method if your collection does not support | |
| * heterogenous elements or the null element. | |
| */ | |
| public static Object[] getFullNonNullStringElements() { | |
| return new Object[] { | |
| "If","the","dull","substance","of","my","flesh","were","thought", | |
| "Injurious","distance","could","not","stop","my","way", | |
| }; | |
| } | |
| /** | |
| * Returns a list of string elements suitable for return by | |
| * {@link #getOtherElements()}. Override getOtherElements to return | |
| * the results of this method if your collection does not support | |
| * heterogenous elements or the null element. | |
| */ | |
| public static Object[] getOtherNonNullStringElements() { | |
| return new Object[] { | |
| "For","then","despite",/* of */"space","I","would","be","brought", | |
| "From","limits","far","remote","where","thou","dost","stay" | |
| }; | |
| } | |
| } |