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