41 import static org.testng.Assert.*; |
41 import static org.testng.Assert.*; |
42 |
42 |
43 public class CheckIndex { |
43 public class CheckIndex { |
44 |
44 |
45 static class AssertingOutOfBoundsException extends RuntimeException { |
45 static class AssertingOutOfBoundsException extends RuntimeException { |
46 } |
46 public AssertingOutOfBoundsException(String message) { |
47 |
47 super(message); |
48 static BiFunction<Integer, Integer, AssertingOutOfBoundsException> assertingOutOfBounds( |
48 } |
49 int expFromIndex, int expToIndexOrSizeOrLength) { |
49 } |
50 return (fromIndex, toIndexOrSizeorLength) -> { |
50 |
51 assertEquals(fromIndex, Integer.valueOf(expFromIndex)); |
51 static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBounds( |
52 assertEquals(toIndexOrSizeorLength, Integer.valueOf(expToIndexOrSizeOrLength)); |
52 String message, String expCheckKind, Integer... expArgs) { |
53 return new AssertingOutOfBoundsException(); |
53 return (checkKind, args) -> { |
54 }; |
54 assertEquals(checkKind, expCheckKind); |
55 } |
55 assertEquals(args, List.of(expArgs)); |
56 |
56 try { |
57 static BiFunction<Integer, Integer, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull( |
57 args.clear(); |
58 int expFromIndex, int expToIndexOrSizeOrLength) { |
58 fail("Out of bounds List<Integer> argument should be unmodifiable"); |
59 return (fromIndex, toIndexOrSizeorLength) -> { |
59 } catch (Exception e) { |
60 assertEquals(fromIndex, Integer.valueOf(expFromIndex)); |
60 } |
61 assertEquals(toIndexOrSizeorLength, Integer.valueOf(expToIndexOrSizeOrLength)); |
61 return new AssertingOutOfBoundsException(message); |
|
62 }; |
|
63 } |
|
64 |
|
65 static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull( |
|
66 String expCheckKind, Integer... expArgs) { |
|
67 return (checkKind, args) -> { |
|
68 assertEquals(checkKind, expCheckKind); |
|
69 assertEquals(args, List.of(expArgs)); |
62 return null; |
70 return null; |
63 }; |
71 }; |
64 } |
72 } |
65 |
73 |
66 static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE}; |
74 static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE}; |
83 int apply(int a, int b, int c); |
91 int apply(int a, int b, int c); |
84 } |
92 } |
85 |
93 |
86 @Test(dataProvider = "checkIndexProvider") |
94 @Test(dataProvider = "checkIndexProvider") |
87 public void testCheckIndex(int index, int length, boolean withinBounds) { |
95 public void testCheckIndex(int index, int length, boolean withinBounds) { |
88 BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> { |
96 String expectedMessage = withinBounds |
|
97 ? null |
|
98 : Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). |
|
99 apply("checkIndex", List.of(index, length)).getMessage(); |
|
100 |
|
101 BiConsumer<Class<? extends RuntimeException>, IntSupplier> checker = (ec, s) -> { |
89 try { |
102 try { |
90 int rIndex = s.getAsInt(); |
103 int rIndex = s.getAsInt(); |
91 if (!withinBounds) |
104 if (!withinBounds) |
92 fail(String.format( |
105 fail(String.format( |
93 "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length)); |
106 "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length)); |
96 catch (RuntimeException e) { |
109 catch (RuntimeException e) { |
97 assertTrue(ec.isInstance(e)); |
110 assertTrue(ec.isInstance(e)); |
98 if (withinBounds) |
111 if (withinBounds) |
99 fail(String.format( |
112 fail(String.format( |
100 "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length)); |
113 "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length)); |
101 } |
114 else |
102 }; |
115 assertEquals(e.getMessage(), expectedMessage); |
103 |
116 } |
104 check.accept(AssertingOutOfBoundsException.class, |
117 }; |
105 () -> Objects.checkIndex(index, length, assertingOutOfBounds(index, length))); |
118 |
106 check.accept(IndexOutOfBoundsException.class, |
119 checker.accept(AssertingOutOfBoundsException.class, |
107 () -> Objects.checkIndex(index, length, assertingOutOfBoundsReturnNull(index, length))); |
120 () -> Objects.checkIndex(index, length, |
108 check.accept(IndexOutOfBoundsException.class, |
121 assertingOutOfBounds(expectedMessage, "checkIndex", index, length))); |
|
122 checker.accept(IndexOutOfBoundsException.class, |
|
123 () -> Objects.checkIndex(index, length, |
|
124 assertingOutOfBoundsReturnNull("checkIndex", index, length))); |
|
125 checker.accept(IndexOutOfBoundsException.class, |
109 () -> Objects.checkIndex(index, length, null)); |
126 () -> Objects.checkIndex(index, length, null)); |
110 check.accept(IndexOutOfBoundsException.class, |
127 checker.accept(IndexOutOfBoundsException.class, |
111 () -> Objects.checkIndex(index, length)); |
128 () -> Objects.checkIndex(index, length)); |
|
129 checker.accept(ArrayIndexOutOfBoundsException.class, |
|
130 () -> Objects.checkIndex(index, length, |
|
131 Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); |
|
132 checker.accept(StringIndexOutOfBoundsException.class, |
|
133 () -> Objects.checkIndex(index, length, |
|
134 Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); |
112 } |
135 } |
113 |
136 |
114 |
137 |
115 @DataProvider |
138 @DataProvider |
116 static Object[][] checkFromToIndexProvider() { |
139 static Object[][] checkFromToIndexProvider() { |
143 catch (RuntimeException e) { |
171 catch (RuntimeException e) { |
144 assertTrue(ec.isInstance(e)); |
172 assertTrue(ec.isInstance(e)); |
145 if (withinBounds) |
173 if (withinBounds) |
146 fail(String.format( |
174 fail(String.format( |
147 "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length)); |
175 "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length)); |
|
176 else |
|
177 assertEquals(e.getMessage(), expectedMessage); |
148 } |
178 } |
149 }; |
179 }; |
150 |
180 |
151 check.accept(AssertingOutOfBoundsException.class, |
181 check.accept(AssertingOutOfBoundsException.class, |
152 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, assertingOutOfBounds(fromIndex, toIndex))); |
182 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, |
153 check.accept(IndexOutOfBoundsException.class, |
183 assertingOutOfBounds(expectedMessage, "checkFromToIndex", fromIndex, toIndex, length))); |
154 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, assertingOutOfBoundsReturnNull(fromIndex, toIndex))); |
184 check.accept(IndexOutOfBoundsException.class, |
|
185 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, |
|
186 assertingOutOfBoundsReturnNull("checkFromToIndex", fromIndex, toIndex, length))); |
155 check.accept(IndexOutOfBoundsException.class, |
187 check.accept(IndexOutOfBoundsException.class, |
156 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, null)); |
188 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, null)); |
157 check.accept(IndexOutOfBoundsException.class, |
189 check.accept(IndexOutOfBoundsException.class, |
158 () -> Objects.checkFromToIndex(fromIndex, toIndex, length)); |
190 () -> Objects.checkFromToIndex(fromIndex, toIndex, length)); |
|
191 check.accept(ArrayIndexOutOfBoundsException.class, |
|
192 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, |
|
193 Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); |
|
194 check.accept(StringIndexOutOfBoundsException.class, |
|
195 () -> Objects.checkFromToIndex(fromIndex, toIndex, length, |
|
196 Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); |
159 } |
197 } |
160 |
198 |
161 |
199 |
162 @DataProvider |
200 @DataProvider |
163 static Object[][] checkFromIndexSizeProvider() { |
201 static Object[][] checkFromIndexSizeProvider() { |
197 catch (RuntimeException e) { |
240 catch (RuntimeException e) { |
198 assertTrue(ec.isInstance(e)); |
241 assertTrue(ec.isInstance(e)); |
199 if (withinBounds) |
242 if (withinBounds) |
200 fail(String.format( |
243 fail(String.format( |
201 "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length)); |
244 "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length)); |
|
245 else |
|
246 assertEquals(e.getMessage(), expectedMessage); |
202 } |
247 } |
203 }; |
248 }; |
204 |
249 |
205 check.accept(AssertingOutOfBoundsException.class, |
250 check.accept(AssertingOutOfBoundsException.class, |
206 () -> Objects.checkFromIndexSize(fromIndex, size, length, assertingOutOfBounds(fromIndex, size))); |
251 () -> Objects.checkFromIndexSize(fromIndex, size, length, |
207 check.accept(IndexOutOfBoundsException.class, |
252 assertingOutOfBounds(expectedMessage, "checkFromIndexSize", fromIndex, size, length))); |
208 () -> Objects.checkFromIndexSize(fromIndex, size, length, assertingOutOfBoundsReturnNull(fromIndex, size))); |
253 check.accept(IndexOutOfBoundsException.class, |
|
254 () -> Objects.checkFromIndexSize(fromIndex, size, length, |
|
255 assertingOutOfBoundsReturnNull("checkFromIndexSize", fromIndex, size, length))); |
209 check.accept(IndexOutOfBoundsException.class, |
256 check.accept(IndexOutOfBoundsException.class, |
210 () -> Objects.checkFromIndexSize(fromIndex, size, length, null)); |
257 () -> Objects.checkFromIndexSize(fromIndex, size, length, null)); |
211 check.accept(IndexOutOfBoundsException.class, |
258 check.accept(IndexOutOfBoundsException.class, |
212 () -> Objects.checkFromIndexSize(fromIndex, size, length)); |
259 () -> Objects.checkFromIndexSize(fromIndex, size, length)); |
|
260 check.accept(ArrayIndexOutOfBoundsException.class, |
|
261 () -> Objects.checkFromIndexSize(fromIndex, size, length, |
|
262 Objects.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); |
|
263 check.accept(StringIndexOutOfBoundsException.class, |
|
264 () -> Objects.checkFromIndexSize(fromIndex, size, length, |
|
265 Objects.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); |
213 } |
266 } |
214 |
267 |
215 @Test |
268 @Test |
216 public void checkIndexOutOfBoundsExceptionConstructors() { |
269 public void uniqueMessagesForCheckKinds() { |
217 BiConsumer<Class<? extends RuntimeException>, IntSupplier> check = (ec, s) -> { |
270 BiFunction<String, List<Integer>, IndexOutOfBoundsException> f = |
218 try { |
271 Objects.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new); |
219 s.getAsInt(); |
272 |
220 fail("Runtime exception expected"); |
273 List<String> messages = new ArrayList<>(); |
221 } |
274 // Exact arguments |
222 catch (RuntimeException e) { |
275 messages.add(f.apply("checkIndex", List.of(-1, 0)).getMessage()); |
223 assertTrue(ec.isInstance(e)); |
276 messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0)).getMessage()); |
224 } |
277 messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0)).getMessage()); |
225 }; |
278 // Unknown check kind |
226 |
279 messages.add(f.apply("checkUnknown", List.of(-1, 0, 0)).getMessage()); |
227 check.accept(IndexOutOfBoundsException.class, |
280 // Known check kind with more arguments |
228 () -> Objects.checkIndex(1, 0, IndexOutOfBoundsException::new)); |
281 messages.add(f.apply("checkIndex", List.of(-1, 0, 0)).getMessage()); |
229 check.accept(StringIndexOutOfBoundsException.class, |
282 messages.add(f.apply("checkFromToIndex", List.of(-1, 0, 0, 0)).getMessage()); |
230 () -> Objects.checkIndex(1, 0, StringIndexOutOfBoundsException::new)); |
283 messages.add(f.apply("checkFromIndexSize", List.of(-1, 0, 0, 0)).getMessage()); |
231 check.accept(ArrayIndexOutOfBoundsException.class, |
284 // Known check kind with fewer arguments |
232 () -> Objects.checkIndex(1, 0, ArrayIndexOutOfBoundsException::new)); |
285 messages.add(f.apply("checkIndex", List.of(-1)).getMessage()); |
|
286 messages.add(f.apply("checkFromToIndex", List.of(-1, 0)).getMessage()); |
|
287 messages.add(f.apply("checkFromIndexSize", List.of(-1, 0)).getMessage()); |
|
288 // Null arguments |
|
289 messages.add(f.apply(null, null).getMessage()); |
|
290 messages.add(f.apply("checkNullArguments", null).getMessage()); |
|
291 messages.add(f.apply(null, List.of(-1)).getMessage()); |
|
292 |
|
293 assertEquals(messages.size(), messages.stream().distinct().count()); |
233 } |
294 } |
234 } |
295 } |