Index: src/test/org/apache/commons/collections/TestCollection.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/collections/src/test/org/apache/commons/collections/TestCollection.java,v
retrieving revision 1.5
diff -u -r1.5 TestCollection.java
--- src/test/org/apache/commons/collections/TestCollection.java	14 Jul 2001 23:33:27 -0000	1.5
+++ src/test/org/apache/commons/collections/TestCollection.java	3 Jun 2002 17:01:57 -0000
@@ -62,138 +62,348 @@
 package org.apache.commons.collections;
 
 import junit.framework.*;
-import java.util.Collection;
+import java.lang.reflect.Array;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+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>
  * To use, simply extend this class, and implement
- * the {@link #makeCollection} method.
+ * the {@link #makeCollection} method.  You may also have to customize
+ * your subclass by changing the protected methods.
  * <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.
  *
  * @author Rodney Waldhoff
+ * @author Paul Jack
  * @version $Id: TestCollection.java,v 1.5 2001/07/14 23:33:27 craigmcc Exp $
  */
 public abstract class TestCollection extends TestObject {
+
+
     public TestCollection(String testName) {
         super(testName);
     }
 
+
+    /**
+     *  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 supportsAdd() {
+        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 supportsRemove() {
+        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();
+    }
+
+
+    /**
+     * Return 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;
+    }
+
+
     /**
-     * Return a new, empty {@link Collection} to used for testing.
+     *  Verifies the given collection.  This method is
+     *  invoked every time a test method alters a collection via an
+     *  add or removal operation.  Default implementation does nothing.
+     *  TestSet, for instance, overrides this method to ensure that the
+     *  set only contains unique elements; TestTreeBag overrides this
+     *  method to make sure iteration is in ascending order.
      */
-    public abstract Collection makeCollection();
+    protected void verifyCollection(Collection c) {
+    }
+
 
+    /**
+     *  Returns an empty collection for Object tests.
+     */
     public Object makeObject() {
         return makeCollection();
     }
 
-    // optional operation
+
+    /**
+     *  Tests {@link Collection#add}.
+     */
     public void testCollectionAdd() {
+        if (!supportsAdd()) return;
+
+        Object[] elements = getFullElements();
+        for (int i = 0; i < elements.length; i++) {
+             Collection c = makeCollection();
+             boolean r = c.add(elements[i]);
+             verifyCollection(c);
+             assertTrue("Empty collection changed after add", r);
+             assertTrue("Collection size is 1 after first add", c.size() == 1);
+        }
+
         Collection c = makeCollection();
-        boolean added1 = tryToAdd(c,"element1");
-        boolean added2 = tryToAdd(c,"element2");
+        int size = 0;
+        for (int i = 0; i < elements.length; i++) {
+             boolean r = c.add(elements[i]);
+             verifyCollection(c);
+             if (r) size++;
+             assertEquals("Collection size should grow after add", 
+              size, c.size());
+             assertTrue("Collection should contain added element",
+              c.contains(elements[i]));
+        }
     }
 
-    // optional operation
+
+    /**
+     *  Tests {@link Collection#addAll}.
+     */
     public void testCollectionAddAll() {
+        if (!supportsAdd()) return;
+
         Collection c = makeCollection();
-        Collection col = new ArrayList();
-        col.add("element1");
-        col.add("element2");
-        col.add("element3");
-        boolean added = false;
-        try {
-            added = c.addAll(col);
-        } catch(UnsupportedOperationException e) {
-            // ignored, must not be supported
-        } catch(ClassCastException e) {
-            // ignored, type must not be supported
-        } catch(IllegalArgumentException e) {
-            // ignored, element must not be supported
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.addAll should only throw UnsupportedOperationException, ClassCastException or IllegalArgumentException. Found " + t.toString());
-        }
+        Object[] elements = getFullElements();
+        boolean r = c.addAll(Arrays.asList(elements));
+        verifyCollection(c);
+        assertTrue("Empty collection should change after addAll", r);
+        for (int i = 0; i < elements.length; i++) {
+             assertTrue("Collection should contain added element",
+              c.contains(elements[i]));
+        }
+
+        c = makeFullCollection();
+        int size = c.size();
+        elements = getOtherElements();
+        r = c.addAll(Arrays.asList(elements));
+        verifyCollection(c);
+        assertTrue("Full collection should change after addAll", r);
+        for (int i = 0; i < elements.length; i++) {
+             assertTrue("Full collection should contain added element",
+              c.contains(elements[i]));
+        }
+        assertEquals("Size should increase after addAll", 
+         size + elements.length, c.size());
+
+        c = makeFullCollection();
+        size = c.size();
+        r = c.addAll(Arrays.asList(getFullElements()));
+        verifyCollection(c);
+        if (r) {
+            assertTrue("Size should increase if addAll returns true", 
+              size < c.size());
+        } else {
+            assertTrue("Size should not change if addAll returns false",
+              size == c.size());
+        } 
     }
 
-    // optional operation
-    public void testCollectionClear() {
-        Collection c = makeCollection();
-        boolean cleared = false;
+
+    /**
+     *  If {@link #supportsAdd} returns false, tests that add operations
+     *  raise <Code>UnsupportedOperationException.
+     */
+    public void testUnsupportedAdd() {
+        if (supportsAdd()) return;
+
         try {
-            c.clear();
-            cleared = true;
-        } catch(UnsupportedOperationException e) {
-            // ignored, must not be supported
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.clear should only throw UnsupportedOperationException. Found " + t.toString());
+            makeCollection().add(new Object());
+            fail("Emtpy collection should not support add.");
+        } catch (UnsupportedOperationException e) {
+            // expected
         }
 
-        if(cleared) {
-            assertTrue("After Collection.clear(), Collection.isEmpty() should be true.",c.isEmpty());
+        try {
+            makeCollection().addAll(Arrays.asList(getFullElements()));
+            fail("Emtpy collection should not support addAll.");
+        } catch (UnsupportedOperationException e) {
+            // expected
         }
 
-        boolean added = tryToAdd(c,"element1");
+        try {
+            makeFullCollection().add(new Object());
+            fail("Full collection should not support add.");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
 
-        if(added) {
-            assertTrue("After element is added, Collection.isEmpty() should be false.",!c.isEmpty());
-            boolean cleared2 = false;
-            try {
-                c.clear();
-                cleared2 = true;
-            } catch(UnsupportedOperationException e) {
-                // ignored, must not be supported
-            } catch(Throwable t) {
-                t.printStackTrace();
-                fail("Collection.clear should only throw UnsupportedOperationException. Found " + t.toString());
-            }
-            if(cleared2) {
-                assertTrue("After Collection.clear(), Collection.isEmpty() should be true.",c.isEmpty());
-            }
+        try {
+            makeFullCollection().addAll(Arrays.asList(getOtherElements()));
+            fail("Full collection should not support addAll.");
+        } catch (UnsupportedOperationException e) {
+            // expected
         }
     }
 
+
+    /**
+     *  Test {@link Collection#clear}.
+     */
+    public void testCollectionClear() {
+        if (!supportsRemove()) return;
+
+        Collection c = makeCollection();
+        c.clear(); // just to make sure it doesn't raise anything
+        verifyCollection(c);
+        assertTrue("Collection should be empty after clear", c.isEmpty());
+        assertEquals("Collection size should be 0 after clear", c.size(), 0);
+
+        c = makeFullCollection();
+        c.clear();
+        verifyCollection(c);
+        assertTrue("Collection should be empty after full clear", c.isEmpty());
+        assertEquals("Collection size should be 0 after full clear", 
+         c.size(), 0);
+    }    
+
+
+    /**
+     *  Tests {@link Collection#contains}.
+     */
     public void testCollectionContains() {
         Collection c = makeCollection();
-        assertTrue("Empty Collection shouldn't contain element.",!c.contains("element1"));
-        boolean added1 = tryToAdd(c,"element1");
-        assertTrue("[1] If an element was added, it should be contained, if it wasn't, it shouldn't.",added1 == c.contains("element1"));
-
-        assertTrue("Shouldn't be contained.",!c.contains("element2"));
-        boolean added2 = tryToAdd(c,"element2");
-        assertTrue("[2] If an element was added, it should be contained, if it wasn't, it shouldn't.",added1 == c.contains("element1"));
-        assertTrue("[3] If an element was added, it should be contained, if it wasn't, it shouldn't.",added2 == c.contains("element2"));
+        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()));
+        }
+
+        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));
+        }
+
+        elements.clear();
+        elements.addAll(Arrays.asList(getOtherElements()));
+        iter = elements.iterator();
+        while (iter.hasNext()) {
+            assertTrue("Full collection shouldn't contain element", 
+             !c.contains(iter.next()));
+        }
     }
 
+
+    /**
+     *  Tests {@link Collection#containsAll}.
+     */
     public void testCollectionContainsAll() {
         Collection c = makeCollection();
-        Collection col = new ArrayList();
-        assertTrue("Every Collection should contain all elements of an empty Collection.",c.containsAll(col));
-        col.add("element1");
-        assertTrue("Empty Collection shouldn't contain all elements of a non-empty Collection.",!c.containsAll(col));
-
-        boolean added1 = tryToAdd(c,"element1");
-        if(added1) {
-            assertTrue("[1] Should contain all.",c.containsAll(col));
-        }
-
-        col.add("element2");
-        assertTrue("Shouldn't contain all.",!c.containsAll(col));
-
-        boolean added2 = tryToAdd(c,"element2");
-        if(added1 && added2) {
-            assertTrue("[2] Should contain all.",c.containsAll(col));
-        }
+        Collection col = new HashSet();
+        assertTrue("Every Collection should contain all elements of an " +
+         "empty Collection.",c.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();
+        assertTrue("Full collection shouldn't contain other elements", 
+         !c.containsAll(col));
+
+        col.clear();
+        col.addAll(Arrays.asList(getFullElements()));
+        assertTrue("Full collection should containAll full elements " + c + " " + col,
+         c.containsAll(col));
+        col = Arrays.asList(getFullElements()).subList(2, 5);
+        assertTrue("Full collection should containAll partial full " +
+         "elements", c.containsAll(col));
+        assertTrue("Full collection should containAll itself", 
+         c.containsAll(c));
+
+        col = new ArrayList();
+        col.addAll(Arrays.asList(getFullElements()));
+        col.addAll(Arrays.asList(getFullElements()));
+        assertTrue("Full collection should containAll duplicate full " +
+         "elements", c.containsAll(col));
     }
 
+
+    /* ---------------------------------
+
+     // 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);
@@ -248,233 +458,492 @@
         }
     }
 
+    -------------------------- */
+
+
+    /**
+     *  Tests {@link Collection#isEmpty}.
+     */
     public void testCollectionIsEmpty() {
         Collection c = makeCollection();
         assertTrue("New Collection should be empty.",c.isEmpty());
-        boolean added = tryToAdd(c,"element1");
-        if(added) {
-            assertTrue("If an element was added, the Collection.isEmpty() should return false.",!c.isEmpty());
-        }
+
+        c =  makeFullCollection();
+        assertTrue("Full collection shouldn't be empty", !c.isEmpty());
     }
 
+
+    /**
+     *  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());
+        assertTrue("Iterator for empty Collection shouldn't have next.",
+         !it1.hasNext());
         try {
             it1.next();
-            fail("Iterator at end of Collection should throw NoSuchElementException when next is called.");
+            fail("Iterator at end of Collection should throw " +
+             "NoSuchElementException when next is called.");
         } catch(NoSuchElementException e) {
             // expected
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.iterator.next() should only throw NoSuchElementException. Found " + t.toString());
+        } 
+
+        c = makeFullCollection();
+        it1 = c.iterator();
+        for (int i = 0; i < c.size(); i++) {
+            assertTrue("Iterator for full collection should haveNext", 
+             it1.hasNext());
+            it1.next();
         }
+        assertTrue("Iterator should be finished", !it1.hasNext());
 
-        boolean added = tryToAdd(c,"element1");
-        if(added) {
-            Iterator it2 = c.iterator();
-            assertTrue("Iterator for non-empty Collection should have next.",it2.hasNext());
-            assertEquals("element1",it2.next());
-            assertTrue("Iterator at end of Collection shouldn't have next.",!it2.hasNext());
-            try {
-                it2.next();
-                fail("Iterator at end of Collection should throw NoSuchElementException when next is called.");
-            } catch(NoSuchElementException e) {
-                // expected
-            } catch(Throwable t) {
-                t.printStackTrace();
-                fail("Collection.iterator.next() should only throw NoSuchElementException. Found " + t.toString());
-            }
+        ArrayList list = new ArrayList();
+        it1 = c.iterator();
+        for (int i = 0; i < c.size(); i++) {
+             Object next = it1.next();
+             assertTrue("Collection should contain element returned by " +
+              "its iterator", c.contains(next));
+             list.add(next);
+        }
+        try {
+            it1.next();
+            fail("iterator.next() should raise NoSuchElementException " +
+             "after it finishes");
+        } catch (NoSuchElementException e) {
+            // expected
+        }
+
+        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)));
         }
     }
 
-    // optional operation
-    public void testCollectionRemove() {
+
+    /**
+     *  Tests removals from {@link Collection#iterator}.
+     */
+    public void testCollectionIteratorRemove() {
+        if (!supportsRemove()) return;
+
         Collection c = makeCollection();
-        boolean added = tryToAdd(c,"element1");
+        try {
+            c.iterator().remove();
+            fail("New iterator.remove should raise IllegalState");
+        } catch (IllegalStateException e) {
+            // expected
+        }
 
         try {
-            assertTrue("Shouldn't be able to remove an element that wasn't added.",!c.remove("element2"));
-        } catch(UnsupportedOperationException e) {
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.remove should only throw UnsupportedOperationException. Found " + t.toString());
+            Iterator iter = c.iterator();
+            iter.hasNext();
+            iter.remove();
+            fail("New iterator.remove should raise IllegalState " +
+             "even after hasNext");
+        } catch (IllegalStateException e) {
+            // expected
         }
 
+        c = makeFullCollection();
+        int size = c.size();
+        HashBag bag = new HashBag(c);
+        Iterator iter = c.iterator();
+        while (iter.hasNext()) {
+            Object o = iter.next();
+            bag.remove(o, 1);
+            iter.remove();
+            size--;
+            assertEquals("Collection should shrink after iterator.remove",
+              c.size(), size);
+            if (bag.getCount(o) == 0) {
+                assertTrue("Collection shouldn't contain element after " +
+                 "iterator.remove", !c.contains(o));
+            } else {
+                assertTrue("Collection should still contain element after " +
+                 "iterator.remove", c.contains(o));
+            }
+            verifyCollection(c);
+        }
+        assertTrue("Collection should be empty after iterator purge",
+         c.isEmpty());
+
+        c = makeFullCollection();
+        iter = c.iterator();
+        iter.next();
+        iter.remove();
         try {
-            assertTrue("If added, should be removed by call to remove.",added == c.remove("element1"));
-            assertTrue("If removed, shouldn't be contained.",!c.contains("element1"));
-        } catch(UnsupportedOperationException e) {
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.remove should only throw UnsupportedOperationException. Found " + t.toString());
+            iter.remove();
+            fail("Second iter.remove should raise IllegalState");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+
+    /**
+     *  Tests {@link Collection#remove}.
+     */
+    public void testCollectionRemove() {
+        if (!supportsRemove()) return;
+
+        Collection c = makeCollection();
+
+        Object[] elements = getFullElements();
+        for (int i = 0; i < elements.length; i++) {
+            assertTrue("Shouldn't remove nonexistent element", 
+             !c.remove(elements[i]));
+            assertEquals("Collection should still be empty after remove of " +
+             "nonexistent element", 0, c.size());
+        }
+
+        Object[] other = getOtherElements();
+        c = makeFullCollection();
+        int size = c.size();
+        for (int i = 0; i < other.length; i++) {
+            assertTrue("Shouldn't remove nonexistent other element", 
+             !c.remove(other[i]));           
+            assertEquals("Collection should still be full after remove of " +
+             "nonexistent other element", size, c.size());
+        }
+
+        size = c.size();
+        for (int i = 0; i < elements.length; i++) {
+            c = makeFullCollection();
+            HashBag bag = new HashBag(c);
+            assertTrue("Collection should remove extant element",
+             c.remove(elements[i]));
+            verifyCollection(c);
+            assertEquals("Collection should shrink after remove", 
+             size - 1, c.size());
+            bag.remove(elements[i], 1);
+            if (bag.getCount(elements[i]) == 0) {
+                assertTrue("Collection shouldn't contain removed element:" + elements[i],
+                 !c.contains(elements[i]));
+            } else {
+                assertTrue("Collection should still contain removed element",
+                 c.contains(elements[i]));
+            }
         }
     }
 
-    // optional operation
+
+    /**
+     *  Tests {@link Collection#removeAll}.
+     */
     public void testCollectionRemoveAll() {
+        if (!supportsRemove()) return;
+
+        Collection c = makeCollection();
+        assertTrue("Emtpy collection removeAll should return false for " +
+         "empty input", !c.removeAll(Collections.EMPTY_SET));
+        assertTrue("Emtpy collection removeAll should return false for " +
+         "nonempty input", !c.removeAll(new ArrayList(c)));
+
+        c = makeFullCollection();
+        assertTrue("Full collection removeAll should return false for " + 
+         "empty input", !c.removeAll(Collections.EMPTY_SET));
+        assertTrue("Full collection removeAll should return false for " +
+         "other elements", !c.removeAll(Arrays.asList(getOtherElements())));
+        assertTrue("Full collection removeAll should return true for " +
+         "full elements", c.removeAll(new HashSet(c)));
+        verifyCollection(c);
+        assertTrue("Collection empty after full removeAll", c.isEmpty());
+
+        c = makeFullCollection();
+        int size = c.size();
+        Collection all = Arrays.asList(getFullElements()).subList(2, 5);
+        assertTrue("Full collection removeAll should work", c.removeAll(all));
+        verifyCollection(c);
+        assertTrue("Collection should shrink after removeAll", 
+         c.size() < size);
+        Iterator iter = all.iterator();
+        while (iter.hasNext()) {
+            assertTrue("Collection shouldn't contain removed element",
+             !c.contains(iter.next()));
+        }
+    }
+
+
+    /**
+     *  Tests {@link Collection#retainAll}.
+     */
+    public void testCollectionRetainAll() {
+        if (!supportsRemove()) return;
+
+        Collection c = makeCollection();
+        List elements = Arrays.asList(getFullElements());
+        List other = Arrays.asList(getOtherElements());
+
+        assertTrue("Empty retainAll() should return false", 
+          !c.retainAll(Collections.EMPTY_SET));
+        assertTrue("Empty retainAll() should return false", 
+          !c.retainAll(elements));
+
+        c = makeFullCollection();
+        assertTrue("Collection should change from retainAll empty", 
+          c.retainAll(Collections.EMPTY_SET));
+        assertTrue("Collection empty after retainAll empty", c.isEmpty());
+
+        c = makeFullCollection();
+        assertTrue("Collection changed from retainAll other", 
+          c.retainAll(other));
+        assertTrue("Collection empty after retainAll other", c.isEmpty());
+
+        c = makeFullCollection();
+        int size = c.size();
+        assertTrue("Collection shouldn't change from retainAll elements",
+          !c.retainAll(elements));
+        assertEquals("Collection size shouldn't change", size, c.size());
+
+        c = makeFullCollection();
+        size = c.size();
+        assertTrue("Collection should changed by partial retainAll",
+          c.retainAll(elements.subList(2, 5)));
+        assertTrue("Collection should shrink after partial retainAll",
+          c.size() < size);
+        verifyCollection(c);
+
+        Iterator iter = c.iterator();
+        while (iter.hasNext()) {
+            assertTrue("Collection only contains retained element", 
+             elements.subList(2, 5).contains(iter.next()));
+        }
+
+        c = makeFullCollection();
+        HashSet set = new HashSet(elements);
+        size = c.size();
+        assertTrue("Collection shouldn't change from retainAll without " +
+         "duplicate elements", !c.retainAll(set));
+        assertEquals("Collection size didn't change from nonduplicate " +
+         "retainAll", size, c.size());
+    }
+
+
+    /**
+     *  Tests {@link Collection#size}.
+     */
+    public void testCollectionSize() {
+        Collection c = makeCollection();
+        assertEquals("Size of new Collection is 0.",0,c.size());
+
+        c = makeFullCollection();
+        assertTrue("Size of full collection should be nonzero", c.size() != 0);
+    }
+
+
+    /**
+     *  Tests {@link Collection#toArray()}.
+     */
+    public void testCollectionToArray() {
+        Collection c = makeCollection();
+        assertEquals("Empty Collection should return empty array for toArray",
+         0, c.toArray().length);
+
+        c = makeFullCollection();
+        HashBag bag = new HashBag(c);
+        Object[] array = c.toArray();
+        assertEquals("Full collection toArray should be same size as " +
+         "collection", array.length, c.size());
+        for (int i = 0; i < array.length; i++) {
+            assertTrue("Collection should contain element in toArray",
+             c.contains(array[i]));
+            bag.remove(array[i], 1);
+        }
+        assertTrue("Collection should return all its elements in toArray",
+          bag.isEmpty());
+    }
+
+
+    /**
+     *  Tests {@link Collection.toArray(Object[])}.
+     */
+    public void testCollectionToArray2() {
         Collection c = makeCollection();
-        assertTrue("Initial Collection is empty.",c.isEmpty());
+        Object[] a = new Object[] { new Object(), null, null };
+        Object[] array = c.toArray(a);
+        assertEquals("Given array shouldn't shrink", array, a);
+        assertEquals("Last element should be set to null", a[0], null);
+
+        c = makeFullCollection();
         try {
-            c.removeAll(c);
-        } catch(UnsupportedOperationException e) {
+            array = c.toArray(new Void[0]);
+            fail("toArray(new Void[0]) should raise ArrayStore");
+        } catch (ArrayStoreException e) {
             // expected
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.removeAll should only throw UnsupportedOperationException. Found " + t.toString());
         }
-        assertTrue("Collection is still empty.",c.isEmpty());
 
-        boolean added = tryToAdd(c,"element1");
-        if(added) {
-            assertTrue("Collection is not empty.",!c.isEmpty());
-            try {
-                c.removeAll(c);
-                assertTrue("Collection is empty.",c.isEmpty());
-            } catch(UnsupportedOperationException e) {
-                // expected
-            } catch(Throwable t) {
-                t.printStackTrace();
-                fail("Collection.removeAll should only throw UnsupportedOperationException. Found " + t.toString());
-            }
+        try {
+            array = c.toArray(null);
+            fail("toArray(null) should raise NPE");
+        } catch (NullPointerException e) {
+            // expected
         }
+
+        array = c.toArray(new Object[0]);
+        a = c.toArray();
+        assertEquals("toArrays should be equal", 
+          Arrays.asList(array), Arrays.asList(a));
+
+        // Figure out if they're all the same class
+        // TODO: It'd be nicer to detect a common superclass
+        HashSet classes = new HashSet();
+        for (int i = 0; i < array.length; i++) {
+            classes.add((array[i] == null) ? null : array[i].getClass());
+        }
+        if (classes.size() > 1) return;
+
+        Class cl = (Class)classes.iterator().next();
+        a = (Object[])Array.newInstance(cl, 0);
+        array = c.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()));
     }
 
-    // optional operation
-    public void testCollectionRemoveAll2() {
+
+    /**
+     *  Tests <Code>toString</Code> on a collection.
+     */
+    public void testCollectionToString() {
         Collection c = makeCollection();
-        Collection col = new ArrayList();
-        col.add("element1");
-        col.add("element2");
-        col.add("element3");
-        boolean added = false;
-        try {
-            added = c.addAll(col);
-            if(added) {
-                added = c.add("element0");
-            }
-        } catch(UnsupportedOperationException e) {
-            // ignored, must not be supported
-        } catch(ClassCastException e) {
-            // ignored, type must not be supported
-        } catch(IllegalArgumentException e) {
-            // ignored, element must not be supported
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.addAll should only throw UnsupportedOperationException, ClassCastException or IllegalArgumentException. Found " + t.toString());
+        assertTrue("toString shouldn't return null", c.toString() != null);
+
+        c = makeFullCollection();
+        assertTrue("toString shouldn't return null", c.toString() != null);
+    }
+
+
+    /**
+     *  If supportsRemove() returns false, tests to see that remove
+     *  operations raise an UnsupportedOperationException.
+     */
+    public void testUnsupportedRemove() {
+        if (supportsRemove()) return;
+
+        try {
+            makeCollection().clear();
+            fail("clear should raise UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // expected
         }
-        col.add("element4");
-        if(added) {
-            assertTrue("Collection is not empty.",!c.isEmpty());
-            try {
-                assertTrue("Should be changed",c.removeAll(col));
-                assertTrue("Collection is not empty.",!c.isEmpty());
-                assertTrue("Collection should contain element",c.contains("element0"));
-                assertTrue("Collection shouldn't contain removed element",!c.contains("element1"));
-                assertTrue("Collection shouldn't contain removed element",!c.contains("element2"));
-                assertTrue("Collection shouldn't contain removed element",!c.contains("element3"));
-                assertTrue("Collection shouldn't contain removed element",!c.contains("element4"));
-            } catch(UnsupportedOperationException e) {
-                // expected
-            } catch(Throwable t) {
-                t.printStackTrace();
-                fail("Collection.removeAll should only throw UnsupportedOperationException. Found " + t.toString());
-            }
+
+        try {
+            makeCollection().remove(null);
+            fail("remove should raise UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // expected
         }
-    }
 
-    // optional operation
-    public void testCollectionRetainAll() {
-        Collection a = makeCollection();
-        Collection b = makeCollection();
         try {
-            assertTrue(!a.retainAll(b));
-            assertTrue(!a.retainAll(a));
-        } catch(UnsupportedOperationException e) {
+            makeCollection().removeAll(null);
+            fail("removeAll should raise UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
             // expected
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.retainAll should only throw UnsupportedOperationException. Found " + t.toString());
         }
 
-        boolean added_b = b.add("element1");
         try {
-            assertTrue(!a.retainAll(b));
-            assertTrue(added_b == b.retainAll(a));
-            assertTrue(b.isEmpty());
-        } catch(UnsupportedOperationException e) {
+            makeCollection().retainAll(null);
+            fail("removeAll should raise UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+        try {
+            Collection c = makeFullCollection();
+            Iterator iterator = c.iterator();
+            iterator.next();
+            iterator.remove();
+            fail("iterator.remove should raise UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
             // expected
-        } catch(Throwable t) {
-            t.printStackTrace();
-            fail("Collection.retainAll should only throw UnsupportedOperationException. Found " + t.toString());
         }
 
-        boolean added_b1 = b.add("element1");
-        boolean added_b2 = b.add("element2");
-        boolean added_a1 = a.add("element1");
-        if(added_b1 && added_b2 && added_a1) {
+    }
+
+
+    /**
+     *  Tests that the collection's iterator is fail-fast.  
+     */
+    public void testCollectionIteratorFailFast() {
+        if (supportsAdd()) {
+            try {
+                Collection c = makeFullCollection();
+                Iterator iter = c.iterator();
+                c.add(getOtherElements()[0]);
+                iter.next();
+                fail("next after add should raise ConcurrentModification");
+            } catch (ConcurrentModificationException e) {
+                // expected
+            }
+
             try {
-                assertTrue(!b.retainAll(b));
-                assertTrue(b.contains("element1"));
-                assertTrue(b.contains("element2"));
-
-                assertTrue(!a.retainAll(b));
-
-                assertTrue(b.retainAll(a));
-                assertTrue(b.contains("element1"));
-                assertTrue(!b.contains("element2"));
-            } catch(UnsupportedOperationException e) {
+                Collection c = makeFullCollection();
+                Iterator iter = c.iterator();
+                c.addAll(Arrays.asList(getOtherElements()));
+                iter.next();
+                fail("next after addAll should raise ConcurrentModification");
+            } catch (ConcurrentModificationException e) {
                 // expected
-            } catch(Throwable t) {
-                t.printStackTrace();
-                fail("Collection.retainAll should only throw UnsupportedOperationException. Found " + t.toString());
             }
         }
-    }
 
-    public void testCollectionSize() {
-        Collection c = makeCollection();
-        assertEquals("Size of new Collection is 0.",0,c.size());
-        boolean added = tryToAdd(c,"element1");
-        if(added) {
-            assertEquals("If one element was added, the Collection.size() should be 1.",1,c.size());
+        if (!supportsRemove()) return;
+
+        try {
+            Collection c = makeFullCollection();
+            Iterator iter = c.iterator();
+            c.clear();
+            iter.next();
+            fail("next after clear should raise ConcurrentModification");
+        } catch (ConcurrentModificationException e) {
+            // expected
+        } catch (NoSuchElementException e) {
+            // (also legal given spec)
         }
-    }
 
-    public void testCollectionToArray() {
-        Collection c = makeCollection();
-        assertEquals("Empty Collection should return empty array for toArray",0,c.toArray().length);
-        boolean added = tryToAdd(c,"element1");
-        if(added) {
-            assertEquals("If an element was added, the Collection.toArray().length should be 1.",1,c.toArray().length);
-        } else {
-            assertEquals("Empty Collection should return empty array for toArray",0,c.toArray().length);
+        try {
+            Collection c = makeFullCollection();
+            Iterator iter = c.iterator();
+            c.remove(getFullElements()[0]);
+            iter.next();
+            fail("next after remove should raise ConcurrentModification");
+        } catch (ConcurrentModificationException e) {
+            // expected
         }
 
-        boolean added2 = tryToAdd(c,"element2");
-        if(added && added2) {
-            assertEquals("If another element was added, the Collection.toArray().length should be 2.",2,c.toArray().length);
-        } else if(added2) {
-            assertEquals("If an element was added, the Collection.toArray().length should be 1.",1,c.toArray().length);
-        } else {
-            assertEquals("Empty Collection should return empty array for toArray",0,c.toArray().length);
+        try {
+            Collection c = makeFullCollection();
+            Iterator iter = c.iterator();
+            c.removeAll(Arrays.asList(getFullElements()).subList(2,5));
+            iter.next();
+            fail("next after removeAll should raise ConcurrentModification");
+        } catch (ConcurrentModificationException e) {
+            // expected
         }
-    }
 
-    public void testCollectionToArray2() {
-        Collection c = makeCollection();
-        assertEquals(10,c.toArray(new String[10]).length);
-        assertEquals(7,c.toArray(new Object[7]).length);
-        boolean added1 = tryToAdd(c,"element1");
-        if(added1) {
-            String[] fits = new String[1];
-            String[] small = new String[0];
-            assertSame(fits,c.toArray(fits));
-            assertTrue(small != c.toArray(small));
+        try {
+            Collection c = makeFullCollection();
+            Iterator iter = c.iterator();
+            c.retainAll(Arrays.asList(getFullElements()).subList(2,5));
+            iter.next();
+            fail("next after retainAll should raise ConcurrentModification");
+        } catch (ConcurrentModificationException e) {
+            // expected
         }
     }
 
+
     /**
      * Try to add the given object to the given Collection.
      * Returns <tt>true</tt> if the element was added,
@@ -484,6 +953,7 @@
      * ClassCastException, or IllegalArgumentException is thrown.
      */
     protected boolean tryToAdd(Collection c,Object obj) {
+        // FIXME: Delete this method after TestList is patched
         try {
             return c.add(obj);
         } catch(UnsupportedOperationException e) {
@@ -497,5 +967,87 @@
             fail("Collection.add should only throw UnsupportedOperationException, ClassCastException or IllegalArgumentException. Found " + t.toString());
             return false; // never get here, since fail throws exception
         }
+    }
+
+
+    
+    /**
+     *  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"
+        };
     }
 }
Index: src/test/org/apache/commons/collections/TestCursorableLinkedList.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/collections/src/test/org/apache/commons/collections/TestCursorableLinkedList.java,v
retrieving revision 1.4
diff -u -r1.4 TestCursorableLinkedList.java
--- src/test/org/apache/commons/collections/TestCursorableLinkedList.java	25 Feb 2002 23:51:24 -0000	1.4
+++ src/test/org/apache/commons/collections/TestCursorableLinkedList.java	3 Jun 2002 17:01:57 -0000
@@ -82,6 +82,16 @@
         junit.textui.TestRunner.main(testCaseName);
     }
 
+
+    public Object[] getFullElements() {
+        return getFullNonNullElements();
+    }
+
+
+    public Object[] getOtherElements() {
+        return getOtherNonNullElements();
+    }
+
     private CursorableLinkedList list = null;
 
     public void setUp() {
Index: src/test/org/apache/commons/collections/TestTreeBag.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/collections/src/test/org/apache/commons/collections/TestTreeBag.java,v
retrieving revision 1.1
diff -u -r1.1 TestTreeBag.java
--- src/test/org/apache/commons/collections/TestTreeBag.java	29 Aug 2001 15:28:07 -0000	1.1
+++ src/test/org/apache/commons/collections/TestTreeBag.java	3 Jun 2002 17:01:57 -0000
@@ -1,119 +1,129 @@
-/*
- * $Header: /home/cvspublic/jakarta-commons/collections/src/test/org/apache/commons/collections/TestTreeBag.java,v 1.1 2001/08/29 15:28:07 jstrachan Exp $
- * $Revision: 1.1 $
- * $Date: 2001/08/29 15:28:07 $
- *
- * ====================================================================
- *
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The end-user documentation included with the redistribution, if
- *    any, must include the following acknowlegement:
- *       "This product includes software developed by the
- *        Apache Software Foundation (http://www.apache.org/)."
- *    Alternately, this acknowlegement may appear in the software itself,
- *    if and wherever such third-party acknowlegements normally appear.
- *
- * 4. The names "The Jakarta Project", "Commons", and "Apache Software
- *    Foundation" must not be used to endorse or promote products derived
- *    from this software without prior written permission. For written
- *    permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache"
- *    nor may "Apache" appear in their names without prior written
- *    permission of the Apache Group.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.commons.collections;
-
-import junit.framework.*;
-
-/**
- * Extension of {@link TestBag} for exercising the {@link TreeBag}
- * implementation.
- *
- * @author Chuck Burdick
- * @version $Id: TestTreeBag.java,v 1.1 2001/08/29 15:28:07 jstrachan Exp $ */
-public class TestTreeBag extends TestBag {
-   public TestTreeBag(String testName) {
-      super(testName);
-   }
-
-   public static Test suite() {
-      return new TestSuite(TestTreeBag.class);
-   }
-
-   public static void main(String args[]) {
-      String[] testCaseName = { TestTreeBag.class.getName() };
-      junit.textui.TestRunner.main(testCaseName);
-   }
-
-   public Bag makeBag() {
-      return new TreeBag();
-   }
-
-   public SortedBag setupBag() {
-      SortedBag bag = (SortedBag)makeBag();
-      bag.add("C");
-      bag.add("A");
-      bag.add("B");
-      bag.add("D");
-      return bag;
-   }
-
-   public void testOrdering() {
-      Bag bag = setupBag();
-      assertEquals("Should get elements in correct order",
-                   "A", bag.toArray()[0]);
-      assertEquals("Should get elements in correct order",
-                   "B", bag.toArray()[1]);
-      assertEquals("Should get elements in correct order",
-                   "C", bag.toArray()[2]);
-      assertEquals("Should get first key",
-                   "A", ((SortedBag)bag).first());
-      assertEquals("Should get last key",
-                   "D", ((SortedBag)bag).last());
-   }
-}
-
-
-
-
-
-
-
+/*
+ * $Header: /home/cvspublic/jakarta-commons/collections/src/test/org/apache/commons/collections/TestTreeBag.java,v 1.1 2001/08/29 15:28:07 jstrachan Exp $
+ * $Revision: 1.1 $
+ * $Date: 2001/08/29 15:28:07 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.collections;
+
+import junit.framework.*;
+
+/**
+ * Extension of {@link TestBag} for exercising the {@link TreeBag}
+ * implementation.
+ *
+ * @author Chuck Burdick
+ * @version $Id: TestTreeBag.java,v 1.1 2001/08/29 15:28:07 jstrachan Exp $ */
+public class TestTreeBag extends TestBag {
+   public TestTreeBag(String testName) {
+      super(testName);
+   }
+
+   public static Test suite() {
+      return new TestSuite(TestTreeBag.class);
+   }
+
+   public static void main(String args[]) {
+      String[] testCaseName = { TestTreeBag.class.getName() };
+      junit.textui.TestRunner.main(testCaseName);
+   }
+
+   public Bag makeBag() {
+      return new TreeBag();
+   }
+
+   public Object[] getFullElements() {
+      return getFullNonNullStringElements();
+   }
+
+   public Object[] getOtherElements() {
+      return getOtherNonNullStringElements();
+   }
+
+
+
+   public SortedBag setupBag() {
+      SortedBag bag = (SortedBag)makeBag();
+      bag.add("C");
+      bag.add("A");
+      bag.add("B");
+      bag.add("D");
+      return bag;
+   }
+
+   public void testOrdering() {
+      Bag bag = setupBag();
+      assertEquals("Should get elements in correct order",
+                   "A", bag.toArray()[0]);
+      assertEquals("Should get elements in correct order",
+                   "B", bag.toArray()[1]);
+      assertEquals("Should get elements in correct order",
+                   "C", bag.toArray()[2]);
+      assertEquals("Should get first key",
+                   "A", ((SortedBag)bag).first());
+      assertEquals("Should get last key",
+                   "D", ((SortedBag)bag).last());
+   }
+}
+
+
+
+
+
+
+

