diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java
index 02010166786f..53035b8ef25f 100644
--- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java
+++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java
@@ -33,7 +33,6 @@ import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.*;
import com.intellij.testIntegration.JavaTestFramework;
import com.intellij.testIntegration.TestFramework;
-import com.intellij.util.ArrayUtil;
import com.siyeh.ig.psiutils.TestUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -98,7 +97,21 @@ public class JUnitUtil {
@NonNls public static final String PARAMETERIZED_CLASS_NAME = "org.junit.runners.Parameterized";
@NonNls public static final String SUITE_CLASS_NAME = "org.junit.runners.Suite";
public static final String JUNIT5_NESTED = "org.junit.jupiter.api.Nested";
- private static final String[] KNOWN_RUNNERS = {"org.junit.runners.Parameterized", "org.junit.runners.BlockJUnit4ClassRunner", "org.junit.runners.JUnit4"};
+ private static final String[] RUNNERS_UNAWARE_OF_INNER_CLASSES = {
+ "org.junit.runners.Parameterized",
+ "org.junit.runners.BlockJUnit4ClassRunner",
+ "org.junit.runners.JUnit4",
+ "org.junit.internal.runners.JUnit38ClassRunner",
+ "org.junit.internal.runners.JUnit4ClassRunner",
+ "org.junit.runners.Suite"
+ };
+
+ private static final String[] RUNNERS_REQUIRE_ANNOTATION_ON_TEST_METHOD = {
+ "org.junit.runners.Parameterized",
+ "org.junit.runners.BlockJUnit4ClassRunner",
+ "org.junit.runners.JUnit4",
+ "org.junit.internal.runners.JUnit4ClassRunner"
+ };
public static boolean isSuiteMethod(@NotNull PsiMethod psiMethod) {
if (!psiMethod.hasModifierProperty(PsiModifier.PUBLIC)) return false;
@@ -136,7 +149,7 @@ public class JUnitUtil {
if (checkClass && checkRunWith) {
PsiAnnotation annotation = getRunWithAnnotation(aClass);
if (annotation != null) {
- return !isRunnerWithRequiredAnnotationOnTestMethod(annotation, KNOWN_RUNNERS);
+ return !isInheritorOrSelfRunner(annotation, RUNNERS_REQUIRE_ANNOTATION_ON_TEST_METHOD);
}
}
if (psiMethod.getParameterList().getParametersCount() > 0) return false;
@@ -225,7 +238,7 @@ public class JUnitUtil {
}
//default runners do not implicitly run inner classes
- if (annotation != null && !isRunnerWithRequiredAnnotationOnTestMethod(annotation, KNOWN_RUNNERS)) {
+ if (annotation != null && !isInheritorOrSelfRunner(annotation, RUNNERS_UNAWARE_OF_INNER_CLASSES)) {
return true;
}
}
@@ -427,15 +440,15 @@ public class JUnitUtil {
}
public static boolean isParameterized(PsiAnnotation annotation) {
- return isRunnerWithRequiredAnnotationOnTestMethod(annotation,"org.junit.runners.Parameterized");
+ return isInheritorOrSelfRunner(annotation, "org.junit.runners.Parameterized");
}
- private static boolean isRunnerWithRequiredAnnotationOnTestMethod(PsiAnnotation annotation, String... runners) {
+ public static boolean isInheritorOrSelfRunner(PsiAnnotation annotation, String... runners) {
final PsiAnnotationMemberValue value = annotation.findAttributeValue(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
if (value instanceof PsiClassObjectAccessExpression) {
final PsiTypeElement operand = ((PsiClassObjectAccessExpression)value).getOperand();
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(operand.getType());
- return psiClass != null && ArrayUtil.find(runners, psiClass.getQualifiedName()) > -1;
+ return psiClass != null && Arrays.stream(runners).anyMatch(runner -> InheritanceUtil.isInheritor(psiClass, runner));
}
return false;
}
diff --git a/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java b/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java
index 02467f532e10..e7309ac8fb2b 100644
--- a/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java
+++ b/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java
@@ -158,6 +158,13 @@ public abstract class JavaTestFramework implements TestFramework {
return false;
}
+ /**
+ * @return true for junit 3 classes with suite method and for junit 4 tests with @Suite annotation
+ */
+ public boolean isSuiteClass(PsiClass psiClass) {
+ return false;
+ }
+
public boolean isTestMethod(PsiMethod method, PsiClass myClass) {
return isTestMethod(method);
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
index 8c2d394f38d8..1619a6c16835 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
@@ -1651,7 +1651,8 @@
level="WARNING" implementationClass="com.siyeh.ig.naming.NewClassNamingConventionInspection"/>
-
+
+
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
index 5a68187bfc72..706dfa0f9eb8 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
@@ -793,6 +793,7 @@ public.field.accessed.in.synchronized.context.display.name=Non-private field acc
string.replaceable.by.string.buffer.display.name=Non-constant String should be StringBuilder
junit.test.class.naming.convention.display.name=JUnit test class naming convention
junit.test.class.naming.convention.element.description=Test
+junit.test.suite.naming.convention.element.description=Test suite
method.coupling.display.name=Overly coupled method
collections.must.have.initial.capacity.display.name=Collection without initial capacity
anonymous.inner.class.display.name=Anonymous inner class
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestClassNamingConvention.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestClassNamingConvention.java
index 270600302313..6be2c4bae6d9 100644
--- a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestClassNamingConvention.java
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestClassNamingConvention.java
@@ -19,6 +19,8 @@ import com.intellij.codeInsight.TestFrameworks;
import com.intellij.codeInspection.naming.NamingConvention;
import com.intellij.codeInspection.naming.NamingConventionBean;
import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiTypeParameter;
+import com.intellij.testIntegration.JavaTestFramework;
import com.intellij.testIntegration.TestFramework;
import com.siyeh.InspectionGadgetsBundle;
@@ -35,8 +37,9 @@ public class TestClassNamingConvention extends NamingConvention {
@Override
public boolean isApplicable(PsiClass member) {
+ if (member instanceof PsiTypeParameter) return false;
TestFramework framework = TestFrameworks.detectFramework(member);
- return framework != null && framework.isTestClass(member);
+ return framework instanceof JavaTestFramework && framework.isTestClass(member) && !((JavaTestFramework)framework).isSuiteClass(member);
}
@Override
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestSuiteNamingConvention.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestSuiteNamingConvention.java
new file mode 100644
index 000000000000..17e946ceac33
--- /dev/null
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestSuiteNamingConvention.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.codeInsight.TestFrameworks;
+import com.intellij.codeInspection.naming.NamingConvention;
+import com.intellij.codeInspection.naming.NamingConventionBean;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiTypeParameter;
+import com.intellij.testIntegration.JavaTestFramework;
+import com.intellij.testIntegration.TestFramework;
+import com.siyeh.InspectionGadgetsBundle;
+
+public class TestSuiteNamingConvention extends NamingConvention {
+
+ private static final int DEFAULT_MIN_LENGTH = 8;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+ public static final String TEST_SUITE_NAMING_CONVENTION_SHORT_NAME = "TestSuiteNamingConvention";
+
+ @Override
+ public NamingConventionBean createDefaultBean() {
+ return new NamingConventionBean("[A-Z][A-Za-z\\d]*Suite", DEFAULT_MIN_LENGTH, DEFAULT_MAX_LENGTH);
+ }
+
+ @Override
+ public boolean isApplicable(PsiClass member) {
+ if (member instanceof PsiTypeParameter) return false;
+ TestFramework framework = TestFrameworks.detectFramework(member);
+ return framework instanceof JavaTestFramework && framework.isTestClass(member) && ((JavaTestFramework)framework).isSuiteClass(member);
+ }
+
+ @Override
+ public String getShortName() {
+ return TEST_SUITE_NAMING_CONVENTION_SHORT_NAME;
+ }
+
+ @Override
+ public String getElementDescription() {
+ return InspectionGadgetsBundle.message("junit.test.suite.naming.convention.element.description");
+ }
+}
\ No newline at end of file
diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnit3Framework.java b/plugins/junit/src/com/intellij/execution/junit/JUnit3Framework.java
index 3b978dd141e1..f98681ce94a5 100644
--- a/plugins/junit/src/com/intellij/execution/junit/JUnit3Framework.java
+++ b/plugins/junit/src/com/intellij/execution/junit/JUnit3Framework.java
@@ -50,6 +50,11 @@ public class JUnit3Framework extends JavaTestFramework {
return true;
}
+ @Override
+ public boolean isSuiteClass(PsiClass psiClass) {
+ return JUnitUtil.findSuiteMethod(psiClass) != null;
+ }
+
@Override
public boolean isTestMethod(PsiMethod method, PsiClass myClass) {
return JUnitUtil.isTestMethod(MethodLocation.elementInClass(method, myClass));
diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java b/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java
index 35fb61f25e07..666d4068a156 100644
--- a/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java
+++ b/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java
@@ -173,6 +173,12 @@ public class JUnit4Framework extends JavaTestFramework {
return new FileTemplateDescriptor("JUnit4 Test Class.java");
}
+ @Override
+ public boolean isSuiteClass(PsiClass psiClass) {
+ PsiAnnotation annotation = JUnitUtil.getRunWithAnnotation(psiClass);
+ return annotation != null && JUnitUtil.isInheritorOrSelfRunner(annotation, "org.junit.runners.Suite");
+ }
+
@Override
public boolean isParameterized(PsiClass clazz) {
PsiAnnotation annotation = JUnitUtil.getRunWithAnnotation(clazz);