Skip to content

Commit 663d62c

Browse files
add support for ShouldSpec
1 parent 51e868e commit 663d62c

File tree

5 files changed

+64
-42
lines changed

5 files changed

+64
-42
lines changed

src/main/kotlin/io/kotest/plugin/intellij/styles/ShouldSpecStyle.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.kotest.plugin.intellij.psi.extractLhsStringArgForDotExpressionWithRhsF
1010
import io.kotest.plugin.intellij.psi.extractStringArgForFunctionWithStringAndLambdaArgs
1111
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
1212
import io.kotest.plugin.intellij.psi.ifOpenQuoteOfFunctionName
13+
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
1314
import org.jetbrains.kotlin.name.FqName
1415
import org.jetbrains.kotlin.psi.KtCallExpression
1516
import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -25,6 +26,13 @@ object ShouldSpecStyle : SpecStyle {
2526
return "should(\"$name\") { }"
2627
}
2728

29+
override fun getDataTestMethodNames(): Set<String> =
30+
setOf(
31+
"withData",
32+
"withContexts",
33+
"withShoulds"
34+
)
35+
2836
override fun isTestElement(element: PsiElement): Boolean = test(element) != null
2937

3038
private val fnNames = setOf("should", "xshould", "context", "xcontext")
@@ -122,7 +130,7 @@ object ShouldSpecStyle : SpecStyle {
122130

123131
override fun test(element: PsiElement): Test? {
124132
return when (element) {
125-
is KtCallExpression -> element.tryKtCallExpression()
133+
is KtCallExpression -> element.tryKtCallExpression() ?: element.tryDataTest()
126134
is KtDotQualifiedExpression -> element.tryKtDotQualifiedExpression()
127135
else -> null
128136
}
@@ -143,6 +151,9 @@ object ShouldSpecStyle : SpecStyle {
143151
* xcontext("test name") {}
144152
* context("test name").config(...) {}
145153
* xcontext("test name").config(...) {}
154+
* withData(...) { }
155+
* withContexts(...) { }
156+
* withShoulds(...) { }
146157
*/
147158
override fun test(element: LeafPsiElement): Test? {
148159
val call = element.ifOpenQuoteOfFunctionName(fnNames)
@@ -151,6 +162,12 @@ object ShouldSpecStyle : SpecStyle {
151162
val ktdot = element.ifDotExpressionSeparator()
152163
if (ktdot != null) return test(ktdot)
153164

165+
// try to find Data Test Method by finding lambda openings
166+
val dataMethodCall = element.isDataTestMethodCall(getDataTestMethodNames())
167+
if (dataMethodCall != null) {
168+
return test(dataMethodCall)
169+
}
170+
154171
return null
155172
}
156173
}

src/main/kotlin/io/kotest/plugin/intellij/styles/SpecStyle.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import io.kotest.plugin.intellij.Test
66
import io.kotest.plugin.intellij.TestElement
77
import io.kotest.plugin.intellij.TestName
88
import io.kotest.plugin.intellij.TestType
9+
import io.kotest.plugin.intellij.psi.enclosingKtClassOrObject
10+
import io.kotest.plugin.intellij.psi.hasFunctionName
911
import io.kotest.plugin.intellij.psi.isContainedInSpecificSpec
1012
import org.jetbrains.kotlin.name.FqName
13+
import org.jetbrains.kotlin.psi.KtCallExpression
1114
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
1215
import org.jetbrains.kotlin.psi.KtDeclarationModifierList
1316
import org.jetbrains.kotlin.psi.KtImportList
@@ -146,4 +149,24 @@ interface SpecStyle {
146149

147150
// TODO default will be removed if this POC is accepted and all other styles implement it
148151
fun getDataTestMethodNames() : Set<String> = emptySet()
152+
153+
/**
154+
* A test container of the form:
155+
*```
156+
* withXXX(1, 2, 3) { }
157+
* withXXX(listOf(1, 2, 3)) { }
158+
* withXXX(nameFn = { "test $it" }, 1, 2, 3) { }
159+
* ...
160+
*```
161+
* plus any other withXXX permutation as per result of [getDataTestMethodNames].
162+
*
163+
* Note: even tho we build a [Test], with some params, the runner will only read the [Test.isDataTest] boolean and determine it needs to run the whole spec.
164+
*/
165+
fun KtCallExpression.tryDataTest(): Test? {
166+
val specClass = enclosingKtClassOrObject() ?: return null
167+
168+
if (!hasFunctionName(getDataTestMethodNames().toList())) return null
169+
170+
return Test(dataTestDefaultTestName, null, specClass, TestType.Container, xdisabled = false, psi = this, isDataTest = true)
171+
}
149172
}

src/main/kotlin/io/kotest/plugin/intellij/styles/StringSpecStyle.kt

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ import io.kotest.plugin.intellij.TestType
88
import io.kotest.plugin.intellij.psi.enclosingKtClassOrObject
99
import io.kotest.plugin.intellij.psi.extractStringForStringExtensionFunctonWithRhsFinalLambda
1010
import io.kotest.plugin.intellij.psi.extractStringFromStringInvokeWithLambda
11-
import io.kotest.plugin.intellij.psi.hasFunctionName
1211
import io.kotest.plugin.intellij.psi.ifCallExpressionLhsStringOpenQuote
1312
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
1413
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
15-
import io.kotest.plugin.intellij.styles.SpecStyle.Companion.dataTestDefaultTestName
1614
import org.jetbrains.kotlin.name.FqName
1715
import org.jetbrains.kotlin.psi.KtCallExpression
1816
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
@@ -36,7 +34,6 @@ object StringSpecStyle : SpecStyle {
3634
"withData",
3735
)
3836

39-
4037
/**
4138
* A test of the form:
4239
*
@@ -50,27 +47,6 @@ object StringSpecStyle : SpecStyle {
5047
return Test(testName, null, specClass, TestType.Test, xdisabled = false, psi = this)
5148
}
5249

53-
/**
54-
* A test container of the form:
55-
*```
56-
* withData(1, 2, 3) { }
57-
* withData(listOf(1, 2, 3)) { }
58-
* withData(nameFn = { "test $it" }, 1, 2, 3) { }
59-
* ... any other withData permutation
60-
*```
61-
* Note: even tho we build a Test, the runner will only read the `isDataTest` boolean to determine it needs to run the whole spec
62-
*/
63-
private fun KtCallExpression.tryWithData(): Test? {
64-
val specClass = enclosingKtClassOrObject() ?: return null
65-
66-
if (!hasFunctionName(getDataTestMethodNames().toList())) return null
67-
68-
69-
// withData is a container because it generates multiple tests at runtime
70-
return Test(dataTestDefaultTestName, null, specClass, TestType.Container, xdisabled = false, psi = this, isDataTest = true)
71-
}
72-
73-
7450
/**
7551
* Matches tests of the form:
7652
*
@@ -92,7 +68,7 @@ object StringSpecStyle : SpecStyle {
9268
*/
9369
override fun test(element: PsiElement): Test? {
9470
return when (element) {
95-
is KtCallExpression -> element.tryTest() ?: element.tryWithData()
71+
is KtCallExpression -> element.tryTest() ?: element.tryDataTest()
9672
is KtDotQualifiedExpression -> element.tryTestWithConfig()
9773
else -> null
9874
}

src/test/kotlin/io/kotest/plugin/intellij/styles/ShouldSpecStyleTest.kt

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,25 @@ class ShouldSpecStyleTest : LightJavaCodeInsightFixtureTestCase() {
2525

2626
val gutters = myFixture.findAllGutters()
2727
println(gutters.map { it.tooltipText }.joinToString("\n"))
28-
gutters.size shouldBe 15
28+
gutters.size shouldBe 16
2929

3030
val expected = listOf(
31-
Gutter("Run ShouldSpecExample", 91, AllIcons.RunConfigurations.TestState.Run_run),
32-
Gutter("Run top level test", 155),
33-
Gutter("Run top level test with config", 247),
34-
Gutter("Run some context", 317),
35-
Gutter("Run some context top level test", 351),
36-
Gutter("Run some context top level test with config", 452),
37-
Gutter("Run some context 2", 536),
38-
Gutter("Run some context 2 some nested context", 573),
39-
Gutter("Run some context 2 some nested context top level test", 617),
40-
Gutter("Run some context 2 some nested context top level test with config", 727),
41-
Gutter("Run a context with config", 852),
42-
Gutter("Run a context with config a should", 894),
43-
Gutter("Disabled - an xcontext with config", 958, AllIcons.RunConfigurations.TestIgnored),
44-
Gutter("Disabled - an xcontext with config a should", 1000, AllIcons.RunConfigurations.TestIgnored),
45-
Gutter("Disabled - xdisabled should", 1037, AllIcons.RunConfigurations.TestIgnored),
31+
Gutter("Run ShouldSpecExample", 126, AllIcons.RunConfigurations.TestState.Run_run),
32+
Gutter("Run top level test", 190),
33+
Gutter("Run top level test with config", 282),
34+
Gutter("Run some context", 352),
35+
Gutter("Run some context top level test", 386),
36+
Gutter("Run some context top level test with config", 487),
37+
Gutter("Run some context 2", 571),
38+
Gutter("Run some context 2 some nested context", 608),
39+
Gutter("Run some context 2 some nested context top level test", 652),
40+
Gutter("Run some context 2 some nested context top level test with config", 762),
41+
Gutter("Run a context with config", 887),
42+
Gutter("Run a context with config a should", 929),
43+
Gutter("Disabled - an xcontext with config", 993, AllIcons.RunConfigurations.TestIgnored),
44+
Gutter("Disabled - an xcontext with config a should", 1035, AllIcons.RunConfigurations.TestIgnored),
45+
Gutter("Disabled - xdisabled should", 1072, AllIcons.RunConfigurations.TestIgnored),
46+
Gutter("Run All Spec Tests, including data tests", 1133),
4647
)
4748

4849
gutters.size shouldBe expected.size

src/test/resources/shouldspec.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.sksamuel.kotest.specs.shouldspec
22

33
import io.kotest.core.spec.style.ShouldSpec
4+
import io.kotest.datatest.withData
45

56
class ShouldSpecExample : ShouldSpec() {
67
init {
@@ -37,5 +38,9 @@ class ShouldSpecExample : ShouldSpec() {
3738
xshould("xdisabled should"){
3839

3940
}
41+
42+
withData(1, 2, 3, 4, 5) { value ->
43+
// test here
44+
}
4045
}
4146
}

0 commit comments

Comments
 (0)