• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ide.eclipse.adt.internal.launch.junit;
18 
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.AdtConstants;
21 import com.android.ide.eclipse.adt.internal.launch.AndroidLaunch;
22 import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration;
23 import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchController;
24 import com.android.ide.eclipse.adt.internal.launch.IAndroidLaunchAction;
25 import com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate;
26 import com.android.ide.eclipse.adt.internal.launch.LaunchMessages;
27 import com.android.ide.eclipse.adt.internal.launch.junit.runtime.AndroidJUnitLaunchInfo;
28 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
29 import com.android.sdklib.SdkConstants;
30 import com.android.sdklib.xml.ManifestData;
31 import com.android.sdklib.xml.ManifestData.Instrumentation;
32 
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IProject;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.IProgressMonitor;
37 import org.eclipse.debug.core.ILaunchConfiguration;
38 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
39 import org.eclipse.jdt.core.IJavaElement;
40 import org.eclipse.jdt.core.JavaCore;
41 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
42 import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
43 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
44 
45 /**
46  * Run configuration that can execute JUnit tests on an Android platform.
47  * <p/>
48  * Will deploy apps on target Android platform by reusing functionality from ADT
49  * LaunchConfigDelegate, and then run JUnits tests by reusing functionality from JDT
50  * JUnitLaunchConfigDelegate.
51  */
52 @SuppressWarnings("restriction")
53 public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
54 
55     /** Launch config attribute that stores instrumentation runner. */
56     static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$
57 
58     private static final String EMPTY_STRING = ""; //$NON-NLS-1$
59 
60     @Override
doLaunch(final ILaunchConfiguration configuration, final String mode, IProgressMonitor monitor, IProject project, final AndroidLaunch androidLaunch, AndroidLaunchConfiguration config, AndroidLaunchController controller, IFile applicationPackage, ManifestData manifestData)61     protected void doLaunch(final ILaunchConfiguration configuration, final String mode,
62             IProgressMonitor monitor, IProject project, final AndroidLaunch androidLaunch,
63             AndroidLaunchConfiguration config, AndroidLaunchController controller,
64             IFile applicationPackage, ManifestData manifestData) {
65 
66         String runner = getRunner(project, configuration, manifestData);
67         if (runner == null) {
68             AdtPlugin.displayError(LaunchMessages.LaunchDialogTitle,
69                     String.format(LaunchMessages.AndroidJUnitDelegate_NoRunnerMsg_s,
70                             project.getName()));
71             androidLaunch.stopLaunch();
72             return;
73         }
74         // get the target app's package
75         String targetAppPackage = getTargetPackage(manifestData, runner);
76         if (targetAppPackage == null) {
77             AdtPlugin.displayError(LaunchMessages.LaunchDialogTitle,
78                     String.format(LaunchMessages.AndroidJUnitDelegate_NoTargetMsg_3s,
79                             project.getName(), runner, SdkConstants.FN_ANDROID_MANIFEST_XML));
80             androidLaunch.stopLaunch();
81             return;
82         }
83         String testAppPackage = manifestData.getPackage();
84         AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project,
85                 testAppPackage, runner);
86         junitLaunchInfo.setTestClass(getTestClass(configuration));
87         junitLaunchInfo.setTestPackage(getTestPackage(configuration));
88         junitLaunchInfo.setTestMethod(getTestMethod(configuration));
89         junitLaunchInfo.setLaunch(androidLaunch);
90         IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(junitLaunchInfo);
91 
92         controller.launch(project, mode, applicationPackage, testAppPackage, targetAppPackage,
93                 manifestData.getDebuggable(), manifestData.getMinSdkVersionString(),
94                 junitLaunch, config, androidLaunch, monitor);
95     }
96 
97     /**
98      * Get the target Android application's package for the given instrumentation runner, or
99      * <code>null</code> if it could not be found.
100      *
101      * @param manifestParser the {@link ManifestData} for the test project
102      * @param runner the instrumentation runner class name
103      * @return the target package or <code>null</code>
104      */
getTargetPackage(ManifestData manifestParser, String runner)105     private String getTargetPackage(ManifestData manifestParser, String runner) {
106         for (Instrumentation instr : manifestParser.getInstrumentations()) {
107             if (instr.getName().equals(runner)) {
108                 return instr.getTargetPackage();
109             }
110         }
111         return null;
112     }
113 
114     /**
115      * Returns the test package stored in the launch configuration, or <code>null</code> if not
116      * specified.
117      *
118      * @param configuration the {@link ILaunchConfiguration} to retrieve the test package info from
119      * @return the test package or <code>null</code>.
120      */
getTestPackage(ILaunchConfiguration configuration)121     private String getTestPackage(ILaunchConfiguration configuration) {
122         // try to retrieve a package name from the JUnit container attribute
123         String containerHandle = getStringLaunchAttribute(
124                 JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, configuration);
125         if (containerHandle != null && containerHandle.length() > 0) {
126             IJavaElement element = JavaCore.create(containerHandle);
127             // containerHandle could be a IProject, check if its a java package
128             if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
129                 return element.getElementName();
130             }
131         }
132         return null;
133     }
134 
135     /**
136      * Returns the test class stored in the launch configuration.
137      *
138      * @param configuration the {@link ILaunchConfiguration} to retrieve the test class info from
139      * @return the test class. <code>null</code> if not specified.
140      */
getTestClass(ILaunchConfiguration configuration)141     private String getTestClass(ILaunchConfiguration configuration) {
142         return getStringLaunchAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
143                 configuration);
144     }
145 
146     /**
147      * Returns the test method stored in the launch configuration.
148      *
149      * @param configuration the {@link ILaunchConfiguration} to retrieve the test method info from
150      * @return the test method. <code>null</code> if not specified.
151      */
getTestMethod(ILaunchConfiguration configuration)152     private String getTestMethod(ILaunchConfiguration configuration) {
153         return getStringLaunchAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME,
154                 configuration);
155     }
156 
157     /**
158      * Gets a instrumentation runner for the launch.
159      * <p/>
160      * If a runner is stored in the given <code>configuration</code>, will return that.
161      * Otherwise, will try to find the first valid runner for the project.
162      * If a runner can still not be found, will return <code>null</code>, and will log an error
163      * to the console.
164      *
165      * @param project the {@link IProject} for the app
166      * @param configuration the {@link ILaunchConfiguration} for the launch
167      * @param manifestData the {@link ManifestData} for the project
168      *
169      * @return <code>null</code> if no instrumentation runner can be found, otherwise return
170      *   the fully qualified runner name.
171      */
getRunner(IProject project, ILaunchConfiguration configuration, ManifestData manifestData)172     private String getRunner(IProject project, ILaunchConfiguration configuration,
173             ManifestData manifestData) {
174         try {
175             String runner = getRunnerFromConfig(configuration);
176             if (runner != null) {
177                 return runner;
178             }
179             final InstrumentationRunnerValidator instrFinder = new InstrumentationRunnerValidator(
180                     BaseProjectHelper.getJavaProject(project), manifestData);
181             runner = instrFinder.getValidInstrumentationTestRunner();
182             if (runner != null) {
183                 AdtPlugin.printErrorToConsole(project, String.format(
184                         LaunchMessages.AndroidJUnitDelegate_NoRunnerConfigMsg_s, runner));
185                 return runner;
186             }
187             AdtPlugin.printErrorToConsole(project, String.format(
188                     LaunchMessages.AndroidJUnitDelegate_NoRunnerConsoleMsg_4s,
189                     project.getName(),
190                     SdkConstants.CLASS_INSTRUMENTATION_RUNNER,
191                     AdtConstants.LIBRARY_TEST_RUNNER,
192                     SdkConstants.FN_ANDROID_MANIFEST_XML));
193             return null;
194         } catch (CoreException e) {
195             AdtPlugin.log(e, "Error when retrieving instrumentation info"); //$NON-NLS-1$
196         }
197 
198         return null;
199     }
200 
getRunnerFromConfig(ILaunchConfiguration configuration)201     private String getRunnerFromConfig(ILaunchConfiguration configuration) throws CoreException {
202         return getStringLaunchAttribute(ATTR_INSTR_NAME, configuration);
203     }
204 
205     /**
206      * Helper method to retrieve a string attribute from the launch configuration
207      *
208      * @param attributeName name of the launch attribute
209      * @param configuration the {@link ILaunchConfiguration} to retrieve the attribute from
210      * @return the attribute's value. <code>null</code> if not found.
211      */
getStringLaunchAttribute(String attributeName, ILaunchConfiguration configuration)212     private String getStringLaunchAttribute(String attributeName,
213             ILaunchConfiguration configuration) {
214         try {
215             String attrValue = configuration.getAttribute(attributeName, EMPTY_STRING);
216             if (attrValue.length() < 1) {
217                 return null;
218             }
219             return attrValue;
220         } catch (CoreException e) {
221             AdtPlugin.log(e, String.format("Error when retrieving launch info %1$s",  //$NON-NLS-1$
222                     attributeName));
223         }
224         return null;
225     }
226 
227     /**
228      * Helper method to set JUnit-related attributes expected by JDT JUnit runner
229      *
230      * @param config the launch configuration to modify
231      */
setJUnitDefaults(ILaunchConfigurationWorkingCopy config)232     static void setJUnitDefaults(ILaunchConfigurationWorkingCopy config) {
233         // set the test runner to JUnit3 to placate JDT JUnit runner logic
234         config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND,
235                 TestKindRegistry.JUNIT3_TEST_KIND_ID);
236     }
237 }
238