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