package org.jetbrains.plugins.cucumber.java.run;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.JavaRunConfigurationExtensionManager;
import com.intellij.execution.Location;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.junit.JavaRunConfigurationProducerBase;
import com.intellij.execution.junit2.info.LocationUtil;
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.openapi.util.NullableComputable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.cucumber.java.CucumberJavaUtil;
import java.util.Collection;
import java.util.Set;
/**
* @author Andrey.Vokin
* @since 8/6/12
*/
public abstract class CucumberJavaRunConfigurationProducer extends JavaRunConfigurationProducerBase<CucumberJavaRunConfiguration> implements Cloneable {
public static final String FORMATTER_OPTIONS = " --format org.jetbrains.plugins.cucumber.java.run.CucumberJvmSMFormatter --monochrome";
public static final String FORMATTER_OPTIONS_1_2 = " --plugin org.jetbrains.plugins.cucumber.java.run.CucumberJvmSMFormatter --monochrome";
public static final String CUCUMBER_1_0_MAIN_CLASS = "cucumber.cli.Main";
public static final String CUCUMBER_1_1_MAIN_CLASS = "cucumber.api.cli.Main";
public static final String CUCUMBER_1_2_PLUGIN_CLASS = "cucumber.api.Plugin";
public static final Set<String> HOOK_ANNOTATION_NAMES = ContainerUtil.newHashSet("cucumber.annotation.Before",
"cucumber.annotation.After",
"cucumber.api.java.Before",
"cucumber.api.java.After");
protected CucumberJavaRunConfigurationProducer() {
super(CucumberJavaRunConfigurationType.getInstance());
}
@Nullable
protected abstract NullableComputable<String> getStepsGlue(@NotNull final PsiElement element);
protected abstract String getConfigurationName(@NotNull ConfigurationContext context);
protected String getNameFilter(@NotNull ConfigurationContext context) {
return "";
}
@Nullable
protected abstract VirtualFile getFileToRun(ConfigurationContext context);
@Override
protected boolean setupConfigurationFromContext(CucumberJavaRunConfiguration configuration,
ConfigurationContext context,
Ref<PsiElement> sourceElement) {
final VirtualFile virtualFile = getFileToRun(context);
if (virtualFile == null) {
return false;
}
final Project project = configuration.getProject();
final PsiElement element = context.getPsiLocation();
if (element == null) {
return false;
}
final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project);
if (module == null) return false;
String mainClassName = null;
String formatterOptions = null;
final Location location = context.getLocation();
if (location != null) {
if (LocationUtil.isJarAttached(location, PsiDirectory.EMPTY_ARRAY, CUCUMBER_1_0_MAIN_CLASS)) {
mainClassName = CUCUMBER_1_0_MAIN_CLASS;
} else if (LocationUtil.isJarAttached(location, PsiDirectory.EMPTY_ARRAY, CUCUMBER_1_1_MAIN_CLASS)) {
mainClassName = CUCUMBER_1_1_MAIN_CLASS;
}
if (LocationUtil.isJarAttached(location, PsiDirectory.EMPTY_ARRAY, CUCUMBER_1_2_PLUGIN_CLASS)) {
formatterOptions = FORMATTER_OPTIONS_1_2;
} else {
formatterOptions = FORMATTER_OPTIONS;
}
}
if (mainClassName == null) {
return false;
}
final VirtualFile file = getFileToRun(context);
if (file == null) {
return false;
}
if (StringUtil.isEmpty(configuration.getGlue())) {
final NullableComputable<String> glue = getStepsGlue(element);
configuration.setGlue(glue);
}
configuration.setNameFilter(getNameFilter(context));
configuration.setFilePath(file.getPath());
configuration.setProgramParameters(formatterOptions);
if (StringUtil.isEmpty(configuration.MAIN_CLASS_NAME)) {
configuration.MAIN_CLASS_NAME = mainClassName;
}
if (configuration.getNameFilter() != null && configuration.getNameFilter().length() > 0) {
final String newProgramParameters = configuration.getProgramParameters() + " --name \"" + configuration.getNameFilter() + "\"";
configuration.setProgramParameters(newProgramParameters);
}
configuration.myGeneratedName = getConfigurationName(context);
configuration.setGeneratedName();
setupConfigurationModule(context, configuration);
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location);
return true;
}
@Override
public boolean isConfigurationFromContext(CucumberJavaRunConfiguration runConfiguration, ConfigurationContext context) {
final Location location = JavaExecutionUtil.stepIntoSingleClass(context.getLocation());
if (location == null) {
return false;
}
final VirtualFile fileToRun = getFileToRun(context);
if (fileToRun == null) {
return false;
}
if (!fileToRun.getPath().equals(runConfiguration.getFilePath())) {
return false;
}
if (!Comparing.strEqual(getNameFilter(context), runConfiguration.getNameFilter())) {
return false;
}
final Module configurationModule = runConfiguration.getConfigurationModule().getModule();
if (!Comparing.equal(location.getModule(), configurationModule)) {
return false;
}
return true;
}
protected Set<String> getHookGlue(final PsiElement element) {
final Set<String> packages = ContainerUtil.newLinkedHashSet();
final Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module == null) {
return packages;
}
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(element.getProject());
final GlobalSearchScope dependenciesScope = module.getModuleWithDependenciesAndLibrariesScope(true);
for (final String fullyQualifiedAnnotationName : HOOK_ANNOTATION_NAMES) {
final PsiClass psiClass = javaPsiFacade.findClass(fullyQualifiedAnnotationName, dependenciesScope);
if (psiClass != null) {
final Query<PsiMethod> psiMethods = AnnotatedElementsSearch
.searchPsiMethods(psiClass, GlobalSearchScope.allScope(element.getProject()));
final Collection<PsiMethod> methods = psiMethods.findAll();
addPackagesOfMethods(methods, packages);
}
}
return packages;
}
private static Set<String> addPackagesOfMethods(final Collection<PsiMethod> psiMethods, final Set<String> packages) {
for (final PsiMethod psiMethod : psiMethods) {
final PsiClassOwner file = (PsiClassOwner)psiMethod.getContainingFile();
final String packageName = file.getPackageName();
if (StringUtil.isNotEmpty(packageName)) {
CucumberJavaUtil.addGlue(packageName, packages);
}
}
return packages;
}
}