package org.threadly.concurrent.collections;
import static org.junit.Assert.*;
import static org.threadly.TestConstants.*;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.threadly.concurrent.collections.ConcurrentArrayList.DataSet;
import org.threadly.util.StringUtils;
@SuppressWarnings("javadoc")
public class ConcurrentArrayListTest {
private ConcurrentArrayList<String> testList;
@Before
public void setup() {
testList = new ConcurrentArrayList<>();
}
@After
public void cleanup() {
testList = null;
}
@SuppressWarnings("unused")
@Test (expected = IllegalArgumentException.class)
public void constructorFail() {
new ConcurrentArrayList<>(null, new Object());
fail("Exception should have thrown");
}
@Test
public void toStringTest() {
testList.add("foo");
String testStr = testList.toString();
assertNotNull(testStr);
assertTrue(testStr.length() > 2);
}
@Test
public void getModificationLockTest() {
Object testLock = new Object();
ConcurrentArrayList<String> testList = new ConcurrentArrayList<>(testLock);
assertTrue(testLock == testList.getModificationLock());
}
@Test
public void setFrontPaddingTest() {
testList.setFrontPadding(1);
assertEquals(1, testList.getFrontPadding());
// make some modifications
testList.add("foo");
testList.offer("bar");
testList.remove(0);
assertEquals(1, testList.getFrontPadding());
}
@Test (expected = IllegalArgumentException.class)
public void setFrontPaddingFail() {
testList.setFrontPadding(-1);
}
@Test
public void setRearPaddingTest() {
testList.setRearPadding(1);
assertEquals(1, testList.getRearPadding());
// make some modifications
testList.add("foo");
testList.offer("bar");
testList.remove(0);
assertEquals(1, testList.getRearPadding());
}
@Test (expected = IllegalArgumentException.class)
public void setRearPaddingFail() {
testList.setRearPadding(-1);
}
@Test
public void trimToSizeTest() {
testList.setRearPadding(2);
testList.add("foo");
assertEquals(3, testList.currentData.dataArray.length);
testList.trimToSize();
assertEquals(1, testList.currentData.dataArray.length);
testList.add("bar");
// verify that padding set does not change
assertEquals(4, testList.currentData.dataArray.length);
testList.add("1");
testList.add("2");
DataSet<?> originalDS = testList.currentData;
testList.trimToSize();
// verify no-op if no trimming needed
assertTrue(originalDS == testList.currentData);
}
@Test
public void sizeTest() {
ListTests.sizeTest(testList);
}
@Test
public void isEmptyTest() {
ListTests.isEmptyTest(testList);
}
@Test
public void getTest() {
ListTests.getTest(testList);
}
@Test (expected = IndexOutOfBoundsException.class)
public void getInvalidIndexTest() {
testList.get(1);
}
@Test
public void indexOfTest() {
ListTests.indexOfTest(testList);
}
@Test
public void lastIndexOfTest() {
ListTests.lastIndexOfTest(testList);
}
@Test
public void containsTest() {
ListTests.containsTest(testList);
}
@Test
public void containsAllTest() {
ListTests.containsAllTest(testList);
}
@Test
public void toArrayTest() {
ListTests.toArrayTest(testList);
}
@Test
public void clearTest() {
ListTests.clearTest(testList);
assertNull(testList.peek());
}
@Test
public void pushTest() {
addFirstOrPushTest(false);
}
@Test
public void addFirstTest() {
addFirstOrPushTest(true);
}
public void addFirstOrPushTest(boolean addFirst) {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
if (addFirst) {
testList.addFirst(str);
} else {
testList.push(str);
}
assertEquals(str, testList.getFirst());
}
}
@Test
public void addLastTest() {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
testList.addLast(str);
assertEquals(str, testList.getLast());
}
}
@Test
public void offerFirstTest() {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
assertTrue(testList.offerFirst(str));
assertEquals(str, testList.getFirst());
}
}
@Test
public void offerLastTest() {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
assertTrue(testList.offerLast(str));
assertEquals(str, testList.getLast());
}
}
@Test (expected = NoSuchElementException.class)
public void getFirstFail() {
testList.getFirst();
}
@Test (expected = NoSuchElementException.class)
public void getLastFail() {
testList.getLast();
}
@Test
public void addNullTest() {
ListTests.addNullTest(testList);
}
@Test
public void addAllTest() {
ListTests.addAllTest(testList);
}
@Test
public void addIndexTest() {
ListTests.addIndexTest(testList);
}
@Test
public void addIndexFail() {
ListTests.addIndexFail(testList);
}
@Test
public void addAllIndexTest() {
ListTests.addAllIndexTest(testList);
}
@Test
public void addAllIndexFail() {
ListTests.addAllIndexFail(testList);
}
@Test
public void peekFirstTest() {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
testList.addFirst(str);
assertEquals(str, testList.peekFirst());
}
}
@Test
public void peekLastTest() {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
testList.addLast(str);
assertEquals(str, testList.peekLast());
}
}
@Test
public void removeAllTest() {
ListTests.removeAllTest(testList);
}
@Test
public void removeFirstOccurrenceNotFoundTest() {
assertFalse(testList.removeFirstOccurrence(null));
assertFalse(testList.removeFirstOccurrence(new Object()));
}
@Test
public void removeFirstOccurrenceTest() {
List<String> firstStr = new ArrayList<>(TEST_QTY);
List<String> secondStr = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str1 = Integer.toString(i);
firstStr.add(str1);
String str2 = Integer.toString(i);
secondStr.add(str2);
testList.add(str1);
assertTrue(testList.offer(str2));
}
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
assertTrue(testList.removeFirstOccurrence(str));
}
assertEquals(secondStr.size(), testList.size());
Iterator<String> it = secondStr.iterator();
Iterator<String> testIt = testList.iterator();
while (it.hasNext()) {
assertTrue(testIt.next() == it.next());
}
}
@Test
public void removeLastOccurrenceNotFoundTest() {
assertFalse(testList.removeLastOccurrence(null));
assertFalse(testList.removeLastOccurrence(new Object()));
}
@Test
public void removeLastOccurrenceTest() {
List<String> firstStr = new ArrayList<>(TEST_QTY);
List<String> secondStr = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str1 = Integer.toString(i);
firstStr.add(str1);
String str2 = Integer.toString(i);
secondStr.add(str2);
testList.add(str1);
assertTrue(testList.offer(str2));
}
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
assertTrue(testList.removeLastOccurrence(str));
}
assertEquals(firstStr.size(), testList.size());
Iterator<String> it = firstStr.iterator();
Iterator<String> testIt = testList.iterator();
while (it.hasNext()) {
assertTrue(testIt.next() == it.next());
}
}
@Test
public void removeTest() {
removeOrPopTest(0);
}
@Test
public void removeFirstTest() {
removeOrPopTest(1);
}
@Test
public void popTest() {
removeOrPopTest(2);
}
public void removeOrPopTest(int removeType) {
List<String> compareList = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
compareList.add(str);
testList.add(str);
}
Iterator<String> it = compareList.iterator();
int removed = 0;
while (it.hasNext()) {
String next = it.next();
switch (removeType) {
case 0:
assertTrue(testList.remove() == next);
break;
case 1:
assertTrue(testList.removeFirst() == next);
break;
case 2:
assertTrue(testList.pop() == next);
break;
default:
throw new UnsupportedOperationException("Unknown remove type: " + removeType);
}
removed++;
assertEquals(TEST_QTY - removed, testList.size());
assertFalse(testList.peek() == next);
}
}
@Test (expected = NoSuchElementException.class)
public void removeFirstFail() {
testList.removeFirst();
}
@Test
public void removeLastTest() {
LinkedList<String> compareList = new LinkedList<>();
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
compareList.add(str);
testList.add(str);
}
Iterator<String> it = compareList.descendingIterator();
int removed = 0;
while (it.hasNext()) {
String next = it.next();
assertTrue(testList.removeLast() == next);
removed++;
assertEquals(TEST_QTY - removed, testList.size());
assertFalse(testList.peekLast() == next);
}
}
@Test (expected = NoSuchElementException.class)
public void removeLastFail() {
testList.removeLast();
}
@Test
public void pollTest() {
pollTest(false);
}
@Test
public void pollFirstTest() {
pollTest(true);
}
public void pollTest(boolean pollFirst) {
List<String> compareList = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
compareList.add(str);
testList.add(str);
}
Iterator<String> it = compareList.iterator();
int removed = 0;
while (it.hasNext()) {
String next = it.next();
if (pollFirst) {
assertTrue(testList.pollFirst() == next);
} else {
assertTrue(testList.poll() == next);
}
removed++;
assertEquals(TEST_QTY - removed, testList.size());
assertFalse(testList.peek() == next);
}
}
@Test
public void pollLastTest() {
LinkedList<String> compareList = new LinkedList<>();
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
compareList.add(str);
testList.add(str);
}
Iterator<String> it = compareList.descendingIterator();
int removed = 0;
while (it.hasNext()) {
String next = it.next();
assertTrue(testList.pollLast() == next);
removed++;
assertEquals(TEST_QTY - removed, testList.size());
assertFalse(testList.peekLast() == next);
}
}
@Test
public void elementTest() {
String foo = StringUtils.makeRandomString(5);
testList.add(foo);
assertEquals(foo, testList.element());
testList.add(StringUtils.makeRandomString(5));
assertEquals(foo, testList.element());
}
@Test (expected = NoSuchElementException.class)
public void elementFail() {
testList.element();
fail("Exception should have been thrown");
}
@Test
public void removeMissingObjectTest() {
ListTests.removeMissingObjectTest(testList);
}
@Test
public void removeObjectTest() {
ListTests.removeObjectTest(testList);
}
@Test
public void removeIndexTest() {
ListTests.removeIndexTest(testList);
}
@Test
public void removeIndexFail() {
ListTests.removeIndexFail(testList);
}
@Test
public void retainAllTest() {
ListTests.retainAllTest(testList);
}
@Test
public void repositionSearchForwardTest() {
List<String> firstStr = new ArrayList<>(TEST_QTY);
List<String> secondStr = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str1 = Integer.toString(i);
firstStr.add(str1);
String str2 = Integer.toString(i);
secondStr.add(str2);
assertTrue(testList.offer(str1));
testList.add(str2);
}
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
testList.reposition(str, i, false);
}
Iterator<String> fIt = firstStr.iterator();
Iterator<String> sIt = secondStr.iterator();
Iterator<String> testIt = testList.iterator();
while (fIt.hasNext()) {
String next = testIt.next();
assertTrue(fIt.next() == next);
assertFalse(sIt.next() == next);
}
}
@Test
public void repositionSearchBackwardTest() {
List<String> firstStr = new ArrayList<>(TEST_QTY);
List<String> secondStr = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str1 = Integer.toString(i);
firstStr.add(str1);
String str2 = Integer.toString(i);
secondStr.add(str2);
assertTrue(testList.offer(str1));
testList.add(str2);
}
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
testList.reposition(str, i, true);
}
Iterator<String> fIt = firstStr.iterator();
Iterator<String> sIt = secondStr.iterator();
Iterator<String> testIt = testList.iterator();
while (sIt.hasNext()) {
String next = testIt.next();
assertTrue(sIt.next() == next);
assertFalse(fIt.next() == next);
}
}
@Test
public void repositionObjectIndexFail() {
try {
testList.reposition(Integer.toString(0), 1);
fail("Exception should have been thrown");
} catch (IndexOutOfBoundsException e) {
// expected
}
try {
testList.reposition(Integer.toString(0), -1);
fail("Exception should have been thrown");
} catch (IndexOutOfBoundsException e) {
// expected
}
}
@Test (expected = NoSuchElementException.class)
public void repositionObjectNotFoundFail() {
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
testList.add(str);
}
testList.reposition("foo", 0);
fail("Exception should have been thrown");
}
@Test
public void repositionIndexTest() {
int testQty = Math.max(10, TEST_QTY);
// should be a no-op
testList.reposition(0, 0);
for (int i = 0; i < testQty; i++) {
String str = Integer.toString(i);
testList.add(str);
}
testList.reposition(testQty - 1, 0);
assertEquals(Integer.toString(testQty - 1), testList.get(0));
assertEquals(Integer.toString(0), testList.get(1));
String expectedNext = testList.get(6);
testList.reposition(0, 5);
assertEquals(Integer.toString(testQty - 1), // one less than index position because shifted right
testList.get(4));
assertEquals(expectedNext, testList.get(6));
testList.reposition(1, 3); // swap 1 to 2
assertEquals(Integer.toString(2), testList.get(1));
assertEquals(Integer.toString(1), testList.get(2));
}
@Test
public void repositionIndexFail() {
try {
testList.reposition(-1, 0);
fail("Exception should have been thrown");
} catch (IndexOutOfBoundsException e) {
// expected
}
try {
testList.reposition(0, -1);
fail("Exception should have been thrown");
} catch (IndexOutOfBoundsException e) {
// expected
}
try {
testList.reposition(0, 1);
fail("Exception should have been thrown");
} catch (IndexOutOfBoundsException e) {
// expected
}
try {
testList.reposition(1, 0);
fail("Exception should have been thrown");
} catch (IndexOutOfBoundsException e) {
// expected
}
}
@Test
public void setFail() {
ListTests.setFail(testList);
}
/* This also tests the ListIterator forwards,
* since this just defaults to that implementation
*/
@Test
public void iteratorTest() {
ListTests.iteratorTest(testList);
}
@Test
public void listIteratorTest() {
ListTests.listIteratorTest(testList);
}
@Test
public void listIteratorFail() {
ListTests.listIteratorFail(testList);
}
@Test
public void equalsTest() {
ListTests.equalsTest(testList);
}
@Test
public void hashCodeTest() {
ListTests.hashCodeTest(testList);
}
@Test
public void testListIteratorBackwards() {
List<String> comparisionList = new ArrayList<>(TEST_QTY);
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
comparisionList.add(str);
testList.add(str);
}
ListIterator<String> clIt = comparisionList.listIterator(TEST_QTY);
ListIterator<String> testIt = testList.listIterator(TEST_QTY);
while (clIt.hasPrevious()) {
assertTrue(testIt.hasPrevious());
assertEquals(clIt.previous(), testIt.previous());
}
}
@Test
public void descendingIteratorTest() {
Deque<String> comparisionDeque = new LinkedList<>();
for (int i = 0; i < TEST_QTY; i++) {
String str = Integer.toString(i);
comparisionDeque.addLast(str);
testList.add(str);
}
Iterator<String> clIt = comparisionDeque.descendingIterator();
Iterator<String> testIt = testList.descendingIterator();
while (clIt.hasNext()) {
assertTrue(testIt.hasNext());
assertEquals(clIt.next(), testIt.next());
}
}
@Test
public void subListTest() {
ListTests.subListTest(testList);
}
@Test
public void subListFail() {
ListTests.subListFail(testList);
}
@Test
public void makeEmptyDataSetTest() {
DataSet<String> ds = ConcurrentArrayList.makeEmptyDataSet(0, 0);
assertEquals(0, ds.size);
ds = ConcurrentArrayList.makeEmptyDataSet(10, 10);
assertEquals(0, ds.size);
}
@Test (expected = IllegalArgumentException.class)
public void makeEmptyDataSetFrontFail() {
ConcurrentArrayList.makeEmptyDataSet(-1, 0);
}
@Test (expected = IllegalArgumentException.class)
public void makeEmptyDataSetRearFail() {
ConcurrentArrayList.makeEmptyDataSet(0, -1);
}
}