| /* | |
| * 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.AbstractCollection; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.Collections; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.ListIterator; | |
| import java.util.NoSuchElementException; | |
| /** | |
| * Tests base {@link java.util.List} methods and contracts. | |
| * <p> | |
| * To use, simply extend this class, and implement | |
| * the {@link #makeList} method. | |
| * <p> | |
| * If your {@link List} fails one of these tests by design, | |
| * you may still use this base set of cases. Simply override the | |
| * test case (method) your {@link List} fails. | |
| * | |
| * @author Rodney Waldhoff | |
| * @author Paul Jack | |
| * @version $Id: TestList.java,v 1.13.2.1 2004/05/22 12:14:05 scolebourne Exp $ | |
| */ | |
| public abstract class TestList extends TestCollection { | |
| /** | |
| * Return a new, empty {@link List} to be used for testing. | |
| * | |
| * @return an empty list for testing. | |
| */ | |
| protected abstract List makeEmptyList(); | |
| /** | |
| * Return a new, full {@link List} to be used for testing. | |
| * | |
| * @return a full list for testing | |
| */ | |
| protected List makeFullList() { | |
| // only works if list supports optional "addAll(Collection)" | |
| List list = makeEmptyList(); | |
| list.addAll(Arrays.asList(getFullElements())); | |
| return list; | |
| } | |
| /** | |
| * Returns {@link makeEmptyList()}. | |
| * | |
| * @return an empty list to be used for testing | |
| */ | |
| final protected Collection makeCollection() { | |
| return makeEmptyList(); | |
| } | |
| /** | |
| * Returns {@link makeFullList()}. | |
| * | |
| * @return a full list to be used for testing | |
| */ | |
| final protected Collection makeFullCollection() { | |
| return makeFullList(); | |
| } | |
| /** | |
| * Whether or not we are testing an iterator that can be | |
| * empty. Default is true. | |
| * | |
| * @return true if Iterators can be empty | |
| */ | |
| public boolean supportsEmptyIterator() { | |
| return true; | |
| } | |
| /** | |
| * Whether or not we are testing an list that allows | |
| * element set. Default is true. | |
| * | |
| * @return true if Lists support element set | |
| */ | |
| public boolean isSetSupported() { | |
| return true; | |
| } | |
| /** | |
| * Returns the {@link collection} field cast to a {@link List}. | |
| * | |
| * @return the collection field as a List | |
| */ | |
| protected List getList() { | |
| return (List)collection; | |
| } | |
| /** | |
| * Returns the {@link confirmed} field cast to a {@link List}. | |
| * | |
| * @return the confirmed field as a List | |
| */ | |
| protected List getConfirmedList() { | |
| return (List)confirmed; | |
| } | |
| public class TestListIterator extends AbstractTestListIterator { | |
| public Object addSetValue() { | |
| return TestList.this.getOtherElements()[0]; | |
| } | |
| public boolean supportsRemove() { | |
| return TestList.this.isRemoveSupported(); | |
| } | |
| public boolean supportsAdd() { | |
| return TestList.this.isAddSupported(); | |
| } | |
| public boolean supportsSet() { | |
| return TestList.this.isSetSupported(); | |
| } | |
| public ListIterator makeEmptyListIterator() { | |
| resetEmpty(); | |
| return ((List) TestList.this.collection).listIterator(); | |
| } | |
| public ListIterator makeFullListIterator() { | |
| resetFull(); | |
| return ((List) TestList.this.collection).listIterator(); | |
| } | |
| public Object makeObject() { | |
| return ((List) TestList.this.collection).listIterator(); | |
| } | |
| } | |
| /** | |
| * Tests the read-only bits of {@link List#listIterator()}. | |
| */ | |
| public void testListListIterator() { | |
| resetFull(); | |
| forwardTest(getList().listIterator(), 0); | |
| backwardTest(getList().listIterator(), 0); | |
| } | |
| /** | |
| * Tests the read-only bits of {@link List#listIterator(int)}. | |
| */ | |
| public void testListListIteratorByIndex() { | |
| resetFull(); | |
| try { | |
| getList().listIterator(-1); | |
| } catch (IndexOutOfBoundsException ex) { | |
| } | |
| resetFull(); | |
| try { | |
| getList().listIterator(getList().size() + 1); | |
| } catch (IndexOutOfBoundsException ex) { | |
| } | |
| resetFull(); | |
| for (int i = 0; i <= confirmed.size(); i++) { | |
| forwardTest(getList().listIterator(i), i); | |
| backwardTest(getList().listIterator(i), i); | |
| } | |
| resetFull(); | |
| for (int i = 0; i <= confirmed.size(); i++) { | |
| backwardTest(getList().listIterator(i), i); | |
| } | |
| } | |
| // ----------------------------------------------------------------------- | |
| /** | |
| * Tests remove on list iterator is correct. | |
| */ | |
| public void testListListIteratorPreviousRemoveNext() { | |
| if (isRemoveSupported() == false) | |
| return; | |
| resetFull(); | |
| if (collection.size() < 4) | |
| return; | |
| ListIterator it = getList().listIterator(); | |
| Object zero = it.next(); | |
| Object one = it.next(); | |
| Object two = it.next(); | |
| Object two2 = it.previous(); | |
| Object one2 = it.previous(); | |
| assertEquals(one, one2); | |
| assertEquals(two, two2); | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(one, getList().get(1)); | |
| assertEquals(two, getList().get(2)); | |
| it.remove(); // removed element at index 1 (one) | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(two, getList().get(1)); | |
| Object two3 = it.next(); // do next after remove | |
| assertEquals(two, two3); | |
| assertEquals(collection.size() > 2, it.hasNext()); | |
| assertEquals(true, it.hasPrevious()); | |
| } | |
| /** | |
| * Tests remove on list iterator is correct. | |
| */ | |
| public void testListListIteratorPreviousRemovePrevious() { | |
| if (isRemoveSupported() == false) | |
| return; | |
| resetFull(); | |
| if (collection.size() < 4) | |
| return; | |
| ListIterator it = getList().listIterator(); | |
| Object zero = it.next(); | |
| Object one = it.next(); | |
| Object two = it.next(); | |
| Object two2 = it.previous(); | |
| Object one2 = it.previous(); | |
| assertEquals(one, one2); | |
| assertEquals(two, two2); | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(one, getList().get(1)); | |
| assertEquals(two, getList().get(2)); | |
| it.remove(); // removed element at index 1 (one) | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(two, getList().get(1)); | |
| Object zero3 = it.previous(); // do previous after remove | |
| assertEquals(zero, zero3); | |
| assertEquals(false, it.hasPrevious()); | |
| assertEquals(collection.size() > 2, it.hasNext()); | |
| } | |
| /** | |
| * Tests remove on list iterator is correct. | |
| */ | |
| public void testListListIteratorNextRemoveNext() { | |
| if (isRemoveSupported() == false) | |
| return; | |
| resetFull(); | |
| if (collection.size() < 4) | |
| return; | |
| ListIterator it = getList().listIterator(); | |
| Object zero = it.next(); | |
| Object one = it.next(); | |
| Object two = it.next(); | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(one, getList().get(1)); | |
| assertEquals(two, getList().get(2)); | |
| Object three = getList().get(3); | |
| it.remove(); // removed element at index 2 (two) | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(one, getList().get(1)); | |
| Object three2 = it.next(); // do next after remove | |
| assertEquals(three, three2); | |
| assertEquals(collection.size() > 3, it.hasNext()); | |
| assertEquals(true, it.hasPrevious()); | |
| } | |
| /** | |
| * Tests remove on list iterator is correct. | |
| */ | |
| public void testListListIteratorNextRemovePrevious() { | |
| if (isRemoveSupported() == false) | |
| return; | |
| resetFull(); | |
| if (collection.size() < 4) | |
| return; | |
| ListIterator it = getList().listIterator(); | |
| Object zero = it.next(); | |
| Object one = it.next(); | |
| Object two = it.next(); | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(one, getList().get(1)); | |
| assertEquals(two, getList().get(2)); | |
| it.remove(); // removed element at index 2 (two) | |
| assertEquals(zero, getList().get(0)); | |
| assertEquals(one, getList().get(1)); | |
| Object one2 = it.previous(); // do previous after remove | |
| assertEquals(one, one2); | |
| assertEquals(true, it.hasNext()); | |
| assertEquals(true, it.hasPrevious()); | |
| } | |
| // ----------------------------------------------------------------------- | |
| /** | |
| * Traverses to the end of the given iterator. | |
| * | |
| * @param iter the iterator to traverse | |
| * @param i the starting index | |
| */ | |
| private void forwardTest(ListIterator iter, int i) { | |
| List list = getList(); | |
| int max = getFullElements().length; | |
| while (i < max) { | |
| assertTrue("Iterator should have next", iter.hasNext()); | |
| assertEquals("Iterator.nextIndex should work", iter.nextIndex(), i); | |
| assertEquals("Iterator.previousIndex should work", iter.previousIndex(), | |
| i - 1); | |
| Object o = iter.next(); | |
| assertEquals("Iterator returned correct element f", list.get(i), o); | |
| i++; | |
| } | |
| assertTrue("Iterator shouldn't have next", !iter.hasNext()); | |
| assertEquals("nextIndex should be size", iter.nextIndex(), max); | |
| assertEquals("previousIndex should be size - 1", iter.previousIndex(), | |
| max - 1); | |
| try { | |
| iter.next(); | |
| fail("Exhausted iterator should raise NoSuchElement"); | |
| } catch (NoSuchElementException e) { | |
| // expected | |
| } | |
| } | |
| /** | |
| * Traverses to the beginning of the given iterator. | |
| * | |
| * @param iter the iterator to traverse | |
| * @param i the starting index | |
| */ | |
| private void backwardTest(ListIterator iter, int i) { | |
| List list = getList(); | |
| while (i > 0) { | |
| assertTrue("Iterator should have previous, i:" + i, iter.hasPrevious()); | |
| assertEquals("Iterator.nextIndex should work, i:" + i, iter.nextIndex(), | |
| i); | |
| assertEquals("Iterator.previousIndex should work, i:" + i, | |
| iter.previousIndex(), i - 1); | |
| Object o = iter.previous(); | |
| assertEquals("Iterator returned correct element b", list.get(i - 1), o); | |
| i--; | |
| } | |
| assertTrue("Iterator shouldn't have previous", !iter.hasPrevious()); | |
| int nextIndex = iter.nextIndex(); | |
| assertEquals("nextIndex should be 0, actual value: " + nextIndex, | |
| nextIndex, 0); | |
| int prevIndex = iter.previousIndex(); | |
| assertEquals("previousIndex should be -1, actual value: " + prevIndex, | |
| prevIndex, -1); | |
| try { | |
| iter.previous(); | |
| fail("Exhausted iterator should raise NoSuchElement"); | |
| } catch (NoSuchElementException e) { | |
| // expected | |
| } | |
| } | |
| /** | |
| * Tests the {@link ListIterator#add(Object)} method of the list iterator. | |
| */ | |
| public void testListIteratorAdd() { | |
| if (!isAddSupported()) | |
| return; | |
| resetEmpty(); | |
| List list1 = getList(); | |
| List list2 = getConfirmedList(); | |
| Object[] elements = getFullElements(); | |
| ListIterator iter1 = list1.listIterator(); | |
| ListIterator iter2 = list2.listIterator(); | |
| for (int i = 0; i < elements.length; i++) { | |
| iter1.add(elements[i]); | |
| iter2.add(elements[i]); | |
| verify(); | |
| } | |
| resetFull(); | |
| iter1 = getList().listIterator(); | |
| iter2 = getConfirmedList().listIterator(); | |
| for (int i = 0; i < elements.length; i++) { | |
| iter1.next(); | |
| iter2.next(); | |
| iter1.add(elements[i]); | |
| iter2.add(elements[i]); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Tests the {@link ListIterator#set(Object)} method of the list iterator. | |
| */ | |
| public void testListIteratorSet() { | |
| if (!isSetSupported()) | |
| return; | |
| Object[] elements = getFullElements(); | |
| resetFull(); | |
| ListIterator iter1 = getList().listIterator(); | |
| ListIterator iter2 = getConfirmedList().listIterator(); | |
| for (int i = 0; i < elements.length; i++) { | |
| iter1.next(); | |
| iter2.next(); | |
| iter1.set(elements[i]); | |
| iter2.set(elements[i]); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Tests {@link List#add(int,Object)}. | |
| */ | |
| public void testListAddByIndex() { | |
| if (!isAddSupported()) return; | |
| Object element = getOtherElements()[0]; | |
| int max = getFullElements().length; | |
| for (int i = 0; i <= max; i++) { | |
| resetFull(); | |
| ((List)collection).add(i, element); | |
| ((List)confirmed).add(i, element); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Tests {@link List#equals(Object)}. | |
| */ | |
| public void testListEquals() { | |
| resetEmpty(); | |
| List list = getList(); | |
| assertTrue("Empty lists should be equal", list.equals(confirmed)); | |
| verify(); | |
| assertTrue("Empty list should equal self", list.equals(list)); | |
| verify(); | |
| List list2 = Arrays.asList(getFullElements()); | |
| assertTrue("Empty list shouldn't equal full", !list.equals(list2)); | |
| verify(); | |
| list2 = Arrays.asList(getOtherElements()); | |
| assertTrue("Empty list shouldn't equal other", !list.equals(list2)); | |
| verify(); | |
| resetFull(); | |
| list = getList(); | |
| assertTrue("Full lists should be equal", list.equals(confirmed)); | |
| verify(); | |
| assertTrue("Full list should equal self", list.equals(list)); | |
| verify(); | |
| list2 = makeEmptyList(); | |
| assertTrue("Full list shouldn't equal empty", !list.equals(list2)); | |
| verify(); | |
| list2 = Arrays.asList(getOtherElements()); | |
| assertTrue("Full list shouldn't equal other", !list.equals(list2)); | |
| verify(); | |
| list2 = Arrays.asList(getFullElements()); | |
| Collections.reverse(list2); | |
| assertTrue("Full list shouldn't equal full list with same elements" + | |
| " but different order", !list.equals(list2)); | |
| verify(); | |
| assertTrue("List shouldn't equal String", !list.equals("")); | |
| verify(); | |
| final List listForC = Arrays.asList(getFullElements()); | |
| Collection c = new AbstractCollection() { | |
| public int size() { | |
| return listForC.size(); | |
| } | |
| public Iterator iterator() { | |
| return listForC.iterator(); | |
| } | |
| }; | |
| assertTrue("List shouldn't equal nonlist with same elements " + | |
| " in same order", !list.equals(c)); | |
| verify(); | |
| } | |
| /** | |
| * Tests {@link List#hashCode()}. | |
| */ | |
| public void testListHashCode() { | |
| resetEmpty(); | |
| int hash1 = collection.hashCode(); | |
| int hash2 = confirmed.hashCode(); | |
| assertEquals("Empty lists should have equal hashCodes", hash1, hash2); | |
| verify(); | |
| resetFull(); | |
| hash1 = collection.hashCode(); | |
| hash2 = confirmed.hashCode(); | |
| assertEquals("Full lists should have equal hashCodes", hash1, hash2); | |
| verify(); | |
| } | |
| /** | |
| * Tests {@link List#get(int)}. | |
| */ | |
| public void testListGetByIndex() { | |
| resetFull(); | |
| List list = getList(); | |
| Object[] elements = getFullElements(); | |
| for (int i = 0; i < elements.length; i++) { | |
| assertEquals("List should contain correct elements", | |
| elements[i], list.get(i)); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Tests {@link List#indexOf()}. | |
| */ | |
| public void testListIndexOf() { | |
| resetFull(); | |
| List list1 = getList(); | |
| List list2 = getConfirmedList(); | |
| Iterator iterator = list2.iterator(); | |
| while (iterator.hasNext()) { | |
| Object element = iterator.next(); | |
| assertEquals("indexOf should return correct result", | |
| list1.indexOf(element), list2.indexOf(element)); | |
| verify(); | |
| } | |
| Object[] other = getOtherElements(); | |
| for (int i = 0; i < other.length; i++) { | |
| assertEquals("indexOf should return -1 for nonexistent element", | |
| list1.indexOf(other[i]), -1); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Tests {@link List#lastIndexOf()}. | |
| */ | |
| public void testListLastIndexOf() { | |
| resetFull(); | |
| List list1 = getList(); | |
| List list2 = getConfirmedList(); | |
| Iterator iterator = list2.iterator(); | |
| while (iterator.hasNext()) { | |
| Object element = iterator.next(); | |
| assertEquals("lastIndexOf should return correct result", | |
| list1.lastIndexOf(element), list2.lastIndexOf(element)); | |
| verify(); | |
| } | |
| Object[] other = getOtherElements(); | |
| for (int i = 0; i < other.length; i++) { | |
| assertEquals("lastIndexOf should return -1 for nonexistent " + | |
| "element", list1.lastIndexOf(other[i]), -1); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Tests {@link List#remove(int)}. | |
| */ | |
| public void testListRemoveByIndex() { | |
| if (!isRemoveSupported()) return; | |
| int max = getFullElements().length; | |
| for (int i = 0; i < max; i++) { | |
| resetFull(); | |
| Object o1 = ((List)collection).remove(i); | |
| Object o2 = ((List)confirmed).remove(i); | |
| assertEquals("remove should return correct element", o1, o2); | |
| verify(); | |
| } | |
| } | |
| /** | |
| * Returns an empty {@link ArrayList}. | |
| */ | |
| protected Collection makeConfirmedCollection() { | |
| ArrayList list = new ArrayList(); | |
| return list; | |
| } | |
| /** | |
| * Returns a full {@link ArrayList}. | |
| */ | |
| protected Collection makeConfirmedFullCollection() { | |
| ArrayList list = new ArrayList(); | |
| list.addAll(Arrays.asList(getFullElements())); | |
| return list; | |
| } | |
| /** | |
| * Verifies that the test list implementation matches the confirmed list | |
| * implementation. | |
| */ | |
| protected void verify() { | |
| super.verify(); | |
| List list1 = getList(); | |
| List list2 = getConfirmedList(); | |
| assertEquals("List should equal confirmed", list1, list2); | |
| assertEquals("Confirmed should equal list", list2, list1); | |
| assertEquals("Hash codes should be equal", | |
| list1.hashCode(), list2.hashCode()); | |
| int i = 0; | |
| Iterator iterator1 = list1.iterator(); | |
| Iterator iterator2 = list2.iterator(); | |
| Object[] array = list1.toArray(); | |
| while (iterator2.hasNext()) { | |
| assertTrue("List iterator should have next", iterator1.hasNext()); | |
| Object o1 = iterator1.next(); | |
| Object o2 = iterator2.next(); | |
| assertEquals("Iterator elements should be equal", o1, o2); | |
| o2 = list1.get(i); | |
| assertEquals("get should return correct element", o1, o2); | |
| o2 = array[i]; | |
| assertEquals("toArray should have correct element", o1, o2); | |
| i++; | |
| } | |
| } | |
| } |