From 5ff20a1b4ecd9c23c8e5f4f845240533046c4729 Mon Sep 17 00:00:00 2001 From: Lev Serebryakov Date: Tue, 1 Aug 2023 18:00:09 +0200 Subject: [PATCH] IJPL-53: Add parameter for RunInEdt JUnit5 annotation to take write intent lock. Turn off by default for JUnit5. GitOrigin-RevId: 9093d3828cf88229b3c6a55ad48ccf2d1d201f47 --- .../java/codeInsight/ClsResolveTest.java | 2 +- .../ExcludePatternsInProjectFileIndexTest.kt | 2 +- .../openapi/roots/impl/OrderEntryGraphTest.kt | 2 +- ...OutputDirectoriesInProjectFileIndexTest.kt | 2 +- .../openapi/roots/impl/PackageIndexTest.kt | 2 +- .../UnloadedModulesInProjectFileIndexTest.kt | 2 +- .../PsiJavaModuleModificationTrackerTest.kt | 2 +- .../test/junit/KotlinJUnit5AcceptanceTest.kt | 2 +- .../openapi/application/impl/RwLockHolder.kt | 4 + ...hExcludedPatternsInProjectFileIndexTest.kt | 2 +- .../impl/IteratingContentUnderExcludedTest.kt | 2 +- .../impl/LibraryInProjectFileIndexTestCase.kt | 2 +- .../impl/ModuleRootsInProjectFileIndexTest.kt | 2 +- ...ModuleAndLibraryRootsInProjectFileIndex.kt | 2 +- .../NestedModuleRootsInProjectFileIndex.kt | 2 +- .../impl/NoIteratingUnderExcludedRootsTest.kt | 2 +- .../roots/impl/SdkInProjectFileIndexTest.kt | 2 +- .../SyntheticLibraryInProjectFileIndexTest.kt | 2 +- ...eIndexOnModuleRootFileModificationsTest.kt | 2 +- .../NonRecursiveWorkspaceFileSetTest.kt | 2 +- ...IndexContributorDynamicRegistrationTest.kt | 2 +- .../testFramework/common/src/EdtTestUtil.java | 4 +- .../testFramework/junit5/src/annotations.kt | 23 +- .../src/impl/EdtInterceptorExtension.kt | 30 +- .../test/showcase/JUnit5RunInEdtTest.java | 278 ++++++++++++++++++ .../ide/EntitiesOrphanageTest.kt | 2 +- .../ide/WorkspaceModelPerformanceTest.kt | 2 +- .../junit5/JUnit5CodeInsightTest.java | 2 +- .../jcef/MarkdownEditorCreationTest.kt | 2 +- 29 files changed, 354 insertions(+), 33 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/ClsResolveTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/ClsResolveTest.java index c463c72c7657..964a325b8cfa 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/ClsResolveTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/ClsResolveTest.java @@ -26,7 +26,7 @@ import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -@RunInEdt +@RunInEdt(writeIntent = true) public class ClsResolveTest { @RegisterExtension public TempDirectoryExtension tempDir = new TempDirectoryExtension(); diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/ExcludePatternsInProjectFileIndexTest.kt b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/ExcludePatternsInProjectFileIndexTest.kt index bcd6ae01fcc7..ec8c7b5eca85 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/ExcludePatternsInProjectFileIndexTest.kt +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/ExcludePatternsInProjectFileIndexTest.kt @@ -32,7 +32,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class ExcludePatternsInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OrderEntryGraphTest.kt b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OrderEntryGraphTest.kt index 5d51a8acb161..e417d586b320 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OrderEntryGraphTest.kt +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OrderEntryGraphTest.kt @@ -20,7 +20,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class OrderEntryGraphTest { @JvmField @RegisterExtension diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OutputDirectoriesInProjectFileIndexTest.kt b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OutputDirectoriesInProjectFileIndexTest.kt index 7b760b181d60..cf5fdbc1954c 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OutputDirectoriesInProjectFileIndexTest.kt +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/OutputDirectoriesInProjectFileIndexTest.kt @@ -29,7 +29,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class OutputDirectoriesInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/PackageIndexTest.kt b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/PackageIndexTest.kt index b6b0d18f82cf..46eccd535e0c 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/PackageIndexTest.kt +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/PackageIndexTest.kt @@ -29,7 +29,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class PackageIndexTest { @JvmField @RegisterExtension diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/UnloadedModulesInProjectFileIndexTest.kt b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/UnloadedModulesInProjectFileIndexTest.kt index ca2b9b7cd0a6..a1a8e2489700 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/UnloadedModulesInProjectFileIndexTest.kt +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/UnloadedModulesInProjectFileIndexTest.kt @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class UnloadedModulesInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/PsiJavaModuleModificationTrackerTest.kt b/java/java-tests/testSrc/com/intellij/psi/impl/PsiJavaModuleModificationTrackerTest.kt index 4af03492181b..04b7822a889d 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/PsiJavaModuleModificationTrackerTest.kt +++ b/java/java-tests/testSrc/com/intellij/psi/impl/PsiJavaModuleModificationTrackerTest.kt @@ -10,7 +10,7 @@ import com.intellij.testFramework.junit5.RunInEdt import org.junit.jupiter.api.Test import kotlin.test.assertTrue -@RunInEdt +@RunInEdt(writeIntent = true) class PsiJavaModuleModificationTrackerTest : LightJavaCodeInsightFixtureTestCase5() { @Test fun changeInPsiModuleInfo() { diff --git a/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/test/junit/KotlinJUnit5AcceptanceTest.kt b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/test/junit/KotlinJUnit5AcceptanceTest.kt index 4c0ff42398eb..0444cadab27b 100644 --- a/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/test/junit/KotlinJUnit5AcceptanceTest.kt +++ b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/test/junit/KotlinJUnit5AcceptanceTest.kt @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -@RunInEdt +@RunInEdt(writeIntent = true) class KotlinJUnit5AcceptanceTest : LightJavaCodeInsightFixtureTestCase5() { @BeforeEach internal fun setUp() { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/RwLockHolder.kt b/platform/platform-impl/src/com/intellij/openapi/application/impl/RwLockHolder.kt index 61f2bbb6a3b7..52f1cd7a7b50 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/RwLockHolder.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/RwLockHolder.kt @@ -35,6 +35,10 @@ class RwLockHolder(writeThread: Thread) { lock.writeIntentUnlock() } + fun isWriteIntentLocked(): Boolean { + return lock.isWriteThread && (lock.isWriteIntentLocked || lock.isWriteAcquired) + } + fun runWithoutImplicitRead(runnable: Runnable) { if (isImplicitReadOnEDTDisabled) { runnable.run() diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ContentRootWithExcludedPatternsInProjectFileIndexTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ContentRootWithExcludedPatternsInProjectFileIndexTest.kt index cbb597647543..f45d8bf8e39f 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ContentRootWithExcludedPatternsInProjectFileIndexTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ContentRootWithExcludedPatternsInProjectFileIndexTest.kt @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class ContentRootWithExcludedPatternsInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/IteratingContentUnderExcludedTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/IteratingContentUnderExcludedTest.kt index 742d00c6a5bb..7298f3074dff 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/IteratingContentUnderExcludedTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/IteratingContentUnderExcludedTest.kt @@ -23,7 +23,7 @@ import java.io.File import kotlin.io.path.pathString @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class IteratingContentUnderExcludedTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/LibraryInProjectFileIndexTestCase.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/LibraryInProjectFileIndexTestCase.kt index e9fd0794d2b1..1281bf64f504 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/LibraryInProjectFileIndexTestCase.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/LibraryInProjectFileIndexTestCase.kt @@ -31,7 +31,7 @@ import kotlin.test.assertEquals import kotlin.test.assertNull @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) abstract class LibraryInProjectFileIndexTestCase { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ModuleRootsInProjectFileIndexTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ModuleRootsInProjectFileIndexTest.kt index ec87ac6a6244..4d17ecf1dcf0 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ModuleRootsInProjectFileIndexTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/ModuleRootsInProjectFileIndexTest.kt @@ -41,7 +41,7 @@ import org.junit.jupiter.api.extension.RegisterExtension import kotlin.test.assertFalse @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class ModuleRootsInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleAndLibraryRootsInProjectFileIndex.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleAndLibraryRootsInProjectFileIndex.kt index 43452b53e37a..7312dcc222d8 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleAndLibraryRootsInProjectFileIndex.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleAndLibraryRootsInProjectFileIndex.kt @@ -24,7 +24,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class NestedModuleAndLibraryRootsInProjectFileIndex { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleRootsInProjectFileIndex.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleRootsInProjectFileIndex.kt index 5eeb35506e3d..c723ccd6ee09 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleRootsInProjectFileIndex.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NestedModuleRootsInProjectFileIndex.kt @@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class NestedModuleRootsInProjectFileIndex { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NoIteratingUnderExcludedRootsTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NoIteratingUnderExcludedRootsTest.kt index 5d64d973859f..75a91074a45d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NoIteratingUnderExcludedRootsTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/NoIteratingUnderExcludedRootsTest.kt @@ -37,7 +37,7 @@ import java.nio.file.Path import java.util.concurrent.ConcurrentHashMap @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class NoIteratingUnderExcludedRootsTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SdkInProjectFileIndexTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SdkInProjectFileIndexTest.kt index be6796f34ace..98fe1b582872 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SdkInProjectFileIndexTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SdkInProjectFileIndexTest.kt @@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class SdkInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SyntheticLibraryInProjectFileIndexTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SyntheticLibraryInProjectFileIndexTest.kt index 7dbe8accf6de..40faca95b5b3 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SyntheticLibraryInProjectFileIndexTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/SyntheticLibraryInProjectFileIndexTest.kt @@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class SyntheticLibraryInProjectFileIndexTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/UpdatingProjectFileIndexOnModuleRootFileModificationsTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/UpdatingProjectFileIndexOnModuleRootFileModificationsTest.kt index 8d67ba3e2108..6689bde83f26 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/UpdatingProjectFileIndexOnModuleRootFileModificationsTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/UpdatingProjectFileIndexOnModuleRootFileModificationsTest.kt @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class UpdatingProjectFileIndexOnModuleRootFileModificationsTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/NonRecursiveWorkspaceFileSetTest.kt b/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/NonRecursiveWorkspaceFileSetTest.kt index f8b38cb4e20b..dc9f26b9c0aa 100644 --- a/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/NonRecursiveWorkspaceFileSetTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/NonRecursiveWorkspaceFileSetTest.kt @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class NonRecursiveWorkspaceFileSetTest { @JvmField @RegisterExtension diff --git a/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/WorkspaceFileIndexContributorDynamicRegistrationTest.kt b/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/WorkspaceFileIndexContributorDynamicRegistrationTest.kt index e7951808871b..39fe551a0c07 100644 --- a/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/WorkspaceFileIndexContributorDynamicRegistrationTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/workspaceModel/core/fileIndex/WorkspaceFileIndexContributorDynamicRegistrationTest.kt @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class WorkspaceFileIndexContributorDynamicRegistrationTest { @JvmField @RegisterExtension diff --git a/platform/testFramework/common/src/EdtTestUtil.java b/platform/testFramework/common/src/EdtTestUtil.java index be1076e9e85d..a4af6dc77ad4 100644 --- a/platform/testFramework/common/src/EdtTestUtil.java +++ b/platform/testFramework/common/src/EdtTestUtil.java @@ -71,7 +71,7 @@ public final class EdtTestUtil { } Ref exception = new Ref<>(); - Runnable r = writeIntent ? + Runnable r = writeIntent && app == null ? () -> { try { setupEventQueue(); @@ -95,7 +95,7 @@ public final class EdtTestUtil { } }; - if (app != null) { + if (app != null && writeIntent) { app.invokeAndWait(r); } else { diff --git a/platform/testFramework/junit5/src/annotations.kt b/platform/testFramework/junit5/src/annotations.kt index 659586cdd461..5f9dec657276 100644 --- a/platform/testFramework/junit5/src/annotations.kt +++ b/platform/testFramework/junit5/src/annotations.kt @@ -10,19 +10,38 @@ import java.lang.annotation.Inherited * Instructs the framework to run methods in EDT. * If [allMethods] is set to `true` (default), then all test class methods will be run in EDT, including lifecycle methods. * If [allMethods] is set to `false`, then methods annotated with [RunMethodInEdt] will be run in EDT. + * If [writeIntent] is set to `true`, then all test methods will be run with Write Intent Lock by default. + * If [writeIntent] is set to `false` (default), then all test methods will be run without Write Intent Lock by default. */ @TestOnly @Target(AnnotationTarget.CLASS) @Inherited @ExtendWith(EdtInterceptorExtension::class) -annotation class RunInEdt(val allMethods: Boolean = true) +annotation class RunInEdt(val allMethods: Boolean = true, val writeIntent: Boolean = false) /** * Instructs the framework to run a single method in EDT. [RunInEdt] is required on the class level for this annotation to be picked up. + * If [writeIntent] is set to [WriteIntentMode.True], then test method will be run with Write Intent Lock. + * If [writeIntent] is set to [WriteIntentMode.False], then test method will be run without Write Intent Lock. + * If [writeIntent] is set to [WriteIntentMode.Default] (default), then Write Intent Lock is controlled by [RunInEdt.writeIntent]. */ @TestOnly @Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION) -annotation class RunMethodInEdt +annotation class RunMethodInEdt(val writeIntent: WriteIntentMode = WriteIntentMode.Default) { + /** + * Enumeration class that represents the mode for write intent. + * + * The WriteIntentMode enum class provides three possible modes: + * - True: Indicates that test must be run under Write Intent Lock. + * - False: Indicates that test must be run without Write Intent Lock. + * - Default: Indicates that the write intent lock is controlled by the parent annotation (see [RunInEdt]). + * + * This class is annotated with the @TestOnly annotation, indicating that it is intended + * for testing purposes only. + */ + @TestOnly + enum class WriteIntentMode { True, False, Default } +} /** * Injects a test [disposable][com.intellij.openapi.Disposable] to a field or a parameter in a test. diff --git a/platform/testFramework/junit5/src/impl/EdtInterceptorExtension.kt b/platform/testFramework/junit5/src/impl/EdtInterceptorExtension.kt index 701021a32f66..449467c8b419 100644 --- a/platform/testFramework/junit5/src/impl/EdtInterceptorExtension.kt +++ b/platform/testFramework/junit5/src/impl/EdtInterceptorExtension.kt @@ -3,6 +3,7 @@ package com.intellij.testFramework.junit5.impl import com.intellij.testFramework.junit5.RunInEdt import com.intellij.testFramework.junit5.RunMethodInEdt +import com.intellij.testFramework.junit5.RunMethodInEdt.WriteIntentMode import com.intellij.testFramework.runInEdtAndGet import org.jetbrains.annotations.TestOnly import org.junit.jupiter.api.extension.DynamicTestInvocationContext @@ -64,7 +65,9 @@ internal class EdtInterceptorExtension : InvocationInterceptor { ): T { if (shouldIntercept(invocationContext)) { extensionContext.getStore(ExtensionContext.Namespace.GLOBAL).put(testFactoryWasInterceptedKey, true) - return intercept(invocation) + val writeIntent = getWriteIntent(invocationContext) + extensionContext.getStore(ExtensionContext.Namespace.GLOBAL).put(testFactoryNeedsWriteIntentKey, writeIntent) + return intercept(invocation, writeIntent) } else { return invocation.proceed() @@ -77,7 +80,8 @@ internal class EdtInterceptorExtension : InvocationInterceptor { extensionContext: ExtensionContext, ) { if (extensionContext.getStore(ExtensionContext.Namespace.GLOBAL).get(testFactoryWasInterceptedKey) == true) { - intercept(invocation) + val writeIntent = extensionContext.getStore(ExtensionContext.Namespace.GLOBAL).get(testFactoryNeedsWriteIntentKey) as Boolean + intercept(invocation, writeIntent) } else { invocation.proceed() @@ -104,10 +108,11 @@ internal class EdtInterceptorExtension : InvocationInterceptor { private companion object { const val testFactoryWasInterceptedKey = "test factory was intercepted" + const val testFactoryNeedsWriteIntentKey = "test factory need write intent" fun intercept(invocation: Invocation, invocationContext: ReflectiveInvocationContext<*>): T { if (shouldIntercept(invocationContext)) { - return intercept(invocation) + return intercept(invocation, getWriteIntent(invocationContext)) } else { return invocation.proceed() @@ -119,8 +124,23 @@ internal class EdtInterceptorExtension : InvocationInterceptor { return runInEdt.allMethods || AnnotationSupport.findAnnotation(invocationContext.executable, RunMethodInEdt::class.java).isPresent } - fun intercept(invocation: Invocation): T { - return runInEdtAndGet { + fun getWriteIntent(invocationContext: ReflectiveInvocationContext<*>): Boolean { + val runInEdt = AnnotationSupport.findAnnotation(invocationContext.targetClass, RunInEdt::class.java).get() + val runMethodInEdtOpt = AnnotationSupport.findAnnotation(invocationContext.executable, RunMethodInEdt::class.java) + if (runMethodInEdtOpt.isEmpty) { + return runInEdt.writeIntent + } + else { + when (runMethodInEdtOpt.get().writeIntent) { + WriteIntentMode.True -> return true + WriteIntentMode.False -> return false + WriteIntentMode.Default -> return runInEdt.writeIntent + } + } + } + + fun intercept(invocation: Invocation, writeIntent: Boolean): T { + return runInEdtAndGet(writeIntent) { invocation.proceed() } } diff --git a/platform/testFramework/junit5/test/showcase/JUnit5RunInEdtTest.java b/platform/testFramework/junit5/test/showcase/JUnit5RunInEdtTest.java index 5d4391783450..d0c3ec462213 100644 --- a/platform/testFramework/junit5/test/showcase/JUnit5RunInEdtTest.java +++ b/platform/testFramework/junit5/test/showcase/JUnit5RunInEdtTest.java @@ -1,6 +1,7 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.testFramework.junit5.showcase; +import com.intellij.ide.IdeEventQueue; import com.intellij.testFramework.junit5.RunInEdt; import com.intellij.testFramework.junit5.RunMethodInEdt; import com.intellij.util.ui.EDT; @@ -115,23 +116,27 @@ final class JUnit5RunInEdtTest { @BeforeAll static void beforeAll() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @RunMethodInEdt MethodLevelAnnotationTest() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @RunMethodInEdt @BeforeEach void beforeEach() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @RunMethodInEdt @Test void testMethod() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @Test @@ -144,6 +149,7 @@ final class JUnit5RunInEdtTest { @ExtendWith(EmptyTestTemplateInvocationContextProvider.class) void testTemplate() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @RunMethodInEdt @@ -152,6 +158,7 @@ final class JUnit5RunInEdtTest { Assertions.assertTrue(EDT.isCurrentThreadEdt()); return List.of(DynamicTest.dynamicTest("dynamic test", () -> { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); })); } @@ -159,12 +166,219 @@ final class JUnit5RunInEdtTest { @AfterEach void afterEach() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @RunMethodInEdt @AfterAll static void afterAll() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + } + + @RunInEdt(allMethods = false, writeIntent = true) // required to make the extension able to handle lifecycle methods + static final class MethodLevelAnnotationTestWithDefaultWriteIntent { + + @RunMethodInEdt + @BeforeAll + static void beforeAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt + MethodLevelAnnotationTestWithDefaultWriteIntent() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt + @BeforeEach + void beforeEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt + @Test + void testMethod() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @Test + void testMethodUnannotated() { + Assertions.assertFalse(EDT.isCurrentThreadEdt()); + } + + @RunMethodInEdt + @TestTemplate + @ExtendWith(EmptyTestTemplateInvocationContextProvider.class) + void testTemplate() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt + @TestFactory + List testFactory() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + return List.of(DynamicTest.dynamicTest("dynamic test", () -> { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + })); + } + + @RunMethodInEdt + @AfterEach + void afterEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt + @AfterAll + static void afterAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + } + + @RunInEdt(allMethods = false) // required to make the extension able to handle lifecycle methods + static final class MethodLevelAnnotationTestWithPerMethodWriteIntent { + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @BeforeAll + static void beforeAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + MethodLevelAnnotationTestWithPerMethodWriteIntent() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @BeforeEach + void beforeEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @Test + void testMethod() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @Test + void testMethodUnannotated() { + Assertions.assertFalse(EDT.isCurrentThreadEdt()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @TestTemplate + @ExtendWith(EmptyTestTemplateInvocationContextProvider.class) + void testTemplate() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @TestFactory + List testFactory() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + return List.of(DynamicTest.dynamicTest("dynamic test", () -> { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + })); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @AfterEach + void afterEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.True) + @AfterAll + static void afterAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + } + + + @RunInEdt(allMethods = false, writeIntent = true) // required to make the extension able to handle lifecycle methods + static final class MethodLevelAnnotationTestWithoutPerMethodWriteIntent { + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @BeforeAll + static void beforeAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + MethodLevelAnnotationTestWithoutPerMethodWriteIntent() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @BeforeEach + void beforeEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @Test + void testMethod() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @Test + void testMethodUnannotated() { + Assertions.assertFalse(EDT.isCurrentThreadEdt()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @TestTemplate + @ExtendWith(EmptyTestTemplateInvocationContextProvider.class) + void testTemplate() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @TestFactory + List testFactory() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + return List.of(DynamicTest.dynamicTest("dynamic test", () -> { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + })); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @AfterEach + void afterEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @RunMethodInEdt(writeIntent = RunMethodInEdt.WriteIntentMode.False) + @AfterAll + static void afterAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } } @@ -174,26 +388,31 @@ final class JUnit5RunInEdtTest { @BeforeAll static void beforeAll() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } ClassLevelAnnotationTest() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @BeforeEach void beforeEach() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @Test void testMethod() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @TestTemplate @ExtendWith(EmptyTestTemplateInvocationContextProvider.class) void testTemplate() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @TestFactory @@ -201,17 +420,75 @@ final class JUnit5RunInEdtTest { Assertions.assertTrue(EDT.isCurrentThreadEdt()); return List.of(DynamicTest.dynamicTest("dynamic test", () -> { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); })); } @AfterEach void afterEach() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } @AfterAll static void afterAll() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + } + + @RunInEdt(writeIntent = true) + static final class ClassLevelAnnotationTestWithGlobalWriteIntent { + + @BeforeAll + static void beforeAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + ClassLevelAnnotationTestWithGlobalWriteIntent() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @BeforeEach + void beforeEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @Test + void testMethod() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @TestTemplate + @ExtendWith(EmptyTestTemplateInvocationContextProvider.class) + void testTemplate() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @TestFactory + List testFactory() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + return List.of(DynamicTest.dynamicTest("dynamic test", () -> { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + })); + } + + @AfterEach + void afterEach() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); + } + + @AfterAll + static void afterAll() { + Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertTrue(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } } @@ -224,6 +501,7 @@ final class JUnit5RunInEdtTest { @Test void testMethod() { Assertions.assertTrue(EDT.isCurrentThreadEdt()); + Assertions.assertFalse(IdeEventQueue.getInstance().getRwLockHolder().isWriteIntentLocked()); } } diff --git a/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/EntitiesOrphanageTest.kt b/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/EntitiesOrphanageTest.kt index 4975ec94f638..49ae6475c25d 100644 --- a/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/EntitiesOrphanageTest.kt +++ b/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/EntitiesOrphanageTest.kt @@ -23,8 +23,8 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import kotlin.test.assertEquals -@RunInEdt @TestApplication +@RunInEdt(writeIntent = true) class EntitiesOrphanageTest { @JvmField diff --git a/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt b/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt index d46c4fca48ab..3c957b9b29f9 100644 --- a/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt +++ b/platform/workspace/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.extension.RegisterExtension @TestApplication -@RunInEdt +@RunInEdt(writeIntent = true) class WorkspaceModelPerformanceTest { companion object { @RegisterExtension diff --git a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5CodeInsightTest.java b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5CodeInsightTest.java index a6d41e38e7a5..2839c00603a8 100644 --- a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5CodeInsightTest.java +++ b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5CodeInsightTest.java @@ -7,7 +7,7 @@ import com.intellij.testFramework.junit5.RunInEdt; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -@RunInEdt +@RunInEdt(writeIntent = true) abstract class JUnit5CodeInsightTest { protected JavaCodeInsightTestFixture myFixture; diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/preview/jcef/MarkdownEditorCreationTest.kt b/plugins/markdown/test/src/org/intellij/plugins/markdown/preview/jcef/MarkdownEditorCreationTest.kt index c57eeafe0e64..c53bc14c081d 100644 --- a/plugins/markdown/test/src/org/intellij/plugins/markdown/preview/jcef/MarkdownEditorCreationTest.kt +++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/preview/jcef/MarkdownEditorCreationTest.kt @@ -23,7 +23,7 @@ import java.nio.file.Path import javax.swing.JComponent @SkipInHeadlessEnvironment -@RunInEdt(allMethods = false) +@RunInEdt(allMethods = false, writeIntent = true) class MarkdownEditorCreationTest { @TestDisposable lateinit var disposable: Disposable