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:
commit
b94b384270
7 changed files with 87 additions and 19 deletions
|
|
@ -52,6 +52,10 @@ allprojects {
|
||||||
detektPlugins("io.nlopez.compose.rules:detekt:0.4.19")
|
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
|
// KtLint
|
||||||
apply {
|
apply {
|
||||||
plugin("org.jlleitschuh.gradle.ktlint")
|
plugin("org.jlleitschuh.gradle.ktlint")
|
||||||
|
|
@ -75,6 +79,7 @@ allprojects {
|
||||||
val generatedPath = "${layout.buildDirectory.asFile.get()}/generated/"
|
val generatedPath = "${layout.buildDirectory.asFile.get()}/generated/"
|
||||||
filter {
|
filter {
|
||||||
exclude { element -> element.file.path.contains(generatedPath) }
|
exclude { element -> element.file.path.contains(generatedPath) }
|
||||||
|
exclude("io/element/android/tests/konsist/failures/**")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dependency check
|
// Dependency check
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ test_arch_core = "androidx.arch.core:core-testing:2.2.0"
|
||||||
test_junit = "junit:junit:4.13.2"
|
test_junit = "junit:junit:4.13.2"
|
||||||
test_runner = "androidx.test:runner:1.6.2"
|
test_runner = "androidx.test:runner:1.6.2"
|
||||||
test_mockk = "io.mockk:mockk:1.13.13"
|
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_turbine = "app.cash.turbine:turbine:1.2.0"
|
||||||
test_truth = "com.google.truth:truth:1.4.4"
|
test_truth = "com.google.truth:truth:1.4.4"
|
||||||
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.18"
|
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.18"
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ fun Project.setupKover() {
|
||||||
"io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
|
"io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
|
||||||
// Test presenters
|
// Test presenters
|
||||||
"io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter",
|
"io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter",
|
||||||
|
// Konsist code to make test fails
|
||||||
|
"io.element.android.tests.konsist.failures",
|
||||||
)
|
)
|
||||||
annotatedBy(
|
annotatedBy(
|
||||||
"androidx.compose.ui.tooling.preview.Preview",
|
"androidx.compose.ui.tooling.preview.Preview",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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.ext.list.withoutParents
|
||||||
import com.lemonappdev.konsist.api.verify.assertEmpty
|
import com.lemonappdev.konsist.api.verify.assertEmpty
|
||||||
import com.lemonappdev.konsist.api.verify.assertTrue
|
import com.lemonappdev.konsist.api.verify.assertTrue
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class KonsistArchitectureTest {
|
class KonsistArchitectureTest {
|
||||||
|
|
@ -66,34 +67,44 @@ class KonsistArchitectureTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Sealed interface used in Composable MUST be Immutable or Stable`() {
|
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
|
// List all sealed interface without Immutable nor Stable annotation in the project
|
||||||
val forbiddenInterfacesForComposableParameter = Konsist.scopeFromProject()
|
val forbiddenInterfacesForComposableParameter = Konsist.scopeFromProject()
|
||||||
.interfaces()
|
.interfaces()
|
||||||
.withSealedModifier()
|
.withSealedModifier()
|
||||||
.withoutAnnotationOf(Immutable::class, Stable::class)
|
.withoutAnnotationOf(Immutable::class, Stable::class)
|
||||||
.map { it.fullyQualifiedName }
|
.map { it.fullyQualifiedName }
|
||||||
|
|
||||||
Konsist.scopeFromProject()
|
Konsist.scopeFromProject()
|
||||||
.functions()
|
.functions()
|
||||||
.withAnnotationOf(Composable::class)
|
.withAnnotationOf(Composable::class)
|
||||||
.assertTrue(additionalMessage = "Consider adding the @Immutable or @Stable annotation to the sealed interface") {
|
.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
|
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
|
true
|
||||||
} else {
|
} else {
|
||||||
var typePackage = param.type.declaration.packagee?.name
|
val typePackage = param.type.sourceDeclaration?.let { declaration ->
|
||||||
if (typePackage == type) {
|
declaration.asTypeParameterDeclaration()?.packagee
|
||||||
// Workaround, now that packagee.fullyQualifiedName is not available anymore
|
?: declaration.asExternalDeclaration()?.packagee
|
||||||
// It seems that when the type in in the same package as the function,
|
?: declaration.asClassOrInterfaceDeclaration()?.packagee
|
||||||
// the package is equal to the type (which is wrong).
|
?: declaration.asKotlinTypeDeclaration()?.packagee
|
||||||
// So in this case, use the package of the function
|
?: declaration.asObjectDeclaration()?.packagee
|
||||||
typePackage = it.packagee?.name
|
}?.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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,11 @@ class KonsistClassNameTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Fake classes must be named using Fake and the interface it fakes`() {
|
fun `Fake classes must be named using Fake and the interface it fakes`() {
|
||||||
|
var failingCases = 0
|
||||||
|
val failingCasesList = listOf(
|
||||||
|
"FakeWrongClassName",
|
||||||
|
"FakeWrongClassSubInterfaceName",
|
||||||
|
)
|
||||||
Konsist.scopeFromProject()
|
Konsist.scopeFromProject()
|
||||||
.classes()
|
.classes()
|
||||||
.withNameContaining("Fake")
|
.withNameContaining("Fake")
|
||||||
|
|
@ -84,16 +89,19 @@ class KonsistClassNameTest {
|
||||||
val interfaceName = it.name
|
val interfaceName = it.name
|
||||||
.replace("FakeRust", "")
|
.replace("FakeRust", "")
|
||||||
.replace("Fake", "")
|
.replace("Fake", "")
|
||||||
(it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) &&
|
val result = (it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) &&
|
||||||
it.parents().any { parent ->
|
it.parents().any { parent ->
|
||||||
// Workaround to get the parent name. For instance:
|
val parentName = parent.name.replace(".", "")
|
||||||
// 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(".", "")
|
|
||||||
parentName == interfaceName
|
parentName == interfaceName
|
||||||
}
|
}
|
||||||
|
if (!result && it.name in failingCasesList) {
|
||||||
|
failingCases++
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
assertThat(failingCases).isEqualTo(failingCasesList.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue