[test framework] add some documentation

Also includes some Grazie-suggested typo fixes.

Merge-request: IJ-MR-159365
Merged-by: Bartek Pacia <bartek.pacia@jetbrains.com>

GitOrigin-RevId: 60ac557d8a16d35dd2b61d748d805b9a2e1e8143
This commit is contained in:
Bartek Pacia
2025-04-18 13:52:35 +00:00
committed by intellij-monorepo-bot
parent 42aec9799d
commit 2a6109afe2
13 changed files with 172 additions and 79 deletions
@@ -0,0 +1,8 @@
// Copyright 2000-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
/**
* Provides interfaces for working with highlighting in standard IDE editors, interfaces
* and classes for defining intention actions and additional functionality related to background
* code analysis in the IDE.
* @see <a href="https://plugins.jetbrains.com/docs/intellij/glossary.html#js6hv0_51">Code Insight (IntelliJ Platform Docs)</a>
*/
package com.intellij.codeInsight;
@@ -1,22 +0,0 @@
<!--
~ Copyright 2000-2007 JetBrains s.r.o.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html><body bgcolor="white">
Provides interfaces for working with highlighting in standard IDEA editors, interfaces
and classes for defining intention actions and additional functionality related to background
code analysis in IDEA.
</body></html>
@@ -19,6 +19,19 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* A JUnit 3-compatible {@link UsefulTestCase} which is based around a {@link JavaCodeInsightTestFixture}.
* <p>
* This class is similar to {@link LightJavaCodeInsightFixtureTestCase}, but with some differences:
* <ul>
* <li>Uses a full project fixture setup with {@link IdeaProjectTestFixture}</li>
* <li>Creates a real module structure using {@link JavaModuleFixtureBuilder}</li>
* <li>Requires more setup time but provides a more complete environment</li>
* </ul>
* It can be considered a "heavy test", even though it doesn't inherit from {@link com.intellij.testFramework.HeavyPlatformTestCase}.
*
* @see <a href="https://plugins.jetbrains.com/docs/intellij/light-and-heavy-tests.html">Light and Heavy Tests (IntelliJ Platform Docs)</a>
*/
@TestDataPath("$CONTENT_ROOT/testData")
public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase implements TestIndexingModeSupporter {
protected JavaCodeInsightTestFixture myFixture;
@@ -87,7 +100,7 @@ public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase impl
return PathManager.getHomePath().replace(File.separatorChar, '/') + getBasePath();
}
protected void tuneFixture(JavaModuleFixtureBuilder<?> moduleBuilder) throws Exception {}
protected void tuneFixture(JavaModuleFixtureBuilder<?> moduleBuilder) throws Exception { }
protected Project getProject() {
return myFixture.getProject();
@@ -11,20 +11,21 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* A {@link CodeInsightTestFixture} extended a bit for Java-dependent tests.
*/
public interface JavaCodeInsightTestFixture extends CodeInsightTestFixture {
JavaPsiFacadeEx getJavaFacade();
PsiClass addClass(@Language("JAVA") final @NotNull @NonNls String classText);
/**
* Finds class by given fully-qualified name in {@link GlobalSearchScope#allScope(Project)}.
* Finds class by given fully qualified name in {@link GlobalSearchScope#allScope(Project)}.
*
* @param name Qualified name of class to find.
* @return Class instance.
*/
@NotNull
PsiClass findClass(@NotNull @NonNls String name);
@NotNull PsiClass findClass(@NotNull @NonNls String name);
@NotNull
PsiPackage findPackage(@NotNull @NonNls String name);
@NotNull PsiPackage findPackage(@NotNull @NonNls String name);
}
@@ -20,6 +20,15 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* A JUnit 3-compatible {@link UsefulTestCase} which is based around a {@link JavaCodeInsightTestFixture}.
* <p>
* This class is similar to {@link JavaCodeInsightFixtureTestCase}, but with some differences:
* <ul>
* <li>Uses a lightweight project setup with {@link LightProjectDescriptor}
* (and provides many predefined descriptors for different Java versions)</li>
* <li>Creates a simpler in-memory project structure</li>
* <li>Faster to initialize and run but with some limitations</li>
* </ul>
* @see LightJavaCodeInsightFixtureTestCase4
* @see LightJavaCodeInsightFixtureTestCase5
*/
@@ -210,4 +219,4 @@ public abstract class LightJavaCodeInsightFixtureTestCase extends UsefulTestCase
public @NotNull IndexingMode getIndexingMode() {
return myIndexingMode;
}
}
}
@@ -10,6 +10,12 @@ import org.junit.rules.RuleChain
import org.junit.rules.TestName
import org.junit.rules.TestRule
/**
* A wrapper around [LightJavaCodeInsightFixtureTestCase] that is JUnit 4-compatible.
*
* @see LightJavaCodeInsightFixtureTestCase
* @see LightJavaCodeInsightFixtureTestCase5
*/
@TestDataPath("\$CONTENT_ROOT/testData")
abstract class LightJavaCodeInsightFixtureTestCase4(
projectDescriptor: LightProjectDescriptor? = null,
@@ -11,6 +11,12 @@ import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.RegisterExtension
/**
* A wrapper around [LightJavaCodeInsightFixtureTestCase] that is JUnit 5-compatible.
*
* @see LightJavaCodeInsightFixtureTestCase
* @see LightJavaCodeInsightFixtureTestCase4
*/
@TestDataPath("\$CONTENT_ROOT/testData")
abstract class LightJavaCodeInsightFixtureTestCase5 (projectDescriptor: LightProjectDescriptor? = null) {
@@ -1,4 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html><body bgcolor="white">
Provides a test framework for writing tests which use IDEA projects, PSI and other services.
</body></html>
@@ -0,0 +1,10 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
/**
* Provides a JUnit 5-based test framework for writing tests which use IDE projects, PSI and other services.
* <p>
* For examples, see {@link com.intellij.testFramework.junit5.showcase}.
* <p>
* This package is a successor to {@link com.intellij.testFramework}.
*/
package com.intellij.testFramework.junit5;
@@ -5,24 +5,47 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Should be implemented by a test together with annotation @RunWith(com.intellij.testFramework.Parameterized.class)
* in order to get test run on all test data files located in directory. The desired directory could be configured
* whether by implementing {@link FileBasedTestCaseHelperEx#getRelativeBasePath()} or by annotating test case
* with {@link TestDataPath} (annotation would enable additional test assistance support, e.g.
* navigation from test data to test class/method as well as starting tests right from test data files).
* <br/><br/>
* BTW @RunWith works also on abstract super classes.
* Should be implemented by a test class together with the annotation {@code @RunWith(com.intellij.testFramework.Parameterized.class)}
* in order to get test run on all test data files located in directory.
* <p>
* The desired directory can be configured by implementing
* {@link FileBasedTestCaseHelperEx#getRelativeBasePath()}
* or by annotating the test case class with {@link TestDataPath}.
* Annotating with {@link TestDataPath} enables additional test assistance support, like:
* <ul>
* <li>navigation from test data to the test class/method</li>
* <li>starting tests right from the test data files</li>
* </ul>
* N.B. {@code @RunWith} works also on abstract super classes.
*
* @see LightPlatformCodeInsightTestCase#params(Class)
*/
public interface FileBasedTestCaseHelper {
/**
* @return for 'before' files should return core file name or null otherwise
* <h3>Example 1</h3>
* Input: {@code afterMethodCanBeStatic.java}
* <p>
* Output: {@code null}
* <h3>Example 2</h3>
* Input: {@code beforeMethodCanBeStatic.java}
* <p>
* Output: {@code MethodCanBeStatic.java}
*
* @return the "core part" of the file name if the file is an "after" file, or null otherwise
*/
@Nullable
String getFileSuffix(@NotNull String fileName);
@Nullable String getFileSuffix(@NotNull String fileName);
/**
* @return for 'after' files should return core file name or null otherwise
* <h3>Example 1</h3>
* Input: {@code afterMethodCanBeStatic.java}
* <p>
* Output: {@code MethodCanBeStatic.java}
* <h3>Example 2</h3>
* Input: {@code beforeMethodCanBeStatic.java}
* <p>
* Output: {@code null}
*
* @return the "core part" of the file name if the file is an "after" file, or null otherwise
*/
default @Nullable String getBaseName(@NotNull String fileAfterSuffix) {
return null;
@@ -77,11 +77,15 @@ import static com.intellij.testFramework.common.TestEnvironmentKt.initializeTest
import static org.junit.Assume.assumeTrue;
/**
* This class is compatible with both JUnit 3 and JUnit 4,
* but not JUnit 5 (see the module intellij.platform.testFramework.junit5 instead).
* This class is compatible with both JUnit 3 and JUnit 4, but not JUnit 5.
* <p>
* To use JUnit 4, annotate your test subclass with {@code @RunWith(JUnit4.class)} or any other (like {@code Parametrized.class}),
* and you are all set.
* To use JUnit 3, make the name of your test methods start with {@code test}, as per the JUnit 3 convention.
* <p>
* To use JUnit 4, annotate your test subclass with {@code @RunWith(JUnit4.class)} or any other runner (like {@code Parametrized.class}).
* <p>
* For JUnit 5 support,
* see the {@code intellij.platform.testFramework.junit5} module in {@code community/platform/testFramework/junit5}.
* <h3>Caveats</h3>
* If you're looking for JUnit 4 for Assume support and still have JUnit 3 tests,
* consider using {@code @RunWith(JUnit38AssumeSupportRunner.class)}.
* <p>
@@ -90,9 +94,9 @@ import static org.junit.Assume.assumeTrue;
* <p>
* Don't define {@code @Rule}s calling {@linkplain #runBare()}, just subclassing this class (directly or indirectly) is enough.
* <p>
* The execution order is the following:
* <h3>Execution order</h3>
* <ul>
* <li><em>(JUnit 4 only)</em> {@linkplain #checkShouldRunTest} that can be used to ignore tests with meaningful message
* <li><em>(JUnit 4 only)</em> {@linkplain #checkShouldRunTest} that can be used to ignore tests with a meaningful message
* <li>{@linkplain #shouldRunTest()} is also called (both JUnit 3 and JUnit 4)
* <li>{@linkplain #setUp()}, usually overridden so that it initializes classes in order from base to specific
* <ul>
@@ -237,7 +241,7 @@ public abstract class UsefulTestCase extends TestCase {
Disposer.setDebugMode(!isStressTest);
if (isIconRequired()) {
// ensure that IconLoader will not use fake empty icon
// ensure that IconLoader will not use a fake empty icon
try {
IconManager.Companion.activate(new CoreIconManager());
}
@@ -431,8 +435,8 @@ Most likely there was an uncaught exception in asynchronous execution that resul
* This reflects the way the default {@link TestCase#runBare} works, with few notable exceptions:
* <ul>
* <li/> {@link #tearDown} is called even if {@link #setUp} has failed;
* <li/> exceptions from tearDown() don't shadow those from the main test method, but are rather linked as suppressed;
* <li/> it allows to customise the way the methods are invoked through {@link #runTestRunnable},
* <li/> exceptions from tearDown() don't shadow those from the main test method but are rather linked as suppressed;
* <li/> it allows customizing the way the methods are invoked through {@link #runTestRunnable},
* {@link #invokeSetUp} and {@link #invokeTearDown}, for example, to make them execute on a different thread.
* </ul>
*/
@@ -461,7 +465,7 @@ Most likely there was an uncaught exception in asynchronous execution that resul
/**
* Logs the setup cost grouped by test fixture class (superclass of the current test class).
*
* @param cost a cost of setup in milliseconds
* @param cost setup cost in milliseconds
*/
private void logPerClassCost(int cost, @NotNull ObjectIntMap<String> costMap, @NotNull ObjectIntMap<String> countMap) {
String name = getClass().getSuperclass().getName();
@@ -1070,7 +1074,7 @@ Most likely there was an uncaught exception in asynchronous execution that resul
/**
* @return true for a test which performs a lot of computations to test resource consumption, not correctness.
* Such tests should avoid performing expensive consistency checks, e.g., data structure consistency complex validations.
* If you want your test to be treated as "Performance", mention "Performance" word in its class/method name.
* If you want your test to be treated as "Performance", include the "Performance" word in its class/method name.
* For example: {@code public void testHighlightingPerformance()}
*/
public final boolean isPerformanceTest() {
@@ -59,7 +59,18 @@ import java.util.function.Function;
import java.util.function.Predicate;
/**
* @see <a href="https://plugins.jetbrains.com/docs/intellij/testing-plugins.html">Testing Plugins</a>.
* Holds state such as editor, file, document, caret(s) position, and so on.
* Also provides a rich API for setting this state up and performing assertions on it.
* <p>
* It is not tied to any specific test framework.
* <p>
* Usually used to test <i>code insight features</i> such as inspections,
* intentions, code completion, highlighting, navigation, and refactorings in
* a headless-like IDE instance.
*
* @see <a href="https://plugins.jetbrains.com/docs/intellij/testing-plugins.html">Testing Overview</a>
* @see <a href="https://plugins.jetbrains.com/docs/intellij/tests-and-fixtures.html">Tests and Fixtures</a>
* @see <a href="https://plugins.jetbrains.com/docs/intellij/testing-highlighting.html">Testing Highlighting</a>
* @see IdeaTestFixtureFactory#createCodeInsightFixture(IdeaProjectTestFixture)
*/
public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
@@ -88,7 +99,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
PsiFile getFile();
/**
* @return the action context for current in-memory editor
* @return the action context for the current in-memory editor
*/
@RequiresReadLock
default ActionContext getActionContext() {
@@ -228,7 +239,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
/**
* Compares a file in the test project with a file in the testdata directory.
*
* @param filePath path to file to be checked, relative to the source root of the test project.
* @param filePath path to the file to be checked, relative to the source root of the test project.
* @param expectedFile path to file to check against, relative to the testdata path.
* @param ignoreTrailingWhitespaces whether the comparison should ignore trailing whitespaces.
*/
@@ -244,7 +255,6 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
*/
void enableInspections(InspectionProfileEntry @NotNull ... inspections);
@SuppressWarnings("unchecked")
void enableInspections(Class<? extends LocalInspectionTool> @NotNull ... inspections);
void enableInspections(@NotNull Collection<Class<? extends LocalInspectionTool>> inspections);
@@ -288,21 +298,38 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
boolean checkWeakWarnings,
@TestDataFile VirtualFile @NotNull ... files);
/**
* Check highlighting of file already loaded by {@code configure*} methods.
*
* @return duration
* @see #checkHighlighting(boolean, boolean, boolean, boolean)
*/
long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings);
/**
* Checks highlighting of the file loaded into the in-memory editor.
* <p>
* To load the file in to the in-memory editor, use the {@code configure*} family of methods,
* for example {@link #configureByText(String, String)} or {@link #configureByFile(String)}}.
* <p>
* Throws an exception if the file isn't loaded into the in-memory editor.
*
* @return highlighting duration in milliseconds
* @see ExpectedHighlightingData
*/
long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, boolean ignoreExtraHighlighting);
/**
* @see #checkHighlighting(boolean, boolean, boolean, boolean)
*/
long checkHighlighting();
/**
* Runs highlighting test for the given files.
* Loads files into the in-memory editor and tests highlighting for the first of them.
* <p>
* The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with {@code checkInfos=false}.
* This is essentially a shortcut for
* {@link #configureByFiles(String...)}
* followed by
* {@link #testHighlighting(boolean, boolean checkInfos, boolean, String...)}
* with {@code checkInfos=false}.
*
* @param filePaths the first file is tested only; the others are just copied along with the first.
* @return highlighting duration in milliseconds
@@ -321,7 +348,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
void testInspection(@NotNull String testDir, @NotNull InspectionToolWrapper<?, ?> toolWrapper, @NotNull VirtualFile sourceDir);
/**
* @return all highlight infos for current file
* @return all highlight infos for the current file
*/
@NotNull
@Unmodifiable
@@ -371,7 +398,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
List<IntentionAction> getAvailableIntentions();
/**
* Returns all intentions or quick fixes which are available in position marked by {@link #CARET_MARKER},
* Returns all intentions or quick fixes that are available in position marked by {@link #CARET_MARKER},
* and whose text starts with the specified hint text.
*
* @param hint the text that the intention text should begin with.
@@ -398,7 +425,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
/**
* Copies multiple files from the testdata directory to the same relative paths in the test project directory, opens the first of them
* in the in-memory editor and returns an intention action or quickfix with the name exactly matching the specified text.
* in the in-memory editor, and returns an intention action or quickfix with the name exactly matching the specified text.
*
* @param intentionName the text that the intention text should be equal to.
* @param filePaths the list of file paths to copy to the test project directory.
@@ -425,9 +452,9 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
@Nullable String getIntentionPreviewText(@NotNull String hint);
/**
* Checks whether intention preview is HTML with expected text.
* Checks whether the intention preview is HTML with expected text.
*
* @param action action to get the preview from
* @param action action to get the preview from
* @param expected expected HTML preview text
*/
void checkIntentionPreviewHtml(@NotNull IntentionAction action, @NotNull @Language("HTML") String expected);
@@ -485,7 +512,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
* <p>
* Checks that lookup is shown, and it contains items with given lookup strings
*
* @param items most probably will contain > 1 items
* @param items most probably will contain more than 1 item
*/
void testCompletionVariants(@NotNull @TestDataFile String fileBefore, String @NotNull ... items);
@@ -543,7 +570,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
/**
* Opens the specified file in the editor, places the caret and selection according to the markup,
* launches the Find Usages action and returns the items displayed in the usage view.
* launches the Find Usages action, and returns the items displayed in the usage view.
*/
@NotNull
Collection<Usage> testFindUsagesUsingAction(@TestDataFile String @NotNull ... fileNames);
@@ -614,6 +641,9 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
void checkResult(@NotNull String filePath, @NotNull String expectedText, boolean stripTrailingSpaces);
/**
* @return document for the specified PSI file.
*/
Document getDocument(@NotNull PsiFile file);
@NotNull
@@ -691,7 +721,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
void renameElementAtCaret(@NotNull String newName);
/**
* Renames element in position marked by {@link #CARET_MARKER} using injected {@link RenameHandler}.
* Renames the element in position marked by {@link #CARET_MARKER} using injected {@link RenameHandler}.
* <p>
* Very close to {@link #renameElementAtCaret(String)} but uses handlers.
*
@@ -735,6 +765,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
/**
* Misnamed, actually it checks only parameter hints.
*
* @see #testInlays(Function, Predicate)
*/
void testInlays();
@@ -776,20 +807,20 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
* carets (places marked with {@link #CARET_MARKER} in file).
* Example:
* <pre>
* PyC&lt;caret&gt; is IDE for Py&lt;caret&gt;
* PyC&lt;caret&gt; is an IDE for Py&lt;caret&gt;
* </pre>
* should be completed to
* <pre>
* PyCharm is IDE for Python
* PyCharm is an IDE for Python
* </pre>
* Actually, it works just like {@link #completeBasic()} but supports
* several {@link #CARET_MARKER}.
* several {@link #CARET_MARKER}s.
*
* @param charToTypeIfOnlyOneOrNoCompletion this char will be typed when the completion performed automatically.
* It is a legacy, consider providing it as {@code null} to avoid typing.
* @param charToTypeIfMultipleCompletions this char will be typed in case of multiple completion variants.
* It could be used to complete the suggestion with {@code '\t'} for example.
* Provide {@code null} to avoid typing.
* @param charToTypeIfMultipleCompletions this char will be typed in case of multiple completion variants.
* It could be used to complete the suggestion with {@code '\t'} for example.
* Provide {@code null} to avoid typing.
* @return list of all completion elements just like in {@link #completeBasic()}
* @see #completeBasic()
*/
@@ -852,7 +883,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
/**
* @return Disposable for the corresponding project fixture.
* It's disposed earlier than {@link UsefulTestCase#getTestRootDisposable()} and can be useful
* e.g. for avoiding library virtual pointers leaks: {@code PsiTestUtil.addLibrary(myFixture.getProjectDisposable(), ...)}
* e.g., for avoiding library virtual pointers leaks: {@code PsiTestUtil.addLibrary(myFixture.getProjectDisposable(), ...)}
*/
default @NotNull Disposable getProjectDisposable() {
return ((ProjectEx)getProject()).getEarlyDisposable();
@@ -0,0 +1,8 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
/**
* Provides a test framework for writing tests which use IDE projects, PSI and other services.
* <p>
* This framework is based around JUnit 3 and JUnit 4. Consider using a JUnit 5-based successor to this package – see {@link com.intellij.testFramework.junit5}.
*/
package com.intellij.testFramework;