Automated import from //branches/master/...@141783,141783

This commit is contained in:
Brett Chabot
2009-03-24 20:54:44 -07:00
committed by The Android Open Source Project
parent 3e6efddf28
commit 6dc9883c6e
4 changed files with 225 additions and 139 deletions

View File

@@ -32,23 +32,21 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; 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.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; 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.
* <p/> * <p/>
* Will deploy apps on target Android platform by reusing functionality from ADT * Will deploy apps on target Android platform by reusing functionality from ADT
* LaunchConfigDelegate, and then run JUnits tests by reusing functionality from JDT * LaunchConfigDelegate, and then run JUnits tests by reusing functionality from JDT
* JUnitLaunchConfigDelegate. * JUnitLaunchConfigDelegate.
*/ */
@SuppressWarnings("restriction") //$NON-NLS-1$ @SuppressWarnings("restriction")
public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { 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 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$ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
@Override @Override
@@ -58,7 +56,7 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
IFile applicationPackage, AndroidManifestParser manifestParser) { IFile applicationPackage, AndroidManifestParser manifestParser) {
String testPackage = manifestParser.getPackage(); String testPackage = manifestParser.getPackage();
String runner = getRunnerFromConfig(configuration); String runner = getRunner(project, configuration, manifestParser);
if (runner == null) { if (runner == null) {
AdtPlugin.displayError("Android Launch", AdtPlugin.displayError("Android Launch",
"An instrumention test runner is not specified!"); "An instrumention test runner is not specified!");
@@ -72,45 +70,57 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(),
junitLaunch, config, androidLaunch, monitor); junitLaunch, config, androidLaunch, monitor);
} }
private String getRunnerFromConfig(ILaunchConfiguration configuration) { /**
String runner = EMPTY_STRING; * 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>.
*
* @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 <code>null</code> if no instrumentation runner can be found, otherwise return
* the fully qualified runner name.
*/
private String getRunner(IProject project, ILaunchConfiguration configuration,
AndroidManifestParser manifestParser) {
try { 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) { } 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) { if (runner.length() < 1) {
return null; return null;
} }
return runner; return runner;
} }
/**
* 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 * Helper method to set JUnit-related attributes expected by JDT JUnit runner
* *
@@ -121,56 +131,4 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND,
TestKindRegistry.JUNIT3_TEST_KIND_ID); 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 <code>INSTRUMENTATION_OK</code> 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 <code>AndroidConstants.LIBRARY_TEST_RUNNER
* </code> 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;
}
} }

View File

@@ -118,7 +118,9 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
private Image mTabIcon = null; private Image mTabIcon = null;
private Combo mInstrumentationCombo; private Combo mInstrumentationCombo;
private static final String EMPTY_STRING = ""; //$NON-NLS-1$ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final String TAG = "AndroidJUnitLaunchConfigurationTab"; //$NON-NLS-1$
private String[] mInstrumentations = null; private String[] mInstrumentations = null;
private InstrumentationRunnerValidator mInstrValidator = null;
private ProjectChooserHelper mProjectChooserHelper; private ProjectChooserHelper mProjectChooserHelper;
/* (non-Javadoc) /* (non-Javadoc)
@@ -349,7 +351,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
break; break;
} }
} }
} }
} catch (CoreException ce) { } catch (CoreException ce) {
// ignore // ignore
} }
@@ -454,7 +456,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
mapResources(config); mapResources(config);
} catch (CoreException e) { } catch (CoreException e) {
// TODO: does the real error need to be extracted out of CoreException // 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); AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config);
@@ -486,7 +488,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
public Image getImage() { public Image getImage() {
// reuse icon from the Android App Launch config tab // reuse icon from the Android App Launch config tab
if (mTabIcon == null) { if (mTabIcon == null) {
mTabIcon= AdtPlugin.getImageLoader().loadImage(MainLaunchConfigTab.LAUNCH_TAB_IMAGE, mTabIcon = AdtPlugin.getImageLoader().loadImage(MainLaunchConfigTab.LAUNCH_TAB_IMAGE,
null); null);
} }
return mTabIcon; return mTabIcon;
@@ -514,7 +516,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
setErrorMessage(e.getMessage()); setErrorMessage(e.getMessage());
return; return;
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
AdtPlugin.log(e.getTargetException(), "Error finding test types"); AdtPlugin.log(e.getTargetException(), "Error finding test types"); //$NON-NLS-1$
return; return;
} finally { } finally {
mTestRadioButton.setSelection(radioSetting[0]); mTestRadioButton.setSelection(radioSetting[0]);
@@ -675,10 +677,10 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
return; return;
} }
} catch (CoreException e) { } catch (CoreException e) {
AdtPlugin.log(e, "validatePage failed"); AdtPlugin.log(e, "validatePage failed"); //$NON-NLS-1$
} }
validateInstrumentation(javaProject); validateInstrumentation();
} }
private void validateJavaProject(IJavaProject javaProject) { private void validateJavaProject(IJavaProject javaProject) {
@@ -688,19 +690,14 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
} }
} }
private void validateInstrumentation(IJavaProject javaProject) { private void validateInstrumentation() {
if (mInstrumentations == null || mInstrumentations.length < 1) {
setErrorMessage("Specified project has no defined instrumentations");
return;
}
String instrumentation = getSelectedInstrumentation(); String instrumentation = getSelectedInstrumentation();
if (instrumentation == null) { if (instrumentation == null) {
setErrorMessage("Instrumentation not specified"); setErrorMessage("Instrumentation runner not specified");
return; return;
} }
String result = AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner( String result = mInstrValidator.validateInstrumentationRunner(instrumentation);
javaProject, instrumentation); if (result != InstrumentationRunnerValidator.INSTRUMENTATION_OK) {
if (result != AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) {
setErrorMessage(result); setErrorMessage(result);
return; return;
} }
@@ -949,14 +946,15 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
/** /**
* Loads the UI with the instrumentations of the specified project, and stores the * Loads the UI with the instrumentations of the specified project, and stores the
* activities in <code>mActivities</code>. * instrumentations in <code>mInstrumentations</code>.
* <p/>
* First activity is selected by default if present.
* *
* @param project the {@link IProject} to load the instrumentations from. * @param project the {@link IProject} to load the instrumentations from.
*/ */
private void loadInstrumentations(IProject project) { private void loadInstrumentations(IProject project) {
mInstrumentations = AndroidJUnitLaunchConfigDelegate.getInstrumentationsForProject(project); try {
mInstrValidator = new InstrumentationRunnerValidator(project);
mInstrumentations = (mInstrValidator == null ? null :
mInstrValidator.getInstrumentations());
if (mInstrumentations != null) { if (mInstrumentations != null) {
mInstrumentationCombo.removeAll(); mInstrumentationCombo.removeAll();
for (String instrumentation : mInstrumentations) { for (String instrumentation : mInstrumentations) {
@@ -966,9 +964,13 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
// config object. // config object.
return; 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 // 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. // the parsing. In either case, we empty the instrumentation list.
mInstrValidator = null;
mInstrumentations = null; mInstrumentations = null;
mInstrumentationCombo.removeAll(); mInstrumentationCombo.removeAll();
} }

View File

@@ -16,10 +16,6 @@
package com.android.ide.eclipse.adt.launch.junit; 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.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaElement;
@@ -43,33 +39,18 @@ public class AndroidJUnitLaunchShortcut extends JUnitLaunchShortcut {
protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement element) protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement element)
throws CoreException { throws CoreException {
ILaunchConfigurationWorkingCopy config = super.createLaunchConfiguration(element); ILaunchConfigurationWorkingCopy config = super.createLaunchConfiguration(element);
IProject project = element.getResource().getProject(); // just get first valid instrumentation runner
String[] instrumentations = String instrumentation = new InstrumentationRunnerValidator(element.getJavaProject()).
AndroidJUnitLaunchConfigDelegate.getInstrumentationsForProject(project); getValidInstrumentationTestRunner();
boolean runnerFound = false; if (instrumentation != null) {
if (instrumentations != null) { config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME,
// just pick the first valid runner instrumentation);
for (String instr : instrumentations) { }
if (AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner( // if a valid runner is not found, rely on launch delegate to log error.
element.getJavaProject(), instr) == // This method is called without explicit user action to launch Android JUnit, so avoid
AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) { // logging an error here.
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);
}
AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config); AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config);
return config; return config;
} }
} }

View File

@@ -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 <code>AndroidConstants.LIBRARY_TEST_RUNNER
* </code> 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 <code>null</code if error occurred parsing instrumentations, otherwise returns array
* of instrumentation class names
*/
String[] getInstrumentations() {
return mInstrumentations;
}
/**
* Helper method to get the first instrumentation that can be used as a test runner.
*
* @return fully qualified instrumentation class name. <code>null</code> 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 <code>INSTRUMENTATION_OK</code> 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;
}
}