Carter
08/30/2023, 6:13 PMList
constructor arguments and verify they are actually ImmutableList
. One trouble I seem to have is that withRepresentedTypeOf doesn’t seem to match List, so I experimented matching the class name instead.
This kind of works but doesn’t seem quite like the right approach. Is there a better way to do this?
Konsist.scopeFromProject()
.classes()
// Skip serializable classes, because immutable collections aren't serializable by default
.withoutSomeAnnotationsOf(kotlinx.serialization.Serializable::class)
.flatMap { it.constructors }
.flatMap { it.parameters }
.filter {
it.type.name.startsWith(List::class.java.simpleName)
}
.assert { it.representsTypeOf<ImmutableList<*>>() }
igor.wojda
08/31/2023, 3:45 PMendsWith
/ contains
instead of startsWith
(see Debug Konsist Test to understand what going on)
2. Regarding the assertion My guess is that <*>
inside does not behave as you expect - in kotlin *
means any type, but Konsist is just comparing strings, so you will compare ImmutableList<SomeType> == ImmutableList<*>
which will be false.
assert { it.type.name.startsWith("ImmutableList") }
Thats being said I am guessing here - please share your Kotlin code snippet you want to verify - best would be containing one ore more correct and incorrect types. This will help me to understand what exactly you want to test.Carter
08/31/2023, 3:46 PMdata class SomeClass(val: List<Elt>)
Preferring:
data class SomeClass(val: ImmutableList<Elt>)
Carter
08/31/2023, 3:48 PMval mutableList = mutableListOf(a, b, c)
val someClass = SomeClass(mutableList)
mutableList.clear()
Although Kotlin is better than Java with default immutability of the List interface, the fact the mutable implementations are subclasses means certain bugs can still persistCarter
08/31/2023, 3:48 PMigor.wojda
08/31/2023, 3:54 PMrepresentsType
as they are erashed in runtime (type erasure), so type name will not match. In this case you have to relay on string comparision.
I think for you case all you need it to check is that the List
type is not used for constructor parameters:
Konsist.scopeFromProject()
.classes()
// Skip serializable classes, because immutable collections aren't serializable by default
.withoutSomeAnnotationsOf(kotlinx.serialization.Serializable::class)
.flatMap { it.constructors }
.flatMap { it.parameters }
.assertNot {
it.type.name.startsWith("List<")
}
Carter
08/31/2023, 3:55 PMCarter
08/31/2023, 3:57 PMigor.wojda
08/31/2023, 3:59 PMigor.wojda
08/31/2023, 4:06 PM.assertNot {
val regex = """.*List.*""".toRegex()
it.type.hasNameMatching(regex)
}
In the future I am planning to introduce more advanced checks - these will allows to verify entire inheritance hierarchy (not only types from a single file). You would be able to express things like "is child of List class"Carter
08/31/2023, 4:56 PMwhen you notice during PR review that devs are making certain mistakesAt the moment I’m protecting against myself 😂.