Skip to content

Commit 9178f38

Browse files
RBusarowkodiakhq[bot]
authored andcommitted
treat testFixtures and the associated main sources like different projects
fixes #286
1 parent cfa1134 commit 9178f38

File tree

4 files changed

+206
-21
lines changed

4 files changed

+206
-21
lines changed

modulecheck-api/src/main/kotlin/modulecheck/api/context/ClasspathDependencies.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ data class ClasspathDependencies(
7171
}
7272
.toSet()
7373

74-
val directPairs = directDependencies.map { TransitiveProjectDependency(it, it) }
74+
val directTransitive = directDependencies.map { TransitiveProjectDependency(it, it) }
7575

76-
return directPairs + inherited
76+
val mainFromTestFixtures = directDependencies.filter { it.isTestFixture }
77+
.map { TransitiveProjectDependency(it, it.copy(isTestFixture = false)) }
78+
79+
return directTransitive + inherited + mainFromTestFixtures
7780
}
7881

7982
companion object Key : ProjectContext.Key<ClasspathDependencies> {

modulecheck-core/src/main/kotlin/modulecheck/core/context/MustBeApi.kt

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ data class MustBeApi(
6161
// exclude anything which is inherited but already included in local `api` deps
6262
cpd in project.projectDependencies[ConfigurationName.api].orEmpty()
6363
}
64-
.filterBlocking { it.project.mustBeApiIn(importsFromDependencies) }
64+
.filterBlocking { it.project.mustBeApiIn(importsFromDependencies, it.isTestFixture) }
6565
.mapBlocking { cpd ->
6666
val source = project
6767
.projectDependencies
@@ -98,22 +98,28 @@ private suspend fun McProject.importsFromDependencies(): Set<String> {
9898
}
9999

100100
suspend fun McProject.mustBeApiIn(
101-
dependentProject: McProject
101+
dependentProject: McProject,
102+
isTestFixtures: Boolean
102103
): Boolean {
103104
val importsFromDependencies = dependentProject.importsFromDependencies()
104-
return declarations()[SourceSetName.MAIN]
105-
.orEmpty()
106-
.map { it.fqName }
107-
.any { declared -> declared in importsFromDependencies }
105+
return mustBeApiIn(importsFromDependencies, isTestFixtures)
108106
}
109107

110108
suspend fun McProject.mustBeApiIn(
111-
importsFromDependencies: Set<String>
109+
importsFromDependencies: Set<String>,
110+
isTestFixtures: Boolean
112111
): Boolean {
113-
return declarations()[SourceSetName.MAIN]
114-
.orEmpty()
115-
.map { it.fqName }
116-
.any { declared -> declared in importsFromDependencies }
112+
113+
val declarations = if (isTestFixtures) {
114+
declarations()[SourceSetName.TEST_FIXTURES]
115+
} else {
116+
declarations()[SourceSetName.MAIN]
117+
} ?: return false
118+
119+
return declarations
120+
.any { declared ->
121+
declared.fqName in importsFromDependencies
122+
}
117123
}
118124

119125
data class InheritedDependencyWithSource(

modulecheck-core/src/main/kotlin/modulecheck/core/rule/InheritedDependencyRule.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,30 +34,35 @@ class InheritedDependencyRule : ModuleCheckRule<InheritedDependencyFinding> {
3434
override suspend fun check(project: McProject): List<InheritedDependencyFinding> {
3535

3636
val mainDirectDependencies = project.projectDependencies.main()
37-
.map { it.project }
37+
.map { it.project to it.isTestFixture }
3838
.toSet()
3939

4040
val used = project.classpathDependencies().all()
41-
.filterNot { it.contributed.project in mainDirectDependencies }
42-
.distinctBy { it.contributed.project.path }
41+
.filterNot { mainDirectDependencies.contains(it.contributed.project to it.contributed.isTestFixture) }
42+
.distinctBy { it.contributed.project.path to it.contributed.isTestFixture }
4343
.filter { project.uses(it) }
4444

45-
val dependencyPathCache = mutableMapOf<SourceSetName, Set<String>>()
46-
fun pathsForSourceSet(sourceSetName: SourceSetName): Set<String> {
45+
val dependencyPathCache = mutableMapOf<SourceSetName, Set<Pair<String, Boolean>>>()
46+
fun pathsForSourceSet(sourceSetName: SourceSetName): Set<Pair<String, Boolean>> {
4747
return dependencyPathCache.getOrPut(sourceSetName) {
48-
project.projectDependencies[sourceSetName].map { it.project.path }.toSet()
48+
project.projectDependencies[sourceSetName]
49+
.map { it.project.path to it.isTestFixture }
50+
.toSet()
4951
}
5052
}
5153

5254
return used.asSequence()
53-
.filterNot { it.contributed.project.path in pathsForSourceSet(it.source.configurationName.toSourceSetName()) }
55+
.filterNot {
56+
pathsForSourceSet(it.source.configurationName.toSourceSetName())
57+
.contains((it.contributed.project.path to it.contributed.isTestFixture))
58+
}
5459
.distinct()
5560
.mapBlocking { transitive ->
5661

5762
val source = transitive.source
5863
val inherited = transitive.contributed
5964

60-
val mustBeApi = inherited.project.mustBeApiIn(project)
65+
val mustBeApi = inherited.project.mustBeApiIn(project, inherited.isTestFixture)
6166

6267
val newConfig = if (mustBeApi) {
6368
source.configurationName.apiVariant()

modulecheck-core/src/test/kotlin/modulecheck/core/InheritedDependenciesTest.kt

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ class InheritedDependenciesTest : ProjectTest() {
788788
}
789789

790790
val lib2 = project(":lib2") {
791+
addDependency("testFixturesImplementation".asConfigurationName(), lib1)
791792
addDependency("testFixturesApi".asConfigurationName(), lib1, asTestFixture = true)
792793

793794
buildFile.writeText(
@@ -797,6 +798,7 @@ class InheritedDependenciesTest : ProjectTest() {
797798
}
798799
799800
dependencies {
801+
testFixturesImplementation(project(path = ":lib1"))
800802
testFixturesApi(testFixtures(project(path = ":lib1")))
801803
}
802804
""".trimIndent()
@@ -1076,6 +1078,175 @@ class InheritedDependenciesTest : ProjectTest() {
10761078
dependency name source build file
10771079
✔ :lib1 inheritedDependency :lib2 /lib3/build.gradle.kts: (6, 3):
10781080
1081+
ModuleCheck found 3 issues
1082+
"""
1083+
}
1084+
1085+
@Test
1086+
fun `inherited main source testFixture in same module with auto-correct should be fixed as normal testImplementation`() {
1087+
1088+
val runner = ModuleCheckRunner(
1089+
autoCorrect = true,
1090+
settings = baseSettings,
1091+
findingFactory = findingFactory,
1092+
logger = logger
1093+
)
1094+
1095+
val lib1 = project(":lib1") {
1096+
addSource(
1097+
"com/modulecheck/lib1/Lib1Class.kt",
1098+
"""
1099+
package com.modulecheck.lib1
1100+
1101+
open class Lib1Class
1102+
""".trimIndent()
1103+
)
1104+
addSource(
1105+
"com/modulecheck/lib1/test/FakeLib1Class.kt",
1106+
"""
1107+
package com.modulecheck.lib1.test
1108+
1109+
import com.modulecheck.lib1.Lib1Class
1110+
1111+
open class FakeLib1Class : Lib1Class()
1112+
""".trimIndent(),
1113+
SourceSetName.TEST_FIXTURES
1114+
)
1115+
}
1116+
1117+
val lib2 = project(":lib2") {
1118+
addDependency(ConfigurationName.testImplementation, lib1, asTestFixture = true)
1119+
1120+
buildFile.writeText(
1121+
"""
1122+
plugins {
1123+
kotlin("jvm")
1124+
}
1125+
1126+
dependencies {
1127+
testImplementation(testFixtures(project(path = ":lib1")))
1128+
}
1129+
""".trimIndent()
1130+
)
1131+
addSource(
1132+
"com/modulecheck/lib2/Lib2Class.kt",
1133+
"""
1134+
package com.modulecheck.lib2
1135+
1136+
import com.modulecheck.lib1.Lib1Class
1137+
import com.modulecheck.lib1.test.FakeLib2Class
1138+
1139+
val clazz = Lib1Class()
1140+
private val clazz2 = FakeLib2Class()
1141+
""".trimIndent(),
1142+
SourceSetName.TEST
1143+
)
1144+
}
1145+
1146+
runner.run(allProjects()).isSuccess shouldBe true
1147+
1148+
lib2.buildFile.readText() shouldBe """
1149+
plugins {
1150+
kotlin("jvm")
1151+
}
1152+
1153+
dependencies {
1154+
testImplementation(project(path = ":lib1"))
1155+
testImplementation(testFixtures(project(path = ":lib1")))
1156+
}
1157+
"""
1158+
1159+
logger.collectReport()
1160+
.joinToString()
1161+
.clean() shouldBe """
1162+
:lib2
1163+
dependency name source build file
1164+
✔ :lib1 inheritedDependency /lib2/build.gradle.kts: (6, 3):
1165+
1166+
ModuleCheck found 1 issue
1167+
"""
1168+
}
1169+
1170+
@Test
1171+
fun `inherited main source testFixture in same module with auto-correct should be fixed as normal api`() {
1172+
1173+
val runner = ModuleCheckRunner(
1174+
autoCorrect = true,
1175+
settings = baseSettings,
1176+
findingFactory = findingFactory,
1177+
logger = logger
1178+
)
1179+
1180+
val lib1 = project(":lib1") {
1181+
addSource(
1182+
"com/modulecheck/lib1/Lib1Class.kt",
1183+
"""
1184+
package com.modulecheck.lib1
1185+
1186+
open class Lib1Class
1187+
""".trimIndent()
1188+
)
1189+
addSource(
1190+
"com/modulecheck/lib1/test/FakeLib1Class.kt",
1191+
"""
1192+
package com.modulecheck.lib1.test
1193+
1194+
import com.modulecheck.lib1.Lib1Class
1195+
1196+
open class FakeLib1Class : Lib1Class()
1197+
""".trimIndent(),
1198+
SourceSetName.TEST_FIXTURES
1199+
)
1200+
}
1201+
1202+
val lib2 = project(":lib2") {
1203+
addDependency(ConfigurationName.implementation, lib1, asTestFixture = true)
1204+
1205+
buildFile.writeText(
1206+
"""
1207+
plugins {
1208+
kotlin("jvm")
1209+
}
1210+
1211+
dependencies {
1212+
implementation(testFixtures(project(path = ":lib1")))
1213+
}
1214+
""".trimIndent()
1215+
)
1216+
addSource(
1217+
"com/modulecheck/lib2/Lib2Class.kt",
1218+
"""
1219+
package com.modulecheck.lib2
1220+
1221+
import com.modulecheck.lib1.Lib1Class
1222+
import com.modulecheck.lib1.test.FakeLib2Class
1223+
1224+
val clazz = Lib1Class()
1225+
private val clazz2 = FakeLib2Class()
1226+
""".trimIndent()
1227+
)
1228+
}
1229+
1230+
runner.run(allProjects()).isSuccess shouldBe true
1231+
1232+
lib2.buildFile.readText() shouldBe """
1233+
plugins {
1234+
kotlin("jvm")
1235+
}
1236+
1237+
dependencies {
1238+
api(project(path = ":lib1"))
1239+
implementation(testFixtures(project(path = ":lib1")))
1240+
}
1241+
"""
1242+
1243+
logger.collectReport()
1244+
.joinToString()
1245+
.clean() shouldBe """
1246+
:lib2
1247+
dependency name source build file
1248+
✔ :lib1 inheritedDependency /lib2/build.gradle.kts: (6, 3):
1249+
10791250
ModuleCheck found 3 issues
10801251
"""
10811252
}

0 commit comments

Comments
 (0)