1 package org.djutils.test;
2
3 /**
4 * UnitTest has the methods to do a testFail(..) method for a unit test.
5 * <p>
6 * Copyright (c) 2024-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
7 * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
8 * distributed under a three-clause BSD-style license, which can be found at
9 * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
10 * </p>
11 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
12 * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
13 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
14 */
15 public final class UnitTest
16 {
17 /** private constructor for utility class. */
18 private UnitTest()
19 {
20 // utility class
21 }
22
23 /**
24 * Method for unit tests to test if an expected exception is thrown on an assignment. This method does not provide an
25 * explanation, and it is not checking for a specific type of exception to be thrown. The testFail() method throws an
26 * AssertionError when the assignment does not throw any exception. A way to use the method is, for instance: <br>
27 *
28 * <pre>
29 * <code>
30 * UnitTest.testFail(() -> methodFailsOnNull(null));
31 * </code>
32 * </pre>
33 *
34 * or
35 *
36 * <pre><code>
37 * UnitTest.testFail(new Try.Assignment<Double>()
38 * {
39 * {@literal @}Override
40 * public Double assign() throws Throwable
41 * {
42 * return methodFailsOnNull(null);
43 * }
44 * });
45 * </code></pre>
46 *
47 * @param assignment functional interface to assign value
48 * @param <V> value type, which is the return type of the assignment
49 * @return assigned value
50 * @throws AssertionError when the assignment fails to throw an exception
51 */
52 public static <V> V testFail(final Assignment<V> assignment)
53 {
54 return testFail(assignment, null, Throwable.class);
55 }
56
57 /**
58 * Method for unit tests to test if an expected exception is thrown on an assignment. This method provides an explanation
59 * message, but it is not checking for a specific type of exception to be thrown. The testFail() method throws an
60 * AssertionError when the assignment does not throw an exception. A way to use the method is, for instance: <br>
61 *
62 * <pre>
63 * <code>
64 * UnitTest.testFail(() -> methodFailsOnNull(null), "call should have thrown an NPE");
65 * </code>
66 * </pre>
67 *
68 * or
69 *
70 * <pre><code>
71 * UnitTest.testFail(new Try.Assignment<Double>()
72 * {
73 * {@literal @}Override
74 * public Double assign() throws Throwable
75 * {
76 * return methodFailsOnNull(null);
77 * }
78 * }, "call should have thrown an NPE");
79 * </code></pre>
80 *
81 * @param assignment functional interface to assign value
82 * @param <V> value type, which is the return type of the assignment
83 * @param message message to use in the AssertionError when the assignment succeeds
84 * @return assigned value
85 * @throws AssertionError when the assignment fails to throw an exception
86 */
87 public static <V> V testFail(final Assignment<V> assignment, final String message)
88 {
89 return testFail(assignment, message, Throwable.class);
90 }
91
92 /**
93 * Method for unit tests to test if an expected exception is thrown on an assignment. This method does not provide an
94 * explanation, but it is checking for a specific type of exception to be thrown. The testFail() method throws an
95 * AssertionError when the assignment does not throw an exception, or when it throws a different exception than
96 * expectedThrowableClass. A way to use the method is, for instance: <br>
97 *
98 * <pre>
99 * <code>
100 * UnitTest.testFail(() -> methodFailsOnNull(null), NullPointerException.class);
101 * </code>
102 * </pre>
103 *
104 * or
105 *
106 * <pre><code>
107 * UnitTest.testFail(new Try.Assignment<Double>()
108 * {
109 * {@literal @}Override
110 * public Double assign() throws Throwable
111 * {
112 * return methodFailsOnNull(null);
113 * }
114 * }, NullPointerException.class);
115 * </code></pre>
116 *
117 * @param assignment functional interface to assign value
118 * @param expectedThrowableClass the class of the exception we expect the assignment to throw
119 * @param <V> value type, which is the return type of the assignment
120 * @param <T> throwable type, which ensures that we provide a throwable class as the argument
121 * @return assigned value
122 * @throws AssertionError when the assignment fails to throw an exception or the correct exception
123 */
124 public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final Class<T> expectedThrowableClass)
125 {
126 return testFail(assignment, null, expectedThrowableClass);
127 }
128
129 /**
130 * Method for unit tests to test if an expected exception is thrown on an assignment. This method provides an explanation
131 * message, and it is checking for a specific type of exception to be thrown. The testFail() method throws an AssertionError
132 * when the assignment does not throw an exception, or when it throws a different exception than expectedThrowableClass. A
133 * way to use the method is, for instance: <br>
134 *
135 * <pre>
136 * <code>
137 * UnitTest.testFail(() -> methodFailsOnNull(null), "call should have thrown an NPE", NullPointerException.class);
138 * </code>
139 * </pre>
140 *
141 * or
142 *
143 * <pre><code>
144 * UnitTest.testFail(new Try.Assignment<Double>()
145 * {
146 * {@literal @}Override
147 * public Double assign() throws Throwable
148 * {
149 * return methodFailsOnNull(null);
150 * }
151 * }, "call should have thrown an NPE", NullPointerException.class);
152 * </code></pre>
153 *
154 * @param assignment functional interface to assign value
155 * @param message message to use in the AssertionError when the test fails
156 * @param expectedThrowableClass the class of the exception we expect the assignment to throw
157 * @param <V> value type, which is the return type of the assignment
158 * @param <T> throwable type, which ensures that we provide a throwable class as the argument
159 * @return assigned value
160 */
161 public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final String message,
162 final Class<T> expectedThrowableClass)
163 {
164 try
165 {
166 assignment.assign();
167 }
168 catch (Throwable cause)
169 {
170 if (!expectedThrowableClass.isAssignableFrom(cause.getClass()))
171 {
172 throw new AssertionError(message + "; Assignment failed on unexpected Throwable, expected ("
173 + expectedThrowableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
174 }
175 return null;
176 }
177 throw new AssertionError(message + "; Assignment did not throw any exception");
178 }
179
180 /**
181 * Method for unit tests to test if an expected exception is thrown on code execution. This method does not provide an
182 * explanation message, nor is it checking for a specific type of exception to be thrown. The testFail() method throws an
183 * AssertionError when the execution does not throw an exception. A way to use the method is, for instance: <br>
184 *
185 * <pre>
186 * <code>
187 * UnitTest.testFail(() -> methodFailsOnNull(null));
188 * </code>
189 * </pre>
190 *
191 * or
192 *
193 * <pre><code>
194 * UnitTest.testFail(new Try.Execution()
195 * {
196 * {@literal @}Override
197 * public void execute() throws Throwable
198 * {
199 * methodFailsOnNull(null);
200 * }
201 * });
202 * </code></pre>
203 *
204 * @param execution functional interface to execute a method that does not need to return a value
205 */
206 public static void testFail(final Execution execution)
207 {
208 testFail(execution, null, Throwable.class);
209 }
210
211 /**
212 * Method for unit tests to test if an expected exception is thrown on code execution. This method provides an explanation
213 * message, but it is not checking for a specific type of exception to be thrown. The testFail() method throws an
214 * AssertionError when the execution does not throw an exception, or when it throws a different exception than
215 * expectedThrowableClass. A way to use the method is, for instance: <br>
216 *
217 * <pre>
218 * <code>
219 * UnitTest.testFail(() -> methodFailsOnNull(null), "call should have thrown an NPE");
220 * </code>
221 * </pre>
222 *
223 * or
224 *
225 * <pre><code>
226 * UnitTest.testFail(new Try.Execution()
227 * {
228 * {@literal @}Override
229 * public void execute() throws Throwable
230 * {
231 * methodFailsOnNull(null);
232 * }
233 * }, "call should have thrown an NPE");
234 * </code></pre>
235 *
236 * @param execution functional interface to execute a method that does not need to return a value
237 * @param message message to use in the AssertionError when the test fails
238 */
239 public static void testFail(final Execution execution, final String message)
240 {
241 testFail(execution, message, Throwable.class);
242 }
243
244 /**
245 * Method for unit tests to test if an expected exception is thrown on code execution. This method does not provide an
246 * explanation message, but it is checking for a specific type of exception to be thrown. The testFail() method throws an
247 * AssertionError when the execution does not throw an exception, or when it throws a different exception than
248 * expectedThrowableClass. A way to use the method is, for instance: <br>
249 *
250 * <pre>
251 * <code>
252 * UnitTest.testFail(() -> methodFailsOnNull(null), NullPointerException.class);
253 * </code>
254 * </pre>
255 *
256 * or
257 *
258 * <pre><code>
259 * UnitTest.testFail(new Try.Execution()
260 * {
261 * {@literal @}Override
262 * public void execute() throws Throwable
263 * {
264 * methodFailsOnNull(null);
265 * }
266 * }, NullPointerException.class);
267 * </code></pre>
268 *
269 * @param execution functional interface to execute a method that does not need to return a value
270 * @param expectedThrowableClass the class of the exception we expect the execution to throw
271 * @param <T> throwable type, which ensures that we provide a throwable class as the argument
272 */
273 public static <T extends Throwable> void testFail(final Execution execution, final Class<T> expectedThrowableClass)
274 {
275 testFail(execution, null, expectedThrowableClass);
276 }
277
278 /**
279 * Method for unit tests to test if an expected exception is thrown on code execution. This method provides an explanation
280 * message, and it is checking for a specific type of exception to be thrown. The testFail() method throws an AssertionError
281 * when the execution does not throw an exception, or when it throws a different exception than expectedThrowableClass. A
282 * way to use the method is, for instance: <br>
283 *
284 * <pre>
285 * <code>
286 * UnitTest.testFail(() -> methodFailsOnNull(null), "call should have thrown an NPE", NullPointerException.class);
287 * </code>
288 * </pre>
289 *
290 * or
291 *
292 * <pre><code>
293 * UnitTest.testFail(new Try.Execution()
294 * {
295 * {@literal @}Override
296 * public void execute() throws Throwable
297 * {
298 * methodFailsOnNull(null);
299 * }
300 * }, "call should have thrown an NPE", NullPointerException.class);
301 * </code></pre>
302 *
303 * @param execution functional interface to execute a method that does not need to return a value
304 * @param message message to use in the AssertionError when the test fails
305 * @param expectedThrowableClass the class of the exception we expect the execution to throw
306 * @param <T> throwable type, which ensures that we provide a throwable class as the argument
307 */
308 public static <T extends Throwable> void testFail(final Execution execution, final String message,
309 final Class<T> expectedThrowableClass)
310 {
311 try
312 {
313 execution.execute();
314 }
315 catch (Throwable cause)
316 {
317 if (!expectedThrowableClass.isAssignableFrom(cause.getClass()))
318 {
319 throw new AssertionError(message + "; Execution failed on unexpected Throwable, expected ("
320 + expectedThrowableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
321 }
322 // expected to fail
323 return;
324 }
325 throw new AssertionError(message + "; Execution did not throw any exception");
326 }
327
328 // Interfaces
329
330 /**
331 * Functional interface for calls to Try.assign(...). For this a lambda expression can be used.
332 *
333 * <pre>
334 * FileInputStream fis = Try.assign(() -> new FileInputStream(fileString), IllegalArgumentException.class,
335 * "File %s is not a valid file.", fileString);
336 * </pre>
337 * <p>
338 * Copyright (c) 2013-2025 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
339 * <br>
340 * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
341 * </p>
342 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
343 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
344 * @param <V> value type
345 */
346 @FunctionalInterface
347 public interface Assignment<V>
348 {
349 /**
350 * Returns a value which is obtained from the context in which the Assignment was created.
351 * @return value which is obtained from the context in which the Assignment was created
352 * @throws Throwable on any throwable in the try
353 */
354 V assign() throws Throwable;
355 }
356
357 /**
358 * Functional interface for calls to Try.execute(...). For this a lambda expression can be used.
359 *
360 * <pre>
361 * Try.execute(() -> fis.close(), "Could not close the file.");
362 * </pre>
363 * <p>
364 * Copyright (c) 2013-2025 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
365 * <br>
366 * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
367 * </p>
368 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
369 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
370 */
371 @FunctionalInterface
372 public interface Execution
373 {
374 /**
375 * Executes some code using the context in which the Execution was created.
376 * @throws Throwable on any throwable in the try
377 */
378 void execute() throws Throwable;
379 }
380
381 }