8135248: Add utility methods to check indexes and ranges
Reviewed-by: forax, chegar, scolebourne, jrose, darcy
--- a/jdk/src/java.base/share/classes/java/lang/ArrayIndexOutOfBoundsException.java Tue Oct 06 18:39:26 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/ArrayIndexOutOfBoundsException.java Wed Oct 07 15:22:43 2015 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,42 +26,58 @@
package java.lang;
/**
- * Thrown to indicate that an array has been accessed with an
- * illegal index. The index is either negative or greater than or
- * equal to the size of the array.
+ * Thrown to indicate that an array has been accessed with an illegal index. The
+ * index is either negative or greater than or equal to the size of the array.
*
- * @author unascribed
- * @since 1.0
+ * @since 1.0
*/
-public
-class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
+public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
private static final long serialVersionUID = -5116101128118950844L;
/**
- * Constructs an <code>ArrayIndexOutOfBoundsException</code> with no
- * detail message.
+ * Constructs an {@code ArrayIndexOutOfBoundsException} with no detail
+ * message.
*/
public ArrayIndexOutOfBoundsException() {
super();
}
/**
- * Constructs a new <code>ArrayIndexOutOfBoundsException</code>
- * class with an argument indicating the illegal index.
+ * Constructs an {@code ArrayIndexOutOfBoundsException} class with the
+ * specified detail message.
*
- * @param index the illegal index.
+ * @param s the detail message.
+ */
+ public ArrayIndexOutOfBoundsException(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a new {@code ArrayIndexOutOfBoundsException} class with an
+ * argument indicating the illegal index.
+ *
+ * <p>The index is included in this exception's detail message. The
+ * exact presentation format of the detail message is unspecified.
+ *
+ * @param index the illegal index.
*/
public ArrayIndexOutOfBoundsException(int index) {
super("Array index out of range: " + index);
}
/**
- * Constructs an <code>ArrayIndexOutOfBoundsException</code> class
- * with the specified detail message.
+ * Constructs a new {@code ArrayIndexOutOfBoundsException} class with
+ * arguments indicating two out of bound values.
+ *
+ * <p>The out of bound values are included in this exception's detail
+ * message. The exact presentation format of the detail message is
+ * unspecified.
*
- * @param s the detail message.
+ * @param a the first out of bound value.
+ * @param b the second out of bound value.
+ * @since 9
*/
- public ArrayIndexOutOfBoundsException(String s) {
- super(s);
+ public ArrayIndexOutOfBoundsException(int a, int b) {
+ super("Array indexed access out of bounds: " + a + ", " + b);
}
}
--- a/jdk/src/java.base/share/classes/java/lang/IndexOutOfBoundsException.java Tue Oct 06 18:39:26 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/IndexOutOfBoundsException.java Wed Oct 07 15:22:43 2015 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,28 +31,57 @@
* <p>
* Applications can subclass this class to indicate similar exceptions.
*
- * @author Frank Yellin
- * @since 1.0
+ * @author Frank Yellin
+ * @since 1.0
*/
-public
-class IndexOutOfBoundsException extends RuntimeException {
+public class IndexOutOfBoundsException extends RuntimeException {
private static final long serialVersionUID = 234122996006267687L;
/**
- * Constructs an <code>IndexOutOfBoundsException</code> with no
- * detail message.
+ * Constructs an {@code IndexOutOfBoundsException} with no detail message.
*/
public IndexOutOfBoundsException() {
super();
}
/**
- * Constructs an <code>IndexOutOfBoundsException</code> with the
- * specified detail message.
+ * Constructs an {@code IndexOutOfBoundsException} with the specified detail
+ * message.
*
- * @param s the detail message.
+ * @param s the detail message
*/
public IndexOutOfBoundsException(String s) {
super(s);
}
+
+ /**
+ * Constructs a new {@code IndexOutOfBoundsException} class with an
+ * argument indicating the illegal index.
+ *
+ * <p>The index is included in this exception's detail message. The
+ * exact presentation format of the detail message is unspecified.
+ *
+ * @param index the illegal index.
+ * @since 9
+ */
+ public IndexOutOfBoundsException(int index) {
+ super("Index out of range: " + index);
+ }
+
+ /**
+ * Constructs an {@code IndexOutOfBoundsException} with arguments indicating
+ * two out of bound values.
+ *
+ * <p>The out of bound values are included in this exception's detail
+ * message. The exact presentation format of the detail message is
+ * unspecified.
+ *
+ * @param a the first out of bound value
+ * @param b the second out of bound value
+ * @since 9
+ */
+ public IndexOutOfBoundsException(int a, int b) {
+ super("Indexed access out of bounds: " + a + ", " + b);
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/lang/StringIndexOutOfBoundsException.java Tue Oct 06 18:39:26 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/StringIndexOutOfBoundsException.java Wed Oct 07 15:22:43 2015 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,44 +26,61 @@
package java.lang;
/**
- * Thrown by {@code String} methods to indicate that an index
- * is either negative or greater than the size of the string. For
- * some methods such as the charAt method, this exception also is
- * thrown when the index is equal to the size of the string.
+ * Thrown by {@code String} methods to indicate that an index is either negative
+ * or greater than the size of the string. For some methods such as the
+ * {@link String#charAt charAt} method, this exception also is thrown when the
+ * index is equal to the size of the string.
*
- * @author unascribed
- * @see java.lang.String#charAt(int)
- * @since 1.0
+ * @see java.lang.String#charAt(int)
+ * @since 1.0
*/
-public
-class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
+public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
private static final long serialVersionUID = -6762910422159637258L;
/**
- * Constructs a {@code StringIndexOutOfBoundsException} with no
- * detail message.
+ * Constructs a {@code StringIndexOutOfBoundsException} with no detail
+ * message.
*/
public StringIndexOutOfBoundsException() {
super();
}
/**
- * Constructs a {@code StringIndexOutOfBoundsException} with
- * the specified detail message.
+ * Constructs a {@code StringIndexOutOfBoundsException} with the specified
+ * detail message.
*
- * @param s the detail message.
+ * @param s the detail message.
*/
public StringIndexOutOfBoundsException(String s) {
super(s);
}
/**
- * Constructs a new {@code StringIndexOutOfBoundsException}
- * class with an argument indicating the illegal index.
+ * Constructs a new {@code StringIndexOutOfBoundsException} class with an
+ * argument indicating the illegal index.
*
- * @param index the illegal index.
+ * <p>The index is included in this exception's detail message. The
+ * exact presentation format of the detail message is unspecified.
+ *
+ * @param index the illegal index.
*/
public StringIndexOutOfBoundsException(int index) {
super("String index out of range: " + index);
}
+
+ /**
+ * Constructs a new {@code StringIndexOutOfBoundsException} class with
+ * arguments indicating two out of bound values.
+ *
+ * <p>The out of bound values are included in this exception's detail
+ * message. The exact presentation format of the detail message is
+ * unspecified.
+ *
+ * @param a the first out of bound value.
+ * @param b the second out of bound value.
+ * @since 9
+ */
+ public StringIndexOutOfBoundsException(int a, int b) {
+ super("String indexed access out of bounds: " + a + ", " + b);
+ }
}
--- a/jdk/src/java.base/share/classes/java/util/Objects.java Tue Oct 06 18:39:26 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Objects.java Wed Oct 07 15:22:43 2015 +0200
@@ -25,13 +25,29 @@
package java.util;
+import java.util.function.BiFunction;
import java.util.function.Supplier;
/**
* This class consists of {@code static} utility methods for operating
- * on objects. These utilities include {@code null}-safe or {@code
- * null}-tolerant methods for computing the hash code of an object,
- * returning a string for an object, and comparing two objects.
+ * on objects, or checking certain conditions before operation. These utilities
+ * include {@code null}-safe or {@code null}-tolerant methods for computing the
+ * hash code of an object, returning a string for an object, comparing two
+ * objects, and checking if indexes or sub-range values are out of bounds.
+ *
+ * @apiNote
+ * Static methods such as {@link Objects#checkIndex},
+ * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are
+ * provided for the convenience of checking if values corresponding to indexes
+ * and sub-ranges are out of bounds.
+ * Variations of these static methods support customization of the runtime
+ * exception, and corresponding exception detail message, that is thrown when
+ * values are out of bounds. Such methods accept a functional interface
+ * argument, instances of {@code BiFunction}, that maps out of bound values to a
+ * runtime exception. Care should be taken when using such methods in
+ * combination with an argument that is a lambda expression, method reference or
+ * class that capture values. In such cases the cost of capture, related to
+ * functional interface allocation, may exceed the cost of checking bounds.
*
* @since 1.7
*/
@@ -290,4 +306,230 @@
throw new NullPointerException(messageSupplier.get());
return obj;
}
+
+ /**
+ * Maps out of bounds values to a runtime exception.
+ *
+ * @param a the first out of bound value
+ * @param b the second out of bound value
+ * @param oobe the exception mapping function that when applied with out of
+ * bounds arguments returns a runtime exception. If {@code null}
+ * then, it's as if an exception mapping function was supplied that
+ * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * @return the runtime exception
+ */
+ private static RuntimeException outOfBounds(
+ int a, int b, BiFunction<Integer, Integer, ? extends RuntimeException> oobe) {
+ return oobe == null
+ ? new IndexOutOfBoundsException(a, b)
+ : oobe.apply(a, b);
+ }
+
+ /**
+ * Checks if the {@code index} is within the bounds of the range from
+ * {@code 0} (inclusive) to {@code length} (exclusive).
+ *
+ * <p>The {@code index} is defined to be out of bounds if any of the
+ * following inequalities is true:
+ * <ul>
+ * <li>{@code index < 0}</li>
+ * <li>{@code index >= length}</li>
+ * <li>{@code length < 0}, which is implied from the former inequalities</li>
+ * </ul>
+ *
+ * @param index the index
+ * @param length the upper-bound (exclusive) of the range
+ * @return {@code index} if it is within bounds of the range
+ * @throws IndexOutOfBoundsException if the {@code index} is out of bounds
+ * @since 9
+ */
+ public static
+ int checkIndex(int index, int length) throws IndexOutOfBoundsException {
+ return checkIndex(index, length, null);
+ }
+
+ /**
+ * Checks if the {@code index} is within the bounds of the range from
+ * {@code 0} (inclusive) to {@code length} (exclusive).
+ *
+ * <p>The {@code index} is defined to be out of bounds if any of the
+ * following inequalities is true:
+ * <ul>
+ * <li>{@code index < 0}</li>
+ * <li>{@code index >= length}</li>
+ * <li>{@code length < 0}, which is implied from the former inequalities</li>
+ * </ul>
+ *
+ * <p>If the {@code index} is out of bounds, then a runtime exception is
+ * thrown that is the result of applying the arguments {@code index} and
+ * {@code length} to the given exception mapping function.
+ *
+ * @param <T> the type of runtime exception to throw if the arguments are
+ * out of bounds
+ * @param index the index
+ * @param length the upper-bound (exclusive) of the range
+ * @param oobe the exception mapping function that when applied with out
+ * of bounds arguments returns a runtime exception. If {@code null}
+ * then, it's as if an exception mapping function was supplied that
+ * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * @return {@code index} if it is within bounds of the range
+ * @throws T if the {@code index} is out of bounds, then a runtime exception
+ * is thrown that is the result of applying the out of bounds
+ * arguments to the exception mapping function.
+ * @throws IndexOutOfBoundsException if the {@code index} is out of bounds
+ * and the exception mapping function is {@code null}
+ * @since 9
+ */
+ /*
+ @HotSpotIntrinsicCandidate
+ This method will be made intrinsic in C2 to guide HotSpot to perform
+ unsigned comparisons of the index and length when it is known the length is
+ a non-negative value (such as that of an array length or from the upper
+ bound of a loop)
+ */
+ public static <T extends RuntimeException>
+ int checkIndex(int index, int length,
+ BiFunction<Integer, Integer, T> oobe) throws T, IndexOutOfBoundsException {
+ if (index < 0 || index >= length)
+ throw outOfBounds(index, length, oobe);
+ return index;
+ }
+
+ /**
+ * Checks if the sub-range from {@code fromIndex} (inclusive) to
+ * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+ * (inclusive) to {@code length} (exclusive).
+ *
+ * <p>The sub-range is defined to be out of bounds if any of the following
+ * inequalities is true:
+ * <ul>
+ * <li>{@code fromIndex < 0}</li>
+ * <li>{@code fromIndex > toIndex}</li>
+ * <li>{@code toIndex > length}</li>
+ * <li>{@code length < 0}, which is implied from the former inequalities</li>
+ * </ul>
+ *
+ * @param fromIndex the lower-bound (inclusive) of the sub-range
+ * @param toIndex the upper-bound (exclusive) of the sub-range
+ * @param length the upper-bound (exclusive) the range
+ * @return {@code fromIndex} if the sub-range within bounds of the range
+ * @throws IndexOutOfBoundsException if the sub-range is out of bounds
+ * @since 9
+ */
+ public static
+ int checkFromToIndex(int fromIndex, int toIndex, int length) throws IndexOutOfBoundsException {
+ return checkFromToIndex(fromIndex, toIndex, length, null);
+ }
+
+ /**
+ * Checks if the sub-range from {@code fromIndex} (inclusive) to
+ * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+ * (inclusive) to {@code length} (exclusive).
+ *
+ * <p>The sub-range is defined to be out of bounds if any of the following
+ * inequalities is true:
+ * <ul>
+ * <li>{@code fromIndex < 0}</li>
+ * <li>{@code fromIndex > toIndex}</li>
+ * <li>{@code toIndex > length}</li>
+ * <li>{@code length < 0}, which is implied from the former inequalities</li>
+ * </ul>
+ *
+ * <p>If the sub-range is out of bounds, then a runtime exception is thrown
+ * that is the result of applying the arguments {@code fromIndex} and
+ * {@code toIndex} to the given exception mapping function.
+ *
+ * @param <T> the type of runtime exception to throw if the arguments are
+ * out of bounds
+ * @param fromIndex the lower-bound (inclusive) of the sub-range
+ * @param toIndex the upper-bound (exclusive) of the sub-range
+ * @param length the upper-bound (exclusive) the range
+ * @param oobe the exception mapping function that when applied with out
+ * of bounds arguments returns a runtime exception. If {@code null}
+ * then, it's as if an exception mapping function was supplied that
+ * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * @return {@code fromIndex} if the sub-range within bounds of the range
+ * @throws T if the sub-range is out of bounds, then a runtime exception is
+ * thrown that is the result of applying the out of bounds arguments
+ * to the exception mapping function.
+ * @throws IndexOutOfBoundsException if the sub-range is out of bounds and
+ * the exception mapping function is {@code null}
+ * @since 9
+ */
+ public static <T extends RuntimeException>
+ int checkFromToIndex(int fromIndex, int toIndex, int length,
+ BiFunction<Integer, Integer, T> oobe) throws T, IndexOutOfBoundsException {
+ if (fromIndex < 0 || fromIndex > toIndex || toIndex > length)
+ throw outOfBounds(fromIndex, toIndex, oobe);
+ return fromIndex;
+ }
+
+ /**
+ * Checks if the sub-range from {@code fromIndex} (inclusive) to
+ * {@code fromIndex + size} (exclusive) is within the bounds of range from
+ * {@code 0} (inclusive) to {@code length} (exclusive).
+ *
+ * <p>The sub-range is defined to be out of bounds if any of the following
+ * inequalities is true:
+ * <ul>
+ * <li>{@code fromIndex < 0}</li>
+ * <li>{@code size < 0}</li>
+ * <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+ * <li>{@code length < 0}, which is implied from the former inequalities</li>
+ * </ul>
+ *
+ * @param fromIndex the lower-bound (inclusive) of the sub-interval
+ * @param size the size of the sub-range
+ * @param length the upper-bound (exclusive) of the range
+ * @return {@code fromIndex} if the sub-range within bounds of the range
+ * @throws IndexOutOfBoundsException if the sub-range is out of bounds
+ * @since 9
+ */
+ public static
+ int checkFromIndexSize(int fromIndex, int size, int length) throws IndexOutOfBoundsException {
+ return checkFromIndexSize(fromIndex, size, length, null);
+ }
+
+ /**
+ * Checks if the sub-range from {@code fromIndex} (inclusive) to
+ * {@code fromIndex + size} (exclusive) is within the bounds of range from
+ * {@code 0} (inclusive) to {@code length} (exclusive).
+ *
+ * <p>The sub-range is defined to be out of bounds if any of the following
+ * inequalities is true:
+ * <ul>
+ * <li>{@code fromIndex < 0}</li>
+ * <li>{@code size < 0}</li>
+ * <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+ * <li>{@code length < 0}, which is implied from the former inequalities</li>
+ * </ul>
+ *
+ * <p>If the sub-range is out of bounds then, a runtime exception is thrown
+ * that is the result of applying the arguments {@code fromIndex} and
+ * {@code size} to the given exception mapping function.
+ *
+ * @param <T> the type of runtime exception to throw if the arguments are
+ * out of bounds
+ * @param fromIndex the lower-bound (inclusive) of the sub-interval
+ * @param size the size of the sub-range
+ * @param length the upper-bound (exclusive) of the range
+ * @param oobe the exception mapping function that when applied with out
+ * of bounds arguments returns a runtime exception. If {@code null}
+ * then, it's as if an exception mapping function was supplied that
+ * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * @return {@code fromIndex} if the sub-range within bounds of the range
+ * @throws T if the sub-range is out of bounds, then a runtime exception is
+ * thrown that is the result of applying the out of bounds arguments
+ * to the exception mapping function.
+ * @throws IndexOutOfBoundsException if the sub-range is out of bounds and
+ * the exception mapping function is {@code null}
+ * @since 9
+ */
+ public static <T extends RuntimeException>
+ int checkFromIndexSize(int fromIndex, int size, int length,
+ BiFunction<Integer, Integer, T> oobe) throws T, IndexOutOfBoundsException {
+ if ((length | fromIndex | size) < 0 || size > length - fromIndex)
+ throw outOfBounds(fromIndex, size, oobe);
+ return fromIndex;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Objects/CheckIndex.java Wed Oct 07 15:22:43 2015 +0200
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary IndexOutOfBoundsException check index tests
+ * @run testng CheckIndex
+ * @bug 8135248
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.IntSupplier;
+
+import static org.testng.Assert.*;
+
+public class CheckIndex {
+
+ static class AssertingOutOfBoundsException extends RuntimeException {
+ }
+
+ static BiFunction<Integer, Integer, AssertingOutOfBoundsException> assertingOutOfBounds(
+ int expFromIndex, int expToIndexOrSizeOrLength) {
+ return (fromIndex, toIndexOrSizeorLength) -> {
+ assertEquals(fromIndex, Integer.valueOf(expFromIndex));
+ assertEquals(toIndexOrSizeorLength, Integer.valueOf(expToIndexOrSizeOrLength));
+ return new AssertingOutOfBoundsException();
+ };
+ }
+
+ static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE};
+
+ @DataProvider
+ static Object[][] checkIndexProvider() {
+ List<Object[]> l = new ArrayList<>();
+ for (int index : VALUES) {
+ for (int length : VALUES) {
+ boolean withinBounds = index >= 0 &&
+ length >= 0 &&
+ index < length;
+ l.add(new Object[]{index, length, withinBounds});
+ }
+ }
+ return l.toArray(new Object[0][0]);
+ }
+
+ interface X {
+ int apply(int a, int b, int c);
+ }
+
+ @Test(dataProvider = "checkIndexProvider")
+ public void testCheckIndex(int index, int length, boolean withinBounds) {
+ BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> {
+ try {
+ int rIndex = s.getAsInt();
+ if (!withinBounds)
+ fail(String.format(
+ "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length));
+ assertEquals(rIndex, index);
+ }
+ catch (RuntimeException e) {
+ assertTrue(ec.isInstance(e));
+ if (withinBounds)
+ fail(String.format(
+ "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length));
+ }
+ };
+
+ check.accept(AssertingOutOfBoundsException.class,
+ () -> Objects.checkIndex(index, length, assertingOutOfBounds(index, length)));
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkIndex(index, length, null));
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkIndex(index, length));
+ }
+
+
+ @DataProvider
+ static Object[][] checkFromToIndexProvider() {
+ List<Object[]> l = new ArrayList<>();
+ for (int fromIndex : VALUES) {
+ for (int toIndex : VALUES) {
+ for (int length : VALUES) {
+ boolean withinBounds = fromIndex >= 0 &&
+ toIndex >= 0 &&
+ length >= 0 &&
+ fromIndex <= toIndex &&
+ toIndex <= length;
+ l.add(new Object[]{fromIndex, toIndex, length, withinBounds});
+ }
+ }
+ }
+ return l.toArray(new Object[0][0]);
+ }
+
+ @Test(dataProvider = "checkFromToIndexProvider")
+ public void testCheckFromToIndex(int fromIndex, int toIndex, int length, boolean withinBounds) {
+ BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> {
+ try {
+ int rIndex = s.getAsInt();
+ if (!withinBounds)
+ fail(String.format(
+ "Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length));
+ assertEquals(rIndex, fromIndex);
+ }
+ catch (RuntimeException e) {
+ assertTrue(ec.isInstance(e));
+ if (withinBounds)
+ fail(String.format(
+ "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length));
+ }
+ };
+
+ check.accept(AssertingOutOfBoundsException.class,
+ () -> Objects.checkFromToIndex(fromIndex, toIndex, length, assertingOutOfBounds(fromIndex, toIndex)));
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkFromToIndex(fromIndex, toIndex, length, null));
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkFromToIndex(fromIndex, toIndex, length));
+ }
+
+
+ @DataProvider
+ static Object[][] checkFromIndexSizeProvider() {
+ List<Object[]> l = new ArrayList<>();
+ for (int fromIndex : VALUES) {
+ for (int size : VALUES) {
+ for (int length : VALUES) {
+ // Explicitly convert to long
+ long lFromIndex = fromIndex;
+ long lSize = size;
+ long lLength = length;
+ // Avoid overflow
+ long lToIndex = lFromIndex + lSize;
+
+ boolean withinBounds = lFromIndex >= 0L &&
+ lSize >= 0L &&
+ lLength >= 0L &&
+ lFromIndex <= lToIndex &&
+ lToIndex <= lLength;
+ l.add(new Object[]{fromIndex, size, length, withinBounds});
+ }
+ }
+ }
+ return l.toArray(new Object[0][0]);
+ }
+
+ @Test(dataProvider = "checkFromIndexSizeProvider")
+ public void testCheckFromIndexSize(int fromIndex, int size, int length, boolean withinBounds) {
+ BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> {
+ try {
+ int rIndex = s.getAsInt();
+ if (!withinBounds)
+ fail(String.format(
+ "Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length));
+ assertEquals(rIndex, fromIndex);
+ }
+ catch (RuntimeException e) {
+ assertTrue(ec.isInstance(e));
+ if (withinBounds)
+ fail(String.format(
+ "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length));
+ }
+ };
+
+ check.accept(AssertingOutOfBoundsException.class,
+ () -> Objects.checkFromIndexSize(fromIndex, size, length, assertingOutOfBounds(fromIndex, size)));
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkFromIndexSize(fromIndex, size, length, null));
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkFromIndexSize(fromIndex, size, length));
+ }
+
+ @Test
+ public void checkIndexOutOfBoundsExceptionConstructors() {
+ BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> {
+ try {
+ s.getAsInt();
+ fail("Runtime exception expected");
+ }
+ catch (RuntimeException e) {
+ assertTrue(ec.isInstance(e));
+ }
+ };
+
+ check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkIndex(1, 0, IndexOutOfBoundsException::new));
+ check.accept(StringIndexOutOfBoundsException.class,
+ () -> Objects.checkIndex(1, 0, StringIndexOutOfBoundsException::new));
+ check.accept(ArrayIndexOutOfBoundsException.class,
+ () -> Objects.checkIndex(1, 0, ArrayIndexOutOfBoundsException::new));
+ }
+}