us.ihmc.commons.lists.RecyclingLinkedListTest Maven / Gradle / Ivy
package us.ihmc.commons.lists;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import org.apache.commons.lang3.mutable.MutableInt;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import us.ihmc.commons.MutationTestFacilitator;
public class RecyclingLinkedListTest
{
@Test
public void testOperations()
{
RecyclingLinkedList linkedList = new RecyclingLinkedList<>(MutableInt::new, MutableInt::setValue);
// Make sure the list behaves predictable and can be reused:
doOperationsAndAsserts(linkedList, true);
doOperationsAndAsserts(linkedList, false);
doOperationsAndAsserts(linkedList, true);
doOperationsAndAsserts(linkedList, false);
}
public void doOperationsAndAsserts(RecyclingLinkedList linkedList, boolean reverse)
{
assertEquals(0, linkedList.size());
assertTrue(linkedList.isEmpty());
MutableInt element = new MutableInt();
RecyclingIterator forwardIterator = linkedList.createForwardIterator();
RecyclingIterator backwardIterator = linkedList.createBackwardIterator();
assertFalse(forwardIterator.hasNext());
if (reverse)
{
// Add elements such that the result is a list from 5 to 9:
addElementsToBack(linkedList, forwardIterator, backwardIterator);
assertEquals(5, linkedList.size());
// Add elements such that the result is a list from 0 to 9:
addElementsToFront(linkedList, forwardIterator, backwardIterator);
assertEquals(10, linkedList.size());
}
else
{
// Add elements such that the result is a list from 0 to 9:
addElementsToFront(linkedList, forwardIterator, backwardIterator);
assertEquals(5, linkedList.size());
// Add elements such that the result is a list from 5 to 9:
addElementsToBack(linkedList, forwardIterator, backwardIterator);
assertEquals(10, linkedList.size());
}
assertFalse(linkedList.isEmpty());
// Check the first and last elements:
linkedList.peekFirst(element);
assertEquals(0, element.intValue());
linkedList.peekLast(element);
assertEquals(9, element.intValue());
// Make sure an iterator will see the values 0 to 9 in order:
int expected = 0;
forwardIterator.reset();
while (forwardIterator.hasNext())
{
if (expected > 9)
{
fail("Iterator should have stopped.");
}
forwardIterator.next(element);
assertEquals(expected++, element.intValue());
}
assertEquals(expected, 10);
forwardIterator.reset();
expected = 9;
backwardIterator.reset();
while (backwardIterator.hasNext())
{
if (expected < 0)
{
fail("Iterator should have stopped.");
}
backwardIterator.next(element);
assertEquals(expected--, element.intValue());
}
assertEquals(expected, -1);
backwardIterator.reset();
if (reverse)
{
// Remove some elements such that the list is from 4 to 7:
removeFromBack(linkedList, element, forwardIterator, backwardIterator);
// Remove some elements such that the list is from 4 to 9:
removeFromFront(linkedList, element, forwardIterator, backwardIterator);
}
else
{
// Remove some elements such that the list is from 4 to 9:
removeFromFront(linkedList, element, forwardIterator, backwardIterator);
// Remove some elements such that the list is from 4 to 7:
removeFromBack(linkedList, element, forwardIterator, backwardIterator);
}
// Make sure the iterator will see the values 4 to 7 in order:
forwardIterator.reset();
expected = 4;
while (forwardIterator.hasNext())
{
if (expected > 7)
{
fail("Iterator should have stopped.");
}
forwardIterator.next(element);
assertEquals(expected++, element.intValue());
}
assertEquals(expected, 8);
backwardIterator.reset();
expected = 7;
while (backwardIterator.hasNext())
{
if (expected < 4)
{
fail("Iterator should have stopped.");
}
backwardIterator.next(element);
assertEquals(expected--, element.intValue());
}
assertEquals(expected, 3);
// Make sure the iterator fails after it is at the end:
try
{
forwardIterator.next(element);
fail("Iterator should have thrown a " + NoSuchElementException.class.getSimpleName() + ".");
}
catch (NoSuchElementException e)
{
}
try
{
backwardIterator.next(element);
fail("Iterator should have thrown a " + NoSuchElementException.class.getSimpleName() + ".");
}
catch (NoSuchElementException e)
{
}
// Add a values to the end up until 20:
linkedList.peekLast(element);
int valueToAdd = element.intValue();
while (++valueToAdd <= 20)
{
element.setValue(valueToAdd);
linkedList.addLast(element);
}
// Add a values to the start down until -20:
linkedList.peekFirst(element);
valueToAdd = element.intValue();
while (--valueToAdd >= -20)
{
element.setValue(valueToAdd);
linkedList.addFirst(element);
}
// Make sure the iterator will see the values -20 to 20 in order:
forwardIterator.reset();
expected = -20;
while (forwardIterator.hasNext())
{
if (expected > 20)
{
fail("Iterator should have stopped.");
}
forwardIterator.next();
expected++;
}
assertEquals(expected, 21);
backwardIterator.reset();
expected = 20;
while (backwardIterator.hasNext())
{
if (expected < -20)
{
fail("Iterator should have stopped.");
}
backwardIterator.next();
expected--;
}
assertEquals(expected, -21);
// Remove elements until the list is empty:
if (reverse)
{
for (int i = -20; i <= 20; i++)
{
if (i % 2 == 0)
{
linkedList.removeFirst(element);
assertEquals(i, element.intValue());
}
else
{
linkedList.removeFirst();
}
}
}
else
{
for (int i = 20; i >= -20; i--)
{
if (i % 2 == 0)
{
linkedList.removeLast(element);
assertEquals(i, element.intValue());
}
else
{
linkedList.removeLast();
}
}
}
assertTrue(linkedList.isEmpty());
// Make sure there is no more elements:
try
{
linkedList.peekFirst(element);
fail("Iterator should have thrown a " + NoSuchElementException.class.getSimpleName() + ".");
}
catch (NoSuchElementException e)
{
}
try
{
linkedList.peekLast(element);
fail("Iterator should have thrown a " + NoSuchElementException.class.getSimpleName() + ".");
}
catch (NoSuchElementException e)
{
}
try
{
linkedList.removeFirst(element);
fail("Iterator should have thrown a " + NoSuchElementException.class.getSimpleName() + ".");
}
catch (NoSuchElementException e)
{
}
try
{
linkedList.removeLast(element);
fail("Iterator should have thrown a " + NoSuchElementException.class.getSimpleName() + ".");
}
catch (NoSuchElementException e)
{
}
}
private void removeFromBack(RecyclingLinkedList linkedList, MutableInt element, RecyclingIterator forwardIterator,
RecyclingIterator backwardIterator)
{
linkedList.removeLast(element);
assertEquals(9, element.intValue());
linkedList.removeLast(element);
assertEquals(8, element.intValue());
// Make sure the iterator fails after a modification:
try
{
forwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
forwardIterator.reset();
// Make sure the iterator fails after a modification:
try
{
backwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
backwardIterator.reset();
}
private void removeFromFront(RecyclingLinkedList linkedList, MutableInt element, RecyclingIterator forwardIterator,
RecyclingIterator backwardIterator)
{
linkedList.removeFirst(element);
assertEquals(0, element.intValue());
linkedList.removeFirst(element);
assertEquals(1, element.intValue());
linkedList.removeFirst(element);
assertEquals(2, element.intValue());
linkedList.removeFirst(element);
assertEquals(3, element.intValue());
// Make sure the iterator fails after a modification:
try
{
forwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
forwardIterator.reset();
// Make sure the iterator fails after a modification:
try
{
backwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
backwardIterator.reset();
}
private void addElementsToBack(RecyclingLinkedList linkedList, RecyclingIterator forwardIterator,
RecyclingIterator backwardIterator)
{
linkedList.addLast(new MutableInt(5));
linkedList.addLast(new MutableInt(6));
linkedList.addLast(new MutableInt(7));
linkedList.addLast(new MutableInt(8));
linkedList.addLast(new MutableInt(9));
// Make sure the iterator fails after a modification:
try
{
forwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
forwardIterator.reset();
// Make sure the iterator fails after a modification:
try
{
backwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
backwardIterator.reset();
}
private void addElementsToFront(RecyclingLinkedList linkedList, RecyclingIterator forwardIterator,
RecyclingIterator backwardIterator)
{
linkedList.addFirst(new MutableInt(4));
linkedList.addFirst(new MutableInt(3));
linkedList.addFirst(new MutableInt(2));
linkedList.addFirst(new MutableInt(1));
linkedList.addFirst(new MutableInt(0));
// Make sure the iterator fails after a modification:
try
{
forwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
forwardIterator.reset();
// Make sure the iterator fails after a modification:
try
{
backwardIterator.hasNext();
fail("Iterator should have thrown a " + ConcurrentModificationException.class.getSimpleName() + ".");
}
catch (ConcurrentModificationException e)
{
}
backwardIterator.reset();
}
@Test
public void testConstructors()
{
new RecyclingLinkedList<>(MutableInt::new, MutableInt::setValue);
new RecyclingLinkedList<>(MutableInt.class, MutableInt::setValue);
new RecyclingLinkedList<>(0, MutableInt::new, MutableInt::setValue);
new RecyclingLinkedList<>(0, MutableInt.class, MutableInt::setValue);
new RecyclingLinkedList<>(100, MutableInt::new, MutableInt::setValue);
new RecyclingLinkedList<>(100, MutableInt.class, MutableInt::setValue);
}
public static void main(String[] args)
{
MutationTestFacilitator.facilitateMutationTestForClass(RecyclingLinkedList.class, RecyclingLinkedListTest.class);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy