• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import kotlin.reflect.KClass
14 
15 /** A [Truth] [Subject] to assert expected [Throwable]s being thrown. */
16 class ErrorSubject
17 private constructor(metadata: FailureMetadata, private val actual: (() -> Any?)?) :
18   Subject(metadata, actual) {
19 
20   @CanIgnoreReturnValue
failsWithnull21   inline fun <reified T : Throwable> failsWith(): ThrowableSubject = failsWith(T::class)
22 
23   @CanIgnoreReturnValue
24   fun <T : Throwable> failsWith(expected: KClass<T>): ThrowableSubject {
25     if (actual == null) {
26       failWithoutActual(
27         fact("expected to fail with", expected.qualifiedName),
28         simpleFact("but no action was provided"),
29       )
30       return assertThat(null as Throwable?)
31     }
32     val error = runCatching(actual).exceptionOrNull()
33     if (error == null) {
34       failWithoutActual(
35         fact("expected to fail with", expected.qualifiedName),
36         simpleFact("but did not fail"),
37       )
38     } else if (!expected.java.isInstance(error)) {
39       failWithoutActual(
40         fact("expected to fail with", expected.qualifiedName),
41         fact("but failed with", error::class.qualifiedName),
42       )
43     }
44     return assertThat(error)
45   }
46 
47   companion object : Factory<ErrorSubject, () -> Any?> {
createSubjectnull48     override fun createSubject(metadata: FailureMetadata, actual: (() -> Any?)?): ErrorSubject =
49       ErrorSubject(metadata, actual)
50   }
51 }
52 
53 /** @see assertFailsWith */
54 inline fun <reified T : Throwable> StandardSubjectBuilder.failsWith(noinline action: () -> Any?) {
55   about(ErrorSubject).that(action).failsWith<T>()
56 }
57 
58 /**
59  * Asserts that the given [action] fails with the expected [Throwable] [T]
60  *
61  * Unfortunately @[CanIgnoreReturnValue] is not supported on inline library functions and as such
62  * this utility function is not returning [ThrowableSubject] for further assertions. If you need
63  * further assertions consider using one of the more verbose forms:
64  * ```
65  * @get:Rule val expect: Expect = Expect.create()
66  * expect.about(ErrorSubject).that { functionUnderTest() }.failsWith<Throwable>().isNotNull()
67  *
68  * assertAbout(ErrorSubject).that { functionUnderTest() }.failsWith<Throwable>().isNotNull()
69  * ```
70  */
assertFailsWithnull71 inline fun <reified T : Throwable> assertFailsWith(noinline action: () -> Any?) {
72   assertAbout(ErrorSubject).that(action).failsWith<T>()
73 }
74