blob: aeda466432a2d133a9c6bd3fb95db5924a551dee [file] [log] [blame]
/*
* Copyright 2000-2009 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.theoryinpractice.testng.inspection;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInspection.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Hani Suleiman Date: Aug 3, 2005 Time: 3:34:56 AM
*/
public class DependsOnMethodInspection extends BaseJavaLocalInspectionTool
{
private static final Logger LOGGER = Logger.getInstance("TestNG Runner");
private static final Pattern PATTERN = Pattern.compile("\"([a-zA-Z1-9_\\(\\)\\*]*)\"");
@NotNull
@Override
public String getGroupDisplayName() {
return "TestNG";
}
@NotNull
@Override
public String getDisplayName() {
return "dependsOnMethods problem";
}
@NotNull
@Override
public String getShortName() {
return "dependsOnMethodTestNG";
}
public boolean isEnabledByDefault() {
return true;
}
@Override
@Nullable
public ProblemDescriptor[] checkClass(@NotNull PsiClass psiClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
PsiAnnotation[] annotations = TestNGUtil.getTestNGAnnotations(psiClass);
if(annotations.length == 0) return ProblemDescriptor.EMPTY_ARRAY;
List<ProblemDescriptor> problemDescriptors = new ArrayList<ProblemDescriptor>();
for (PsiAnnotation annotation : annotations) {
final PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue("dependsOnMethods");
if (value != null && !TestNGUtil.isDisabled(annotation)) {
String text = value.getText();
if (value instanceof PsiReferenceExpression) {
final PsiElement resolve = ((PsiReferenceExpression)value).resolve();
if (resolve instanceof PsiField && ((PsiField)resolve).hasModifierProperty(PsiModifier.STATIC) && ((PsiField)resolve).hasModifierProperty(PsiModifier.FINAL)) {
final PsiExpression initializer = ((PsiField)resolve).getInitializer();
if (initializer != null) {
text = initializer.getText();
}
}
}
final Set<String> names = new HashSet<String>();
final Matcher matcher = PATTERN.matcher(text);
int idx = 0;
while (matcher.find()) {
String methodName = matcher.group(1);
if (!names.add(methodName)) {
PsiAnnotationMemberValue element2Highlight = value;
if (value instanceof PsiArrayInitializerMemberValue) {
final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers();
if (idx < initializers.length) {
element2Highlight = initializers[idx];
}
}
problemDescriptors.add(manager.createProblemDescriptor(element2Highlight, "Duplicated method name: " + methodName,
(LocalQuickFix)null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
isOnTheFly));
}
checkMethodNameDependency(manager, psiClass, methodName, value, problemDescriptors, isOnTheFly);
idx++;
}
}
}
return problemDescriptors.toArray(new ProblemDescriptor[problemDescriptors.size()]);
}
private static void checkMethodNameDependency(InspectionManager manager, PsiClass psiClass, String methodName, PsiAnnotationMemberValue value,
List<ProblemDescriptor> problemDescriptors, boolean onTheFly) {
LOGGER.debug("Found dependsOnMethods with text: " + methodName);
if (methodName.length() > 0 && methodName.charAt(methodName.length() - 1) == ')') {
LOGGER.debug("dependsOnMethods contains ()" + psiClass.getName());
// TODO Add quick fix for removing brackets on annotation
ProblemDescriptor descriptor = manager.createProblemDescriptor(value,
"Method '" + methodName + "' should not include () characters.",
(LocalQuickFix) null,
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly);
problemDescriptors.add(descriptor);
} else {
final String configAnnotation = TestNGUtil.getConfigAnnotation(PsiTreeUtil.getParentOfType(value, PsiMethod.class));
final PsiMethod[] foundMethods;
if (methodName.endsWith("*")) {
final String methodNameMask = StringUtil.trimEnd(methodName, "*");
final List<PsiMethod> methods = ContainerUtil.filter(psiClass.getMethods(), new Condition<PsiMethod>() {
@Override
public boolean value(PsiMethod method) {
return method.getName().startsWith(methodNameMask);
}
});
foundMethods = methods.toArray(new PsiMethod[methods.size()]);
} else {
foundMethods = psiClass.findMethodsByName(methodName, true);
}
if (foundMethods.length == 0) {
LOGGER.debug("dependsOnMethods method doesn't exist:" + methodName);
ProblemDescriptor descriptor = manager.createProblemDescriptor(value,
"Method '" + methodName + "' unknown.",
(LocalQuickFix) null,
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly);
problemDescriptors.add(descriptor);
} else {
boolean hasTestsOrConfigs = false;
for (PsiMethod foundMethod : foundMethods) {
if (configAnnotation != null) {
hasTestsOrConfigs |= AnnotationUtil.isAnnotated(foundMethod, configAnnotation, true);
} else {
hasTestsOrConfigs |= TestNGUtil.hasTest(foundMethod);
}
}
if (!hasTestsOrConfigs) {
ProblemDescriptor descriptor = manager.createProblemDescriptor(value,
configAnnotation == null ? "Method '" + methodName + "' is not a test or configuration method." :
"Method '" + methodName + "' is not annotated with @" + configAnnotation,
(LocalQuickFix) null,
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly);
problemDescriptors.add(descriptor);
}
}
}
}
}