testng: extract strategy

This commit is contained in:
Anna Kozlova
2015-04-16 12:24:36 +02:00
parent 6d405bc74c
commit 538db34fc0
12 changed files with 847 additions and 448 deletions
@@ -20,40 +20,31 @@
*/
package com.theoryinpractice.testng.configuration;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.testframework.SearchForTestsTask;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.ClassUtil;
import com.theoryinpractice.testng.model.IDEARemoteTestRunnerClient;
import com.theoryinpractice.testng.model.TestClassFilter;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.xml.*;
import java.io.*;
import java.net.ServerSocket;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class SearchingForTestsTask extends SearchForTestsTask {
private static final Logger LOG = Logger.getInstance("#" + SearchingForTestsTask.class.getName());
@@ -280,182 +271,9 @@ public class SearchingForTestsTask extends SearchForTestsTask {
protected void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
final PsiManager psiManager = PsiManager.getInstance(myProject);
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
final String packageName = data.getPackageName();
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
new Computable<PsiPackage>() {
@Nullable
public PsiPackage compute() {
return JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(packageName);
}
}
);
if (psiPackage == null) {
throw CantRunException.packageNotFound(packageName);
}
else {
TestSearchScope scope = myConfig.getPersistantData().getScope();
//TODO we should narrow this down by module really, if that's what's specified
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true);
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
}
}
}
else if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
//it's a class
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
})) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
calculateDependencies(null, classes, psiClass);
}
else if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
//it's a method
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(
new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
}
)) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
collectTestMethods(classes, psiClass, data.getMethodName());
}
else if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
//for a group, we include all classes
PsiClass[] testClasses = TestNGUtil
.getAllTestClasses(new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true), false);
if (testClasses != null) {
for (PsiClass c : testClasses) {
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
}
}
else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
for (final String pattern : data.getPatterns()) {
final String className;
final String methodName;
if (pattern.contains(",")) {
methodName = StringUtil.getShortName(pattern, ',');
className = StringUtil.getPackageName(pattern, ',');
} else {
className = pattern;
methodName = null;
}
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, className.replace('/', '.'), null, true, getSearchScope());
}
});
if (psiClass != null) {
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return TestNGUtil.hasTest(psiClass);
}
});
if (hasTest) {
if (StringUtil.isEmpty(methodName)) {
calculateDependencies(null, classes, psiClass);
}
else {
collectTestMethods(classes, psiClass, methodName);
}
} else {
throw new CantRunException("No tests found in class " + className);
}
}
}
if (classes.size() != data.getPatterns().size()) {
TestSearchScope scope = myConfig.getPersistantData().getScope();
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
for (String p : data.getPatterns()) {
final Pattern compilePattern;
try {
compilePattern = Pattern.compile(p);
}
catch (PatternSyntaxException e) {
continue;
}
if (compilePattern != null) {
compilePatterns.add(compilePattern);
}
}
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true){
@Override
public boolean isAccepted(PsiClass psiClass) {
if (super.isAccepted(psiClass)) {
final String qualifiedName = psiClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
for (Pattern pattern : compilePatterns) {
if (pattern.matcher(qualifiedName).matches()) return true;
}
}
return false;
}
};
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
}
}
}
}
private void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return psiClass.findMethodsByName(methodName, true);
}
}
);
calculateDependencies(methods, classes, psiClass);
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
classes.put(psiClass, psiMethods);
}
for (PsiMethod method : methods) {
psiMethods.put(method, Collections.<String>emptyList());
final TestNGTestObject testObject = TestNGTestObject.fromConfig(myConfig);
if (testObject != null) {
testObject.fillTestObjects(classes);
}
}
@@ -492,152 +310,4 @@ public class SearchingForTestsTask extends SearchForTestsTask {
return params;
}
private void calculateDependencies(PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
@Nullable final PsiClass... classes) {
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
}
private void calculateDependencies(final PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
@Nullable final PsiClass... classes) {
if (classes != null && classes.length > 0) {
final Set<String> groupDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
if (!groupDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = classes[0].getProject();
final PsiClass testAnnotation =
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
LOG.assertTrue(testAnnotation != null);
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(psiMember);
}
}
}
}
});
}
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
if (methods == null) {
for (PsiClass c : classes) {
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
} else {
for (PsiMember psiMember : membersToCheckNow) {
PsiClass psiClass;
PsiMethod[] meths = null;
if (psiMember instanceof PsiMethod) {
psiClass = psiMember.getContainingClass();
meths = new PsiMethod[] {(PsiMethod)psiMember};
} else {
psiClass = (PsiClass)psiMember;
}
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
}
}
}
}
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
final Set<PsiMember> membersToCheckNow,
final PsiMethod[] methods,
final PsiClass... classes) {
final PsiClass[] psiClasses;
if (methods != null && methods.length > 0) {
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
for (final PsiMethod method : methods) {
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return method.getContainingClass();
}
}));
}
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
} else {
psiClasses = classes;
}
for (final PsiClass containingClass : psiClasses) {
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
if (!testMethodDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = containingClass.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String dependency : testMethodDependencies) {
final String className = StringUtil.getPackageName(dependency);
final String methodName = StringUtil.getShortName(dependency);
if (StringUtil.isEmpty(className)) {
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
else {
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
if (aClass != null) {
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
}
}
}
});
}
}
}
private static void checkClassMethods(String methodName,
PsiClass containingClass,
Set<PsiMember> alreadyMarkedToBeChecked,
Set<PsiMember> membersToCheckNow,
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
for (PsiMethod method : psiMethods) {
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
appendMember(method, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(method);
}
}
}
private static boolean appendMember(final PsiMember psiMember,
final Set<PsiMember> underConsideration,
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
boolean result = false;
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
results.put(psiClass, psiMethods);
if (psiMember instanceof PsiClass) {
result = underConsideration.add(psiMember);
}
}
if (psiMember instanceof PsiMethod) {
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
if (add) {
return underConsideration.add(psiMember);
}
return false;
}
return result;
}
@NotNull
private GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
}
}
@@ -29,7 +29,6 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit.RefactoringListeners;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
@@ -47,12 +46,12 @@ import com.intellij.refactoring.listeners.RefactoringElementAdapter;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.listeners.UndoRefactoringElementListener;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.xml.Parser;
import java.util.*;
@@ -68,7 +67,7 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
public boolean ALTERNATIVE_JRE_PATH_ENABLED;
public String ALTERNATIVE_JRE_PATH;
private static final Object PARSE_LOCK = new Object();
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
public static final String DEFAULT_PACKAGE_CONFIGURATION_NAME = ExecutionBundle.message("default.package.configuration.name");
@@ -149,32 +148,14 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
@Override
public String suggestedName() {
return data.getGeneratedName(getConfigurationModule());
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
return testObject != null ? testObject.getGeneratedName() : null;
}
@Override
public String getActionName() {
if (TestType.CLASS.getType().equals(data.TEST_OBJECT)) {
String shortName = JavaExecutionUtil.getShortClassName(data.MAIN_CLASS_NAME);
return ProgramRunnerUtil.shortenName(shortName, 0);
}
if (TestType.PACKAGE.getType().equals(data.TEST_OBJECT)) {
String s = getName();
if (!isGeneratedName()) return '\"' + s + '\"';
if (data.getPackageName().trim().length() > 0) {
return "Tests in \"" + data.getPackageName() + '\"';
}
else {
return "All Tests";
}
}
if (TestType.METHOD.getType().equals(data.TEST_OBJECT)) {
return data.getMethodName() + "()";
}
if (TestType.SUITE.getType().equals(data.TEST_OBJECT)) {
return data.getSuiteName();
}
return data.getGroupName();
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
return testObject != null ? ProgramRunnerUtil.shortenName(testObject.getActionName(), 0) : null;
}
public void setVMParameters(String value) {
@@ -299,45 +280,9 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
if (data.TEST_OBJECT.equals(TestType.CLASS.getType()) || data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
final SourceScope scope = data.getScope().getSourceScope(this);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
if (methods.length == 0) {
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
}
for (PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
}
}
}
}
else if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
PsiPackage psiPackage = JavaPsiFacade.getInstance(project).findPackage(data.getPackageName());
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
}
else if (data.TEST_OBJECT.equals(TestType.SUITE.getType())) {
try {
final Parser parser = new Parser(data.getSuiteName());
parser.setLoadClasses(false);
synchronized (PARSE_LOCK) {
parser.parse();//try to parse suite.xml
}
}
catch (Exception e) {
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
}
} else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
final Set<String> patterns = data.getPatterns();
if (patterns.isEmpty()) {
throw new RuntimeConfigurationWarning("No pattern selected");
}
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
if (testObject != null) {
testObject.checkConfiguration();
}
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), getConfigurationModule().getModule());
@@ -33,6 +33,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import org.testng.IDEATestNGRemoteListener;
public abstract class TestNGConfigurationProducer extends JavaRunConfigurationProducerBase<TestNGConfiguration> implements Cloneable {
@@ -58,7 +59,7 @@ public abstract class TestNGConfigurationProducer extends JavaRunConfigurationPr
String paramSetName = contextLocation instanceof PsiMemberParameterizedLocation
? getInvocationNumber(((PsiMemberParameterizedLocation)contextLocation).getParamSetName()) : null;
if (paramSetName != null && !Comparing.strEqual(paramSetName, testNGConfiguration.getProgramParameters())) return false;
TestData testobject = testNGConfiguration.getPersistantData();
TestNGTestObject testobject = TestNGTestObject.fromConfig(testNGConfiguration);
if (testobject != null) {
if (testobject.isConfiguredByElement(element)) {
final Module configurationModule = testNGConfiguration.getConfigurationModule().getModule();
@@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import icons.TestngIcons;
import org.jetbrains.annotations.NotNull;
@@ -72,7 +73,8 @@ public class TestNGConfigurationType implements ConfigurationType
return false;
else {
final PsiElement element = location.getPsiElement();
if (testobject.isConfiguredByElement(element)) {
final TestNGTestObject testNGTestObject = TestNGTestObject.fromConfig(config);
if (testNGTestObject != null && testNGTestObject.isConfiguredByElement(element)) {
final Module configurationModule = config.getConfigurationModule().getModule();
if (Comparing.equal(location.getModule(), configurationModule)) return true;
@@ -18,16 +18,15 @@ package com.theoryinpractice.testng.model;
import com.intellij.execution.ExternalizablePath;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.Location;
import com.intellij.execution.configurations.JavaRunConfigurationModule;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiPackage;
import java.util.*;
@@ -174,26 +173,6 @@ public class TestData implements Cloneable
return data;
}
public String getGeneratedName(JavaRunConfigurationModule runconfigurationmodule) {
if (TestType.PACKAGE.getType().equals(TEST_OBJECT)) if (getPackageName().length() == 0) return "<default>";
else return getPackageName();
String name = JavaExecutionUtil.getPresentableClassName(getMainClassName());
if (TestType.METHOD.getType().equals(TEST_OBJECT)) {
return name + '.' + getMethodName();
}
else if (TestType.SUITE.getType().equals(TEST_OBJECT)) {
return getSuiteName();
}
else {
if (TestType.PATTERN.getType().equals(TEST_OBJECT)) {
final int size = myPatterns.size();
if (size == 0) return "Temp suite";
return StringUtil.getShortName(myPatterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
return name;
}
}
public String getMainClassName() {
return MAIN_CLASS_NAME == null ? "" : MAIN_CLASS_NAME;
}
@@ -217,28 +196,6 @@ public class TestData implements Cloneable
return JavaExecutionUtil.findModule(psiclass);
}
public boolean isConfiguredByElement(PsiElement element) {
if (TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
if (element instanceof PsiPackage) {
return Comparing.strEqual(PACKAGE_NAME, ((PsiPackage) element).getQualifiedName());
} else if (element instanceof PsiDirectory) {
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
return psiPackage != null && Comparing.strEqual(PACKAGE_NAME, psiPackage.getQualifiedName());
}
}
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiMethod && TEST_OBJECT.equals(TestType.METHOD.getType())) {
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
return aClass != null &&
Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
Comparing.strEqual(METHOD_NAME, ((PsiMethod) element).getName());
} else if (element instanceof PsiClass && TEST_OBJECT.equals(TestType.CLASS.getType())) {
return Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
}
return false;
}
public Map<String, String> getEnvs() {
return ENVS;
}
@@ -0,0 +1,95 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestClass extends TestNGTestObject {
public TestNGTestClass(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
//it's a class
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
})) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
calculateDependencies(null, classes, psiClass);
}
@Override
public String getGeneratedName() {
return JavaExecutionUtil.getPresentableClassName(myConfig.getPersistantData().getMainClassName());
}
@Override
public String getActionName() {
return JavaExecutionUtil.getShortClassName(myConfig.getPersistantData().MAIN_CLASS_NAME);
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
final SourceScope scope = data.getScope().getSourceScope(myConfig);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiClass) {
return Comparing.strEqual(myConfig.getPersistantData().getMethodName(), JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
}
return false;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class TestNGTestGroup extends TestNGTestObject {
public TestNGTestGroup(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
//for a group, we include all classes
final TestClassFilter classFilter =
new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
PsiClass[] testClasses = TestNGUtil.getAllTestClasses(classFilter, false);
if (testClasses != null) {
for (PsiClass c : testClasses) {
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
}
}
@Override
public String getGeneratedName() {
return myConfig.getPersistantData().getGroupName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getGroupName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
//check group exist?
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestMethod extends TestNGTestObject {
public TestNGTestMethod(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(
new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
}
)) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
collectTestMethods(classes, psiClass, data.getMethodName());
}
@Override
public String getGeneratedName() {
final TestData data = myConfig.getPersistantData();
return JavaExecutionUtil.getPresentableClassName(data.getMainClassName()) + '.' + data.getMethodName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getMethodName() + "()";
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
final SourceScope scope = data.getScope().getSourceScope(myConfig);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
if (methods.length == 0) {
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
}
for (PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
}
}
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiMethod) {
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
final TestData data = myConfig.getPersistantData();
return aClass != null &&
Comparing.strEqual(data.MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
Comparing.strEqual(data.METHOD_NAME, ((PsiMethod) element).getName());
}
return false;
}
}
@@ -0,0 +1,247 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public abstract class TestNGTestObject {
private static final Logger LOG = Logger.getInstance("#" + TestNGTestObject.class.getName());
protected final TestNGConfiguration myConfig;
public TestNGTestObject(TestNGConfiguration config) {
myConfig = config;
}
public static TestNGTestObject fromConfig(TestNGConfiguration config) {
final TestData data = config.getPersistantData();
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
return new TestNGTestPackage(config);
}
if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
return new TestNGTestClass(config);
}
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
return new TestNGTestMethod(config);
}
if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
return new TestNGTestGroup(config);
}
if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
return new TestNGTestPattern(config);
}
if (data.TEST_OBJECT.equals(TestType.SUITE.getType())){
return new TestNGTestSuite(config);
}
assert false : data.TEST_OBJECT;
return null;
}
public abstract void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException;
public abstract String getGeneratedName();
public abstract String getActionName();
public abstract void checkConfiguration() throws RuntimeConfigurationException;
public boolean isConfiguredByElement(PsiElement element) {
return false;
}
protected void calculateDependencies(PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
@Nullable final PsiClass... classes) {
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
}
private void calculateDependencies(final PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
@Nullable final PsiClass... classes) {
if (classes != null && classes.length > 0) {
final Set<String> groupDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
if (!groupDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = classes[0].getProject();
final PsiClass testAnnotation =
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
LOG.assertTrue(testAnnotation != null);
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(psiMember);
}
}
}
}
});
}
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
if (methods == null) {
for (PsiClass c : classes) {
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
} else {
for (PsiMember psiMember : membersToCheckNow) {
PsiClass psiClass;
PsiMethod[] meths = null;
if (psiMember instanceof PsiMethod) {
psiClass = psiMember.getContainingClass();
meths = new PsiMethod[] {(PsiMethod)psiMember};
} else {
psiClass = (PsiClass)psiMember;
}
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
}
}
}
}
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
final Set<PsiMember> membersToCheckNow,
final PsiMethod[] methods,
final PsiClass... classes) {
final PsiClass[] psiClasses;
if (methods != null && methods.length > 0) {
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
for (final PsiMethod method : methods) {
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return method.getContainingClass();
}
}));
}
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
} else {
psiClasses = classes;
}
for (final PsiClass containingClass : psiClasses) {
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
if (!testMethodDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = containingClass.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String dependency : testMethodDependencies) {
final String className = StringUtil.getPackageName(dependency);
final String methodName = StringUtil.getShortName(dependency);
if (StringUtil.isEmpty(className)) {
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
else {
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
if (aClass != null) {
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
}
}
}
});
}
}
}
private static void checkClassMethods(String methodName,
PsiClass containingClass,
Set<PsiMember> alreadyMarkedToBeChecked,
Set<PsiMember> membersToCheckNow,
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
for (PsiMethod method : psiMethods) {
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
appendMember(method, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(method);
}
}
}
private static boolean appendMember(final PsiMember psiMember,
final Set<PsiMember> underConsideration,
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
boolean result = false;
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
results.put(psiClass, psiMethods);
if (psiMember instanceof PsiClass) {
result = underConsideration.add(psiMember);
}
}
if (psiMember instanceof PsiMethod) {
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
if (add) {
return underConsideration.add(psiMember);
}
return false;
}
return result;
}
@NotNull
protected GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
}
protected void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return psiClass.findMethodsByName(methodName, true);
}
}
);
calculateDependencies(methods, classes, psiClass);
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
classes.put(psiClass, psiMethods);
}
for (PsiMethod method : methods) {
psiMethods.put(method, Collections.<String>emptyList());
}
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestPackage extends TestNGTestObject {
public TestNGTestPackage(TestNGConfiguration configuration) {
super(configuration);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {
final String packageName = myConfig.getPersistantData().getPackageName();
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
new Computable<PsiPackage>() {
@Nullable
public PsiPackage compute() {
return JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(packageName);
}
}
);
if (psiPackage == null) {
throw CantRunException.packageNotFound(packageName);
}
else {
TestSearchScope scope = myConfig.getPersistantData().getScope();
//TODO we should narrow this down by module really, if that's what's specified
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
}
}
}
@Override
public String getGeneratedName() {
final String packageName = myConfig.getPersistantData().getPackageName();
return packageName.length() == 0 ? "<default>" : packageName;
}
@Override
public String getActionName() {
String s = myConfig.getName();
if (!myConfig.isGeneratedName()) return '\"' + s + '\"';
if (myConfig.getPersistantData().getPackageName().trim().length() > 0) {
return "Tests in \"" + myConfig.getPersistantData().getPackageName() + '\"';
}
else {
return "All Tests";
}
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
PsiPackage psiPackage = JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(data.getPackageName());
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
final String packageName = myConfig.getPersistantData().getPackageName();
if (element instanceof PsiPackage) {
return Comparing.strEqual(packageName, ((PsiPackage)element).getQualifiedName());
} else if (element instanceof PsiDirectory) {
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
return psiPackage != null && Comparing.strEqual(packageName, psiPackage.getQualifiedName());
}
return false;
}
}
@@ -0,0 +1,145 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.ClassUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class TestNGTestPattern extends TestNGTestObject {
private static final Logger LOG = Logger.getInstance("#" + TestNGTestPattern.class.getName());
public TestNGTestPattern(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
for (final String pattern : data.getPatterns()) {
final String className;
final String methodName;
if (pattern.contains(",")) {
methodName = StringUtil.getShortName(pattern, ',');
className = StringUtil.getPackageName(pattern, ',');
} else {
className = pattern;
methodName = null;
}
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), className.replace('/', '.'), null, true, getSearchScope());
}
});
if (psiClass != null) {
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return TestNGUtil.hasTest(psiClass);
}
});
if (hasTest) {
if (StringUtil.isEmpty(methodName)) {
calculateDependencies(null, classes, psiClass);
}
else {
collectTestMethods(classes, psiClass, methodName);
}
} else {
throw new CantRunException("No tests found in class " + className);
}
}
}
if (classes.size() != data.getPatterns().size()) {
TestSearchScope scope = myConfig.getPersistantData().getScope();
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
for (String p : data.getPatterns()) {
final Pattern compilePattern;
try {
compilePattern = Pattern.compile(p);
}
catch (PatternSyntaxException e) {
continue;
}
if (compilePattern != null) {
compilePatterns.add(compilePattern);
}
}
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true){
@Override
public boolean isAccepted(PsiClass psiClass) {
if (super.isAccepted(psiClass)) {
final String qualifiedName = psiClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
for (Pattern pattern : compilePatterns) {
if (pattern.matcher(qualifiedName).matches()) return true;
}
}
return false;
}
};
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
}
}
}
@Override
public String getGeneratedName() {
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
final int size = patterns.size();
if (size == 0) return "Temp suite";
return StringUtil.getShortName(patterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
@Override
public String getActionName() {
return getGeneratedName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
if (patterns.isEmpty()) {
throw new RuntimeConfigurationWarning("No pattern selected");
}
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2015 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.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.testng.xml.Parser;
import java.util.List;
import java.util.Map;
public class TestNGTestSuite extends TestNGTestObject {
private static final Object PARSE_LOCK = new Object();
public TestNGTestSuite(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {}
@Override
public String getGeneratedName() {
return myConfig.getPersistantData().getSuiteName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getSuiteName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
try {
final Parser parser = new Parser(data.getSuiteName());
parser.setLoadClasses(false);
synchronized (PARSE_LOCK) {
parser.parse();//try to parse suite.xml
}
}
catch (Exception e) {
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
}
}
}