Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/kotlin/io/kotest/plugin/intellij/Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ data class Test(
val specClassName: KtClassOrObject, // the containing class name, which all tests must have
val testType: TestType,
val xdisabled: Boolean, // if true then this test was defined using one of the x methods
val psi: PsiElement // the canonical element that identifies this test
val psi: PsiElement, // the canonical element that identifies this test
val isDataTest: Boolean = false
) {

// true if this test is not xdisabled and not disabled by a bang and not nested inside another disabled test
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/io/kotest/plugin/intellij/psi/utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,8 @@ fun KtValueArgumentList.isSingleStringTemplateArg(): Boolean =
&& children[0] is KtValueArgument
&& children[0].children.size == 1
&& children[0].children[0] is KtStringTemplateExpression

fun LeafPsiElement.isDataTestMethodCall(dataTestMethodNames:Set<String>): KtCallExpression? {
val lambdaCall = ifCallExpressionLambdaOpenBrace()
return lambdaCall.takeIf {lambdaCall?.functionName() in dataTestMethodNames}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ data class GradleTaskNamesBuilder(
private fun includeArg(): String? {
return when (test) {
null -> "$PROPERTY_INCLUDE='${spec.fqName?.asString()}'"
else -> "$PROPERTY_INCLUDE='${test.descriptorPath()}'"
else ->
when(test.isDataTest){
false -> "$PROPERTY_INCLUDE='${test.descriptorPath()}'"
true -> "$PROPERTY_INCLUDE='${spec.fqName?.asString()}'"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ class TestOrSpecGradleRunConfigurationProducer : GradleRunConfigurationProducer(
if (test != null) {
// if we specified a test descriptor before, it needs to match for this configuration to be the same
val descriptorArg = GradleUtils.getIncludeArg(configuration.settings.taskNames) ?: return false
if (test.isDataTest) {
val spec = element.enclosingSpec()
return spec?.fqName?.asString() == descriptorArg
}
if (test.descriptorPath() == descriptorArg) return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ class TestPathRunConfigurationProducer : LazyRunConfigurationProducer<KotestRunC

val ktclass = element.enclosingKtClass()
if (ktclass != null) {
configuration.setTestPath(test.testPath())
if (test.isDataTest)
configuration.setTestPath(null)
else
configuration.setTestPath(test.testPath())
configuration.setSpec(ktclass)
configuration.setModule(context.module)
configuration.name = generateName(ktclass, test)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.kotest.plugin.intellij.psi.extractLhsStringArgForDotExpressionWithRhsF
import io.kotest.plugin.intellij.psi.extractStringArgForFunctionWithStringAndLambdaArgs
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
import io.kotest.plugin.intellij.psi.ifOpenQuoteOfFunctionName
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
Expand All @@ -23,6 +24,16 @@ object BehaviorSpecStyle : SpecStyle {
override fun fqn() = FqName("io.kotest.core.spec.style.BehaviorSpec")
override fun specStyleName(): String = "Behavior Spec"

override fun getDataTestMethodNames(): Set<String> =
setOf(
"withData",
"withContexts",
"withGivens",
"withWhens",
"withThens",
"withAnds"
)

override fun isTestElement(element: PsiElement): Boolean = test(element) != null

private val contexts = listOf("Context", "context", "`Context`", "`context`")
Expand Down Expand Up @@ -173,6 +184,7 @@ object BehaviorSpecStyle : SpecStyle {
?: element.tryXWhen()
?: element.tryThen()
?: element.tryXThen()
?: element.tryDataTest()
is KtDotQualifiedExpression -> element.tryThenWithConfig()
else -> null
}
Expand All @@ -191,13 +203,49 @@ object BehaviorSpecStyle : SpecStyle {
return setOf("OPEN_QUOTE", "DOT")
}

/**
* For a BehaviorSpec we consider the following scenarios:
*
* context("test name") {}
* xcontext("test name") {}
* context("test name").config(...) {}
* xcontext("test name").config(...) {}
* given("test name") {}
* xgiven("test name") {}
* given("test name").config(...) {}
* xgiven("test name").config(...) {}
* when("test name") {}
* xwhen("test name") {}
* when("test name").config(...) {}
* xwhen("test name").config(...) {}
* then("test name") {}
* xthen("test name") {}
* then("test name").config(...) {}
* xthen("test name").config(...) {}
* and("test name") {}
* xand("test name") {}
* and("test name").config(...) {}
* xand("test name").config(...) {}
* withData(...) { }
* withContexts(...) { }
* withGivens(...) { }
* withWhens(...) { }
* withThens(...) { }
* withAnds(...) { }
*/
override fun test(element: LeafPsiElement): Test? {
val ktcall1 = element.ifOpenQuoteOfFunctionName(fnNames)
if (ktcall1 != null) return test(ktcall1)

val ktdot = element.ifDotExpressionSeparator()
if (ktdot != null) return test(ktdot)

// try to find Data Test Method by finding lambda openings
val dataMethodCall = element.isDataTestMethodCall(getDataTestMethodNames())
if (dataMethodCall != null) {
return test(dataMethodCall)
}

return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.kotest.plugin.intellij.psi.extractLhsStringArgForDotExpressionWithRhsF
import io.kotest.plugin.intellij.psi.extractStringArgForFunctionWithStringAndLambdaArgs
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
import io.kotest.plugin.intellij.psi.ifOpenQuoteOfFunctionName
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClassOrObject
Expand All @@ -25,6 +26,14 @@ object DescribeSpecStyle : SpecStyle {
return "describe(\"$name\") { }"
}

override fun getDataTestMethodNames(): Set<String> =
setOf(
"withData",
"withContexts",
"withDescribes",
"withIts"
)

private val fnNames = setOf("describe", "xdescribe", "context", "xcontext", "it", "xit")

override fun isTestElement(element: PsiElement): Boolean = test(element) != null
Expand Down Expand Up @@ -246,6 +255,7 @@ object DescribeSpecStyle : SpecStyle {
?: element.tryXDescribe()
?: element.tryContext()
?: element.tryXContent()
?: element.tryDataTest()
is KtDotQualifiedExpression ->
element.tryDescribeWithConfig()
?: element.tryXDescribeWithConfig()
Expand All @@ -261,13 +271,38 @@ object DescribeSpecStyle : SpecStyle {
return setOf("OPEN_QUOTE", "DOT")
}

/**
* For a DescribeSpec we consider the following scenarios:
*
* describe("test name") { }
* xdescribe("test name") { }
* context("test name") { }
* xcontext("test name") { }
* it("test name") { }
* xit("test name") { }
* describe("test name").config(...) {}
* xdescribe("test name").config(...) {}
* context("test name").config(...) {}
* xcontext("test name").config(...) {}
* it("test name").config(...) {}
* xit("test name").config(...) {}
* withData(...) { }
* withContexts(...) { }
* withDescribes(...) { }
* withIts(...) { }
*/
override fun test(element: LeafPsiElement): Test? {
val call = element.ifOpenQuoteOfFunctionName(fnNames)
if (call != null) return test(call)

val dot = element.ifDotExpressionSeparator()
if (dot != null) return test(dot)

// try to find Data Test Method by finding lambda openings
val dataMethodCall = element.isDataTestMethodCall(getDataTestMethodNames())
if (dataMethodCall != null) {
return test(dataMethodCall)
}
return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.kotest.plugin.intellij.psi.extractLhsStringArgForDotExpressionWithRhsF
import io.kotest.plugin.intellij.psi.extractStringArgForFunctionWithStringAndLambdaArgs
import io.kotest.plugin.intellij.psi.ifCallExpressionLambdaOpenBrace
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClassOrObject
Expand All @@ -25,6 +26,13 @@ object ExpectSpecStyle : SpecStyle {
return "expect(\"$name\") { }"
}

override fun getDataTestMethodNames(): Set<String> =
setOf(
"withData",
"withContexts",
"withExpects"
)

override fun isTestElement(element: PsiElement): Boolean = test(element) != null

private fun locateParent(element: PsiElement): Test? {
Expand Down Expand Up @@ -60,7 +68,7 @@ object ExpectSpecStyle : SpecStyle {

override fun test(element: PsiElement): Test? {
return when (element) {
is KtCallExpression -> element.tryExpect() ?: element.tryContext()
is KtCallExpression -> element.tryExpect() ?: element.tryContext() ?: element.tryDataTest()
is KtDotQualifiedExpression -> element.tryExpectWithConfig()
else -> null
}
Expand All @@ -70,13 +78,30 @@ object ExpectSpecStyle : SpecStyle {
return setOf("OPEN_QUOTE")
}

/**
* For a ExpectSpec we consider the following scenarios:
*
* expect("test name") { }
* expect("test name").config(...) {}
* context("test name") {}
* context("test name").config(...) {}
* withData(...) { }
* withContexts(...) { }
* withExpects(...) { }
*/
override fun test(element: LeafPsiElement): Test? {
val ktcall = element.ifCallExpressionLambdaOpenBrace()
if (ktcall != null) return test(ktcall)

val ktdot = element.ifDotExpressionSeparator()
if (ktdot != null) return test(ktdot)

// try to find Data Test Method by finding lambda openings
val dataMethodCall = element.isDataTestMethodCall(getDataTestMethodNames())
if (dataMethodCall != null) {
return test(dataMethodCall)
}

return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.kotest.plugin.intellij.psi.extractLhsStringArgForDotExpressionWithRhsF
import io.kotest.plugin.intellij.psi.extractStringArgForFunctionWithStringAndLambdaArgs
import io.kotest.plugin.intellij.psi.ifCallExpressionLambdaOpenBrace
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClassOrObject
Expand All @@ -25,6 +26,13 @@ object FeatureSpecStyle : SpecStyle {
return "feature(\"$name\") { }"
}

override fun getDataTestMethodNames(): Set<String> =
setOf(
"withData",
"withFeatures",
"withScenarios"
)

override fun isTestElement(element: PsiElement): Boolean = test(element) != null

private fun locateParent(element: PsiElement): Test? {
Expand Down Expand Up @@ -67,7 +75,7 @@ object FeatureSpecStyle : SpecStyle {

override fun test(element: PsiElement): Test? {
return when (element) {
is KtCallExpression -> element.tryScenario() ?: element.tryFeature()
is KtCallExpression -> element.tryScenario() ?: element.tryFeature() ?: element.tryDataTest()
is KtDotQualifiedExpression -> element.tryFeatureWithConfig() ?: element.tryScenarioWithConfig()
else -> null
}
Expand All @@ -77,13 +85,34 @@ object FeatureSpecStyle : SpecStyle {
return setOf("OPEN_QUOTE")
}

/**
* For a FeatureSpec we consider the following scenarios:
*
* feature("test name") { }
* xfeature("test name") { }
* feature("test name").config(...) {}
* xfeature("test name").config(...) {}
* scenario("test name") {}
* xscenario("test name") {}
* scenario("test name").config(...) {}
* xscenario("test name").config(...) {}
* withData(...) { }
* withFeatures(...) { }
* withScenarios(...) { }
*/
override fun test(element: LeafPsiElement): Test? {
val ktcall = element.ifCallExpressionLambdaOpenBrace()
if (ktcall != null) return test(ktcall)

val ktdot = element.ifDotExpressionSeparator()
if (ktdot != null) return test(ktdot)

// try to find Data Test Method by finding lambda openings
val dataMethodCall = element.isDataTestMethodCall(getDataTestMethodNames())
if (dataMethodCall != null) {
return test(dataMethodCall)
}

return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import io.kotest.plugin.intellij.psi.extractStringLiteralFromLhsOfInfixFunction
import io.kotest.plugin.intellij.psi.ifMinusOperator
import io.kotest.plugin.intellij.psi.ifCallExpressionLhsStringOpenQuote
import io.kotest.plugin.intellij.psi.ifDotExpressionSeparator
import io.kotest.plugin.intellij.psi.isDataTestMethodCall
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression
Expand All @@ -28,6 +29,11 @@ object FreeSpecStyle : SpecStyle {
return "\"$name\" { }"
}

override fun getDataTestMethodNames(): Set<String> =
setOf(
"withData"
)

override fun isTestElement(element: PsiElement): Boolean = test(element) != null

private fun locateParent(element: PsiElement): Test? {
Expand Down Expand Up @@ -79,7 +85,7 @@ object FreeSpecStyle : SpecStyle {

override fun test(element: PsiElement): Test? {
return when (element) {
is KtCallExpression -> element.tryTest()
is KtCallExpression -> element.tryTest() ?: element.tryDataTest()
is KtDotQualifiedExpression -> element.tryTestWithConfig()
is KtBinaryExpression -> element.tryContainer()
else -> null
Expand All @@ -95,6 +101,7 @@ object FreeSpecStyle : SpecStyle {
*
* "test name" {} // a test
* "test name" - {} // a container
* withData(...) { }
*/
override fun test(element: LeafPsiElement): Test? {
val ktcall = element.ifCallExpressionLhsStringOpenQuote()
Expand All @@ -106,6 +113,12 @@ object FreeSpecStyle : SpecStyle {
val ktbinary = element.ifMinusOperator()
if (ktbinary != null) return test(ktbinary)

// try to find Data Test Method by finding lambda openings
val dataMethodCall = element.isDataTestMethodCall(getDataTestMethodNames())
if (dataMethodCall != null) {
return test(dataMethodCall)
}

return null
}
}
Loading