[Gradle] Implement IdeaKotlinObjectGraphTest and fix discovered issues
KT-54825
This commit is contained in:
committed by
Space Team
parent
9771e57951
commit
224a237385
-1
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.gradle.idea.proto.generated.kpm.IdeaKpmDependencyPro
|
||||
import org.jetbrains.kotlin.gradle.idea.proto.generated.kpm.IdeaKpmDependencyProto.DependencyCase
|
||||
import org.jetbrains.kotlin.gradle.idea.proto.generated.kpm.ideaKpmDependencyProto
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaSerializationContext
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.*
|
||||
|
||||
internal fun IdeaSerializationContext.IdeaKpmDependencyProto(dependency: IdeaKpmDependency): IdeaKpmDependencyProto {
|
||||
return ideaKpmDependencyProto {
|
||||
|
||||
+10
-2
@@ -17,10 +17,18 @@ data class IdeaKotlinResolvedBinaryDependency(
|
||||
val binaryFile: File,
|
||||
override val extras: MutableExtras,
|
||||
override val coordinates: IdeaKotlinBinaryCoordinates?
|
||||
) : IdeaKotlinBinaryDependency()
|
||||
) : IdeaKotlinBinaryDependency() {
|
||||
internal companion object {
|
||||
const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
|
||||
data class IdeaKotlinUnresolvedBinaryDependency(
|
||||
val cause: String?,
|
||||
override val coordinates: IdeaKotlinBinaryCoordinates?,
|
||||
override val extras: MutableExtras
|
||||
) : IdeaKotlinBinaryDependency()
|
||||
) : IdeaKotlinBinaryDependency() {
|
||||
internal companion object {
|
||||
const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -5,7 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.idea.tcs
|
||||
|
||||
sealed interface IdeaKotlinDependencyCoordinates
|
||||
import java.io.Serializable
|
||||
|
||||
sealed interface IdeaKotlinDependencyCoordinates : Serializable
|
||||
|
||||
data class IdeaKotlinBinaryCoordinates(
|
||||
val group: String,
|
||||
@@ -16,6 +18,11 @@ data class IdeaKotlinBinaryCoordinates(
|
||||
override fun toString(): String {
|
||||
return "$group:$module:$version${sourceSetName?.let { ":$it" }.orEmpty()}"
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val serialVersionUID = 0L
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class IdeaKotlinSourceCoordinates(
|
||||
@@ -27,4 +34,8 @@ data class IdeaKotlinSourceCoordinates(
|
||||
override fun toString(): String {
|
||||
return "${buildId.takeIf { it != ":" }.orEmpty()}$projectPath/$sourceSetName"
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -14,6 +14,14 @@ data class IdeaKotlinSourceDependency(
|
||||
override val extras: MutableExtras
|
||||
) : IdeaKotlinDependency {
|
||||
enum class Type : Serializable {
|
||||
Regular, Friend, DependsOn
|
||||
Regular, Friend, DependsOn;
|
||||
|
||||
internal companion object {
|
||||
const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.idea.tcs
|
||||
|
||||
import org.jetbrains.kotlin.tooling.core.AbstractExtras
|
||||
import org.jetbrains.kotlin.tooling.core.Extras
|
||||
import org.jetbrains.kotlin.tooling.core.MutableExtras
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import org.junit.runners.Parameterized.Parameters
|
||||
import org.reflections.Reflections
|
||||
import org.reflections.scanners.Scanners
|
||||
import java.io.Serializable
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class IdeaKotlinObjectGraphTest(private val node: KClass<*>, private val clazzName: String) {
|
||||
|
||||
@Test
|
||||
fun `test - node implements Serializable`() {
|
||||
assertTrue(
|
||||
Serializable::class.java.isAssignableFrom(node.java),
|
||||
"Expected clazz $clazzName to implement ${Serializable::class.qualifiedName}`"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - node is sealed`() {
|
||||
if (node.java.isInterface || node.isAbstract) {
|
||||
assertTrue(node.isSealed, "Expected $clazzName to be sealed")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - node implementations contain serialVersionUID`() {
|
||||
if (!node.java.isInterface && !Modifier.isAbstract(node.java.modifiers)) {
|
||||
val serialVersionUID = assertNotNull(
|
||||
node.java.getDeclaredFieldOrNull("serialVersionUID"),
|
||||
"Expected $node to declare 'serialVersionUID' field"
|
||||
)
|
||||
|
||||
assertTrue(
|
||||
Modifier.isStatic(serialVersionUID.modifiers),
|
||||
"Expected $node to declare 'serialVersionUID' statically"
|
||||
)
|
||||
|
||||
assertTrue(
|
||||
serialVersionUID.type.isPrimitive,
|
||||
"Expected $node to declare primitive 'serialVersionUID'"
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
serialVersionUID.type, Long::class.javaPrimitiveType,
|
||||
"Expected $node to declare 'serialVersionUID' of type Long"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Class<*>.getDeclaredFieldOrNull(name: String): Field? {
|
||||
return try {
|
||||
getDeclaredField(name)
|
||||
} catch (t: NoSuchFieldException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val reflections = Reflections("org.jetbrains.kotlin")
|
||||
private val ideaTcsReflections = Reflections("org.jetbrains.kotlin.gradle.idea.tcs")
|
||||
private val ignoredNodes = setOf(
|
||||
/*
|
||||
Extras interface and AbstractExtras are okay for now:
|
||||
Let's check known implementations for correctness
|
||||
*/
|
||||
Extras::class, MutableExtras::class, AbstractExtras::class
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Parameters(name = "{1}")
|
||||
fun findClasses(): List<Array<Any>> {
|
||||
val classes = mutableSetOf<KClass<*>>()
|
||||
|
||||
val resolveQueue = ArrayDeque<KClass<*>>()
|
||||
|
||||
resolveQueue += ideaTcsReflections.getAll(Scanners.SubTypes)
|
||||
.map { Class.forName(it) }
|
||||
.filter { it.name.startsWith("org.jetbrains.kotlin.gradle.idea.tcs") }
|
||||
.map { it.kotlin }
|
||||
|
||||
while (resolveQueue.isNotEmpty()) {
|
||||
val next = resolveQueue.removeFirst()
|
||||
if (!classes.add(next)) continue
|
||||
|
||||
next.resolveReachableClasses().forEach { 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")
|
||||
resolveQueue.addAll(subtypes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return classes
|
||||
.filter { it !in ignoredNodes }
|
||||
.map { clazz -> arrayOf(clazz, checkNotNull(clazz.displayName())) }
|
||||
|
||||
}
|
||||
|
||||
private fun KClass<*>.displayName() = java.name
|
||||
.removePrefix("org.jetbrains.kotlin")
|
||||
.removePrefix(".gradle")
|
||||
.removePrefix(".idea")
|
||||
.removePrefix(".tcs")
|
||||
.removePrefix(".")
|
||||
|
||||
private fun KClass<*>.resolveReachableClasses(): Set<KClass<*>> {
|
||||
return this.memberProperties
|
||||
.map { member -> member.returnType }
|
||||
.flatMap { type -> setOf(type) + type.arguments.mapNotNull { it.type } }
|
||||
.mapNotNull { type -> type.classifier as? KClass<*> }
|
||||
.filter { clazz -> clazz.java.name.startsWith("org.jetbrains") }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -8,7 +8,6 @@
|
||||
package org.jetbrains.kotlin.gradle.idea.testFixtures.kpm
|
||||
|
||||
import org.jetbrains.kotlin.gradle.idea.kpm.*
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.*
|
||||
import kotlin.test.fail
|
||||
|
||||
fun IdeaKpmProject.assertIsNotEmpty(): IdeaKpmProject = apply {
|
||||
|
||||
Reference in New Issue
Block a user