Merge pull request #3947 from element-hq/renovate/com.lemonappdev-konsist-0.x

Update dependency com.lemonappdev:konsist to v0.17.0
This commit is contained in:
Benoit Marty
2024-11-26 18:00:59 +01:00
committed by GitHub
7 changed files with 87 additions and 19 deletions

View File

@@ -52,6 +52,10 @@ allprojects {
detektPlugins("io.nlopez.compose.rules:detekt:0.4.19")
}
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
exclude("io/element/android/tests/konsist/failures/**")
}
// KtLint
apply {
plugin("org.jlleitschuh.gradle.ktlint")
@@ -75,6 +79,7 @@ allprojects {
val generatedPath = "${layout.buildDirectory.asFile.get()}/generated/"
filter {
exclude { element -> element.file.path.contains(generatedPath) }
exclude("io/element/android/tests/konsist/failures/**")
}
}
// Dependency check

View File

@@ -150,7 +150,7 @@ test_arch_core = "androidx.arch.core:core-testing:2.2.0"
test_junit = "junit:junit:4.13.2"
test_runner = "androidx.test:runner:1.6.2"
test_mockk = "io.mockk:mockk:1.13.13"
test_konsist = "com.lemonappdev:konsist:0.16.1"
test_konsist = "com.lemonappdev:konsist:0.17.0"
test_turbine = "app.cash.turbine:turbine:1.2.0"
test_truth = "com.google.truth:truth:1.4.4"
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.18"

View File

@@ -98,6 +98,8 @@ fun Project.setupKover() {
"io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
// Test presenters
"io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter",
// Konsist code to make test fails
"io.element.android.tests.konsist.failures",
)
annotatedBy(
"androidx.compose.ui.tooling.preview.Preview",

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.tests.konsist.failures
import androidx.compose.runtime.Composable
// Make test `Sealed interface used in Composable MUST be Immutable or Stable` fails
sealed interface SealedInterface
@Composable
fun FailingComposableWithNonImmutableSealedInterface(
sealedInterface: SealedInterface
) {
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.tests.konsist.failures
// Make test `Fake classes must be named using Fake and the interface it fakes` fails
interface MyInterface
// This class should be named FakeMyInterface
class FakeWrongClassName : MyInterface
class MyClass {
interface MyFactory
}
// This class should be named FakeMyClassMyFactory
class FakeWrongClassSubInterfaceName : MyClass.MyFactory

View File

@@ -22,6 +22,7 @@ import com.lemonappdev.konsist.api.ext.list.withoutName
import com.lemonappdev.konsist.api.ext.list.withoutParents
import com.lemonappdev.konsist.api.verify.assertEmpty
import com.lemonappdev.konsist.api.verify.assertTrue
import org.junit.Assert.assertTrue
import org.junit.Test
class KonsistArchitectureTest {
@@ -66,34 +67,44 @@ class KonsistArchitectureTest {
@Test
fun `Sealed interface used in Composable MUST be Immutable or Stable`() {
var failingTestFound = false
// List all sealed interface without Immutable nor Stable annotation in the project
val forbiddenInterfacesForComposableParameter = Konsist.scopeFromProject()
.interfaces()
.withSealedModifier()
.withoutAnnotationOf(Immutable::class, Stable::class)
.map { it.fullyQualifiedName }
Konsist.scopeFromProject()
.functions()
.withAnnotationOf(Composable::class)
.assertTrue(additionalMessage = "Consider adding the @Immutable or @Stable annotation to the sealed interface") {
it.parameters.all { param ->
val result = it.parameters.all { param ->
val type = param.type.text
return@all if (type.startsWith("@") || type.startsWith("(") || type.startsWith("suspend")) {
return@all if (type.startsWith("@") || type.contains("->") || type.startsWith("suspend")) {
true
} else {
var typePackage = param.type.declaration.packagee?.name
if (typePackage == type) {
// Workaround, now that packagee.fullyQualifiedName is not available anymore
// It seems that when the type in in the same package as the function,
// the package is equal to the type (which is wrong).
// So in this case, use the package of the function
typePackage = it.packagee?.name
val typePackage = param.type.sourceDeclaration?.let { declaration ->
declaration.asTypeParameterDeclaration()?.packagee
?: declaration.asExternalDeclaration()?.packagee
?: declaration.asClassOrInterfaceDeclaration()?.packagee
?: declaration.asKotlinTypeDeclaration()?.packagee
?: declaration.asObjectDeclaration()?.packagee
}?.name
if (typePackage == null) {
false
} else {
val fullyQualifiedName = "$typePackage.$type"
fullyQualifiedName !in forbiddenInterfacesForComposableParameter
}
val fullyQualifiedName = "$typePackage.$type"
fullyQualifiedName !in forbiddenInterfacesForComposableParameter
}
}
if (!result && !failingTestFound && it.name == "FailingComposableWithNonImmutableSealedInterface") {
failingTestFound = true
true
} else {
result
}
}
assertTrue("FailingComposableWithNonImmutableSealedInterface should make this test fail.", failingTestFound)
}
}

View File

@@ -73,6 +73,11 @@ class KonsistClassNameTest {
@Test
fun `Fake classes must be named using Fake and the interface it fakes`() {
var failingCases = 0
val failingCasesList = listOf(
"FakeWrongClassName",
"FakeWrongClassSubInterfaceName",
)
Konsist.scopeFromProject()
.classes()
.withNameContaining("Fake")
@@ -84,16 +89,19 @@ class KonsistClassNameTest {
val interfaceName = it.name
.replace("FakeRust", "")
.replace("Fake", "")
(it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) &&
val result = (it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) &&
it.parents().any { parent ->
// Workaround to get the parent name. For instance:
// parent.name used to return `UserListPresenter.Factory` but is now returning `Factory`.
// So we need to retrieve the name of the parent class differently.
val packageName = parent.packagee!!.name
val parentName = parent.fullyQualifiedName!!.substringAfter("$packageName.").replace(".", "")
val parentName = parent.name.replace(".", "")
parentName == interfaceName
}
if (!result && it.name in failingCasesList) {
failingCases++
true
} else {
result
}
}
assertThat(failingCases).isEqualTo(failingCasesList.size)
}
@Test