| /* |
| * Copyright 2000-2010 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 org.jetbrains.android.run.testing; |
| |
| import com.android.builder.model.AndroidProject; |
| import com.android.tools.idea.gradle.IdeaAndroidProject; |
| import com.intellij.execution.JavaExecutionUtil; |
| import com.intellij.execution.Location; |
| import com.intellij.execution.actions.ConfigurationContext; |
| import com.intellij.execution.actions.ConfigurationFromContext; |
| import com.intellij.execution.junit.JUnitConfigurationProducer; |
| import com.intellij.execution.junit.JUnitUtil; |
| import com.intellij.execution.junit.JavaRunConfigurationProducerBase; |
| import com.intellij.execution.junit.JavaRuntimeConfigurationProducerBase; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Ref; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.psi.PsiClass; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiMethod; |
| import com.intellij.psi.PsiPackage; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import org.jetbrains.android.facet.AndroidFacet; |
| import org.jetbrains.android.run.AndroidRunConfigurationType; |
| import org.jetbrains.android.run.TargetSelectionMode; |
| import org.jetbrains.android.util.AndroidUtils; |
| import org.jetbrains.annotations.NotNull; |
| |
| /** |
| * @author Eugene.Kudelevsky |
| */ |
| public class AndroidTestConfigurationProducer extends JavaRunConfigurationProducerBase<AndroidTestRunConfiguration> { |
| |
| public AndroidTestConfigurationProducer() { |
| super(AndroidTestRunConfigurationType.getInstance()); |
| } |
| |
| private boolean setupAllInPackageConfiguration(AndroidTestRunConfiguration configuration, |
| PsiElement element, |
| ConfigurationContext context, |
| Ref<PsiElement> sourceElement) { |
| final PsiPackage p = JavaRuntimeConfigurationProducerBase.checkPackage(element); |
| if (p == null) { |
| return false; |
| } |
| final String packageName = p.getQualifiedName(); |
| setupConfiguration(configuration, p, context, sourceElement); |
| configuration.TESTING_TYPE = packageName.length() > 0 |
| ? AndroidTestRunConfiguration.TEST_ALL_IN_PACKAGE |
| : AndroidTestRunConfiguration.TEST_ALL_IN_MODULE; |
| configuration.PACKAGE_NAME = packageName; |
| configuration.setGeneratedName(); |
| return true; |
| } |
| |
| private boolean setupClassConfiguration(AndroidTestRunConfiguration configuration, |
| PsiElement element, |
| ConfigurationContext context, |
| Ref<PsiElement> sourceElement) { |
| PsiClass elementClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, false); |
| |
| while (elementClass != null) { |
| if (JUnitUtil.isTestClass(elementClass)) { |
| setupConfiguration(configuration, elementClass, context, sourceElement); |
| configuration.TESTING_TYPE = AndroidTestRunConfiguration.TEST_CLASS; |
| configuration.CLASS_NAME = elementClass.getQualifiedName(); |
| configuration.setGeneratedName(); |
| return true; |
| } |
| elementClass = PsiTreeUtil.getParentOfType(elementClass, PsiClass.class); |
| } |
| return false; |
| } |
| |
| private boolean setupMethodConfiguration(AndroidTestRunConfiguration configuration, |
| PsiElement element, |
| ConfigurationContext context, |
| Ref<PsiElement> sourceElement) { |
| PsiMethod elementMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); |
| |
| while (elementMethod != null) { |
| if (isTestMethod(elementMethod)) { |
| PsiClass c = elementMethod.getContainingClass(); |
| setupConfiguration(configuration, elementMethod, context, sourceElement); |
| assert c != null; |
| configuration.TESTING_TYPE = AndroidTestRunConfiguration.TEST_METHOD; |
| configuration.CLASS_NAME = c.getQualifiedName(); |
| configuration.METHOD_NAME = elementMethod.getName(); |
| configuration.setGeneratedName(); |
| return true; |
| } |
| elementMethod = PsiTreeUtil.getParentOfType(elementMethod, PsiMethod.class); |
| } |
| return false; |
| } |
| |
| private boolean setupConfiguration(AndroidTestRunConfiguration configuration, |
| PsiElement element, |
| ConfigurationContext context, |
| Ref<PsiElement> sourceElement) { |
| final Module module = AndroidUtils.getAndroidModule(context); |
| |
| if (module == null) { |
| return false; |
| } |
| sourceElement.set(element); |
| setupConfigurationModule(context, configuration); |
| |
| final TargetSelectionMode targetSelectionMode = AndroidUtils |
| .getDefaultTargetSelectionMode(module, AndroidTestRunConfigurationType.getInstance(), AndroidRunConfigurationType.getInstance()); |
| |
| if (targetSelectionMode != null) { |
| configuration.setTargetSelectionMode(targetSelectionMode); |
| } |
| return true; |
| } |
| |
| private static boolean isTestMethod(PsiMethod method) { |
| PsiClass testClass = method.getContainingClass(); |
| if (testClass != null && JUnitUtil.isTestClass(testClass)) { |
| return new JUnitUtil.TestMethodFilter(testClass).value(method); |
| } |
| return false; |
| } |
| |
| @Override |
| protected boolean setupConfigurationFromContext(AndroidTestRunConfiguration configuration, |
| ConfigurationContext context, |
| Ref<PsiElement> sourceElement) { |
| Module module = AndroidUtils.getAndroidModule(context); |
| if (module == null) { |
| return false; |
| } |
| |
| Location location = context.getLocation(); |
| |
| if (location == null) { |
| return false; |
| } |
| location = JavaExecutionUtil.stepIntoSingleClass(location); |
| |
| if (location == null) { |
| return false; |
| } |
| final PsiElement element = location.getPsiElement(); |
| |
| AndroidFacet facet = AndroidFacet.getInstance(module); |
| if (facet == null) { |
| return false; |
| } |
| |
| IdeaAndroidProject androidModel = facet.getAndroidModel(); |
| if (androidModel != null && !androidModel.getSelectedTestArtifactName().equals(AndroidProject.ARTIFACT_ANDROID_TEST)) { |
| // Only suggest the android test run configuration if it makes sense for the selected test artifact. |
| return false; |
| } |
| |
| setupInstrumentationTestRunner(configuration, facet); |
| if (setupAllInPackageConfiguration(configuration, element, context, sourceElement)) { |
| return true; |
| } |
| if (setupMethodConfiguration(configuration, element, context, sourceElement)) { |
| return true; |
| } |
| return setupClassConfiguration(configuration, element, context, sourceElement); |
| } |
| |
| private static void setupInstrumentationTestRunner(@NotNull AndroidTestRunConfiguration configuration, @NotNull AndroidFacet facet) { |
| configuration.INSTRUMENTATION_RUNNER_CLASS = StringUtil.notNullize(AndroidTestRunConfiguration.findInstrumentationRunner(facet)); |
| } |
| |
| @Override |
| public boolean isConfigurationFromContext(AndroidTestRunConfiguration configuration, ConfigurationContext context) { |
| Location location = context.getLocation(); |
| final Module contextModule = AndroidUtils.getAndroidModule(context); |
| |
| if (contextModule == null || location == null) { |
| return false; |
| } |
| location = JavaExecutionUtil.stepIntoSingleClass(location); |
| |
| if (location == null) { |
| return false; |
| } |
| final PsiElement element = location.getPsiElement(); |
| final PsiPackage psiPackage = JavaRuntimeConfigurationProducerBase.checkPackage(element); |
| final String packageName = psiPackage == null ? null : psiPackage.getQualifiedName(); |
| |
| final PsiClass elementClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, false); |
| final String className = elementClass == null ? null : elementClass.getQualifiedName(); |
| |
| final PsiMethod elementMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); |
| final String methodName = elementMethod == null ? null : elementMethod.getName(); |
| final Module moduleInConfig = configuration.getConfigurationModule().getModule(); |
| |
| if (!Comparing.equal(contextModule, moduleInConfig)) { |
| return false; |
| } |
| switch (configuration.TESTING_TYPE) { |
| case AndroidTestRunConfiguration.TEST_ALL_IN_MODULE: |
| return psiPackage != null && packageName.isEmpty(); |
| |
| case AndroidTestRunConfiguration.TEST_ALL_IN_PACKAGE: |
| return packageName != null && packageName.equals(configuration.PACKAGE_NAME); |
| |
| case AndroidTestRunConfiguration.TEST_CLASS: |
| return elementMethod == null && className != null && className.equals(configuration.CLASS_NAME); |
| |
| case AndroidTestRunConfiguration.TEST_METHOD: |
| return methodName != null && methodName.equals(configuration.METHOD_NAME) && |
| className != null && className.equals(configuration.CLASS_NAME); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) { |
| // If we decided the context is for an instrumentation test (see {@link #setupConfigurationFromContext}), it should replace |
| // other test configurations, as they won't work anyway. |
| return other.isProducedBy(JUnitConfigurationProducer.class); |
| } |
| } |