CheckIndex.java revision 15491:6f390eafc676
138032Speter/* 238032Speter * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 338032Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 438032Speter * 538032Speter * This code is free software; you can redistribute it and/or modify it 638032Speter * under the terms of the GNU General Public License version 2 only, as 738032Speter * published by the Free Software Foundation. 838032Speter * 938032Speter * This code is distributed in the hope that it will be useful, but WITHOUT 1038032Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1138032Speter * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1238032Speter * version 2 for more details (a copy is included in the LICENSE file that 1338032Speter * accompanied this code). 1438032Speter * 1538032Speter * You should have received a copy of the GNU General Public License version 1638032Speter * 2 along with this work; if not, write to the Free Software Foundation, 1738032Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1838032Speter * 1938032Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2038032Speter * or visit www.oracle.com if you need additional information or have any 2138032Speter * questions. 2238032Speter */ 2338032Speter 2438032Speter/** 2538032Speter * @test 2638032Speter * @summary Objects.checkIndex/jdk.internal.util.Preconditions.checkIndex tests 2738032Speter * @run testng CheckIndex 2838032Speter * @bug 8135248 8142493 8155794 2938032Speter * @modules java.base/jdk.internal.util 3038032Speter */ 3138032Speter 3238032Speterimport jdk.internal.util.Preconditions; 3338032Speterimport org.testng.annotations.DataProvider; 3438032Speterimport org.testng.annotations.Test; 3538032Speter 3638032Speterimport java.util.ArrayList; 3738032Speterimport java.util.List; 38266692Sgshapiroimport java.util.Objects; 3938032Speterimport java.util.function.BiConsumer; 4038032Speterimport java.util.function.BiFunction; 4138032Speterimport java.util.function.IntSupplier; 4238032Speter 4338032Speterimport static org.testng.Assert.*; 4438032Speter 4538032Speterpublic class CheckIndex { 4638032Speter 4738032Speter static class AssertingOutOfBoundsException extends RuntimeException { 4838032Speter public AssertingOutOfBoundsException(String message) { 4938032Speter super(message); 5038032Speter } 5138032Speter } 5238032Speter 5338032Speter static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBounds( 5438032Speter String message, String expCheckKind, Integer... expArgs) { 5538032Speter return (checkKind, args) -> { 5638032Speter assertEquals(checkKind, expCheckKind); 5738032Speter assertEquals(args, List.of(expArgs)); 5838032Speter try { 5938032Speter args.clear(); 6038032Speter fail("Out of bounds List<Integer> argument should be unmodifiable"); 6138032Speter } catch (Exception e) { 6238032Speter } 6338032Speter return new AssertingOutOfBoundsException(message); 6438032Speter }; 6538032Speter } 6638032Speter 6738032Speter static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull( 6838032Speter String expCheckKind, Integer... expArgs) { 6938032Speter return (checkKind, args) -> { 7038032Speter assertEquals(checkKind, expCheckKind); 7138032Speter assertEquals(args, List.of(expArgs)); 7238032Speter return null; 7338032Speter }; 7438032Speter } 7538032Speter 7638032Speter static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE}; 7738032Speter 7838032Speter @DataProvider 7938032Speter static Object[][] checkIndexProvider() { 8038032Speter List<Object[]> l = new ArrayList<>(); 8138032Speter for (int index : VALUES) { 8238032Speter for (int length : VALUES) { 8338032Speter boolean withinBounds = index >= 0 && 8438032Speter length >= 0 && 8538032Speter index < length; 8638032Speter l.add(new Object[]{index, length, withinBounds}); 8738032Speter } 8838032Speter } 8938032Speter return l.toArray(new Object[0][0]); 9038032Speter } 9138032Speter 9238032Speter interface X { 9338032Speter int apply(int a, int b, int c); 9438032Speter } 9538032Speter 9638032Speter @Test(dataProvider = "checkIndexProvider") 9738032Speter public void testCheckIndex(int index, int length, boolean withinBounds) { 9838032Speter String expectedMessage = withinBounds 9938032Speter ? null 10038032Speter : Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). 10138032Speter apply("checkIndex", List.of(index, length)).getMessage(); 10238032Speter 10338032Speter BiConsumer<Class<? extends RuntimeException>, IntSupplier> checker = (ec, s) -> { 10438032Speter try { 10538032Speter int rIndex = s.getAsInt(); 10638032Speter if (!withinBounds) 10738032Speter fail(String.format( 10838032Speter "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length)); 10938032Speter assertEquals(rIndex, index); 11038032Speter } 11138032Speter catch (RuntimeException e) { 11238032Speter assertTrue(ec.isInstance(e)); 11338032Speter if (withinBounds) 11438032Speter fail(String.format( 11538032Speter "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length)); 11638032Speter else 11738032Speter assertEquals(e.getMessage(), expectedMessage); 11838032Speter } 11938032Speter }; 12038032Speter 12138032Speter checker.accept(AssertingOutOfBoundsException.class, 12238032Speter () -> Preconditions.checkIndex(index, length, 12338032Speter assertingOutOfBounds(expectedMessage, "checkIndex", index, length))); 12438032Speter checker.accept(IndexOutOfBoundsException.class, 12538032Speter () -> Preconditions.checkIndex(index, length, 12638032Speter assertingOutOfBoundsReturnNull("checkIndex", index, length))); 12738032Speter checker.accept(IndexOutOfBoundsException.class, 12838032Speter () -> Preconditions.checkIndex(index, length, null)); 12938032Speter checker.accept(IndexOutOfBoundsException.class, 13038032Speter () -> Objects.checkIndex(index, length)); 13138032Speter checker.accept(ArrayIndexOutOfBoundsException.class, 13238032Speter () -> Preconditions.checkIndex(index, length, 13338032Speter Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); 13438032Speter checker.accept(StringIndexOutOfBoundsException.class, 13538032Speter () -> Preconditions.checkIndex(index, length, 13638032Speter Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); 13738032Speter } 13838032Speter 13938032Speter 14038032Speter @DataProvider 14138032Speter static Object[][] checkFromToIndexProvider() { 14238032Speter List<Object[]> l = new ArrayList<>(); 14338032Speter for (int fromIndex : VALUES) { 14438032Speter for (int toIndex : VALUES) { 14538032Speter for (int length : VALUES) { 14638032Speter boolean withinBounds = fromIndex >= 0 && 14738032Speter toIndex >= 0 && 14838032Speter length >= 0 && 14938032Speter fromIndex <= toIndex && 15038032Speter toIndex <= length; 15138032Speter l.add(new Object[]{fromIndex, toIndex, length, withinBounds}); 15238032Speter } 15338032Speter } 15438032Speter } 15538032Speter return l.toArray(new Object[0][0]); 15638032Speter } 15738032Speter 15838032Speter @Test(dataProvider = "checkFromToIndexProvider") 15938032Speter public void testCheckFromToIndex(int fromIndex, int toIndex, int length, boolean withinBounds) { 16038032Speter String expectedMessage = withinBounds 16138032Speter ? null 16238032Speter : Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). 16338032Speter apply("checkFromToIndex", List.of(fromIndex, toIndex, length)).getMessage(); 16438032Speter 16538032Speter BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> { 16638032Speter try { 16738032Speter int rIndex = s.getAsInt(); 16838032Speter if (!withinBounds) 16938032Speter fail(String.format( 17038032Speter "Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length)); 17138032Speter assertEquals(rIndex, fromIndex); 17238032Speter } 17338032Speter catch (RuntimeException e) { 17438032Speter assertTrue(ec.isInstance(e)); 17538032Speter if (withinBounds) 17638032Speter fail(String.format( 17738032Speter "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length)); 17838032Speter else 17938032Speter assertEquals(e.getMessage(), expectedMessage); 18038032Speter } 18138032Speter }; 18238032Speter 18338032Speter check.accept(AssertingOutOfBoundsException.class, 18438032Speter () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, 18538032Speter assertingOutOfBounds(expectedMessage, "checkFromToIndex", fromIndex, toIndex, length))); 18638032Speter check.accept(IndexOutOfBoundsException.class, 18738032Speter () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, 18838032Speter assertingOutOfBoundsReturnNull("checkFromToIndex", fromIndex, toIndex, length))); 18938032Speter check.accept(IndexOutOfBoundsException.class, 19038032Speter () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, null)); 19138032Speter check.accept(IndexOutOfBoundsException.class, 192 () -> Objects.checkFromToIndex(fromIndex, toIndex, length)); 193 check.accept(ArrayIndexOutOfBoundsException.class, 194 () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, 195 Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); 196 check.accept(StringIndexOutOfBoundsException.class, 197 () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, 198 Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); 199 } 200 201 202 @DataProvider 203 static Object[][] checkFromIndexSizeProvider() { 204 List<Object[]> l = new ArrayList<>(); 205 for (int fromIndex : VALUES) { 206 for (int size : VALUES) { 207 for (int length : VALUES) { 208 // Explicitly convert to long 209 long lFromIndex = fromIndex; 210 long lSize = size; 211 long lLength = length; 212 // Avoid overflow 213 long lToIndex = lFromIndex + lSize; 214 215 boolean withinBounds = lFromIndex >= 0L && 216 lSize >= 0L && 217 lLength >= 0L && 218 lFromIndex <= lToIndex && 219 lToIndex <= lLength; 220 l.add(new Object[]{fromIndex, size, length, withinBounds}); 221 } 222 } 223 } 224 return l.toArray(new Object[0][0]); 225 } 226 227 @Test(dataProvider = "checkFromIndexSizeProvider") 228 public void testCheckFromIndexSize(int fromIndex, int size, int length, boolean withinBounds) { 229 String expectedMessage = withinBounds 230 ? null 231 : Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). 232 apply("checkFromIndexSize", List.of(fromIndex, size, length)).getMessage(); 233 234 BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> { 235 try { 236 int rIndex = s.getAsInt(); 237 if (!withinBounds) 238 fail(String.format( 239 "Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length)); 240 assertEquals(rIndex, fromIndex); 241 } 242 catch (RuntimeException e) { 243 assertTrue(ec.isInstance(e)); 244 if (withinBounds) 245 fail(String.format( 246 "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length)); 247 else 248 assertEquals(e.getMessage(), expectedMessage); 249 } 250 }; 251 252 check.accept(AssertingOutOfBoundsException.class, 253 () -> Preconditions.checkFromIndexSize(fromIndex, size, length, 254 assertingOutOfBounds(expectedMessage, "checkFromIndexSize", fromIndex, size, length))); 255 check.accept(IndexOutOfBoundsException.class, 256 () -> Preconditions.checkFromIndexSize(fromIndex, size, length, 257 assertingOutOfBoundsReturnNull("checkFromIndexSize", fromIndex, size, length))); 258 check.accept(IndexOutOfBoundsException.class, 259 () -> Preconditions.checkFromIndexSize(fromIndex, size, length, null)); 260 check.accept(IndexOutOfBoundsException.class, 261 () -> Objects.checkFromIndexSize(fromIndex, size, length)); 262 check.accept(ArrayIndexOutOfBoundsException.class, 263 () -> Preconditions.checkFromIndexSize(fromIndex, size, length, 264 Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); 265 check.accept(StringIndexOutOfBoundsException.class, 266 () -> Preconditions.checkFromIndexSize(fromIndex, size, length, 267 Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); 268 } 269 270 @Test 271 public void uniqueMessagesForCheckKinds() { 272 BiFunction<String, List<Integer>, IndexOutOfBoundsException> f = 273 Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new); 274 275 List<String> messages = new ArrayList<>(); 276 // Exact arguments 277 messages.add(f.apply("checkIndex", List.of(-1, 0)).getMessage()); 278 messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0)).getMessage()); 279 messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0)).getMessage()); 280 // Unknown check kind 281 messages.add(f.apply("checkUnknown", List.of(-1, 0, 0)).getMessage()); 282 // Known check kind with more arguments 283 messages.add(f.apply("checkIndex", List.of(-1, 0, 0)).getMessage()); 284 messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0, 0)).getMessage()); 285 messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0, 0)).getMessage()); 286 // Known check kind with fewer arguments 287 messages.add(f.apply("checkIndex", List.of(-1)).getMessage()); 288 messages.add(f.apply("checkFromToIndex", List.of(-1, 0)).getMessage()); 289 messages.add(f.apply("checkFromIndexSize", List.of(-1, 0)).getMessage()); 290 // Null arguments 291 messages.add(f.apply(null, null).getMessage()); 292 messages.add(f.apply("checkNullArguments", null).getMessage()); 293 messages.add(f.apply(null, List.of(-1)).getMessage()); 294 295 assertEquals(messages.size(), messages.stream().distinct().count()); 296 } 297} 298