
commonMain.io.kotest.assertions.throwables.StrictThrowableHandling.kt Maven / Gradle / Ivy
package io.kotest.assertions.throwables
import io.kotest.assertions.AssertionCounter
import io.kotest.assertions.failure
import io.kotest.mpp.bestName
/**
* Verifies that a block of code throws a Throwable of type [T], not including subclasses of [T]
*
* Use this function to wrap a block of code to verify if it throws a specific throwable [T], when [shouldThrowExactly]
* can't be used for whatever reason, such as assignment operations (assignments are statements therefore has no return
* value).
*
* This function will exclude subclasses of [T]. For example, if you test for [java.io.IOException] and the code block
* throws [java.io.FileNotFoundException], the test will fail, as [java.io.FileNotFoundException] is a subclass of
* [java.io.IOException], but not exactly [java.io.IOException].
*
* If you wish to include any subclasses, you should use [shouldThrowUnit] instead.
*
* If you don't care about the thrown type at all, use [shouldThrowAnyUnit] instead.
*
* ```
* val thrown: FooException = shouldThrowExactlyUnit {
* // Code that we expect to throw FooException
* throw FooException()
* }
* ```
*
* @see [shouldThrowExactly]
*/
inline fun shouldThrowExactlyUnit(block: () -> Unit): T = shouldThrowExactly { block() }
/**
* Verifies that a block of code doesn't throw a Throwable of type [T], not including subclasses of [T]
*
* Use this function to wrap a block of code that you'd like to verify whether it throws [T] (not including) or not.
* If [T] is thrown, this will thrown an [AssertionError]. If anything else is thrown, the throwable will be propagated.
* This is done so that no unexpected error is silently ignored.
*
* This should be used when [shouldNotThrowExactly] can't be used, such as when doing assignments (assignments are statements,
* therefore has no return value).
*
* This function won't include subclasses of [T]. For example, if you test for [java.io.IOException] and the code block
* throws [java.io.FileNotFoundException], propagate the [java.io.FileNotFoundException] instead of wrapping it in an AssertionError.
*
* If you wish to test [T] and subclasses, use [shouldNotThrowUnit].
*
* If you don't care about the thrown exception, use [shouldNotThrowAnyUnit]
*
* * ```
* shouldNotThrowExactlyUnit {
* throw FooException() // Fails
* }
* ```
*
* @see [shouldNotThrowExactly]
*
*/
inline fun shouldNotThrowExactlyUnit(block: () -> Unit) = shouldNotThrowExactly(block)
/**
* Verifies that a block of code throws a Throwable of type [T], not including subclasses of [T]
*
* Use this function to wrap a block of code to verify if it throws a specific throwable [T]
*
* This function will exclude subclasses of [T]. For example, if you test for [java.io.IOException] and the code block
* throws [java.io.FileNotFoundException], the test will fail, as [java.io.FileNotFoundException] is a subclass of
* [java.io.IOException], but not exactly [java.io.IOException].
*
* If you wish to include any subclasses, you should use [shouldThrow] instead.
*
* If you don't care about the thrown type at all, use [shouldThrowAny] instead.
*
*
*
* **Attention to assignment operations**:
*
* When doing an assignment to a variable, the code won't compile, because an assignment is not of type [Any], as required
* by [block]. If you need to test that an assignment throws a [Throwable], use [shouldThrowExactlyUnit] or it's variations.
*
* ```
* val thrown: FooException = shouldThrowExactly {
* // Code that we expect to throw FooException
* throw FooException()
* }
* ```
*
* @see [shouldThrowExactly]
*/
inline fun shouldThrowExactly(block: () -> Any?): T {
AssertionCounter.inc()
val expectedExceptionClass = T::class
val thrownThrowable = try {
block()
null // Can't throw failure here directly, as it would be caught by the catch clause, and it's an AssertionError, which is a special case
} catch (thrown: Throwable) {
thrown
}
return when {
thrownThrowable == null -> throw failure("Expected exception ${T::class.bestName()} but no exception was thrown.")
thrownThrowable::class == expectedExceptionClass -> thrownThrowable as T // This should be before `is AssertionError`. If the user is purposefully trying to verify `shouldThrow{}` this will take priority
thrownThrowable is AssertionError -> throw thrownThrowable
else -> throw failure("Expected exception ${expectedExceptionClass.bestName()} but a ${thrownThrowable::class.simpleName} was thrown instead.",
thrownThrowable)
}
}
/**
* Verifies that a block of code doesn't throw a Throwable of type [T], not including subclasses of [T]
*
* Use this function to wrap a block of code that you'd like to verify whether it throws [T] (not including) or not.
* If [T] is thrown, this will thrown an [AssertionError]. If anything else is thrown, the throwable will be propagated.
* This is done so that no unexpected error is silently ignored.
*
*
* This function won't include subclasses of [T]. For example, if you test for [java.io.IOException] and the code block
* throws [java.io.FileNotFoundException], propagate the [java.io.FileNotFoundException] instead of wrapping it in an AssertionError.
*
* If you wish to test [T] and subclasses, use [shouldNotThrow].
*
* If you don't care about the thrown exception, use [shouldNotThrowAny]
*
* **Attention to assignment operations**:
*
* When doing an assignment to a variable, the code won't compile, because an assignment is not of type [Any], as required
* by [block]. If you need to test that an assignment doesn't throw a [Throwable], use [shouldNotThrowExactlyUnit] or it's variations.
*
* ```
* val thrown: FooException = shouldThrowExactly {
* // Code that we expect to throw FooException
* throw FooException()
* }
* ```
*
* @see [shouldNotThrowExactlyUnit]
*
*/
inline fun shouldNotThrowExactly(block: () -> Any?) {
AssertionCounter.inc()
val thrown = try {
block()
return
} catch (t: Throwable) {
t
}
if (thrown::class == T::class) throw failure("No exception expected, but a ${thrown::class.simpleName} was thrown.",
thrown)
throw thrown
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy