Skip to content

Commit cd2a320

Browse files
committed
Align JVM- and KLib-validation behavior for empty projects
Also, reworked error reporting for the compare task.
1 parent 69f94f3 commit cd2a320

File tree

4 files changed

+59
-39
lines changed

4 files changed

+59
-39
lines changed

src/functionalTest/kotlin/kotlinx/validation/test/DefaultConfigTests.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() {
2626
}
2727
}
2828

29+
val projectName = rootProjectDir.name
2930
runner.buildAndFail().apply {
30-
assertTrue { output.contains("Please ensure that ':apiDump' was executed") }
31+
Assertions.assertThat(output).contains(
32+
"Expected file with API declarations 'api/$projectName.api' does not exist."
33+
).contains(
34+
"Please ensure that ':apiDump' was executed in order to get an API dump to compare the build against"
35+
)
3136
assertTaskFailure(":apiCheck")
3237
}
3338
}

src/functionalTest/kotlin/kotlinx/validation/test/KlibVerificationTests.kt

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import org.gradle.testkit.runner.BuildResult
1414
import org.jetbrains.kotlin.konan.target.HostManager
1515
import org.jetbrains.kotlin.konan.target.KonanTarget
1616
import org.jetbrains.kotlin.utils.addToStdlib.butIf
17+
import org.junit.Assert
1718
import org.junit.Assume
1819
import org.junit.Test
1920
import java.io.File
@@ -49,27 +50,32 @@ internal class KlibVerificationTests : BaseKotlinGradleTest() {
4950
resolve("/examples/gradle/base/withNativePlugin.gradle.kts")
5051
}
5152
}
53+
5254
private fun BaseKotlinScope.additionalBuildConfig(config: String) {
5355
buildGradleKts {
5456
resolve(config)
5557
}
5658
}
59+
5760
private fun BaseKotlinScope.addToSrcSet(pathTestFile: String, sourceSet: String = "commonMain") {
5861
val fileName = Paths.get(pathTestFile).fileName.toString()
5962
kotlin(fileName, sourceSet) {
6063
resolve(pathTestFile)
6164
}
6265
}
66+
6367
private fun BaseKotlinScope.runApiCheck() {
6468
runner {
6569
arguments.add(":apiCheck")
6670
}
6771
}
72+
6873
private fun BaseKotlinScope.runApiDump() {
6974
runner {
7075
arguments.add(":apiDump")
7176
}
7277
}
78+
7379
private fun assertApiCheckPassed(buildResult: BuildResult) {
7480
buildResult.assertTaskSuccess(":apiCheck")
7581
}
@@ -603,8 +609,10 @@ internal class KlibVerificationTests : BaseKotlinGradleTest() {
603609
checkKlibDump(runner.build(), "/examples/classes/AnotherBuildConfig.klib.dump")
604610

605611
// Update the source file by adding a declaration
606-
val updatedSourceFile = File(this::class.java.getResource(
607-
"/examples/classes/AnotherBuildConfigModified.kt")!!.toURI()
612+
val updatedSourceFile = File(
613+
this::class.java.getResource(
614+
"/examples/classes/AnotherBuildConfigModified.kt"
615+
)!!.toURI()
608616
)
609617
val existingSource = runner.projectDir.resolve(
610618
"src/commonMain/kotlin/AnotherBuildConfig.kt"
@@ -624,8 +632,10 @@ internal class KlibVerificationTests : BaseKotlinGradleTest() {
624632
checkKlibDump(runner.build(), "/examples/classes/AnotherBuildConfig.klib.dump")
625633

626634
// Update the source file by adding a declaration
627-
val updatedSourceFile = File(this::class.java.getResource(
628-
"/examples/classes/AnotherBuildConfigLinuxArm64.kt")!!.toURI()
635+
val updatedSourceFile = File(
636+
this::class.java.getResource(
637+
"/examples/classes/AnotherBuildConfigLinuxArm64.kt"
638+
)!!.toURI()
629639
)
630640
val existingSource = runner.projectDir.resolve(
631641
"src/linuxArm64Main/kotlin/AnotherBuildConfigLinuxArm64.kt"
@@ -649,8 +659,10 @@ internal class KlibVerificationTests : BaseKotlinGradleTest() {
649659
assertApiCheckPassed(runner.build())
650660

651661
// Update the source file by adding a declaration
652-
val updatedSourceFile = File(this::class.java.getResource(
653-
"/examples/classes/AnotherBuildConfigModified.kt")!!.toURI()
662+
val updatedSourceFile = File(
663+
this::class.java.getResource(
664+
"/examples/classes/AnotherBuildConfigModified.kt"
665+
)!!.toURI()
654666
)
655667
val existingSource = runner.projectDir.resolve(
656668
"src/commonMain/kotlin/AnotherBuildConfig.kt"
@@ -723,13 +735,18 @@ internal class KlibVerificationTests : BaseKotlinGradleTest() {
723735
}
724736

725737
@Test
726-
fun `apiCheck should not fail for empty project`() {
738+
fun `apiCheck should fail for empty project`() {
727739
val runner = test {
728740
baseProjectSetting()
729741
addToSrcSet("/examples/classes/AnotherBuildConfig.kt", sourceSet = "commonTest")
730742
runApiCheck()
731743
}
732-
runner.build()
744+
runner.buildAndFail().apply {
745+
assertTaskFailure(":klibApiExtractForValidation")
746+
Assertions.assertThat(output).contains(
747+
"File with project's API declarations 'api/testproject.klib.api' does not exist."
748+
)
749+
}
733750
}
734751

735752
@Test

src/main/kotlin/KotlinApiCompareTask.kt

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@ import org.gradle.api.file.RegularFileProperty
1414
import org.gradle.api.tasks.*
1515

1616
@CacheableTask
17-
public open class KotlinApiCompareTask @Inject constructor(): DefaultTask() {
17+
public open class KotlinApiCompareTask @Inject constructor() : DefaultTask() {
1818

19-
@get:InputFiles
20-
@get:SkipWhenEmpty
19+
@get:InputFiles // don't fail the task if file does not exist, instead print custom error message from verify()
2120
@get:PathSensitive(PathSensitivity.RELATIVE)
2221
public val projectApiFile: RegularFileProperty = project.objects.fileProperty()
2322

24-
@get:InputFiles
25-
@get:SkipWhenEmpty
23+
@get:InputFiles // don't fail the task if file does not exist, instead print custom error message from verify()
2624
@get:PathSensitive(PathSensitivity.RELATIVE)
2725
public val generatedApiFile: RegularFileProperty = project.objects.fileProperty()
2826

@@ -35,51 +33,46 @@ public open class KotlinApiCompareTask @Inject constructor(): DefaultTask() {
3533
val projectApiFile = projectApiFile.get().asFile
3634
val generatedApiFile = generatedApiFile.get().asFile
3735

38-
val projectApiDir = projectApiFile.parentFile
39-
if (!projectApiDir.exists()) {
40-
error("Expected folder with API declarations '$projectApiDir' does not exist.\n" +
41-
"Please ensure that ':apiDump' was executed in order to get API dump to compare the build against")
42-
}
43-
val buildApiDir = generatedApiFile.parentFile
44-
if (!buildApiDir.exists()) {
45-
error("Expected folder with generate API declarations '$buildApiDir' does not exist.")
46-
}
47-
val subject = projectName
48-
4936
if (!projectApiFile.exists()) {
50-
error("File ${projectApiFile.name} is missing from ${projectApiDir.relativeDirPath()}, please run " +
51-
":$subject:apiDump task to generate one")
37+
error(
38+
"Expected file with API declarations '${projectApiFile.relativeTo(rootDir)}' does not exist.\n" +
39+
"Please ensure that ':apiDump' was executed in order to get " +
40+
"an API dump to compare the build against"
41+
)
5242
}
5343
if (!generatedApiFile.exists()) {
54-
error("File ${generatedApiFile.name} is missing from dump results.")
44+
error(
45+
"Expected file with generated API declarations '${generatedApiFile.relativeTo(rootDir)}'" +
46+
" does not exist."
47+
)
5548
}
5649

57-
// Normalize case-sensitivity
5850
val diffSet = mutableSetOf<String>()
5951
val diff = compareFiles(projectApiFile, generatedApiFile)
6052
if (diff != null) diffSet.add(diff)
6153
if (diffSet.isNotEmpty()) {
6254
val diffText = diffSet.joinToString("\n\n")
63-
error("API check failed for project $subject.\n$diffText\n\n You can run :$subject:apiDump task to overwrite API declarations")
55+
val subject = projectName
56+
error(
57+
"API check failed for project $subject.\n$diffText\n\n" +
58+
"You can run :$subject:apiDump task to overwrite API declarations"
59+
)
6460
}
6561
}
6662

67-
private fun File.relativeDirPath(): String {
68-
return toRelativeString(rootDir) + File.separator
69-
}
70-
7163
private fun compareFiles(checkFile: File, builtFile: File): String? {
7264
val checkText = checkFile.readText()
7365
val builtText = builtFile.readText()
7466

75-
// We don't compare full text because newlines on Windows & Linux/macOS are different
67+
// We don't compare a full text because newlines on Windows & Linux/macOS are different
7668
val checkLines = checkText.lines()
7769
val builtLines = builtText.lines()
7870
if (checkLines == builtLines)
7971
return null
8072

8173
val patch = DiffUtils.diff(checkLines, builtLines)
82-
val diff = UnifiedDiffUtils.generateUnifiedDiff(checkFile.toString(), builtFile.toString(), checkLines, patch, 3)
74+
val diff =
75+
UnifiedDiffUtils.generateUnifiedDiff(checkFile.toString(), builtFile.toString(), checkLines, patch, 3)
8376
return diff.joinToString("\n")
8477
}
8578
}

src/main/kotlin/KotlinKlibExtractAbiTask.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public abstract class KotlinKlibExtractAbiTask : DefaultTask() {
2525
/**
2626
* Merged KLib dump that should be filtered by this task.
2727
*/
28-
@get:InputFiles
28+
@get:InputFiles // don't fail the task if file does not exist, instead print custom error message from generate()
2929
@get:PathSensitive(PathSensitivity.RELATIVE)
3030
public abstract val inputAbiFile: RegularFileProperty
3131

@@ -47,13 +47,18 @@ public abstract class KotlinKlibExtractAbiTask : DefaultTask() {
4747
@get:OutputFile
4848
public abstract val outputAbiFile: RegularFileProperty
4949

50+
private val rootDir = project.rootDir
51+
5052
@OptIn(ExperimentalBCVApi::class)
5153
@TaskAction
5254
internal fun generate() {
5355
val inputFile = inputAbiFile.asFile.get()
54-
if (!inputFile.exists()) return
56+
if (!inputFile.exists()) {
57+
error("File with project's API declarations '${inputFile.relativeTo(rootDir)}' does not exist.\n" +
58+
"Please ensure that ':apiDump' was executed in order to get API dump to compare the build against")
59+
}
5560
if (inputFile.length() == 0L) {
56-
error("Project ABI file $inputAbiFile is empty.")
61+
error("Project ABI file ${inputFile.relativeTo(rootDir)} is empty.")
5762
}
5863
val dump = KlibDump.from(inputFile)
5964
val enabledTargets = requiredTargets.get().map(KlibTarget::targetName).toSet()

0 commit comments

Comments
 (0)