org.jdom2.test.util.AbstractTestList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdom Show documentation
Show all versions of jdom Show documentation
A complete, Java-based solution for accessing, manipulating,
and outputting XML data
The newest version!
package org.jdom2.test.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.jdom2.test.util.UnitTestUtil.*;
import java.lang.reflect.Array;
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.junit.Test;
import org.jdom2.internal.ArrayCopy;
/**
* This base class can be used to test multiple implementations of List>
* It is reusable for different list types, and does the 'normal' type testing.
*
*
*
* @author Rolf Lear
*
*/
@SuppressWarnings({ "unchecked", "javadoc" })
public abstract class AbstractTestList {
/**
* The following is a list of somewhat binary-progressive prime numbers.
* sequence is +2, +2, +2, +2, +4, +4, +4, +4, +8, +8, +8, +8,
* +16, +16, +16, +16, +32, ......
* given the above sequence, get the first prime number that is larger than
* the sequence value.
*/
private static final int[] BIGPRIMES = new int[] {3, 5, 7, 11, 13, 17, 23,
29, 37, 41, 53, 59, 73, 89, 107, 127, 157, 191, 223, 251, 313, 379, 443,
509, 641, 761, 907, 1019, 1277, 1531, 1787, 2053, 2557, 3067, 3581,
4091, 5113, 6143, 7177, 8191, 10243, 12281, 14341, 16381, 20477, 24571,
28669, 32771, 40961, 49157, 57347, 65537, 81919, 98297, 114689, 131071,
163841, 196613, 229373, 262139, 327673, 393209, 458747, 524287, 655357,
786431, 917503, 1048571};
private static final int[][] SMALLSHUFFLE = new int[][] {
new int[]{},
new int[]{0},
new int[]{1,0},
new int[]{2, 0, 1},
new int[]{2, 0, 3, 1},
new int[]{4, 1, 2, 0, 3},
new int[]{3, 0, 2, 4, 5, 1}
};
private final boolean i_nullok;
private final Class i_tclass;
/**
* Generalised constructor for testing a list.
* @param tclass all content should be an instance (or subtype) of this class
* @param nullok are null values allowed on the list.
* @param samplecontent some sample data to load in to the list. The more, the better.
*/
public AbstractTestList(Class tclass, boolean nullok) {
super();
i_nullok = nullok;
i_tclass = tclass;
}
/**
* Create a list of the type to test. It should be empty.
* @return the list to test.
*/
public abstract List buildEmptyList();
/**
* This is sample data that should be legal in the list.
* There should be at least 10 or so elements.
* @return the sample data.
*/
public abstract T[] buildSampleContent();
/**
* This should contain at least one additional valid entry
* that can be legally be added to the list after it is already populated
* with the sample data.
* @return the extra data.
*/
public abstract T[] buildAdditionalContent();
/**
* This should contain data that is of the correct generic type of the data
* but has some property that makes it illegal. This can be empty....
* @return the IllegalArgument test data.
*/
public abstract T[] buildIllegalArgumentContent();
/**
* This list should be of content that is of the wrong class (a class not
* compatible with
* @return the ClassCast test data.
*/
public abstract Object[] buildIllegalClassContent();
/* *********************************
* Private support methods
* ********************************* */
/**
* Create an array of the required type with the required length
* @param length The length of the array to create.
* @return the created array.
*/
protected final T[] buildArray(int length) {
return (T[])Array.newInstance(i_tclass, length);
}
/**
* Remove an element from an array.
* @param content The original content.
* @param index The element to remove
* @return a new array with the specified element removed.
*/
protected final T[] arrayRemove(T[] content, int index) {
if (index < 0 || index >= content.length) {
throw new IllegalArgumentException("Can not have index " + index
+ " when there are only " + content.length + " elements.");
}
T[] ret = ArrayCopy.copyOf(content, content.length - 1);
System.arraycopy(content, index + 1, ret, index, ret.length - index);
return ret;
}
/**
* Insert an element in to the content at the specified index.
* @param content The base content to add to.
* @param index The position to insert (items from this position will be
* moved to the right). Using content.lenght will add to the end.
* @param insert The value to insert
* @return The amended content array
*/
protected final T[] arrayInsert(T[] content, int index, T...insert) {
if (index < 0 || index > content.length) {
throw new IllegalArgumentException("Can not use index " + index
+ " when there is only " + content.length + " content.");
}
if (insert == null) {
throw new NullPointerException("Can not have a null insert vararg array");
}
T[] ret = ArrayCopy.copyOf(content, content.length + insert.length);
System.arraycopy(ret, index, ret, index+insert.length, content.length - index);
System.arraycopy(insert, 0, ret, index, insert.length);
return ret;
}
/**
* Reverse the contents of an array.
* @param content The array to reverse.
* @return a new array with the same content as the input, but in reverse
* order
*/
protected final T[] arrayReverse(T[] content) {
T[] ret = ArrayCopy.copyOf(content, content.length);
for (int i = (content.length - 1) / 2; i >= 0; i--) {
final T tmp = ret[i];
ret[i] = ret[ret.length - 1 - i];
ret[ret.length - 1 - i] = tmp;
}
return ret;
}
private final int pickPrime(final int len) {
if (len < SMALLSHUFFLE.length) {
throw new IllegalStateException("Should have a prime set already");
}
int pindex = 0;
while (pindex < BIGPRIMES.length && BIGPRIMES[pindex] <= (len / 2)) {
pindex++;
}
if (pindex >= BIGPRIMES.length) {
throw new IllegalStateException("Unable to create a shuffled order " +
"for that many elements: " + len);
}
return BIGPRIMES[pindex];
}
/*
* helper method for shuffle().
*/
private final int shuffleCompute(final int offset, final int len, final int prime) {
// Integer.MAX_INT is a prime number... but too big
// Using a Prime in this way guarantees that we loop through all the values
// in the sequence without having duplicates.
return (offset + prime) % len;
}
/**
* Generate a (very) pseudo-random order of a given length.
* The shuffled order is always repeatable, predictable, but also
* appears 'random'. This is useful so that we can compare strange-ordered
* inserts/removes/sets.
* @param len How many elements to include.
* @return An array of int. Each value will be unique, from 0 to len-1
*/
protected final int[] shuffle(final int len) {
if (len < SMALLSHUFFLE.length) {
return ArrayCopy.copyOf(SMALLSHUFFLE[len], len);
}
final int prime = pickPrime(len);
int[] ret = new int[len];
int c = shuffleCompute(0, len, prime);
for (int i = len - 1; i >= 0; i--) {
c = shuffleCompute(c, len, prime);
if (ret[c] != 0) {
// this should never happen, but this is a double-check
// guarantee that we never miss values in the sequence.
throw new IllegalStateException("Oops");
}
ret[c] = i;
}
return ret;
}
/**
* Run a list though the basic paces of operation.
* @param list the List to exercise.
* @param content the content (in the order) that we expect in the list.
*/
protected final void exercise(List list, T...content) {
assertTrue("List is null", list != null);
assertTrue("Content is null", content != null);
assertTrue(content.length == list.size());
assertTrue(list.toString() != null);
if (content.length == 0) {
assertTrue(list.size() == 0);
assertTrue(list.isEmpty());
} else {
assertTrue(list.size() > 0);
assertFalse(list.isEmpty());
}
for (int i = 0; i < content.length; i++) {
if (list.get(i) != content[i]) {
fail(String.format("We expect element in list at position %d to be %s",
i, content[i]));
}
int pos = list.indexOf(content[i]);
assertTrue(pos >= 0);
if (pos != i) {
// may be duplicates in the list....
assertTrue(pos < i); // but pos must be first...
assertEquals(content[pos], content[i]);
}
assertTrue(list.contains(content[i]));
}
for (int i = content.length - 1; i >= 0; i--) {
assertTrue(list.get(i) == content[i]);
int pos = list.lastIndexOf(content[i]);
assertTrue(pos >= 0);
if (pos != i) {
// may be duplicates in the list....
assertTrue(pos > i); // but pos must be later...
assertEquals(content[pos], content[i]);
}
}
quickCheck(list, content);
{
// Check the iteration code.
// the iterator implementation can be different to the ListIterator
Iterator it = list.iterator();
try {
it.remove();
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
int i = 0;
while (i < content.length) {
assertTrue(it.hasNext());
assertTrue(it.next() == content[i]);
it.remove();
try {
it.remove();
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
i++;
}
assertFalse(it.hasNext());
try {
it.next();
failNoException(NoSuchElementException.class);
} catch (Exception e) {
checkException(NoSuchElementException.class, e);
}
try {
it.remove();
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
for (T d : content) {
list.add(d);
}
}
quickCheck(list, content);
{
//Read-Only List iteration through list contents.
for (int origin = 0; origin <= content.length; origin++) {
// start at every place
ListIterator li = list.listIterator(origin);
for (int i = origin; i < content.length; i++) {
assertTrue(li.hasNext());
assertTrue(li.nextIndex() == i);
assertTrue(li.previousIndex() == i - 1);
T emt = li.next();
assertTrue(content[i] == emt);
}
assertTrue(li.nextIndex() == content.length);
assertFalse(li.hasNext());
try {
li.next();
failNoException(NoSuchElementException.class);
} catch (Exception e) {
checkException(NoSuchElementException.class, e);
}
assertTrue(li.previousIndex() == (content.length - 1));
for (int i = content.length - 1; i >= 0; i--) {
assertTrue(li.previousIndex() == i);
assertTrue(li.nextIndex() == i + 1);
assertTrue(li.hasPrevious());
T emt = li.previous();
assertTrue(content[i] == emt);
}
assertTrue(li.previousIndex() == -1);
assertFalse(li.hasPrevious());
try {
li.previous();
failNoException(NoSuchElementException.class);
} catch (Exception e) {
checkException(NoSuchElementException.class, e);
}
assertTrue(li.nextIndex() == 0);
for (int i = 0; i < origin; i++) {
assertTrue(li.hasNext());
assertTrue(li.nextIndex() == i);
assertTrue(content[i] == li.next());
}
ListIterator fbli = list.listIterator(origin);
assertTrue(fbli.nextIndex() == origin);
assertTrue(fbli.previousIndex() == (origin - 1));
}
}
{
//Read/write List iteration through list contents.
for (int origin = 0; origin <= content.length; origin++) {
// start at every place
ListIterator li = list.listIterator(origin);
for (int i = origin; i < content.length; i++) {
assertTrue(li.hasNext());
assertTrue(li.nextIndex() == i);
assertTrue(li.previousIndex() == i - 1);
T emt = li.next();
assertTrue(content[i] == emt);
int n = li.nextIndex();
int p = li.previousIndex();
li.remove();
assertTrue(p - 1 == li.previousIndex());
assertTrue(n - 1 == li.nextIndex());
try {
li.remove();
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
li.add(emt);
assertTrue(p == li.previousIndex());
assertTrue(n == li.nextIndex());
}
assertTrue(li.nextIndex() == content.length);
assertFalse(li.hasNext());
try {
li.next();
failNoException(NoSuchElementException.class);
} catch (Exception e) {
checkException(NoSuchElementException.class, e);
}
assertTrue(li.previousIndex() == (content.length - 1));
for (int i = content.length - 1; i >= 0; i--) {
assertTrue(li.previousIndex() == i);
assertTrue(li.nextIndex() == i + 1);
assertTrue(li.hasPrevious());
T emt = li.previous();
assertTrue(content[i] == emt);
int p = li.previousIndex();
int n = li.nextIndex();
li.remove();
assertTrue(p == li.previousIndex());
assertTrue(n == li.nextIndex());
try {
li.remove();
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
li.add(emt);
assertTrue(content[i] == li.previous());
assertTrue(p == li.previousIndex());
assertTrue(n == li.nextIndex());
}
assertTrue(li.previousIndex() == -1);
assertFalse(li.hasPrevious());
try {
li.previous();
failNoException(NoSuchElementException.class);
} catch (Exception e) {
checkException(NoSuchElementException.class, e);
}
assertTrue(li.nextIndex() == 0);
for (int i = 0; i < origin; i++) {
assertTrue(li.hasNext());
assertTrue(li.nextIndex() == i);
assertTrue(content[i] == li.next());
}
ListIterator fbli = list.listIterator(origin);
assertTrue(fbli.nextIndex() == origin);
assertTrue(fbli.previousIndex() == (origin - 1));
}
quickCheck(list, content);
}
{
// remove all, and re-add them.
ListIterator it = list.listIterator(0);
for (int i = 0; i < content.length; i++) {
assertTrue(it.hasNext());
assertTrue(it.next() == content[i]);
it.remove();
}
for (int i = 0; i < content.length; i++) {
assertFalse(it.hasNext());
it.add(content[i]);
assertTrue(it.hasPrevious());
assertFalse(it.hasNext());
assertTrue(content[i] == it.previous());
assertTrue(content[i] == it.next());
assertFalse(it.hasNext());
}
assertFalse(it.hasNext());
quickCheck(list, content);
// then do it backwards.
it = list.listIterator(content.length);
for (int i = content.length - 1; i >= 0; i--) {
assertTrue(it.hasPrevious());
assertTrue(it.previous() == content[i]);
it.remove();
}
for (int i = content.length - 1; i >= 0; i--) {
assertFalse(it.hasPrevious());
it.add(content[i]);
assertTrue(it.hasPrevious());
assertTrue(content[i] == it.previous());
assertFalse(it.hasPrevious());
assertTrue(it.hasNext());
}
assertFalse(it.hasPrevious());
quickCheck(list, content);
}
if (content.length > 0) {
// Check the iterator set() method.
// first forward....
ListIterator li = list.listIterator();
try {
li.set(content[0]);
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
T tmpa = li.next();
li.remove();
for (int i = 1; i < content.length; i++) {
T tmpb = li.next();
assertTrue(content[i] == tmpb);
li.set(tmpa);
tmpa = tmpb;
}
li.add(tmpa);
quickCheck(list, content);
// then backward ....
try {
li.set(content[0]);
failNoException(IllegalStateException.class);
} catch (Exception e) {
checkException(IllegalStateException.class, e);
}
tmpa = li.previous();
li.remove();
for (int i = content.length - 2; i >= 0; i--) {
T tmpb = li.previous();
assertTrue(content[i] == tmpb);
li.set(tmpa);
tmpa = tmpb;
}
li.add(tmpa);
quickCheck(list, content);
}
}
private void illegalExercise(List list, T[] content, T d,
Class extends Exception> eclass) {
quickCheck(list, content);
try {
list.add(d);
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
try {
list.addAll(Collections.singleton(d));
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
for (int i = list.size() - 1; i >= 0; i--) {
try {
list.set(i, d);
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
}
for (int i = list.size(); i >= 0; i--) {
try {
list.add(i, d);
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
try {
list.addAll(i, Collections.singletonList(d));
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
try {
list.addAll(i, Collections.singletonList(d));
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
}
quickCheck(list, content);
ListIterator li = list.listIterator();
for (int i = 0; i < list.size(); i++) {
assertTrue(li.hasNext());
assertTrue(content[i] == li.next());
try {
li.add(d);
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
// The AbstractList class increments the cursor on the iterator
// even if the add fails...
// This poor accounting means that th FilterList (which does the right thing)
// can't be tested as well... Create this artificail moveTo() to
// fix the AbstractList failings.
li = moveTo(list, i);
T prev = li.previous();
assertTrue(content[i] == prev);
assertTrue(content[i] == li.next());
try {
li.set(d);
failNoException(eclass);
} catch (Exception e) {
checkException(eclass, e);
}
// The ContentList class modifies the modcount for set()
// even if the set() fails...
// This poor accounting means that the FilterList (which does the right thing)
// can't be tested as well... Create this artificail moveTo() to
// fix the AbstractList failings.
li = moveTo(list, i);
}
quickCheck(list, content);
}
private ListIterator moveTo(List list, int i) {
ListIterator li = list.listIterator();
while (i-- >= 0) {
assertTrue(li.hasNext());
li.next();
}
return li;
}
protected void quickCheck(List list, T[] content) {
// Simple iteration through the list contents.
Iterator it = list.iterator();
int i = 0;
while (i < content.length) {
assertTrue(it.hasNext());
assertTrue(content[i] == it.next());
i++;
}
assertFalse(it.hasNext());
try {
T overflow = it.next();
fail("There should be no element after hasNext() fails, but we got: " + overflow);
} catch (NoSuchElementException nsee) {
// this is what should happen!
}
}
/* *********************************
* Test the quality of the input data
* ********************************* */
@Test
public void testSamples() {
for (T s : buildSampleContent()) {
if (s != null && !i_tclass.isInstance(s)) {
fail("We expect all sample data to be an instance of " + i_tclass.getName());
}
}
}
@Test
public void testIllegalClassData() {
for (Object o : buildIllegalClassContent()) {
if (o == null || i_tclass.isInstance(o)) {
fail("We expect all IllegalClass data to be something other than " + i_tclass.getName());
}
}
}
@Test
public void testIllegalArgumentData() {
for (T s : buildIllegalArgumentContent()) {
if (s != null && !i_tclass.isInstance(s)) {
fail("We expect all IllegalArgument data to be an instance of " + i_tclass.getName());
}
}
}
/* *********************************
* The actual tests to run.
* ********************************* */
@Test
public void testToString() {
// basic run
assertTrue(buildEmptyList().toString() != null);
}
@Test
public void testEmpty() {
List empty = buildEmptyList();
assertTrue(empty.size() == 0);
assertTrue(empty.isEmpty());
exercise(empty, buildArray(0));
}
@Test
public void testAdd() {
for (T s : buildSampleContent()) {
List list = buildEmptyList();
assertTrue(list.isEmpty());
assertTrue(list.add(s));
exercise(list, s);
}
List list = buildEmptyList();
T[] content = buildSampleContent();
for (T s : content) {
assertTrue(list.add(s));
}
exercise(list, content);
}
@Test
public void testAddAll() {
for (T s : buildSampleContent()) {
List list = buildEmptyList();
assertTrue(list.isEmpty());
assertTrue(list.addAll(Arrays.asList(s)));
exercise(list, s);
list.clear();
}
List list = buildEmptyList();
T[] content = buildSampleContent();
assertTrue(list.addAll(Arrays.asList(content)));
exercise(list, content);
T[] data = buildArray(0);
assertFalse(list.addAll(Arrays.asList(data)));
}
@Test
public void testAddAllInt() {
for (T s : buildSampleContent()) {
List list = buildEmptyList();
assertTrue(list.isEmpty());
assertTrue(list.addAll(0, Arrays.asList(s)));
exercise(list, s);
list.clear();
}
List list = buildEmptyList();
T[] content = buildSampleContent();
assertTrue(list.addAll(0, Arrays.asList(content)));
exercise(list, content);
T[] data = buildArray(0);
assertFalse(list.addAll(0, Arrays.asList(data)));
}
@Test
public void testIllegalAddAllInt() {
final T[] illegal = buildIllegalArgumentContent();
if (illegal.length <= 0) {
// for android.
//Assume.assumeTrue(illegal.length > 0);
return;
}
final T[] extra = buildAdditionalContent();
if (extra.length <= 0) {
// for android.
//Assume.assumeTrue(extra.length > 0);
return;
}
final T[] content = buildSampleContent();
if (content.length <= 0) {
// for android.
//Assume.assumeTrue(content.length > 0);
return;
}
T[] toadd = ArrayCopy.copyOf(extra, extra.length + illegal.length);
System.arraycopy(illegal, 0, toadd, extra.length, illegal.length);
// right, we have legal content in 'content', and then in 'illegal' we
// have some legal content, and then some illegal content.
// populate the list.
List list = buildEmptyList();
assertTrue(list.addAll(0, Arrays.asList(content)));
quickCheck(list, content);
// check that the first to-add can be added.
list.add(0, toadd[0]);
//then remove it again.
assertTrue(toadd[0] == list.remove(0));
for (int i = 0; i <= content.length; i++) {
quickCheck(list, content);
// now, add the illegal, and then inspect the list...
try {
list.addAll(i, Arrays.asList(toadd));
failNoException(IllegalArgumentException.class);
} catch (Exception e) {
checkException(IllegalArgumentException.class, e);
}
// make sure that the member that previously could be added can
// still be added.
list.add(0, toadd[0]);
//then remove it again.
assertTrue(toadd[0] == list.remove(0));
// make sure it's all OK.
exercise(list, content);
if (content.length < 2) {
// for android.
// Assume.assumeTrue(content.length >= 2);
return;
}
// now check to make sure that concurrency is not affected....
Iterator it = list.iterator();
// move it along at least once.....
assertTrue(content[0] == it.next());
// now do a failed addAll.
try {
list.addAll(i, Arrays.asList(toadd));
failNoException(IllegalArgumentException.class);
} catch (Exception e) {
checkException(IllegalArgumentException.class, e);
}
// we should be able to move the iteratoe because the modcount should
// not have been affected.....
assertTrue(content[1] == it.next());
}
}
@Test
public void testClear() {
List list = buildEmptyList();
assertTrue(list.addAll(Arrays.asList(buildSampleContent())));
assertFalse(list.isEmpty());
list.clear();
assertTrue(list.isEmpty());
}
@Test
public void testInsert() {
for (T s : buildSampleContent()) {
List list = buildEmptyList();
assertTrue(list.isEmpty());
list.add(0, s);
exercise(list, s);
}
List list = buildEmptyList();
T[] content = buildSampleContent();
for (T s : content) {
list.add(0, s);
}
exercise(list, arrayReverse(content));
list.clear();
int[] order = shuffle(content.length);
T[] mix = buildArray(order.length);
for (int i = 0; i < order.length; i++) {
mix[i] = content[order[i]];
}
for (int i = 0; i < content.length; i++) {
int pos = 0;
for (int j = 0; j < order.length; j++) {
if (order[j] < i) {
pos++;
}
if (order[j] == i) {
break;
}
}
list.add(pos, content[i]);
}
exercise(list, mix);
}
@Test
public void testNullAdd() {
if (i_nullok) {
List list = buildEmptyList();
assertTrue(list.add(null));
assertTrue(list.get(0) == null);
list.add(1, null);
assertTrue(list.get(1) == null);
assertTrue(list.addAll(Arrays.asList(buildArray(10))));
assertTrue(list.size() == 12);
} else {
try {
List list = buildEmptyList();
assertFalse(list.add(null));
failNoException(NullPointerException.class);
} catch (Exception e) {
checkException(NullPointerException.class, e);
}
try {
List list = buildEmptyList();
list.add(0, null);
failNoException(NullPointerException.class);
} catch (Exception e) {
checkException(NullPointerException.class, e);
}
try {
List list = buildEmptyList();
T[] data = buildSampleContent();
for (int i = 0; i < data.length; i+= 2) {
list.add(data[i]);
data[i] = null;
}
if (data.length == 1) {
data[0] = null;
}
list.addAll(0, Arrays.asList(data));
failNoException(NullPointerException.class);
} catch (Exception e) {
checkException(NullPointerException.class, e);
}
try {
List list = buildEmptyList();
T[] data = buildSampleContent();
for (int i = 0; i < data.length; i+= 2) {
list.add(data[i]);
data[i] = null;
}
if (data.length == 1) {
data[0] = null;
}
list.addAll(Arrays.asList(data));
failNoException(NullPointerException.class);
} catch (Exception e) {
checkException(NullPointerException.class, e);
}
}
try {
List list = buildEmptyList();
Collection data = null;
list.addAll(0, data);
failNoException(NullPointerException.class);
} catch (Exception e) {
checkException(NullPointerException.class, e);
}
try {
List list = buildEmptyList();
Collection data = null;
list.addAll(Arrays.asList(buildSampleContent()));
list.addAll(data);
failNoException(NullPointerException.class);
} catch (Exception e) {
checkException(NullPointerException.class, e);
}
}
@Test
public void testIllegalIndex() {
T[] data = buildSampleContent();
try {
List list = buildEmptyList();
list.add(-10, data[0]);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.add(1, data[0]);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.addAll(-10, Arrays.asList(data));
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.addAll(1, Arrays.asList(data));
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.set(-1, data[0]);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.set(1, data[0]);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.get(-1);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.get(1);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.remove(-10);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
try {
List list = buildEmptyList();
list.remove(1);
failNoException(IndexOutOfBoundsException.class);
} catch (Exception e) {
checkException(IndexOutOfBoundsException.class, e);
}
}
@Test
public void testRemove() {
for (T s : buildSampleContent()) {
List list = buildEmptyList();
assertTrue(list.isEmpty());
assertTrue(list.add(s));
exercise(list, s);
assertTrue(list.remove(0) == s);
exercise(list);
}
T[] samplecontent = buildSampleContent();
for (int i = 0; i < samplecontent.length; i++) {
T[] content = samplecontent;
List list = buildEmptyList();
for (T s : content) {
assertTrue(list.add(s));
}
exercise(list, content);
assertTrue(content[i] == list.remove(i));
content = arrayRemove(content, i);
exercise(list, content);
while (list.size() > i) {
assertTrue(content[i] == list.remove(i));
content = arrayRemove(content, i);
}
while (!list.isEmpty()) {
assertTrue(content[content.length -1] == list.remove(list.size() - 1));
content = arrayRemove(content, content.length - 1);
}
assertTrue(list.isEmpty());
}
List list = buildEmptyList();
for (T s : samplecontent) {
assertTrue(list.add(s));
}
exercise(list, samplecontent);
if (i_nullok) {
list = buildEmptyList();
assertTrue(list.add(null));
assertTrue(list.get(0) == null);
}
}
@Test
public void testIllegalArgumentContent() {
for (T d : buildIllegalArgumentContent()) {
List list = buildEmptyList();
T[] content = buildSampleContent();
for (T i : content) {
list.add(i);
}
illegalExercise(list, content, d, IllegalArgumentException.class);
}
}
@Test
public void testIllegalClassContent() {
for (Object d : buildIllegalClassContent()) {
List list = buildEmptyList();
T[] content = buildSampleContent();
for (T i : content) {
list.add(i);
}
illegalExercise(list, content, (T)d, ClassCastException.class);
}
}
@Test
public void testNullContent() {
if (i_nullok) {
return;
}
List list = buildEmptyList();
T[] content = buildSampleContent();
for (T i : content) {
list.add(i);
}
illegalExercise(list, content, (T)null, NullPointerException.class);
}
@Test
public void testConcurrentMod() {
List list = buildEmptyList();
T[] sample = buildSampleContent();
assertTrue("Not enough sample data " + sample.length, sample.length > 2);
list.add(sample[0]);
ListIterator it = list.listIterator();
Iterator si = list.iterator();
// It is important to add some content, and do a next()
// before testing concurrency, because some iterator methods
// check for the Iterator state before checking concurrency.
// this puts the iterator in to a valid state for remove(), set(), etc.
assertTrue(sample[0] == it.next());
assertTrue(sample[0] == si.next());
// create a concurrent issue.
// we have checked for more than 2 elements so this should be fine.
list.add(sample[1]);
list.add(sample[2]);
// hasNext() should never throw CME.
assertTrue(it.hasNext());
assertTrue(1 == it.nextIndex());
// hasNext() should never throw CME.
assertTrue(it.hasNext());
try {
it.next();
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
it = list.listIterator(3);
assertTrue(sample[2] == it.previous());
// create a concurrent issue.
list.remove(2);
// hasPrevious() should never throw CME.
assertTrue(it.hasPrevious());
assertTrue(1 == it.previousIndex());
// hasPrevious() should never throw CME.
assertTrue(it.hasPrevious());
try {
it.previous();
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
// hasPrevious() should never throw CME.
assertTrue(it.hasPrevious());
try {
it.set(sample[sample.length - 1]);
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
// hasPrevious() should never throw CME.
assertTrue(it.hasPrevious());
try {
it.add(sample[sample.length - 1]);
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
// hasPrevious() should never throw CME.
assertTrue(it.hasPrevious());
try {
it.remove();
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
// Now test the Simple Iterator concurrency
// hasNext() should never throw CME.
assertTrue(si.hasNext());
try {
si.next();
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
try {
si.remove();
failNoException(ConcurrentModificationException.class);
} catch (Exception e) {
checkException(ConcurrentModificationException.class, e);
}
}
@Test
public void testConcurrentSetMod() {
List list = buildEmptyList();
T[] sample = buildSampleContent();
assertTrue("Not enough sample data " + sample.length, sample.length > 2);
list.addAll(Arrays.asList(sample));
quickCheck(list, sample);
T tmp = list.remove(0);
T[] tmpsamp = ArrayCopy.copyOfRange(sample, 1, sample.length);
quickCheck(list, tmpsamp);
// get a handle on our iterator....
ListIterator it = list.listIterator();
// make sure a set of the underlying does not effect the iterator.
tmpsamp[0] = tmp;
list.set(0, tmp);
quickCheck(list, tmpsamp);
// next() should not throw CME because set() should not change modCount.
assertTrue(tmp == it.next());
// then, for kicks, restore the original list with
it.add(sample[1]);
quickCheck(list, sample);
}
}