CheckIndex.java revision 14158:e1d83a0973f6
1258945Sroberto/* 2280849Scy * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3258945Sroberto * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4258945Sroberto * 5258945Sroberto * This code is free software; you can redistribute it and/or modify it 6258945Sroberto * under the terms of the GNU General Public License version 2 only, as 7258945Sroberto * published by the Free Software Foundation. 8258945Sroberto * 9258945Sroberto * This code is distributed in the hope that it will be useful, but WITHOUT 10258945Sroberto * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11258945Sroberto * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12258945Sroberto * version 2 for more details (a copy is included in the LICENSE file that 13258945Sroberto * accompanied this code). 14258945Sroberto * 15258945Sroberto * You should have received a copy of the GNU General Public License version 16258945Sroberto * 2 along with this work; if not, write to the Free Software Foundation, 17258945Sroberto * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18280849Scy * 19258945Sroberto * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20258945Sroberto * or visit www.oracle.com if you need additional information or have any 21258945Sroberto * questions. 22258945Sroberto */ 23258945Sroberto 24258945Sroberto/** 25258945Sroberto * @test 26258945Sroberto * @summary IndexOutOfBoundsException check index tests 27258945Sroberto * @run testng CheckIndex 28258945Sroberto * @bug 8135248 8142493 29258945Sroberto */ 30258945Sroberto 31258945Srobertoimport org.testng.annotations.DataProvider; 32258945Srobertoimport org.testng.annotations.Test; 33258945Sroberto 34258945Srobertoimport java.util.ArrayList; 35258945Srobertoimport java.util.List; 36258945Srobertoimport java.util.Objects; 37258945Srobertoimport java.util.function.BiConsumer; 38258945Srobertoimport java.util.function.BiFunction; 39258945Srobertoimport java.util.function.IntSupplier; 40258945Sroberto 41258945Srobertoimport static org.testng.Assert.*; 42258945Sroberto 43258945Srobertopublic class CheckIndex { 44258945Sroberto 45258945Sroberto static class AssertingOutOfBoundsException extends RuntimeException { 46258945Sroberto public AssertingOutOfBoundsException(String message) { 47258945Sroberto super(message); 48258945Sroberto } 49258945Sroberto } 50258945Sroberto 51258945Sroberto static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBounds( 52258945Sroberto String message, String expCheckKind, Integer... expArgs) { 53258945Sroberto return (checkKind, args) -> { 54258945Sroberto assertEquals(checkKind, expCheckKind); 55258945Sroberto assertEquals(args, List.of(expArgs)); 56258945Sroberto try { 57258945Sroberto args.clear(); 58258945Sroberto fail("Out of bounds List<Integer> argument should be unmodifiable"); 59258945Sroberto } catch (Exception e) { 60258945Sroberto } 61258945Sroberto return new AssertingOutOfBoundsException(message); 62258945Sroberto }; 63258945Sroberto } 64258945Sroberto 65258945Sroberto static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull( 66258945Sroberto String expCheckKind, Integer... expArgs) { 67258945Sroberto return (checkKind, args) -> { 68258945Sroberto assertEquals(checkKind, expCheckKind); 69258945Sroberto assertEquals(args, List.of(expArgs)); 70258945Sroberto return null; 71258945Sroberto }; 72258945Sroberto } 73258945Sroberto 74258945Sroberto static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE}; 75258945Sroberto 76258945Sroberto @DataProvider 77258945Sroberto static Object[][] checkIndexProvider() { 78258945Sroberto List<Object[]> l = new ArrayList<>(); 79258945Sroberto for (int index : VALUES) { 80258945Sroberto for (int length : VALUES) { 81258945Sroberto boolean withinBounds = index >= 0 && 82258945Sroberto length >= 0 && 83258945Sroberto index < length; 84258945Sroberto l.add(new Object[]{index, length, withinBounds}); 85258945Sroberto } 86258945Sroberto } 87258945Sroberto return l.toArray(new Object[0][0]); 88258945Sroberto } 89258945Sroberto 90258945Sroberto interface X { 91258945Sroberto int apply(int a, int b, int c); 92258945Sroberto } 93258945Sroberto 94258945Sroberto @Test(dataProvider = "checkIndexProvider") 95258945Sroberto public void testCheckIndex(int index, int length, boolean withinBounds) { 96258945Sroberto String expectedMessage = withinBounds 97258945Sroberto ? null 98258945Sroberto : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). 99258945Sroberto apply("checkIndex", List.of(index, length)).getMessage(); 100258945Sroberto 101258945Sroberto BiConsumer<Class<? extends RuntimeException>, IntSupplier> checker = (ec, s) -> { 102258945Sroberto try { 103258945Sroberto int rIndex = s.getAsInt(); 104258945Sroberto if (!withinBounds) 105258945Sroberto fail(String.format( 106258945Sroberto "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length)); 107258945Sroberto assertEquals(rIndex, index); 108258945Sroberto } 109258945Sroberto catch (RuntimeException e) { 110258945Sroberto assertTrue(ec.isInstance(e)); 111258945Sroberto if (withinBounds) 112258945Sroberto fail(String.format( 113258945Sroberto "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length)); 114258945Sroberto else 115258945Sroberto assertEquals(e.getMessage(), expectedMessage); 116258945Sroberto } 117258945Sroberto }; 118258945Sroberto 119258945Sroberto checker.accept(AssertingOutOfBoundsException.class, 120258945Sroberto () -> Objects.checkIndex(index, length, 121258945Sroberto assertingOutOfBounds(expectedMessage, "checkIndex", index, length))); 122258945Sroberto checker.accept(IndexOutOfBoundsException.class, 123258945Sroberto () -> Objects.checkIndex(index, length, 124258945Sroberto assertingOutOfBoundsReturnNull("checkIndex", index, length))); 125258945Sroberto checker.accept(IndexOutOfBoundsException.class, 126258945Sroberto () -> Objects.checkIndex(index, length, null)); 127258945Sroberto checker.accept(IndexOutOfBoundsException.class, 128258945Sroberto () -> Objects.checkIndex(index, length)); 129258945Sroberto checker.accept(ArrayIndexOutOfBoundsException.class, 130258945Sroberto () -> Objects.checkIndex(index, length, 131258945Sroberto Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); 132258945Sroberto checker.accept(StringIndexOutOfBoundsException.class, 133258945Sroberto () -> Objects.checkIndex(index, length, 134258945Sroberto Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); 135258945Sroberto } 136258945Sroberto 137258945Sroberto 138258945Sroberto @DataProvider 139258945Sroberto static Object[][] checkFromToIndexProvider() { 140258945Sroberto List<Object[]> l = new ArrayList<>(); 141258945Sroberto for (int fromIndex : VALUES) { 142258945Sroberto for (int toIndex : VALUES) { 143258945Sroberto for (int length : VALUES) { 144258945Sroberto boolean withinBounds = fromIndex >= 0 && 145258945Sroberto toIndex >= 0 && 146258945Sroberto length >= 0 && 147258945Sroberto fromIndex <= toIndex && 148258945Sroberto toIndex <= length; 149280849Scy l.add(new Object[]{fromIndex, toIndex, length, withinBounds}); 150280849Scy } 151280849Scy } 152280849Scy } 153280849Scy return l.toArray(new Object[0][0]); 154258945Sroberto } 155258945Sroberto 156258945Sroberto @Test(dataProvider = "checkFromToIndexProvider") 157258945Sroberto public void testCheckFromToIndex(int fromIndex, int toIndex, int length, boolean withinBounds) { 158258945Sroberto String expectedMessage = withinBounds 159258945Sroberto ? null 160258945Sroberto : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). 161258945Sroberto apply("checkFromToIndex", List.of(fromIndex, toIndex, length)).getMessage(); 162258945Sroberto 163258945Sroberto BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> { 164258945Sroberto try { 165258945Sroberto int rIndex = s.getAsInt(); 166258945Sroberto if (!withinBounds) 167258945Sroberto fail(String.format( 168258945Sroberto "Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length)); 169258945Sroberto assertEquals(rIndex, fromIndex); 170258945Sroberto } 171258945Sroberto catch (RuntimeException e) { 172258945Sroberto assertTrue(ec.isInstance(e)); 173258945Sroberto if (withinBounds) 174258945Sroberto fail(String.format( 175258945Sroberto "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length)); 176258945Sroberto else 177258945Sroberto assertEquals(e.getMessage(), expectedMessage); 178258945Sroberto } 179258945Sroberto }; 180258945Sroberto 181258945Sroberto check.accept(AssertingOutOfBoundsException.class, 182258945Sroberto () -> Objects.checkFromToIndex(fromIndex, toIndex, length, 183258945Sroberto assertingOutOfBounds(expectedMessage, "checkFromToIndex", fromIndex, toIndex, length))); 184258945Sroberto check.accept(IndexOutOfBoundsException.class, 185258945Sroberto () -> Objects.checkFromToIndex(fromIndex, toIndex, length, 186258945Sroberto assertingOutOfBoundsReturnNull("checkFromToIndex", fromIndex, toIndex, length))); 187258945Sroberto check.accept(IndexOutOfBoundsException.class, 188258945Sroberto () -> Objects.checkFromToIndex(fromIndex, toIndex, length, null)); 189258945Sroberto check.accept(IndexOutOfBoundsException.class, 190258945Sroberto () -> Objects.checkFromToIndex(fromIndex, toIndex, length)); 191258945Sroberto check.accept(ArrayIndexOutOfBoundsException.class, 192258945Sroberto () -> Objects.checkFromToIndex(fromIndex, toIndex, length, 193258945Sroberto Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); 194258945Sroberto check.accept(StringIndexOutOfBoundsException.class, 195258945Sroberto () -> Objects.checkFromToIndex(fromIndex, toIndex, length, 196258945Sroberto Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); 197258945Sroberto } 198258945Sroberto 199258945Sroberto 200258945Sroberto @DataProvider 201258945Sroberto static Object[][] checkFromIndexSizeProvider() { 202258945Sroberto List<Object[]> l = new ArrayList<>(); 203258945Sroberto for (int fromIndex : VALUES) { 204258945Sroberto for (int size : VALUES) { 205258945Sroberto for (int length : VALUES) { 206258945Sroberto // Explicitly convert to long 207258945Sroberto long lFromIndex = fromIndex; 208258945Sroberto long lSize = size; 209258945Sroberto long lLength = length; 210258945Sroberto // Avoid overflow 211258945Sroberto long lToIndex = lFromIndex + lSize; 212258945Sroberto 213258945Sroberto boolean withinBounds = lFromIndex >= 0L && 214258945Sroberto lSize >= 0L && 215258945Sroberto lLength >= 0L && 216258945Sroberto lFromIndex <= lToIndex && 217258945Sroberto lToIndex <= lLength; 218258945Sroberto l.add(new Object[]{fromIndex, size, length, withinBounds}); 219258945Sroberto } 220258945Sroberto } 221258945Sroberto } 222258945Sroberto return l.toArray(new Object[0][0]); 223280849Scy } 224280849Scy 225280849Scy @Test(dataProvider = "checkFromIndexSizeProvider") 226280849Scy public void testCheckFromIndexSize(int fromIndex, int size, int length, boolean withinBounds) { 227280849Scy String expectedMessage = withinBounds 228280849Scy ? null 229280849Scy : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). 230280849Scy apply("checkFromIndexSize", List.of(fromIndex, size, length)).getMessage(); 231280849Scy 232280849Scy BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> { 233280849Scy try { 234280849Scy int rIndex = s.getAsInt(); 235258945Sroberto if (!withinBounds) 236258945Sroberto fail(String.format( 237258945Sroberto "Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length)); 238258945Sroberto assertEquals(rIndex, fromIndex); 239258945Sroberto } 240258945Sroberto catch (RuntimeException e) { 241258945Sroberto assertTrue(ec.isInstance(e)); 242258945Sroberto if (withinBounds) 243258945Sroberto fail(String.format( 244258945Sroberto "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length)); 245258945Sroberto else 246258945Sroberto assertEquals(e.getMessage(), expectedMessage); 247258945Sroberto } 248258945Sroberto }; 249258945Sroberto 250258945Sroberto check.accept(AssertingOutOfBoundsException.class, 251258945Sroberto () -> Objects.checkFromIndexSize(fromIndex, size, length, 252258945Sroberto assertingOutOfBounds(expectedMessage, "checkFromIndexSize", fromIndex, size, length))); 253258945Sroberto check.accept(IndexOutOfBoundsException.class, 254258945Sroberto () -> Objects.checkFromIndexSize(fromIndex, size, length, 255258945Sroberto assertingOutOfBoundsReturnNull("checkFromIndexSize", fromIndex, size, length))); 256258945Sroberto check.accept(IndexOutOfBoundsException.class, 257258945Sroberto () -> Objects.checkFromIndexSize(fromIndex, size, length, null)); 258258945Sroberto check.accept(IndexOutOfBoundsException.class, 259258945Sroberto () -> Objects.checkFromIndexSize(fromIndex, size, length)); 260258945Sroberto check.accept(ArrayIndexOutOfBoundsException.class, 261258945Sroberto () -> Objects.checkFromIndexSize(fromIndex, size, length, 262258945Sroberto Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); 263258945Sroberto check.accept(StringIndexOutOfBoundsException.class, 264258945Sroberto () -> Objects.checkFromIndexSize(fromIndex, size, length, 265258945Sroberto Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); 266258945Sroberto } 267258945Sroberto 268258945Sroberto @Test 269258945Sroberto public void uniqueMessagesForCheckKinds() { 270258945Sroberto BiFunction<String, List<Integer>, IndexOutOfBoundsException> f = 271258945Sroberto Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new); 272258945Sroberto 273258945Sroberto List<String> messages = new ArrayList<>(); 274258945Sroberto // Exact arguments 275258945Sroberto messages.add(f.apply("checkIndex", List.of(-1, 0)).getMessage()); 276258945Sroberto messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0)).getMessage()); 277258945Sroberto messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0)).getMessage()); 278258945Sroberto // Unknown check kind 279258945Sroberto messages.add(f.apply("checkUnknown", List.of(-1, 0, 0)).getMessage()); 280258945Sroberto // Known check kind with more arguments 281258945Sroberto messages.add(f.apply("checkIndex", List.of(-1, 0, 0)).getMessage()); 282258945Sroberto messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0, 0)).getMessage()); 283258945Sroberto messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0, 0)).getMessage()); 284258945Sroberto // Known check kind with fewer arguments 285258945Sroberto messages.add(f.apply("checkIndex", List.of(-1)).getMessage()); 286258945Sroberto messages.add(f.apply("checkFromToIndex", List.of(-1, 0)).getMessage()); 287258945Sroberto messages.add(f.apply("checkFromIndexSize", List.of(-1, 0)).getMessage()); 288258945Sroberto // Null arguments 289258945Sroberto messages.add(f.apply(null, null).getMessage()); 290258945Sroberto messages.add(f.apply("checkNullArguments", null).getMessage()); 291258945Sroberto messages.add(f.apply(null, List.of(-1)).getMessage()); 292258945Sroberto 293258945Sroberto assertEquals(messages.size(), messages.stream().distinct().count()); 294258945Sroberto } 295258945Sroberto} 296258945Sroberto