Repository: amzn/ion-java (java)

Issue:
IonSequenceLite.subList does not throw when passed start or end values that are out of range
According to the [List javadoc](https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#subList(int,%20int)), the subList method should throw:

```
    IndexOutOfBoundsException - if an endpoint index value is out of range (fromIndex < 0 || toIndex > size)
    IllegalArgumentException - if the endpoint indices are out of order (fromIndex > toIndex)
```

However, instead what happens is that we are returned a `List<IonValue>` instance with an invalid size.  This is demonstrated with the following:

```
public class ScratchPad {
    static final IonSystem SYSTEM = IonSystemBuilder.standard().build();

    @Test
    public void sizeMe() {
        List<IonValue> list = SYSTEM.newList(new int[] { 1, 2, 3}).subList(0, 3000);
        System.out.println(list.size()); // 3000 - what?!?!
    }
}
```

Pull request description:
Throw exception when IonSequenceLite.subList(int, int) arguments invalid
Throw exceptions according to the [List<T>.subList(int, in)](https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#subList(int,%20int)) javadoc.

Fixes #295

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.


Patch:
diff --git a/src/com/amazon/ion/impl/lite/IonSequenceLite.java b/src/com/amazon/ion/impl/lite/IonSequenceLite.java
index f8e2fdf4..d7e2eeeb 100644
--- a/src/com/amazon/ion/impl/lite/IonSequenceLite.java
+++ b/src/com/amazon/ion/impl/lite/IonSequenceLite.java
@@ -338,8 +338,25 @@ abstract class IonSequenceLite
         return indexOf(o);
     }
 
+    private static void checkSublistParameters(int size, int fromIndex, int toIndex)
+    {
+        if(fromIndex < 0)
+        {
+            throw new IndexOutOfBoundsException("fromIndex is less than zero");
+        }
+        if(toIndex < fromIndex)
+        {
+            throw new IllegalArgumentException("toIndex may not be less than fromIndex");
+        }
+        if(toIndex > size)
+        {
+            throw new IndexOutOfBoundsException("toIndex exceeds size");
+        }
+    }
+
     public List<IonValue> subList(int fromIndex, int toIndex)
     {
+        checkSublistParameters(this.size(), fromIndex, toIndex);
         return new SubListView(fromIndex, toIndex);
     }
 
@@ -688,6 +705,7 @@ abstract class IonSequenceLite
         }
 
         public List<IonValue> subList(final int fromIndex, final int toIndex) {
+            checkSublistParameters(this.size(), fromIndex, toIndex);
             checkForParentModification();
             return new SubListView(toParentIndex(fromIndex), toParentIndex(toIndex));
         }


Test patch:
diff --git a/test/com/amazon/ion/impl/lite/BaseIonSequenceLiteSublistTestCase.java b/test/com/amazon/ion/impl/lite/BaseIonSequenceLiteSublistTestCase.java
index 2bc94f7c..13562eef 100644
--- a/test/com/amazon/ion/impl/lite/BaseIonSequenceLiteSublistTestCase.java
+++ b/test/com/amazon/ion/impl/lite/BaseIonSequenceLiteSublistTestCase.java
@@ -44,6 +44,11 @@ public abstract class BaseIonSequenceLiteSublistTestCase {
 
     protected abstract IonSequence newSequence();
 
+    List<IonValue> newSubList() {
+        List<IonValue> seq = newSequence();
+        return seq.subList(0, seq.size());
+    }
+
     @Test
     public void sublistSize() {
         final IonSequence sequence = newSequence();
@@ -52,6 +57,7 @@ public abstract class BaseIonSequenceLiteSublistTestCase {
         assertEquals(3, actual.size());
     }
 
+
     @Test
     public void sublistIsEmpty() {
         IonSequence sequence = newSequence();
@@ -60,6 +66,40 @@ public abstract class BaseIonSequenceLiteSublistTestCase {
         assertFalse(sequence.subList(0, 1).isEmpty());
     }
 
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void subListFromIndexLessThanZero() {
+        newSequence().subList(-1, 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void subListToIndexLessThanFromIndex() {
+        newSequence().subList(2, 1);
+    }
+
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void subListToIndexExceedsSize() {
+        IonSequence seq = newSequence();
+        // toIndex is exclusive, hence the + 1
+        seq.subList(0, seq.size() + 1);
+    }
+
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void subListOfSubListFromIndexLessThanZero() {
+        newSubList().subList(-1, 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void subListOfSubListToIndexLessThanFromIndex() {
+        newSubList().subList(2, 1);
+    }
+
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void subListOfSubListToIndexExceedsSize() {
+        List<IonValue> seq = newSubList();
+        // toIndex is exclusive, hence the + 1
+        seq.subList(0, seq.size() + 1);
+    }
+
     @Test
     public void sublistGet() {
         final IonSequence sequence = newSequence();