Skip to content

Commit 5912961

Browse files
committed
Add gutter run icon for SuiteConfig with --suite flag
- Add SUITE_CONFIG constant for \Testo\Application\Config\SuiteConfig - Add line marker on `new SuiteConfig(...)` for per-suite run - Extract suite name from first constructor parameter - Run config sets --suite=<name> and --config=<file> flags - Match existing SuiteConfig configs in isConfigurationFromContext https://claude.ai/code/session_01TmFvjfMtoxTvddQRBzsbPN
1 parent 809910f commit 5912961

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

src/main/kotlin/com/github/xepozz/testo/TestoClasses.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ object TestoClasses {
1313
const val BENCH = "\\Testo\\Bench"
1414

1515
const val APPLICATION_CONFIG = "\\Testo\\Application\\Config\\ApplicationConfig"
16+
const val SUITE_CONFIG = "\\Testo\\Application\\Config\\SuiteConfig"
1617

1718
const val ASSERT = "\\Testo\\Assert"
1819
const val ASSERTION_EXCEPTION = "\\Testo\\Assert\\State\\Assertion\\AssertionException"

src/main/kotlin/com/github/xepozz/testo/tests/TestoTestRunLineMarkerProvider.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ class TestoTestRunLineMarkerProvider : RunLineMarkerContributor() {
5454
getLocationHint(element.containingFile)
5555
}
5656

57+
element is ClassReference && element.parent is NewExpression && element.fqn == TestoClasses.SUITE_CONFIG -> {
58+
getLocationHint(element.containingFile)
59+
}
60+
5761
element is ClassReference && element.parent is PhpAttribute -> {
5862
val attribute = element.parent as PhpAttribute
5963
if (attribute.fqn !in RUNNABLE_ATTRIBUTES) return null

src/main/kotlin/com/github/xepozz/testo/tests/run/TestoRunConfigurationProducer.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import com.jetbrains.php.lang.psi.elements.NewExpression
4141
import com.jetbrains.php.lang.psi.elements.PhpAttribute
4242
import com.jetbrains.php.lang.psi.elements.PhpClass
4343
import com.jetbrains.php.lang.psi.elements.PhpNamedElement
44+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression
4445
import com.jetbrains.php.lang.psi.elements.PhpYield
4546
import com.jetbrains.php.phpunit.PhpMethodLocation
4647
import com.jetbrains.php.phpunit.PhpUnitRuntimeConfigurationProducer
@@ -71,6 +72,15 @@ class TestoRunConfigurationProducer : PhpTestConfigurationProducer<TestoRunConfi
7172
testRunnerSettings.configurationFilePath = virtualFile.path
7273
return element
7374
}
75+
if (element is ClassReference && element.parent is NewExpression && element.fqn == TestoClasses.SUITE_CONFIG) {
76+
val newExpression = element.parent as NewExpression
77+
val suiteName = extractSuiteName(newExpression) ?: return null
78+
testRunnerSettings.scope = PhpTestRunnerSettings.Scope.ConfigurationFile
79+
testRunnerSettings.isUseAlternativeConfigurationFile = true
80+
testRunnerSettings.configurationFilePath = virtualFile.path
81+
testRunnerSettings.suite = suiteName
82+
return element
83+
}
7484
if (element is PhpAttribute) {
7585
val function = element.owner as? Function ?: return null
7686
setupConfiguration(testRunnerSettings, function, element.containingFile.virtualFile) ?: return null
@@ -146,6 +156,14 @@ class TestoRunConfigurationProducer : PhpTestConfigurationProducer<TestoRunConfi
146156
return testRunnerSettings.scope == PhpTestRunnerSettings.Scope.ConfigurationFile
147157
&& testRunnerSettings.configurationFilePath == element.containingFile.virtualFile.path
148158
}
159+
if (element is ClassReference && element.parent is NewExpression && element.fqn == TestoClasses.SUITE_CONFIG) {
160+
val testoSettings = testRunnerSettings as? TestoRunnerSettings ?: return false
161+
val newExpression = element.parent as NewExpression
162+
val suiteName = extractSuiteName(newExpression) ?: return false
163+
return testoSettings.scope == PhpTestRunnerSettings.Scope.ConfigurationFile
164+
&& testoSettings.configurationFilePath == element.containingFile.virtualFile.path
165+
&& testoSettings.suite == suiteName
166+
}
149167
if (element is PhpClass) {
150168
return when {
151169
testRunnerSettings.scope != PhpTestRunnerSettings.Scope.File -> false
@@ -292,7 +310,7 @@ class TestoRunConfigurationProducer : PhpTestConfigurationProducer<TestoRunConfi
292310
}
293311

294312
private fun findTestElement(target: PsiElement?): PsiElement? = when (target) {
295-
is ClassReference -> target.takeIf { it.parent is NewExpression && it.fqn == TestoClasses.APPLICATION_CONFIG }
313+
is ClassReference -> target.takeIf { it.parent is NewExpression && (it.fqn == TestoClasses.APPLICATION_CONFIG || it.fqn == TestoClasses.SUITE_CONFIG) }
296314
is PhpAttribute -> target.takeIf { it.owner.isTestoExecutable() || it.owner.isTestoDataProviderLike() }
297315
is Function -> target.takeIf { it.isTestoExecutable() || it.isTestoDataProviderLike() }
298316
is PhpClass -> target.takeIf { it.isTestoClass() }
@@ -535,6 +553,15 @@ class TestoRunConfigurationProducer : PhpTestConfigurationProducer<TestoRunConfi
535553
}
536554
}
537555

556+
private fun extractSuiteName(newExpression: NewExpression): String? {
557+
val firstParam = newExpression.parameters.firstOrNull() ?: return null
558+
if (firstParam is StringLiteralExpression) {
559+
return firstParam.contents
560+
}
561+
val literal = com.intellij.psi.util.PsiTreeUtil.findChildOfType(firstParam, StringLiteralExpression::class.java)
562+
return literal?.contents
563+
}
564+
538565
private fun getContainingClass(location: Location<*>, method: Method) = when (location) {
539566
is PhpMethodLocation -> location.containingClass
540567
else -> method.containingClass

0 commit comments

Comments
 (0)