junit 5 inspection to warn about @RunWith(JUnitPlatform.class) without test methods (IDEA-160253)

This commit is contained in:
Anna Kozlova
2017-03-29 20:24:33 +02:00
parent ca122bda9e
commit 62bf50b8d1
6 changed files with 173 additions and 1 deletions
@@ -91,6 +91,10 @@ public abstract class LightInspectionTestCase extends LightCodeInsightFixtureTes
}
protected final void doTest(@Language("JAVA") @NotNull String classText) {
doTest(classText, "X.java");
}
protected final void doTest(@Language("JAVA") @NotNull String classText, String fileName) {
final StringBuilder newText = new StringBuilder();
int start = 0;
int end = classText.indexOf("/*");
@@ -121,7 +125,7 @@ public abstract class LightInspectionTestCase extends LightCodeInsightFixtureTes
end = classText.indexOf("/*", end + 1);
}
newText.append(classText, start, classText.length());
myFixture.configureByText("X.java", newText.toString());
myFixture.configureByText(fileName, newText.toString());
myFixture.testHighlighting(true, false, false);
}
@@ -2806,6 +2806,10 @@
key="junit5.converter.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.junit.JUnit5ConverterInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="JUnit5Platform" bundle="com.siyeh.InspectionGadgetsBundle"
key="junit5.platform.runner.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="true" level="WARNING"
implementationClass="com.siyeh.ig.junit.JUnit5PlatformInspection"/>
</extensions>
</idea-plugin>
@@ -2210,4 +2210,5 @@ string.concatenation.introduce.fix=Introduce StringBuilder
string.concatenation.introduce.fix.name=Introduce new {1} to update variable ''{0}''
ignored.class.names=Ignore classes (including subclasses)
junit5.platform.runner.display.name=@RunWith(JUnitPlatform.class) without test methods
@@ -0,0 +1,70 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.junit;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiClassUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public class JUnit5PlatformInspection extends BaseInspection {
@Nls
@NotNull
@Override
public String getDisplayName() {
return InspectionGadgetsBundle.message("junit5.platform.runner.display.name");
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
return (String)infos[0];
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new BaseInspectionVisitor() {
@Override
public void visitClass(PsiClass aClass) {
PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
if (nameIdentifier != null && PsiClassUtil.isRunnableClass(aClass, true, false)) {
PsiAnnotation annotation = AnnotationUtil.findAnnotation(aClass, "org.junit.runner.RunWith");
if (annotation != null) {
final PsiAnnotationMemberValue value = annotation.findAttributeValue(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
if (value instanceof PsiClassObjectAccessExpression) {
final PsiTypeElement operand = ((PsiClassObjectAccessExpression)value).getOperand();
final PsiClass runnerClass = PsiUtil.resolveClassInClassTypeOnly(operand.getType());
if (runnerClass != null && "org.junit.platform.runner.JUnitPlatform".equals(runnerClass.getQualifiedName()) &&
Arrays.stream(aClass.getMethods()).noneMatch(method -> method.hasModifierProperty(PsiModifier.PUBLIC) &&
method.getParameterList().getParametersCount() == 0 &&
AnnotationUtil.isAnnotated(method, "org.junit.Test", false))) {
registerError(nameIdentifier, "Class #ref annotated @RunWith(JUnitPlatform.class) lacks test methods");
}
}
}
}
}
};
}
}
@@ -0,0 +1,9 @@
<html>
<body>
Reports classes annotated with @RunWith(JUnitPlatform.class) which provide no test methods. These classes won't start tests because
org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder.DefensiveAnnotatedBuilder prevents recursion and
org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder.DefensiveJUnit4Builder expects test methods
<!-- tooltip end -->
<p>
</body>
</html>
@@ -0,0 +1,84 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.junit;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
public class JUnit5PlatformInspectionTest extends LightInspectionTestCase {
public void testNoMethods() {
doTest("import org.junit.Test;\n" +
"import org.junit.platform.runner.JUnitPlatform;\n" +
"import org.junit.runner.RunWith;\n" +
"@RunWith(JUnitPlatform.class)\n" +
"public class /*Class NoMethodsTest annotated @RunWith(JUnitPlatform.class) lacks test methods*/NoMethodsTest/**/ {}", "NoMethodsTest.java");
}
public void testNoPublicMethods() {
doTest("import org.junit.Test;\n" +
"import org.junit.platform.runner.JUnitPlatform;\n" +
"import org.junit.runner.RunWith;\n" +
"@RunWith(JUnitPlatform.class)\n" +
"public class /*Class NoPublicMethodsTest annotated @RunWith(JUnitPlatform.class) lacks test methods*/NoPublicMethodsTest/**/ {\n" +
" @Test\n" +
" void name() throws Exception {\n" +
" System.out.println(\"Hello world\");\n" +
" }\n" +
"}", "NoPublicMethodsTest.java");
}
public void testNoNoParamMethods() {
doTest("import org.junit.Test;\n" +
"import org.junit.platform.runner.JUnitPlatform;\n" +
"import org.junit.runner.RunWith;\n" +
"@RunWith(JUnitPlatform.class)\n" +
"public class /*Class NoNoParamMethodsTest annotated @RunWith(JUnitPlatform.class) lacks test methods*/NoNoParamMethodsTest/**/ {\n" +
" @Test\n" +
" public void name(int i) throws Exception {\n" +
" System.out.println(\"Hello world\");\n" +
" }\n" +
"}", "NoNoParamMethodsTest.java");
}
public void testWithRunnableMethods() {
doTest("import org.junit.Test;\n" +
"import org.junit.platform.runner.JUnitPlatform;\n" +
"import org.junit.runner.RunWith;\n" +
"@RunWith(JUnitPlatform.class)\n" +
"public class WithRunnableMethodsTest {\n" +
" @Test\n" +
" public void name() throws Exception {\n" +
" System.out.println(\"Hello world\");\n" +
" }\n" +
"}", "WithRunnableMethodsTest.java");
}
@Override
protected String[] getEnvironmentClasses() {
return new String[]{
"package org.junit; public @interface Test{}",
"package org.junit.platform.runner; public class JUnitPlatform {}",
"package org.junit.runner; public @interface RunWith{Class value();}"
};
}
@Override
protected InspectionProfileEntry getInspection() {
return new JUnit5PlatformInspection();
}
}