From 998225802346b6c442e54d1daea883a9517df9f4 Mon Sep 17 00:00:00 2001 From: Arkadii Ivanov Date: Wed, 29 Jan 2025 19:00:53 +0000 Subject: [PATCH] Rethrow fatal errors on JVM --- .../badoo/reaktive/base/ErrorCallbackExt.kt | 39 ++++- .../badoo/reaktive/utils/HandleSourceError.kt | 13 ++ .../badoo/reaktive/test/TestErrorCallback.kt | 15 ++ .../reaktive/utils/TryCatchAndHandleTest.kt | 50 +++++++ .../com/badoo/reaktive/utils/TryCatchTest.kt | 67 +++++++++ .../utils/TryCatchWithOnSuccessTest.kt | 79 ++++++++++ .../badoo/reaktive/utils/HandleSourceError.kt | 3 + .../reaktive/utils/HandleSourceError.jvm.kt | 6 + .../utils/HandleReaktiveErrorJvmTest.kt | 127 ++++++++++++++++ .../reaktive/utils/MyVirtualMachineError.kt | 3 + .../utils/TryCatchAndHandleJvmTest.kt | 92 ++++++++++++ .../badoo/reaktive/utils/TryCatchJvmTest.kt | 135 +++++++++++++++++ .../utils/TryCatchWithOnSuccessJvmTest.kt | 138 ++++++++++++++++++ .../utils/HandleSourceError.native.kt | 3 + 14 files changed, 767 insertions(+), 3 deletions(-) create mode 100644 reaktive/src/commonTest/kotlin/com/badoo/reaktive/test/TestErrorCallback.kt create mode 100644 reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleTest.kt create mode 100644 reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchTest.kt create mode 100644 reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessTest.kt create mode 100644 reaktive/src/jsCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt create mode 100644 reaktive/src/jvmCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.jvm.kt create mode 100644 reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/HandleReaktiveErrorJvmTest.kt create mode 100644 reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/MyVirtualMachineError.kt create mode 100644 reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleJvmTest.kt create mode 100644 reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchJvmTest.kt create mode 100644 reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessJvmTest.kt create mode 100644 reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.native.kt diff --git a/reaktive/src/commonMain/kotlin/com/badoo/reaktive/base/ErrorCallbackExt.kt b/reaktive/src/commonMain/kotlin/com/badoo/reaktive/base/ErrorCallbackExt.kt index 8b2e5667b..f9bad56db 100644 --- a/reaktive/src/commonMain/kotlin/com/badoo/reaktive/base/ErrorCallbackExt.kt +++ b/reaktive/src/commonMain/kotlin/com/badoo/reaktive/base/ErrorCallbackExt.kt @@ -1,6 +1,8 @@ package com.badoo.reaktive.base +import com.badoo.reaktive.base.exceptions.CompositeException import com.badoo.reaktive.utils.handleReaktiveError +import com.badoo.reaktive.utils.throwIfFatal inline fun ErrorCallback.tryCatch( block: () -> T, @@ -10,7 +12,18 @@ inline fun ErrorCallback.tryCatch( try { block() } catch (e: Throwable) { - handleReaktiveError(errorTransformer(e), ::onError) + e.throwIfFatal() + + val transformedError = + try { + errorTransformer(e) + } catch (e2: Throwable) { + e2.throwIfFatal() + CompositeException(cause1 = e, cause2 = e2) + } + + handleReaktiveError(transformedError, ::onError) + return } .also(onSuccess) @@ -23,7 +36,17 @@ inline fun ErrorCallback.tryCatch( try { block() } catch (e: Throwable) { - handleReaktiveError(errorTransformer(e), ::onError) + e.throwIfFatal() + + val transformedError = + try { + errorTransformer(e) + } catch (e2: Throwable) { + e2.throwIfFatal() + CompositeException(cause1 = e, cause2 = e2) + } + + handleReaktiveError(transformedError, ::onError) } } @@ -34,6 +57,16 @@ internal inline fun tryCatchAndHandle( try { block() } catch (e: Throwable) { - handleReaktiveError(errorTransformer(e)) + e.throwIfFatal() + + val transformedError = + try { + errorTransformer(e) + } catch (e2: Throwable) { + e2.throwIfFatal() + CompositeException(cause1 = e, cause2 = e2) + } + + handleReaktiveError(transformedError) } } diff --git a/reaktive/src/commonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt b/reaktive/src/commonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt index 836f66421..6c1d429de 100644 --- a/reaktive/src/commonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt +++ b/reaktive/src/commonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt @@ -3,6 +3,8 @@ package com.badoo.reaktive.utils import com.badoo.reaktive.base.exceptions.CompositeException fun handleReaktiveError(error: Throwable, onError: ((Throwable) -> Unit)? = null) { + error.throwIfFatal() + if (onError == null) { handleError(error) } else { @@ -14,6 +16,7 @@ private fun handleError(error: Throwable) { try { reaktiveUncaughtErrorHandler(error) } catch (errorDeliveryException: Throwable) { + errorDeliveryException.throwIfFatal() printErrors("Error delivering uncaught error", error, errorDeliveryException) } } @@ -22,11 +25,13 @@ private fun handleError(error: Throwable, onError: (Throwable) -> Unit) { try { onError(error) } catch (errorHandlerException: Throwable) { + errorHandlerException.throwIfFatal() printErrors("onError callback failed", error, errorHandlerException) try { reaktiveUncaughtErrorHandler(CompositeException(error, errorHandlerException)) } catch (errorDeliveryException: Throwable) { + errorDeliveryException.throwIfFatal() printErrors("Error delivering uncaught error", error, errorDeliveryException) } } @@ -37,3 +42,11 @@ private fun printErrors(message: String, outerError: Throwable, innerError: Thro outerError.printStackTrace() innerError.printStackTrace() } + +fun Throwable.throwIfFatal() { + if (isFatal()) { + throw this + } +} + +internal expect fun Throwable.isFatal(): Boolean diff --git a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/test/TestErrorCallback.kt b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/test/TestErrorCallback.kt new file mode 100644 index 000000000..570a5f2f5 --- /dev/null +++ b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/test/TestErrorCallback.kt @@ -0,0 +1,15 @@ +package com.badoo.reaktive.test + +import com.badoo.reaktive.base.ErrorCallback + +class TestErrorCallback( + private val onError: (Throwable) -> Unit = {}, +) : ErrorCallback { + + var error: Throwable? = null + + override fun onError(error: Throwable) { + onError.invoke(error) + this.error = error + } +} diff --git a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleTest.kt b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleTest.kt new file mode 100644 index 000000000..364baeab6 --- /dev/null +++ b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleTest.kt @@ -0,0 +1,50 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.exceptions.CompositeException +import com.badoo.reaktive.base.tryCatchAndHandle +import com.badoo.reaktive.test.mockUncaughtExceptionHandler +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertIs +import kotlin.test.assertSame + +class TryCatchAndHandleTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun calls_reaktiveUncaughtErrorHandler_WHEN_block_thrown_exception() { + val caughtException = mockUncaughtExceptionHandler() + val error = Exception() + + tryCatchAndHandle { throw error } + + assertSame(error, caughtException.value) + } + + @Test + fun calls_reaktiveUncaughtErrorHandler_WHEN_errorTransformer_thrown_exception() { + val caughtException = mockUncaughtExceptionHandler() + val error1 = Exception() + val error2 = Exception() + + tryCatchAndHandle( + errorTransformer = { throw error2 }, + block = { throw error1 }, + ) + + val error = caughtException.value + assertIs(error) + assertSame(error1, error.cause1) + assertSame(error2, error.cause2) + } + + @Test + fun swallows_WHEN_reaktiveUncaughtErrorHandler_thrown_exception() { + reaktiveUncaughtErrorHandler = { throw Exception() } + tryCatchAndHandle { throw Exception() } + } +} diff --git a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchTest.kt b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchTest.kt new file mode 100644 index 000000000..39795917d --- /dev/null +++ b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchTest.kt @@ -0,0 +1,67 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.exceptions.CompositeException +import com.badoo.reaktive.base.tryCatch +import com.badoo.reaktive.test.TestErrorCallback +import com.badoo.reaktive.test.mockUncaughtExceptionHandler +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertIs +import kotlin.test.assertSame + +class TryCatchTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun calls_ErrorCallback_WHEN_block_thrown_exception() { + val errorCallback = TestErrorCallback() + val error = Exception() + + errorCallback.tryCatch { throw error } + + assertSame(error, errorCallback.error) + } + + @Test + fun calls_ErrorCallback_WHEN_errorTransformer_thrown_exception() { + val errorCallback = TestErrorCallback() + val error1 = Exception() + val error2 = Exception() + + errorCallback.tryCatch( + errorTransformer = { throw error2 }, + block = { throw error1 }, + ) + + val error = errorCallback.error + assertIs(error) + assertSame(error1, error.cause1) + assertSame(error2, error.cause2) + } + + @Test + fun calls_reaktiveUncaughtErrorHandler_WHEN_ErrorCallback_thrown_exception() { + val caughtException = mockUncaughtExceptionHandler() + val error1 = Exception() + val error2 = Exception() + + val errorCallback = TestErrorCallback { throw error2 } + errorCallback.tryCatch { throw error1 } + + val error = caughtException.value + assertIs(error) + assertSame(error1, error.cause1) + assertSame(error2, error.cause2) + } + + @Test + fun swallows_WHEN_reaktiveUncaughtErrorHandler_thrown_exception() { + reaktiveUncaughtErrorHandler = { throw Exception() } + val errorCallback = TestErrorCallback { throw Exception() } + errorCallback.tryCatch { throw Exception() } + } +} diff --git a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessTest.kt b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessTest.kt new file mode 100644 index 000000000..e8cea29d1 --- /dev/null +++ b/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessTest.kt @@ -0,0 +1,79 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.exceptions.CompositeException +import com.badoo.reaktive.base.tryCatch +import com.badoo.reaktive.test.TestErrorCallback +import com.badoo.reaktive.test.mockUncaughtExceptionHandler +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertSame + +class TryCatchWithOnSuccessTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun calls_onSuccess_WHEN_block_not_thrown() { + val errorCallback = TestErrorCallback() + var result: Int? = null + + errorCallback.tryCatch(block = { 0 }, onSuccess = { result = 0 }) + + assertEquals(0, result) + } + + @Test + fun calls_ErrorCallback_WHEN_block_thrown_exception() { + val errorCallback = TestErrorCallback() + val error = Exception() + + errorCallback.tryCatch(block = { throw error }, onSuccess = {}) + + assertSame(error, errorCallback.error) + } + + @Test + fun calls_ErrorCallback_WHEN_errorTransformer_thrown_exception() { + val errorCallback = TestErrorCallback() + val error1 = Exception() + val error2 = Exception() + + errorCallback.tryCatch( + block = { throw error1 }, + errorTransformer = { throw error2 }, + onSuccess = {}, + ) + + val error = errorCallback.error + assertIs(error) + assertSame(error1, error.cause1) + assertSame(error2, error.cause2) + } + + @Test + fun calls_reaktiveUncaughtErrorHandler_WHEN_ErrorCallback_thrown_exception() { + val caughtException = mockUncaughtExceptionHandler() + val error1 = Exception() + val error2 = Exception() + + val errorCallback = TestErrorCallback { throw error2 } + errorCallback.tryCatch(block = { throw error1 }, onSuccess = {}) + + val error = caughtException.value + assertIs(error) + assertSame(error1, error.cause1) + assertSame(error2, error.cause2) + } + + @Test + fun swallows_WHEN_reaktiveUncaughtErrorHandler_thrown_exception() { + reaktiveUncaughtErrorHandler = { throw Exception() } + val errorCallback = TestErrorCallback { throw Exception() } + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } +} diff --git a/reaktive/src/jsCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt b/reaktive/src/jsCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt new file mode 100644 index 000000000..2256c81b4 --- /dev/null +++ b/reaktive/src/jsCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.kt @@ -0,0 +1,3 @@ +package com.badoo.reaktive.utils + +actual fun Throwable.isFatal(): Boolean = false diff --git a/reaktive/src/jvmCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.jvm.kt b/reaktive/src/jvmCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.jvm.kt new file mode 100644 index 000000000..6391f60f1 --- /dev/null +++ b/reaktive/src/jvmCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.jvm.kt @@ -0,0 +1,6 @@ +package com.badoo.reaktive.utils + +internal actual fun Throwable.isFatal(): Boolean = + (this is VirtualMachineError) || + (this is ThreadDeath) || + (this is LinkageError) diff --git a/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/HandleReaktiveErrorJvmTest.kt b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/HandleReaktiveErrorJvmTest.kt new file mode 100644 index 000000000..22629fb00 --- /dev/null +++ b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/HandleReaktiveErrorJvmTest.kt @@ -0,0 +1,127 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.exceptions.CompositeException +import com.badoo.reaktive.test.mockUncaughtExceptionHandler +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertIs + +class HandleReaktiveErrorJvmTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun rethrows_WHEN_VirtualMachineError() { + assertFailsWith { + handleReaktiveError(MyVirtualMachineError()) + } + } + + @Test + fun rethrows_WHEN_ThreadDeath() { + assertFailsWith { + handleReaktiveError(ThreadDeath()) + } + } + + @Test + fun rethrows_WHEN_LinkageError() { + assertFailsWith { + handleReaktiveError(LinkageError()) + } + } + + @Test + fun calls_reaktiveUncaughtErrorHandler_WHEN_exception_and_onError_not_supplied() { + val caughtException = mockUncaughtExceptionHandler() + val error = Exception() + + handleReaktiveError(error) + + assertEquals(error, caughtException.value) + } + + @Test + fun calls_onError_WHEN_exception_and_onError_supplied() { + val error = Exception() + var receivedError: Throwable? = null + + handleReaktiveError(error = error, onError = { receivedError = it }) + + assertEquals(error, receivedError) + } + + @Test + fun rethrows_WHEN_onError_thrown_VirtualMachineError() { + assertFailsWith { + handleReaktiveError(error = Exception(), onError = { throw MyVirtualMachineError() }) + } + } + + @Test + fun rethrows_WHEN_onError_thrown_ThreadDeath() { + assertFailsWith { + handleReaktiveError(error = Exception(), onError = { throw ThreadDeath() }) + } + } + + @Test + fun rethrows_WHEN_onError_thrown_LinkageError() { + assertFailsWith { + handleReaktiveError(error = Exception(), onError = { throw LinkageError() }) + } + } + + @Test + fun calls_reaktiveUncaughtErrorHandler_WHEN_onError_thrown_exception() { + val caughtException = mockUncaughtExceptionHandler() + val error1 = Exception() + val error2 = Exception() + + handleReaktiveError(error = error1, onError = { throw error2 }) + + val error = caughtException.value + assertIs(error) + assertEquals(error1, error.cause1) + assertEquals(error2, error.cause2) + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_VirtualMachineError() { + reaktiveUncaughtErrorHandler = { throw MyVirtualMachineError() } + + assertFailsWith { + handleReaktiveError(error = Exception()) + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_ThreadDeath() { + reaktiveUncaughtErrorHandler = { throw ThreadDeath() } + + assertFailsWith { + handleReaktiveError(error = Exception()) + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_LinkageError() { + reaktiveUncaughtErrorHandler = { throw LinkageError() } + + assertFailsWith { + handleReaktiveError(error = Exception()) + } + } + + @Test + fun swallows_WHEN_reaktiveUncaughtErrorHandler_thrown_exception() { + reaktiveUncaughtErrorHandler = { throw Exception() } + + handleReaktiveError(error = Exception()) + } +} diff --git a/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/MyVirtualMachineError.kt b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/MyVirtualMachineError.kt new file mode 100644 index 000000000..08a00d489 --- /dev/null +++ b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/MyVirtualMachineError.kt @@ -0,0 +1,3 @@ +package com.badoo.reaktive.utils + +class MyVirtualMachineError : VirtualMachineError() diff --git a/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleJvmTest.kt b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleJvmTest.kt new file mode 100644 index 000000000..ee3b719c6 --- /dev/null +++ b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchAndHandleJvmTest.kt @@ -0,0 +1,92 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.tryCatchAndHandle +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class TryCatchAndHandleJvmTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun rethrows_WHEN_block_thrown_VirtualMachineError() { + assertFailsWith { + tryCatchAndHandle { throw MyVirtualMachineError() } + } + } + + @Test + fun rethrows_WHEN_block_thrown_ThreadDeath() { + assertFailsWith { + tryCatchAndHandle { throw ThreadDeath() } + } + } + + @Test + fun rethrows_WHEN_block_thrown_LinkageError() { + assertFailsWith { + tryCatchAndHandle { throw LinkageError() } + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_VirtualMachineError() { + assertFailsWith { + tryCatchAndHandle( + errorTransformer = { throw MyVirtualMachineError() }, + block = { throw Exception() }, + ) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_ThreadDeath() { + assertFailsWith { + tryCatchAndHandle( + errorTransformer = { throw ThreadDeath() }, + block = { throw Exception() }, + ) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_LinkageError() { + assertFailsWith { + tryCatchAndHandle( + errorTransformer = { throw LinkageError() }, + block = { throw Exception() }, + ) + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_VirtualMachineError() { + reaktiveUncaughtErrorHandler = { throw MyVirtualMachineError() } + + assertFailsWith { + tryCatchAndHandle { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_ThreadDeath() { + reaktiveUncaughtErrorHandler = { throw ThreadDeath() } + + assertFailsWith { + tryCatchAndHandle { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_LinkageError() { + reaktiveUncaughtErrorHandler = { throw LinkageError() } + + assertFailsWith { + tryCatchAndHandle { throw Exception() } + } + } +} diff --git a/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchJvmTest.kt b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchJvmTest.kt new file mode 100644 index 000000000..81adb8a92 --- /dev/null +++ b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchJvmTest.kt @@ -0,0 +1,135 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.tryCatch +import com.badoo.reaktive.test.TestErrorCallback +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class TryCatchJvmTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun rethrows_WHEN_block_thrown_VirtualMachineError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch { throw MyVirtualMachineError() } + } + } + + @Test + fun rethrows_WHEN_block_thrown_ThreadDeath() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch { throw ThreadDeath() } + } + } + + @Test + fun rethrows_WHEN_block_thrown_LinkageError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch { throw LinkageError() } + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_VirtualMachineError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch( + errorTransformer = { throw MyVirtualMachineError() }, + block = { throw Exception() }, + ) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_ThreadDeath() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch( + errorTransformer = { throw ThreadDeath() }, + block = { throw Exception() }, + ) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_LinkageError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch( + errorTransformer = { throw LinkageError() }, + block = { throw Exception() }, + ) + } + } + + @Test + fun rethrows_WHEN_ErrorCallback_thrown_VirtualMachineError() { + val errorCallback = TestErrorCallback { throw MyVirtualMachineError() } + + assertFailsWith { + errorCallback.tryCatch { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_ErrorCallback_thrown_ThreadDeath() { + val errorCallback = TestErrorCallback { throw ThreadDeath() } + + assertFailsWith { + errorCallback.tryCatch { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_ErrorCallback_thrown_LinkageError() { + val errorCallback = TestErrorCallback { throw LinkageError() } + + assertFailsWith { + errorCallback.tryCatch { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_VirtualMachineError() { + reaktiveUncaughtErrorHandler = { throw MyVirtualMachineError() } + val errorCallback = TestErrorCallback { throw Exception() } + + assertFailsWith { + errorCallback.tryCatch { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_ThreadDeath() { + reaktiveUncaughtErrorHandler = { throw ThreadDeath() } + val errorCallback = TestErrorCallback { throw Exception() } + + assertFailsWith { + errorCallback.tryCatch { throw Exception() } + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_LinkageError() { + reaktiveUncaughtErrorHandler = { throw LinkageError() } + val errorCallback = TestErrorCallback { throw Exception() } + + assertFailsWith { + errorCallback.tryCatch { throw Exception() } + } + } +} diff --git a/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessJvmTest.kt b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessJvmTest.kt new file mode 100644 index 000000000..fe78c5ff5 --- /dev/null +++ b/reaktive/src/jvmTest/kotlin/com/badoo/reaktive/utils/TryCatchWithOnSuccessJvmTest.kt @@ -0,0 +1,138 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.base.tryCatch +import com.badoo.reaktive.test.TestErrorCallback +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class TryCatchWithOnSuccessJvmTest { + + @AfterTest + fun after() { + resetReaktiveUncaughtErrorHandler() + } + + @Test + fun rethrows_WHEN_block_thrown_VirtualMachineError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch(block = { throw MyVirtualMachineError() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_block_thrown_ThreadDeath() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch(block = { throw ThreadDeath() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_block_thrown_LinkageError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch(block = { throw LinkageError() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_VirtualMachineError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch( + block = { throw Exception() }, + errorTransformer = { throw MyVirtualMachineError() }, + onSuccess = {}, + ) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_ThreadDeath() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch( + block = { throw Exception() }, + errorTransformer = { throw ThreadDeath() }, + onSuccess = {}, + ) + } + } + + @Test + fun rethrows_WHEN_errorTransformer_thrown_LinkageError() { + val errorCallback = TestErrorCallback() + + assertFailsWith { + errorCallback.tryCatch( + block = { throw Exception() }, + errorTransformer = { throw LinkageError() }, + onSuccess = {}, + ) + } + } + + @Test + fun rethrows_WHEN_ErrorCallback_thrown_VirtualMachineError() { + val errorCallback = TestErrorCallback { throw MyVirtualMachineError() } + + assertFailsWith { + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_ErrorCallback_thrown_ThreadDeath() { + val errorCallback = TestErrorCallback { throw ThreadDeath() } + + assertFailsWith { + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_ErrorCallback_thrown_LinkageError() { + val errorCallback = TestErrorCallback { throw LinkageError() } + + assertFailsWith { + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_VirtualMachineError() { + reaktiveUncaughtErrorHandler = { throw MyVirtualMachineError() } + val errorCallback = TestErrorCallback { throw Exception() } + + assertFailsWith { + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_ThreadDeath() { + reaktiveUncaughtErrorHandler = { throw ThreadDeath() } + val errorCallback = TestErrorCallback { throw Exception() } + + assertFailsWith { + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } + } + + @Test + fun rethrows_WHEN_reaktiveUncaughtErrorHandler_thrown_LinkageError() { + reaktiveUncaughtErrorHandler = { throw LinkageError() } + val errorCallback = TestErrorCallback { throw Exception() } + + assertFailsWith { + errorCallback.tryCatch(block = { throw Exception() }, onSuccess = {}) + } + } +} diff --git a/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.native.kt b/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.native.kt new file mode 100644 index 000000000..7a8ce2629 --- /dev/null +++ b/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/HandleSourceError.native.kt @@ -0,0 +1,3 @@ +package com.badoo.reaktive.utils + +internal actual fun Throwable.isFatal(): Boolean = false