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