doc / ch.tutteli.atrium.api.fluent.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>() // subject is now of type Int
    .toBeGreaterThan(0)

fails {
    expect("A")
        .toBeAnInstanceOf<Long>() // fails
        .toBeLessThan(2L)         // not evaluated/reported because `toBeAnInstanceOf` already fails
    //                               use `toBeAnInstanceOf<...> { ... }` if you want that all expectations are evaluated
}

Return
An Expect with the new type TSub.

Since
0.17.0

inline 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
  .toBeAnInstanceOfnInstanceOf<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"}).toBeAnInstanceOfnInstanceOf<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 toBeAnInstanceOfnInstanceOf<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)).toBeAnInstanceOfnInstanceOf<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
        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> {
        toEqual(43) // ...reporting mentions that subject was expected `to equal: 43`
    }
}

fails { // because sub-expectation fails
    expect(n).toBeAnInstanceOf<Long> {
        toEqual(-1L)     // fails
        toBeLessThan(2L) // still evaluated even though `toEqual` already fails,
        //                  use `.toBeAnInstanceOf<...>().` if you want a fail fast behaviour
    }
}

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