diff --git a/src/share/classes/java/util/Arrays.java b/src/share/classes/java/util/Arrays.java index 47c99ef7f826300b333373177b5c86cca066f929..43463a5aff6a60545f0b41e1746ece689b9d3ef7 100644 --- a/src/share/classes/java/util/Arrays.java +++ b/src/share/classes/java/util/Arrays.java @@ -1583,6 +1583,7 @@ public class Arrays { * @since 1.8 */ public static void parallelPrefix(T[] array, BinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.CumulateTask<> (null, op, array, 0, array.length).invoke(); @@ -1606,6 +1607,7 @@ public class Arrays { */ public static void parallelPrefix(T[] array, int fromIndex, int toIndex, BinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.CumulateTask<> @@ -1627,6 +1629,7 @@ public class Arrays { * @since 1.8 */ public static void parallelPrefix(long[] array, LongBinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.LongCumulateTask (null, op, array, 0, array.length).invoke(); @@ -1649,6 +1652,7 @@ public class Arrays { */ public static void parallelPrefix(long[] array, int fromIndex, int toIndex, LongBinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.LongCumulateTask @@ -1673,6 +1677,7 @@ public class Arrays { * @since 1.8 */ public static void parallelPrefix(double[] array, DoubleBinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.DoubleCumulateTask (null, op, array, 0, array.length).invoke(); @@ -1695,6 +1700,7 @@ public class Arrays { */ public static void parallelPrefix(double[] array, int fromIndex, int toIndex, DoubleBinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.DoubleCumulateTask @@ -1716,6 +1722,7 @@ public class Arrays { * @since 1.8 */ public static void parallelPrefix(int[] array, IntBinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.IntCumulateTask (null, op, array, 0, array.length).invoke(); @@ -1738,6 +1745,7 @@ public class Arrays { */ public static void parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.IntCumulateTask diff --git a/test/java/util/Arrays/ParallelPrefix.java b/test/java/util/Arrays/ParallelPrefix.java index 072de79c42c55372072df2c5e956b035214746c1..8d0d788247a015cbd179b791bc44d36f0d79a919 100644 --- a/test/java/util/Arrays/ParallelPrefix.java +++ b/test/java/util/Arrays/ParallelPrefix.java @@ -22,7 +22,7 @@ */ /** - * @test + * @test 8014076 8025067 * @summary unit test for Arrays.ParallelPrefix(). * @author Tristan Yan * @run testng ParallelPrefix @@ -54,30 +54,44 @@ public class ParallelPrefix { private final static int LARGE_ARRAY_SIZE = 1 << 12; private final static int[] ARRAY_SIZE_COLLECTION = new int[]{ - SMALL_ARRAY_SIZE, THRESHOLD_ARRAY_SIZE,MEDIUM_ARRAY_SIZE, LARGE_ARRAY_SIZE}; + SMALL_ARRAY_SIZE, + THRESHOLD_ARRAY_SIZE, + MEDIUM_ARRAY_SIZE, + LARGE_ARRAY_SIZE + }; @DataProvider public static Object[][] intSet(){ - return genericData(size -> IntStream.range(0, size).toArray(), new IntBinaryOperator[]{Integer::sum, Integer::min}); + return genericData(size -> IntStream.range(0, size).toArray(), + new IntBinaryOperator[]{ + Integer::sum, + Integer::min}); } @DataProvider public static Object[][] longSet(){ - return genericData(size -> LongStream.range(0, size).toArray(), new LongBinaryOperator[]{Long::sum, Long::min}); + return genericData(size -> LongStream.range(0, size).toArray(), + new LongBinaryOperator[]{ + Long::sum, + Long::min}); } @DataProvider public static Object[][] doubleSet(){ return genericData(size -> IntStream.range(0, size).mapToDouble(i -> (double)i).toArray(), - new DoubleBinaryOperator[]{Double::sum, Double::min}); + new DoubleBinaryOperator[]{ + Double::sum, + Double::min}); } @DataProvider public static Object[][] stringSet(){ Function stringsFunc = size -> IntStream.range(0, size).mapToObj(Integer::toString).toArray(String[]::new); - BinaryOperator cancatBop = String::concat; - return genericData(stringsFunc, new BinaryOperator[]{cancatBop}); + BinaryOperator concat = String::concat; + return genericData(stringsFunc, + (BinaryOperator[]) new BinaryOperator[]{ + concat }); } private static Object[][] genericData(Function generateFunc, OPS[] ops) { @@ -161,5 +175,123 @@ public class ParallelPrefix { Arrays.parallelPrefix(parallelRangeResult, op); assertEquals(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex)); } + + @Test + public void testNPEs() { + // null array + assertThrows( () -> Arrays.parallelPrefix((int[]) null, Integer::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((long []) null, Long::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((double []) null, Double::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((String []) null, String::concat), + NullPointerException.class, "should throw NPE"); + + // null array w/ range + assertThrows( () -> Arrays.parallelPrefix((int[]) null, 0, 0, Integer::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((long []) null, 0, 0, Long::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((double []) null, 0, 0, Double::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((String []) null, 0, 0, String::concat), + NullPointerException.class, "should throw NPE"); + + // null op + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, null), + NullPointerException.class, "should throw NPE"); + + // null op w/ range + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + } + + @Test + public void testIAEs() { + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 1, 0, Integer::max), + IllegalArgumentException.class, "should throw IAE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 1, 0, Long::max), + IllegalArgumentException.class, "should throw IAE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 1, 0, Double::max), + IllegalArgumentException.class, "should throw IAE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 1, 0, String::concat), + IllegalArgumentException.class, "should throw IAE"); + } + + @Test + public void testAIOBEs() { + // bad "fromIndex" + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, -1, 0, Integer::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, -1, 0, Long::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, -1, 0, Double::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, -1, 0, String::concat), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + + // bad "toIndex" + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 0, 1, Integer::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 0, 1, Long::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 0, 1, Double::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 0, 1, String::concat), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + } + + // "library" code + + public interface Thrower { + + public void run() throws T; + } + + + public static void assertThrows(Thrower thrower, Class throwable) { + assertThrows(thrower, throwable, null); + } + + public static void assertThrows(Thrower thrower, Class throwable, String message) { + Throwable thrown; + try { + thrower.run(); + thrown = null; + } catch (Throwable caught) { + thrown = caught; + } + + assertInstance(thrown, throwable, + ((null != message) ? message : "") + + " Failed to throw " + throwable.getCanonicalName()); + } + + public static void assertThrows(Class throwable, String message, Thrower... throwers) { + for(Thrower thrower : throwers) { + assertThrows(thrower, throwable, message); + } + } + + public static void assertInstance(Object actual, Class expected) { + assertInstance(expected.isInstance(actual), null); + } + + public static void assertInstance(Object actual, Class expected, String message) { + assertTrue(expected.isInstance(actual), message); + } }