rev 14354 : 8155794: Move Objects.checkIndex BiFunction accepting methods to an internal package
Reviewed-by:

   1 /*
   2  * Copyright (c) 2015, 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
  26  * @summary IndexOutOfBoundsException check index tests
  27  * @run testng CheckIndex
  28  * @bug 8135248 8142493

  29  */
  30 

  31 import org.testng.annotations.DataProvider;
  32 import org.testng.annotations.Test;
  33 
  34 import java.util.ArrayList;
  35 import java.util.List;
  36 import java.util.Objects;
  37 import java.util.function.BiConsumer;
  38 import java.util.function.BiFunction;
  39 import java.util.function.IntSupplier;
  40 
  41 import static org.testng.Assert.*;
  42 
  43 public class CheckIndex {
  44 
  45     static class AssertingOutOfBoundsException extends RuntimeException {
  46         public AssertingOutOfBoundsException(String message) {
  47             super(message);
  48         }
  49     }
  50 
  51     static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBounds(
  52             String message, String expCheckKind, Integer... expArgs) {
  53         return (checkKind, args) -> {
  54             assertEquals(checkKind, expCheckKind);
  55             assertEquals(args, List.of(expArgs));
  56             try {
  57                 args.clear();
  58                 fail("Out of bounds List<Integer> argument should be unmodifiable");
  59             } catch (Exception e)  {
  60             }
  61             return new AssertingOutOfBoundsException(message);
  62         };
  63     }
  64 
  65     static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull(
  66             String expCheckKind, Integer... expArgs) {
  67         return (checkKind, args) -> {
  68             assertEquals(checkKind, expCheckKind);
  69             assertEquals(args, List.of(expArgs));
  70             return null;
  71         };
  72     }
  73 
  74     static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE};
  75 
  76     @DataProvider
  77     static Object[][] checkIndexProvider() {
  78         List<Object[]> l = new ArrayList<>();
  79         for (int index : VALUES) {
  80             for (int length : VALUES) {
  81                 boolean withinBounds = index >= 0 &&
  82                                        length >= 0 &&
  83                                        index < length;
  84                 l.add(new Object[]{index, length, withinBounds});
  85             }
  86         }
  87         return l.toArray(new Object[0][0]);
  88     }
  89 
  90     interface X {
  91         int apply(int a, int b, int c);
  92     }
  93 
  94     @Test(dataProvider = "checkIndexProvider")
  95     public void testCheckIndex(int index, int length, boolean withinBounds) {
  96         String expectedMessage = withinBounds
  97                                  ? null
  98                                  : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new).
  99                 apply("checkIndex", List.of(index, length)).getMessage();
 100 
 101         BiConsumer<Class<? extends RuntimeException>, IntSupplier> checker = (ec, s) -> {
 102             try {
 103                 int rIndex = s.getAsInt();
 104                 if (!withinBounds)
 105                     fail(String.format(
 106                             "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length));
 107                 assertEquals(rIndex, index);
 108             }
 109             catch (RuntimeException e) {
 110                 assertTrue(ec.isInstance(e));
 111                 if (withinBounds)
 112                     fail(String.format(
 113                             "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length));
 114                 else
 115                     assertEquals(e.getMessage(), expectedMessage);
 116             }
 117         };
 118 
 119         checker.accept(AssertingOutOfBoundsException.class,
 120                      () -> Objects.checkIndex(index, length,
 121                                               assertingOutOfBounds(expectedMessage, "checkIndex", index, length)));
 122         checker.accept(IndexOutOfBoundsException.class,
 123                      () -> Objects.checkIndex(index, length,
 124                                               assertingOutOfBoundsReturnNull("checkIndex", index, length)));
 125         checker.accept(IndexOutOfBoundsException.class,
 126                      () -> Objects.checkIndex(index, length, null));
 127         checker.accept(IndexOutOfBoundsException.class,
 128                      () -> Objects.checkIndex(index, length));
 129         checker.accept(ArrayIndexOutOfBoundsException.class,
 130                      () -> Objects.checkIndex(index, length,
 131                                               Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new)));
 132         checker.accept(StringIndexOutOfBoundsException.class,
 133                      () -> Objects.checkIndex(index, length,
 134                                               Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new)));
 135     }
 136 
 137 
 138     @DataProvider
 139     static Object[][] checkFromToIndexProvider() {
 140         List<Object[]> l = new ArrayList<>();
 141         for (int fromIndex : VALUES) {
 142             for (int toIndex : VALUES) {
 143                 for (int length : VALUES) {
 144                     boolean withinBounds = fromIndex >= 0 &&
 145                                            toIndex >= 0 &&
 146                                            length >= 0 &&
 147                                            fromIndex <= toIndex &&
 148                                            toIndex <= length;
 149                     l.add(new Object[]{fromIndex, toIndex, length, withinBounds});
 150                 }
 151             }
 152         }
 153         return l.toArray(new Object[0][0]);
 154     }
 155 
 156     @Test(dataProvider = "checkFromToIndexProvider")
 157     public void testCheckFromToIndex(int fromIndex, int toIndex, int length, boolean withinBounds) {
 158         String expectedMessage = withinBounds
 159                                  ? null
 160                                  : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new).
 161                 apply("checkFromToIndex", List.of(fromIndex, toIndex, length)).getMessage();
 162 
 163         BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> {
 164             try {
 165                 int rIndex = s.getAsInt();
 166                 if (!withinBounds)
 167                     fail(String.format(
 168                             "Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length));
 169                 assertEquals(rIndex, fromIndex);
 170             }
 171             catch (RuntimeException e) {
 172                 assertTrue(ec.isInstance(e));
 173                 if (withinBounds)
 174                     fail(String.format(
 175                             "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length));
 176                 else
 177                     assertEquals(e.getMessage(), expectedMessage);
 178             }
 179         };
 180 
 181         check.accept(AssertingOutOfBoundsException.class,
 182                      () -> Objects.checkFromToIndex(fromIndex, toIndex, length,
 183                                                     assertingOutOfBounds(expectedMessage, "checkFromToIndex", fromIndex, toIndex, length)));
 184         check.accept(IndexOutOfBoundsException.class,
 185                      () -> Objects.checkFromToIndex(fromIndex, toIndex, length,
 186                                                     assertingOutOfBoundsReturnNull("checkFromToIndex", fromIndex, toIndex, length)));
 187         check.accept(IndexOutOfBoundsException.class,
 188                      () -> Objects.checkFromToIndex(fromIndex, toIndex, length, null));
 189         check.accept(IndexOutOfBoundsException.class,
 190                      () -> Objects.checkFromToIndex(fromIndex, toIndex, length));
 191         check.accept(ArrayIndexOutOfBoundsException.class,
 192                      () -> Objects.checkFromToIndex(fromIndex, toIndex, length,
 193                                               Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new)));
 194         check.accept(StringIndexOutOfBoundsException.class,
 195                      () -> Objects.checkFromToIndex(fromIndex, toIndex, length,
 196                                               Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new)));
 197     }
 198 
 199 
 200     @DataProvider
 201     static Object[][] checkFromIndexSizeProvider() {
 202         List<Object[]> l = new ArrayList<>();
 203         for (int fromIndex : VALUES) {
 204             for (int size : VALUES) {
 205                 for (int length : VALUES) {
 206                     // Explicitly convert to long
 207                     long lFromIndex = fromIndex;
 208                     long lSize = size;
 209                     long lLength = length;
 210                     // Avoid overflow
 211                     long lToIndex = lFromIndex + lSize;
 212 
 213                     boolean withinBounds = lFromIndex >= 0L &&
 214                                            lSize >= 0L &&
 215                                            lLength >= 0L &&
 216                                            lFromIndex <= lToIndex &&
 217                                            lToIndex <= lLength;
 218                     l.add(new Object[]{fromIndex, size, length, withinBounds});
 219                 }
 220             }
 221         }
 222         return l.toArray(new Object[0][0]);
 223     }
 224 
 225     @Test(dataProvider = "checkFromIndexSizeProvider")
 226     public void testCheckFromIndexSize(int fromIndex, int size, int length, boolean withinBounds) {
 227         String expectedMessage = withinBounds
 228                                  ? null
 229                                  : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new).
 230                 apply("checkFromIndexSize", List.of(fromIndex, size, length)).getMessage();
 231 
 232         BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> {
 233             try {
 234                 int rIndex = s.getAsInt();
 235                 if (!withinBounds)
 236                     fail(String.format(
 237                             "Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length));
 238                 assertEquals(rIndex, fromIndex);
 239             }
 240             catch (RuntimeException e) {
 241                 assertTrue(ec.isInstance(e));
 242                 if (withinBounds)
 243                     fail(String.format(
 244                             "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length));
 245                 else
 246                     assertEquals(e.getMessage(), expectedMessage);
 247             }
 248         };
 249 
 250         check.accept(AssertingOutOfBoundsException.class,
 251                      () -> Objects.checkFromIndexSize(fromIndex, size, length,
 252                                                       assertingOutOfBounds(expectedMessage, "checkFromIndexSize", fromIndex, size, length)));
 253         check.accept(IndexOutOfBoundsException.class,
 254                      () -> Objects.checkFromIndexSize(fromIndex, size, length,
 255                                                       assertingOutOfBoundsReturnNull("checkFromIndexSize", fromIndex, size, length)));
 256         check.accept(IndexOutOfBoundsException.class,
 257                      () -> Objects.checkFromIndexSize(fromIndex, size, length, null));
 258         check.accept(IndexOutOfBoundsException.class,
 259                      () -> Objects.checkFromIndexSize(fromIndex, size, length));
 260         check.accept(ArrayIndexOutOfBoundsException.class,
 261                      () -> Objects.checkFromIndexSize(fromIndex, size, length,
 262                                                     Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new)));
 263         check.accept(StringIndexOutOfBoundsException.class,
 264                      () -> Objects.checkFromIndexSize(fromIndex, size, length,
 265                                                     Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new)));
 266     }
 267 
 268     @Test
 269     public void uniqueMessagesForCheckKinds() {
 270         BiFunction<String, List<Integer>, IndexOutOfBoundsException> f =
 271                 Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new);
 272 
 273         List<String> messages = new ArrayList<>();
 274         // Exact arguments
 275         messages.add(f.apply("checkIndex", List.of(-1, 0)).getMessage());
 276         messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0)).getMessage());
 277         messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0)).getMessage());
 278         // Unknown check kind
 279         messages.add(f.apply("checkUnknown", List.of(-1, 0, 0)).getMessage());
 280         // Known check kind with more arguments
 281         messages.add(f.apply("checkIndex", List.of(-1, 0, 0)).getMessage());
 282         messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0, 0)).getMessage());
 283         messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0, 0)).getMessage());
 284         // Known check kind with fewer arguments
 285         messages.add(f.apply("checkIndex", List.of(-1)).getMessage());
 286         messages.add(f.apply("checkFromToIndex", List.of(-1, 0)).getMessage());
 287         messages.add(f.apply("checkFromIndexSize", List.of(-1, 0)).getMessage());
 288         // Null arguments
 289         messages.add(f.apply(null, null).getMessage());
 290         messages.add(f.apply("checkNullArguments", null).getMessage());
 291         messages.add(f.apply(null, List.of(-1)).getMessage());
 292 
 293         assertEquals(messages.size(), messages.stream().distinct().count());
 294     }
 295 }
--- EOF ---