You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@geode.apache.org by GitBox <gi...@apache.org> on 2022/04/07 14:21:37 UTC

[GitHub] [geode] BalaKaza opened a new pull request, #7566: GEODE-10204: Add Test Coverage for SizeableByteArrayList

BalaKaza opened a new pull request, #7566:
URL: https://github.com/apache/geode/pull/7566

   Added additional test cases for public methods.
   
   Authored-by: Bala Kaza Venkata <bk...@vmware.com>
   
   <!-- Thank you for submitting a contribution to Apache Geode. -->
   
   <!-- In order to streamline the review of the contribution we ask you
   to ensure the following steps have been taken: 
   -->
   
   ### For all changes:
   - [x] Is there a JIRA ticket associated with this PR? Is it referenced in the commit message?
   
   - [x] Has your PR been rebased against the latest commit within the target branch (typically `develop`)?
   
   - [x] Is your initial contribution a single, squashed commit?
   
   - [x] Does `gradlew build` run cleanly?
   
   - [x] Have you written or updated unit tests to verify your changes?
   
   - [x] If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under [ASF 2.0](http://www.apache.org/legal/resolved.html#category-a)?
   
   <!-- Note:
   Please ensure that once the PR is submitted, check Concourse for build issues and
   submit an update to your PR as soon as possible. If you need help, please send an
   email to dev@geode.apache.org.
   -->
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@geode.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [geode] jdeppe-pivotal merged pull request #7566: GEODE-10204: Add Test Coverage for SizeableByteArrayList

Posted by GitBox <gi...@apache.org>.
jdeppe-pivotal merged PR #7566:
URL: https://github.com/apache/geode/pull/7566


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@geode.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [geode] DonalEvans commented on a diff in pull request #7566: GEODE-10204: Add Test Coverage for SizeableByteArrayList

Posted by GitBox <gi...@apache.org>.
DonalEvans commented on code in PR #7566:
URL: https://github.com/apache/geode/pull/7566#discussion_r847500308


##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {

Review Comment:
   This test and the four below it should be called "removeNElements_removes..."



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));

Review Comment:
   We shouldn't be asserting on the sizing of the list in tests that aren't explicitly about sizing.



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {

Review Comment:
   This should be "IfElementToRemoveExists"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {

Review Comment:
   This should be `i < INITIAL_NUMBER_OF_ELEMENTS`, otherwise the loop will never execute.



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {

Review Comment:
   We can add two additional test cases to this test seeing what happens if the index list includes an index that is past the end of the list, and also check that passing an invalid index does not result in the list being modified:
   ```
     @Test
     public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
       int size = 5;
       SizeableByteArrayList list = setupList(size);
   
       assertThatThrownBy(() -> list.removeIndexes(Collections.singletonList(-1))).isInstanceOf(
           IndexOutOfBoundsException.class);
       assertThat(list.size()).isEqualTo(size);
   
       assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
           IndexOutOfBoundsException.class);
       assertThat(list.size()).isEqualTo(size);
   
       assertThatThrownBy(() -> list.removeIndexes(Collections.singletonList(size))).isInstanceOf(
           IndexOutOfBoundsException.class);
       assertThat(list.size()).isEqualTo(size);
   
       assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(2, 3, 4, size))).isInstanceOf(
           IndexOutOfBoundsException.class);
       assertThat(list.size()).isEqualTo(size);
     }
   ```
   The last case in this test fails for two reasons. First, an `IndexOutOfBoundsException` is not thrown, but rather a `NoSuchElementException`, and secondly, if the assertion is changed to be that a `NoSuchElementException` is thrown, the size assertion fails, because the elements at indexes 2, 3 and 4 are removed before the method hits an exception. In order to fix this incorrect behaviour, we should iterate the indexes to remove in `removeIndexes()` and throw `IndexOutOfBoundsException` if any of them are invalid:
   ```
     public void removeIndexes(List<Integer> removalList) {
       for (Integer index : removalList) {
         if (index < 0 || index >= size()) {
           throw new IndexOutOfBoundsException();
         }
       }
       int removalListIndex = 0;
       int firstIndexToRemove = removalList.get(0);
   ...
   ```



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {

Review Comment:
   I think this should be "GivenIndexIsValid"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;

Review Comment:
   This should probably be called "indexToRemove"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void set_getSizeInBytesIsAccurate() {
-    // Create a list with one initial element and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
-
-    // Set the list's element to a larger element and ensure the size is correct
-    byte[] largerElement = "a larger updated element name".getBytes();
-    list.set(0, largerElement);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.remove(size)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.remove(-1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Revert the list's element to the original value and ensure size is consistent
-    list.set(0, element);
-    assertThat(list.getSizeInBytes()).isEqualTo(initialSize);
+  @Test
+  public void removeLastOccurrence_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.removeLastOccurrence(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void addElementAtIndex_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void set_setsNewElementAtGivenIndexIsValid() {

Review Comment:
   This might be better as "set_setsNewElementAtIndex_withValidIndex"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void set_getSizeInBytesIsAccurate() {
-    // Create a list with one initial element and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
-
-    // Set the list's element to a larger element and ensure the size is correct
-    byte[] largerElement = "a larger updated element name".getBytes();
-    list.set(0, largerElement);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.remove(size)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.remove(-1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Revert the list's element to the original value and ensure size is consistent
-    list.set(0, element);
-    assertThat(list.getSizeInBytes()).isEqualTo(initialSize);
+  @Test
+  public void removeLastOccurrence_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.removeLastOccurrence(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void addElementAtIndex_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void set_setsNewElementAtGivenIndexIsValid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 1;
+
+    byte[] oldElement = list.set(indexToBeSet, newElement);
+    byte[] expectedOldElement = expectedList.set(indexToBeSet, newElement);
+    assertThat(oldElement).isEqualTo(expectedOldElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Add an element by index and assert size is updated
-    byte[] element = "element name".getBytes();
-    list.add(1, element);
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  @Test
+  public void set_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {

Review Comment:
   This should be "IfIndexIsInvalid"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void set_getSizeInBytesIsAccurate() {
-    // Create a list with one initial element and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
-
-    // Set the list's element to a larger element and ensure the size is correct
-    byte[] largerElement = "a larger updated element name".getBytes();
-    list.set(0, largerElement);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.remove(size)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.remove(-1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Revert the list's element to the original value and ensure size is consistent
-    list.set(0, element);
-    assertThat(list.getSizeInBytes()).isEqualTo(initialSize);
+  @Test
+  public void removeLastOccurrence_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.removeLastOccurrence(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void addElementAtIndex_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void set_setsNewElementAtGivenIndexIsValid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 1;
+
+    byte[] oldElement = list.set(indexToBeSet, newElement);
+    byte[] expectedOldElement = expectedList.set(indexToBeSet, newElement);
+    assertThat(oldElement).isEqualTo(expectedOldElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Add an element by index and assert size is updated
-    byte[] element = "element name".getBytes();
-    list.add(1, element);
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  @Test
+  public void set_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    byte[] newElement = "new Element".getBytes();
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.set(size, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.set(-1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
   }
 
   @Test
-  public void addFirst_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void add_addsNewElementAtGivenIndexIsValid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 5;

Review Comment:
   Rather than just adding an element to the end of the list, to differentiate this method from `addLast()` and `addFirst()` it would be good to have tests that check the behaviour when adding the element part-way through the list and at the start of the list. This can be done quite simply with parameterization:
   ```
     @Test
     @Parameters({"0", "2", "5"})
     public void add_addsNewElementAtIndex_withValidIndex(int indexToAdd) {
       int size = 5;
       SizeableByteArrayList list = setupList(size);
   
       List<byte[]> expectedList =
           IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
               .collect(Collectors.toCollection(LinkedList::new));
       assertThat(list).containsExactlyElementsOf(expectedList);
   
       byte[] newElement = "new Element".getBytes();
   
       list.add(indexToAdd, newElement);
       expectedList.add(indexToAdd, newElement);
       assertThat(list).containsExactlyElementsOf(expectedList);
     }
   ```



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void set_getSizeInBytesIsAccurate() {
-    // Create a list with one initial element and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
-
-    // Set the list's element to a larger element and ensure the size is correct
-    byte[] largerElement = "a larger updated element name".getBytes();
-    list.set(0, largerElement);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {

Review Comment:
   This should be "IfIndexIsInvalid"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void set_getSizeInBytesIsAccurate() {
-    // Create a list with one initial element and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
-
-    // Set the list's element to a larger element and ensure the size is correct
-    byte[] largerElement = "a larger updated element name".getBytes();
-    list.set(0, largerElement);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.remove(size)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.remove(-1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Revert the list's element to the original value and ensure size is consistent
-    list.set(0, element);
-    assertThat(list.getSizeInBytes()).isEqualTo(initialSize);
+  @Test
+  public void removeLastOccurrence_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.removeLastOccurrence(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void addElementAtIndex_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void set_setsNewElementAtGivenIndexIsValid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 1;
+
+    byte[] oldElement = list.set(indexToBeSet, newElement);
+    byte[] expectedOldElement = expectedList.set(indexToBeSet, newElement);
+    assertThat(oldElement).isEqualTo(expectedOldElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Add an element by index and assert size is updated
-    byte[] element = "element name".getBytes();
-    list.add(1, element);
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  @Test
+  public void set_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    byte[] newElement = "new Element".getBytes();
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.set(size, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.set(-1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
   }
 
   @Test
-  public void addFirst_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void add_addsNewElementAtGivenIndexIsValid() {

Review Comment:
   This might be better as "add_addsNewElementAtIndex_withValidIndex"



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@geode.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [geode] jdeppe-pivotal commented on a diff in pull request #7566: GEODE-10204: Add Test Coverage for SizeableByteArrayList

Posted by GitBox <gi...@apache.org>.
jdeppe-pivotal commented on code in PR #7566:
URL: https://github.com/apache/geode/pull/7566#discussion_r847352559


##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,285 +15,509 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
   @Test
-  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
-    int elementsToAdd = 100;
-
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add elements and assert that the size is correct after each add
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+  public void remove_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
-      list.remove(0);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void getSizeInBytesIsAccurate_ForCopiedList() {
-    SizeableByteArrayList original = createList();
-    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+  public void remove_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
 
-    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  @Test
+  public void remove_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
   }
 
   @Test
-  public void clearSublist_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove subset of elements and assert that the size is correct
-    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
 
-    list.clearSublist(0, list.size());
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
   }
 
   @Test
-  public void removeObjects_getSizeInBytesIsAccurate() {
-    // Create a list with only duplicate elements and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] bytes = "anElement".getBytes();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      // Clone the byte array because otherwise we end up with the list containing multiple
-      // references to the same object in memory rather than references to multiple different
-      // objects
-      list.addFirst(bytes.clone());
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i > INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
     }
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Remove elements from the head
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Remove elements from the tail
-    list.remove(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
     assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
 
-    // Remove all of the remaining elements
-    list.remove(bytes, 0);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    assertThat(list).isEmpty();
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void removeObject_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 0),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(4, 0),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(2, 2),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "3".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(5, 1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, -1),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+    };
   }
 
   @Test
-  public void removeIndexes_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
-      // Remove in batches of 5
-      List<Integer> indexesToRemove = new ArrayList<>(5);
-      for (int j = 0; j < 5 && i >= 0; j++) {
-        indexesToRemove.add(0, i--);
-      }
-      list.removeIndexes(indexesToRemove);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveDoesExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void removeIndex_getSizeInBytesIsAccurate() {
-    // Create a list with an initial size and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Remove all the elements and assert that the size is correct after each remove
-    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
-      list.remove(i);
-      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-    }
-    assertThat(list.size()).isEqualTo(0);
+  @Test
+  public void remove_WithIndex_removesGivenIndexElementIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void set_getSizeInBytesIsAccurate() {
-    // Create a list with one initial element and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
-
-    // Set the list's element to a larger element and ensure the size is correct
-    byte[] largerElement = "a larger updated element name".getBytes();
-    list.set(0, largerElement);
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.remove(size)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.remove(-1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
 
-    // Revert the list's element to the original value and ensure size is consistent
-    list.set(0, element);
-    assertThat(list.getSizeInBytes()).isEqualTo(initialSize);
+  @Test
+  public void removeLastOccurrence_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.removeLastOccurrence(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
   }
 
   @Test
-  public void addElementAtIndex_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void set_setsNewElementAtGivenIndexIsValid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 1;
+
+    byte[] oldElement = list.set(indexToBeSet, newElement);
+    byte[] expectedOldElement = expectedList.set(indexToBeSet, newElement);
+    assertThat(oldElement).isEqualTo(expectedOldElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
 
-    // Add an element by index and assert size is updated
-    byte[] element = "element name".getBytes();
-    list.add(1, element);
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  @Test
+  public void set_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    byte[] newElement = "new Element".getBytes();
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.set(size, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.set(-1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
   }
 
   @Test
-  public void addFirst_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  public void add_addsNewElementAtGivenIndexIsValid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 5;
 
-    // Add an element and assert size is updated
-    byte[] element = "element name".getBytes();
-    list.addFirst(element);
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+    list.add(indexToBeSet, newElement);
+    expectedList.add(indexToBeSet, newElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void addLast_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = createList();
-    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
-
-    // Add an element and assert size is updated
-    byte[] element = "element name".getBytes();
-    list.addLast(element);
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  public void add_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    byte[] newElement = "new Element".getBytes();
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.add(size + 1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.add(-1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
   }
 
   @Test
-  public void insertElementBeforeReferenceElement_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] referenceElement = "element".getBytes();
-    list.addFirst(referenceElement);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
+  public void addFirst_addsNewElementAtFirstIndex() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
 
-    // Insert an element by reference and assert size is updated
-    byte[] beforeElement = "before".getBytes();
-    list.insert(beforeElement, referenceElement, true);
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
 
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+    byte[] newElement = "new Element".getBytes();
+
+    list.addFirst(newElement);
+    expectedList.addFirst(newElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void insertElementAfterReferenceElement_getSizeInBytesIsAccurate() {
-    // Create a new list and confirm that it correctly reports its size
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] referenceElement = "element".getBytes();
-    list.addFirst(referenceElement);
-    long initialSize = list.getSizeInBytes();
-    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
+  public void addLast_addsNewElementAtLastIndex() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
 
-    // Insert an element by reference and assert size is updated
-    byte[] beforeElement = "after".getBytes();
-    list.insert(beforeElement, referenceElement, false);
+    byte[] newElement = "new Element".getBytes();
 
-    long sizeAfterAddingElement = list.getSizeInBytes();
-    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+    list.addLast(newElement);
+    expectedList.addLast(newElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
   }
 
   @Test
-  public void insertElementBeforeReferenceElement_placesElementCorrectly() {
-    // Create a new list with a single element
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] referenceElement = "element".getBytes();
-    list.addFirst(referenceElement);
-
-    // Insert new element before reference element
-    byte[] beforeElement = "before".getBytes();
-    list.insert(beforeElement, referenceElement, true);
+  @Parameters(method = "getValidArgumentsForInsert")
+  @TestCaseName("{method}: elementToInsert:{0}, referenceElement:{1}, before{2}, expectedList{3}, expectedIndex{4}")
+  public void insert_insertsGivenElementForValidInputs(byte[] elementToInsert,
+      byte[] referenceElement,
+      boolean before,
+      byte[][] expectedList,
+      int expectedIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    int insertedIndex = list.insert(elementToInsert, referenceElement, before);
+    assertThat(insertedIndex).isEqualTo(expectedIndex);
+    assertThat(list).containsExactly(expectedList);
+  }
 
-    // Assert list contains exactly the elements in the expected order
-    assertThat(list).containsExactly(beforeElement, referenceElement);
+  @SuppressWarnings("unused")
+  private Object[] getValidArgumentsForInsert() {
+    // Values are elementToInsert,referenceElement,before, expectedList, expectedIndex
+    // For initial list of size 5
+    byte[] newElement = "newElement".getBytes();
+    return new Object[] {
+        new Object[] {newElement, "2".getBytes(), true,
+            new byte[][] {"0".getBytes(), "1".getBytes(), newElement, "2".getBytes(),
+                "3".getBytes(),
+                "4".getBytes()},
+            2},
+        new Object[] {newElement, "3".getBytes(), false,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                newElement,
+                "4".getBytes()},
+            4},
+        new Object[] {newElement, "0".getBytes(), true,
+            new byte[][] {newElement, "0".getBytes(), "1".getBytes(), "2".getBytes(),
+                "3".getBytes(),
+                "4".getBytes()},
+            0},
+        new Object[] {newElement, "4".getBytes(), true,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                newElement,
+                "4".getBytes()},
+            4},
+        new Object[] {newElement, "0".getBytes(), false,
+            new byte[][] {"0".getBytes(), newElement, "1".getBytes(), "2".getBytes(),
+                "3".getBytes(),
+                "4".getBytes()},
+            1},
+        new Object[] {newElement, "4".getBytes(), false,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes(), newElement},
+            5},
+        new Object[] {newElement, "5".getBytes(), true,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()},
+            -1},
+        new Object[] {newElement, "-1".getBytes(), true,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()},
+            -1}
+    };
   }
 
   @Test
-  public void insertElementAfterReferenceElement_placesElementCorrectly() {
-    // Create a new list with a single element
+  public void getSizeInBytes_isAccurateForEmptySizeableByteArrayList() {
     SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] referenceElement = "element".getBytes();
-    list.addFirst(referenceElement);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
 
-    // Insert new element after reference element
-    byte[] afterElement = "after".getBytes();
-    list.insert(afterElement, referenceElement, false);
+  @Test
+  public void getSizeInBytes_isAccurateForSizeableByteArrayListElements() {
+    int elementsToAdd = 100;
+
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add elements and assert that the size is correct after each add
+    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.addFirst(makeByteArrayOfSpecifiedLength(i));
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
 
-    // Assert list contains exactly the elements in the expected order
-    assertThat(list).containsExactly(referenceElement, afterElement);
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.remove(0);
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
   }
 
   @Test
-  public void insertElementAfterNonexistentReferenceElement_doesNotPlaceElement() {
-    // Create a new list with a single element
-    SizeableByteArrayList list = new SizeableByteArrayList();
-    byte[] nonExistentElement = "non-existent-element".getBytes();
+  public void equals_returnsTrueIfBothListsAreEqual() {
+    int size = 5;
+    SizeableByteArrayList list1 = setupList(size);
+    SizeableByteArrayList list2 = setupList(size);
+
+    assertThat(list1.equals(list2)).isTrue();
+    byte[] someElement = "dummy".getBytes();
+    list2.addLast(someElement);
+    assertThat(list1.equals(list2)).isFalse();
 
-    // Attempt to insert an element after a non-existent reference element
-    byte[] afterElement = "after".getBytes();
-    list.insert(afterElement, nonExistentElement, false);
+  }
 
-    // Assert that no elements were added to the list
-    assertThat(list).isEmpty();
+  private SizeableByteArrayList setupList(int size) {
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    for (int i = 0; i < size; i++) {
+      list.addLast(String.valueOf(i).getBytes());
+    }
+    return list;
   }
 
-  private SizeableByteArrayList createList() {
+  private SizeableByteArrayList setupListWithDuplicateValues(String repeatedElement) {
     SizeableByteArrayList list = new SizeableByteArrayList();
-    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
-      list.addFirst(makeByteArrayOfSpecifiedLength(i + 1));
+    byte[] bytes = repeatedElement.getBytes();
+    for (int i = 0; i < 6; i++) {
+      list.addLast(bytes);
+      list.addLast(String.valueOf(i).getBytes());
     }
+    list.addLast(bytes);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedListContents);

Review Comment:
   I don't think you need this. Any errors in the setup of this data will be highlighted in the actual test assertions.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@geode.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [geode] DonalEvans commented on a diff in pull request #7566: GEODE-10204: Add Test Coverage for SizeableByteArrayList

Posted by GitBox <gi...@apache.org>.
DonalEvans commented on code in PR #7566:
URL: https://github.com/apache/geode/pull/7566#discussion_r847745692


##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -487,6 +498,267 @@ public void equals_returnsTrueIfBothListsAreEqual() {
 
   }
 
+  @Test
+  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
+    int elementsToAdd = 100;
+
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add elements and assert that the size is correct after each add
+    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.addFirst(makeByteArrayOfSpecifiedLength(i));
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.remove(0);
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void getSizeInBytesIsAccurate_ForCopiedList() {
+    SizeableByteArrayList original = createList();
+    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+
+    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  }
+
+  @Test
+  public void clearSublist_getSizeInBytesIsAccurate() {
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove subset of elements and assert that the size is correct
+    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    list.clearSublist(0, list.size());
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void removeObjects_getSizeInBytesIsAccurate() {

Review Comment:
   This test should be named "removeNElements_getSizeInBytesIsAccurate"



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -487,6 +498,267 @@ public void equals_returnsTrueIfBothListsAreEqual() {
 
   }
 
+  @Test
+  public void getSizeInBytesIsAccurate_ForEmptySizeableByteArrayList() {
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void getSizeInBytesIsAccurate_ForSizeableByteArrayListElements() {
+    int elementsToAdd = 100;
+
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add elements and assert that the size is correct after each add
+    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.addFirst(makeByteArrayOfSpecifiedLength(i));
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.remove(0);
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void getSizeInBytesIsAccurate_ForCopiedList() {
+    SizeableByteArrayList original = createList();
+    SizeableByteArrayList copy = new SizeableByteArrayList(original);
+
+    assertThat(original.getSizeInBytes()).isEqualTo(copy.getSizeInBytes());
+  }
+
+  @Test
+  public void clearSublist_getSizeInBytesIsAccurate() {
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove subset of elements and assert that the size is correct
+    list.clearSublist(INITIAL_NUMBER_OF_ELEMENTS / 5, INITIAL_NUMBER_OF_ELEMENTS / 2);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    list.clearSublist(0, list.size());
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void removeObjects_getSizeInBytesIsAccurate() {
+    // Create a list with only duplicate elements and confirm that it correctly reports its size
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    byte[] bytes = "anElement".getBytes();
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
+      // Clone the byte array because otherwise we end up with the list containing multiple
+      // references to the same object in memory rather than references to multiple different
+      // objects
+      list.addFirst(bytes.clone());
+    }
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove elements from the head
+    list.removeNElements(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove elements from the tail
+    list.removeNElements(bytes, INITIAL_NUMBER_OF_ELEMENTS / 4);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove all of the remaining elements
+    list.removeNElements(bytes, 0);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    assertThat(list).isEmpty();
+  }
+
+  @Test
+  public void removeObject_getSizeInBytesIsAccurate() {
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; ++i) {
+      list.remove(makeByteArrayOfSpecifiedLength(i + 1));
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void removeIndexes_getSizeInBytesIsAccurate() {
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i;) {
+      // Remove in batches of 5
+      List<Integer> indexesToRemove = new ArrayList<>(5);
+      for (int j = 0; j < 5 && i >= 0; j++) {
+        indexesToRemove.add(0, i--);
+      }
+      list.removeIndexes(indexesToRemove);
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void removeIndex_getSizeInBytesIsAccurate() {
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = INITIAL_NUMBER_OF_ELEMENTS - 1; 0 <= i; --i) {
+      list.remove(i);
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void set_getSizeInBytesIsAccurate() {
+    // Create a list with one initial element and confirm that it correctly reports its size
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    byte[] element = "element name".getBytes();
+    list.addFirst(element);
+    long initialSize = list.getSizeInBytes();
+    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
+
+    // Set the list's element to a larger element and ensure the size is correct
+    byte[] largerElement = "a larger updated element name".getBytes();
+    list.set(0, largerElement);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Revert the list's element to the original value and ensure size is consistent
+    list.set(0, element);
+    assertThat(list.getSizeInBytes()).isEqualTo(initialSize);
+  }
+
+  @Test
+  public void addElementAtIndex_getSizeInBytesIsAccurate() {
+    // Create a new list and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add an element by index and assert size is updated
+    byte[] element = "element name".getBytes();
+    list.add(1, element);
+    long sizeAfterAddingElement = list.getSizeInBytes();
+    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void addFirst_getSizeInBytesIsAccurate() {
+    // Create a new list and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add an element and assert size is updated
+    byte[] element = "element name".getBytes();
+    list.addFirst(element);
+    long sizeAfterAddingElement = list.getSizeInBytes();
+    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void addLast_getSizeInBytesIsAccurate() {
+    // Create a new list and confirm that it correctly reports its size
+    SizeableByteArrayList list = createList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add an element and assert size is updated
+    byte[] element = "element name".getBytes();
+    list.addLast(element);
+    long sizeAfterAddingElement = list.getSizeInBytes();
+    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void insertElementBeforeReferenceElement_getSizeInBytesIsAccurate() {
+    // Create a new list and confirm that it correctly reports its size
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    byte[] referenceElement = "element".getBytes();
+    list.addFirst(referenceElement);
+    long initialSize = list.getSizeInBytes();
+    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
+
+    // Insert an element by reference and assert size is updated
+    byte[] beforeElement = "before".getBytes();
+    list.insert(beforeElement, referenceElement, true);
+
+    long sizeAfterAddingElement = list.getSizeInBytes();
+    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void insertElementAfterReferenceElement_getSizeInBytesIsAccurate() {
+    // Create a new list and confirm that it correctly reports its size
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    byte[] referenceElement = "element".getBytes();
+    list.addFirst(referenceElement);
+    long initialSize = list.getSizeInBytes();
+    assertThat(initialSize).isEqualTo(sizer.sizeof(list));
+
+    // Insert an element by reference and assert size is updated
+    byte[] beforeElement = "after".getBytes();
+    list.insert(beforeElement, referenceElement, false);
+
+    long sizeAfterAddingElement = list.getSizeInBytes();
+    assertThat(sizeAfterAddingElement).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void insertElementBeforeReferenceElement_placesElementCorrectly() {

Review Comment:
   This test and the two below it are duplicated by `insert_insertsGivenElementForValidInputs()` so they can be removed.



##########
geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableByteArrayListTest.java:
##########
@@ -15,19 +15,489 @@
 package org.apache.geode.redis.internal.data.collections;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
+@RunWith(GeodeParamsRunner.class)
 public class SizeableByteArrayListTest {
   private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
   private final int INITIAL_NUMBER_OF_ELEMENTS = 20;
 
+  @Test
+  public void removeNElements_removesElementsFromHeadWhenCountIsPositive() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {"0", "1", repeatedElement, "2", repeatedElement, "3", repeatedElement, "4",
+            repeatedElement, "5", repeatedElement};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
+
+  @Test
+  public void removeNElements_removesElementsFromTailWhenCountIsNegative() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents =
+        {repeatedElement, "0", repeatedElement, "1", repeatedElement, "2", repeatedElement, "3",
+            repeatedElement, "4",
+            "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -2);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
+
+  @Test
+  public void removeNElements_removesAllElementsWhenCountIsZero() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 0);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
+
+  @Test
+  public void removeNElements_removesAllElementsWhenCountIsGreaterThanSize() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), 100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
+
+  @Test
+  public void removeNElements_removesAllElementsWhenCountIsGreaterThanSizeWithNegativeCount() {
+    String repeatedElement = "anElement";
+    SizeableByteArrayList list = setupListWithDuplicateValues(repeatedElement);
+
+    String[] expectedContents = {"0", "1", "2", "3", "4", "5"};
+    List<byte[]> expectedListContents =
+        Arrays.stream(expectedContents).map(String::getBytes).collect(
+            Collectors.toList());
+    Integer[] expectedIndexes = {0, 2, 4, 6, 8, 10, 12};
+    List<Integer> removedIndexes = list.removeNElements(repeatedElement.getBytes(), -100);
+    assertThat(list).containsExactlyElementsOf(expectedListContents);
+    assertThat(removedIndexes).containsExactly(expectedIndexes);
+  }
+
+  @Test
+  @Parameters(method = "getValidRanges")
+  @TestCaseName("{method}: fromIndex:{0}, toIndex:{1}")
+  public void clearSublist_clearsElementsFromValidSubList(int fromIndex, int toIndex) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toList());
+    assertThat(list).containsExactlyElementsOf(expectedList);
+    list.clearSublist(fromIndex, toIndex);
+    expectedList.subList(fromIndex, toIndex).clear();
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @SuppressWarnings("unused")
+  private Object[] getValidRanges() {
+    // Values are fromIndex, toIndex
+    // For initial list of size 5
+    return new Object[] {
+        "0, 0",
+        "0, 3",
+        "0, 5",
+        "5, 5",
+        "2, 5",
+        "1, 4"
+    };
+  }
+
+  @Test
+  public void clearSublist_throwsExceptionWithInvalidArguments() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.clearSublist(-1, 3)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(0, size + 1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.clearSublist(3, 2)).isInstanceOf(
+        IllegalArgumentException.class);
+  }
+
+  @Test
+  public void indexOf_returnsIndexOfElementWhenElementExist() {
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS; i++) {
+      assertThat(list.indexOf(list.get(i))).isEqualTo(i);
+    }
+  }
+
+  @Test
+  public void indexOf_returnsNegativeOneWhenElementDoesNotExist() {
+    SizeableByteArrayList list = setupList(2);
+    Object nonExisting = "nonExisting".getBytes();
+    assertThat(list.indexOf(nonExisting)).isEqualTo(-1);
+  }
+
+  @Test
+  public void lastIndexOf_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.lastIndexOf(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
+  }
+
+  @Test
+  @Parameters(method = "getValidIndexList")
+  @TestCaseName("{method}: removalList:{0}, expected:{1}")
+  public void removeIndexes_removesGivenIndexesForValidIndexList(List<Integer> removalList,
+      byte[][] expected) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    list.removeIndexes(removalList);
+    assertThat(list).containsExactly(expected);
+  }
+
+  @SuppressWarnings("unused")
+  private Object[] getValidIndexList() {
+    // Values are removalList, expected
+    // For initial list of size 5
+    return new Object[] {
+        new Object[] {Arrays.asList(0, 4),
+            new byte[][] {"1".getBytes(), "2".getBytes(), "3".getBytes()}},
+        new Object[] {Arrays.asList(1, 2, 3, 4), new byte[][] {"0".getBytes()}},
+        new Object[] {Arrays.asList(2, 3),
+            new byte[][] {"0".getBytes(), "1".getBytes(), "4".getBytes()}}
+    };
+  }
+
+  @Test
+  public void removeIndexes_throwsIndexOutOfBoundsExceptionForInvalidIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThat(list.size()).isEqualTo(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(1, size))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThat(list.size()).isEqualTo(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(-1, 2, 3, 4))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThat(list.size()).isEqualTo(size);
+    assertThatThrownBy(() -> list.removeIndexes(Collections.singletonList(size))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThat(list.size()).isEqualTo(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(2, 3, 4, size))).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThat(list.size()).isEqualTo(size);
+
+  }
+
+  @Test
+  public void removeIndexes_throwsIllegalArgumentExceptionForUnsortedIndexList() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(0, 0))).isInstanceOf(
+        IllegalArgumentException.class);
+    assertThatThrownBy(() -> list.removeIndexes(Arrays.asList(1, 3, 2, 4))).isInstanceOf(
+        IllegalArgumentException.class);
+  }
+
+  @Test
+  public void remove_WithElement_removesGivenElementIfElementToRemoveExists() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = list.get(2);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    byte[] elementToRemoveInExpectedList = expectedList.get(2);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemoveInExpectedList);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  public void remove_WithElement_doesNotRemoveElementIfElementToRemoveDoesNotExist() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    byte[] elementToRemove = "non-existing".getBytes();
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    boolean isRemoved = list.remove(elementToRemove);
+    boolean expectedIsRemoved = expectedList.remove(elementToRemove);
+    assertThat(isRemoved).isEqualTo(expectedIsRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  public void remove_WithIndex_removesIndexWhenGivenIndexToRemoveIsValid() {
+    int size = 5;
+    int elementToRemove = 1;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] elementRemoved = list.remove(elementToRemove);
+    byte[] expectedElementRemoved = expectedList.remove(elementToRemove);
+    assertThat(elementRemoved).isEqualTo(expectedElementRemoved);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  public void remove_WithIndex_throwsIndexOutOfBoundsExceptionIfIndexIsInvalid() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.remove(size)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.remove(-1)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
+
+  @Test
+  public void removeLastOccurrence_throwsUnsupportedException() {
+    SizeableByteArrayList list = setupList(2);
+    assertThatThrownBy(() -> list.removeLastOccurrence(list.get(0))).isInstanceOf(
+        UnsupportedOperationException.class);
+  }
+
+  @Test
+  public void set_setsNewElementAtIndex_withValidIndex() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+    int indexToBeSet = 1;
+
+    byte[] oldElement = list.set(indexToBeSet, newElement);
+    byte[] expectedOldElement = expectedList.set(indexToBeSet, newElement);
+    assertThat(oldElement).isEqualTo(expectedOldElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  public void set_throwsIndexOutOfBoundsExceptionIfIndexIsInvalid() {
+    int size = 5;
+    byte[] newElement = "new Element".getBytes();
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.set(size, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.set(-1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
+
+  @Test
+  @Parameters({"0", "2", "5"})
+  public void add_addsNewElementAtIndex_withValidIndex(int indexToAdd) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    List<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+
+    list.add(indexToAdd, newElement);
+    expectedList.add(indexToAdd, newElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  public void add_throwsIndexOutOfBoundsExceptionIfIndexElementIsInvalid() {
+    int size = 5;
+    byte[] newElement = "new Element".getBytes();
+    SizeableByteArrayList list = setupList(size);
+    assertThatThrownBy(() -> list.add(size + 1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+    assertThatThrownBy(() -> list.add(-1, newElement)).isInstanceOf(
+        IndexOutOfBoundsException.class);
+  }
+
+  @Test
+  public void addFirst_addsNewElementAtFirstIndex() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+
+    list.addFirst(newElement);
+    expectedList.addFirst(newElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  public void addLast_addsNewElementAtLastIndex() {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+
+    LinkedList<byte[]> expectedList =
+        IntStream.range(0, size).mapToObj(i -> String.valueOf(i).getBytes())
+            .collect(Collectors.toCollection(LinkedList::new));
+    assertThat(list).containsExactlyElementsOf(expectedList);
+
+    byte[] newElement = "new Element".getBytes();
+
+    list.addLast(newElement);
+    expectedList.addLast(newElement);
+    assertThat(list).containsExactlyElementsOf(expectedList);
+  }
+
+  @Test
+  @Parameters(method = "getValidArgumentsForInsert")
+  @TestCaseName("{method}: referenceElement:{1}, before:{2}")
+  public void insert_insertsGivenElementForValidInputs(byte[] elementToInsert,
+      String referenceElement,
+      boolean before,
+      int expectedIndex,
+      byte[][] expectedList) {
+    int size = 5;
+    SizeableByteArrayList list = setupList(size);
+    int insertedIndex = list.insert(elementToInsert, referenceElement.getBytes(), before);
+    assertThat(insertedIndex).isEqualTo(expectedIndex);
+    assertThat(list).containsExactly(expectedList);
+  }
+
+  @SuppressWarnings("unused")
+  private Object[] getValidArgumentsForInsert() {
+    // Values are elementToInsert, referenceElement, before, expectedIndex, expectedList
+    // For initial list of size 5
+    byte[] newElement = "newElement".getBytes();
+    return new Object[] {
+        // Before first element
+        new Object[] {newElement, "0", true, 0,
+            new byte[][] {newElement, "0".getBytes(), "1".getBytes(), "2".getBytes(),
+                "3".getBytes(), "4".getBytes()}},
+        // After first element
+        new Object[] {newElement, "0", false, 1,
+            new byte[][] {"0".getBytes(), newElement, "1".getBytes(), "2".getBytes(),
+                "3".getBytes(), "4".getBytes()}},
+        // Before last element
+        new Object[] {newElement, "4", true, 4,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                newElement, "4".getBytes()}},
+        // After last element
+        new Object[] {newElement, "4", false, 5,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes(), newElement}},
+        // Before middle element
+        new Object[] {newElement, "2", true, 2,
+            new byte[][] {"0".getBytes(), "1".getBytes(), newElement, "2".getBytes(),
+                "3".getBytes(), "4".getBytes()}},
+        // After middle element
+        new Object[] {newElement, "2", false, 3,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), newElement,
+                "3".getBytes(), "4".getBytes()}},
+        // Before nonexistent element
+        new Object[] {newElement, "non-existent", true, -1,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}},
+        // After nonexistent element
+        new Object[] {newElement, "non-existent", false, -1,
+            new byte[][] {"0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
+                "4".getBytes()}}
+    };
+  }
+
+  @Test
+  public void getSizeInBytes_isAccurateForEmptySizeableByteArrayList() {
+    SizeableByteArrayList list = new SizeableByteArrayList();
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+  }
+
+  @Test
+  public void getSizeInBytes_isAccurateForSizeableByteArrayListElements() {
+    int elementsToAdd = 100;
+
+    // Create a list with an initial size and confirm that it correctly reports its size
+    SizeableByteArrayList list = setupList(INITIAL_NUMBER_OF_ELEMENTS);
+    assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+
+    // Add elements and assert that the size is correct after each add
+    for (int i = INITIAL_NUMBER_OF_ELEMENTS; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.addFirst(makeByteArrayOfSpecifiedLength(i));
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd);
+
+    // Remove all the elements and assert that the size is correct after each remove
+    for (int i = 0; i < INITIAL_NUMBER_OF_ELEMENTS + elementsToAdd; ++i) {
+      list.remove(0);
+      assertThat(list.getSizeInBytes()).isEqualTo(sizer.sizeof(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+
+  @Test
+  public void equals_returnsTrueIfBothListsAreEqual() {

Review Comment:
   This test is also testing that `equals()` returns false when the lists are not equal, so it might be better named "equals_returnsCorrectly" or something. Also, it would be good to add a test for when the lists are the same length but don't contain the same elements, since that's not covered currently. Adding the following would be enough, I think:
   ```
       byte[] anotherElement = "anotherDummy".getBytes();
       list1.addLast(anotherElement);
       assertThat(list1.equals(list2)).isFalse();
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@geode.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org