| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php |
| * |
| * 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.android.ide.eclipse.adt.internal.launch.junit; |
| |
| import com.android.SdkConstants; |
| import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner.TestSize; |
| import com.android.ide.common.xml.ManifestData; |
| import com.android.ide.common.xml.ManifestData.Instrumentation; |
| import com.android.ide.eclipse.adt.AdtConstants; |
| import com.android.ide.eclipse.adt.AdtPlugin; |
| import com.android.ide.eclipse.adt.internal.launch.AndroidLaunch; |
| import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration; |
| import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchController; |
| import com.android.ide.eclipse.adt.internal.launch.IAndroidLaunchAction; |
| import com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate; |
| import com.android.ide.eclipse.adt.internal.launch.LaunchMessages; |
| import com.android.ide.eclipse.adt.internal.launch.junit.runtime.AndroidJUnitLaunchInfo; |
| import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants; |
| import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; |
| import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
| import org.eclipse.swt.widgets.Display; |
| |
| /** |
| * Run configuration that can execute JUnit tests on an Android platform. |
| * <p/> |
| * Will deploy apps on target Android platform by reusing functionality from ADT |
| * LaunchConfigDelegate, and then run JUnits tests by reusing functionality from JDT |
| * JUnitLaunchConfigDelegate. |
| */ |
| @SuppressWarnings("restriction") |
| public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { |
| |
| /** Launch config attribute that stores instrumentation runner. */ |
| static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$ |
| |
| /** Launch config attribute that stores the test size annotation to run. */ |
| static final String ATTR_TEST_SIZE = AdtPlugin.PLUGIN_ID + ".testSize"; //$NON-NLS-1$ |
| |
| private static final String EMPTY_STRING = ""; //$NON-NLS-1$ |
| |
| @Override |
| protected void doLaunch(final ILaunchConfiguration configuration, final String mode, |
| final IProgressMonitor monitor, final IProject project, |
| final AndroidLaunch androidLaunch, final AndroidLaunchConfiguration config, |
| final AndroidLaunchController controller, final IFile applicationPackage, |
| final ManifestData manifestData) { |
| |
| String runner = getRunner(project, configuration, manifestData); |
| if (runner == null) { |
| AdtPlugin.displayError(LaunchMessages.LaunchDialogTitle, |
| String.format(LaunchMessages.AndroidJUnitDelegate_NoRunnerMsg_s, |
| project.getName())); |
| androidLaunch.stopLaunch(); |
| return; |
| } |
| // get the target app's package |
| final String targetAppPackage = getTargetPackage(manifestData, runner); |
| if (targetAppPackage == null) { |
| AdtPlugin.displayError(LaunchMessages.LaunchDialogTitle, |
| String.format(LaunchMessages.AndroidJUnitDelegate_NoTargetMsg_3s, |
| project.getName(), runner, SdkConstants.FN_ANDROID_MANIFEST_XML)); |
| androidLaunch.stopLaunch(); |
| return; |
| } |
| final String testAppPackage = manifestData.getPackage(); |
| AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project, |
| testAppPackage, runner); |
| junitLaunchInfo.setTestClass(getTestClass(configuration)); |
| junitLaunchInfo.setTestPackage(getTestPackage(configuration)); |
| junitLaunchInfo.setTestMethod(getTestMethod(configuration)); |
| junitLaunchInfo.setLaunch(androidLaunch); |
| junitLaunchInfo.setTestSize(getTestSize(configuration)); |
| final IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(junitLaunchInfo); |
| |
| // launch on a separate thread if currently on the display thread |
| if (Display.getCurrent() != null) { |
| Job job = new Job("Junit Launch") { //$NON-NLS-1$ |
| @Override |
| protected IStatus run(IProgressMonitor m) { |
| controller.launch(project, mode, applicationPackage, testAppPackage, |
| targetAppPackage, manifestData.getDebuggable(), |
| manifestData.getMinSdkVersionString(), |
| junitLaunch, config, androidLaunch, monitor); |
| return Status.OK_STATUS; |
| } |
| }; |
| job.setPriority(Job.INTERACTIVE); |
| job.schedule(); |
| } else { |
| controller.launch(project, mode, applicationPackage, testAppPackage, targetAppPackage, |
| manifestData.getDebuggable(), manifestData.getMinSdkVersionString(), |
| junitLaunch, config, androidLaunch, monitor); |
| } |
| } |
| |
| /** |
| * Get the target Android application's package for the given instrumentation runner, or |
| * <code>null</code> if it could not be found. |
| * |
| * @param manifestParser the {@link ManifestData} for the test project |
| * @param runner the instrumentation runner class name |
| * @return the target package or <code>null</code> |
| */ |
| private String getTargetPackage(ManifestData manifestParser, String runner) { |
| for (Instrumentation instr : manifestParser.getInstrumentations()) { |
| if (instr.getName().equals(runner)) { |
| return instr.getTargetPackage(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the test package stored in the launch configuration, or <code>null</code> if not |
| * specified. |
| * |
| * @param configuration the {@link ILaunchConfiguration} to retrieve the test package info from |
| * @return the test package or <code>null</code>. |
| */ |
| private String getTestPackage(ILaunchConfiguration configuration) { |
| // try to retrieve a package name from the JUnit container attribute |
| String containerHandle = getStringLaunchAttribute( |
| JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, configuration); |
| if (containerHandle != null && containerHandle.length() > 0) { |
| IJavaElement element = JavaCore.create(containerHandle); |
| // containerHandle could be a IProject, check if its a java package |
| if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { |
| return element.getElementName(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the test class stored in the launch configuration. |
| * |
| * @param configuration the {@link ILaunchConfiguration} to retrieve the test class info from |
| * @return the test class. <code>null</code> if not specified. |
| */ |
| private String getTestClass(ILaunchConfiguration configuration) { |
| return getStringLaunchAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, |
| configuration); |
| } |
| |
| /** |
| * Returns the test method stored in the launch configuration. |
| * |
| * @param configuration the {@link ILaunchConfiguration} to retrieve the test method info from |
| * @return the test method. <code>null</code> if not specified. |
| */ |
| private String getTestMethod(ILaunchConfiguration configuration) { |
| return getStringLaunchAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, |
| configuration); |
| } |
| |
| /** |
| * Returns the test sizes to run as saved in the launch configuration. |
| * @return {@link TestSize} if only tests of specific sizes should be run, |
| * null if all tests should be run |
| */ |
| private TestSize getTestSize(ILaunchConfiguration configuration) { |
| String testSizeAnnotation = getStringLaunchAttribute( |
| AndroidJUnitLaunchConfigDelegate.ATTR_TEST_SIZE, |
| configuration); |
| if (AndroidJUnitLaunchConfigurationTab.SMALL_TEST_ANNOTATION.equals( |
| testSizeAnnotation)){ |
| return TestSize.SMALL; |
| } else if (AndroidJUnitLaunchConfigurationTab.MEDIUM_TEST_ANNOTATION.equals( |
| testSizeAnnotation)) { |
| return TestSize.MEDIUM; |
| } else if (AndroidJUnitLaunchConfigurationTab.LARGE_TEST_ANNOTATION.equals( |
| testSizeAnnotation)) { |
| return TestSize.LARGE; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Gets a instrumentation runner for the launch. |
| * <p/> |
| * If a runner is stored in the given <code>configuration</code>, will return that. |
| * Otherwise, will try to find the first valid runner for the project. |
| * If a runner can still not be found, will return <code>null</code>, and will log an error |
| * to the console. |
| * |
| * @param project the {@link IProject} for the app |
| * @param configuration the {@link ILaunchConfiguration} for the launch |
| * @param manifestData the {@link ManifestData} for the project |
| * |
| * @return <code>null</code> if no instrumentation runner can be found, otherwise return |
| * the fully qualified runner name. |
| */ |
| private String getRunner(IProject project, ILaunchConfiguration configuration, |
| ManifestData manifestData) { |
| try { |
| String runner = getRunnerFromConfig(configuration); |
| if (runner != null) { |
| return runner; |
| } |
| final InstrumentationRunnerValidator instrFinder = new InstrumentationRunnerValidator( |
| BaseProjectHelper.getJavaProject(project), manifestData); |
| runner = instrFinder.getValidInstrumentationTestRunner(); |
| if (runner != null) { |
| AdtPlugin.printErrorToConsole(project, String.format( |
| LaunchMessages.AndroidJUnitDelegate_NoRunnerConfigMsg_s, runner)); |
| return runner; |
| } |
| AdtPlugin.printErrorToConsole(project, String.format( |
| LaunchMessages.AndroidJUnitDelegate_NoRunnerConsoleMsg_4s, |
| project.getName(), |
| SdkConstants.CLASS_INSTRUMENTATION_RUNNER, |
| AdtConstants.LIBRARY_TEST_RUNNER, |
| SdkConstants.FN_ANDROID_MANIFEST_XML)); |
| return null; |
| } catch (CoreException e) { |
| AdtPlugin.log(e, "Error when retrieving instrumentation info"); //$NON-NLS-1$ |
| } |
| |
| return null; |
| } |
| |
| private String getRunnerFromConfig(ILaunchConfiguration configuration) { |
| return getStringLaunchAttribute(ATTR_INSTR_NAME, configuration); |
| } |
| |
| /** |
| * Helper method to retrieve a string attribute from the launch configuration |
| * |
| * @param attributeName name of the launch attribute |
| * @param configuration the {@link ILaunchConfiguration} to retrieve the attribute from |
| * @return the attribute's value. <code>null</code> if not found. |
| */ |
| private String getStringLaunchAttribute(String attributeName, |
| ILaunchConfiguration configuration) { |
| try { |
| String attrValue = configuration.getAttribute(attributeName, EMPTY_STRING); |
| if (attrValue.length() < 1) { |
| return null; |
| } |
| return attrValue; |
| } catch (CoreException e) { |
| AdtPlugin.log(e, String.format("Error when retrieving launch info %1$s", //$NON-NLS-1$ |
| attributeName)); |
| } |
| return null; |
| } |
| |
| /** |
| * Helper method to set JUnit-related attributes expected by JDT JUnit runner |
| * |
| * @param config the launch configuration to modify |
| */ |
| static void setJUnitDefaults(ILaunchConfigurationWorkingCopy config) { |
| // set the test runner to JUnit3 to placate JDT JUnit runner logic |
| config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, |
| TestKindRegistry.JUNIT3_TEST_KIND_ID); |
| } |
| } |