xref: /aosp_15_r20/external/android_onboarding/java/com/android/onboarding/testing/SuccessSubject.kt (revision c625018464ae97c56936c82b1b617e11aa899faa)
1 package com.android.onboarding.testing
2 
3 import com.google.common.truth.Fact.fact
4 import com.google.common.truth.Fact.simpleFact
5 import com.google.common.truth.FailureMetadata
6 import com.google.common.truth.StandardSubjectBuilder
7 import com.google.common.truth.Subject
8 import com.google.common.truth.ThrowableSubject
9 import com.google.common.truth.Truth
10 import com.google.common.truth.Truth.assertAbout
11 import com.google.common.truth.Truth.assertThat
12 import com.google.errorprone.annotations.CanIgnoreReturnValue
13 
14 /** A [Truth] [Subject] to assert that no [Throwable]s were thrown failing lazily otherwise. */
15 class SuccessSubject
16 private constructor(metadata: FailureMetadata, private val actual: (() -> Any?)?) :
17   Subject(metadata, actual) {
18 
19   @CanIgnoreReturnValue
doesNotFailnull20   fun doesNotFail(): Subject {
21     if (actual == null) {
22       failWithoutActual(
23         simpleFact("expected to not fail"),
24         simpleFact("but no action was provided"),
25       )
26       return assertThat(null as Any?)
27     }
28     val result =
29       runCatching(actual).onFailure {
30         failWithoutActual(
31           simpleFact("expected to not fail"),
32           fact("but failed with", it::class.qualifiedName),
33         )
34       }
35     return assertThat(result.getOrNull())
36   }
37 
38   companion object : Factory<SuccessSubject, () -> Any?> {
createSubjectnull39     override fun createSubject(metadata: FailureMetadata, actual: (() -> Any?)?): SuccessSubject =
40       SuccessSubject(metadata, actual)
41   }
42 }
43 
44 /** @see assertDoesNotFail */
45 fun StandardSubjectBuilder.doesNotFail(action: () -> Any?) {
46   about(SuccessSubject).that(action).doesNotFail()
47 }
48 
49 /**
50  * Asserts that a given [action] does not throw an exception. If the [action] does throw an
51  * exception, it is registered lazily to the [StandardSubjectBuilder] allowing the rest of the test
52  * assertions to continue.
53  *
54  * Unfortunately @[CanIgnoreReturnValue] is not supported on inline library functions and as such
55  * this utility function is not returning [ThrowableSubject] for further assertions. If you need
56  * further assertions consider using one of the more verbose forms:
57  * ```
58  * @get:Rule val expect: Expect = Expect.create()
59  * expect.about(SuccessSubject).that { functionUnderTest() }.doesNotFail().isNotNull()
60  *
61  * assertAbout(SuccessSubject).that { functionUnderTest() }.doesNotFail().isNotNull()
62  * ```
63  */
assertDoesNotFailnull64 fun assertDoesNotFail(action: () -> Any?) {
65   assertAbout(SuccessSubject).that(action).doesNotFail()
66 }
67