/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.list; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import org.apache.commons.collections.BulkTest; import org.apache.commons.collections.collection.AbstractTestCollection; import org.apache.commons.collections.iterators.AbstractTestListIterator; /** * Abstract test class for {@link java.util.List} methods and contracts. * <p> * To use, simply extend this class, and implement * the {@link #makeEmptyList} 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 or override one of the * protected methods from AbstractTestCollection. * * @version $Revision: 646780 $ $Date: 2008-04-10 13:48:07 +0100 (Thu, 10 Apr 2008) $ * * @author Rodney Waldhoff * @author Paul Jack * @author Stephen Colebourne * @author Neil O'Toole */ public abstract class AbstractTestList extends AbstractTestCollection { /** * JUnit constructor. * * @param testName the test class name */ public AbstractTestList(String testName) { super(testName); } //----------------------------------------------------------------------- /** * Returns true if the collections produced by * {@link #makeCollection()} and {@link #makeFullCollection()} * support the <code>set operation.<p> * Default implementation returns true. Override if your collection * class does not support set. */ public boolean isSetSupported() { return true; } //----------------------------------------------------------------------- /** * Verifies that the test list implementation matches the confirmed list * implementation. */ public 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++; } } //----------------------------------------------------------------------- /** * List equals method is defined. */ public boolean isEqualsCheckable() { return true; } /** * Returns an empty {@link ArrayList}. */ public Collection makeConfirmedCollection() { ArrayList list = new ArrayList(); return list; } /** * Returns a full {@link ArrayList}. */ public Collection makeConfirmedFullCollection() { ArrayList list = new ArrayList(); list.addAll(Arrays.asList(getFullElements())); return list; } /** * Return a new, empty {@link List} to be used for testing. * * @return an empty list for testing. */ public abstract List makeEmptyList(); /** * Return a new, full {@link List} to be used for testing. * * @return a full list for testing */ public 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 */ public final Collection makeCollection() { return makeEmptyList(); } /** * Returns {@link #makeFullList()}. * * @return a full list to be used for testing */ public final Collection makeFullCollection() { return makeFullList(); } //----------------------------------------------------------------------- /** * Returns the {@link #collection} field cast to a {@link List}. * * @return the collection field as a List */ public List getList() { return (List) collection; } /** * Returns the {@link #confirmed} field cast to a {@link List}. * * @return the confirmed field as a List */ public List getConfirmedList() { return (List) confirmed; } //----------------------------------------------------------------------- /** * Tests bounds checking for {@link List#add(int, Object)} on an * empty list. */ public void testListAddByIndexBoundsChecking() { if (!isAddSupported()) { return; } List list; Object element = getOtherElements()[0]; try { list = makeEmptyList(); list.add(Integer.MIN_VALUE, element); fail("List.add should throw IndexOutOfBoundsException [Integer.MIN_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } try { list = makeEmptyList(); list.add(-1, element); fail("List.add should throw IndexOutOfBoundsException [-1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list = makeEmptyList(); list.add(1, element); fail("List.add should throw IndexOutOfBoundsException [1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list = makeEmptyList(); list.add(Integer.MAX_VALUE, element); fail("List.add should throw IndexOutOfBoundsException [Integer.MAX_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } } /** * Tests bounds checking for {@link List#add(int, Object)} on a * full list. */ public void testListAddByIndexBoundsChecking2() { if (!isAddSupported()) { return; } List list; Object element = getOtherElements()[0]; try { list = makeFullList(); list.add(Integer.MIN_VALUE, element); fail("List.add should throw IndexOutOfBoundsException [Integer.MIN_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } try { list = makeFullList(); list.add(-1, element); fail("List.add should throw IndexOutOfBoundsException [-1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list = makeFullList(); list.add(list.size() + 1, element); fail("List.add should throw IndexOutOfBoundsException [size + 1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list = makeFullList(); list.add(Integer.MAX_VALUE, element); fail("List.add should throw IndexOutOfBoundsException [Integer.MAX_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } } /** * 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(); assertEquals("Empty lists should be equal", true, list.equals(confirmed)); verify(); assertEquals("Empty list should equal self", true, list.equals(list)); verify(); List list2 = Arrays.asList(getFullElements()); assertEquals("Empty list shouldn't equal full", false, list.equals(list2)); verify(); list2 = Arrays.asList(getOtherElements()); assertEquals("Empty list shouldn't equal other", false, list.equals(list2)); verify(); resetFull(); list = getList(); assertEquals("Full lists should be equal", true, list.equals(confirmed)); verify(); assertEquals("Full list should equal self", true, list.equals(list)); verify(); list2 = makeEmptyList(); assertEquals("Full list shouldn't equal empty", false, list.equals(list2)); verify(); list2 = Arrays.asList(getOtherElements()); assertEquals("Full list shouldn't equal other", false, list.equals(list2)); verify(); list2 = Arrays.asList(getFullElements()); if (list2.size() < 2 && isAddSupported()) { // main list is only size 1, so lets add other elements to get a better list list.addAll(Arrays.asList(getOtherElements())); confirmed.addAll(Arrays.asList(getOtherElements())); list2 = new ArrayList(list2); list2.addAll(Arrays.asList(getOtherElements())); } if (list2.size() > 1) { Collections.reverse(list2); assertEquals( "Full list shouldn't equal full list with same elements but different order", false, list.equals(list2)); verify(); } resetFull(); list = getList(); assertEquals("List shouldn't equal String", false, 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(); } }; assertEquals("List shouldn't equal nonlist with same elements in same order", false, 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 bounds checking for {@link List#get(int)} on an * empty list. */ public void testListGetByIndexBoundsChecking() { List list = makeEmptyList(); try { list.get(Integer.MIN_VALUE); fail("List.get should throw IndexOutOfBoundsException [Integer.MIN_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(-1); fail("List.get should throw IndexOutOfBoundsException [-1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(0); fail("List.get should throw IndexOutOfBoundsException [0]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(1); fail("List.get should throw IndexOutOfBoundsException [1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(Integer.MAX_VALUE); fail("List.get should throw IndexOutOfBoundsException [Integer.MAX_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } } /** * Tests bounds checking for {@link List#get(int)} on a * full list. */ public void testListGetByIndexBoundsChecking2() { List list = makeFullList(); try { list.get(Integer.MIN_VALUE); fail("List.get should throw IndexOutOfBoundsException [Integer.MIN_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(-1); fail("List.get should throw IndexOutOfBoundsException [-1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(getFullElements().length); fail("List.get should throw IndexOutOfBoundsException [size]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.get(Integer.MAX_VALUE); fail("List.get should throw IndexOutOfBoundsException [Integer.MAX_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } } /** * 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 bounds checking for {@link List#set(int,Object)} on an * empty list. */ public void testListSetByIndexBoundsChecking() { if (!isSetSupported()) { return; } List list = makeEmptyList(); Object element = getOtherElements()[0]; try { list.set(Integer.MIN_VALUE, element); fail("List.set should throw IndexOutOfBoundsException [Integer.MIN_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.set(-1, element); fail("List.set should throw IndexOutOfBoundsException [-1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.set(0, element); fail("List.set should throw IndexOutOfBoundsException [0]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.set(1, element); fail("List.set should throw IndexOutOfBoundsException [1]"); } catch (IndexOutOfBoundsException e) { // expected } try { list.set(Integer.MAX_VALUE, element); fail("List.set should throw IndexOutOfBoundsException [Integer.MAX_VALUE]"); } catch (IndexOutOfBoundsException e) { // expected } } /** * Tests bounds checking for {@link List#set(int,Object)} on a * full list. */ public void testListSetByIndexBoundsChecking2() { if (!isSetSupported()) return; List list = makeFullList(); Object element = getOtherElements()[0]; try { list.set(Integer.MIN_VALUE, element); fail("List.set should throw IndexOutOfBoundsException " + "[Integer.MIN_VALUE]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.set(-1, element); fail("List.set should throw IndexOutOfBoundsException [-1]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.set(getFullElements().length, element); fail("List.set should throw IndexOutOfBoundsException [size]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.set(Integer.MAX_VALUE, element); fail("List.set should throw IndexOutOfBoundsException " + "[Integer.MAX_VALUE]"); } catch(IndexOutOfBoundsException e) { // expected } } /** * Test {@link List#set(int,Object)}. */ public void testListSetByIndex() { if (!isSetSupported()) return; resetFull(); Object[] elements = getFullElements(); Object[] other = getOtherElements(); for (int i = 0; i < elements.length; i++) { Object n = other[i % other.length]; Object v = ((List)collection).set(i, n); assertEquals("Set should return correct element", elements[i], v); ((List)confirmed).set(i, n); verify(); } } /** * If {@link #isSetSupported()} returns false, tests that set operation * raises <Code>UnsupportedOperationException. */ public void testUnsupportedSet() { if (isSetSupported()) return; resetFull(); try { ((List) collection).set(0, new Object()); fail("Emtpy collection should not support set."); } catch (UnsupportedOperationException e) { // expected } // make sure things didn't change even if the expected exception was // thrown. verify(); } /** * Tests bounds checking for {@link List#remove(int)} on an * empty list. */ public void testListRemoveByIndexBoundsChecking() { if (!isRemoveSupported()) return; List list = makeEmptyList(); try { list.remove(Integer.MIN_VALUE); fail("List.remove should throw IndexOutOfBoundsException " + "[Integer.MIN_VALUE]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(-1); fail("List.remove should throw IndexOutOfBoundsException [-1]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(0); fail("List.remove should throw IndexOutOfBoundsException [0]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(1); fail("List.remove should throw IndexOutOfBoundsException [1]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(Integer.MAX_VALUE); fail("List.remove should throw IndexOutOfBoundsException " + "[Integer.MAX_VALUE]"); } catch(IndexOutOfBoundsException e) { // expected } } /** * Tests bounds checking for {@link List#remove(int)} on a * full list. */ public void testListRemoveByIndexBoundsChecking2() { if (!isRemoveSupported()) return; List list = makeFullList(); try { list.remove(Integer.MIN_VALUE); fail("List.remove should throw IndexOutOfBoundsException " + "[Integer.MIN_VALUE]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(-1); fail("List.remove should throw IndexOutOfBoundsException [-1]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(getFullElements().length); fail("List.remove should throw IndexOutOfBoundsException [size]"); } catch(IndexOutOfBoundsException e) { // expected } try { list.remove(Integer.MAX_VALUE); fail("List.remove should throw IndexOutOfBoundsException " + "[Integer.MAX_VALUE]"); } catch(IndexOutOfBoundsException e) { // expected } } /** * 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(); } } /** * 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", 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", 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(); } } public void testEmptyListSerialization() throws IOException, ClassNotFoundException { List list = makeEmptyList(); if (!(list instanceof Serializable && isTestSerialization())) return; byte[] objekt = writeExternalFormToBytes((Serializable) list); List list2 = (List) readExternalFormFromBytes(objekt); assertTrue("Both lists are empty",list.size() == 0); assertTrue("Both lists are empty",list2.size() == 0); } public void testFullListSerialization() throws IOException, ClassNotFoundException { List list = makeFullList(); int size = getFullElements().length; if (!(list instanceof Serializable && isTestSerialization())) return; byte[] objekt = writeExternalFormToBytes((Serializable) list); List list2 = (List) readExternalFormFromBytes(objekt); assertEquals("Both lists are same size",list.size(), size); assertEquals("Both lists are same size",list2.size(), size); } /** * Compare the current serialized form of the List * against the canonical version in CVS. */ public void testEmptyListCompatibility() throws IOException, ClassNotFoundException { /** * Create canonical objects with this code List list = makeEmptyList(); if (!(list instanceof Serializable)) return; writeExternalFormToDisk((Serializable) list, getCanonicalEmptyCollectionName(list)); */ // test to make sure the canonical form has been preserved List list = makeEmptyList(); if(list instanceof Serializable && !skipSerializedCanonicalTests() && isTestSerialization()) { List list2 = (List) readExternalFormFromDisk(getCanonicalEmptyCollectionName(list)); assertTrue("List is empty",list2.size() == 0); assertEquals(list, list2); } } /** * Compare the current serialized form of the List * against the canonical version in CVS. */ public void testFullListCompatibility() throws IOException, ClassNotFoundException { /** * Create canonical objects with this code List list = makeFullList(); if (!(list instanceof Serializable)) return; writeExternalFormToDisk((Serializable) list, getCanonicalFullCollectionName(list)); */ // test to make sure the canonical form has been preserved List list = makeFullList(); if(list instanceof Serializable && !skipSerializedCanonicalTests() && isTestSerialization()) { List list2 = (List) readExternalFormFromDisk(getCanonicalFullCollectionName(list)); if (list2.size() == 4) { // old serialized tests return; } assertEquals("List is the right size",list.size(), list2.size()); assertEquals(list, list2); } } //----------------------------------------------------------------------- /** * Returns a {@link BulkTest} for testing {@link List#subList(int,int)}. * The returned bulk test will run through every <code>TestList</code> * method, <i>including</i> another <code>bulkTestSubList</code>. * Sublists are tested until the size of the sublist is less than 10. * Each sublist is 6 elements smaller than its parent list. * (By default this means that two rounds of sublists will be tested). * The verify() method is overloaded to test that the original list is * modified when the sublist is. */ public BulkTest bulkTestSubList() { if (getFullElements().length - 6 < 10) return null; return new BulkTestSubList(this); } public static class BulkTestSubList extends AbstractTestList { private AbstractTestList outer; public BulkTestSubList(AbstractTestList outer) { super(""); this.outer = outer; } public Object[] getFullElements() { List l = Arrays.asList(outer.getFullElements()); return l.subList(3, l.size() - 3).toArray(); } public Object[] getOtherElements() { return outer.getOtherElements(); } public boolean isAddSupported() { return outer.isAddSupported(); } public boolean isSetSupported() { return outer.isSetSupported(); } public boolean isRemoveSupported() { return outer.isRemoveSupported(); } public List makeEmptyList() { return outer.makeFullList().subList(4, 4); } public List makeFullList() { int size = getFullElements().length; return outer.makeFullList().subList(3, size - 3); } public void resetEmpty() { outer.resetFull(); this.collection = outer.getList().subList(4, 4); this.confirmed = outer.getConfirmedList().subList(4, 4); } public void resetFull() { outer.resetFull(); int size = outer.confirmed.size(); this.collection = outer.getList().subList(3, size - 3); this.confirmed = outer.getConfirmedList().subList(3, size - 3); } public void verify() { super.verify(); outer.verify(); } public boolean isTestSerialization() { return false; } } /** * Tests that a sublist raises a {@link java.util.ConcurrentModificationException ConcurrentModificationException} * if elements are added to the original list. */ public void testListSubListFailFastOnAdd() { if (!isFailFastSupported()) return; if (!isAddSupported()) return; resetFull(); int size = collection.size(); List sub = getList().subList(1, size); getList().add(getOtherElements()[0]); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().add(0, getOtherElements()[0]); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().addAll(Arrays.asList(getOtherElements())); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().addAll(0, Arrays.asList(getOtherElements())); failFastAll(sub); } /** * Tests that a sublist raises a {@link java.util.ConcurrentModificationException ConcurrentModificationException} * if elements are removed from the original list. */ public void testListSubListFailFastOnRemove() { if (!isFailFastSupported()) return; if (!isRemoveSupported()) return; resetFull(); int size = collection.size(); List sub = getList().subList(1, size); getList().remove(0); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().remove(getFullElements()[2]); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().removeAll(Arrays.asList(getFullElements())); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().retainAll(Arrays.asList(getOtherElements())); failFastAll(sub); resetFull(); sub = getList().subList(1, size); getList().clear(); failFastAll(sub); } /** * Invokes all the methods on the given sublist to make sure they raise * a {@link java.util.ConcurrentModificationException ConcurrentModificationException}. */ protected void failFastAll(List list) { Method[] methods = List.class.getMethods(); for (int i = 0; i < methods.length; i++) { failFastMethod(list, methods[i]); } } /** * Invokes the given method on the given sublist to make sure it raises * a {@link java.util.ConcurrentModificationException ConcurrentModificationException}. * * Unless the method happens to be the equals() method, in which case * the test is skipped. There seems to be a bug in * java.util.AbstractList.subList(int,int).equals(Object) -- it never * raises a ConcurrentModificationException. * * @param list the sublist to test * @param m the method to invoke */ protected void failFastMethod(List list, Method m) { if (m.getName().equals("equals")) return; Object element = getOtherElements()[0]; Collection c = Collections.singleton(element); Class[] types = m.getParameterTypes(); Object[] params = new Object[types.length]; for (int i = 0; i < params.length; i++) { if (types[i] == Integer.TYPE) params[i] = new Integer(0); else if (types[i] == Collection.class) params[i] = c; else if (types[i] == Object.class) params[i] = element; else if (types[i] == Object[].class) params[i] = new Object[0]; } try { m.invoke(list, params); fail(m.getName() + " should raise ConcurrentModification"); } catch (IllegalAccessException e) { // impossible } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if (t instanceof ConcurrentModificationException) { // expected return; } else { fail(m.getName() + " raised unexpected " + e); } } } //----------------------------------------------------------------------- public BulkTest bulkTestListIterator() { return new TestListIterator(); } public class TestListIterator extends AbstractTestListIterator { public TestListIterator() { super("TestListIterator"); } public Object addSetValue() { return AbstractTestList.this.getOtherElements()[0]; } public boolean supportsRemove() { return AbstractTestList.this.isRemoveSupported(); } public boolean supportsAdd() { return AbstractTestList.this.isAddSupported(); } public boolean supportsSet() { return AbstractTestList.this.isSetSupported(); } public ListIterator makeEmptyListIterator() { resetEmpty(); return ((List) AbstractTestList.this.collection).listIterator(); } public ListIterator makeFullListIterator() { resetFull(); return ((List) AbstractTestList.this.collection).listIterator(); } } }