package freenet.support;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import junit.framework.TestCase;
import freenet.support.DoublyLinkedListImpl.Item;
public class DoublyLinkedListImplTest extends TestCase {
private static class T extends Item<T> {
int value;
boolean isClone;
T(int v) {
value = v;
}
@Override
public T clone() {
T c = new T(value);
c.isClone = true;
return c;
}
@Override
public String toString() {
if (isClone)
return "[" + value + "]";
else
return "(" + value + ")";
}
void assertV(int v) {
assertEquals(v, value);
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (o.getClass() != this.getClass())
return false;
T t = (T) o;
return t.value == value && t.isClone == isClone;
}
@Override
public int hashCode() {
return value;
}
}
public void testForwardPushPop() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
list.push(new T(0));
list.push(new T(1));
list.push(new T(2));
list.push(new T(3));
assertFalse("isEmpty()", list.isEmpty());
list.pop().assertV(3);
assertFalse("isEmpty()", list.isEmpty());
list.pop().assertV(2);
assertFalse("isEmpty()", list.isEmpty());
// add again
list.push(new T(4));
list.push(new T(5));
list.pop().assertV(5);
assertFalse("isEmpty()", list.isEmpty());
list.pop().assertV(4);
assertFalse("isEmpty()", list.isEmpty());
list.pop().assertV(1);
assertFalse("isEmpty()", list.isEmpty());
list.pop().assertV(0);
assertTrue("isEmpty()", list.isEmpty());
assertNull("pop()", list.pop());
}
public void testForwardShiftUnshift() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
list.unshift(new T(0));
list.unshift(new T(1));
list.unshift(new T(2));
list.unshift(new T(3));
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(3);
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(2);
assertFalse("isEmpty()", list.isEmpty());
// add again
list.unshift(new T(4));
list.unshift(new T(5));
list.shift().assertV(5);
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(4);
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(1);
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(0);
assertTrue("isEmpty()", list.isEmpty());
assertNull("shift()", list.shift());
}
public void testClearSize() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
list.unshift(new T(0));
list.unshift(new T(1));
list.unshift(new T(2));
list.unshift(new T(3));
assertEquals("size()", 4, list.size());
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(3);
assertEquals("size()", 3, list.size());
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(2);
assertEquals("size()", 2, list.size());
assertFalse("isEmpty()", list.isEmpty());
list.clear();
assertEquals("size()", 0, list.size());
assertTrue("isEmpty()", list.isEmpty());
// add again
list.unshift(new T(4));
list.unshift(new T(5));
assertEquals("size()", 2, list.size());
assertFalse("isEmpty()", list.isEmpty());
list.shift().assertV(5);
list.shift().assertV(4);
assertEquals("size()", 0, list.size());
assertTrue("isEmpty()", list.isEmpty());
}
// public void testClone() {
// DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
// for (int i = 0; i < 3; i++) {
// list.unshift(new T(i));
// }
//
// DoublyLinkedList<T> listClone = list.clone();
//
// for (int i = 2; i >= 0; i--) {
// T t = (T) list.shift();
// t.assertV(i);
// t.assertIsNotClone();
//
// T tc = (T) listClone.shift();
// tc.assertV(i);
// tc.assertIsClone();
// }
// }
public void testShiftN() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
for (int i = 0; i < 5; i++) {
list.push(new T(i));
}
DoublyLinkedList<T> list2 = list.shift(2);
assertEquals("list2.size()", 2, list2.size());
list2.shift().assertV(0);
list2.shift().assertV(1);
assertTrue("list2.isEmpty()", list2.isEmpty());
assertEquals("list.size()", 3, list.size());
list.shift().assertV(2);
list2 = list.shift(20);
assertTrue("list.isEmpty()", list.isEmpty());
list2.shift().assertV(3);
list2.shift().assertV(4);
assertTrue("list2.isEmpty()", list2.isEmpty());
list2 = list.shift(20);
assertTrue("list2.isEmpty()", list2.isEmpty());
}
public void testPopN() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
for (int i = 0; i < 5; i++) {
list.unshift(new T(i));
}
DoublyLinkedList<T> list2 = list.pop(2);
assertEquals("list2.size()", 2, list2.size());
list2.pop().assertV(0);
list2.pop().assertV(1);
assertTrue("list2.isEmpty()", list2.isEmpty());
assertEquals("list.size()", 3, list.size());
list.pop().assertV(2);
list2 = list.pop(20);
assertTrue("list.isEmpty()", list.isEmpty());
list2.pop().assertV(3);
list2.pop().assertV(4);
assertTrue("list2.isEmpty()", list2.isEmpty());
list2 = list.pop(20);
assertTrue("list2.isEmpty()", list2.isEmpty());
}
public void testHeadTail() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
assertNull("head() == null", list.head());
assertNull("tail() == null", list.tail());
T[] array = new T[5];
for (int i = 0; i < 5; i++) {
array[i] = new T(i);
list.push(array[i]);
}
assertTrue("head() == 0", array[0] == list.head());
assertTrue("tail() == 4", array[4] == list.tail());
list.shift();
assertTrue("head() == 1", array[1] == list.head());
assertTrue("tail() == 4", array[4] == list.tail());
list.pop();
assertTrue("head() == 1", array[1] == list.head());
assertTrue("tail() == 3", array[3] == list.tail());
list.clear();
assertNull("head() == null", list.head());
assertNull("tail() == null", list.tail());
}
public void testIternator() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
T[] array = new T[5];
for (int i = 0; i < 5; i++) {
array[i] = new T(i);
list.push(array[i]);
}
// manual, forward
T h = list.head();
for (int i = 0; i < 5; i++) {
assertEquals("manual iternate, forward", array[i], h);
//assertEquals("DoublyLinkedList.next() == Item.next()", h.getNext(), list.next(h));
assertEquals("hasNext()", i != 4, list.hasNext(h));
assertEquals("hasPrev()", i != 0, list.hasPrev(h));
h.assertV(i);
h = list.next(h);
}
assertEquals("h==null", null, h);
// manual, reverse
T t = list.tail();
for (int i = 4; i >= 0; i--) {
assertEquals("manual iternate, reverse", array[i], t);
//assertEquals("DoublyLinkedList.prev() == Item.getPrev()", tail.getPrev(), list.prev(tail));
assertEquals("hasNext()", i != 4, list.hasNext(t));
assertEquals("hasPrev()", i != 0, list.hasPrev(t));
t.assertV(i);
t = list.prev(t);
}
assertNull("t==null", t);
Enumeration<T> e = list.elements();
for (int i = 0; i < 5; i++) {
assertTrue("hasMoreElements()", e.hasMoreElements());
T n = e.nextElement();
n.assertV(i);
assertEquals("hasMoreElements()", i != 4, e.hasMoreElements());
}
try {
e.nextElement();
fail("NoSuchElementException");
} catch (NoSuchElementException nsee) {
}
}
public void testRandomRemovePush() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
T[] array = new T[5];
for (int i = 0; i < 5; i++) {
array[i] = new T(i);
list.push(array[i]);
}
assertTrue(list.remove(array[3]) == array[3]);
list.push(array[3]);
// Remove non-exist item -> give null
assertNull(list.remove(new T(-1)));
// Remove non-identical (but equal) item -> give null
assertNull(list.remove(new T(2)));
list.shift().assertV(0);
list.shift().assertV(1);
list.shift().assertV(2);
list.shift().assertV(4);
list.shift().assertV(3);
assertNull(list.remove(new T(-1)));
}
public void testRandomShiftPush() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
list.push(new T(0));
list.push(new T(1));
list.unshift(new T(2));
list.push(new T(3));
list.unshift(new T(4));
list.unshift(new T(5));
list.shift().assertV(5);
list.pop().assertV(3);
list.pop().assertV(1);
list.pop().assertV(0);
list.shift().assertV(4);
list.shift().assertV(2);
}
public void testRandomInsert() {
DoublyLinkedList<T> list = new DoublyLinkedListImpl<T>();
T[] array = new T[5];
for (int i = 0; i < 5; i++) {
array[i] = new T(i);
list.push(array[i]);
}
list.insertPrev(array[0], new T(100));
list.insertPrev(array[2], new T(102));
list.insertNext(array[4], new T(104));
list.insertNext(array[4], new T(105));
DoublyLinkedList<T> list2 = new DoublyLinkedListImpl<T>();
T l2 = new T(9999);
list2.push(l2);
try {
// already exist
list2.insertNext(l2, l2);
fail("PromiscuousItemException");
} catch (PromiscuousItemException pie) {
}
try {
// already exist
list2.insertNext(l2, l2);
fail("PromiscuousItemException");
} catch (PromiscuousItemException pie) {
}
try {
// bad position
list2.insertPrev(array[3], new T(8888));
fail("PromiscuousItemException");
} catch (PromiscuousItemException pie) {
}
try {
// bad position
list2.insertNext(array[3], new T(8888));
fail("PromiscuousItemException");
} catch (PromiscuousItemException pie) {
}
try {
// item in other list
list2.insertPrev(l2, array[3]);
fail("PromiscuousItemException");
} catch (PromiscuousItemException pie) {
}
try {
// item in other list
list2.insertNext(l2, array[3]);
fail("PromiscuousItemException");
} catch (PromiscuousItemException pie) {
}
T l3 = new T(9999);
list2.push(l3);
try {
// VirginItemException
l3.setPrev(null); // corrupt it
list2.insertPrev(l3, new T(8888));
fail("VirginItemException");
} catch (VirginItemException vie) {
}
try {
// VirginItemException
l2.setNext(null); // corrupt it
list2.insertNext(l2, new T(8888));
fail("VirginItemException");
} catch (VirginItemException vie) {
}
list.shift().assertV(100);
list.shift().assertV(0);
list.shift().assertV(1);
list.shift().assertV(102);
list.shift().assertV(2);
list.shift().assertV(3);
list.shift().assertV(4);
list.shift().assertV(105);
list.shift().assertV(104);
}
}