javaarrayskotlinunit-testinghamcrest

Why is Hamcrest arrayWithSize not working with Kotlin


I'm trying to test the length of an integer array with hamcrest and <

import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.collection.IsArrayWithSize.arrayWithSize
import org.hamcrest.core.IsEqual.equalTo
import org.hamcrest.core.Is.`is` as Is
…
     val parts = intArrayOf(1, 2, 3)
     assertThat(parts, arrayWithSize(3))
     assertThat(parts, Is(arrayWithSize(3)))
     assertThat(parts, Is(arrayWithSize(equalTo(3))))

As far as I understand all three asserts should work and the equivalent statements will work in Java. But they don't work with Kotlin:

[ERROR] …/Decomposed_Test.kt:[287,14] Type mismatch: inferred type is IntArray but String! was expected
[ERROR] …/Decomposed_Test.kt:[287,21] Type mismatch: inferred type is Matcher<Array<(???..???)>!>! but Boolean was expected
[ERROR] …/Decomposed_Test.kt:[288,14] Type mismatch: inferred type is IntArray but String! was expected
[ERROR] …/Decomposed_Test.kt:[288,21] Type mismatch: inferred type is Matcher<(???..???)>! but Boolean was expected
[ERROR] …/Decomposed_Test.kt:[289,14] Type mismatch: inferred type is IntArray but String! was expected
[ERROR] …/Decomposed_Test.kt:[289,21] Type mismatch: inferred type is Matcher<(???..???)>! but Boolean was expected

This is of course wrong as I'm not comparing strings. I tried adding some reasons to the assert to see of that helps:

import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.collection.IsArrayWithSize.arrayWithSize
import org.hamcrest.core.IsEqual.equalTo
import org.hamcrest.core.Is.`is` as Is
…
     val parts = intArrayOf(1, 2, 3)
     assertThat(/* reason = */ "array has 3 elements", /* actual = */ parts, /* matcher = */ arrayWithSize(3))
     assertThat(/* reason = */ "array has 3 elements", /* actual = */ parts, /* matcher = */ Is(arrayWithSize(3)))
     assertThat(/* reason = */ "array has 3 elements", /* actual = */ parts, /* matcher = */ Is(arrayWithSize(equalTo(3))))

Different error message but still doesn't help:

[ERROR] …/Decomposed_Test.kt:[287,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>! was expected
[ERROR] …/Decomposed_Test.kt:[288,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>? was expected
[ERROR] …/Decomposed_Test.kt:[288,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>! was expected
[ERROR] …/Decomposed_Test.kt:[288,94] Type mismatch: inferred type is Matcher<Array<(out) (???..???)>!>! but Matcher<IntArray!>! was expected
[ERROR] …/Decomposed_Test.kt:[289,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>? was expected
[ERROR] …/Decomposed_Test.kt:[289,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>! was expected
[ERROR] …/Decomposed_Test.kt:[289,94] Type mismatch: inferred type is Matcher<Array<(out) (???..???)>!>! but Matcher<IntArray!>! was expected

Why is that?

PS: I'm not interested in suggestions of alternate frameworks.


Solution

  • Answering my own question (as I often do) the correct code is:

    import org.hamcrest.MatcherAssert.assertThat
    import org.hamcrest.collection.IsArrayWithSize.arrayWithSize
    import org.hamcrest.core.IsEqual.equalTo
    import org.hamcrest.core.Is.`is` as Is
    …
         val parts = intArrayOf(1, 2, 3)
         assertThat(/* actual = */ parts.toTypedArray(), /* matcher = */ arrayWithSize(3))
         assertThat(/* actual = */ parts.toTypedArray(), /* matcher = */ Is(arrayWithSize(3)))
         assertThat(/* actual = */ parts.toTypedArray(), /* matcher = */ Is(arrayWithSize(equalTo(3))))
    

    That conversion is quite the performance killer but in a unit test I don't care. If I ever come around to converting the main source from java to kotlin stuff like this might hurt.