[KPM] IdeaKotlinProjectModelObjectGraphTest: Include subtypes when resolving nodes

KT-51386
This commit is contained in:
sebastian.sellmair
2022-02-18 16:09:51 +01:00
committed by Space
parent 2be85610a3
commit 1e5d398d6e
@@ -23,8 +23,6 @@ import kotlin.test.assertTrue
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class IdeaKotlinProjectModelObjectGraphTest(private val node: KClass<*>, @Suppress("unused_parameter") clazzName: String) { class IdeaKotlinProjectModelObjectGraphTest(private val node: KClass<*>, @Suppress("unused_parameter") clazzName: String) {
private val reflections = Reflections("org.jetbrains.kotlin")
@Test @Test
fun `test - node implements Serializable`() { fun `test - node implements Serializable`() {
assertTrue( assertTrue(
@@ -35,50 +33,38 @@ class IdeaKotlinProjectModelObjectGraphTest(private val node: KClass<*>, @Suppre
@Test @Test
fun `test - node implementations contain serialVersionUID`() { fun `test - node implementations contain serialVersionUID`() {
val implementations = reflections.getSubTypesOf(node.java).plus(node.java) if (!node.java.isInterface && !Modifier.isAbstract(node.java.modifiers)) {
.filter { subtype -> !subtype.isInterface && !Modifier.isAbstract(subtype.modifiers) }
assertTrue(
implementations.isNotEmpty(),
"No implementations found for $node"
)
implementations.forEach { implementation -> assertNodeImplementationDefinesSerialVersionUID(implementation) }
}
@Test
fun `test - node implementations are marked with InternalKotlinGradlePluginApi when data class`() {
reflections.getSubTypesOf(node.java).plus(node.java)
.filter { subtype -> subtype.kotlin.isData && subtype.kotlin.visibility == PUBLIC }
.forEach { dataClass ->
assertTrue(
dataClass.annotations.any { it.annotationClass.simpleName == "InternalKotlinGradlePluginApi" },
"Expected $dataClass to be annotated with '@InternalKotlinGradlePluginApi'"
)
}
}
private fun assertNodeImplementationDefinesSerialVersionUID(implementationClass: Class<*>) {
val serialVersionUID = assertNotNull( val serialVersionUID = assertNotNull(
implementationClass.getDeclaredFieldOrNull("serialVersionUID"), node.java.getDeclaredFieldOrNull("serialVersionUID"),
"Expected $implementationClass to declare 'serialVersionUID' field" "Expected $node to declare 'serialVersionUID' field"
) )
assertTrue( assertTrue(
Modifier.isStatic(serialVersionUID.modifiers), Modifier.isStatic(serialVersionUID.modifiers),
"Expected $implementationClass to declare 'serialVersionUID' statically" "Expected $node to declare 'serialVersionUID' statically"
) )
assertTrue( assertTrue(
serialVersionUID.type.isPrimitive, serialVersionUID.type.isPrimitive,
"Expected $implementationClass to declare primitive 'serialVersionUID'" "Expected $node to declare primitive 'serialVersionUID'"
) )
assertEquals( assertEquals(
serialVersionUID.type, Long::class.javaPrimitiveType, serialVersionUID.type, Long::class.javaPrimitiveType,
"Expected $implementationClass to declare 'serialVersionUID' of type Long" "Expected $node to declare 'serialVersionUID' of type Long"
) )
} }
}
@Test
fun `test - node implementations are marked with InternalKotlinGradlePluginApi when data class`() {
if (node.isData && node.visibility == PUBLIC) {
assertTrue(
node.annotations.any { it.annotationClass.simpleName == "InternalKotlinGradlePluginApi" },
"Expected $node to be annotated with '@InternalKotlinGradlePluginApi'"
)
}
}
private fun Class<*>.getDeclaredFieldOrNull(name: String): Field? { private fun Class<*>.getDeclaredFieldOrNull(name: String): Field? {
return try { return try {
@@ -89,6 +75,8 @@ class IdeaKotlinProjectModelObjectGraphTest(private val node: KClass<*>, @Suppre
} }
companion object { companion object {
private val reflections = Reflections("org.jetbrains.kotlin")
@JvmStatic @JvmStatic
@Parameterized.Parameters(name = "{1}") @Parameterized.Parameters(name = "{1}")
fun findNodes(): List<Array<Any>> { fun findNodes(): List<Array<Any>> {
@@ -100,6 +88,12 @@ class IdeaKotlinProjectModelObjectGraphTest(private val node: KClass<*>, @Suppre
children.forEach { child -> children.forEach { child ->
if (classes.add(child)) { if (classes.add(child)) {
resolveQueue.add(child) resolveQueue.add(child)
if (child.java.isInterface || Modifier.isAbstract(child.java.modifiers)) {
val subtypes = reflections.getSubTypesOf(child.java).map { it.kotlin }
assertTrue(subtypes.isNotEmpty(), "Missing implementations for $child")
classes.addAll(subtypes)
resolveQueue.addAll(subtypes)
}
} }
} }
} }