diff options
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit')
10 files changed, 1243 insertions, 0 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java new file mode 100644 index 000000000000..69444ef1431f --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2013 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.psi.*; +import com.intellij.psi.util.PsiFormatUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.TestUtils; +import org.jetbrains.annotations.NotNull; + +public class BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase extends BaseInspection { + @Override + @NotNull + public String getID() { + return "BeforeOrAfterWithIncorrectSignature"; + } + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "before.class.or.after.class.is.public.static.void.no.arg.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "before.class.or.after.class.is.public.static.void.no.arg.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new BeforeClassOrAfterClassIsPublicStaticVoidNoArgVisitor(); + } + + private static class BeforeClassOrAfterClassIsPublicStaticVoidNoArgVisitor + extends BaseInspectionVisitor { + + @Override + public void visitMethod(@NotNull PsiMethod method) { + //note: no call to super; + if (!TestUtils.isJUnit4BeforeClassOrAfterClassMethod(method)) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + final PsiClass targetClass = method.getContainingClass(); + if (targetClass == null) { + return; + } + + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParametersCount() != 0 || + !returnType.equals(PsiType.VOID) || + !method.hasModifierProperty(PsiModifier.PUBLIC) || + !method.hasModifierProperty(PsiModifier.STATIC)) { + registerMethodError(method, "Change signature of \'" + + PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, + PsiFormatUtil.SHOW_NAME | + PsiFormatUtil.SHOW_MODIFIERS | + PsiFormatUtil.SHOW_PARAMETERS | + PsiFormatUtil.SHOW_TYPE, + PsiFormatUtil.SHOW_TYPE) + + "\' to \'public static void " + + method.getName() + + "()\'"); + } + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java new file mode 100644 index 000000000000..c527c7ee951c --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2013 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.PsiClass; +import com.intellij.psi.PsiMethod; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.TestUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +public class JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase extends BaseInspection { + protected static final String IGNORE = "org.junit.Ignore"; + + @Override + @Nls + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message("junit4.test.method.in.class.extending.junit3.testcase.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + if (AnnotationUtil.isAnnotated((PsiMethod)infos[1], IGNORE, false)) { + return InspectionGadgetsBundle.message("ignore.test.method.in.class.extending.junit3.testcase.problem.descriptor"); + } + return InspectionGadgetsBundle.message("junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor"); + } + + @Override + public boolean isEnabledByDefault() { + return true; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new Junit4AnnotatedMethodInJunit3TestCaseVisitor(); + } + + private static class Junit4AnnotatedMethodInJunit3TestCaseVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (!TestUtils.isJUnitTestClass(containingClass)) { + return; + } + if (AnnotationUtil.isAnnotated(method, IGNORE, false) && method.getName().startsWith("test")) { + registerMethodError(method, containingClass, method); + } else if (TestUtils.isJUnit4TestMethod(method)) { + registerMethodError(method, containingClass, method); + } + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java new file mode 100644 index 000000000000..fce2f99b4b10 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java @@ -0,0 +1,115 @@ +/* + * Copyright 2000-2013 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.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.naming.ConventionInspection; +import org.jetbrains.annotations.NotNull; + +public class JUnitAbstractTestClassNamingConventionInspectionBase extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 12; + private static final int DEFAULT_MAX_LENGTH = 64; + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "junit.abstract.test.class.naming.convention.display.name"); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final String className = (String)infos[0]; + if (className.length() < getMinLength()) { + return InspectionGadgetsBundle.message( + "junit.abstract.test.class.naming.convention.problem.descriptor.short"); + } + else if (className.length() > getMaxLength()) { + return InspectionGadgetsBundle.message( + "junit.abstract.test.class.naming.convention.problem.descriptor.long"); + } + return InspectionGadgetsBundle.message( + "junit.abstract.test.class.naming.convention.problem.descriptor.regex.mismatch", + getRegex()); + } + + @Override + protected String getDefaultRegex() { + return "[A-Z][A-Za-z\\d]*TestCase"; + } + + @Override + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + @Override + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new NamingConventionsVisitor(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + + @Override + public void visitElement(PsiElement element) { + if (!(element instanceof PsiClass)) { + super.visitElement(element); + return; + } + + PsiClass aClass = (PsiClass)element; + if (aClass.isInterface() || aClass.isEnum() || + aClass.isAnnotationType()) { + return; + } + if (aClass instanceof PsiTypeParameter) { + return; + } + if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (!InheritanceUtil.isInheritor(aClass, + "junit.framework.TestCase")) { + return; + } + final String name = aClass.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerClassError(aClass, name); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java new file mode 100644 index 000000000000..cbbd14eab21b --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2013 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.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.naming.ConventionInspection; +import com.siyeh.ig.psiutils.TestUtils; +import org.jetbrains.annotations.NotNull; + +public class JUnitTestClassNamingConventionInspectionBase extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 8; + private static final int DEFAULT_MAX_LENGTH = 64; + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "junit.test.class.naming.convention.display.name"); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final String className = (String)infos[0]; + if (className.length() < getMinLength()) { + return InspectionGadgetsBundle.message( + "junit.test.class.naming.convention.problem.descriptor.short"); + } + else if (className.length() > getMaxLength()) { + return InspectionGadgetsBundle.message( + "junit.test.class.naming.convention.problem.descriptor.long"); + } + return InspectionGadgetsBundle.message( + "junit.test.class.naming.convention.problem.descriptor.regex.mismatch", + getRegex()); + } + + @Override + protected String getDefaultRegex() { + return "[A-Z][A-Za-z\\d]*Test"; + } + + @Override + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + @Override + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new NamingConventionsVisitor(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + @Override + public void visitElement(PsiElement element) { + if (!(element instanceof PsiClass)) { + super.visitElement(element); + return; + } + + PsiClass aClass = (PsiClass)element; + if (aClass.isInterface() || aClass.isEnum() || + aClass.isAnnotationType()) { + return; + } + if (aClass instanceof PsiTypeParameter) { + return; + } + if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (!InheritanceUtil.isInheritor(aClass, + "junit.framework.TestCase")) { + if (!hasJUnit4TestMethods(aClass)) { + return; + } + } + final String name = aClass.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerClassError(aClass, name); + } + + private boolean hasJUnit4TestMethods(@NotNull PsiClass aClass) { + //use this if this method turns out to have bad performance: + //if (!TestUtils.isTest(aClass)) { + // return false; + //} + final PsiMethod[] methods = aClass.getMethods(); + for (PsiMethod method : methods) { + if (TestUtils.isJUnit4TestMethod(method)) { + return true; + } + } + return false; + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java new file mode 100644 index 000000000000..af3f874fca3b --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2013 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.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class MisspelledSetUpInspectionBase extends BaseInspection { + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "misspelled.set.up.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "misspelled.set.up.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new MisspelledSetUpVisitor(); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class MisspelledSetUpVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(@NotNull PsiMethod method) { + //note: no call to super + final PsiClass aClass = method.getContainingClass(); + @NonNls final String methodName = method.getName(); + if (!"setup".equals(methodName)) { + return; + } + if (aClass == null) { + return; + } + if (!InheritanceUtil.isInheritor(aClass, + "junit.framework.TestCase")) { + return; + } + registerMethodError(method); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java new file mode 100644 index 000000000000..d6858bff4ec4 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2013 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.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class MisspelledTearDownInspectionBase extends BaseInspection { + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "misspelled.tear.down.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "misspelled.tear.down.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new MisspelledSetUpVisitor(); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class MisspelledSetUpVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(@NotNull PsiMethod method) { + // note: no call to super + @NonNls final String methodName = method.getName(); + if (!"teardown".equals(methodName)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (!InheritanceUtil.isInheritor(aClass, + "junit.framework.TestCase")) { + return; + } + registerMethodError(method); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java new file mode 100644 index 000000000000..b13dbc94ec4d --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java @@ -0,0 +1,129 @@ +/* + * Copyright 2000-2013 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.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ParameterizedParametersStaticCollectionInspectionBase extends BaseInspection { + protected static final String PARAMETERS_FQN = "org.junit.runners.Parameterized.Parameters"; + private static final String PARAMETERIZED_FQN = "org.junit.runners.Parameterized"; + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return infos.length > 0 + ? (String)infos[1] + : "Class #ref annotated @RunWith(Parameterized.class) lacks data provider"; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new BaseInspectionVisitor() { + @Override + public void visitClass(PsiClass aClass) { + final PsiAnnotation annotation = AnnotationUtil.findAnnotation(aClass, "org.junit.runner.RunWith"); + if (annotation != null) { + for (PsiNameValuePair pair : annotation.getParameterList().getAttributes()) { + final PsiAnnotationMemberValue value = pair.getValue(); + if (value instanceof PsiClassObjectAccessExpression) { + final PsiTypeElement typeElement = ((PsiClassObjectAccessExpression)value).getOperand(); + if (typeElement.getType().getCanonicalText().equals(PARAMETERIZED_FQN)) { + List<MethodCandidate> candidates = new ArrayList<MethodCandidate>(); + for (PsiMethod method : aClass.getMethods()) { + PsiType returnType = method.getReturnType(); + final PsiClass returnTypeClass = PsiUtil.resolveClassInType(returnType); + final Project project = aClass.getProject(); + final PsiClass collectionsClass = + JavaPsiFacade.getInstance(project).findClass(Collection.class.getName(), GlobalSearchScope.allScope(project)); + if (AnnotationUtil.isAnnotated(method, PARAMETERS_FQN, false)) { + final PsiModifierList modifierList = method.getModifierList(); + boolean hasToFixSignature = false; + String message = "Make method \'" + method.getName() + "\' "; + String errorString = "Method \'#ref()\' should be "; + if (!modifierList.hasModifierProperty(PsiModifier.PUBLIC)) { + message += PsiModifier.PUBLIC + " "; + errorString += PsiModifier.PUBLIC + " "; + hasToFixSignature = true; + } + if (!modifierList.hasModifierProperty(PsiModifier.STATIC)) { + message += PsiModifier.STATIC; + errorString += PsiModifier.STATIC; + hasToFixSignature = true; + } + if (collectionsClass != null && + (returnTypeClass == null || !InheritanceUtil.isInheritorOrSelf(returnTypeClass, collectionsClass, true))) { + message += (hasToFixSignature ? " and" : "") + " return Collection"; + errorString += (hasToFixSignature ? " and" : "") + " return Collection"; + returnType = JavaPsiFacade.getElementFactory(project).createType(collectionsClass); + hasToFixSignature = true; + } + if (hasToFixSignature) { + candidates.add(new MethodCandidate(method, message, errorString, returnType)); + continue; + } + return; + } + } + if (candidates.isEmpty()) { + registerClassError(aClass); + } + else { + for (MethodCandidate candidate : candidates) { + registerMethodError(candidate.myMethod, candidate.myProblem, candidate.myErrorString, candidate.myReturnType); + } + } + } + } + } + } + } + }; + } + + @Override + @Nls + @NotNull + public String getDisplayName() { + return "@RunWith(Parameterized.class) without data provider"; + } + + private static class MethodCandidate { + PsiMethod myMethod; + String myProblem; + private final String myErrorString; + PsiType myReturnType; + + public MethodCandidate(PsiMethod method, String problem, String errorString, PsiType returnType) { + myMethod = method; + myProblem = problem; + myErrorString = errorString; + myReturnType = returnType; + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java new file mode 100644 index 000000000000..32f412b4184e --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2013 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.psi.PsiClass; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.TestUtils; +import org.jetbrains.annotations.NotNull; + +public class TestCaseInProductCodeInspectionBase extends BaseInspection { + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "test.case.in.product.code.display.name"); + } + + @Override + @NotNull + public String getID() { + return "JUnitTestCaseInProductSource"; + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "test.case.in.product.code.problem.descriptor"); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new TestCaseInProductCodeVisitor(); + } + + private static class TestCaseInProductCodeVisitor + extends BaseInspectionVisitor { + + @Override + public void visitClass(@NotNull PsiClass aClass) { + if (TestUtils.isTest(aClass)) { + return; + } + if (!InheritanceUtil.isInheritor(aClass, + "junit.framework.TestCase")) { + return; + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java new file mode 100644 index 000000000000..59710abc953b --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java @@ -0,0 +1,255 @@ +/* + * Copyright 2000-2013 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.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.TestUtils; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class TestMethodWithoutAssertionInspectionBase extends BaseInspection { + protected final List<String> methodNamePatterns = new ArrayList<String>(); + protected final List<String> classNames = new ArrayList<String>(); + /** + * @noinspection PublicField + */ + @NonNls public String assertionMethods = + "org.junit.Assert,assert.*|fail.*," + + "junit.framework.Assert,assert.*|fail.*," + + "org.mockito.Mockito,verify.*," + + "org.junit.rules.ExpectedException,expect.*," + + "org.hamcrest.MatcherAssert,assertThat"; + @SuppressWarnings({"PublicField"}) + public boolean assertKeywordIsAssertion = false; + private Map<String, Pattern> patternCache = null; + + public TestMethodWithoutAssertionInspectionBase() { + parseString(assertionMethods, classNames, methodNamePatterns); + } + + @Override + @NotNull + public String getID() { + return "JUnitTestMethodWithNoAssertions"; + } + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message("test.method.without.assertion.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("test.method.without.assertion.problem.descriptor"); + } + + @Override + public void readSettings(@NotNull Element element) throws InvalidDataException { + super.readSettings(element); + parseString(assertionMethods, classNames, methodNamePatterns); + } + + @Override + public void writeSettings(@NotNull Element element) throws WriteExternalException { + assertionMethods = formatString(classNames, methodNamePatterns); + super.writeSettings(element); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new TestMethodWithoutAssertionVisitor(); + } + + private boolean methodNamesMatch(String methodName, String methodNamePattern) { + Pattern pattern; + if (patternCache != null) { + pattern = patternCache.get(methodNamePattern); + } + else { + patternCache = new HashMap<String, Pattern>(methodNamePatterns.size()); + pattern = null; + } + if (pattern == null) { + try { + pattern = Pattern.compile(methodNamePattern); + patternCache.put(methodNamePattern, pattern); + } + catch (PatternSyntaxException ignore) { + return false; + } + catch (NullPointerException ignore) { + return false; + } + } + if (pattern == null) { + return false; + } + final Matcher matcher = pattern.matcher(methodName); + return matcher.matches(); + } + + private class TestMethodWithoutAssertionVisitor + extends BaseInspectionVisitor { + + @Override + public void visitMethod(@NotNull PsiMethod method) { + super.visitMethod(method); + if (!TestUtils.isJUnitTestMethod(method)) { + return; + } + if (hasExpectedExceptionAnnotation(method)) { + return; + } + if (containsAssertion(method)) { + return; + } + if (lastStatementIsCallToMethodWithAssertion(method)) { + return; + } + registerMethodError(method); + } + + private boolean lastStatementIsCallToMethodWithAssertion(PsiMethod method) { + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return false; + } + final PsiStatement[] statements = body.getStatements(); + if (statements.length <= 0) { + return false; + } + final PsiStatement lastStatement = statements[0]; + if (!(lastStatement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)lastStatement; + final PsiExpression expression = expressionStatement.getExpression(); + if (!(expression instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + if (qualifierExpression != null && !(qualifierExpression instanceof PsiThisExpression)) { + return false; + } + final PsiMethod targetMethod = methodCallExpression.resolveMethod(); + return containsAssertion(targetMethod); + } + + private boolean containsAssertion(PsiElement element) { + if (element == null) { + return false; + } + final ContainsAssertionVisitor + visitor = new ContainsAssertionVisitor(); + element.accept(visitor); + return visitor.containsAssertion(); + } + + private boolean hasExpectedExceptionAnnotation(PsiMethod method) { + final PsiModifierList modifierList = method.getModifierList(); + final PsiAnnotation testAnnotation = modifierList.findAnnotation("org.junit.Test"); + if (testAnnotation == null) { + return false; + } + final PsiAnnotationParameterList parameterList = testAnnotation.getParameterList(); + final PsiNameValuePair[] nameValuePairs = parameterList.getAttributes(); + for (PsiNameValuePair nameValuePair : nameValuePairs) { + @NonNls final String parameterName = nameValuePair.getName(); + if ("expected".equals(parameterName)) { + return true; + } + } + return false; + } + } + + private class ContainsAssertionVisitor extends JavaRecursiveElementVisitor { + + private boolean containsAssertion = false; + + @Override + public void visitElement(@NotNull PsiElement element) { + if (!containsAssertion) { + super.visitElement(element); + } + } + + @Override + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { + if (containsAssertion) { + return; + } + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + @NonNls final String methodName = methodExpression.getReferenceName(); + if (methodName == null) { + return; + } + final int methodNamesSize = methodNamePatterns.size(); + for (int i = 0; i < methodNamesSize; i++) { + final String pattern = methodNamePatterns.get(i); + if (!methodNamesMatch(methodName, pattern)) { + continue; + } + final PsiMethod method = call.resolveMethod(); + if (method == null || method.isConstructor()) { + continue; + } + final PsiClass aClass = method.getContainingClass(); + if (!InheritanceUtil.isInheritor(aClass, classNames.get(i))) { + continue; + } + containsAssertion = true; + break; + } + } + + @Override + public void visitAssertStatement(PsiAssertStatement statement) { + if (containsAssertion) { + return; + } + super.visitAssertStatement(statement); + if (!assertKeywordIsAssertion) { + return; + } + containsAssertion = true; + } + + public boolean containsAssertion() { + return containsAssertion; + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java new file mode 100644 index 000000000000..59b168af1434 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java @@ -0,0 +1,236 @@ +/* + * 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.codeInspection.ProblemDescriptor; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class UseOfObsoleteAssertInspection extends BaseInspection { + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message("usage.of.obsolete.assert.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("use.of.obsolete.assert.problem.descriptor"); + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new ReplaceObsoleteAssertsFix(); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new UseOfObsoleteAssertVisitor(); + } + + private static class UseOfObsoleteAssertVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + final Project project = expression.getProject(); + final Module module = ModuleUtilCore.findModuleForPsiElement(expression); + if (module == null) { + return; + } + final PsiClass newAssertClass = JavaPsiFacade.getInstance(project) + .findClass("org.junit.Assert", GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)); + if (newAssertClass == null) { + return; + } + final PsiMethod psiMethod = expression.resolveMethod(); + if (psiMethod == null || !psiMethod.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass != null && Comparing.strEqual(containingClass.getQualifiedName(), "junit.framework.Assert")) { + registerMethodCallError(expression); + } + } + } + + private static class ReplaceObsoleteAssertsFix extends InspectionGadgetsFix { + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + final PsiElement psiElement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class); + if (!(psiElement instanceof PsiMethodCallExpression)) { + return; + } + final PsiClass newAssertClass = + JavaPsiFacade.getInstance(project).findClass("org.junit.Assert", GlobalSearchScope.allScope(project)); + final PsiClass oldAssertClass = + JavaPsiFacade.getInstance(project).findClass("junit.framework.Assert", GlobalSearchScope.allScope(project)); + + if (newAssertClass == null) { + return; + } + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)psiElement; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + final PsiElement usedImport = qualifierExpression instanceof PsiReferenceExpression ? + ((PsiReferenceExpression)qualifierExpression).advancedResolve(true).getCurrentFileResolveScope() : + methodExpression.advancedResolve(true).getCurrentFileResolveScope(); + final PsiMethod psiMethod = methodCallExpression.resolveMethod(); + + final boolean isImportUnused = isImportBecomeUnused(methodCallExpression, usedImport, psiMethod); + + PsiImportStaticStatement staticStatement = null; + if (qualifierExpression == null) { + staticStatement = staticallyImported(oldAssertClass, methodExpression); + } + + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project); + if (staticStatement == null) { + methodExpression.setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass)); + + if (isImportUnused && usedImport instanceof PsiImportStatementBase) { + usedImport.delete(); + } + + styleManager.shortenClassReferences(methodExpression); + } + else { + if (isImportUnused) { + final PsiJavaCodeReferenceElement importReference = staticStatement.getImportReference(); + if (importReference != null) { + if (staticStatement.isOnDemand()) { + importReference.bindToElement(newAssertClass); + } + else { + final PsiElement importQExpression = importReference.getQualifier(); + if (importQExpression instanceof PsiReferenceExpression) { + ((PsiReferenceExpression)importQExpression).bindToElement(newAssertClass); + } + } + } + } + else { + methodExpression + .setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass)); + styleManager.shortenClassReferences(methodExpression); + } + } + /* + //refs can be optimized now but should we really? + if (isImportUnused) { + for (PsiReference reference : ReferencesSearch.search(newAssertClass, new LocalSearchScope(methodCallExpression.getContainingFile()))) { + final PsiElement element = reference.getElement(); + styleManager.shortenClassReferences(element); + } + }*/ + } + + private static boolean isImportBecomeUnused(final PsiMethodCallExpression methodCallExpression, + final PsiElement usedImport, + final PsiMethod psiMethod) { + final boolean[] proceed = new boolean[]{true}; + methodCallExpression.getContainingFile().accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (proceed[0]) { + super.visitElement(element); + } + } + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (expression == methodCallExpression) { + return; + } + final PsiMethod resolved = expression.resolveMethod(); + if (resolved == psiMethod) { + proceed[0] = false; + } + else { + final PsiElement resolveScope = + expression.getMethodExpression().advancedResolve(false).getCurrentFileResolveScope(); + if (resolveScope == usedImport) { + proceed[0] = false; + } + } + } + }); + return proceed[0]; + } + + @Nullable + private static PsiImportStaticStatement staticallyImported(PsiClass oldAssertClass, PsiReferenceExpression methodExpression) { + final String referenceName = methodExpression.getReferenceName(); + final PsiFile containingFile = methodExpression.getContainingFile(); + if (!(containingFile instanceof PsiJavaFile)) { + return null; + } + final PsiImportList importList = ((PsiJavaFile)containingFile).getImportList(); + if (importList == null) { + return null; + } + final PsiImportStaticStatement[] statements = importList.getImportStaticStatements(); + for (PsiImportStaticStatement statement : statements) { + if (oldAssertClass != statement.resolveTargetClass()) { + continue; + } + final String importRefName = statement.getReferenceName(); + final PsiJavaCodeReferenceElement importReference = statement.getImportReference(); + if (importReference == null) { + continue; + } + if (Comparing.strEqual(importRefName, referenceName)) { + final PsiElement qualifier = importReference.getQualifier(); + if (qualifier instanceof PsiJavaCodeReferenceElement) { + return statement; + } + } + else if (importRefName == null) { + return statement; + } + } + return null; + } + + @NotNull + @Override + public String getName() { + return InspectionGadgetsBundle.message("use.of.obsolete.assert.quickfix"); + } + + @Override + @NotNull + public String getFamilyName() { + return getName(); + } + + } +}
\ No newline at end of file |