Skip to content

Commit

Permalink
Preserve old operation display names for backward compatibility with …
Browse files Browse the repository at this point in the history
…IntelliJ

Fixes #24538
  • Loading branch information
ov7a committed Apr 26, 2024
1 parent c65afab commit 0e67f27
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 21 deletions.
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -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 <a href="https://github.com/gradle/gradle/issues/24538">this issue</a> 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 <a href="https://github.com/JetBrains/kotlin/blob/1d38040a6bef2dba31d447bf28c220b81665a710/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MppTestReportHelper.kt#L55-L64">overriding TestDescriptor</a>.
* The problem only occurs in IntelliJ IDEA with multiplatform projects.
Expand All @@ -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) {
Expand Down
Expand Up @@ -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)
Expand All @@ -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)
}
}

Expand All @@ -353,14 +355,15 @@ abstract class TestLauncherSpec extends ToolingApiSpecification implements WithO
private final Set<OperationDescriptor> verifiedEvents
private final OperationDescriptor parent
private String testDisplayName
private String operationDisplayName

static void assertSpec(OperationDescriptor descriptor, List<JvmTestOperationDescriptor> testEvents, Set<OperationDescriptor> verifiedEvents, @DelegatesTo(value = TestEventSpec, strategy = Closure.DELEGATE_FIRST) Closure<?> spec) {
static void assertSpec(OperationDescriptor descriptor, List<JvmTestOperationDescriptor> testEvents, Set<OperationDescriptor> 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<JvmTestOperationDescriptor> testEvents, Set<OperationDescriptor> verifiedEvents) {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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) {
Expand All @@ -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)
}
}
}

Expand Down
Expand Up @@ -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"
}
}
Expand Down Expand Up @@ -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"
}
}
Expand Down Expand Up @@ -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'"
}
}
Expand Down Expand Up @@ -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"
}
}
Expand Down Expand Up @@ -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"
}
}
Expand Down

0 comments on commit 0e67f27

Please sign in to comment.