mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[junit6] support for running junit6 IDEA-378235
(cherry picked from commit d8150843a509548fe1f04b8871a469a212584f0f) IJ-MR-175463 GitOrigin-RevId: 59e5f52d5653e7bbac6ee4f9b9fdb62d12732f68
This commit is contained in:
committed by
intellij-monorepo-bot
parent
aeab189eb4
commit
e97d627f6d
Generated
+38
@@ -0,0 +1,38 @@
|
||||
<component name="libraryTable">
|
||||
<library name="JUnit6" type="repository">
|
||||
<properties maven-id="org.junit.jupiter:junit-jupiter-api:6.0.0-RC2">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/6.0.0-RC2/junit-jupiter-api-6.0.0-RC2.jar">
|
||||
<sha256sum>db1404414d23effbeb1202025f1e984f9069ddeed6d4c1826bb70bce8c70fb31</sha256sum>
|
||||
</artifact>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar">
|
||||
<sha256sum>48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b</sha256sum>
|
||||
</artifact>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/6.0.0-RC2/junit-platform-commons-6.0.0-RC2.jar">
|
||||
<sha256sum>7f7d65576d02547d4d6b44ec3d49dd37904cd8927baae5bddd541cd24d513a39</sha256sum>
|
||||
</artifact>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar">
|
||||
<sha256sum>b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38</sha256sum>
|
||||
</artifact>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar">
|
||||
<sha256sum>1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/6.0.0-RC2/junit-jupiter-api-6.0.0-RC2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/6.0.0-RC2/junit-platform-commons-6.0.0-RC2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/6.0.0-RC2/junit-jupiter-api-6.0.0-RC2-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/6.0.0-RC2/junit-platform-commons-6.0.0-RC2-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
Generated
+33
@@ -0,0 +1,33 @@
|
||||
<component name="libraryTable">
|
||||
<library name="JUnit6Launcher" type="repository">
|
||||
<properties maven-id="org.junit.platform:junit-platform-launcher:6.0.0-RC2">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/6.0.0-RC2/junit-platform-launcher-6.0.0-RC2.jar">
|
||||
<sha256sum>3c41ec667a185ec0b51ca8d9d68e5f0e425d6645c6e4eb64b8a81716a4deaed1</sha256sum>
|
||||
</artifact>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/6.0.0-RC2/junit-platform-engine-6.0.0-RC2.jar">
|
||||
<sha256sum>8f5e8cb552c311d4a236334975a5ff9ec4db5f64e84151d01500f31fa19edfba</sha256sum>
|
||||
</artifact>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar">
|
||||
<sha256sum>1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
<exclude>
|
||||
<dependency maven-id="org.apiguardian:apiguardian-api" />
|
||||
<dependency maven-id="org.opentest4j:opentest4j" />
|
||||
<dependency maven-id="org.junit.platform:junit-platform-commons" />
|
||||
</exclude>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/6.0.0-RC2/junit-platform-launcher-6.0.0-RC2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/6.0.0-RC2/junit-platform-engine-6.0.0-RC2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/6.0.0-RC2/junit-platform-launcher-6.0.0-RC2-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/6.0.0-RC2/junit-platform-engine-6.0.0-RC2-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
Generated
+2
@@ -590,6 +590,8 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/junit/testFramework/intellij.junit.testFramework.iml" filepath="$PROJECT_DIR$/plugins/junit/testFramework/intellij.junit.testFramework.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/junit5_rt/intellij.junit.v5.rt.iml" filepath="$PROJECT_DIR$/plugins/junit5_rt/intellij.junit.v5.rt.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/junit5_rt_tests/intellij.junit.v5.rt.tests.iml" filepath="$PROJECT_DIR$/plugins/junit5_rt_tests/intellij.junit.v5.rt.tests.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/junit6_rt/intellij.junit.v6.rt.iml" filepath="$PROJECT_DIR$/plugins/junit6_rt/intellij.junit.v6.rt.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/junit6_rt_tests/intellij.junit.v6.rt.tests.iml" filepath="$PROJECT_DIR$/plugins/junit6_rt_tests/intellij.junit.v6.rt.tests.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jvm/jvm-analysis-api/intellij.jvm.analysis.iml" filepath="$PROJECT_DIR$/jvm/jvm-analysis-api/intellij.jvm.analysis.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jvm/jvm-analysis-impl/intellij.jvm.analysis.impl.iml" filepath="$PROJECT_DIR$/jvm/jvm-analysis-impl/intellij.jvm.analysis.impl.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jvm/jvm-analysis-internal-testFramework/intellij.jvm.analysis.internal.testFramework.iml" filepath="$PROJECT_DIR$/jvm/jvm-analysis-internal-testFramework/intellij.jvm.analysis.internal.testFramework.iml" />
|
||||
|
||||
@@ -885,6 +885,8 @@ plugins/junit/kotlin-tests-shared
|
||||
plugins/junit/testFramework
|
||||
plugins/junit5_rt
|
||||
plugins/junit5_rt_tests
|
||||
plugins/junit6_rt
|
||||
plugins/junit6_rt_tests
|
||||
plugins/junit_rt
|
||||
plugins/keymaps/eclipse-keymap
|
||||
plugins/keymaps/netbeans5.6-keymap
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
@@ -71,7 +71,7 @@ public class InheritorChooser {
|
||||
}
|
||||
|
||||
if (classes.size() == 1) {
|
||||
runForClass(classes.get(0), psiMethod, context, performRunnable);
|
||||
runForClass(classes.getFirst(), psiMethod, context, performRunnable);
|
||||
return true;
|
||||
}
|
||||
if (classes.isEmpty()) return false;
|
||||
@@ -83,7 +83,7 @@ public class InheritorChooser {
|
||||
final List<PsiClass> psiClasses = new ArrayList<>(Arrays.asList(((PsiClassOwner)containingFile).getClasses()));
|
||||
psiClasses.retainAll(classes);
|
||||
if (psiClasses.size() == 1) {
|
||||
runForClass(psiClasses.get(0), psiMethod, context, performRunnable);
|
||||
runForClass(psiClasses.getFirst(), psiMethod, context, performRunnable);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public class InheritorChooser {
|
||||
classes.sort(renderer.getComparator());
|
||||
|
||||
//suggest to run all inherited tests
|
||||
classes.add(0, null);
|
||||
classes.addFirst(null);
|
||||
String locationName = psiMethod != null ? psiMethod.getName() : containingClass.getName();
|
||||
JBPopupFactory.getInstance()
|
||||
.createPopupChooserBuilder(classes)
|
||||
@@ -137,7 +137,7 @@ public class InheritorChooser {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void collectClasses(PsiClass containingClass, List<? super PsiClass> classes, HashSet<? super PsiClass> visited) {
|
||||
private static void collectClasses(PsiClass containingClass, List<? super PsiClass> classes, Set<? super PsiClass> visited) {
|
||||
if (!visited.add(containingClass)) return;
|
||||
Set<PsiClass> containers = new HashSet<>();
|
||||
final boolean isJUnit5 = ReadAction.compute(() -> JUnitUtil.isJUnit5(containingClass));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
@@ -38,7 +38,7 @@ public final class JUnitUtil {
|
||||
public static final String RULE_ANNOTATION = "org.junit.Rule";
|
||||
public static final String TEST5_PACKAGE_FQN = "org.junit.jupiter.api";
|
||||
public static final String TEST5_ANNOTATION = "org.junit.jupiter.api.Test";
|
||||
|
||||
|
||||
public static final String CUSTOM_TESTABLE_ANNOTATION = "org.junit.platform.commons.annotation.Testable";
|
||||
public static final Set<String> CUSTOM_TESTABLE_ANNOTATION_LIST = Collections.singleton(CUSTOM_TESTABLE_ANNOTATION);
|
||||
|
||||
@@ -304,7 +304,6 @@ public final class JUnitUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isJUnit5TestClass(final @NotNull PsiClass psiClass, boolean checkAbstract) {
|
||||
final PsiModifierList modifierList = psiClass.getModifierList();
|
||||
if (modifierList == null) return false;
|
||||
|
||||
@@ -68,6 +68,7 @@ public final @NonNls class JUnitCommonClassNames {
|
||||
public static final String ORG_JUNIT_JUPITER_API_EXTENSION_EXTEND_WITH = "org.junit.jupiter.api.extension.ExtendWith";
|
||||
public static final String ORG_JUNIT_JUPITER_API_TEST_INSTANCE = "org.junit.jupiter.api.TestInstance";
|
||||
public static final String ORG_JUNIT_PLATFORM_ENGINE_TEST_ENGINE = "org.junit.platform.engine.TestEngine";
|
||||
public static final String ORG_JUNIT_PLATFORM_ENGINE_CANCELLATION_TOKEN = "org.junit.platform.engine.CancellationToken";
|
||||
public static final String ORG_JUNIT_PLATFORM_ENGINE = "org.junit.platform.engine";
|
||||
public static final String ORG_JUNIT_JUPITER_API_EXTENSION_REGISTER_EXTENSION = "org.junit.jupiter.api.extension.RegisterExtension";
|
||||
public static final String ORG_JUNIT_JUPITER_API_EXTENSION_BEFORE_ALL_CALLBACK = "org.junit.jupiter.api.extension.BeforeAllCallback";
|
||||
@@ -83,4 +84,7 @@ public final @NonNls class JUnitCommonClassNames {
|
||||
public static final String ORG_JUNIT_EXPERIMENTAL_THEORIES_DATAPOINTS = "org.junit.experimental.theories.DataPoints";
|
||||
public static final String ORG_JUNIT_EXPERIMENTAL_RUNNERS_ENCLOSED = "org.junit.experimental.runners.Enclosed";
|
||||
public static final String ORG_JUNIT_JUPITER_API_IO_TEMPDIR = "org.junit.jupiter.api.io.TempDir";
|
||||
public static final String ORG_JUNIT_PLATFORM_SUITE_API_SUITE = "org.junit.platform.suite.api.Suite";
|
||||
// junit 6
|
||||
public static final String ORG_JUNIT_JUPITER_API_METHOD_ORDERER_DEFAULT = "org.junit.jupiter.api.MethodOrderer.Default";
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -42,15 +43,19 @@ public abstract class JavaTestFramework implements JvmTestFramework {
|
||||
public boolean isLibraryAttached(@NotNull Module module) {
|
||||
GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module);
|
||||
Project project = module.getProject();
|
||||
PsiClass c = DumbService.getInstance(project).computeWithAlternativeResolveEnabled(() -> JavaPsiFacade.getInstance(project).findClass(getMarkerClassFQName(), scope));
|
||||
return c != null;
|
||||
return DumbService.getInstance(project).computeWithAlternativeResolveEnabled(() -> {
|
||||
for (String markerClassFQName : getMarkerClassFQNames()) {
|
||||
if (JavaPsiFacade.getInstance(project).findClass(markerClassFQName, scope) != null) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getLibraryPath() {
|
||||
ExternalLibraryDescriptor descriptor = getFrameworkLibraryDescriptor();
|
||||
if (descriptor != null) {
|
||||
return descriptor.getLibraryClassesRoots().get(0);
|
||||
return descriptor.getLibraryClassesRoots().getFirst();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -60,14 +65,24 @@ public abstract class JavaTestFramework implements JvmTestFramework {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Collection<String> getMarkerClassFQNames() {
|
||||
return Collections.singleton(getMarkerClassFQName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getMarkerClassFQNames()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
protected abstract String getMarkerClassFQName();
|
||||
|
||||
/**
|
||||
* Return {@code true} iff {@link #getMarkerClassFQName()} can be found in the resolve scope of {@code clazz}
|
||||
* Return {@code true} iff {@link #getMarkerClassFQNames()} can be found in the resolve scope of {@code clazz}
|
||||
*/
|
||||
public boolean isFrameworkAvailable(@NotNull PsiElement clazz) {
|
||||
String markerClassFQName = getMarkerClassFQName();
|
||||
return isFrameworkApplicable(clazz, markerClassFQName);
|
||||
for (String markerClassFQName : getMarkerClassFQNames()) {
|
||||
if (isFrameworkApplicable(clazz, markerClassFQName)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean isFrameworkApplicable(@NotNull PsiElement clazz, String markerClassFQName) {
|
||||
|
||||
+66
-6
@@ -3246,6 +3246,72 @@ java_library(
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "junit6",
|
||||
exports = [
|
||||
":junit-jupiter-api-6_0_0-RC2_http_import",
|
||||
":opentest4j-1_3_0_http_import",
|
||||
":junit-platform-commons-6_0_0-RC2_http_import",
|
||||
":apiguardian-api-1_1_2_http_import",
|
||||
":jspecify-1_0_0_http_import",
|
||||
],
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "junit-jupiter-api-6_0_0-RC2_http_import",
|
||||
jar = "@junit-jupiter-api-6_0_0-RC2_http//file",
|
||||
source_jar = "@junit-jupiter-api-6_0_0-RC2-sources_http//file"
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "junit-platform-commons-6_0_0-RC2_http_import",
|
||||
jar = "@junit-platform-commons-6_0_0-RC2_http//file",
|
||||
source_jar = "@junit-platform-commons-6_0_0-RC2-sources_http//file"
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "jspecify-1_0_0_http_import",
|
||||
jar = "@jspecify-1_0_0_http//file",
|
||||
source_jar = "@jspecify-1_0_0-sources_http//file"
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "junit6-provided",
|
||||
exports = [":junit6"],
|
||||
neverlink = True,
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "junit6Launcher",
|
||||
exports = [
|
||||
":junit-platform-launcher-6_0_0-RC2_http_import",
|
||||
":junit-platform-engine-6_0_0-RC2_http_import",
|
||||
":jspecify-1_0_0_http_import",
|
||||
],
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "junit-platform-launcher-6_0_0-RC2_http_import",
|
||||
jar = "@junit-platform-launcher-6_0_0-RC2_http//file",
|
||||
source_jar = "@junit-platform-launcher-6_0_0-RC2-sources_http//file"
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "junit-platform-engine-6_0_0-RC2_http_import",
|
||||
jar = "@junit-platform-engine-6_0_0-RC2_http//file",
|
||||
source_jar = "@junit-platform-engine-6_0_0-RC2-sources_http//file"
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "junit6Launcher-provided",
|
||||
exports = [":junit6Launcher"],
|
||||
neverlink = True,
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "jvm-native-trusted-roots",
|
||||
jar = "@jvm-native-trusted-roots-1_1_7_http//file",
|
||||
@@ -4557,12 +4623,6 @@ jvm_import(
|
||||
source_jar = "@lifecycle-common-jvm-2_9_2-sources_http//file"
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "jspecify-1_0_0_http_import",
|
||||
jar = "@jspecify-1_0_0_http//file",
|
||||
source_jar = "@jspecify-1_0_0-sources_http//file"
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "lifecycle-runtime-desktop-2_9_2_http_import",
|
||||
jar = "@lifecycle-runtime-desktop-2_9_2_http//file",
|
||||
|
||||
+70
-14
@@ -4605,6 +4605,76 @@ http_file(
|
||||
downloaded_file_path = "junit-vintage-engine-5.13.4-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-jupiter-api-6_0_0-RC2_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-api/6.0.0-RC2/junit-jupiter-api-6.0.0-RC2.jar",
|
||||
sha256 = "db1404414d23effbeb1202025f1e984f9069ddeed6d4c1826bb70bce8c70fb31",
|
||||
downloaded_file_path = "junit-jupiter-api-6.0.0-RC2.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-platform-commons-6_0_0-RC2_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/platform/junit-platform-commons/6.0.0-RC2/junit-platform-commons-6.0.0-RC2.jar",
|
||||
sha256 = "7f7d65576d02547d4d6b44ec3d49dd37904cd8927baae5bddd541cd24d513a39",
|
||||
downloaded_file_path = "junit-platform-commons-6.0.0-RC2.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "jspecify-1_0_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar",
|
||||
sha256 = "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab",
|
||||
downloaded_file_path = "jspecify-1.0.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-jupiter-api-6_0_0-RC2-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-api/6.0.0-RC2/junit-jupiter-api-6.0.0-RC2-sources.jar",
|
||||
sha256 = "4addc5bf25b7ecdd2b24b2710632fca9854410cc96d5e2332c0ac3b123ebb080",
|
||||
downloaded_file_path = "junit-jupiter-api-6.0.0-RC2-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-platform-commons-6_0_0-RC2-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/platform/junit-platform-commons/6.0.0-RC2/junit-platform-commons-6.0.0-RC2-sources.jar",
|
||||
sha256 = "e1469584f6c28fcf4eaf44dc3fd300bbeb51912f4052edbef7ee5ee0a28ff744",
|
||||
downloaded_file_path = "junit-platform-commons-6.0.0-RC2-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "jspecify-1_0_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/jspecify/jspecify/1.0.0/jspecify-1.0.0-sources.jar",
|
||||
sha256 = "adf0898191d55937fb3192ba971826f4f294292c4a960740f3c27310e7b70296",
|
||||
downloaded_file_path = "jspecify-1.0.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-platform-launcher-6_0_0-RC2_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/platform/junit-platform-launcher/6.0.0-RC2/junit-platform-launcher-6.0.0-RC2.jar",
|
||||
sha256 = "3c41ec667a185ec0b51ca8d9d68e5f0e425d6645c6e4eb64b8a81716a4deaed1",
|
||||
downloaded_file_path = "junit-platform-launcher-6.0.0-RC2.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-platform-engine-6_0_0-RC2_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/platform/junit-platform-engine/6.0.0-RC2/junit-platform-engine-6.0.0-RC2.jar",
|
||||
sha256 = "8f5e8cb552c311d4a236334975a5ff9ec4db5f64e84151d01500f31fa19edfba",
|
||||
downloaded_file_path = "junit-platform-engine-6.0.0-RC2.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-platform-launcher-6_0_0-RC2-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/platform/junit-platform-launcher/6.0.0-RC2/junit-platform-launcher-6.0.0-RC2-sources.jar",
|
||||
sha256 = "f100a0b9b4249e8f050375b47875b91dba01c41fa226dfb31c94c3bdc9de0f72",
|
||||
downloaded_file_path = "junit-platform-launcher-6.0.0-RC2-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "junit-platform-engine-6_0_0-RC2-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/junit/platform/junit-platform-engine/6.0.0-RC2/junit-platform-engine-6.0.0-RC2-sources.jar",
|
||||
sha256 = "6b725abf25a6688bf413980ab07ecb2423cf093fea08a607eef01afa7f6a457d",
|
||||
downloaded_file_path = "junit-platform-engine-6.0.0-RC2-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "jvm-native-trusted-roots-1_1_7_http",
|
||||
url = "https://cache-redirector.jetbrains.com/packages.jetbrains.team/maven/p/ij/intellij-dependencies/org/jetbrains/nativecerts/jvm-native-trusted-roots/1.1.7/jvm-native-trusted-roots-1.1.7.jar",
|
||||
@@ -6418,13 +6488,6 @@ http_file(
|
||||
downloaded_file_path = "lifecycle-common-jvm-2.9.2.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "jspecify-1_0_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar",
|
||||
sha256 = "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab",
|
||||
downloaded_file_path = "jspecify-1.0.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "lifecycle-runtime-desktop-2_9_2_http",
|
||||
url = "https://cache-redirector.jetbrains.com/dl.google.com/dl/android/maven2/androidx/lifecycle/lifecycle-runtime-desktop/2.9.2/lifecycle-runtime-desktop-2.9.2.jar",
|
||||
@@ -6586,13 +6649,6 @@ http_file(
|
||||
downloaded_file_path = "lifecycle-common-jvm-2.9.2-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "jspecify-1_0_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/org/jspecify/jspecify/1.0.0/jspecify-1.0.0-sources.jar",
|
||||
sha256 = "adf0898191d55937fb3192ba971826f4f294292c4a960740f3c27310e7b70296",
|
||||
downloaded_file_path = "jspecify-1.0.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "lifecycle-runtime-desktop-2_9_2-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/dl.google.com/dl/android/maven2/androidx/lifecycle/lifecycle-runtime-desktop/2.9.2/lifecycle-runtime-desktop-2.9.2-sources.jar",
|
||||
|
||||
+11
-15
@@ -10,7 +10,9 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.file.Path;
|
||||
import java.util.AbstractMap.SimpleImmutableEntry;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
// in java - don't use kotlin to avoid loading non-JDK classes
|
||||
@ApiStatus.Internal
|
||||
@@ -84,21 +86,15 @@ public final class JUnitDevMainKt {
|
||||
|
||||
String result = null;
|
||||
|
||||
String junitRtJar = File.separator + "junit-rt.jar";
|
||||
String junitRtPackage = File.separator + "intellij.junit.rt";
|
||||
for (String s : testEntryPointClasspath.split(File.pathSeparator)) {
|
||||
if (s.endsWith(junitRtJar) || s.endsWith(junitRtPackage)) {
|
||||
result = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String junit5RtJar = File.separator + "junit5-rt.jar";
|
||||
String junit5RtPackage = File.separator + "intellij.junit.v5.rt";
|
||||
for (String s : testEntryPointClasspath.split(File.pathSeparator)) {
|
||||
if (s.endsWith(junit5RtJar) || s.endsWith(junit5RtPackage)) {
|
||||
result = result == null ? s : result + File.pathSeparator + s;
|
||||
break;
|
||||
List<String> versions = Arrays.asList("", "5", "6");
|
||||
for (String version : versions) {
|
||||
String junitRtJar = File.separator + "junit" + version + "-rt.jar";
|
||||
String junitRtPackage = File.separator + "intellij.junit" + (version.isEmpty() ? "" : ".v" + version) + ".rt";
|
||||
for (String s : testEntryPointClasspath.split(File.pathSeparator)) {
|
||||
if (s.endsWith(junitRtJar) || s.endsWith(junitRtPackage)) {
|
||||
result = result == null ? s : result + File.pathSeparator + s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ object CommunityRepositoryModules {
|
||||
pluginAuto("intellij.junit") { spec ->
|
||||
spec.withModule("intellij.junit.rt", "junit-rt.jar")
|
||||
spec.withModule("intellij.junit.v5.rt", "junit5-rt.jar")
|
||||
spec.withModule("intellij.junit.v6.rt", "junit6-rt.jar")
|
||||
},
|
||||
plugin("intellij.testng") { spec ->
|
||||
spec.mainJarName = "testng-plugin.jar"
|
||||
|
||||
-1
@@ -318,7 +318,6 @@ public class PersistentFS_FindFilesTest {
|
||||
}
|
||||
finally {
|
||||
pool.shutdown();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
pool.awaitTermination(1, MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +371,7 @@ de.plushnikov.intellij.plugin.*
|
||||
com.intellij.junit4.*
|
||||
com.intellij.testng.integration.*
|
||||
com.intellij.testDiscovery.*
|
||||
com.intellij.execution.junit.*
|
||||
|
||||
[PYTHON_TESTS]
|
||||
com.jetbrains.python.*
|
||||
|
||||
+10
-10
@@ -108,7 +108,7 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
"modulePath/prod1", module);
|
||||
ModuleRootModificationUtil.updateModel(module, model -> {
|
||||
ContentEntry entry = model.getContentEntries()[0];
|
||||
entry.removeSourceFolder(entry.getSourceFolders(JavaSourceRootType.SOURCE).get(0));
|
||||
entry.removeSourceFolder(entry.getSourceFolders(JavaSourceRootType.SOURCE).getFirst());
|
||||
});
|
||||
JavaParameters params4Tests = configuration.getTestObject().createJavaParameters4Tests();
|
||||
assertEmpty(params4Tests.getModulePath().getPathList());
|
||||
@@ -128,7 +128,7 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
PathsList modulePath = params4Tests.getModulePath();
|
||||
|
||||
assertTrue("module path: " + modulePath.getPathsString(),
|
||||
modulePath.getPathList().stream().anyMatch(filePath -> filePath.contains("junit-jupiter-api")));
|
||||
ContainerUtil.exists(modulePath.getPathList(), filePath -> filePath.contains("junit-jupiter-api")));
|
||||
//production module output is not on the module path
|
||||
assertFalse("module path: " + modulePath.getPathsString(),
|
||||
modulePath.getPathList().contains(getCompilerOutputPath(module)));
|
||||
@@ -138,7 +138,7 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
assertSize(2, modulePath.getPathList());
|
||||
|
||||
//launcher should be put on the classpath
|
||||
assertTrue(params4Tests.getClassPath().getPathList().stream().anyMatch(filePath -> filePath.contains("launcher")));
|
||||
assertTrue(ContainerUtil.exists(params4Tests.getClassPath().getPathList(), filePath -> filePath.contains("launcher")));
|
||||
}
|
||||
|
||||
public void testModuleInfoInTestModularizedJunit() throws Exception {
|
||||
@@ -153,8 +153,8 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
" --add-modules org.junit.platform.launcher", moduleOptions.getParametersList().getParametersString());
|
||||
|
||||
PathsList classPath = params4Tests.getClassPath();
|
||||
assertContainsElements(classPath.getPathList(), PathUtil.getJarPathForClass(JUnitStarter.class));
|
||||
assertContainsElements(classPath.getPathList(), ContainerUtil.map(TestObject.getJUnit5RtFiles(), File::getPath));
|
||||
assertContainsElements(classPath.getPathList(), TestObject.getJUnitRtPath().getPath());
|
||||
assertContainsElements(classPath.getPathList(), ContainerUtil.map(TestObject.getJUnitRtFiles(JUnitStarter.JUNIT5_PARAMETER), File::getPath));
|
||||
|
||||
PathsList modulePath = params4Tests.getModulePath();
|
||||
checkLibrariesOnPathList(module, modulePath);
|
||||
@@ -165,7 +165,7 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
//test module output is on the module path
|
||||
assertTrue("module path: " + modulePath.getPathsString(),
|
||||
modulePathList.contains(getCompilerOutputPath(module, true)));
|
||||
assertTrue(modulePathList.stream().anyMatch(filePath -> filePath.contains("launcher")));
|
||||
assertTrue(ContainerUtil.exists(modulePathList, filePath -> filePath.contains("launcher")));
|
||||
}
|
||||
|
||||
public void testModuleInfoInTestModularizedJunitDependencyOnAnotherModule() throws Exception {
|
||||
@@ -176,7 +176,7 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
model.addModuleOrderEntry(module1);
|
||||
});
|
||||
JpsMavenRepositoryLibraryDescriptor nonModularizedJupiterDescription =
|
||||
new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", "5.5.2");
|
||||
new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", "6.0.0-RC2");
|
||||
JUnitConfiguration configuration = setupConfiguration(nonModularizedJupiterDescription, "modulePath/test2", module);
|
||||
JavaParameters params4Tests = configuration.getTestObject().createJavaParameters4Tests();
|
||||
ParamsGroup moduleOptions = JavaTestFrameworkRunnableState.getJigsawOptions(params4Tests);
|
||||
@@ -185,8 +185,8 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
" --add-modules org.junit.platform.launcher", moduleOptions.getParametersList().getParametersString());
|
||||
|
||||
PathsList classPath = params4Tests.getClassPath();
|
||||
assertContainsElements(classPath.getPathList(), PathUtil.getJarPathForClass(JUnitStarter.class));
|
||||
assertContainsElements(classPath.getPathList(), ContainerUtil.map(TestObject.getJUnit5RtFiles(), File::getPath));
|
||||
assertContainsElements(classPath.getPathList(), TestObject.getJUnitRtPath().getPath());
|
||||
assertContainsElements(classPath.getPathList(), ContainerUtil.map(TestObject.getJUnitRtFiles(JUnitStarter.JUNIT6_PARAMETER), File::getPath));
|
||||
|
||||
PathsList modulePath = params4Tests.getModulePath();
|
||||
checkLibrariesOnPathList(module, modulePath);
|
||||
@@ -198,7 +198,7 @@ public class JUnitModulePathTest extends BaseConfigurationTestCase {
|
||||
//test module output is on the module path
|
||||
assertTrue("module path: " + modulePath.getPathsString(),
|
||||
modulePathList.contains(getCompilerOutputPath(module, true)));
|
||||
assertTrue(modulePathList.stream().anyMatch(filePath -> filePath.contains("launcher")));
|
||||
assertTrue(ContainerUtil.exists(modulePathList, filePath -> filePath.contains("launcher")));
|
||||
}
|
||||
|
||||
private JUnitConfiguration setupConfiguration(JpsMavenRepositoryLibraryDescriptor libraryDescriptor, String sources, Module module) throws Exception {
|
||||
|
||||
@@ -6,4 +6,7 @@
|
||||
- name: intellij.junit
|
||||
- name: lib/junit5-rt.jar
|
||||
modules:
|
||||
- name: intellij.junit.v5.rt
|
||||
- name: intellij.junit.v5.rt
|
||||
- name: lib/junit6-rt.jar
|
||||
modules:
|
||||
- name: intellij.junit.v6.rt
|
||||
@@ -28,7 +28,8 @@
|
||||
<cantBeStatic implementation="com.intellij.execution.junit2.inspection.JUnitCantBeStaticExtension" />
|
||||
<testFramework implementation="com.intellij.execution.junit.JUnit4Framework" id="junit4"/>
|
||||
<testFramework implementation="com.intellij.execution.junit.JUnit3Framework" id="junit3" order="after junit4"/>
|
||||
<testFramework implementation="com.intellij.execution.junit.JUnit5Framework" id="junit5" order="after junit3"/>
|
||||
<testFramework implementation="com.intellij.execution.junit.JUnit6Framework" id="junit6" order="after junit3"/>
|
||||
<testFramework implementation="com.intellij.execution.junit.JUnit5Framework" id="junit5" order="after junit6"/>
|
||||
<configurationType implementation="com.intellij.execution.junit.JUnitConfigurationType"/>
|
||||
<library.dependencyScopeSuggester implementation="com.intellij.execution.junit.JUnitDependencyScopeSuggester"/>
|
||||
<externalSystem.runConfigurationImporter implementation="com.intellij.execution.junit.JUnitRunConfigurationImporter"/>
|
||||
@@ -49,6 +50,7 @@
|
||||
<stacktrace.fold substring="at com.intellij.junit3."/>
|
||||
<stacktrace.fold substring="at com.intellij.junit4."/>
|
||||
<stacktrace.fold substring="at com.intellij.junit5."/>
|
||||
<stacktrace.fold substring="at com.intellij.junit6."/>
|
||||
<stacktrace.fold substring="at com.intellij.rt.junit."/>
|
||||
<stacktrace.fold substring="at junit.framework.TestSuite.run"/>
|
||||
<stacktrace.fold substring="at junit.framework.TestCase.run"/>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@org.junit.jupiter.api.AfterAll
|
||||
static void afterAll() {
|
||||
${BODY}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<!-- Copyright 2000-2019 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. -->
|
||||
<html>
|
||||
<body>
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">
|
||||
Creates an afterAll method in a JUnit 6 test class.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">Predefined variables take the following values:</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td valign="top"><font face="verdana" size="-1">Name of the created method</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${BODY}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td valign="top"><font face="verdana" size="-1">Generated method body</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
@org.junit.jupiter.api.BeforeAll
|
||||
static void beforeAll() {
|
||||
${BODY}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<!-- Copyright 2000-2019 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. -->
|
||||
<html>
|
||||
<body>
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">
|
||||
Creates a beforeAll method in a JUnit 6 test class.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">Predefined variables take the following values:</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td valign="top"><font face="verdana" size="-1">Name of the created method</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${BODY}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td valign="top"><font face="verdana" size="-1">generated method body</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
@org.junit.jupiter.api.BeforeEach
|
||||
void setUp() {
|
||||
${BODY}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<html>
|
||||
<body>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">
|
||||
Creates a setUp method in a JUnit 6 test class.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">Predefined variables take the following values:</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the created method</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${BODY}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Generated method body</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
@org.junit.jupiter.api.AfterEach
|
||||
void tearDown() {
|
||||
${BODY}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<html>
|
||||
<body>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">
|
||||
Creates a tearDown method in a JUnit 6 test class.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">Predefined variables take the following values:</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the created method</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${BODY}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Generated method body</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
#parse("File Header.java")
|
||||
class ${NAME} {
|
||||
${BODY}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<html>
|
||||
<body>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">
|
||||
Creates a JUnit 6 test class.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">Predefined variables take the following values:</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the created class</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${CLASS_NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the tested class</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${BODY}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Generated class body</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
@org.junit.jupiter.api.Test
|
||||
void ${NAME}() {
|
||||
${BODY}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<html>
|
||||
<body>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">
|
||||
Creates a test method in a JUnit 6 test class.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3"><font face="verdana" size="-1">Predefined variables take the following values:</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the created method</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><nobr><font face="verdana" size="-2"><b>${BODY}</b></font></nobr></td>
|
||||
<td width="10"> </td>
|
||||
<td width="100%" valign="top"><font face="verdana" size="-1">Generated method body</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
@@ -16,6 +16,11 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.siyeh.ig.junit.JUnitCommonClassNames.ORG_JUNIT_PLATFORM_SUITE_API_SUITE;
|
||||
|
||||
public class JUnit5Framework extends JUnitTestFramework {
|
||||
|
||||
@Override
|
||||
@@ -29,17 +34,13 @@ public class JUnit5Framework extends JUnitTestFramework {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMarkerClassFQName() {
|
||||
return JUnitUtil.TEST5_ANNOTATION;
|
||||
protected Collection<String> getMarkerClassFQNames() {
|
||||
return List.of(JUnitUtil.TEST5_ANNOTATION, JUnitUtil.CUSTOM_TESTABLE_ANNOTATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFrameworkAvailable(@NotNull PsiElement clazz) {
|
||||
return callWithAlternateResolver(clazz.getProject(), ()->{
|
||||
return isFrameworkApplicable(clazz, JUnitUtil.CUSTOM_TESTABLE_ANNOTATION) ||
|
||||
//check explicit jupiter to support library with broken dependency
|
||||
isFrameworkApplicable(clazz, JUnitUtil.TEST5_ANNOTATION);
|
||||
}, false);
|
||||
protected String getMarkerClassFQName() {
|
||||
return JUnitUtil.TEST5_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -196,7 +197,7 @@ public class JUnit5Framework extends JUnitTestFramework {
|
||||
public boolean isSuiteClass(PsiClass psiClass) {
|
||||
if (psiClass == null) return false;
|
||||
return callWithAlternateResolver(psiClass.getProject(), () -> {
|
||||
return AnnotationUtil.isAnnotated(psiClass, "org.junit.platform.suite.api.Suite", AnnotationUtil.CHECK_HIERARCHY);
|
||||
return AnnotationUtil.isAnnotated(psiClass, ORG_JUNIT_PLATFORM_SUITE_API_SUITE, AnnotationUtil.CHECK_HIERARCHY);
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
|
||||
import com.intellij.execution.JUnitBundle;
|
||||
import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.siyeh.ig.junit.JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_METHOD_ORDERER_DEFAULT;
|
||||
import static com.siyeh.ig.junit.JUnitCommonClassNames.ORG_JUNIT_PLATFORM_SUITE_API_SUITE;
|
||||
|
||||
public class JUnit6Framework extends JUnitTestFramework {
|
||||
|
||||
@Override
|
||||
public boolean isDumbAware() {
|
||||
return this.getClass().isAssignableFrom(JUnit6Framework.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return "JUnit6";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getMarkerClassFQNames() {
|
||||
return List.of(ORG_JUNIT_JUPITER_API_METHOD_ORDERER_DEFAULT, "org.junit.platform.commons.annotation.Contract");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMarkerClassFQName() {
|
||||
return ORG_JUNIT_JUPITER_API_METHOD_ORDERER_DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRunSingleClassAsJUnit5(Project project, GlobalSearchScope scope) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ExternalLibraryDescriptor getFrameworkLibraryDescriptor() {
|
||||
return JUnitExternalLibraryDescriptor.JUNIT6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getDefaultSuperClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTestClass(PsiClass clazz, boolean canBePotential) {
|
||||
return callWithAlternateResolver(clazz.getProject(), () -> {
|
||||
if (canBePotential) return isUnderTestSources(clazz);
|
||||
if (!isFrameworkAvailable(clazz)) return false;
|
||||
return JUnitUtil.isJUnit5TestClass(clazz, false);
|
||||
}, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable PsiMethod findSetUpMethod(@NotNull PsiClass clazz) {
|
||||
return callWithAlternateResolver(clazz.getProject(), ()->{
|
||||
for (PsiMethod each : clazz.getMethods()) {
|
||||
if (AnnotationUtil.isAnnotated(each, JUnitUtil.BEFORE_EACH_ANNOTATION_NAME, 0)) return each;
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable PsiMethod findBeforeClassMethod(@NotNull PsiClass clazz) {
|
||||
return callWithAlternateResolver(clazz.getProject(), () -> {
|
||||
for (PsiMethod each : clazz.getMethods()) {
|
||||
if (each.hasModifierProperty(PsiModifier.STATIC)
|
||||
&& AnnotationUtil.isAnnotated(each, JUnitUtil.BEFORE_ALL_ANNOTATION_NAME, 0)) return each;
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable PsiMethod findTearDownMethod(@NotNull PsiClass clazz) {
|
||||
return callWithAlternateResolver(clazz.getProject(), () -> {
|
||||
for (PsiMethod each : clazz.getMethods()) {
|
||||
if (AnnotationUtil.isAnnotated(each, JUnitUtil.AFTER_EACH_ANNOTATION_NAME, 0)) return each;
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable PsiMethod findAfterClassMethod(@NotNull PsiClass clazz) {
|
||||
return callWithAlternateResolver(clazz.getProject(), () -> {
|
||||
for (PsiMethod each : clazz.getMethods()) {
|
||||
if (each.hasModifierProperty(PsiModifier.STATIC)
|
||||
&& AnnotationUtil.isAnnotated(each, JUnitUtil.AFTER_ALL_ANNOTATION_NAME, 0)) {
|
||||
return each;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable PsiMethod findOrCreateSetUpMethod(PsiClass clazz) throws IncorrectOperationException {
|
||||
PsiMethod method = findSetUpMethod(clazz);
|
||||
if (method != null) return method;
|
||||
|
||||
PsiManager manager = clazz.getManager();
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
|
||||
|
||||
method = createSetUpPatternMethod(factory);
|
||||
PsiMethod existingMethod = clazz.findMethodBySignature(method, false);
|
||||
if (existingMethod != null) {
|
||||
if (AnnotationUtil.isAnnotated(existingMethod, JUnitUtil.BEFORE_ALL_ANNOTATION_NAME, 0)) return existingMethod;
|
||||
int exit = ApplicationManager.getApplication().isUnitTestMode() ?
|
||||
Messages.OK :
|
||||
Messages.showOkCancelDialog(JUnitBundle.message("create.setup.dialog.message", "@BeforeEach"),
|
||||
JUnitBundle.message("create.setup.dialog.title"),
|
||||
Messages.getWarningIcon());
|
||||
if (exit == Messages.OK) {
|
||||
AddAnnotationPsiFix.addPhysicalAnnotationIfAbsent(JUnitUtil.BEFORE_EACH_ANNOTATION_NAME, PsiNameValuePair.EMPTY_ARRAY,
|
||||
existingMethod.getModifierList());
|
||||
return existingMethod;
|
||||
}
|
||||
}
|
||||
final PsiMethod testMethod = JUnitUtil.findFirstTestMethod(clazz);
|
||||
if (testMethod != null) {
|
||||
method = (PsiMethod)clazz.addBefore(method, testMethod);
|
||||
} else {
|
||||
method = (PsiMethod)clazz.add(method);
|
||||
}
|
||||
JavaCodeStyleManager.getInstance(manager.getProject()).shortenClassReferences(method);
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIgnoredMethod(PsiElement element) {
|
||||
if (element == null) return false;
|
||||
return callWithAlternateResolver(element.getProject(), () -> {
|
||||
if (element instanceof PsiMethod method) {
|
||||
final PsiMethod ignoredTestMethod =
|
||||
AnnotationUtil.isAnnotated(method, "org.junit.jupiter.api.Disabled", 0) ? JUnitUtil.getTestMethod(element) : null;
|
||||
return ignoredTestMethod != null;
|
||||
}
|
||||
return false;
|
||||
}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptNestedClasses() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTemplateDescriptor getSetUpMethodFileTemplateDescriptor() {
|
||||
return new FileTemplateDescriptor("JUnit6 SetUp Method.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTemplateDescriptor getBeforeClassMethodFileTemplateDescriptor() {
|
||||
return new FileTemplateDescriptor("JUnit6 BeforeAll Method.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTemplateDescriptor getTearDownMethodFileTemplateDescriptor() {
|
||||
return new FileTemplateDescriptor("JUnit6 TearDown Method.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTemplateDescriptor getAfterClassMethodFileTemplateDescriptor() {
|
||||
return new FileTemplateDescriptor("JUnit6 AfterAll Method.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FileTemplateDescriptor getTestMethodFileTemplateDescriptor() {
|
||||
return new FileTemplateDescriptor("JUnit6 Test Method.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTemplateDescriptor getTestClassFileTemplateDescriptor() {
|
||||
return new FileTemplateDescriptor("JUnit6 Test Class.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuiteClass(PsiClass psiClass) {
|
||||
if (psiClass == null) return false;
|
||||
return callWithAlternateResolver(psiClass.getProject(), () -> {
|
||||
return AnnotationUtil.isAnnotated(psiClass, ORG_JUNIT_PLATFORM_SUITE_API_SUITE, AnnotationUtil.CHECK_HIERARCHY);
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
+11
-14
@@ -1,25 +1,22 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class JUnitExternalLibraryDescriptor extends ExternalLibraryDescriptor {
|
||||
public static final ExternalLibraryDescriptor JUNIT3 = new JUnitExternalLibraryDescriptor("3", "3.8.2");
|
||||
public static final ExternalLibraryDescriptor JUNIT4 = new JUnitExternalLibraryDescriptor("4", "4.13.1");
|
||||
public static final ExternalLibraryDescriptor JUNIT5 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "5.8.1",
|
||||
"5.8.1");
|
||||
public static final ExternalLibraryDescriptor JUNIT3 = new JUnitExternalLibraryDescriptor("junit", "junit", "3", "3.8.2", "3.0");
|
||||
public static final ExternalLibraryDescriptor JUNIT4 = new JUnitExternalLibraryDescriptor("junit", "junit", "4", "4.13.1", "4.0");
|
||||
public static final ExternalLibraryDescriptor JUNIT5 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "5", "5.13.4", "5.0.0");
|
||||
public static final ExternalLibraryDescriptor JUNIT6 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "6", "6.0.0-RC2", "6.0.0-RC2");
|
||||
private final String myVersion;
|
||||
|
||||
private JUnitExternalLibraryDescriptor(String baseVersion, String preferredVersion) {
|
||||
this("junit", "junit", baseVersion, preferredVersion);
|
||||
}
|
||||
|
||||
private JUnitExternalLibraryDescriptor(final String groupId,
|
||||
final String artifactId,
|
||||
final String version,
|
||||
String preferredVersion) {
|
||||
super(groupId, artifactId, version + ".0", version + ".999", preferredVersion);
|
||||
private JUnitExternalLibraryDescriptor(@NotNull String groupId,
|
||||
@NotNull String artifactId,
|
||||
@NotNull String version,
|
||||
@NotNull String preferredVersion,
|
||||
@NotNull String minVersion) {
|
||||
super(groupId, artifactId, minVersion, version + ".999", preferredVersion);
|
||||
myVersion = version;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,7 @@ import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.FilenameIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -82,6 +81,10 @@ import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static com.intellij.execution.junit.JUnitExternalLibraryDescriptor.JUNIT5;
|
||||
import static com.intellij.execution.junit.JUnitExternalLibraryDescriptor.JUNIT6;
|
||||
import static com.siyeh.ig.junit.JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_METHOD_ORDERER_DEFAULT;
|
||||
|
||||
public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitConfiguration> implements PossiblyDumbAware {
|
||||
private static final String LAUNCHER_MODULE_NAME = "org.junit.platform.launcher";
|
||||
private static final String JUPITER_ENGINE_NAME = "org.junit.jupiter.engine";
|
||||
@@ -100,6 +103,14 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
|
||||
private final Map<Module, JavaParameters> myAdditionalJarsForModuleFork = new HashMap<>();
|
||||
|
||||
private static final Map<String, String> RUNNER_VERSIONS = Map.of(
|
||||
JUnitStarter.JUNIT3_PARAMETER, "3",
|
||||
JUnitStarter.JUNIT4_PARAMETER, "4",
|
||||
JUnitStarter.JUNIT5_PARAMETER, "5",
|
||||
JUnitStarter.JUNIT6_PARAMETER, "6"
|
||||
);
|
||||
protected static final Set<String> JUPITER_RUNNERS = Set.of(JUnitStarter.JUNIT5_PARAMETER, JUnitStarter.JUNIT6_PARAMETER);
|
||||
|
||||
protected TestObject(JUnitConfiguration configuration, ExecutionEnvironment environment) {
|
||||
super(environment);
|
||||
myConfiguration = configuration;
|
||||
@@ -180,7 +191,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
Set<Module> result = new HashSet<>();
|
||||
final SourceScope sourceScope = getSourceScope();
|
||||
final Project project = getConfiguration().getProject();
|
||||
if (sourceScope != null && packageName != null && JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) {
|
||||
if (sourceScope != null && packageName != null && JUPITER_RUNNERS.contains(getRunner())) {
|
||||
final PsiPackage aPackage = JavaPsiFacade.getInstance(getConfiguration().getProject()).findPackage(packageName);
|
||||
if (aPackage != null) {
|
||||
final TestSearchScope scope = getScope();
|
||||
@@ -235,10 +246,12 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
throw new CantRunException(JavaBundle.message("error.message.ide.does.not.support.starting.processes.using.old.java",
|
||||
jdkVersion.getDescription()));
|
||||
}
|
||||
javaParameters.getClassPath().addFirst(path != null ? path : PathUtil.getJarPathForClass(JUnitStarter.class));
|
||||
javaParameters.getClassPath().addFirst(path != null ? path : getJUnitRtPath().getAbsolutePath());
|
||||
|
||||
//include junit5 listeners for the case custom junit 5 engines would be detected on runtime
|
||||
javaParameters.getClassPath().addAllFiles(getJUnit5RtFiles());
|
||||
javaParameters.getClassPath().addAllFiles(getJUnitRtFiles(JUnitStarter.JUNIT5_PARAMETER));
|
||||
//include junit6 listeners for the case custom junit 6 engines would be detected on runtime
|
||||
javaParameters.getClassPath().addAllFiles(getJUnitRtFiles(JUnitStarter.JUNIT6_PARAMETER));
|
||||
|
||||
appendDownloadedDependenciesForForkedConfigurations(javaParameters, module);
|
||||
}
|
||||
@@ -261,30 +274,43 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
}
|
||||
|
||||
public static List<File> getJUnit5RtFiles() {
|
||||
File junit4Rt = new File(PathUtil.getJarPathForClass(JUnit4IdeaTestRunner.class));
|
||||
public static List<File> getJUnitRtFiles(@NotNull String runner) {
|
||||
String version = RUNNER_VERSIONS.getOrDefault(runner, "5");
|
||||
File junit4Rt = getJUnitRtPath();
|
||||
String junit4Name = junit4Rt.getName();
|
||||
String junit5Name;
|
||||
String junitCurrentName;
|
||||
if (junit4Rt.isDirectory()) {
|
||||
junit5Name = junit4Name.replace("junit", "junit.v5");
|
||||
junitCurrentName = junit4Name.replace("junit", "junit.v" + version);
|
||||
}
|
||||
else {
|
||||
var relevantJarsRoot = ArchivedCompilationContextUtil.getArchivedCompiledClassesLocation();
|
||||
Map<String, List<String>> mapping = ArchivedCompilationContextUtil.getArchivedCompiledClassesMapping();
|
||||
if (relevantJarsRoot != null && junit4Rt.toPath().startsWith(relevantJarsRoot) && mapping != null) {
|
||||
return ContainerUtil.map(mapping.get("production/intellij.junit.v5.rt"), File::new);
|
||||
return ContainerUtil.map(mapping.get("production/intellij.junit.v" + version + ".rt"), File::new);
|
||||
}
|
||||
else {
|
||||
junit5Name = junit4Name.replace("junit", "junit5");
|
||||
junitCurrentName = junit4Name.replace("junit", "junit" + version);
|
||||
}
|
||||
}
|
||||
return Collections.singletonList(new File(junit4Rt.getParent(), junit5Name));
|
||||
return Collections.singletonList(new File(junit4Rt.getParent(), junitCurrentName));
|
||||
}
|
||||
|
||||
public static File getJUnitRtPath() {
|
||||
String currentPath = PathUtil.getJarPathForClass(TestObject.class);
|
||||
String currentUrl = VfsUtil.getUrlForLibraryRoot(new File(currentPath));
|
||||
if (StandardFileSystems.FILE_PROTOCOL.equals(VirtualFileManager.extractProtocol(currentUrl))) {
|
||||
File rtDir = new File(new File(currentPath).getParentFile(), "intellij.junit.rt");
|
||||
if (rtDir.exists()) {
|
||||
return rtDir;
|
||||
}
|
||||
}
|
||||
return new File(PathUtil.getJarPathForClass(JUnit4IdeaTestRunner.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Junit 5 searches for tests in the classpath.
|
||||
* When 2 modules have e.g. the same package, one depends on another, and tests have to run in single module only,
|
||||
* by configuration settings or to avoid repetition in fork by module mode, additional filters per output directories are required.
|
||||
* Junit 5/6 searches for tests in the classpath.
|
||||
* When 2 modules have e.g. the same package, one depends on another, and tests have to run in a single module only,
|
||||
* by configuration settings or to avoid repetition in fork by module mode; additional filters per output directories are required.
|
||||
*/
|
||||
protected static @Unmodifiable List<String> composeDirectoryFilter(@NotNull Module module) {
|
||||
return ContainerUtil.map(OrderEnumerator.orderEntries(module)
|
||||
@@ -296,6 +322,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
@Override
|
||||
protected JavaParameters createJavaParameters() throws ExecutionException {
|
||||
JavaParameters javaParameters = super.createJavaParameters();
|
||||
|
||||
if (javaParameters.getMainClass() == null) { // for custom main class, e.g. overridden by JUnitDevKitUnitTestingSettings.Companion#apply
|
||||
javaParameters.setMainClass(JUnitConfiguration.JUNIT_START_CLASS);
|
||||
}
|
||||
@@ -329,17 +356,17 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void appendJUnit5LauncherClasses(JavaParameters javaParameters,
|
||||
Project project,
|
||||
GlobalSearchScope globalSearchScope,
|
||||
boolean ensureOnModulePath) throws CantRunException {
|
||||
|
||||
public void appendJUnitLauncherClasses(String runnerName,
|
||||
JavaParameters javaParameters,
|
||||
Project project,
|
||||
GlobalSearchScope globalSearchScope,
|
||||
boolean ensureOnModulePath) throws CantRunException {
|
||||
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
DumbService dumbService = DumbService.getInstance(project);
|
||||
|
||||
String launcherVersion = getLibraryVersion("org.junit.platform.commons.JUnitException", globalSearchScope, project);
|
||||
if (launcherVersion == null) {
|
||||
LOG.info("Failed to detect junit 5 launcher version, please configure explicit dependency");
|
||||
LOG.info("Failed to detect junit " + RUNNER_VERSIONS.getOrDefault(runnerName, "5") + " launcher version, please configure explicit dependency");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -350,7 +377,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
.isEmpty()).executeSynchronously() &&
|
||||
VersionComparatorUtil.compare(launcherVersion, "1.5.0") >= 0;
|
||||
|
||||
if (isModularized) { //for modularized junit ensure launcher is included in the module graph
|
||||
if (isModularized) { //for modularized junit ensure the launcher is included in the module graph
|
||||
ParamsGroup group = getOrCreateJigsawOptions(javaParameters);
|
||||
ParametersList vmParametersList = group.getParametersList();
|
||||
if (!vmParametersList.hasParameter(LAUNCHER_MODULE_NAME)) {
|
||||
@@ -368,8 +395,12 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
|
||||
//add standard engines only if no engine api is present
|
||||
if (!hasJUnit5EnginesAPI(globalSearchScope, psiFacade) || !isCustomJUnit5(globalSearchScope)) {
|
||||
String jupiterVersion = ObjectUtils.notNull(getLibraryVersion(JUnitUtil.TEST5_ANNOTATION, globalSearchScope, project), "5.0.0");
|
||||
if (!hasJupiterEnginesAPI(globalSearchScope, psiFacade) || !isCustomJUnit(globalSearchScope,
|
||||
JUnitStarter.JUNIT6_PARAMETER.equals(runnerName)
|
||||
? JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_CANCELLATION_TOKEN
|
||||
: JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_TEST_ENGINE)) {
|
||||
String defaultMinVersion = JUnitStarter.JUNIT6_PARAMETER.equals(runnerName) ? JUNIT6.getMinVersion() : JUNIT5.getMinVersion();
|
||||
String jupiterVersion = ObjectUtils.notNull(getLibraryVersion(JUnitUtil.TEST5_ANNOTATION, globalSearchScope, project), defaultMinVersion);
|
||||
if (JUnitUtil.hasPackageWithDirectories(psiFacade, JUnitUtil.TEST5_PACKAGE_FQN, globalSearchScope)) {
|
||||
if (!JUnitUtil.hasPackageWithDirectories(psiFacade, JUPITER_ENGINE_NAME, globalSearchScope)) {
|
||||
downloadDependenciesWhenRequired(project, additionalDependencies,
|
||||
@@ -382,7 +413,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
|
||||
if (JUnitUtil.hasPackageWithDirectories(psiFacade, "org.junit.platform.suite.api", globalSearchScope)) {
|
||||
if (!JUnitUtil.hasPackageWithDirectories(psiFacade, SUITE_ENGINE_NAME, globalSearchScope)) {
|
||||
String suiteVersion = getLibraryVersion("org.junit.platform.suite.api.Suite", globalSearchScope, project);
|
||||
String suiteVersion = getLibraryVersion(JUnitCommonClassNames.ORG_JUNIT_PLATFORM_SUITE_API_SUITE, globalSearchScope, project);
|
||||
if (suiteVersion != null && VersionComparatorUtil.compare(suiteVersion, "1.8.0") >= 0) {
|
||||
downloadDependenciesWhenRequired(project, additionalDependencies,
|
||||
new RepositoryLibraryProperties("org.junit.platform", "junit-platform-suite-engine", suiteVersion));
|
||||
@@ -433,8 +464,8 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
|
||||
/**
|
||||
* junit 4.12+ must be on the classpath for vintage engine to work correctly.
|
||||
* Don't add engine when it will fail to detect tests anyway.
|
||||
* junit 4.12+ must be on the classpath for the vintage engine to work correctly.
|
||||
* Don't add engine when it fails to detect tests anyway.
|
||||
* <p>
|
||||
* Reflection is needed for the case when no sources are attached
|
||||
*/
|
||||
@@ -452,7 +483,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasJUnit5EnginesAPI(GlobalSearchScope globalSearchScope, JavaPsiFacade psiFacade) {
|
||||
public static boolean hasJupiterEnginesAPI(GlobalSearchScope globalSearchScope, JavaPsiFacade psiFacade) {
|
||||
return JUnitUtil.hasPackageWithDirectories(psiFacade, "org.junit.platform.engine", globalSearchScope);
|
||||
}
|
||||
|
||||
@@ -548,7 +579,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
|
||||
@Override
|
||||
protected boolean isIdBasedTestTree() {
|
||||
return JUnitStarter.JUNIT5_PARAMETER.equals(getRunner());
|
||||
return JUPITER_RUNNERS.contains(getRunner());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -571,14 +602,14 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
super.downloadAdditionalDependencies(javaParameters);
|
||||
|
||||
String preferredRunner = getRunner();
|
||||
if (JUnitStarter.JUNIT5_PARAMETER.equals(preferredRunner)) {
|
||||
if (JUPITER_RUNNERS.contains(preferredRunner)) {
|
||||
JUnitConfiguration configuration = getConfiguration();
|
||||
final Project project = configuration.getProject();
|
||||
Module module = configuration.getConfigurationModule().getModule();
|
||||
ThrowableComputable<Void, ExecutionException> downloader = () -> {
|
||||
appendJUnit5LauncherClasses(javaParameters, project,
|
||||
getScopeForJUnit(module, project),
|
||||
useModulePath() && module != null && ReadAction.compute(() -> findJavaModule(module, true)) != null);
|
||||
appendJUnitLauncherClasses(preferredRunner, javaParameters, project,
|
||||
getScopeForJUnit(module, project),
|
||||
useModulePath() && module != null && ReadAction.compute(() -> findJavaModule(module, true)) != null);
|
||||
if (forkPerModule()) {
|
||||
for (Module packageModule : ReadAction.compute(() -> collectPackageModules(configuration.getPackage()))) {
|
||||
JavaParameters parameters = new JavaParameters();
|
||||
@@ -587,12 +618,9 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
parameters.getVMParametersList().addParamsGroup(group.clone());
|
||||
}
|
||||
parameters.setJdk(javaParameters.getJdk());
|
||||
appendJUnit5LauncherClasses(parameters,
|
||||
project,
|
||||
getScopeForJUnit(packageModule, project),
|
||||
useModulePath() &&
|
||||
packageModule != null &&
|
||||
ReadAction.compute(() -> findJavaModule(packageModule, true)) != null);
|
||||
appendJUnitLauncherClasses(preferredRunner, parameters, project,
|
||||
getScopeForJUnit(packageModule, project),
|
||||
useModulePath() && packageModule != null && ReadAction.compute(() -> findJavaModule(packageModule, true)) != null);
|
||||
myAdditionalJarsForModuleFork.put(packageModule, parameters);
|
||||
}
|
||||
}
|
||||
@@ -728,6 +756,20 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
}
|
||||
|
||||
private String getRunner(@NotNull GlobalSearchScope scope, @NotNull Project project) {
|
||||
if (JavaPsiFacade.getInstance(project).findClass(ORG_JUNIT_JUPITER_API_METHOD_ORDERER_DEFAULT, scope) != null ||
|
||||
isCustomJUnit(scope, JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_CANCELLATION_TOKEN)) {
|
||||
return JUnitStarter.JUNIT6_PARAMETER;
|
||||
}
|
||||
else if (JUnitUtil.isJUnit5(scope, project) ||
|
||||
isCustomJUnit(scope, JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_TEST_ENGINE)) {
|
||||
return JUnitStarter.JUNIT5_PARAMETER;
|
||||
}
|
||||
else {
|
||||
return DEFAULT_RUNNER;
|
||||
}
|
||||
}
|
||||
|
||||
private @NotNull String getRunnerInner() {
|
||||
Project project = myConfiguration.getProject();
|
||||
LOG.assertTrue(!DumbService.getInstance(project).isAlternativeResolveEnabled());
|
||||
@@ -737,8 +779,9 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
return JUnitStarter.JUNIT4_PARAMETER;
|
||||
}
|
||||
if (JUnitConfiguration.TEST_TAGS.equals(data.TEST_OBJECT)) {
|
||||
return JUnitStarter.JUNIT5_PARAMETER;
|
||||
return getRunner(globalSearchScope, project);
|
||||
}
|
||||
|
||||
boolean isMethodConfiguration = JUnitConfiguration.TEST_METHOD.equals(data.TEST_OBJECT);
|
||||
boolean isClassConfiguration = JUnitConfiguration.TEST_CLASS.equals(data.TEST_OBJECT);
|
||||
final PsiClass psiClass = isMethodConfiguration || isClassConfiguration
|
||||
@@ -746,6 +789,10 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
if (psiClass != null) {
|
||||
Set<TestFramework> testFrameworks = TestFrameworks.detectApplicableFrameworks(psiClass);
|
||||
TestFramework testFramework = ContainerUtil.getFirstItem(testFrameworks);
|
||||
if (testFramework instanceof JUnit6Framework ||
|
||||
testFrameworks.size() > 1 && ContainerUtil.find(testFrameworks, f -> f instanceof JUnit6Framework) != null) {
|
||||
return JUnitStarter.JUNIT6_PARAMETER;
|
||||
}
|
||||
if (testFramework instanceof JUnit5Framework ||
|
||||
testFrameworks.size() > 1 && ContainerUtil.find(testFrameworks, f -> f instanceof JUnit5Framework) != null) {
|
||||
return JUnitStarter.JUNIT5_PARAMETER;
|
||||
@@ -760,28 +807,29 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
return JUnitStarter.JUNIT4_PARAMETER;
|
||||
}
|
||||
}
|
||||
return JUnitUtil.isJUnit5(globalSearchScope, project) || isCustomJUnit5(globalSearchScope) ? JUnitStarter.JUNIT5_PARAMETER : DEFAULT_RUNNER;
|
||||
|
||||
return getRunner(globalSearchScope, project);
|
||||
}
|
||||
|
||||
private boolean isCustomJUnit5(GlobalSearchScope globalSearchScope) {
|
||||
private boolean isCustomJUnit(GlobalSearchScope globalSearchScope, String jupiterClassName) {
|
||||
Project project = myConfiguration.getProject();
|
||||
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
|
||||
Boolean isCustomJUnit5UsingPsi =
|
||||
Boolean isCustomJUnitUsingPsi =
|
||||
ReadAction.nonBlocking(() -> {
|
||||
if (DumbService.isDumb(project)) {
|
||||
return null;
|
||||
}
|
||||
return findCustomJunit5TestEngineUsingPsi(globalSearchScope, project, psiFacade);
|
||||
return hasCustomJupiterTestEngineUsingPsi(globalSearchScope, project, psiFacade, jupiterClassName);
|
||||
}).executeSynchronously();
|
||||
if (isCustomJUnit5UsingPsi != null) {
|
||||
return isCustomJUnit5UsingPsi;
|
||||
if (isCustomJUnitUsingPsi != null) {
|
||||
return isCustomJUnitUsingPsi;
|
||||
}
|
||||
return findCustomJUnit5TestEngineUsingClassLoader(globalSearchScope, psiFacade);
|
||||
return findCustomJupiterTestEngineUsingClassLoader(globalSearchScope, psiFacade);
|
||||
}
|
||||
|
||||
private boolean findCustomJUnit5TestEngineUsingClassLoader(@NotNull GlobalSearchScope globalSearchScope,
|
||||
@NotNull JavaPsiFacade psiFacade) {
|
||||
private boolean findCustomJupiterTestEngineUsingClassLoader(@NotNull GlobalSearchScope globalSearchScope,
|
||||
@NotNull JavaPsiFacade psiFacade) {
|
||||
boolean hasPlatformEngine = ReadAction.compute(() -> {
|
||||
PsiPackage aPackage = psiFacade.findPackage(JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE);
|
||||
return aPackage != null && aPackage.getDirectories(globalSearchScope).length > 0;
|
||||
@@ -793,7 +841,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
serviceLoader = ServiceLoader.load(Class.forName(JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_TEST_ENGINE, false, loader), loader);
|
||||
for (Object engine : serviceLoader) {
|
||||
String engineClassName = engine.getClass().getName();
|
||||
if (isCustomJunit5TestEngineName(engineClassName)) {
|
||||
if (isCustomJupiterTestEngineName(engineClassName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -804,10 +852,11 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean findCustomJunit5TestEngineUsingPsi(@NotNull GlobalSearchScope globalSearchScope,
|
||||
private static boolean hasCustomJupiterTestEngineUsingPsi(@NotNull GlobalSearchScope globalSearchScope,
|
||||
@NotNull Project project,
|
||||
@NotNull JavaPsiFacade psiFacade) {
|
||||
PsiClass testEngine = psiFacade.findClass(JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_TEST_ENGINE, globalSearchScope);
|
||||
@NotNull JavaPsiFacade psiFacade,
|
||||
@NotNull String jupiterClassName) {
|
||||
PsiClass testEngine = psiFacade.findClass(jupiterClassName, globalSearchScope);
|
||||
if (testEngine == null) return false;
|
||||
Collection<VirtualFile> files = FilenameIndex.getVirtualFilesByName(PsiJavaModule.MODULE_INFO_FILE, globalSearchScope);
|
||||
if (!files.isEmpty() && ReferencesSearch.search(testEngine, GlobalSearchScope.filesScope(project, files)).anyMatch(ref -> isCustomEngineProvided(testEngine, ref))) {
|
||||
@@ -815,7 +864,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
PsiManager psiManager = PsiManager.getInstance(project);
|
||||
GlobalSearchScope scope = GlobalSearchScope.getScopeRestrictedByFileTypes(globalSearchScope, SPIFileType.INSTANCE);
|
||||
return FilenameIndex.getVirtualFilesByName(JUnitCommonClassNames.ORG_JUNIT_PLATFORM_ENGINE_TEST_ENGINE, scope)
|
||||
return FilenameIndex.getVirtualFilesByName(jupiterClassName, scope)
|
||||
.stream()
|
||||
.map(f -> psiManager.findFile(f))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -823,7 +872,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
.map(r -> r.resolve())
|
||||
.filter(e -> e instanceof PsiClass)
|
||||
.map(e -> (PsiClass)e)
|
||||
.filter(c -> isCustomJunit5TestEngineName(c.getQualifiedName()))
|
||||
.filter(c -> isCustomJupiterTestEngineName(c.getQualifiedName()))
|
||||
.anyMatch(c -> InheritanceUtil.isInheritorOrSelf(c, testEngine, true));
|
||||
}
|
||||
|
||||
@@ -838,7 +887,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isCustomJunit5TestEngineName(@Nullable String engineImplClassName) {
|
||||
private static boolean isCustomJupiterTestEngineName(@Nullable String engineImplClassName) {
|
||||
return !"org.junit.jupiter.engine.JupiterTestEngine".equals(engineImplClassName) &&
|
||||
!"org.junit.vintage.engine.VintageTestEngine".equals(engineImplClassName);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.execution.*;
|
||||
@@ -67,7 +67,7 @@ public class TestPackage extends TestObject {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SearchForTestsTask createSearchingForTestsTask(@NotNull TargetEnvironment remoteEnvironment) throws ExecutionException {
|
||||
public @Nullable SearchForTestsTask createSearchingForTestsTask(@NotNull TargetEnvironment remoteEnvironment) {
|
||||
final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
|
||||
final Module module = getConfiguration().getConfigurationModule().getModule();
|
||||
return new SearchForTestsTask(getConfiguration().getProject(), getServerSocket()) {
|
||||
@@ -78,7 +78,7 @@ public class TestPackage extends TestObject {
|
||||
myClasses.clear();
|
||||
final SourceScope sourceScope = getSourceScope();
|
||||
if (sourceScope != null) {
|
||||
if (JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) {
|
||||
if (JUPITER_RUNNERS.contains(getRunner())) {
|
||||
searchTests5(module, myClasses);
|
||||
}
|
||||
else {
|
||||
@@ -95,7 +95,7 @@ public class TestPackage extends TestObject {
|
||||
try {
|
||||
String packageName = getPackageName(data);
|
||||
String filters = getFilters(myClasses, packageName);
|
||||
if (JUnitStarter.JUNIT5_PARAMETER.equals(getRunner()) && module != null && filterOutputByDirectoryForJunit5(myClasses)) {
|
||||
if (JUPITER_RUNNERS.contains(getRunner()) && module != null && filterOutputByDirectoryForJunit5(myClasses)) {
|
||||
JUnitStarter.printClassesList(composeDirectoryFilter(getModuleWithTestsToFilter(module)), packageName, "", filters, myTempFile);
|
||||
}
|
||||
else {
|
||||
@@ -148,7 +148,7 @@ public class TestPackage extends TestObject {
|
||||
}
|
||||
|
||||
protected boolean requiresSmartMode() {
|
||||
return !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner());
|
||||
return !JUPITER_RUNNERS.contains(getRunner());
|
||||
}
|
||||
|
||||
protected boolean filterOutputByDirectoryForJunit5(final Set<Location<?>> classNames) {
|
||||
@@ -167,7 +167,7 @@ public class TestPackage extends TestObject {
|
||||
collectClassesRecursively(classFilter, acceptClassCondition, classes);
|
||||
}
|
||||
else {
|
||||
LinkedHashSet<PsiClass> psiClasses = new LinkedHashSet<>();
|
||||
Set<PsiClass> psiClasses = new LinkedHashSet<>();
|
||||
ConfigurationUtil.findAllTestClasses(classFilter, module, psiClasses);
|
||||
psiClasses.stream().map(PsiLocation::fromPsiElement).forEach(classes::add);
|
||||
}
|
||||
@@ -198,7 +198,7 @@ public class TestPackage extends TestObject {
|
||||
final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
|
||||
final Project project = getConfiguration().getProject();
|
||||
final SourceScope sourceScope = data.getScope().getSourceScope(getConfiguration());
|
||||
if (sourceScope == null || !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) { //check for junit 5
|
||||
if (sourceScope == null || !JUPITER_RUNNERS.contains(getRunner())) { //check for junit 5/6
|
||||
ReadAction.run(() -> JUnitUtil.checkTestCase(sourceScope, project));
|
||||
}
|
||||
createTempFiles(javaParameters);
|
||||
|
||||
@@ -94,8 +94,8 @@ public final class UniqueIdConfigurationProducer extends JUnitConfigurationProdu
|
||||
Project project = context.getProject();
|
||||
GlobalSearchScope searchScope =
|
||||
module != null ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) : GlobalSearchScope.projectScope(project);
|
||||
if (!DumbModeAccessType.RELIABLE_DATA_ONLY.ignoreDumbMode(() -> JUnitUtil.isJUnit5(searchScope, project) ||
|
||||
TestObject.hasJUnit5EnginesAPI(searchScope, JavaPsiFacade.getInstance(project)))) {
|
||||
if (!DumbModeAccessType.RELIABLE_DATA_ONLY.ignoreDumbMode(() -> JUnitUtil.isJUnit5(searchScope, project) ||
|
||||
TestObject.hasJupiterEnginesAPI(searchScope, JavaPsiFacade.getInstance(project)))) {
|
||||
return null;
|
||||
}
|
||||
return
|
||||
|
||||
+4
-1
@@ -15,10 +15,13 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public final class JUnit3StyleTestMethodInJUnit4ClassInspection extends BaseInspection {
|
||||
private static final List<String> IGNORED_FRAMEWORKS = List.of("JUnit4", "JUnit5", "JUnit6");
|
||||
|
||||
@Override
|
||||
protected @NotNull String buildErrorString(Object... infos) {
|
||||
@@ -49,7 +52,7 @@ public final class JUnit3StyleTestMethodInJUnit4ClassInspection extends BaseInsp
|
||||
if (testFramework != null) {
|
||||
if (testFramework.isTestMethod(method, false)) {
|
||||
final @NonNls String testFrameworkName = testFramework.getName();
|
||||
if (testFrameworkName.equals("JUnit4") || testFrameworkName.equals("JUnit5")) return;
|
||||
if (IGNORED_FRAMEWORKS.contains(testFrameworkName)) return;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(method, "org.junit.Ignore", 0) ||
|
||||
testFramework.findSetUpMethod(containingClass) == method ||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.junit.codeInspection.naming;
|
||||
|
||||
import com.intellij.codeInspection.naming.NamingConvention;
|
||||
@@ -20,7 +20,7 @@ public final class JUnit4MethodNamingConvention extends NamingConvention<PsiMeth
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(PsiMethod member) {
|
||||
return TestUtils.isExecutableTestMethod(member, List.of("JUnit4", "JUnit5"));
|
||||
return TestUtils.isExecutableTestMethod(member, List.of("JUnit4", "JUnit5", "JUnit6"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ public class JUnitConfigurationModel {
|
||||
|
||||
if (myProject.isDefault() ||
|
||||
JUnitUtil.isJUnit5(searchScope, myProject) ||
|
||||
TestObject.hasJUnit5EnginesAPI(searchScope, JavaPsiFacade.getInstance(myProject))) {
|
||||
TestObject.hasJupiterEnginesAPI(searchScope, JavaPsiFacade.getInstance(myProject))) {
|
||||
aModel.addElement(UNIQUE_ID);
|
||||
aModel.addElement(TAGS);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit5;
|
||||
|
||||
import com.intellij.codeInsight.TestFrameworks;
|
||||
@@ -169,7 +169,7 @@ public class JUnit5AcceptanceTest extends JUnit5CodeInsightTest {
|
||||
.map(action -> action.getText())
|
||||
.filter(name -> name.startsWith("Add")).collect(Collectors.toSet());
|
||||
assertAll("Detected frameworks: " + frameworks,
|
||||
() -> assertTrue(frameworks.contains("Add 'JUnit5.8.1' to classpath")));
|
||||
() -> assertTrue(frameworks.contains("Add 'JUnit5' to classpath")));
|
||||
|
||||
myFixture.configureByText("MyTest.java",
|
||||
"class MyTest {@<error descr=\"Cannot resolve symbol 'DisplayName'\">DisplayName</error> void method() {}}");
|
||||
@@ -179,7 +179,7 @@ public class JUnit5AcceptanceTest extends JUnit5CodeInsightTest {
|
||||
.map(action -> action.getText())
|
||||
.filter(name -> name.startsWith("Add")).collect(Collectors.toSet());
|
||||
assertAll("Detected frameworks: " + displayNameFrameworks,
|
||||
() -> assertTrue(displayNameFrameworks.contains("Add 'JUnit5.8.1' to classpath")));
|
||||
() -> assertTrue(displayNameFrameworks.contains("Add 'JUnit5' to classpath")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
### auto-generated section `build intellij.junit.v6.rt` start
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library")
|
||||
|
||||
jvm_library(
|
||||
name = "junit-v6-rt",
|
||||
module_name = "intellij.junit.v6.rt",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["src/**/*.kt", "src/**/*.java", "src/**/*.form"], allow_empty = True),
|
||||
kotlinc_opts = "@community//:k17",
|
||||
deps = [
|
||||
"//plugins/junit_rt:junit-rt",
|
||||
"//java/java-runtime:rt",
|
||||
"@lib//:junit6Launcher-provided",
|
||||
"@lib//:junit6-provided",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.junit.v6.rt` end
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_17" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="intellij.junit.rt" />
|
||||
<orderEntry type="module" module-name="intellij.java.rt" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="JUnit6Launcher" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="JUnit6" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
Binary file not shown.
@@ -0,0 +1,159 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.rt.execution.junit.IDEAJUnitListener;
|
||||
import com.intellij.rt.execution.junit.IDEAJUnitListenerEx;
|
||||
import com.intellij.rt.junit.IdeaTestRunner;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.engine.UniqueId;
|
||||
import org.junit.platform.engine.support.descriptor.EngineDescriptor;
|
||||
import org.junit.platform.launcher.*;
|
||||
import org.junit.platform.launcher.core.LauncherFactory;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class JUnit6IdeaTestRunner implements IdeaTestRunner<TestIdentifier> {
|
||||
private final List<JUnit6TestExecutionListener> myExecutionListeners = new ArrayList<>();
|
||||
private ArrayList<String> myListeners;
|
||||
private Launcher myLauncher;
|
||||
|
||||
public JUnit6IdeaTestRunner() {
|
||||
Runnable warmup = (Runnable) Proxy.newProxyInstance(
|
||||
JUnit6IdeaTestRunner.class.getClassLoader(),
|
||||
new Class<?>[]{Runnable.class},
|
||||
(proxy, method, args) -> null);
|
||||
warmup.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createListeners(ArrayList<String> listeners, int count) {
|
||||
myListeners = listeners;
|
||||
do {
|
||||
JUnit6TestExecutionListener currentListener = new JUnit6TestExecutionListener();
|
||||
myExecutionListeners.add(currentListener);
|
||||
if (count > 2) {
|
||||
currentListener.initializeIdSuffix(count);
|
||||
}
|
||||
}
|
||||
while (--count > 0);
|
||||
myLauncher = LauncherFactory.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int startRunnerWithArgs(String[] args, String programParam, int count, boolean sendTree) {
|
||||
try {
|
||||
JUnit6TestExecutionListener listener = myExecutionListeners.get(0);
|
||||
listener.initializeIdSuffix(!sendTree);
|
||||
final String[] packageNameRef = new String[1];
|
||||
final LauncherDiscoveryRequest discoveryRequest = JUnit6TestRunnerUtil.buildRequest(args, packageNameRef, programParam);
|
||||
List<TestExecutionListener> listeners = new ArrayList<>();
|
||||
listeners.add(listener);
|
||||
for (String listenerClassName : myListeners) {
|
||||
final IDEAJUnitListener junitListener = (IDEAJUnitListener)Class.forName(listenerClassName).getDeclaredConstructor().newInstance();
|
||||
listeners.add(new MyCustomListenerWrapper(junitListener));
|
||||
}
|
||||
if (sendTree) {
|
||||
for (JUnit6TestExecutionListener executionListener : myExecutionListeners) {
|
||||
executionListener.setRootName(packageNameRef[0]);
|
||||
executionListener.setSendTree();
|
||||
}
|
||||
}
|
||||
|
||||
myLauncher.execute(discoveryRequest, listeners.toArray(new TestExecutionListener[0]));
|
||||
|
||||
return listener.wasSuccessful() ? 0 : -1;
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.err.println("Internal Error occurred.");
|
||||
e.printStackTrace(System.err);
|
||||
return -2;
|
||||
}
|
||||
finally {
|
||||
if (count > 0) myExecutionListeners.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
private TestPlan myForkedTestPlan;
|
||||
private static final TestIdentifier FAKE_ROOT = TestIdentifier.from(new EngineDescriptor(UniqueId.forEngine("FAKE_ENGINE"), "FAKE ENGINE"));
|
||||
@Override
|
||||
public TestIdentifier getTestToStart(String[] args, String name) {
|
||||
final LauncherDiscoveryRequest discoveryRequest = JUnit6TestRunnerUtil.buildRequest(args, new String[1], "");
|
||||
myForkedTestPlan = LauncherFactory.create().discover(discoveryRequest);
|
||||
final Set<TestIdentifier> roots = myForkedTestPlan.getRoots();
|
||||
if (roots.isEmpty()) return null;
|
||||
List<TestIdentifier> nonEmptyRoots = roots.stream()
|
||||
.filter(identifier -> !myForkedTestPlan.getChildren(identifier).isEmpty())
|
||||
.toList();
|
||||
if (nonEmptyRoots.isEmpty()) return null;
|
||||
return nonEmptyRoots.size() == 1 ? nonEmptyRoots.get(0) : FAKE_ROOT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TestIdentifier> getChildTests(TestIdentifier description) {
|
||||
if (description == FAKE_ROOT) {
|
||||
return myForkedTestPlan.getRoots()
|
||||
.stream()
|
||||
.flatMap(root -> myForkedTestPlan.getChildren(root).stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return new ArrayList<>(myForkedTestPlan.getChildren(description));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link com.intellij.execution.junit.TestClass#getForkMode()}
|
||||
*/
|
||||
@Override
|
||||
public String getStartDescription(TestIdentifier child) {
|
||||
if (myForkedTestPlan.getParent(child).isEmpty()) {
|
||||
//if fork mode is "repeat", then the only child is the corresponding class
|
||||
child = myForkedTestPlan.getChildren(child).iterator().next();
|
||||
}
|
||||
final TestIdentifier testIdentifier = child;
|
||||
final String className = JUnit6TestExecutionListener.getClassName(testIdentifier);
|
||||
final String methodSignature = JUnit6TestExecutionListener.getMethodSignature(testIdentifier);
|
||||
if (methodSignature != null) {
|
||||
return className + "," + methodSignature;
|
||||
}
|
||||
return className != null ? className : testIdentifier.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestClassName(TestIdentifier child) {
|
||||
return child.toString();
|
||||
}
|
||||
|
||||
private static class MyCustomListenerWrapper implements TestExecutionListener {
|
||||
private final IDEAJUnitListener myJunitListener;
|
||||
|
||||
MyCustomListenerWrapper(IDEAJUnitListener junitListener) {
|
||||
myJunitListener = junitListener;}
|
||||
|
||||
@Override
|
||||
public void executionStarted(TestIdentifier testIdentifier) {
|
||||
if (testIdentifier.isTest()) {
|
||||
final String className = JUnit6TestExecutionListener.getClassName(testIdentifier);
|
||||
final String methodName = JUnit6TestExecutionListener.getMethodName(testIdentifier);
|
||||
myJunitListener.testStarted(className, methodName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executionFinished(TestIdentifier testIdentifier, @NonNull TestExecutionResult testExecutionResult) {
|
||||
if (testIdentifier.isTest()) {
|
||||
final String className = JUnit6TestExecutionListener.getClassName(testIdentifier);
|
||||
final String methodName = JUnit6TestExecutionListener.getMethodName(testIdentifier);
|
||||
if (myJunitListener instanceof IDEAJUnitListenerEx) {
|
||||
((IDEAJUnitListenerEx)myJunitListener).testFinished(className, methodName, testExecutionResult.getStatus() == TestExecutionResult.Status.SUCCESSFUL);
|
||||
}
|
||||
else {
|
||||
myJunitListener.testFinished(className, methodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.junit4.ExpectedPatterns;
|
||||
import com.intellij.rt.execution.junit.ComparisonFailureData;
|
||||
import com.intellij.rt.execution.junit.MapSerializerUtil;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.engine.TestSource;
|
||||
import org.junit.platform.engine.UniqueId;
|
||||
import org.junit.platform.engine.reporting.ReportEntry;
|
||||
import org.junit.platform.engine.support.descriptor.ClassSource;
|
||||
import org.junit.platform.engine.support.descriptor.CompositeTestSource;
|
||||
import org.junit.platform.engine.support.descriptor.FileSource;
|
||||
import org.junit.platform.engine.support.descriptor.MethodSource;
|
||||
import org.junit.platform.launcher.TestExecutionListener;
|
||||
import org.junit.platform.launcher.TestIdentifier;
|
||||
import org.junit.platform.launcher.TestPlan;
|
||||
import org.opentest4j.MultipleFailuresError;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.rt.execution.TestListenerProtocol.CLASS_CONFIGURATION;
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class JUnit6TestExecutionListener implements TestExecutionListener {
|
||||
private static final String NO_LOCATION_HINT = "";
|
||||
private static final String NO_LOCATION_HINT_VALUE = "";
|
||||
|
||||
private final PrintStream myPrintStream;
|
||||
private TestPlan myTestPlan;
|
||||
private long myCurrentTestStart;
|
||||
private int myFinishCount = 0;
|
||||
private String myRootName;
|
||||
private String myPresentableName;
|
||||
private boolean mySuccessful = true;
|
||||
private String myIdSuffix = "";
|
||||
private boolean mySendTree;
|
||||
|
||||
public JUnit6TestExecutionListener() {
|
||||
this(System.out);
|
||||
}
|
||||
|
||||
public JUnit6TestExecutionListener(PrintStream printStream) {
|
||||
myPrintStream = printStream;
|
||||
myPrintStream.println("##teamcity[enteredTheMatrix]");
|
||||
}
|
||||
|
||||
public boolean wasSuccessful() {
|
||||
return mySuccessful;
|
||||
}
|
||||
|
||||
public void initializeIdSuffix(boolean forked) {
|
||||
if (forked && myIdSuffix.isEmpty()) {
|
||||
myIdSuffix = String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeIdSuffix(int i) {
|
||||
myIdSuffix = i + "th";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportingEntryPublished(@NonNull TestIdentifier testIdentifier, ReportEntry entry) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("timestamp = ").append(entry.getTimestamp());
|
||||
entry.getKeyValuePairs().forEach((key, value) -> builder.append(", ").append(key).append(" = ").append(value));
|
||||
builder.append("\n");
|
||||
myPrintStream.println("##teamcity[testStdOut" + idAndName(testIdentifier) + " out = '" + escapeName(builder.toString()) + "']");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testPlanExecutionStarted(@NonNull TestPlan testPlan) {
|
||||
myTestPlan = testPlan;
|
||||
if (mySendTree) {
|
||||
for (TestIdentifier root : myTestPlan.getRoots()) {
|
||||
assert root.isContainer();
|
||||
for (TestIdentifier testIdentifier : myTestPlan.getChildren(root)) {
|
||||
String legacyReportingName = testIdentifier.getLegacyReportingName();
|
||||
if (legacyReportingName.equals(myRootName)) setPresentableName(testIdentifier.getDisplayName());
|
||||
sendTreeUnderRoot(testIdentifier, new HashSet<>());
|
||||
}
|
||||
}
|
||||
myPrintStream.println("##teamcity[treeEnded]");
|
||||
}
|
||||
|
||||
if (myRootName != null) {
|
||||
int lastPointIdx = myRootName.lastIndexOf('.');
|
||||
String name = myRootName;
|
||||
String comment = null;
|
||||
if (lastPointIdx >= 0) {
|
||||
name = myRootName.substring(lastPointIdx + 1);
|
||||
comment = myRootName.substring(0, lastPointIdx);
|
||||
}
|
||||
|
||||
String messageName = (myPresentableName == null || myPresentableName.isEmpty()) ? name : myPresentableName;
|
||||
|
||||
myPrintStream.println("##teamcity[rootName name = '" + escapeName(messageName) +
|
||||
(comment != null ? ("' comment = '" + escapeName(comment)) : "") + "'" +
|
||||
" location = 'java:suite://" + escapeName(myRootName) +
|
||||
"']");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendTreeUnderRoot(TestIdentifier root, HashSet<TestIdentifier> visited) {
|
||||
String idAndName = idAndName(root);
|
||||
if (root.isContainer()) {
|
||||
boolean skipContainer = shouldSkipContainer(root);
|
||||
if (!skipContainer) myPrintStream.println("##teamcity[suiteTreeStarted" + idAndName + " " + getLocationHint(root) + "]");
|
||||
for (TestIdentifier childIdentifier : myTestPlan.getChildren(root)) {
|
||||
if (visited.add(childIdentifier)) {
|
||||
sendTreeUnderRoot(childIdentifier, visited);
|
||||
}
|
||||
else {
|
||||
System.err.println("Identifier '" + getId(childIdentifier) + "' is reused");
|
||||
}
|
||||
}
|
||||
if (!skipContainer) myPrintStream.println("##teamcity[suiteTreeEnded" + idAndName + "]");
|
||||
}
|
||||
else if (root.isTest()) {
|
||||
myPrintStream.println("##teamcity[suiteTreeNode " + idAndName + " " + getLocationHint(root) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executionSkipped(@NonNull TestIdentifier testIdentifier, @NonNull String reason) {
|
||||
executionStarted (testIdentifier);
|
||||
executionFinished(testIdentifier, TestExecutionResult.Status.ABORTED, null, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executionStarted(TestIdentifier testIdentifier) {
|
||||
if (testIdentifier.isTest()) {
|
||||
testStarted(testIdentifier);
|
||||
myCurrentTestStart = System.nanoTime();
|
||||
}
|
||||
else if (!shouldSkipContainer(testIdentifier)) {
|
||||
myFinishCount = 0;
|
||||
myPrintStream.println("##teamcity[testSuiteStarted" + idAndName(testIdentifier) + getLocationHint(testIdentifier) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executionFinished(@NonNull TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
|
||||
TestExecutionResult.Status status = testExecutionResult.getStatus();
|
||||
Throwable throwableOptional = testExecutionResult.getThrowable().orElse(null);
|
||||
executionFinished(testIdentifier, status, throwableOptional, null);
|
||||
mySuccessful &= TestExecutionResult.Status.SUCCESSFUL == testExecutionResult.getStatus();
|
||||
}
|
||||
|
||||
private void executionFinished(TestIdentifier testIdentifier,
|
||||
TestExecutionResult.Status status,
|
||||
Throwable throwableOptional,
|
||||
String reason) {
|
||||
if (testIdentifier.isTest()) {
|
||||
long duration = getDuration();
|
||||
if (status == TestExecutionResult.Status.FAILED) {
|
||||
testFailure(testIdentifier, MapSerializerUtil.TEST_FAILED, throwableOptional, duration, reason, true);
|
||||
}
|
||||
else if (status == TestExecutionResult.Status.ABORTED) {
|
||||
testFailure(testIdentifier, MapSerializerUtil.TEST_IGNORED, throwableOptional, duration, reason, true);
|
||||
}
|
||||
testFinished(testIdentifier, duration);
|
||||
myFinishCount++;
|
||||
}
|
||||
else if (!shouldSkipContainer(testIdentifier) || status == TestExecutionResult.Status.FAILED){
|
||||
String messageName = null;
|
||||
if (status == TestExecutionResult.Status.FAILED) {
|
||||
messageName = MapSerializerUtil.TEST_FAILED;
|
||||
}
|
||||
else if (status == TestExecutionResult.Status.ABORTED) {
|
||||
messageName = MapSerializerUtil.TEST_IGNORED;
|
||||
}
|
||||
if (messageName != null) {
|
||||
Set<TestIdentifier> descendants = myTestPlan != null ? myTestPlan.getDescendants(testIdentifier) : Collections.emptySet();
|
||||
if (status == TestExecutionResult.Status.FAILED) {
|
||||
String parentId = getParentId(testIdentifier);
|
||||
String nameAndId = " name='" + CLASS_CONFIGURATION +
|
||||
"' nodeId='" + escapeName(getId(testIdentifier)) +
|
||||
"' parentNodeId='" + escapeName(parentId) + "' ";
|
||||
myPrintStream.println("##teamcity[testStarted " + nameAndId + " ]");
|
||||
testFailure(CLASS_CONFIGURATION, getId(testIdentifier), parentId, messageName, throwableOptional, 0, reason, true);
|
||||
myPrintStream.println("##teamcity[testFinished" + nameAndId + "]");
|
||||
}
|
||||
else if (descendants.isEmpty()) {
|
||||
testFailure(testIdentifier, MapSerializerUtil.TEST_IGNORED, throwableOptional, 0, reason, true);
|
||||
}
|
||||
|
||||
if (!descendants.isEmpty() && myFinishCount == 0) {
|
||||
for (TestIdentifier childIdentifier : descendants) {
|
||||
testStarted(childIdentifier);
|
||||
Throwable throwable = status == TestExecutionResult.Status.ABORTED ? throwableOptional : null;
|
||||
testFailure(childIdentifier, MapSerializerUtil.TEST_IGNORED, throwable, 0, reason, status == TestExecutionResult.Status.ABORTED);
|
||||
testFinished(childIdentifier, 0);
|
||||
}
|
||||
myFinishCount = 0;
|
||||
}
|
||||
}
|
||||
myPrintStream.println("##teamcity[testSuiteFinished" + idAndName(testIdentifier) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldSkipContainer(TestIdentifier testIdentifier) {
|
||||
UniqueId id = UniqueId.parse(testIdentifier.getUniqueId());
|
||||
List<UniqueId.Segment> segments = id.getSegments();
|
||||
if (segments.isEmpty()) return false;
|
||||
UniqueId.Segment lastSegment = segments.get(segments.size() - 1);
|
||||
return lastSegment.getType().equals("engine") ||
|
||||
myRootName != null && myRootName.equals(lastSegment.getValue());
|
||||
}
|
||||
|
||||
protected long getDuration() {
|
||||
return (System.nanoTime() - myCurrentTestStart) / 1_000_000;
|
||||
}
|
||||
|
||||
private void testStarted(TestIdentifier testIdentifier) {
|
||||
myPrintStream.println("##teamcity[testStarted" + idAndName(testIdentifier) + " " + getLocationHint(testIdentifier) + "]");
|
||||
}
|
||||
|
||||
private void testFinished(TestIdentifier testIdentifier, long duration) {
|
||||
myPrintStream.println("##teamcity[testFinished" + idAndName(testIdentifier) + (duration > 0 ? " duration='" + duration + "'" : "") + "]");
|
||||
}
|
||||
|
||||
private void testFailure(TestIdentifier testIdentifier,
|
||||
String messageName,
|
||||
Throwable ex,
|
||||
long duration,
|
||||
String reason,
|
||||
boolean includeThrowable) {
|
||||
testFailure(testIdentifier.getDisplayName(), getId(testIdentifier), getParentId(testIdentifier), messageName, ex, duration, reason, includeThrowable);
|
||||
}
|
||||
|
||||
private void testFailure(String methodName,
|
||||
String id,
|
||||
String parentId,
|
||||
String messageName,
|
||||
Throwable ex,
|
||||
long duration,
|
||||
String reason,
|
||||
boolean includeThrowable) {
|
||||
Map<String, String> attrs = new LinkedHashMap<>();
|
||||
attrs.put("name", methodName);
|
||||
attrs.put("id", id);
|
||||
attrs.put("nodeId", id);
|
||||
attrs.put("parentNodeId", parentId);
|
||||
if (duration > 0) {
|
||||
attrs.put("duration", Long.toString(duration));
|
||||
}
|
||||
if (reason != null) {
|
||||
attrs.put("message", reason);
|
||||
}
|
||||
try {
|
||||
if (ex != null) {
|
||||
ComparisonFailureData failureData = null;
|
||||
if (ex instanceof MultipleFailuresError && ((MultipleFailuresError)ex).hasFailures()) {
|
||||
for (Throwable assertionError : ((MultipleFailuresError)ex).getFailures()) {
|
||||
testFailure(methodName, id, parentId, messageName, assertionError, duration, reason, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
failureData = ExpectedPatterns.createExceptionNotification(ex);
|
||||
}
|
||||
catch (Throwable ignore) {}
|
||||
}
|
||||
|
||||
if (includeThrowable || failureData == null) {
|
||||
ComparisonFailureData.registerSMAttributes(failureData, getTrace(ex), ex.getMessage(), attrs, ex, "Comparison Failure: ", "expected: <");
|
||||
}
|
||||
else {
|
||||
ComparisonFailureData.registerSMAttributes(failureData, "", ex.getMessage(), attrs, ex, "Comparison Failure: ", "expected: <");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myPrintStream.println(MapSerializerUtil.asString(messageName, attrs));
|
||||
}
|
||||
}
|
||||
|
||||
protected String getTrace(Throwable ex) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(stringWriter);
|
||||
ex.printStackTrace(writer);
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
public void setRootName(String rootName) {
|
||||
myRootName = rootName;
|
||||
}
|
||||
|
||||
public void setPresentableName(String presentableName) {
|
||||
myPresentableName = presentableName;
|
||||
}
|
||||
|
||||
public void setSendTree() {
|
||||
mySendTree = true;
|
||||
}
|
||||
|
||||
private String getId(TestIdentifier identifier) {
|
||||
return identifier.getUniqueId() + myIdSuffix;
|
||||
}
|
||||
|
||||
private String idAndName(TestIdentifier testIdentifier) {
|
||||
return " id='" + escapeName(getId(testIdentifier)) +
|
||||
"' name='" + escapeName(testIdentifier.getDisplayName()) +
|
||||
"' nodeId='" + escapeName(getId(testIdentifier)) +
|
||||
"' parentNodeId='" + escapeName(getParentId(testIdentifier)) + "'";
|
||||
}
|
||||
|
||||
private String getParentId(TestIdentifier testIdentifier) {
|
||||
Optional<TestIdentifier> parent = myTestPlan.getParent(testIdentifier);
|
||||
return parent
|
||||
.map(identifier -> shouldSkipContainer(identifier) ? getParentId(identifier) : identifier.getUniqueId() + myIdSuffix)
|
||||
.orElse("0");
|
||||
}
|
||||
|
||||
|
||||
private String getLocationHint(TestIdentifier root) {
|
||||
return getLocationHint(root, myTestPlan.getParent(root).orElse(null));
|
||||
}
|
||||
|
||||
public static String getLocationHint(TestIdentifier root, TestIdentifier rootParent) {
|
||||
return root.getSource()
|
||||
.map(testSource -> getLocationHintValue(testSource, rootParent != null ? rootParent.getSource().orElse(null) : null))
|
||||
.filter(maybeLocationHintValue -> !NO_LOCATION_HINT_VALUE.equals(maybeLocationHintValue))
|
||||
.map(locationHintValue -> "locationHint='" + locationHintValue + "'" + getMetaInfo(root))
|
||||
.orElse(NO_LOCATION_HINT);
|
||||
}
|
||||
|
||||
private static String getMetaInfo(TestIdentifier root) {
|
||||
return root.getSource()
|
||||
.map(testSource -> {
|
||||
if (testSource instanceof MethodSource) {
|
||||
return " metainfo='" + ((MethodSource)testSource).getMethodParameterTypes() + "'";
|
||||
}
|
||||
if (testSource instanceof ClassSource) {
|
||||
return ((ClassSource)testSource).getPosition()
|
||||
.map(position ->
|
||||
" metainfo='"
|
||||
// Convert JUnit's 1-based values to 0-based
|
||||
+ (position.getLine() - 1) + ":"
|
||||
+ (position.getColumn().orElse(1) - 1) + "'")
|
||||
.orElse(NO_LOCATION_HINT);
|
||||
}
|
||||
return NO_LOCATION_HINT;
|
||||
})
|
||||
.orElse(NO_LOCATION_HINT);
|
||||
}
|
||||
|
||||
public static String getLocationHintValue(TestSource testSource, TestSource parentSource) {
|
||||
|
||||
if (testSource instanceof CompositeTestSource compositeTestSource) {
|
||||
for (TestSource sourceFromComposite : compositeTestSource.getSources()) {
|
||||
String locationHintValue = getLocationHintValue(sourceFromComposite, parentSource);
|
||||
if (!NO_LOCATION_HINT_VALUE.equals(locationHintValue)) {
|
||||
return locationHintValue;
|
||||
}
|
||||
}
|
||||
return NO_LOCATION_HINT_VALUE;
|
||||
}
|
||||
|
||||
if (testSource instanceof FileSource fileSource) {
|
||||
File file = fileSource.getFile();
|
||||
String line = fileSource.getPosition()
|
||||
.map(position -> ":" + position.getLine())
|
||||
.orElse("");
|
||||
return "file://" + file.getAbsolutePath() + line;
|
||||
}
|
||||
|
||||
if (testSource instanceof MethodSource methodSource) {
|
||||
return javaLocation(methodSource.getClassName(), methodSource.getMethodName(), true);
|
||||
}
|
||||
|
||||
if (testSource instanceof ClassSource) {
|
||||
String className = ((ClassSource)testSource).getClassName();
|
||||
return javaLocation(className, null, false);
|
||||
}
|
||||
|
||||
if (parentSource != null) {
|
||||
return getLocationHintValue(parentSource,null);
|
||||
}
|
||||
|
||||
return NO_LOCATION_HINT_VALUE;
|
||||
}
|
||||
|
||||
private static String javaLocation(String className, String maybeMethodName, boolean isTest) {
|
||||
String type = isTest ? "test" : "suite";
|
||||
String methodName = maybeMethodName == null ? "" : "/" + maybeMethodName;
|
||||
String location = escapeName(className + methodName);
|
||||
return "java:" + type + "://" + location;
|
||||
}
|
||||
|
||||
private static String escapeName(String str) {
|
||||
return MapSerializerUtil.escapeStr(str, MapSerializerUtil.STD_ESCAPER);
|
||||
}
|
||||
|
||||
public static String getClassName(TestIdentifier description) {
|
||||
return description.getSource().map(source -> {
|
||||
if (source instanceof MethodSource) {
|
||||
return ((MethodSource)source).getClassName();
|
||||
}
|
||||
if (source instanceof ClassSource) {
|
||||
return ((ClassSource)source).getClassName();
|
||||
}
|
||||
return null;
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
public static String getMethodName(TestIdentifier testIdentifier) {
|
||||
return testIdentifier.getSource().map((source) -> {
|
||||
if (source instanceof MethodSource) {
|
||||
return ((MethodSource)source).getMethodName();
|
||||
}
|
||||
return null;
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
static String getMethodSignature(TestIdentifier testIdentifier) {
|
||||
return testIdentifier.getSource().map((source) -> {
|
||||
if (source instanceof MethodSource) {
|
||||
String parameterTypes = ((MethodSource)source).getMethodParameterTypes();
|
||||
return ((MethodSource)source).getMethodName() + (parameterTypes != null ? "(" + parameterTypes + ")" : "");
|
||||
}
|
||||
return null;
|
||||
}).orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.junit.platform.commons.support.ReflectionSupport;
|
||||
import org.junit.platform.engine.DiscoverySelector;
|
||||
import org.junit.platform.engine.FilterResult;
|
||||
import org.junit.platform.engine.TestDescriptor;
|
||||
import org.junit.platform.engine.TestSource;
|
||||
import org.junit.platform.engine.discovery.*;
|
||||
import org.junit.platform.engine.support.descriptor.MethodSource;
|
||||
import org.junit.platform.launcher.LauncherDiscoveryRequest;
|
||||
import org.junit.platform.launcher.PostDiscoveryFilter;
|
||||
import org.junit.platform.launcher.TagFilter;
|
||||
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class JUnit6TestRunnerUtil {
|
||||
private static final Pattern VALUE_SOURCE_PATTERN = Pattern.compile("valueSource\\s(\\d+)");
|
||||
private static Class<?> NESTED_CLASS_SELECTOR_CLASS = null;
|
||||
|
||||
public static LauncherDiscoveryRequest buildRequest(String[] suiteClassNames, String[] packageNameRef, String param) {
|
||||
if (suiteClassNames.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LauncherDiscoveryRequestBuilder builder = LauncherDiscoveryRequestBuilder.request();
|
||||
|
||||
|
||||
if (suiteClassNames.length == 1 && suiteClassNames[0].charAt(0) == '@') {
|
||||
// all tests in the package specified
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(suiteClassNames[0].substring(1), StandardCharsets.UTF_8))) {
|
||||
final String packageName = reader.readLine();
|
||||
if (packageName == null) return null;
|
||||
|
||||
String tags = reader.readLine();
|
||||
String filters = reader.readLine();
|
||||
String line;
|
||||
|
||||
List<DiscoverySelector> selectors = new ArrayList<>();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
DiscoverySelector selector = createSelector(line, null);
|
||||
if (selector != null) {
|
||||
selectors.add(selector);
|
||||
}
|
||||
}
|
||||
if (hasBrokenSelector(selectors)) {
|
||||
builder.filters(createMethodFilter(new ArrayList<>(selectors)));
|
||||
for (int i = 0; i < selectors.size(); i++) {
|
||||
DiscoverySelector selector = selectors.get(i);
|
||||
if (selector instanceof MethodSelector) {
|
||||
selectors.set(i, createClassSelector(((MethodSelector)selector).getClassName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
packageNameRef[0] = packageName.isEmpty() ? "<default package>" : packageName;
|
||||
if (selectors.isEmpty()) {
|
||||
builder.selectors(DiscoverySelectors.selectPackage(packageName));
|
||||
}
|
||||
else {
|
||||
builder.selectors(selectors);
|
||||
if (!packageName.isEmpty()) {
|
||||
builder.filters(PackageNameFilter.includePackageNames(packageName));
|
||||
}
|
||||
}
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
String[] classNames = filters.split("\\|\\|");
|
||||
for (String className : classNames) {
|
||||
if (!className.contains("*")) {
|
||||
try {
|
||||
Class.forName(className, false, JUnit6TestRunnerUtil.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
System.err.println(MessageFormat.format(ResourceBundle.getBundle("messages.RuntimeBundle").getString("junit.class.not.found"), className));
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.filters(ClassNameFilter.includeClassNamePatterns(classNames));
|
||||
}
|
||||
if (tags != null && !tags.isEmpty()) {
|
||||
builder.filters(TagFilter.includeTags(tags.split(" ")));
|
||||
}
|
||||
return builder.filters(ClassNameFilter.excludeClassNamePatterns("com\\.intellij\\.rt.*", "com\\.intellij\\.junit3.*")).build();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DiscoverySelector selector = createSelector(suiteClassNames[0], packageNameRef);
|
||||
if (selector instanceof MethodSelector) {
|
||||
DiscoverySelector classSelector = createClassSelector(((MethodSelector)selector).getClassName());
|
||||
DiscoverySelector methodSelector = isNestedClassSelector(classSelector)
|
||||
? DiscoverySelectors.selectMethod(((NestedClassSelector)classSelector).getNestedClassName(),
|
||||
((MethodSelector)selector).getMethodName())
|
||||
: selector;
|
||||
builder.filters(createMethodFilter(Collections.singletonList(methodSelector)));
|
||||
selector = classSelector;
|
||||
}
|
||||
if (selector instanceof MethodSelector && param != null) {
|
||||
DiscoverySelector methodSelectIteration = createMethodSelectIteration(selector, param);
|
||||
if (methodSelectIteration != null) {
|
||||
return builder.selectors(methodSelectIteration).build();
|
||||
}
|
||||
}
|
||||
assert selector != null : "selector by class name is never null";
|
||||
return builder.selectors(selector).build();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isNestedClassSelector(DiscoverySelector selector) {
|
||||
if (NESTED_CLASS_SELECTOR_CLASS == null) {
|
||||
try {
|
||||
NESTED_CLASS_SELECTOR_CLASS = Class.forName("org.junit.platform.engine.discovery.NestedClassSelector");
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return NESTED_CLASS_SELECTOR_CLASS.isInstance(selector);
|
||||
}
|
||||
|
||||
private static boolean loadMethodByReflection(MethodSelector selector) {
|
||||
try {
|
||||
Class<?> aClass = Class.forName(selector.getClassName());
|
||||
return ReflectionSupport.findMethod(aClass, selector.getMethodName(), selector.getParameterTypes()).isPresent();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasBrokenSelector(List<DiscoverySelector> selectors) {
|
||||
for (DiscoverySelector selector : selectors) {
|
||||
if (selector instanceof MethodSelector && !loadMethodByReflection((MethodSelector)selector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static PostDiscoveryFilter createMethodFilter(List<DiscoverySelector> selectors) {
|
||||
return new PostDiscoveryFilter() {
|
||||
@Override
|
||||
public @NonNull FilterResult apply(TestDescriptor descriptor) {
|
||||
return FilterResult.includedIf(shouldRun(descriptor),
|
||||
() -> descriptor.getDisplayName() + " matches",
|
||||
() -> descriptor.getDisplayName() + " doesn't match");
|
||||
}
|
||||
|
||||
private boolean shouldRun(TestDescriptor descriptor) {
|
||||
TestSource source = descriptor.getSource().orElse(null);
|
||||
if (source instanceof MethodSource) {
|
||||
for (DiscoverySelector selector : selectors) {
|
||||
if (selector instanceof MethodSelector &&
|
||||
((MethodSelector)selector).getMethodName().equals(((MethodSource)source).getMethodName()) &&
|
||||
(((MethodSelector)selector).getClassName().equals(((MethodSource)source).getClassName()) ||
|
||||
inNestedClass((MethodSource)source, createClassSelector(((MethodSelector)selector).getClassName())))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (DiscoverySelector selector : selectors) {
|
||||
if (selector instanceof ClassSelector && ((ClassSelector)selector).getClassName().equals(((MethodSource)source).getClassName()) ||
|
||||
inNestedClass((MethodSource)source, selector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean inNestedClass(MethodSource source, DiscoverySelector selector) {
|
||||
return isNestedClassSelector(selector) &&
|
||||
((NestedClassSelector)selector).getNestedClassName().equals(source.getClassName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique id is prepended with prefix: @see com.intellij.execution.junit.TestUniqueId#getUniqueIdPresentation()
|
||||
* Method contains ','
|
||||
*/
|
||||
private static DiscoverySelector createSelector(String line, String[] packageNameRef) {
|
||||
if (line.startsWith("\u001B")) {
|
||||
String uniqueId = line.substring("\u001B".length());
|
||||
return DiscoverySelectors.selectUniqueId(uniqueId);
|
||||
}
|
||||
else if (line.startsWith("\u002B")) {
|
||||
String directory = line.substring("\u002B".length());
|
||||
List<ClasspathRootSelector> selectors = DiscoverySelectors.selectClasspathRoots(Collections.singleton(Paths.get(directory)));
|
||||
if (selectors.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return selectors.iterator().next();
|
||||
}
|
||||
}
|
||||
else if (line.contains(",")) {
|
||||
MethodSelector selector = DiscoverySelectors.selectMethod(line.replaceFirst(",", "#"));
|
||||
if (packageNameRef != null) {
|
||||
packageNameRef[0] = selector.getClassName();
|
||||
}
|
||||
return selector;
|
||||
}
|
||||
else {
|
||||
if (packageNameRef != null) {
|
||||
packageNameRef[0] = line;
|
||||
}
|
||||
|
||||
return createClassSelector(line);
|
||||
}
|
||||
}
|
||||
|
||||
private static DiscoverySelector createClassSelector(String line) {
|
||||
int nestedClassIdx = line.lastIndexOf("$");
|
||||
if (nestedClassIdx > 0) {
|
||||
AtomicReference<DiscoverySelector> nestedClassSelector = new AtomicReference<>();
|
||||
ReflectionSupport.tryToLoadClass(line).ifFailure(__ -> {
|
||||
nestedClassSelector.set(getNestedSelector(line, nestedClassIdx));
|
||||
});
|
||||
if (nestedClassSelector.get() != null) return nestedClassSelector.get();
|
||||
}
|
||||
return DiscoverySelectors.selectClass(line);
|
||||
}
|
||||
|
||||
private static DiscoverySelector createMethodSelectIteration(DiscoverySelector methodSelector, String param) {
|
||||
Integer index = null;
|
||||
if (param != null) {
|
||||
Matcher matcher = VALUE_SOURCE_PATTERN.matcher(param);
|
||||
if (matcher.find()) {
|
||||
String group = matcher.group(1);
|
||||
try {
|
||||
index = Integer.parseInt(group);
|
||||
}
|
||||
catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (index != null) {
|
||||
try {
|
||||
return DiscoverySelectors.selectIteration(methodSelector, index);
|
||||
}
|
||||
catch (NoSuchMethodError e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static NestedClassSelector getNestedSelector(String line, int nestedClassIdx) {
|
||||
String enclosingClass = line.substring(0, nestedClassIdx);
|
||||
String nestedClassName = line.substring(nestedClassIdx + 1);
|
||||
DiscoverySelector enclosingClassSelector = createClassSelector(enclosingClass);
|
||||
Class<?> klass = isNestedClassSelector(enclosingClassSelector)
|
||||
? ((NestedClassSelector)enclosingClassSelector).getNestedClass()
|
||||
: ((ClassSelector)enclosingClassSelector).getJavaClass();
|
||||
Class<?> superclass = klass.getSuperclass();
|
||||
while (superclass != null) {
|
||||
for (Class<?> nested : superclass.getDeclaredClasses()) {
|
||||
if (nested.getSimpleName().equals(nestedClassName)) {
|
||||
List<Class<?>> enclosingClasses;
|
||||
if (isNestedClassSelector(enclosingClassSelector)) {
|
||||
enclosingClasses = new ArrayList<>(((NestedClassSelector)enclosingClassSelector).getEnclosingClasses());
|
||||
enclosingClasses.add(klass);
|
||||
}
|
||||
else {
|
||||
enclosingClasses = Collections.singletonList(klass);
|
||||
}
|
||||
return DiscoverySelectors.selectNestedClass(enclosingClasses, nested);
|
||||
}
|
||||
}
|
||||
superclass = superclass.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
### auto-generated section `build intellij.junit.v6.rt.tests` start
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library")
|
||||
|
||||
jvm_library(
|
||||
name = "junit-v6-rt-tests_test_lib",
|
||||
module_name = "intellij.junit.v6.rt.tests",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["test/**/*.kt", "test/**/*.java", "test/**/*.form"], allow_empty = True),
|
||||
deps = [
|
||||
"//java/testFramework",
|
||||
"//java/execution/impl",
|
||||
"//plugins/junit",
|
||||
"//java/java-tests:tests_test_lib",
|
||||
"//aether-dependency-resolver",
|
||||
"//aether-dependency-resolver:aether-dependency-resolver_test_lib",
|
||||
"//java/compiler/openapi:java-compiler",
|
||||
"//platform/analysis-api:analysis",
|
||||
"//platform/core-api:core",
|
||||
"//platform/core-ui",
|
||||
"//platform/editor-ui-api:editor-ui",
|
||||
"//platform/execution-impl",
|
||||
"//jps/model-api:model",
|
||||
"//platform/lang-core",
|
||||
"//platform/projectModel-api:projectModel",
|
||||
"//platform/smRunner",
|
||||
"//platform/smRunner:smRunner_test_lib",
|
||||
"//platform/testFramework",
|
||||
"//platform/testFramework:testFramework_test_lib",
|
||||
"//java/java-runtime:rt",
|
||||
"@lib//:stream_ex",
|
||||
"//platform/platform-util-io:ide-util-io",
|
||||
"//platform/testFramework/junit5",
|
||||
"//platform/testFramework/junit5:junit5_test_lib",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.junit.v6.rt.tests` end
|
||||
|
||||
### auto-generated section `test intellij.junit.v6.rt.tests` start
|
||||
load("@community//build:tests-options.bzl", "jps_test")
|
||||
|
||||
jps_test(
|
||||
name = "junit-v6-rt-tests_test",
|
||||
runtime_deps = [":junit-v6-rt-tests_test_lib"]
|
||||
)
|
||||
### auto-generated section `test intellij.junit.v6.rt.tests` end
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="intellij.java.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.execution.impl" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.junit" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.aetherDependencyResolver" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.compiler" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.analysis" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.editor.ui" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.execution.impl" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jps.model" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.core" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.smRunner" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.rt" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="StreamEx" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.util.io" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,188 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.codeInsight.TestFrameworks;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.JavaParameters;
|
||||
import com.intellij.execution.junit.*;
|
||||
import com.intellij.execution.junit2.info.MethodLocation;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.testIntegration.TestFramework;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class JUnit6AcceptanceTest extends JUnit6CodeInsightTest {
|
||||
|
||||
@Test
|
||||
void testFactoryMethods() {
|
||||
PsiClass aClass = myFixture.addClass(
|
||||
"/** @noinspection ALL*/ class MyTest {@org.junit.jupiter.api.TestFactory java.util.List<org.junit.jupiter.api.DynamicTest> tests() {return null;}}");
|
||||
PsiMethod factoryMethod = aClass.getMethods()[0];
|
||||
assertNotNull(factoryMethod);
|
||||
assertTrue(JUnitUtil.isTestAnnotated(factoryMethod));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultMethodInInterface() {
|
||||
PsiClass aClass = myFixture.addClass("interface MyTest {@org.junit.jupiter.api.Test default void method() {}}");
|
||||
assertTrue(JUnitUtil.isTestClass(aClass, false, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void recognizedInnerClassesWithTestMethods() {
|
||||
PsiClass aClass = myFixture
|
||||
.addClass("import org.junit.jupiter.api.*; /** @noinspection ALL*/ class MyTest {@Nested class NTest { @Test void method() {}}}");
|
||||
assertTrue(JUnitUtil.isTestClass(aClass, false, false));
|
||||
PsiClass innerClass = aClass.getInnerClasses()[0];
|
||||
assertTrue(JUnitUtil.isTestClass(innerClass));
|
||||
assertTrue(JUnitUtil.isTestMethod(MethodLocation.elementInClass(innerClass.getMethods()[0], innerClass)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectStaticMethods() {
|
||||
PsiClass aClass =
|
||||
myFixture.addClass("import org.junit.jupiter.api.*; /** @noinspection ALL*/ class MyTest { @Test static void method() {}}");
|
||||
assertFalse(JUnitUtil.isTestClass(aClass, false, false));
|
||||
assertFalse(JUnitUtil.isTestMethod(MethodLocation.elementInClass(aClass.getMethods()[0], aClass)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectPrivateMethods() {
|
||||
PsiClass aClass =
|
||||
myFixture.addClass("import org.junit.jupiter.api.*; /** @noinspection ALL*/ class MyTest { @Test private void method() {}}");
|
||||
assertFalse(JUnitUtil.isTestClass(aClass, false, false));
|
||||
assertFalse(JUnitUtil.isTestMethod(MethodLocation.elementInClass(aClass.getMethods()[0], aClass)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFrameworkDetection() {
|
||||
PsiClass aClass = myFixture.addClass("/** @noinspection ALL*/ class MyTest {@org.junit.jupiter.api.Test void method() {}}");
|
||||
assertNotNull(aClass);
|
||||
TestFramework framework = TestFrameworks.detectFramework(aClass);
|
||||
assertNotNull(framework, "No test framework detected");
|
||||
assertInstanceOf(JUnit6Framework.class, framework, framework.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFrameworkDetectionWithMixedJunit4Junit6() throws ExecutionException {
|
||||
myFixture.addClass("package org.junit; public @interface Test {}");
|
||||
PsiClass aClass = myFixture.addClass("/** @noinspection ALL*/ public class MyTest {@org.junit.jupiter.api.Test void method() {} @org.junit.Test void method2(){} }");
|
||||
assertNotNull(aClass);
|
||||
TestFramework framework = TestFrameworks.detectFramework(aClass);
|
||||
assertInstanceOf(JUnit4Framework.class, framework, framework.getName());
|
||||
JUnitConfiguration configuration = new JUnitConfiguration("", myFixture.getProject());
|
||||
configuration.beClassConfiguration(aClass);
|
||||
JavaParameters parameters = configuration.getTestObject().createJavaParameters4Tests();
|
||||
assertTrue(parameters.getProgramParametersList().hasParameter("-junit6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClassWithDisabledCondition() throws ExecutionException {
|
||||
myFixture.addClass("package org.junit.jupiter.api; public @interface Disabled {}");
|
||||
PsiClass aClass = myFixture.addClass(
|
||||
"""
|
||||
/** @noinspection ALL*/
|
||||
@org.junit.jupiter.api.Disabled
|
||||
public class MyTest {@org.junit.jupiter.api.Test void method() {}}""");
|
||||
assertNotNull(aClass);
|
||||
TestFramework framework = TestFrameworks.detectFramework(aClass);
|
||||
assertInstanceOf(JUnit6Framework.class, framework, framework.getName());
|
||||
JUnitConfiguration configuration = new JUnitConfiguration("", myFixture.getProject());
|
||||
configuration.beClassConfiguration(aClass);
|
||||
JavaParameters parameters = configuration.getTestObject().createJavaParameters4Tests();
|
||||
assertTrue(parameters.getVMParametersList().hasParameter("-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMetaDisabledClass() throws ExecutionException {
|
||||
myFixture.addClass("""
|
||||
package org.test.sample;
|
||||
@org.junit.jupiter.api.Disabled
|
||||
public @interface MetaDisabled {}""");
|
||||
PsiClass aClass = myFixture.addClass(
|
||||
"""
|
||||
/** @noinspection ALL*/
|
||||
@org.test.sample.MetaDisabled
|
||||
public class MyTest {@org.junit.jupiter.api.Test void method() {}}""");
|
||||
assertNotNull(aClass);
|
||||
TestFramework framework = TestFrameworks.detectFramework(aClass);
|
||||
assertInstanceOf(JUnit6Framework.class, framework, framework.getName());
|
||||
JUnitConfiguration configuration = new JUnitConfiguration("", myFixture.getProject());
|
||||
configuration.beClassConfiguration(aClass);
|
||||
JavaParameters parameters = configuration.getTestObject().createJavaParameters4Tests();
|
||||
assertTrue(parameters.getVMParametersList().hasParameter("-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithDisabledCondition() throws ExecutionException {
|
||||
PsiClass aClass = myFixture.addClass(
|
||||
"""
|
||||
/** @noinspection ALL*/
|
||||
public class MyTest {
|
||||
@org.junit.jupiter.api.Disabled
|
||||
@org.junit.jupiter.api.Test void method() {}}""");
|
||||
assertNotNull(aClass);
|
||||
TestFramework framework = TestFrameworks.detectFramework(aClass);
|
||||
assertInstanceOf(JUnit6Framework.class, framework, framework.getName());
|
||||
JUnitConfiguration configuration = new JUnitConfiguration("", myFixture.getProject());
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent") PsiMethod method = Arrays.stream(aClass.getMethods()).findFirst().get();
|
||||
configuration.beMethodConfiguration(MethodLocation.elementInClass(method, aClass));
|
||||
JavaParameters parameters = configuration.getTestObject().createJavaParameters4Tests();
|
||||
assertTrue(parameters.getVMParametersList().hasParameter("-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodPresentations() {
|
||||
myFixture.addClass("package a; public class TestInfo {}");
|
||||
PsiClass aClass = myFixture.addClass("/** @noinspection ALL*/ class MyTest<T extends a.TestInfo> {" +
|
||||
" @org.junit.jupiter.api.Test void method() {}" +
|
||||
" @org.junit.jupiter.api.Test void method(a.TestInfo info) {}" +
|
||||
" @org.junit.jupiter.api.Test void method(T info) {}" +
|
||||
" @org.junit.Test void method1() {}" +
|
||||
" @org.junit.Test void method1(a.TestInfo info) {}" +
|
||||
"}");
|
||||
assertNotNull(aClass);
|
||||
|
||||
Stream<String> expectedData = Arrays.stream(new String[]{"method", "method(a.TestInfo)", "method(a.TestInfo)", "method1", "method1"});
|
||||
StreamEx.of(aClass.getMethods())
|
||||
.zipWith(expectedData)
|
||||
.forEach(e -> assertEquals(e.getValue(), JUnitConfiguration.Data.getMethodPresentation(e.getKey())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void metaAnnotations() {
|
||||
myFixture.addClass("""
|
||||
package a;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@org.junit.jupiter.api.Test
|
||||
@interface MyTest {}""");
|
||||
PsiClass aClass = myFixture.addClass("""
|
||||
class ATest {
|
||||
@a.MyTest
|
||||
void foo() {}
|
||||
}
|
||||
""");
|
||||
assertTrue(JUnitUtil.isTestClass(aClass, false, false));
|
||||
assertTrue(JUnitUtil.isTestMethod(MethodLocation.elementInClass(aClass.getMethods()[0], aClass)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customEngineOnly() {
|
||||
PsiClass customEngineTest = myFixture.addClass("import org.junit.platform.commons.annotation.Testable;" +
|
||||
" /** @noinspection ALL*/ " +
|
||||
"@Testable\n" +
|
||||
"class MyTests{}");
|
||||
assertTrue(JUnitUtil.isTestClass(customEngineTest));
|
||||
|
||||
PsiClass customEngineAnnotationOnSuper = myFixture.addClass("class MyCustomClass extends MyTests{}");
|
||||
assertTrue(JUnitUtil.isTestClass(customEngineAnnotationOnSuper));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.fixtures.*;
|
||||
import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
|
||||
import com.intellij.testFramework.junit5.RunInEdt;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
@RunInEdt(writeIntent = true)
|
||||
public abstract class JUnit6CodeInsightTest {
|
||||
protected JavaCodeInsightTestFixture myFixture;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||
TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder = factory.createLightFixtureBuilder(
|
||||
new DefaultLightProjectDescriptor(IdeaTestUtil::getMockJdk21), "JUnit6CodeInsightTest"
|
||||
);
|
||||
final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture();
|
||||
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture, new LightTempDirTestFixtureImpl(true));
|
||||
myFixture.setUp();
|
||||
|
||||
//init junit 6 framework
|
||||
myFixture.addClass("package org.junit.platform.commons.annotation; public @interface Testable {}");
|
||||
myFixture.addClass("package org.junit.jupiter.api; public interface MethodOrderer { class Default implements MethodOrderer {} }");
|
||||
myFixture.addClass("package org.junit.jupiter.api; @org.junit.platform.commons.annotation.Testable public @interface Test {}");
|
||||
myFixture.addClass("package org.junit.jupiter.api; public @interface Nested {}");
|
||||
myFixture.addClass("package org.junit.jupiter.api; @org.junit.platform.commons.annotation.Testable public @interface TestFactory {}");
|
||||
myFixture.addClass("package org.junit.jupiter.params.provider; public @interface MethodSource {}");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
myFixture.tearDown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
public interface JUnit6Constants {
|
||||
String VERSION = "6.0.0-RC2";
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.junit.JUnitConfiguration;
|
||||
import com.intellij.java.execution.AbstractTestFrameworkCompilingIntegrationTest;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import jetbrains.buildServer.messages.serviceMessages.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
|
||||
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.junit6.ServiceMessageUtil.replaceAttributes;
|
||||
|
||||
@SuppressWarnings("SSBasedInspection")
|
||||
public class JUnit6EventsTest extends AbstractTestFrameworkCompilingIntegrationTest {
|
||||
@Override
|
||||
protected String getTestContentRoot() {
|
||||
return VfsUtilCore.pathToUrl(PlatformTestUtil.getCommunityPath() + "/plugins/junit6_rt_tests/testData/integration/events");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupModule() throws Exception {
|
||||
super.setupModule();
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> model.addContentEntry(getTestContentRoot())
|
||||
.addSourceFolder(getTestContentRoot() + "/test", true));
|
||||
final ArtifactRepositoryManager repoManager = getRepoManager();
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", JUnit6Constants.VERSION),
|
||||
repoManager);
|
||||
}
|
||||
|
||||
public void testMultipleFailures() throws Exception {
|
||||
ProcessOutput output = doStartTestsProcess(createRunMethodConfiguration("com.intellij.junit6.testData.MyTestClass", "test1"));
|
||||
assertEmpty(output.err);
|
||||
|
||||
List<ServiceMessage> messages = output.messages;
|
||||
|
||||
Map<String, TestStarted> tests = getStartedTests(messages);
|
||||
// Ensure our test method started with a proper location hint
|
||||
TestStarted started = tests.values().stream()
|
||||
.filter(t -> "java:test://com.intellij.junit6.testData.MyTestClass/test1".equals(t.getAttributes().get("locationHint")))
|
||||
.findFirst().orElse(null);
|
||||
assertNotNull(started);
|
||||
assertEquals("java:test://com.intellij.junit6.testData.MyTestClass/test1", started.getAttributes().get("locationHint"));
|
||||
String nodeId = started.getAttributes().get("nodeId");
|
||||
|
||||
// There should be multiple failures reported for the same test
|
||||
List<ServiceMessage> failed = messages.stream()
|
||||
.filter(m -> nodeId.equals(m.getAttributes().get("nodeId")))
|
||||
.filter(m -> m instanceof TestFailed).toList();
|
||||
assertSize(3, failed);
|
||||
|
||||
Set<String> errors = failed.stream().filter(m -> m.getAttributes().get("expected") != null)
|
||||
.map(m -> "expected='" + m.getAttributes().get("expected") + "', actual='" + m.getAttributes().get("actual") + "'")
|
||||
.collect(Collectors.toSet());
|
||||
assertEquals(Set.of(
|
||||
"expected='expected1', actual='actual1'",
|
||||
"expected='expected2', actual='actual2'"
|
||||
), errors);
|
||||
|
||||
// StdOut message should include our published entries
|
||||
Set<String> outs = messages.stream()
|
||||
.filter(m -> nodeId.equals(m.getAttributes().get("nodeId")))
|
||||
.filter(m -> m instanceof TestStdOut)
|
||||
.map(m -> m.getAttributes().get("out"))
|
||||
.map(s -> s.replaceAll("timestamp = [0-9\\-:.T]+", "timestamp = ##timestamp##"))
|
||||
.collect(Collectors.toSet());
|
||||
assertEquals(Set.of("timestamp = ##timestamp##, key1 = value1, stdout = out1\n"), outs);
|
||||
}
|
||||
|
||||
public void testContainerFailure() throws Exception {
|
||||
ProcessOutput output = doStartTestsProcess(createRunMethodConfiguration("com.intellij.junit6.testData.MyTestClass", "brokenStream"));
|
||||
assertEmpty(output.err);
|
||||
|
||||
// Expect a configuration failure
|
||||
List<String> test = output.messages.stream().filter(BaseTestMessage.class::isInstance)
|
||||
.map(BaseTestMessage.class::cast)
|
||||
.filter(m -> m.getTestName().equals("Class Configuration"))
|
||||
.map(m -> replaceAttributes(m, Map.of("details", "##details##")))
|
||||
.toList();
|
||||
assertEquals(List.of(
|
||||
"##teamcity[testStarted name='Class Configuration' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' parentNodeId='0']",
|
||||
"##teamcity[testFailed name='Class Configuration' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' parentNodeId='0' error='true' message='java.lang.IllegalStateException: broken' details='##details##']",
|
||||
"##teamcity[testFinished name='Class Configuration' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' parentNodeId='0']"
|
||||
), test);
|
||||
}
|
||||
|
||||
public void testContainerDisabled() throws Exception {
|
||||
ProcessOutput output = doStartTestsProcess(createRunClassConfiguration("com.intellij.junit6.testData.MyTestClass"));
|
||||
assertEmpty(output.err);
|
||||
|
||||
List<String> tests = output.messages.stream().filter(m -> m instanceof BaseTestMessage)
|
||||
.map(m -> replaceAttributes(m, Map.of(
|
||||
"timestamp", "##timestamp##",
|
||||
"duration", "##duration##",
|
||||
"message", "##message##",
|
||||
"details", "##details##"
|
||||
)))
|
||||
.map(s -> s.replaceAll("timestamp = [0-9\\-:.T]+", "timestamp = ##timestamp##")).toList();
|
||||
|
||||
assertEquals(List.of(
|
||||
"##teamcity[testStarted id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:disabledTest()|]' name='disabledTest()' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:disabledTest()|]' parentNodeId='0' locationHint='java:test://com.intellij.junit6.testData.MyTestClass/disabledTest' metainfo='']",
|
||||
"##teamcity[testIgnored name='disabledTest()' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:disabledTest()|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:disabledTest()|]' parentNodeId='0' message='##message##']",
|
||||
"##teamcity[testFinished id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:disabledTest()|]' name='disabledTest()' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:disabledTest()|]' parentNodeId='0']",
|
||||
"##teamcity[testStarted id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' name='test1(TestReporter)' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' parentNodeId='0' locationHint='java:test://com.intellij.junit6.testData.MyTestClass/test1' metainfo='org.junit.jupiter.api.TestReporter']",
|
||||
"##teamcity[testStdOut id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' name='test1(TestReporter)' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' parentNodeId='0' out='timestamp = ##timestamp##, key1 = value1, stdout = out1|n']",
|
||||
"##teamcity[testFailed name='test1(TestReporter)' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' parentNodeId='0' duration='##duration##' message='##message##' expected='expected1' actual='actual1' details='##details##']",
|
||||
"##teamcity[testFailed name='test1(TestReporter)' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' parentNodeId='0' duration='##duration##' message='##message##' expected='expected2' actual='actual2' details='##details##']",
|
||||
"##teamcity[testFailed name='test1(TestReporter)' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' parentNodeId='0' duration='##duration##' message='##message##' details='##details##']",
|
||||
"##teamcity[testFinished id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' name='test1(TestReporter)' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[method:test1(org.junit.jupiter.api.TestReporter)|]' parentNodeId='0' duration='##duration##']",
|
||||
"##teamcity[testIgnored name='brokenStreamDisabled()' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStreamDisabled()|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStreamDisabled()|]' parentNodeId='0' message='##message##']",
|
||||
"##teamcity[testStarted name='Class Configuration' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' parentNodeId='0']",
|
||||
"##teamcity[testFailed name='Class Configuration' id='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' parentNodeId='0' error='true' message='##message##' details='##details##']",
|
||||
"##teamcity[testFinished name='Class Configuration' nodeId='|[engine:junit-jupiter|]/|[class:com.intellij.junit6.testData.MyTestClass|]/|[test-factory:brokenStream()|]' parentNodeId='0']"
|
||||
), tests);
|
||||
}
|
||||
|
||||
public void testEscaping() throws Exception {
|
||||
ProcessOutput output = doStartTestsProcess(createRunMethodConfiguration("com.intellij.junit6.testData.AnnotationsTestClass", "test1"));
|
||||
assertEmpty(output.err);
|
||||
|
||||
Map<String, TestStarted> tests = getStartedTests(output.messages);
|
||||
TestStarted started = tests.values().stream()
|
||||
.filter(t -> t.getAttributes().get("locationHint").equals("java:test://com.intellij.junit6.testData.AnnotationsTestClass/test1"))
|
||||
.findFirst().orElse(null);
|
||||
assertNotNull(started);
|
||||
// TeamCity service messages encode names internally; here we ensure the original display name is preserved
|
||||
assertEquals("test's method", started.getAttributes().get("name"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RunConfiguration createRunMethodConfiguration(final String className, final String methodName) {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.projectScope(myProject));
|
||||
assertNotNull(aClass);
|
||||
PsiMethod method = aClass.findMethodsByName(methodName, false)[0];
|
||||
RunConfiguration configuration = createConfiguration(method);
|
||||
assertInstanceOf(configuration, JUnitConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RunConfiguration createRunClassConfiguration(final String className) {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.projectScope(myProject));
|
||||
assertNotNull(aClass);
|
||||
RunConfiguration configuration = createConfiguration(aClass);
|
||||
assertInstanceOf(configuration, JUnitConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private static Map<String, TestStarted> getStartedTests(List<ServiceMessage> messages) {
|
||||
return messages.stream().filter(TestStarted.class::isInstance).map(TestStarted.class::cast)
|
||||
.collect(Collectors.toMap(t -> t.getAttributes().get("id"), t -> t));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.testIntegration.BaseGenerateTestSupportMethodAction;
|
||||
import com.intellij.testIntegration.TestIntegrationUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class JUnit6GenerationTest extends JUnit6CodeInsightTest {
|
||||
@Test
|
||||
void testMethodInTopLevelClass() {
|
||||
doTest("import org.junit.jupiter.api.Test; class MyTest {<caret> @Test void m2(){}}",
|
||||
"""
|
||||
import org.junit.jupiter.api.Test; class MyTest {
|
||||
@Test
|
||||
void name() {
|
||||
\s
|
||||
}
|
||||
|
||||
@Test void m2(){}}""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMethodInNestedClass() {
|
||||
doTest("import org.junit.jupiter.api.Nested; class MyTest { @Nested class NTest { <caret>}}",
|
||||
"""
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MyTest { @Nested class NTest {
|
||||
@Test
|
||||
void name() {
|
||||
\s
|
||||
}
|
||||
}}""");
|
||||
}
|
||||
|
||||
private void doTest(String text, String expected) {
|
||||
myFixture.configureByText("MyTest.java", text);
|
||||
|
||||
new BaseGenerateTestSupportMethodAction.MyHandler(TestIntegrationUtils.MethodKind.TEST)
|
||||
.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile());
|
||||
myFixture.checkResult(expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.execution.junit.JUnitConfiguration;
|
||||
import com.intellij.java.execution.AbstractTestFrameworkCompilingIntegrationTest;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
|
||||
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JUnit6NamingTest extends AbstractTestFrameworkCompilingIntegrationTest {
|
||||
@Override
|
||||
protected String getTestContentRoot() {
|
||||
return VfsUtilCore.pathToUrl(PlatformTestUtil.getCommunityPath() + "/plugins/junit6_rt_tests/testData/integration/naming");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupModule() throws Exception {
|
||||
super.setupModule();
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> model.addContentEntry(getTestContentRoot())
|
||||
.addSourceFolder(getTestContentRoot() + "/test", true));
|
||||
final ArtifactRepositoryManager repoManager = getRepoManager();
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", JUnit6Constants.VERSION), repoManager);
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.platform", "junit-platform-suite-api", JUnit6Constants.VERSION), repoManager);
|
||||
}
|
||||
|
||||
public void testArrayParameters() {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass("MyTest", GlobalSearchScope.projectScope(myProject));
|
||||
assertNotNull(aClass);
|
||||
PsiJavaFile file = (PsiJavaFile)aClass.getContainingFile();
|
||||
String[] methodPresentations =
|
||||
Arrays.stream(file.getClasses()[0].getMethods())
|
||||
.map(method -> JUnitConfiguration.Data.getMethodPresentation(method))
|
||||
.toArray(String[]::new);
|
||||
Assertions.assertArrayEquals(new String[]{"foo(int[])",
|
||||
"foo(int)",
|
||||
"foo([Ljava.lang.String;)",
|
||||
"foo(java.lang.String)",
|
||||
"foo([LMyTest$Foo;)",
|
||||
"foo(MyTest$Foo)"},
|
||||
methodPresentations,
|
||||
Arrays.toString(methodPresentations));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.junit.JUnitConfiguration;
|
||||
import com.intellij.java.execution.AbstractTestFrameworkCompilingIntegrationTest;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
|
||||
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.junit6.ServiceMessageUtil.replaceAttributes;
|
||||
|
||||
@DisplayName("junit 6 navigation features: location strings, etc")
|
||||
public class JUnit6NavigationTest extends AbstractTestFrameworkCompilingIntegrationTest {
|
||||
@Override
|
||||
protected String getTestContentRoot() {
|
||||
return VfsUtilCore.pathToUrl(PlatformTestUtil.getCommunityPath() + "/plugins/junit6_rt_tests/testData/integration/navigation");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupModule() throws Exception {
|
||||
super.setupModule();
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> model.addContentEntry(getTestContentRoot())
|
||||
.addSourceFolder(getTestContentRoot() + "/test", true));
|
||||
final ArtifactRepositoryManager repoManager = getRepoManager();
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", JUnit6Constants.VERSION), repoManager);
|
||||
}
|
||||
|
||||
public void testNavigation() throws Exception {
|
||||
ProcessOutput output = doStartTestsProcess(createRunClassConfiguration("org.example.impl.NavTest"));
|
||||
assertEmpty(output.err);
|
||||
|
||||
List<String> messages = output.messages.stream().filter(m -> m.getAttributes().containsKey("locationHint"))
|
||||
.map(m -> m.getAttributes().get("locationHint").startsWith("file://")
|
||||
? replaceAttributes(m, Map.of("locationHint", "file://##path##"))
|
||||
: m.asString())
|
||||
.toList();
|
||||
|
||||
assertEquals(List.of(
|
||||
"##teamcity[suiteTreeStarted id='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]' name='fileSourceDynamicTests()' nodeId='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]' parentNodeId='0' locationHint='java:test://org.example.impl.NavTest/fileSourceDynamicTests' metainfo='']",
|
||||
"##teamcity[suiteTreeNode id='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[method:methodNavigation()|]' name='methodNavigation()' nodeId='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[method:methodNavigation()|]' parentNodeId='0' locationHint='java:test://org.example.impl.NavTest/methodNavigation' metainfo='']",
|
||||
"##teamcity[testSuiteStarted id='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]' name='fileSourceDynamicTests()' nodeId='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]' parentNodeId='0' locationHint='java:test://org.example.impl.NavTest/fileSourceDynamicTests' metainfo='']",
|
||||
"##teamcity[testStarted id='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]/|[dynamic-test:#1|]' name='fileSource' nodeId='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]/|[dynamic-test:#1|]' parentNodeId='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[test-factory:fileSourceDynamicTests()|]' locationHint='file://##path##']",
|
||||
"##teamcity[testStarted id='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[method:methodNavigation()|]' name='methodNavigation()' nodeId='|[engine:junit-jupiter|]/|[class:org.example.impl.NavTest|]/|[method:methodNavigation()|]' parentNodeId='0' locationHint='java:test://org.example.impl.NavTest/methodNavigation' metainfo='']"
|
||||
), messages);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RunConfiguration createRunClassConfiguration(final String className) {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.projectScope(myProject));
|
||||
assertNotNull(aClass);
|
||||
|
||||
RunConfiguration configuration = createConfiguration(aClass);
|
||||
assertInstanceOf(configuration, JUnitConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.junit.JUnitConfiguration;
|
||||
import com.intellij.java.execution.AbstractTestFrameworkCompilingIntegrationTest;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import jetbrains.buildServer.messages.serviceMessages.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
|
||||
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JUnit6OldSuiteApiIntegrationTest extends AbstractTestFrameworkCompilingIntegrationTest {
|
||||
@Override
|
||||
protected String getTestContentRoot() {
|
||||
return VfsUtilCore.pathToUrl(PlatformTestUtil.getCommunityPath() + "/plugins/junit6_rt_tests/testData/integration/oldSuiteApi");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupModule() throws Exception {
|
||||
super.setupModule();
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> model.addContentEntry(getTestContentRoot())
|
||||
.addSourceFolder(getTestContentRoot() + "/test", true));
|
||||
final ArtifactRepositoryManager repoManager = getRepoManager();
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", JUnit6Constants.VERSION), repoManager);
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.platform", "junit-platform-suite-api", JUnit6Constants.VERSION),
|
||||
repoManager);
|
||||
}
|
||||
|
||||
public void testRunClass() throws Exception {
|
||||
ProcessOutput processOutput = doStartTestsProcess(createRunClassConfiguration("org.example.impl.MyTest"));
|
||||
assertEmpty(processOutput.out);
|
||||
assertEmpty(processOutput.err);
|
||||
|
||||
List<ServiceMessage> messages = processOutput.messages;
|
||||
|
||||
Map<String, TestStarted> tests = getStartedTests(messages);
|
||||
assertEquals(Set.of("java:test://org.example.impl.MyTest/test"),
|
||||
tests.values().stream().map(t -> t.getAttributes().get("locationHint")).collect(Collectors.toSet()));
|
||||
assertEquals(Set.of(), getTestIds(messages, TestFailed.class));
|
||||
assertEquals(tests.keySet(), getTestIds(messages, TestFinished.class));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RunConfiguration createRunClassConfiguration(final String className) {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.projectScope(myProject));
|
||||
assertNotNull(aClass);
|
||||
|
||||
RunConfiguration configuration = createConfiguration(aClass);
|
||||
assertInstanceOf(configuration, JUnitConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
||||
private static Map<String, TestStarted> getStartedTests(List<ServiceMessage> messages) {
|
||||
return messages.stream().filter(TestStarted.class::isInstance).map(TestStarted.class::cast)
|
||||
.collect(Collectors.toMap(t -> t.getAttributes().get("id"), t -> t));
|
||||
}
|
||||
|
||||
|
||||
private static <T extends BaseTestMessage> Set<String> getTestIds(List<ServiceMessage> messages, Class<T> clazz) {
|
||||
return messages.stream().filter(clazz::isInstance).map(clazz::cast).map(o -> o.getAttributes().get("id")).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.junit.JUnitConfiguration;
|
||||
import com.intellij.java.execution.AbstractTestFrameworkCompilingIntegrationTest;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import jetbrains.buildServer.messages.serviceMessages.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
|
||||
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JUnit6SuiteApiIntegrationTest extends AbstractTestFrameworkCompilingIntegrationTest {
|
||||
@Override
|
||||
protected String getTestContentRoot() {
|
||||
return VfsUtilCore.pathToUrl(PlatformTestUtil.getCommunityPath() + "/plugins/junit6_rt_tests/testData/integration/suiteApi");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupModule() throws Exception {
|
||||
super.setupModule();
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> model.addContentEntry(getTestContentRoot())
|
||||
.addSourceFolder(getTestContentRoot() + "/test", true));
|
||||
final ArtifactRepositoryManager repoManager = getRepoManager();
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.jupiter", "junit-jupiter-api", JUnit6Constants.VERSION), repoManager);
|
||||
addMavenLibs(myModule, new JpsMavenRepositoryLibraryDescriptor("org.junit.platform", "junit-platform-suite-api", JUnit6Constants.VERSION), repoManager);
|
||||
}
|
||||
|
||||
public void testRunClass() throws Exception {
|
||||
ProcessOutput processOutput = doStartTestsProcess(createRunClassConfiguration("org.example.api.SmokeSuite"));
|
||||
assertEmpty(processOutput.out);
|
||||
assertEmpty(processOutput.err);
|
||||
|
||||
List<ServiceMessage> messages = processOutput.messages;
|
||||
|
||||
Map<String, TestStarted> tests = getStartedTests(messages);
|
||||
assertEquals(Set.of("java:test://org.example.impl.MyTest/test"),
|
||||
tests.values().stream().map(t -> t.getAttributes().get("locationHint")).collect(Collectors.toSet()));
|
||||
assertEquals(Set.of(), getTestIds(messages, TestFailed.class));
|
||||
assertEquals(tests.keySet(), getTestIds(messages, TestFinished.class));
|
||||
}
|
||||
|
||||
public void testRunPackage() throws Exception {
|
||||
ProcessOutput processOutput = doStartTestsProcess(createRunPackageConfiguration("org.example.api"));
|
||||
assertEmpty(processOutput.out);
|
||||
assertEmpty(processOutput.err);
|
||||
|
||||
List<ServiceMessage> messages = processOutput.messages;
|
||||
|
||||
Map<String, TestStarted> tests = getStartedTests(messages);
|
||||
assertEquals(Set.of("java:test://org.example.impl.MyTest/test",
|
||||
"java:test://org.example.impl.FirstTest/test1",
|
||||
"java:test://org.example.impl.FirstTest/test2",
|
||||
"java:test://org.example.impl.SecondTest/test1",
|
||||
"java:test://org.example.impl.SecondTest/test2"),
|
||||
tests.values().stream().map(t -> t.getAttributes().get("locationHint")).collect(Collectors.toSet()));
|
||||
assertEquals(getTestIds(tests, Set.of("java:test://org.example.impl.FirstTest/test1",
|
||||
"java:test://org.example.impl.SecondTest/test2")),
|
||||
getTestIds(messages, TestFailed.class));
|
||||
assertEquals(tests.keySet(), getTestIds(messages, TestFinished.class));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RunConfiguration createRunClassConfiguration(final String className) {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.projectScope(myProject));
|
||||
assertNotNull(aClass);
|
||||
|
||||
RunConfiguration configuration = createConfiguration(aClass);
|
||||
assertInstanceOf(configuration, JUnitConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private RunConfiguration createRunPackageConfiguration(final String packageName) {
|
||||
PsiPackage aPackage = JavaPsiFacade.getInstance(myProject).findPackage(packageName);
|
||||
assertNotNull(aPackage);
|
||||
|
||||
RunConfiguration configuration = createConfiguration(aPackage);
|
||||
assertInstanceOf(configuration, JUnitConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private static Map<String, TestStarted> getStartedTests(List<ServiceMessage> messages) {
|
||||
return messages.stream().filter(TestStarted.class::isInstance).map(TestStarted.class::cast)
|
||||
.collect(Collectors.toMap(t -> t.getAttributes().get("id"), t -> t));
|
||||
}
|
||||
|
||||
private static <T extends BaseTestMessage> Set<String> getTestIds(Map<String, TestStarted> tests, Set<String> locationHints) {
|
||||
return tests.entrySet().stream()
|
||||
.filter(e -> locationHints.contains(e.getValue().getAttributes().get("locationHint")))
|
||||
.map(t -> t.getKey())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static <T extends BaseTestMessage> Set<String> getTestIds(List<ServiceMessage> messages, Class<T> clazz) {
|
||||
return messages.stream().filter(clazz::isInstance).map(clazz::cast).map(o -> o.getAttributes().get("id")).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public void testRerunFailedFromSuite() throws Exception {
|
||||
ProcessOutput initialOutput = doStartTestsProcess(createRunPackageConfiguration("org.example.api"));
|
||||
assertEmpty(initialOutput.out);
|
||||
assertEmpty(initialOutput.err);
|
||||
|
||||
List<ServiceMessage> initialMessages = initialOutput.messages;
|
||||
Map<String, TestStarted> started = getStartedTests(initialMessages);
|
||||
Set<String> failedIds = getTestIds(initialMessages, TestFailed.class);
|
||||
|
||||
Set<String> failedHints = failedIds.stream()
|
||||
.map(id -> started.get(id))
|
||||
.map(t -> t.getAttributes().get("locationHint"))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
assertEquals(Set.of(
|
||||
"java:test://org.example.impl.FirstTest/test1",
|
||||
"java:test://org.example.impl.SecondTest/test2"
|
||||
), failedHints);
|
||||
|
||||
ProcessOutput rerunOutput = doStartTestsProcess(createRunPackageConfiguration("org.example.api"), failedHints);
|
||||
assertEmpty(rerunOutput.out);
|
||||
assertEmpty(rerunOutput.err);
|
||||
|
||||
Map<String, TestStarted> rerunStarted = getStartedTests(rerunOutput.messages);
|
||||
Set<String> rerunHints = rerunStarted.values().stream().map(t -> t.getAttributes().get("locationHint")).collect(Collectors.toSet());
|
||||
|
||||
assertEquals(failedHints, rerunHints);
|
||||
assertEquals(rerunStarted.keySet(), getTestIds(rerunOutput.messages, TestFinished.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6;
|
||||
|
||||
import jetbrains.buildServer.messages.serviceMessages.ServiceMessage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class ServiceMessageUtil {
|
||||
public static @NotNull String replaceAttributes(@NotNull ServiceMessage message, @NotNull Map<String, String> attributes) {
|
||||
Map<String, String> attrs = new LinkedHashMap<>(message.getAttributes());
|
||||
for (Map.Entry<String, String> entry : attributes.entrySet()) {
|
||||
if (attrs.containsKey(entry.getKey())) {
|
||||
attrs.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return ServiceMessage.asString(message.getMessageName(), attrs);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6.testData;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AnnotationsTestClass {
|
||||
@Test
|
||||
@DisplayName("test's method")
|
||||
void test1() {}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.junit6.testData;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
import org.junit.jupiter.api.TestReporter;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
|
||||
public class MyTestClass {
|
||||
@Test
|
||||
void test1(TestReporter reporter) {
|
||||
Map<String, String> map = new LinkedHashMap<String, String>();
|
||||
map.put("key1", "value1");
|
||||
map.put("stdout", "out1");
|
||||
reporter.publishEntry(map);
|
||||
Assertions.assertAll("2 errors",
|
||||
() -> Assertions.assertEquals("expected1", "actual1", "message1"),
|
||||
() -> Assertions.assertEquals("expected2", "actual2", "message2")
|
||||
);
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
Stream<DynamicTest> brokenStream() {
|
||||
throw new IllegalStateException("broken");
|
||||
}
|
||||
|
||||
@org.junit.jupiter.api.Disabled("container disabled")
|
||||
@TestFactory
|
||||
Stream<DynamicTest> brokenStreamDisabled() {
|
||||
return Stream.of();
|
||||
}
|
||||
|
||||
@org.junit.jupiter.api.Disabled("disabled")
|
||||
@Test
|
||||
void disabledTest() {}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MyTest {
|
||||
@Test void foo(int[] i) {}
|
||||
@Test void foo(int i) {}
|
||||
@Test void foo(String[] i) {}
|
||||
@Test void foo(String i) {}
|
||||
@Test void foo(Foo[] i) {}
|
||||
@Test void foo(Foo i) {}
|
||||
|
||||
static class Foo {}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.example.impl;
|
||||
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
|
||||
public class NavTest {
|
||||
@Test
|
||||
void methodNavigation() {}
|
||||
|
||||
@TestFactory
|
||||
Collection<DynamicTest> fileSourceDynamicTests() {
|
||||
List<DynamicTest> list = new ArrayList<>();
|
||||
try {
|
||||
// Create a temporary file to force FileSource in JUnit Platform
|
||||
URI uri = Files.createTempFile("navtest", ".txt").toUri();
|
||||
list.add(dynamicTest("fileSource", uri, () -> {}));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
+10
@@ -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.
|
||||
package org.example.impl;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MyTest {
|
||||
@Test
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.example.api;
|
||||
|
||||
import org.example.impl.FirstTest;
|
||||
import org.example.impl.SecondTest;
|
||||
import org.junit.platform.suite.api.SelectClasses;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
|
||||
@Suite
|
||||
@SelectClasses({FirstTest.class, SecondTest.class})
|
||||
public class AllTests {
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.example.api;
|
||||
|
||||
import org.example.impl.MyTest;
|
||||
import org.junit.platform.suite.api.SelectClasses;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
|
||||
@Suite
|
||||
@SelectClasses({MyTest.class})
|
||||
public class SmokeSuite {
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.example.impl;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class FirstTest {
|
||||
@Test
|
||||
public void test1() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
}
|
||||
}
|
||||
+10
@@ -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.
|
||||
package org.example.impl;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MyTest {
|
||||
@Test
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.example.impl;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SecondTest {
|
||||
@Test
|
||||
public void test1() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -14,7 +15,6 @@ import java.util.List;
|
||||
/**
|
||||
* Before rename or move
|
||||
*
|
||||
* @noinspection HardCodedStringLiteral
|
||||
* @see com.intellij.execution.junit.JUnitConfiguration#JUNIT_START_CLASS
|
||||
*/
|
||||
public final class JUnitStarter {
|
||||
@@ -24,12 +24,14 @@ public final class JUnitStarter {
|
||||
public static final String JUNIT3_PARAMETER = "-junit3";
|
||||
public static final String JUNIT4_PARAMETER = "-junit4";
|
||||
public static final String JUNIT5_PARAMETER = "-junit5";
|
||||
public static final String JUNIT6_PARAMETER = "-junit6";
|
||||
private static final String JUNIT5_KEY = "idea.is.junit5";
|
||||
|
||||
private static final String SOCKET = "-socket";
|
||||
private static final String JUNIT3_RUNNER_NAME = "com.intellij.junit3.JUnit3IdeaTestRunner";
|
||||
private static final String JUNIT4_RUNNER_NAME = "com.intellij.junit4.JUnit4IdeaTestRunner";
|
||||
private static final String JUNIT5_RUNNER_NAME = "com.intellij.junit5.JUnit5IdeaTestRunner";
|
||||
private static final String JUNIT6_RUNNER_NAME = "com.intellij.junit6.JUnit6IdeaTestRunner";
|
||||
private static String ourForkMode;
|
||||
private static String ourCommandFileName;
|
||||
private static String ourWorkingDirs;
|
||||
@@ -44,13 +46,14 @@ public final class JUnitStarter {
|
||||
|
||||
String agentName = processParameters(argList, listeners, name);
|
||||
|
||||
if (!JUNIT5_RUNNER_NAME.equals(agentName) && !canWorkWithJUnitVersion(System.err, agentName)) {
|
||||
if (!Arrays.asList(JUNIT5_RUNNER_NAME, JUNIT6_RUNNER_NAME).contains(agentName) && !canWorkWithJUnitVersion(System.err, agentName)) {
|
||||
System.exit(-3);
|
||||
}
|
||||
if (!checkVersion(args, System.err)) {
|
||||
System.exit(-3);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SSBasedInspection")
|
||||
String[] array = argList.toArray(new String[0]);
|
||||
int exitCode = prepareStreamsAndStart(array, agentName, listeners, name[0]);
|
||||
System.exit(exitCode);
|
||||
@@ -72,6 +75,9 @@ public final class JUnitStarter {
|
||||
else if (arg.equals(JUNIT5_PARAMETER)) {
|
||||
agentName = JUNIT5_RUNNER_NAME;
|
||||
}
|
||||
else if (arg.equals(JUNIT6_PARAMETER)) {
|
||||
agentName = JUNIT6_RUNNER_NAME;
|
||||
}
|
||||
else {
|
||||
if (arg.startsWith("@name")) {
|
||||
params[0] = arg.substring("@name".length());
|
||||
@@ -243,7 +249,7 @@ public final class JUnitStarter {
|
||||
public static void printClassesList(List<String> classNames, String packageName, String category, String filters, File tempFile)
|
||||
throws IOException {
|
||||
|
||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tempFile), StandardCharsets.UTF_8))) {
|
||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(tempFile.toPath()), StandardCharsets.UTF_8))) {
|
||||
writer.println(packageName); //package name
|
||||
writer.println(category); //category
|
||||
writer.println(filters); //patterns
|
||||
|
||||
+2
-2
@@ -20,12 +20,12 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
|
||||
abstract class AbstractKotlinPsiBasedTestFramework : KotlinPsiBasedTestFramework {
|
||||
protected abstract val markerClassFqn: String
|
||||
protected abstract val markerClassFqns: Collection<String>
|
||||
protected abstract val disabledTestAnnotation: String
|
||||
protected abstract val allowTestMethodsInObject: Boolean
|
||||
|
||||
protected open fun isFrameworkAvailable(element: KtElement): Boolean =
|
||||
isFrameworkAvailable(element, markerClassFqn, true)
|
||||
markerClassFqns.any { isFrameworkAvailable(element, it, true) }
|
||||
|
||||
protected fun isFrameworkAvailable(element: KtElement, markerClassFqn: String, javaOnly: Boolean): Boolean {
|
||||
val module = element.module ?: return false
|
||||
|
||||
+4
-4
@@ -39,10 +39,10 @@ interface KotlinPsiBasedTestFramework {
|
||||
fun findTearDown(classOrObject: KtClassOrObject): KtNamedFunction? = null
|
||||
|
||||
companion object {
|
||||
const val KOTLIN_TEST_TEST = "kotlin.test.Test"
|
||||
const val KOTLIN_TEST_IGNORE = "kotlin.test.Ignore"
|
||||
const val KOTLIN_TEST_BEFORE_TEST = "kotlin.test.BeforeTest"
|
||||
const val KOTLIN_TEST_AFTER_TEST = "kotlin.test.AfterTest"
|
||||
const val KOTLIN_TEST_TEST: String = "kotlin.test.Test"
|
||||
const val KOTLIN_TEST_IGNORE: String = "kotlin.test.Ignore"
|
||||
const val KOTLIN_TEST_BEFORE_TEST: String = "kotlin.test.BeforeTest"
|
||||
const val KOTLIN_TEST_AFTER_TEST: String = "kotlin.test.AfterTest"
|
||||
|
||||
fun PsiElement?.asKtClassOrObject(): KtClassOrObject? =
|
||||
when (this) {
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
order="before junit4"/>
|
||||
<testFramework implementation="org.jetbrains.kotlin.idea.junit.KotlinJUnit5Framework"
|
||||
order="before junit5"/>
|
||||
<testFramework implementation="org.jetbrains.kotlin.idea.junit.KotlinJUnit6Framework"
|
||||
order="before junit6"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin.idea">
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@ import org.jetbrains.kotlin.psi.psiUtil.isPrivate
|
||||
|
||||
class KotlinJUnit3Framework: JUnit3Framework(), KotlinPsiBasedTestFramework {
|
||||
private val psiBasedDelegate = object : AbstractKotlinPsiBasedTestFramework() {
|
||||
override val markerClassFqn: String
|
||||
get() = JUnitUtil.TEST_CASE_CLASS
|
||||
override val markerClassFqns: Collection<String>
|
||||
get() = listOf(JUnitUtil.TEST_CASE_CLASS)
|
||||
|
||||
override val disabledTestAnnotation: String
|
||||
get() = throw UnsupportedOperationException("JUnit3 does not support Ignore methods")
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isPrivate
|
||||
|
||||
class KotlinJUnit4Framework: JUnit4Framework(), KotlinPsiBasedTestFramework {
|
||||
private val psiBasedDelegate = object : AbstractKotlinPsiBasedTestFramework() {
|
||||
override val markerClassFqn: String = JUnitUtil.TEST_ANNOTATION
|
||||
override val markerClassFqns: Collection<String> = listOf(JUnitUtil.TEST_ANNOTATION)
|
||||
override val disabledTestAnnotation: String = "org.junit.Ignore"
|
||||
override val allowTestMethodsInObject: Boolean = false
|
||||
|
||||
|
||||
+6
-6
@@ -28,8 +28,8 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
class KotlinJUnit5Framework: JUnit5Framework(), KotlinPsiBasedTestFramework {
|
||||
private val psiBasedDelegate = object : AbstractKotlinPsiBasedTestFramework() {
|
||||
|
||||
override val markerClassFqn: String = JUnitUtil.TEST5_ANNOTATION
|
||||
override val disabledTestAnnotation: String = "org.junit.jupiter.api.Disabled"
|
||||
override val markerClassFqns: Collection<String> = markerClassFQNames
|
||||
override val disabledTestAnnotation: String = JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_DISABLED
|
||||
override val allowTestMethodsInObject: Boolean = true
|
||||
|
||||
override fun checkTestClass(declaration: KtClassOrObject): ThreeState {
|
||||
@@ -83,7 +83,7 @@ class KotlinJUnit5Framework: JUnit5Framework(), KotlinPsiBasedTestFramework {
|
||||
NO
|
||||
} else if (declaration is KtClass && declaration.isInner()) {
|
||||
if (isAnnotated(declaration, JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_NESTED)) YES else NO
|
||||
} else if (declaration.isTopLevel() && isAnnotated(declaration, "org.junit.jupiter.api.extension.ExtendWith")) {
|
||||
} else if (declaration.isTopLevel() && isAnnotated(declaration, JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_EXTENSION_EXTEND_WITH)) {
|
||||
YES
|
||||
} else if (findAnnotatedFunction(declaration, testableAnnotations) != null) {
|
||||
YES
|
||||
@@ -188,9 +188,9 @@ class KotlinJUnit5Framework: JUnit5Framework(), KotlinPsiBasedTestFramework {
|
||||
private val METHOD_ANNOTATION_FQN = setOf(
|
||||
JUnitUtil.TEST5_ANNOTATION,
|
||||
KotlinPsiBasedTestFramework.KOTLIN_TEST_TEST,
|
||||
"org.junit.jupiter.params.ParameterizedTest",
|
||||
"org.junit.jupiter.api.RepeatedTest",
|
||||
"org.junit.jupiter.api.TestFactory",
|
||||
JUnitCommonClassNames.ORG_JUNIT_JUPITER_PARAMS_PARAMETERIZED_TEST,
|
||||
JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_REPEATED_TEST,
|
||||
JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_TEST_FACTORY,
|
||||
"org.junit.jupiter.api.TestTemplate",
|
||||
"org.junitpioneer.jupiter.RetryingTest"
|
||||
)
|
||||
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.junit
|
||||
|
||||
import com.intellij.execution.junit.JUnit6Framework
|
||||
import com.intellij.execution.junit.JUnitUtil
|
||||
import com.intellij.ide.fileTemplates.FileTemplateDescriptor
|
||||
import com.intellij.java.analysis.OuterModelsModificationTrackerManager
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.intellij.util.ThreeState
|
||||
import com.intellij.util.ThreeState.*
|
||||
import com.siyeh.ig.junit.JUnitCommonClassNames
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import org.jetbrains.kotlin.idea.testIntegration.framework.AbstractKotlinPsiBasedTestFramework
|
||||
import org.jetbrains.kotlin.idea.testIntegration.framework.KotlinPsiBasedTestFramework
|
||||
import org.jetbrains.kotlin.idea.testIntegration.framework.KotlinPsiBasedTestFramework.Companion.asKtClassOrObject
|
||||
import org.jetbrains.kotlin.idea.testIntegration.framework.KotlinPsiBasedTestFramework.Companion.asKtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
|
||||
class KotlinJUnit6Framework: JUnit6Framework(), KotlinPsiBasedTestFramework {
|
||||
private val psiBasedDelegate = object : AbstractKotlinPsiBasedTestFramework() {
|
||||
|
||||
override val markerClassFqns: Collection<String> = markerClassFQNames
|
||||
override val disabledTestAnnotation: String = JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_DISABLED
|
||||
override val allowTestMethodsInObject: Boolean = true
|
||||
|
||||
override fun checkTestClass(declaration: KtClassOrObject): ThreeState {
|
||||
val checkState = super.checkTestClass(declaration)
|
||||
if (checkState != UNSURE) return checkState
|
||||
return CachedValuesManager.getCachedValue(declaration) {
|
||||
CachedValueProvider.Result.create(
|
||||
checkJUnit6TestClass(declaration),
|
||||
OuterModelsModificationTrackerManager.getTracker(declaration.project)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun isPotentialTestClass(element: PsiElement): Boolean {
|
||||
if (element.language != KotlinLanguage.INSTANCE) return false
|
||||
val psiElement = (element as? KtLightElement<*, *>)?.kotlinOrigin ?: element
|
||||
val ktClassOrObject = psiElement.parentOfType<KtClassOrObject>(true) ?: return false
|
||||
|
||||
return CachedValuesManager.getCachedValue(ktClassOrObject) {
|
||||
CachedValueProvider.Result.create(
|
||||
checkJUnit6PotentialTestClass(ktClassOrObject) != NO,
|
||||
OuterModelsModificationTrackerManager.getTracker(ktClassOrObject.project)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isTestMethod(declaration: KtNamedFunction): Boolean {
|
||||
if (!super.isTestMethod(declaration)) return false
|
||||
if (declaration.annotationEntries.isEmpty()) return false
|
||||
return isJUnit6TestMethod(declaration)
|
||||
}
|
||||
|
||||
private fun checkJUnit6TestClass(declaration: KtClassOrObject): ThreeState =
|
||||
if (!isFrameworkAvailable(declaration)) {
|
||||
NO
|
||||
} else {
|
||||
checkIsJUnit6LikeTestClass(declaration, false)
|
||||
}
|
||||
|
||||
private fun checkJUnit6PotentialTestClass(declaration: KtClassOrObject): ThreeState =
|
||||
if (!isFrameworkAvailable(declaration) && !isFrameworkAvailable(declaration, KotlinPsiBasedTestFramework.KOTLIN_TEST_TEST, false)) {
|
||||
NO
|
||||
} else {
|
||||
checkIsJUnit6LikeTestClass(declaration, true)
|
||||
}
|
||||
|
||||
private fun checkIsJUnit6LikeTestClass(declaration: KtClassOrObject, isPotential: Boolean): ThreeState =
|
||||
if (isPotential) {
|
||||
if (isUnderTestSources(declaration)) UNSURE else NO
|
||||
} else if (!isFrameworkAvailable(declaration)) {
|
||||
NO
|
||||
} else if (declaration is KtClass && declaration.isInner()) {
|
||||
if (isAnnotated(declaration, JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_NESTED)) YES else NO
|
||||
} else if (declaration.isTopLevel() && isAnnotated(declaration, JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_EXTENSION_EXTEND_WITH)) {
|
||||
YES
|
||||
} else if (findAnnotatedFunction(declaration, testableAnnotations) != null) {
|
||||
YES
|
||||
} else {
|
||||
UNSURE
|
||||
}
|
||||
|
||||
private fun isJUnit6TestMethod(method: KtNamedFunction): Boolean {
|
||||
return isAnnotated(method, METHOD_ANNOTATION_FQN)
|
||||
}
|
||||
|
||||
override fun findSetUp(classOrObject: KtClassOrObject): KtNamedFunction? =
|
||||
findAnnotatedFunction(classOrObject.takeIf { isTestClass(it) }, setUpAnnotations)
|
||||
|
||||
override fun findTearDown(classOrObject: KtClassOrObject): KtNamedFunction? =
|
||||
findAnnotatedFunction(classOrObject.takeIf { isTestClass(it) }, tearDownAnnotations)
|
||||
|
||||
}
|
||||
|
||||
override fun responsibleFor(declaration: KtNamedDeclaration): Boolean =
|
||||
psiBasedDelegate.responsibleFor(declaration)
|
||||
|
||||
override fun checkTestClass(declaration: KtClassOrObject): ThreeState = psiBasedDelegate.checkTestClass(declaration)
|
||||
|
||||
override fun isTestClass(clazz: PsiElement): Boolean =
|
||||
when (val checkTestClass = checkTestClass(clazz)) {
|
||||
UNSURE -> super.isTestClass(clazz)
|
||||
else -> checkTestClass == YES
|
||||
}
|
||||
|
||||
override fun isPotentialTestClass(clazz: PsiElement): Boolean =
|
||||
isTestClass(clazz) || psiBasedDelegate.isPotentialTestClass(clazz)
|
||||
|
||||
override fun findSetUpMethod(clazz: PsiElement): PsiElement? =
|
||||
when (checkTestClass(clazz)) {
|
||||
UNSURE -> super.findSetUpMethod(clazz)
|
||||
NO -> null
|
||||
else -> clazz.asKtClassOrObject()?.let(psiBasedDelegate::findSetUp)
|
||||
}
|
||||
|
||||
override fun findTearDownMethod(clazz: PsiElement): PsiElement? =
|
||||
when (checkTestClass(clazz)) {
|
||||
UNSURE -> super.findTearDownMethod(clazz)
|
||||
NO -> null
|
||||
else -> clazz.asKtClassOrObject()?.let(psiBasedDelegate::findTearDown)
|
||||
}
|
||||
|
||||
override fun isIgnoredMethod(element: PsiElement?): Boolean =
|
||||
when (checkTestClass(element)) {
|
||||
UNSURE -> super.isIgnoredMethod(element)
|
||||
NO -> false
|
||||
else -> element.asKtNamedFunction()?.let(psiBasedDelegate::isIgnoredMethod) ?: false
|
||||
}
|
||||
|
||||
override fun isTestMethod(element: PsiElement?): Boolean =
|
||||
when (checkTestClass(element)) {
|
||||
UNSURE -> super.isTestMethod(element)
|
||||
NO -> false
|
||||
else -> element.asKtNamedFunction()?.let(psiBasedDelegate::isTestMethod) ?: false
|
||||
}
|
||||
|
||||
override fun getLanguage(): Language = KotlinLanguage.INSTANCE
|
||||
|
||||
override fun isTestMethod(declaration: KtNamedFunction): Boolean =
|
||||
psiBasedDelegate.isTestMethod(declaration)
|
||||
|
||||
override fun isIgnoredMethod(declaration: KtNamedFunction): Boolean =
|
||||
psiBasedDelegate.isIgnoredMethod(declaration)
|
||||
|
||||
override fun getSetUpMethodFileTemplateDescriptor(): FileTemplateDescriptor? {
|
||||
return if (KotlinPluginModeProvider.isK1Mode()) {
|
||||
super.getSetUpMethodFileTemplateDescriptor()
|
||||
} else {
|
||||
FileTemplateDescriptor("Kotlin JUnit5 SetUp Function.kt")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTearDownMethodFileTemplateDescriptor(): FileTemplateDescriptor? {
|
||||
return if (KotlinPluginModeProvider.isK1Mode()) {
|
||||
super.getTearDownMethodFileTemplateDescriptor()
|
||||
} else {
|
||||
FileTemplateDescriptor("Kotlin JUnit5 TearDown Function.kt")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTestMethodFileTemplateDescriptor(): FileTemplateDescriptor {
|
||||
return if (KotlinPluginModeProvider.isK1Mode()) {
|
||||
super.getTestMethodFileTemplateDescriptor()
|
||||
} else {
|
||||
FileTemplateDescriptor("Kotlin JUnit5 Test Function.kt")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTestClassFileTemplateDescriptor(): FileTemplateDescriptor? =
|
||||
if (KotlinPluginModeProvider.isK1Mode()) {
|
||||
super.getTestClassFileTemplateDescriptor()
|
||||
} else {
|
||||
FileTemplateDescriptor("Kotlin JUnit5 Test Class.kt")
|
||||
}
|
||||
}
|
||||
|
||||
private val METHOD_ANNOTATION_FQN = setOf(
|
||||
JUnitUtil.TEST5_ANNOTATION,
|
||||
KotlinPsiBasedTestFramework.KOTLIN_TEST_TEST,
|
||||
JUnitCommonClassNames.ORG_JUNIT_JUPITER_PARAMS_PARAMETERIZED_TEST,
|
||||
JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_REPEATED_TEST,
|
||||
JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_TEST_FACTORY,
|
||||
"org.junit.jupiter.api.TestTemplate",
|
||||
"org.junitpioneer.jupiter.RetryingTest"
|
||||
)
|
||||
|
||||
private val setUpAnnotations = setOf(JUnitUtil.BEFORE_EACH_ANNOTATION_NAME, KotlinPsiBasedTestFramework.KOTLIN_TEST_BEFORE_TEST)
|
||||
private val tearDownAnnotations = setOf(JUnitUtil.AFTER_EACH_ANNOTATION_NAME, KotlinPsiBasedTestFramework.KOTLIN_TEST_AFTER_TEST)
|
||||
private val testableAnnotations = METHOD_ANNOTATION_FQN + setUpAnnotations + tearDownAnnotations
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinTestNGFramework: TestNGFramework(), KotlinPsiBasedTestFramework {
|
||||
private val psiBasedDelegate = object : AbstractKotlinPsiBasedTestFramework() {
|
||||
override val markerClassFqn: String = TestNGUtil.TEST_ANNOTATION_FQN
|
||||
override val markerClassFqns: Collection<String> = listOf(TestNGUtil.TEST_ANNOTATION_FQN)
|
||||
override val disabledTestAnnotation: String
|
||||
get() = throw UnsupportedOperationException("TestNG does not support Ignore methods")
|
||||
override val allowTestMethodsInObject: Boolean = false
|
||||
|
||||
Reference in New Issue
Block a user