1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test 8014076 8025067
  26  * @summary unit test for Arrays.ParallelPrefix().
  27  * @author Tristan Yan
  28  * @run testng ParallelPrefix
  29  * @key intermittent
  30  */
  31 
  32 import java.util.Arrays;
  33 import java.util.function.BinaryOperator;
  34 import java.util.function.DoubleBinaryOperator;
  35 import java.util.function.Function;
  36 import java.util.function.IntBinaryOperator;
  37 import java.util.function.LongBinaryOperator;
  38 import java.util.stream.IntStream;
  39 import java.util.stream.LongStream;
  40 import static org.testng.Assert.*;
  41 import org.testng.annotations.DataProvider;
  42 import org.testng.annotations.Test;
  43 
  44 public class ParallelPrefix {
  45     //Array size less than MIN_PARTITION
  46     private static final int SMALL_ARRAY_SIZE = 1 << 3;
  47 
  48     //Array size equals MIN_PARTITION
  49     private static final int THRESHOLD_ARRAY_SIZE = 1 << 4;
  50 
  51     //Array size greater than MIN_PARTITION
  52     private static final int MEDIUM_ARRAY_SIZE = 1 << 8;
  53 
  54     //Array size much greater than MIN_PARTITION
  55     private static final int LARGE_ARRAY_SIZE = 1 << 14;
  56 
  57     private static final int[] ARRAY_SIZE_COLLECTION  = new int[]{
  58         SMALL_ARRAY_SIZE,
  59         THRESHOLD_ARRAY_SIZE,
  60         MEDIUM_ARRAY_SIZE,
  61         LARGE_ARRAY_SIZE
  62     };
  63 
  64     @DataProvider(name = "intSet")
  65     public static Object[][] intSet(){
  66         return genericData(size -> IntStream.range(0, size).toArray(),
  67                 new IntBinaryOperator[]{
  68                     Integer::sum,
  69                     Integer::min});
  70     }
  71 
  72     @DataProvider(name = "longSet")
  73     public static Object[][] longSet(){
  74         return genericData(size -> LongStream.range(0, size).toArray(),
  75                 new LongBinaryOperator[]{
  76                     Long::sum,
  77                     Long::min});
  78     }
  79 
  80     @DataProvider(name = "doubleSet")
  81     public static Object[][] doubleSet(){
  82         return genericData(size -> IntStream.range(0, size).mapToDouble(i -> (double)i).toArray(),
  83                 new DoubleBinaryOperator[]{
  84                     Double::sum,
  85                     Double::min});
  86     }
  87 
  88     @DataProvider(name = "stringSet")
  89     public static Object[][] stringSet(){
  90         Function<Integer, String[]> stringsFunc = size ->
  91                 IntStream.range(0, size).mapToObj(Integer::toString).toArray(String[]::new);
  92         BinaryOperator<String> concat = String::concat;
  93         return genericData(stringsFunc,
  94                 (BinaryOperator<String>[]) new BinaryOperator[]{
  95                     concat });
  96     }
  97 
  98     private static <T, OPS> Object[][] genericData(Function<Integer, T> generateFunc, OPS[] ops) {
  99         //test arrays which size is equals n-1, n, n+1, test random data
 100         Object[][] data = new Object[ARRAY_SIZE_COLLECTION.length * 3 * ops.length][4];
 101         for(int n = 0; n < ARRAY_SIZE_COLLECTION.length; n++ ) {
 102             for(int testValue = -1 ; testValue <= 1; testValue++) {
 103                 int array_size = ARRAY_SIZE_COLLECTION[n] + testValue;
 104                 for(int opsN = 0; opsN < ops.length; opsN++) {
 105                     int index = n * 3 * ops.length + (testValue + 1) * ops.length + opsN;
 106                     data[index][0] = generateFunc.apply(array_size);
 107                     data[index][1] = array_size / 3;
 108                     data[index][2] = 2 * array_size / 3;
 109                     data[index][3] = ops[opsN];
 110                 }
 111             }
 112         }
 113         return data;
 114     }
 115 
 116     @Test(dataProvider="intSet")
 117     public void testParallelPrefixForInt(int[] data, int fromIndex, int toIndex, IntBinaryOperator op) {
 118         int[] sequentialResult = data.clone();
 119         for (int index = fromIndex + 1; index < toIndex; index++) {
 120             sequentialResult[index ] = op.applyAsInt(sequentialResult[index  - 1], sequentialResult[index]);
 121         }
 122 
 123         int[] parallelResult = data.clone();
 124         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
 125         assertArraysEqual(parallelResult, sequentialResult);
 126 
 127         int[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
 128         Arrays.parallelPrefix(parallelRangeResult, op);
 129         assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
 130     }
 131 
 132     @Test(dataProvider="longSet")
 133     public void testParallelPrefixForLong(long[] data, int fromIndex, int toIndex, LongBinaryOperator op) {
 134         long[] sequentialResult = data.clone();
 135         for (int index = fromIndex + 1; index < toIndex; index++) {
 136             sequentialResult[index ] = op.applyAsLong(sequentialResult[index  - 1], sequentialResult[index]);
 137         }
 138 
 139         long[] parallelResult = data.clone();
 140         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
 141         assertArraysEqual(parallelResult, sequentialResult);
 142 
 143         long[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
 144         Arrays.parallelPrefix(parallelRangeResult, op);
 145         assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
 146     }
 147 
 148     @Test(dataProvider="doubleSet")
 149     public void testParallelPrefixForDouble(double[] data, int fromIndex, int toIndex, DoubleBinaryOperator op) {
 150         double[] sequentialResult = data.clone();
 151         for (int index = fromIndex + 1; index < toIndex; index++) {
 152             sequentialResult[index ] = op.applyAsDouble(sequentialResult[index  - 1], sequentialResult[index]);
 153         }
 154 
 155         double[] parallelResult = data.clone();
 156         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
 157         assertArraysEqual(parallelResult, sequentialResult);
 158 
 159         double[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
 160         Arrays.parallelPrefix(parallelRangeResult, op);
 161         assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
 162     }
 163 
 164     @Test(dataProvider="stringSet")
 165     public void testParallelPrefixForStringr(String[] data , int fromIndex, int toIndex, BinaryOperator<String> op) {
 166         String[] sequentialResult = data.clone();
 167         for (int index = fromIndex + 1; index < toIndex; index++) {
 168             sequentialResult[index ] = op.apply(sequentialResult[index  - 1], sequentialResult[index]);
 169         }
 170 
 171         String[] parallelResult = data.clone();
 172         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
 173         assertArraysEqual(parallelResult, sequentialResult);
 174 
 175         String[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
 176         Arrays.parallelPrefix(parallelRangeResult, op);
 177         assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
 178     }
 179 
 180     @Test
 181     public void testNPEs() {
 182         // null array
 183         assertThrows( () -> Arrays.parallelPrefix((int[]) null, Integer::max),
 184                 NullPointerException.class, "should throw NPE");
 185         assertThrows( () -> Arrays.parallelPrefix((long []) null, Long::max),
 186                 NullPointerException.class, "should throw NPE");
 187         assertThrows( () -> Arrays.parallelPrefix((double []) null, Double::max),
 188                 NullPointerException.class, "should throw NPE");
 189         assertThrows( () -> Arrays.parallelPrefix((String []) null, String::concat),
 190                 NullPointerException.class, "should throw NPE");
 191 
 192         // null array w/ range
 193         assertThrows( () -> Arrays.parallelPrefix((int[]) null, 0, 0, Integer::max),
 194                 NullPointerException.class, "should throw NPE");
 195         assertThrows( () -> Arrays.parallelPrefix((long []) null, 0, 0, Long::max),
 196                 NullPointerException.class, "should throw NPE");
 197         assertThrows( () -> Arrays.parallelPrefix((double []) null, 0, 0, Double::max),
 198                 NullPointerException.class, "should throw NPE");
 199         assertThrows( () -> Arrays.parallelPrefix((String []) null, 0, 0, String::concat),
 200                 NullPointerException.class, "should throw NPE");
 201 
 202         // null op
 203         assertThrows( () -> Arrays.parallelPrefix(new int[] {}, null),
 204                 NullPointerException.class, "should throw NPE");
 205         assertThrows( () -> Arrays.parallelPrefix(new long[] {}, null),
 206                 NullPointerException.class, "should throw NPE");
 207         assertThrows( () -> Arrays.parallelPrefix(new double[] {}, null),
 208                 NullPointerException.class, "should throw NPE");
 209         assertThrows( () -> Arrays.parallelPrefix(new String[] {}, null),
 210                 NullPointerException.class, "should throw NPE");
 211 
 212         // null op w/ range
 213         assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 0, 0, null),
 214                 NullPointerException.class, "should throw NPE");
 215         assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 0, 0, null),
 216                 NullPointerException.class, "should throw NPE");
 217         assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 0, 0, null),
 218                 NullPointerException.class, "should throw NPE");
 219         assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 0, 0, null),
 220                 NullPointerException.class, "should throw NPE");
 221     }
 222 
 223     @Test
 224     public void testIAEs() {
 225         assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 1, 0, Integer::max),
 226                 IllegalArgumentException.class, "should throw IAE");
 227         assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 1, 0, Long::max),
 228                 IllegalArgumentException.class, "should throw IAE");
 229         assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 1, 0, Double::max),
 230                 IllegalArgumentException.class, "should throw IAE");
 231         assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 1, 0, String::concat),
 232                 IllegalArgumentException.class, "should throw IAE");
 233     }
 234 
 235     @Test
 236     public void testAIOBEs() {
 237         // bad "fromIndex"
 238         assertThrows( () -> Arrays.parallelPrefix(new int[] {}, -1, 0, Integer::max),
 239                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 240         assertThrows( () -> Arrays.parallelPrefix(new long[] {}, -1, 0, Long::max),
 241                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 242         assertThrows( () -> Arrays.parallelPrefix(new double[] {}, -1, 0, Double::max),
 243                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 244         assertThrows( () -> Arrays.parallelPrefix(new String[] {}, -1, 0, String::concat),
 245                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 246 
 247         // bad "toIndex"
 248         assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 0, 1, Integer::max),
 249                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 250         assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 0, 1, Long::max),
 251                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 252         assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 0, 1, Double::max),
 253                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 254         assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 0, 1, String::concat),
 255                 ArrayIndexOutOfBoundsException.class, "should throw AIOBE");
 256     }
 257 
 258     // "library" code
 259 
 260     public interface Thrower<T extends Throwable> {
 261 
 262         public void run() throws T;
 263     }
 264 
 265 
 266     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
 267         assertThrows(thrower, throwable, null);
 268     }
 269 
 270     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
 271         Throwable thrown;
 272         try {
 273             thrower.run();
 274             thrown = null;
 275         } catch (Throwable caught) {
 276             thrown = caught;
 277         }
 278 
 279         assertInstance(thrown, throwable,
 280             ((null != message) ? message : "") +
 281             " Failed to throw " + throwable.getCanonicalName());
 282     }
 283 
 284     public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
 285         for(Thrower<T> thrower : throwers) {
 286             assertThrows(thrower, throwable, message);
 287         }
 288     }
 289 
 290     public static void assertInstance(Object actual, Class<?> expected) {
 291         assertInstance(expected.isInstance(actual), null);
 292     }
 293 
 294     public static void assertInstance(Object actual, Class<?> expected, String message) {
 295         assertTrue(expected.isInstance(actual), message);
 296     }
 297 
 298     static void assertArraysEqual(int[] actual, int[] expected) {
 299         try {
 300             assertEquals(actual, expected, "");
 301         } catch (AssertionError x) {
 302             throw new AssertionError(String.format("Expected:%s, actual:%s",
 303                     Arrays.toString(expected), Arrays.toString(actual)), x);
 304         }
 305     }
 306 
 307     static void assertArraysEqual(long[] actual, long[] expected) {
 308         try {
 309             assertEquals(actual, expected, "");
 310         } catch (AssertionError x) {
 311             throw new AssertionError(String.format("Expected:%s, actual:%s",
 312                     Arrays.toString(expected), Arrays.toString(actual)), x);
 313         }
 314     }
 315 
 316     static void assertArraysEqual(double[] actual, double[] expected) {
 317         try {
 318             assertEquals(actual, expected, "");
 319         } catch (AssertionError x) {
 320             throw new AssertionError(String.format("Expected:%s, actual:%s",
 321                     Arrays.toString(expected), Arrays.toString(actual)), x);
 322         }
 323     }
 324 
 325     static void assertArraysEqual(String[] actual, String[] expected) {
 326         try {
 327             assertEquals(actual, expected, "");
 328         } catch (AssertionError x) {
 329             throw new AssertionError(String.format("Expected:%s, actual:%s",
 330                     Arrays.toString(expected), Arrays.toString(actual)), x);
 331         }
 332     }
 333 }
 334