doc / ch.tutteli.atrium.api.infix.en_GB / toBeAnInstanceOf

toBeAnInstanceOf

inline fun <reified TSub : Any> Expect<*>.toBeAnInstanceOf(): Expect<TSub> (source)

Expects that the subject of this expectation is a TSub (the same type or a sub-type) and changes the subject to this type.

Notice, that asserting a function type is flawed. The actual types are ignored as function types erase to Function0, Function1 etc. on byte code level, which means the assertion holds as long as the subject is a function and has the same amount of arguments regardless if the types differ. For instance expect({x: Int -> "hello"}).toBeAnInstanceOf<String -> Unit>{} holds, even though (Int) -> String is clearly not a (String) -> Unit.

More generally speaking, the flaw applies to all generic types. For instance toBeAnInstanceOf<List<String>> would only check if the subject is a List without checking if the element type is actually String. Or in other words expect(listOf(1, 2)).toBeAnInstanceOf<List<String>>{} holds, even though List<Int> is clearly not a List<String>.

val n: Number = 1
expect(n).toBeAnInstanceOf<Int>() toBeGreaterThan 0
//                   | subject is now of type Int

fails {
    expect("A").toBeAnInstanceOf<Long>() toBeLessThan 2L
    //                                      | not shown in reporting as `toBeAnInstanceOf` already fails
}

Return
An Expect with the new type TSub.

Since
0.17.0

inline infix fun <reified TSub : Any> Expect<*>.toBeAnInstanceOf(noinline assertionCreator: Expect<TSub>.() -> Unit): Expect<TSub> (source)

Expects that the subject of this expectation is a TSub (the same type or a sub-type) and that it holds all assertions the given assertionCreator creates.

Notice, in contrast to other assertion functions which expect an assertionCreator, this function returns not Expect of the initial type, which was some type T , but an Expect of the specified type TSub. This has the side effect that a subsequent call has only assertion functions available which are suited for TSub. Since Expect is invariant it especially means that an assertion function which was not written in a generic way will not be available. Fixing such a function is easy (in most cases), you need to transform it into a generic from. Following an example:

interface Person
class Student: Person
fun Expect<Person>.foo()        = "dummy"  // limited only to Person, not recommended
fun <T: Person> Expect<T>.bar() = "dummy"  // available to Person and all subtypes, the way to go
fun Expect<Student>.baz()       = "dummy"  // specific only for Student, ok since closed class

val p: Person = Student()
expect(p)               // subject of type Person
  .toBeAnInstanceOf<Student> { ... } // subject now refined to Student
  .baz()                // available via Student
  .foo()                // not available to Student, only to Person, results in compilation error
  .bar()                // available via T : Person

Notice, that asserting a function type is flawed. The actual types are ignored as function types erase to Function0, Function1 etc. on byte code level, which means the assertion holds as long as the subject is a function and has the same amount of arguments regardless if the types differ. For instance expect({x: Int -> "hello"}).toBeAnInstanceOf<String -> Unit>{} holds, even though (Int) -> String is clearly not a (String) -> Unit.

More generally speaking, the flaw applies to all generic types. For instance toBeAnInstanceOf<List<String>> would only check if the subject is a List without checking if the element type is actually String. Or in other words expect(listOf(1, 2)).toBeAnInstanceOf<List<String>>{} holds, even though List<Int> is clearly not a List<String>.

val n: Number = 16
expect(n).toBeAnInstanceOf<Int> { // subject is now of type Int
    it toBeGreaterThanOrEqualTo 15
} /* subject remains type Int also after the block
*/ toBeLessThan 20

fails { // because wrong type expected (Long instead of String), but since we use a block...
    expect("A").toBeAnInstanceOf<Long> {
        it toEqual 43 // ...reporting mentions that subject was expected `to equal: 43`
    }
}

fails { // because sub-expectation fails
    expect(n).toBeAnInstanceOf<Long> {
        it toEqual -1L
    }
}

fails {
    // because you forgot to define an expectation in the expectation group block
    // use `.toBeAnInstanceOf<Int>()` if this is all you expect
    expect<Number>(1).toBeAnInstanceOf<Int> { }
}

Return
An Expect with the new type TSub.

Since
0.17.0