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 }