Skip to content

Commit a2849f8

Browse files
authored
Added support for the IntelliJ verifier
* introduced a simple JSON converter to avoid dependencies in the plugin on third-party libraries * upgraded IntelliJ agent version to 1.0.688
1 parent 756d837 commit a2849f8

File tree

14 files changed

+937
-173
lines changed

14 files changed

+937
-173
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.kover.test.functional.cases
6+
7+
import kotlinx.kover.api.*
8+
import kotlinx.kover.test.functional.core.*
9+
import kotlinx.kover.test.functional.core.BaseGradleScriptTest
10+
import kotlin.test.*
11+
12+
internal class VerificationTests : BaseGradleScriptTest() {
13+
@Test
14+
fun testVerified() {
15+
builder("Test verification passed")
16+
.languages(GradleScriptLanguage.KOTLIN, GradleScriptLanguage.GROOVY)
17+
.engines(CoverageEngine.INTELLIJ, CoverageEngine.JACOCO)
18+
.sources("simple")
19+
.rule("test rule") {
20+
bound {
21+
minValue = 50
22+
maxValue = 60
23+
}
24+
bound {
25+
valueType = VerificationValueType.COVERED_LINES_COUNT
26+
minValue = 2
27+
maxValue = 10
28+
}
29+
}
30+
.build()
31+
.run("koverVerify")
32+
}
33+
34+
@Test
35+
fun testNotVerifiedIntelliJ() {
36+
builder("Test verification failed for IntelliJ Engine")
37+
.languages(GradleScriptLanguage.KOTLIN, GradleScriptLanguage.GROOVY)
38+
.engines(CoverageEngine.INTELLIJ)
39+
.sources("simple")
40+
.rule("test rule") {
41+
bound {
42+
minValue = 58
43+
maxValue = 60
44+
}
45+
bound {
46+
valueType = VerificationValueType.COVERED_LINES_COUNT
47+
minValue = 2
48+
maxValue = 3
49+
}
50+
}
51+
.build()
52+
.runWithError("koverVerify") {
53+
output {
54+
assertTrue {
55+
this.contains(
56+
"> Rule 'test rule' violated:\n" +
57+
" covered lines percentage is 57.142900, but expected minimum is 58\n" +
58+
" covered lines count is 4, but expected maximum is 3"
59+
)
60+
}
61+
}
62+
}
63+
}
64+
65+
@Test
66+
fun testNotVerifiedJaCoCo() {
67+
builder("Test verification failed for JaCoCo Engine")
68+
.languages(GradleScriptLanguage.KOTLIN, GradleScriptLanguage.GROOVY)
69+
.engines(CoverageEngine.JACOCO)
70+
.sources("simple")
71+
.rule("test rule") {
72+
bound {
73+
minValue = 58
74+
maxValue = 60
75+
}
76+
bound {
77+
valueType = VerificationValueType.COVERED_LINES_COUNT
78+
minValue = 2
79+
maxValue = 3
80+
}
81+
}
82+
.build()
83+
.runWithError("koverVerify") {
84+
output {
85+
assertTrue {
86+
this.contains(
87+
"[ant:jacocoReport] Rule violated for bundle :: lines covered ratio is 0.50, but expected minimum is 0.58\n" +
88+
"[ant:jacocoReport] Rule violated for bundle :: lines covered count is 4, but expected maximum is 3"
89+
)
90+
}
91+
}
92+
}
93+
}
94+
95+
96+
}

src/functionalTest/kotlin/kotlinx/kover/test/functional/cases/utils/Commons.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
package kotlinx.kover.test.functional.cases.utils
26

37
import kotlinx.kover.api.*

src/functionalTest/kotlin/kotlinx/kover/test/functional/core/Builder.kt

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
package kotlinx.kover.test.functional.core
26

37
import kotlinx.kover.api.*
8+
import org.gradle.api.*
49
import java.io.*
510

611
internal fun createBuilder(rootDir: File, description: String): TestCaseBuilder {
@@ -96,9 +101,9 @@ private class TestCaseBuilderImpl(
96101
@Suppress("UNCHECKED_CAST")
97102
private open class ProjectBuilderImpl<B : ProjectBuilder<B>>(val projectState: ProjectBuilderState) : ProjectBuilder<B> {
98103

99-
override fun verification(rules: Iterable<VerificationRule>): B {
100-
projectState.rules += rules
101-
return this as B
104+
override fun rule(name: String?, builder: RuleBuilder.() -> Unit): B {
105+
projectState.rules += TestVerificationRule(projectState.rules.size, name).apply(builder)
106+
return this as B
102107
}
103108

104109
override fun configTest(script: String): B {
@@ -137,5 +142,26 @@ private open class ProjectBuilderImpl<B : ProjectBuilder<B>>(val projectState: P
137142
}
138143
}
139144

145+
private data class TestVerificationRule(
146+
override val id: Int,
147+
override var name: String?
148+
) : VerificationRule, RuleBuilder {
149+
override val bounds: MutableList<VerificationBound> = mutableListOf()
150+
override fun bound(configureBound: Action<VerificationBound>) {
151+
bounds += TestVerificationBound(bounds.size).also { configureBound.execute(it) }
152+
}
153+
154+
override fun bound(builder: VerificationBound.() -> Unit) {
155+
bounds += TestVerificationBound(bounds.size).apply(builder)
156+
}
157+
}
158+
159+
private data class TestVerificationBound(
160+
override val id: Int,
161+
override var minValue: Int? = null,
162+
override var maxValue: Int? = null,
163+
override var valueType: VerificationValueType = VerificationValueType.COVERED_LINES_PERCENTAGE
164+
) : VerificationBound
165+
140166

141167

src/functionalTest/kotlin/kotlinx/kover/test/functional/core/Runner.kt

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
package kotlinx.kover.test.functional.core
26

37
import kotlinx.kover.api.*
@@ -13,35 +17,64 @@ internal class GradleRunnerImpl(private val projects: Map<ProjectSlice, File>) :
1317

1418
override fun run(vararg args: String, checker: RunResult.() -> Unit): GradleRunnerImpl {
1519
val argsList = listOf(*args)
16-
1720
projects.forEach { (slice, project) ->
1821
try {
19-
project.runGradle(argsList, checker)
20-
} catch (e: Throwable) {
22+
val buildResult = project.runGradle(argsList)
23+
RunResultImpl(buildResult, project).apply { checkIntellijErrors() }.apply(checker)
24+
} catch (e: UnexpectedBuildFailure) {
2125
throw AssertionError("Assertion error occurred in test for project $slice", e)
2226
}
2327
}
24-
28+
return this
29+
}
30+
override fun runWithError(vararg args: String, errorChecker: RunResult.() -> Unit): GradleRunnerImpl {
31+
val argsList = listOf(*args)
32+
projects.forEach { (slice, project) ->
33+
try {
34+
project.runGradleWithError(argsList)
35+
throw AssertionError("Assertion error expected in test for project $slice")
36+
} catch (e: UnexpectedBuildFailure) {
37+
RunResultImpl(e.buildResult, project).apply { checkIntellijErrors() }.apply(errorChecker)
38+
}
39+
}
2540
return this
2641
}
2742
}
2843

2944
internal class SingleGradleRunnerImpl(private val projectDir: File) : GradleRunner {
3045
override fun run(vararg args: String, checker: RunResult.() -> Unit): SingleGradleRunnerImpl {
31-
projectDir.runGradle(listOf(*args), checker)
46+
val buildResult = projectDir.runGradle(listOf(*args))
47+
RunResultImpl(buildResult, projectDir).apply { checkIntellijErrors() }.apply(checker)
48+
return this
49+
}
50+
51+
override fun runWithError(vararg args: String, errorChecker: RunResult.() -> Unit): SingleGradleRunnerImpl {
52+
try {
53+
projectDir.runGradleWithError(listOf(*args))
54+
throw AssertionError("Assertion error expected in test")
55+
} catch (e: UnexpectedBuildFailure) {
56+
RunResultImpl(e.buildResult, projectDir).apply { checkIntellijErrors() }.apply(errorChecker)
57+
}
3258
return this
3359
}
3460
}
3561

36-
private fun File.runGradle(args: List<String>, checker: RunResult.() -> Unit) {
37-
val buildResult = org.gradle.testkit.runner.GradleRunner.create()
62+
private fun File.runGradle(args: List<String>): BuildResult {
63+
return org.gradle.testkit.runner.GradleRunner.create()
3864
.withProjectDir(this)
3965
.withPluginClasspath()
4066
.addPluginTestRuntimeClasspath()
4167
.withArguments(args)
4268
.build()
69+
}
4370

44-
RunResultImpl(buildResult, this).apply { checkIntellijErrors() }.apply(checker)
71+
private fun File.runGradleWithError(args: List<String>) {
72+
org.gradle.testkit.runner.GradleRunner.create()
73+
.withProjectDir(this)
74+
.withPluginClasspath()
75+
.addPluginTestRuntimeClasspath()
76+
.withArguments(args)
77+
.build()
4578
}
4679

4780
private fun org.gradle.testkit.runner.GradleRunner.addPluginTestRuntimeClasspath() = apply {

src/functionalTest/kotlin/kotlinx/kover/test/functional/core/Types.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
package kotlinx.kover.test.functional.core
26

37
import kotlinx.kover.api.*
@@ -10,7 +14,8 @@ internal enum class ProjectType { KOTLIN_JVM, KOTLIN_MULTIPLATFORM, ANDROID }
1014

1115
internal interface ProjectBuilder<B : ProjectBuilder<B>> {
1216
fun sources(template: String): B
13-
fun verification(rules: Iterable<VerificationRule>): B
17+
18+
fun rule(name: String? = null, builder: RuleBuilder.() -> Unit): B
1419

1520
fun configTest(script: String): B
1621
fun configTest(kotlin: String, groovy: String): B
@@ -22,6 +27,10 @@ internal interface ProjectBuilder<B : ProjectBuilder<B>> {
2227
fun dependency(kotlin: String, groovy: String): B
2328
}
2429

30+
internal interface RuleBuilder {
31+
fun bound(builder: VerificationBound.() -> Unit)
32+
}
33+
2534
internal interface TestCaseBuilder : ProjectBuilder<TestCaseBuilder> {
2635
fun languages(vararg languages: GradleScriptLanguage): TestCaseBuilder
2736
fun engines(vararg engines: CoverageEngine): TestCaseBuilder
@@ -56,6 +65,7 @@ internal data class KoverRootConfig(
5665

5766
internal interface GradleRunner {
5867
fun run(vararg args: String, checker: RunResult.() -> Unit = {}): GradleRunner
68+
fun runWithError(vararg args: String, errorChecker: RunResult.() -> Unit = {}): GradleRunner
5969
}
6070

6171
internal interface RunResult {

src/functionalTest/kotlin/kotlinx/kover/test/functional/core/Writer.kt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
package kotlinx.kover.test.functional.core
26

37
import kotlinx.kover.api.*
@@ -190,7 +194,31 @@ private fun ProjectBuilderState.buildTestTask(slice: ProjectSlice): String {
190194

191195
@Suppress("UNUSED_PARAMETER")
192196
private fun ProjectBuilderState.buildVerifications(slice: ProjectSlice): String {
193-
return ""
197+
if (rules.isEmpty()) {
198+
return ""
199+
}
200+
201+
val builder = StringBuilder()
202+
builder.appendLine()
203+
builder.appendLine("tasks.koverVerify {")
204+
205+
for (rule in rules) {
206+
builder.appendLine(" rule {")
207+
rule.name?.also { builder.appendLine(""" name = "$it"""") }
208+
for (bound in rule.bounds) {
209+
builder.appendLine(" bound {")
210+
bound.minValue?.let { builder.appendLine(" minValue = $it") }
211+
bound.maxValue?.let { builder.appendLine(" maxValue = $it") }
212+
if (bound.valueType != VerificationValueType.COVERED_LINES_PERCENTAGE) {
213+
builder.appendLine(" valueType = kotlinx.kover.api.VerificationValueType.${bound.valueType}")
214+
}
215+
builder.appendLine(" }")
216+
}
217+
builder.appendLine(" }")
218+
}
219+
builder.appendLine("}")
220+
221+
return builder.toString()
194222
}
195223

196224
private fun CommonBuilderState.buildSettings(slice: ProjectSlice): String {

src/main/kotlin/kotlinx/kover/api/Rules.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.kover.api
@@ -13,6 +13,12 @@ import javax.annotation.*
1313
* Works only with lines counter.
1414
*/
1515
public interface VerificationRule {
16+
/**
17+
* Unique ID of the rule.
18+
*/
19+
@get:Internal
20+
public val id: Int
21+
1622
/**
1723
* Custom name of the rule.
1824
*/
@@ -34,6 +40,12 @@ public interface VerificationRule {
3440
}
3541

3642
public interface VerificationBound {
43+
/**
44+
* ID of the bound unique in the rule.
45+
*/
46+
@get:Internal
47+
public val id: Int
48+
3749
/**
3850
* Minimal value to compare with counter value.
3951
*/

0 commit comments

Comments
 (0)