From a451f67177ef987a1c23313537697b4e249cf9b8 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Tue, 24 Mar 2009 20:54:44 -0700 Subject: [PATCH] Automated import from //branches/master/...@141783,141783 --- .../junit/AndroidJUnitLaunchConfigDelegate.java | 138 +++++++------------- .../junit/AndroidJUnitLaunchConfigurationTab.java | 42 +++--- .../launch/junit/AndroidJUnitLaunchShortcut.java | 39 ++---- .../junit/InstrumentationRunnerValidator.java | 145 +++++++++++++++++++++ 4 files changed, 225 insertions(+), 139 deletions(-) create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java index a624b0001..fa8e4b01a 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java @@ -32,23 +32,21 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; -import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants; import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; /** - * Run configuration that can execute JUnit tests on an Android platform + * Run configuration that can execute JUnit tests on an Android platform. *

- * Will deploy apps on target Android platform by reusing functionality from ADT - * LaunchConfigDelegate, and then run JUnits tests by reusing functionality from JDT + * 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") //$NON-NLS-1$ +@SuppressWarnings("restriction") public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { - /** Launch config attribute that stores instrumentation runner */ + /** Launch config attribute that stores instrumentation runner. */ static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$ - static final String INSTRUMENTATION_OK = null; private static final String EMPTY_STRING = ""; //$NON-NLS-1$ @Override @@ -58,7 +56,7 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { IFile applicationPackage, AndroidManifestParser manifestParser) { String testPackage = manifestParser.getPackage(); - String runner = getRunnerFromConfig(configuration); + String runner = getRunner(project, configuration, manifestParser); if (runner == null) { AdtPlugin.displayError("Android Launch", "An instrumention test runner is not specified!"); @@ -72,14 +70,51 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), junitLaunch, config, androidLaunch, monitor); } - - private String getRunnerFromConfig(ILaunchConfiguration configuration) { - String runner = EMPTY_STRING; + + /** + * Gets a instrumentation runner for the launch. + *

+ * If a runner is stored in the given configuration, 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 null. + * + * @param project the {@link IProject} for the app + * @param configuration the {@link ILaunchConfiguration} for the launch + * @param manifestParser the {@link AndroidManifestParser} for the project + * + * @return null if no instrumentation runner can be found, otherwise return + * the fully qualified runner name. + */ + private String getRunner(IProject project, ILaunchConfiguration configuration, + AndroidManifestParser manifestParser) { try { - runner = configuration.getAttribute(ATTR_INSTR_NAME, EMPTY_STRING); + String runner = getRunnerFromConfig(configuration); + if (runner != null) { + return runner; + } + final InstrumentationRunnerValidator instrFinder = new InstrumentationRunnerValidator( + BaseProjectHelper.getJavaProject(project), manifestParser); + runner = instrFinder.getValidInstrumentationTestRunner(); + if (runner != null) { + AdtPlugin.printErrorToConsole(project, + String.format("Warning: No instrumentation runner found for the launch, " + + "using %1$s", runner)); + return runner; + } + AdtPlugin.printErrorToConsole(project, + String.format("ERROR: Application does not specify a %1$s instrumentation or does not declare uses-library %2$s", + AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, + AndroidConstants.LIBRARY_TEST_RUNNER)); + return null; } catch (CoreException e) { - AdtPlugin.log(e, "Error when retrieving instrumentation info from launch config"); //$NON-NLS-1$ + AdtPlugin.log(e, "Error when retrieving instrumentation info"); //$NON-NLS-1$ } + return null; + + } + + private String getRunnerFromConfig(ILaunchConfiguration configuration) throws CoreException { + String runner = configuration.getAttribute(ATTR_INSTR_NAME, EMPTY_STRING); if (runner.length() < 1) { return null; } @@ -87,31 +122,6 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { } /** - * Helper method to return the set of instrumentations for the Android project - * - * @param project the {@link IProject} to get instrumentations for - * @return null if error occurred parsing instrumentations, otherwise returns array of - * instrumentation class names - */ - static String[] getInstrumentationsForProject(IProject project) { - if (project != null) { - try { - // parse the manifest for the list of instrumentations - AndroidManifestParser manifestParser = AndroidManifestParser.parse( - BaseProjectHelper.getJavaProject(project), null /* errorListener */, - true /* gatherData */, false /* markErrors */); - if (manifestParser != null) { - return manifestParser.getInstrumentations(); - } - } catch (CoreException e) { - AdtPlugin.log(e, "%s: Error parsing AndroidManifest.xml", //$NON-NLS-1$ - project.getName()); - } - } - return null; - } - - /** * Helper method to set JUnit-related attributes expected by JDT JUnit runner * * @param config the launch configuration to modify @@ -121,56 +131,4 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, TestKindRegistry.JUNIT3_TEST_KIND_ID); } - - /** - * Helper method to determine if specified instrumentation can be used as a test runner - * - * @param project the {@link IJavaProject} to validate - * @param instrumentation the instrumentation class name to validate - * @return INSTRUMENTATION_OK if valid, otherwise returns error message - */ - static String validateInstrumentationRunner(IJavaProject project, String instrumentation) { - AndroidManifestParser manifestParser; - try { - manifestParser = AndroidManifestParser.parse( - project, null /* errorListener */, - true /* gatherData */, false /* markErrors */); - // check if this instrumentation is the standard test runner - if (!instrumentation.equals(AndroidConstants.CLASS_INSTRUMENTATION_RUNNER)) { - // check if it extends the standard test runner - String result = BaseProjectHelper.testClassForManifest(project, - instrumentation, AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, true); - if (result != BaseProjectHelper.TEST_CLASS_OK) { - return String.format("The instrumentation runner must be of type %s", - AndroidConstants.CLASS_INSTRUMENTATION_RUNNER); - } - } - if (!hasTestRunnerLibrary(manifestParser)) { - return String.format("%s does not not use the %s library", - project.getProject().getName(), AndroidConstants.LIBRARY_TEST_RUNNER); - } - } catch (CoreException e) { - String err = String.format("Error parsing AndroidManifest for %s", - project.getProject().getName()); - AdtPlugin.log(e, err); - return err; - } - return INSTRUMENTATION_OK; - } - - /** - * Helper method to determine if given manifest has a AndroidConstants.LIBRARY_TEST_RUNNER - * library reference - * - * @param manifestParser the {@link AndroidManifestParser} to search - * @return true if test runner library found, false otherwise - */ - static boolean hasTestRunnerLibrary(AndroidManifestParser manifestParser) { - for (String lib : manifestParser.getUsesLibraries()) { - if (lib.equals(AndroidConstants.LIBRARY_TEST_RUNNER)) { - return true; - } - } - return false; - } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java index aa59a5157..eb5748269 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java @@ -118,7 +118,9 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private Image mTabIcon = null; private Combo mInstrumentationCombo; private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + private static final String TAG = "AndroidJUnitLaunchConfigurationTab"; //$NON-NLS-1$ private String[] mInstrumentations = null; + private InstrumentationRunnerValidator mInstrValidator = null; private ProjectChooserHelper mProjectChooserHelper; /* (non-Javadoc) @@ -349,7 +351,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat break; } } - } + } } catch (CoreException ce) { // ignore } @@ -454,7 +456,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat mapResources(config); } catch (CoreException e) { // TODO: does the real error need to be extracted out of CoreException - AdtPlugin.log(e, "Error occurred saving configuration"); + AdtPlugin.log(e, "Error occurred saving configuration"); //$NON-NLS-1$ } AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config); @@ -486,7 +488,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat public Image getImage() { // reuse icon from the Android App Launch config tab if (mTabIcon == null) { - mTabIcon= AdtPlugin.getImageLoader().loadImage(MainLaunchConfigTab.LAUNCH_TAB_IMAGE, + mTabIcon = AdtPlugin.getImageLoader().loadImage(MainLaunchConfigTab.LAUNCH_TAB_IMAGE, null); } return mTabIcon; @@ -514,7 +516,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat setErrorMessage(e.getMessage()); return; } catch (InvocationTargetException e) { - AdtPlugin.log(e.getTargetException(), "Error finding test types"); + AdtPlugin.log(e.getTargetException(), "Error finding test types"); //$NON-NLS-1$ return; } finally { mTestRadioButton.setSelection(radioSetting[0]); @@ -675,10 +677,10 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat return; } } catch (CoreException e) { - AdtPlugin.log(e, "validatePage failed"); + AdtPlugin.log(e, "validatePage failed"); //$NON-NLS-1$ } - validateInstrumentation(javaProject); + validateInstrumentation(); } private void validateJavaProject(IJavaProject javaProject) { @@ -688,19 +690,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } } - private void validateInstrumentation(IJavaProject javaProject) { - if (mInstrumentations == null || mInstrumentations.length < 1) { - setErrorMessage("Specified project has no defined instrumentations"); - return; - } + private void validateInstrumentation() { String instrumentation = getSelectedInstrumentation(); if (instrumentation == null) { - setErrorMessage("Instrumentation not specified"); + setErrorMessage("Instrumentation runner not specified"); return; } - String result = AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner( - javaProject, instrumentation); - if (result != AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) { + String result = mInstrValidator.validateInstrumentationRunner(instrumentation); + if (result != InstrumentationRunnerValidator.INSTRUMENTATION_OK) { setErrorMessage(result); return; } @@ -949,14 +946,15 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat /** * Loads the UI with the instrumentations of the specified project, and stores the - * activities in mActivities. - *

- * First activity is selected by default if present. + * instrumentations in mInstrumentations. * * @param project the {@link IProject} to load the instrumentations from. */ private void loadInstrumentations(IProject project) { - mInstrumentations = AndroidJUnitLaunchConfigDelegate.getInstrumentationsForProject(project); + try { + mInstrValidator = new InstrumentationRunnerValidator(project); + mInstrumentations = (mInstrValidator == null ? null : + mInstrValidator.getInstrumentations()); if (mInstrumentations != null) { mInstrumentationCombo.removeAll(); for (String instrumentation : mInstrumentations) { @@ -966,9 +964,13 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat // config object. return; } - + } catch (CoreException e) { + AdtPlugin.logAndPrintError(e, TAG, "ERROR: Failed to get instrumentations for %1$s", + project.getName()); + } // if we reach this point, either project is null, or we got an exception during // the parsing. In either case, we empty the instrumentation list. + mInstrValidator = null; mInstrumentations = null; mInstrumentationCombo.removeAll(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java index 30649e2e8..f06f7eb4c 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java @@ -16,10 +16,6 @@ package com.android.ide.eclipse.adt.launch.junit; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.jdt.core.IJavaElement; @@ -43,33 +39,18 @@ public class AndroidJUnitLaunchShortcut extends JUnitLaunchShortcut { protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement element) throws CoreException { ILaunchConfigurationWorkingCopy config = super.createLaunchConfiguration(element); - IProject project = element.getResource().getProject(); - String[] instrumentations = - AndroidJUnitLaunchConfigDelegate.getInstrumentationsForProject(project); - boolean runnerFound = false; - if (instrumentations != null) { - // just pick the first valid runner - for (String instr : instrumentations) { - if (AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner( - element.getJavaProject(), instr) == - AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) { - - config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, - instr); - runnerFound = true; - break; - } - } - } - if (!runnerFound) { - // TODO: put this in a string properties - String msg = String.format("ERROR: Application does not specify a %s instrumentation or does not declare uses-library %s", - AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, - AndroidConstants.LIBRARY_TEST_RUNNER); - AdtPlugin.printErrorToConsole(project, msg); + // just get first valid instrumentation runner + String instrumentation = new InstrumentationRunnerValidator(element.getJavaProject()). + getValidInstrumentationTestRunner(); + if (instrumentation != null) { + config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, + instrumentation); } - AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config); + // if a valid runner is not found, rely on launch delegate to log error. + // This method is called without explicit user action to launch Android JUnit, so avoid + // logging an error here. + AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config); return config; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java new file mode 100644 index 000000000..f22fc7cda --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java @@ -0,0 +1,145 @@ +/* + * 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.launch.junit; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.common.AndroidConstants; +import com.android.ide.eclipse.common.project.AndroidManifestParser; +import com.android.ide.eclipse.common.project.BaseProjectHelper; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; + +/** + * Provides validation for Android instrumentation test runner + */ +class InstrumentationRunnerValidator { + private final IJavaProject mJavaProject; + private String[] mInstrumentations = null; + private boolean mHasRunnerLibrary = false; + + static final String INSTRUMENTATION_OK = null; + + /** + * Initializes the InstrumentationRunnerValidator. + * + * @param javaProject the {@link IJavaProject} for the Android project to validate + */ + InstrumentationRunnerValidator(IJavaProject javaProject) { + mJavaProject = javaProject; + try { + AndroidManifestParser manifestParser = AndroidManifestParser.parse(javaProject, + null /* errorListener */, true /* gatherData */, false /* markErrors */); + init(manifestParser); + } catch (CoreException e) { + AdtPlugin.printErrorToConsole(javaProject.getProject(), "ERROR: Failed to parse %1$s", + AndroidConstants.FN_ANDROID_MANIFEST); + } + } + + /** + * Initializes the InstrumentationRunnerValidator. + * + * @param project the {@link IProject} for the Android project to validate + * @throws CoreException if a fatal error occurred in initialization + */ + InstrumentationRunnerValidator(IProject project) throws CoreException { + this(BaseProjectHelper.getJavaProject(project)); + } + + /** + * Initializes the InstrumentationRunnerValidator with an existing {@link AndroidManifestParser} + * + * @param javaProject the {@link IJavaProject} for the Android project to validate + * @param manifestParser the {@link AndroidManifestParser} for the Android project + */ + InstrumentationRunnerValidator(IJavaProject javaProject, AndroidManifestParser manifestParser) { + mJavaProject = javaProject; + init(manifestParser); + } + + private void init(AndroidManifestParser manifestParser) { + mInstrumentations = manifestParser.getInstrumentations(); + mHasRunnerLibrary = hasTestRunnerLibrary(manifestParser); + } + + /** + * Helper method to determine if given manifest has a AndroidConstants.LIBRARY_TEST_RUNNER + * library reference + * + * @param manifestParser the {@link AndroidManifestParser} to search + * @return true if test runner library found, false otherwise + */ + private boolean hasTestRunnerLibrary(AndroidManifestParser manifestParser) { + for (String lib : manifestParser.getUsesLibraries()) { + if (lib.equals(AndroidConstants.LIBRARY_TEST_RUNNER)) { + return true; + } + } + return false; + } + + /** + * Return the set of instrumentations for the Android project. + * + * @return nullnull if no valid + * instrumentation can be found. + */ + String getValidInstrumentationTestRunner() { + for (String instrumentation : getInstrumentations()) { + if (validateInstrumentationRunner(instrumentation) == INSTRUMENTATION_OK) { + return instrumentation; + } + } + return null; + } + + /** + * Helper method to determine if specified instrumentation can be used as a test runner + * + * @param instrumentation the instrumentation class name to validate. Assumes this + * instrumentation is one of {@link #getInstrumentations()} + * @return INSTRUMENTATION_OK if valid, otherwise returns error message + */ + String validateInstrumentationRunner(String instrumentation) { + if (!mHasRunnerLibrary) { + return String.format("The application does not declare uses-library %1$s", + AndroidConstants.LIBRARY_TEST_RUNNER); + } + // check if this instrumentation is the standard test runner + if (!instrumentation.equals(AndroidConstants.CLASS_INSTRUMENTATION_RUNNER)) { + // check if it extends the standard test runner + String result = BaseProjectHelper.testClassForManifest(mJavaProject, + instrumentation, AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, true); + if (result != BaseProjectHelper.TEST_CLASS_OK) { + return String.format("The instrumentation runner must be of type %s", + AndroidConstants.CLASS_INSTRUMENTATION_RUNNER); + } + } + return INSTRUMENTATION_OK; + } +} -- 2.11.0