# HG changeset patch # User mduigou # Date 1380648180 25200 # Node ID 11418b1f61ffc3f4ea9fc861c15a739042782e6f # Parent eb2dfc7436afc2fa14b3b36a6fde3ae80146d37c 8025067: Unconditionally throw NPE if null op provided to Arrays.parallelPrefix Reviewed-by: henryjen, chegar, psandoz diff -r eb2dfc7436af -r 11418b1f61ff jdk/src/share/classes/java/util/Arrays.java --- a/jdk/src/share/classes/java/util/Arrays.java Mon Sep 30 15:50:06 2013 -0700 +++ b/jdk/src/share/classes/java/util/Arrays.java Tue Oct 01 10:23:00 2013 -0700 @@ -1583,6 +1583,7 @@ * @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 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 @@ * @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 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 @@ * @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 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 @@ * @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 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 -r eb2dfc7436af -r 11418b1f61ff jdk/test/java/util/Arrays/ParallelPrefix.java --- a/jdk/test/java/util/Arrays/ParallelPrefix.java Mon Sep 30 15:50:06 2013 -0700 +++ b/jdk/test/java/util/Arrays/ParallelPrefix.java Tue Oct 01 10:23:00 2013 -0700 @@ -22,7 +22,7 @@ */ /** - * @test + * @test 8014076 8025067 * @summary unit test for Arrays.ParallelPrefix(). * @author Tristan Yan * @run testng ParallelPrefix @@ -54,30 +54,44 @@ 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 @@ 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); + } }