diff --git a/platforms/ide/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestOperationMapper.java b/platforms/ide/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestOperationMapper.java
index e0b4da59c0da..866c8168e6f6 100644
--- a/platforms/ide/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestOperationMapper.java
+++ b/platforms/ide/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestOperationMapper.java
@@ -18,6 +18,7 @@
import com.google.common.collect.ImmutableList;
import org.gradle.api.internal.tasks.testing.AbstractTestDescriptor;
import org.gradle.api.internal.tasks.testing.DecoratingTestDescriptor;
+import org.gradle.api.internal.tasks.testing.DefaultParameterizedTestDescriptor;
import org.gradle.api.internal.tasks.testing.operations.ExecuteTestBuildOperationType;
import org.gradle.api.tasks.testing.TestDescriptor;
import org.gradle.api.tasks.testing.TestFailure;
@@ -37,6 +38,7 @@
import org.gradle.internal.operations.OperationFinishEvent;
import org.gradle.internal.operations.OperationIdentifier;
import org.gradle.internal.operations.OperationStartEvent;
+import org.gradle.tooling.events.OperationDescriptor;
import org.gradle.tooling.events.OperationType;
import org.gradle.tooling.internal.protocol.InternalFailure;
import org.gradle.tooling.internal.protocol.events.InternalJvmTestDescriptor;
@@ -93,6 +95,7 @@ private DefaultTestDescriptor toTestDescriptorForSuite(OperationIdentifier build
TestDescriptor originalDescriptor = getOriginalDescriptor(suite);
if (originalDescriptor instanceof AbstractTestDescriptor) {
methodName = ((AbstractTestDescriptor) originalDescriptor).getMethodName();
+ operationDisplayName = adjustOperationDisplayNameForIntelliJ(operationDisplayName, (AbstractTestDescriptor) originalDescriptor);
} else {
operationDisplayName = getLegacyOperationDisplayName(operationDisplayName, originalDescriptor);
}
@@ -103,12 +106,31 @@ private DefaultTestDescriptor toTestDescriptorForTest(OperationIdentifier buildO
String operationDisplayName = test.toString();
TestDescriptor originalDescriptor = getOriginalDescriptor(test);
- if (!(originalDescriptor instanceof AbstractTestDescriptor)) {
+ if (originalDescriptor instanceof AbstractTestDescriptor) {
+ operationDisplayName = adjustOperationDisplayNameForIntelliJ(operationDisplayName, (AbstractTestDescriptor) originalDescriptor);
+ } else {
operationDisplayName = getLegacyOperationDisplayName(operationDisplayName, originalDescriptor);
}
return new DefaultTestDescriptor(buildOperationId, test.getName(), operationDisplayName, test.getDisplayName(), InternalJvmTestDescriptor.KIND_ATOMIC, null, test.getClassName(), test.getName(), parentId, taskTracker.getTaskPath(buildOperationId));
}
+ /**
+ * This is a workaround to preserve backward compatibility with IntelliJ IDEA.
+ * The problem only occurs in IntelliJ IDEA because it parses {@link OperationDescriptor#getDisplayName()} to get the test display name.
+ * Once its code is updated to use {@link org.gradle.tooling.events.test.TestOperationDescriptor#getTestDisplayName()}, the workaround can be removed as well.
+ * Alternatively, it can be removed in Gradle 9.0.
+ * See this issue for more details.
+ */
+ private String adjustOperationDisplayNameForIntelliJ(String operationDisplayName, AbstractTestDescriptor descriptor) {
+ String displayName = descriptor.getDisplayName();
+ if (!descriptor.getName().equals(displayName) && !(descriptor.getClassDisplayName() != null && descriptor.getName().endsWith(descriptor.getClassDisplayName()))) {
+ return descriptor.getDisplayName();
+ } else if (descriptor instanceof DefaultParameterizedTestDescriptor) { // for spock parameterized tests
+ return descriptor.getDisplayName();
+ }
+ return operationDisplayName;
+ }
+
/**
* This is a workaround for Kotlin Gradle Plugin overriding TestDescriptor.
* The problem only occurs in IntelliJ IDEA with multiplatform projects.
@@ -125,7 +147,8 @@ private static String getLegacyOperationDisplayName(String operationDisplayName,
}
/**
- * can be removed once {@link #getLegacyOperationDisplayName(String, TestDescriptor) the workaround above} is removed
+ * can be removed once the workaround above ({@link #getLegacyOperationDisplayName(String, TestDescriptor) 1} and
+ * {@link #adjustOperationDisplayNameForIntelliJ(String, AbstractTestDescriptor) 2}) are removed
*/
private static TestDescriptor getOriginalDescriptor(TestDescriptor testDescriptor) {
if (testDescriptor instanceof DecoratingTestDescriptor) {
diff --git a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy
index 7d2854566315..39cccbd91606 100644
--- a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy
+++ b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy
@@ -318,6 +318,8 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
}
interface TestEventSpec {
+ void operationDisplayName(String displayName)
+
void testDisplayName(String displayName)
void suite(String name, @DelegatesTo(value = TestEventSpec, strategy = Closure.DELEGATE_FIRST) Closure> spec)
@@ -343,7 +345,7 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
if (task == null) {
throw new AssertionError("Expected to find a test task $path but none was found")
}
- DefaultTestEventSpec.assertSpec(task.parent, testEvents, verifiedEvents, rootSpec)
+ DefaultTestEventSpec.assertSpec(task.parent, testEvents, verifiedEvents, "Task $path", rootSpec)
}
}
@@ -353,14 +355,15 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
private final Set verifiedEvents
private final OperationDescriptor parent
private String testDisplayName
+ private String operationDisplayName
- static void assertSpec(OperationDescriptor descriptor, List testEvents, Set verifiedEvents, @DelegatesTo(value = TestEventSpec, strategy = Closure.DELEGATE_FIRST) Closure> spec) {
+ static void assertSpec(OperationDescriptor descriptor, List testEvents, Set verifiedEvents, String expectedOperationDisplayName, @DelegatesTo(value = TestEventSpec, strategy = Closure.DELEGATE_FIRST) Closure> spec) {
verifiedEvents.add(descriptor)
DefaultTestEventSpec childSpec = new DefaultTestEventSpec(descriptor, testEvents, verifiedEvents)
spec.delegate = childSpec
spec.resolveStrategy = Closure.DELEGATE_FIRST
spec()
- childSpec.validate()
+ childSpec.validate(expectedOperationDisplayName)
}
DefaultTestEventSpec(OperationDescriptor parent, List testEvents, Set verifiedEvents) {
@@ -369,6 +372,11 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
this.verifiedEvents = verifiedEvents
}
+ @Override
+ void operationDisplayName(String displayName) {
+ this.operationDisplayName = displayName
+ }
+
@Override
void testDisplayName(String displayName) {
this.testDisplayName = displayName
@@ -394,12 +402,8 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
if (child == null) {
failWith("test suite", name)
}
- if (name.startsWith("Gradle Test")) {
- assert normalizeExecutor(child.displayName) == name
- } else {
- assert child.displayName == "Test suite '$name'"
- }
- assertSpec(child, testEvents, verifiedEvents, spec)
+ String expectedOperationDisplayName = name.startsWith("Gradle Test") ? normalizeExecutor(child.displayName) : "Test suite '$name'"
+ assertSpec(child, testEvents, verifiedEvents, expectedOperationDisplayName, spec)
}
@Override
@@ -415,8 +419,7 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
if (child == null) {
failWith("test class", name)
}
- assert child.displayName == "Test class $name"
- assertSpec(child, testEvents, verifiedEvents, spec)
+ assertSpec(child, testEvents, verifiedEvents, "Test class $name", spec)
}
@Override
@@ -434,8 +437,7 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
if (child == null) {
failWith("test", name)
}
- assert child.displayName == "Test $name($expectedClassName)"
- assertSpec(child, testEvents, verifiedEvents, spec)
+ assertSpec(child, testEvents, verifiedEvents, "Test $name($expectedClassName)", spec)
}
@Override
@@ -453,8 +455,7 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
if (child == null) {
failWith("test method suite", name)
}
- assert child.displayName == "Test method $name"
- assertSpec(child, testEvents, verifiedEvents, spec)
+ assertSpec(child, testEvents, verifiedEvents, "Test method $name", spec)
}
private void failWith(String what, String name) {
@@ -471,10 +472,15 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
throw err.build()
}
- void validate() {
+ void validate(String expectedOperationDisplayName) {
if (testDisplayName != null && parent.respondsTo("getTestDisplayName")) {
assert testDisplayName == ((TestOperationDescriptor) parent).testDisplayName
}
+ if (operationDisplayName != null) {
+ assert operationDisplayName == normalizeExecutor(parent.displayName)
+ } else {
+ assert expectedOperationDisplayName == normalizeExecutor(parent.displayName)
+ }
}
}
diff --git a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r70/TestDisplayNameJUnit5CrossVersionSpec.groovy b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r70/TestDisplayNameJUnit5CrossVersionSpec.groovy
index e6f357293ca1..28e98bda46d5 100644
--- a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r70/TestDisplayNameJUnit5CrossVersionSpec.groovy
+++ b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r70/TestDisplayNameJUnit5CrossVersionSpec.groovy
@@ -78,8 +78,10 @@ public class SimpleTests {
suite("Gradle Test Run :test") {
suite("Gradle Test Executor") {
testClass("org.example.SimpleTests") {
+ operationDisplayName "a class display name"
testDisplayName "a class display name"
test("test()") {
+ operationDisplayName "and a test display name"
testDisplayName "and a test display name"
}
}
@@ -191,29 +193,40 @@ class TestingAStackDemo {
suite("Gradle Test Run :test") {
suite("Gradle Test Executor") {
testClass("org.example.TestingAStackDemo") {
+ operationDisplayName "A stack"
testDisplayName "A stack"
test("isInstantiatedWithNew()") {
+ operationDisplayName "is instantiated with new Stack()"
testDisplayName "is instantiated with new Stack()"
}
testClass("org.example.TestingAStackDemo\$WhenNew") {
+ operationDisplayName "when new"
testDisplayName "when new"
test("isEmpty()") {
+ operationDisplayName "is empty"
testDisplayName "is empty"
}
test("throwsExceptionWhenPeeked()") {
+ operationDisplayName "throws EmptyStackException when peeked"
testDisplayName "throws EmptyStackException when peeked"
}
test("throwsExceptionWhenPopped()") {
+ operationDisplayName "throws EmptyStackException when popped"
testDisplayName "throws EmptyStackException when popped"
}
testClass("org.example.TestingAStackDemo\$WhenNew\$AfterPushing") {
+ operationDisplayName "after pushing an element"
+ testDisplayName "after pushing an element"
test("isNotEmpty()") {
+ operationDisplayName "it is no longer empty"
testDisplayName "it is no longer empty"
}
test("returnElementWhenPeeked()") {
+ operationDisplayName "returns the element when peeked but remains not empty"
testDisplayName "returns the element when peeked but remains not empty"
}
test("returnElementWhenPopped()") {
+ operationDisplayName "returns the element when popped and is empty"
testDisplayName "returns the element when popped and is empty"
}
}
@@ -265,22 +278,29 @@ public class ParameterizedTests {
suite("Gradle Test Run :test") {
suite("Gradle Test Executor") {
testClass("org.example.ParameterizedTests") {
+ operationDisplayName "Parameterized test"
testDisplayName "Parameterized test"
testMethodSuite("test1(String)") {
+ operationDisplayName "1st test"
testDisplayName "1st test"
test("test1(String)[1]") {
+ operationDisplayName "[1] foo"
testDisplayName "[1] foo"
}
test("test1(String)[2]") {
+ operationDisplayName "[2] bar"
testDisplayName "[2] bar"
}
}
testMethodSuite("test2(String)") {
+ operationDisplayName "2nd test"
testDisplayName "2nd test"
test("test2(String)[1]") {
+ operationDisplayName "1 ==> the test for 'foo'"
testDisplayName "1 ==> the test for 'foo'"
}
test("test2(String)[2]") {
+ operationDisplayName "2 ==> the test for 'bar'"
testDisplayName "2 ==> the test for 'bar'"
}
}
@@ -345,23 +365,30 @@ public class DynamicTests {
testClass("org.example.DynamicTests") {
testDisplayName "DynamicTests"
testMethodSuite("testFactory()") {
+ operationDisplayName "testFactory()"
testDisplayName "testFactory()"
testMethodSuite("testFactory()[1]") {
+ operationDisplayName "some container"
testDisplayName "some container"
testMethodSuite("testFactory()[1][1]") {
+ operationDisplayName "some nested container"
testDisplayName "some nested container"
test("testFactory()[1][1][1]") {
+ operationDisplayName "foo"
testDisplayName "foo"
}
test("testFactory()[1][1][2]") {
+ operationDisplayName "bar"
testDisplayName "bar"
}
}
}
}
testMethodSuite("anotherTestFactory()") {
+ operationDisplayName "another test factory"
testDisplayName "another test factory"
test("anotherTestFactory()[1]") {
+ operationDisplayName "foo"
testDisplayName "foo"
}
}
@@ -423,32 +450,42 @@ public class ComplexTests {
suite("Gradle Test Run :test") {
suite("Gradle Test Executor") {
testClass("org.example.ComplexTests") {
+ operationDisplayName "some_name for_tests"
testDisplayName "some_name for_tests"
test("test()") {
+ operationDisplayName "test"
testDisplayName "test"
}
test("simple_test()") {
+ operationDisplayName "simple test"
testDisplayName "simple test"
}
test("ugly_test()") {
+ operationDisplayName "pretty pretty_test"
testDisplayName "pretty pretty_test"
}
testMethodSuite("parametrized_test(int, String)") {
+ operationDisplayName "parametrized test (int, String)"
testDisplayName "parametrized test (int, String)"
test("parametrized_test(int, String)[1]") {
+ operationDisplayName "[1] 10, first"
testDisplayName "[1] 10, first"
}
test("parametrized_test(int, String)[2]") {
+ operationDisplayName "[2] 20, second"
testDisplayName "[2] 20, second"
}
}
testMethodSuite("ugly_parametrized_test(int, String)") {
+ operationDisplayName "pretty parametrized test"
testDisplayName "pretty parametrized test"
test("ugly_parametrized_test(int, String)[1]") {
+ operationDisplayName "[1] 30, third"
testDisplayName "[1] 30, third"
}
test("ugly_parametrized_test(int, String)[2]") {
+ operationDisplayName "[2] 40, fourth"
testDisplayName "[2] 40, fourth"
}
}
diff --git a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r75/CustomTestTaskProgressEventCrossVersionTest.groovy b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r75/CustomTestTaskProgressEventCrossVersionTest.groovy
index fd204cbdd577..0426468d3787 100644
--- a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r75/CustomTestTaskProgressEventCrossVersionTest.groovy
+++ b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r75/CustomTestTaskProgressEventCrossVersionTest.groovy
@@ -49,9 +49,7 @@ class CustomTestTaskProgressEventCrossVersionTest extends ToolingApiSpecificatio
void statusChanged(ProgressEvent event) {
if (event.descriptor.displayName == "Test suite 'MyCustomTestRoot'") {
suiteEvent = event
- } else if (targetDist.hasTestDisplayNames && event.descriptor.displayName == 'Test MyCustomTest(org.my.MyClass)') {
- testEvent = event
- } else if (!targetDist.hasTestDisplayNames && event.descriptor.displayName == 'org.my.MyClass descriptor') {
+ } else if (event.descriptor.displayName == 'org.my.MyClass descriptor') {
testEvent = event
}
}
diff --git a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r88/TestDisplayNameSpockCrossVersionSpec.groovy b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r88/TestDisplayNameSpockCrossVersionSpec.groovy
index fdecc6745aa8..73eb718e6d96 100644
--- a/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r88/TestDisplayNameSpockCrossVersionSpec.groovy
+++ b/platforms/ide/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r88/TestDisplayNameSpockCrossVersionSpec.groovy
@@ -125,6 +125,7 @@ class ParameterizedTests extends Specification {
testClass("org.example.ParameterizedTests") {
testDisplayName "ParameterizedTests"
testMethodSuite("length of #name is #length") {
+ operationDisplayName "length of #name is #length"
testDisplayName "length of #name is #length"
test("length of Spock is 5") {
testDisplayName "length of Spock is 5"