diff --git a/build.gradle.kts b/build.gradle.kts index 6120fef1..42c2821d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,7 @@ allprojects { } } - version = "0.0.3" + version = "0.0.4" group = "io.github.ustudiocompany" configurations.all { diff --git a/library/failure/api/failure-library.api b/library/failure/api/failure-library.api index dc8d7597..782b651f 100644 --- a/library/failure/api/failure-library.api +++ b/library/failure/api/failure-library.api @@ -119,12 +119,14 @@ public final class io/github/ustudiocompany/uframework/failure/FailureKt { public abstract interface class io/github/ustudiocompany/uframework/failure/TypeFailure : io/github/ustudiocompany/uframework/failure/Failure { public static final field ACTUAL_VALUE_DETAIL_KEY Ljava/lang/String; public static final field Companion Lio/github/ustudiocompany/uframework/failure/TypeFailure$Companion; + public static final field EXCEPTION_STACKTRACE Ljava/lang/String; public static final field PATTERN_DETAIL_KEY Ljava/lang/String; public abstract fun getType-uX7CcE4 ()Ljava/lang/Class; } public final class io/github/ustudiocompany/uframework/failure/TypeFailure$Companion { public static final field ACTUAL_VALUE_DETAIL_KEY Ljava/lang/String; + public static final field EXCEPTION_STACKTRACE Ljava/lang/String; public static final field PATTERN_DETAIL_KEY Ljava/lang/String; } diff --git a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt index 44747939..9c1580d2 100644 --- a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt +++ b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt @@ -2,6 +2,7 @@ package io.github.ustudiocompany.uframework.failure import io.github.ustudiocompany.uframework.failure.Failure.Cause import io.github.ustudiocompany.uframework.failure.Failure.Details +import io.github.ustudiocompany.uframework.failure.TypeFailure.Companion.EXCEPTION_STACKTRACE public interface Failure { /** @@ -122,13 +123,16 @@ public fun Failure.fullCode(delimiter: String = "."): String = }.toString() /** - * Returns all details of the failure and its causes. + * Returns all details of the failure, its causes, and root exception details if it exists. * @return the all details. */ public fun Failure.allDetails(): Details { val allDetails = fold(initial = { mutableListOf().apply { addAll(it.details) } }) { acc, failure -> acc.apply { addAll(failure.details) } } + val exception = root().exceptionOrNull() + if (exception != null) + allDetails.add(Details.Item(key = EXCEPTION_STACKTRACE, value = exception.stackTraceToString())) return if (allDetails.isEmpty()) Details.NONE else diff --git a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt index c7bf258f..ab1d9daf 100644 --- a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt +++ b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt @@ -6,5 +6,6 @@ public interface TypeFailure : Failure { public companion object { public const val ACTUAL_VALUE_DETAIL_KEY: String = "actual-value" public const val PATTERN_DETAIL_KEY: String = "pattern" + public const val EXCEPTION_STACKTRACE: String = "exception-stackTrace" } } diff --git a/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt b/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt index 5ab74a51..f12c72dd 100644 --- a/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt +++ b/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt @@ -2,6 +2,7 @@ package io.github.ustudiocompany.uframework.failure import io.github.ustudiocompany.uframework.failure.Failure.Cause import io.github.ustudiocompany.uframework.failure.Failure.Details +import io.github.ustudiocompany.uframework.failure.TypeFailure.Companion.EXCEPTION_STACKTRACE import io.github.ustudiocompany.uframework.test.kotest.UnitTest import io.kotest.datatest.withData import io.kotest.matchers.collections.shouldContainOnly @@ -14,29 +15,38 @@ internal class AllDetailsFailureTest : UnitTest() { withData( nameFn = { (failure, _) -> failure.toString() }, listOf( - failure(code = CODE_1) to Details.NONE, - failure(code = CODE_1, details = Details.of(KEY_1 to VALUE_1)) to Details.of(KEY_1 to VALUE_1), - failure(code = CODE_2, cause = failure(code = CODE_1)) to Details.NONE, - failure( + failureRoot(code = CODE_1) to + Details.NONE, + failureRootException(details = Details.of(KEY_1 to VALUE_1)) to + Details.of( + KEY_1 to VALUE_1, + EXCEPTION_STACKTRACE to VALUE_4 + ), + failureChild(code = CODE_2, cause = failureRoot(code = CODE_1)) to + Details.NONE, + failureChild( code = CODE_2, - cause = failure(CODE_1), + cause = failureRoot(CODE_1), details = Details.of(KEY_1 to VALUE_1) - ) to Details.of(KEY_1 to VALUE_1), - failure( + ) to + Details.of(KEY_1 to VALUE_1), + failureChild( code = CODE_2, - cause = failure( + cause = failureRoot( code = CODE_1, details = Details.of(KEY_1 to VALUE_1) ) - ) to Details.of(KEY_1 to VALUE_1), - failure( + ) to + Details.of(KEY_1 to VALUE_1), + failureChild( code = CODE_2, - cause = failure( + cause = failureRoot( code = CODE_1, details = Details.of(KEY_1 to VALUE_1) ), details = Details.of(KEY_2 to VALUE_2) - ) to Details.of(KEY_1 to VALUE_1, KEY_2 to VALUE_2) + ) to + Details.of(KEY_1 to VALUE_1, KEY_2 to VALUE_2) ) ) { (failure, expected) -> failure.allDetails() shouldContainOnly expected @@ -44,8 +54,13 @@ internal class AllDetailsFailureTest : UnitTest() { } } - private fun failure(code: String, details: Details = Details.NONE): Failure = Root(code = code, details = details) - private fun failure(code: String, cause: Failure, details: Details = Details.NONE): Failure = + private fun failureRoot(code: String, details: Details = Details.NONE): Failure = + Root(code = code, details = details) + + private fun failureRootException(code: String = CODE_1, details: Details = Details.NONE): Failure = + RootException(code = code, details = details) + + private fun failureChild(code: String, cause: Failure, details: Details = Details.NONE): Failure = Child(code = code, cause = Cause.Failure(cause), details = details) private companion object { @@ -56,11 +71,20 @@ internal class AllDetailsFailureTest : UnitTest() { private const val KEY_2 = "key-2" private const val VALUE_1 = "value-1" private const val VALUE_2 = "value-2" + private const val VALUE_3 = "value-3" + private val testException = Exception(VALUE_3) + private val VALUE_4 = testException.stackTraceToString() } private data class Root( override val code: String, - override val details: Details = Details.NONE + override val details: Details = Details.NONE, + ) : Failure + + private data class RootException( + override val code: String, + override val details: Details = Details.NONE, + override val cause: Cause = Cause.Exception(testException) ) : Failure private data class Child(