diff options
10 files changed, 404 insertions, 80 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java index 9995426..9dd1d16 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java @@ -49,6 +49,7 @@ public class RemoteAndroidTestRunner { private static final String LOG_ARG_NAME = "log"; private static final String DEBUG_ARG_NAME = "debug"; private static final String COVERAGE_ARG_NAME = "coverage"; + private static final String PACKAGE_ARG_NAME = "package"; /** * Creates a remote Android test runner. @@ -146,6 +147,16 @@ public class RemoteAndroidTestRunner { } /** + * Sets to run all tests in specified package + * Must be called before 'run'. + * + * @param packageName fully qualified package name (eg x.y.z) + */ + public void setTestPackageName(String packageName) { + addInstrumentationArg(PACKAGE_ARG_NAME, packageName); + } + + /** * Adds a argument to include in instrumentation command. * <p/> * Must be called before 'run'. If an argument with given name has already been provided, it's diff --git a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java index 6a653ad..864e219 100644 --- a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java +++ b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java @@ -17,16 +17,17 @@ package com.android.ddmlib.testrunner; import com.android.ddmlib.Client; -import com.android.ddmlib.Device.DeviceState; import com.android.ddmlib.FileListingService; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; -import com.android.ddmlib.log.LogReceiver; import com.android.ddmlib.RawImage; import com.android.ddmlib.SyncService; +import com.android.ddmlib.Device.DeviceState; +import com.android.ddmlib.log.LogReceiver; import java.io.IOException; import java.util.Map; + import junit.framework.TestCase; /** @@ -81,6 +82,17 @@ public class RemoteAndroidTestRunnerTest extends TestCase { } /** + * Test the building of the instrumentation runner command with test package set. + */ + public void testRunWithPackage() { + final String packageName = "foo.test"; + mRunner.setTestPackageName(packageName); + mRunner.run(new EmptyListener()); + assertStringsEquals(String.format("am instrument -w -r -e package %s %s/%s", packageName, + TEST_PACKAGE, TEST_RUNNER), mMockDevice.getLastShellCommand()); + } + + /** * Test the building of the instrumentation runner command with extra argument added. */ public void testRunWithAddInstrumentationArg() { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index 4b9d3a0..8092f3a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -43,7 +43,8 @@ Require-Bundle: com.android.ide.eclipse.ddms, org.eclipse.jdt.junit, org.eclipse.jdt.junit.runtime, org.eclipse.ltk.core.refactoring, - org.eclipse.ltk.ui.refactoring + org.eclipse.ltk.ui.refactoring, + org.eclipse.core.expressions Eclipse-LazyStart: true Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.build;x-friends:="com.android.ide.eclipse.tests", diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index a75b8b9..35ceba7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -563,7 +563,7 @@ <adapt type="org.eclipse.jdt.core.IJavaElement"> <test property="org.eclipse.jdt.core.isInJavaProjectWithNature" value="com.android.ide.eclipse.adt.AndroidNature"/> <test property="org.eclipse.jdt.core.hasTypeOnClasspath" value="junit.framework.Test"/> - <test property="org.eclipse.jdt.junit.canLaunchAsJUnit" forcePluginActivation="true"/> + <test property="com.android.ide.eclipse.adt.canLaunchAsJUnit"/> </adapt> </iterate> </with> @@ -595,4 +595,14 @@ id="com.android.ide.eclipse.adt.refactoring.extract.string"> </contribution> </extension> + <extension + point="org.eclipse.core.expressions.propertyTesters"> + <propertyTester + properties="isTest,canLaunchAsJUnit" + namespace="com.android.ide.eclipse.adt" + type="org.eclipse.core.runtime.IAdaptable" + class="com.android.ide.eclipse.adt.launch.junit.AndroidJUnitPropertyTester" + id="com.android.ide.eclipse.adt.AndroidJUnitPropertyTester"> + </propertyTester> + </extension> </plugin> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java index 747fcfe..9bcc63d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java @@ -24,7 +24,6 @@ import com.android.ide.eclipse.adt.launch.junit.runtime.RemoteAdtTestRunner; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; @@ -39,18 +38,15 @@ import org.eclipse.jdt.launching.VMRunnerConfiguration; */ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { - private String mTestPackage; - private String mRunner; + private final AndroidJUnitLaunchInfo mLaunchInfo; /** * Creates a AndroidJUnitLaunchAction. * - * @param testPackage the Android application package that contains the tests to run - * @param runner the InstrumentationTestRunner that will execute the tests + * @param launchInfo the {@link AndroidJUnitLaunchInfo} for the JUnit run */ - public AndroidJUnitLaunchAction(String testPackage, String runner) { - mTestPackage = testPackage; - mRunner = runner; + public AndroidJUnitLaunchAction(AndroidJUnitLaunchInfo launchInfo) { + mLaunchInfo = launchInfo; } /** @@ -60,17 +56,21 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice) */ public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) { - String msg = String.format("Launching instrumentation %s on device %s", mRunner, - device.getSerialNumber()); + String msg = String.format("Launching instrumentation %s on device %s", + mLaunchInfo.getRunner(), device.getSerialNumber()); AdtPlugin.printToConsole(info.getProject(), msg); try { - JUnitLaunchDelegate junitDelegate = new JUnitLaunchDelegate(info, device); + mLaunchInfo.setDebugMode(info.isDebugMode()); + mLaunchInfo.setDevice(info.getDevice()); + mLaunchInfo.setLaunch(info.getLaunch()); + JUnitLaunchDelegate junitDelegate = new JUnitLaunchDelegate(mLaunchInfo); final String mode = info.isDebugMode() ? ILaunchManager.DEBUG_MODE : ILaunchManager.RUN_MODE; + junitDelegate.launch(info.getLaunch().getLaunchConfiguration(), mode, info.getLaunch(), info.getMonitor()); - + // TODO: need to add AMReceiver-type functionality somewhere } catch (CoreException e) { AdtPlugin.printErrorToConsole(info.getProject(), "Failed to launch test"); @@ -82,20 +82,18 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { * {@inheritDoc} */ public String getLaunchDescription() { - return String.format("%s JUnit launch", mRunner); + return String.format("%s JUnit launch", mLaunchInfo.getRunner()); } /** * Extends the JDT JUnit launch delegate to allow for JUnit UI reuse. */ - private class JUnitLaunchDelegate extends JUnitLaunchConfigurationDelegate { + private static class JUnitLaunchDelegate extends JUnitLaunchConfigurationDelegate { - private IDevice mDevice; - private DelayedLaunchInfo mLaunchInfo; + private AndroidJUnitLaunchInfo mLaunchInfo; - public JUnitLaunchDelegate(DelayedLaunchInfo info, IDevice device) { - mLaunchInfo = info; - mDevice = device; + public JUnitLaunchDelegate(AndroidJUnitLaunchInfo launchInfo) { + mLaunchInfo = launchInfo; } /* (non-Javadoc) @@ -110,34 +108,28 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * {@inheritDoc} - * @throws CoreException * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#verifyMainTypeName(org.eclipse.debug.core.ILaunchConfiguration) */ @Override - public String verifyMainTypeName(ILaunchConfiguration configuration) throws CoreException { + public String verifyMainTypeName(ILaunchConfiguration configuration) { return "com.android.ide.eclipse.adt.junit.internal.runner.RemoteAndroidTestRunner"; //$NON-NLS-1$ } /** * Overrides parent to return a VM Runner implementation which launches a thread, rather * than a separate VM process - * @throws CoreException */ @Override - public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) - throws CoreException { - return new VMTestRunner(new AndroidJUnitLaunchInfo(mLaunchInfo.getProject(), - mTestPackage, mRunner, mLaunchInfo.isDebugMode(), mDevice)); + public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) { + return new VMTestRunner(mLaunchInfo); } /** * {@inheritDoc} - * @throws CoreException * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getLaunch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String) */ @Override - public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) - throws CoreException { + public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) { return mLaunchInfo.getLaunch(); } } @@ -161,7 +153,7 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { IProgressMonitor monitor) throws CoreException { TestRunnerProcess runnerProcess = - new TestRunnerProcess(config, launch, mJUnitInfo); + new TestRunnerProcess(config, mJUnitInfo); runnerProcess.start(); launch.addProcess(runnerProcess); } @@ -173,15 +165,12 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { private static class TestRunnerProcess extends Thread implements IProcess { private final VMRunnerConfiguration mRunConfig; - private final ILaunch mLaunch; private final AndroidJUnitLaunchInfo mJUnitInfo; private RemoteAdtTestRunner mTestRunner = null; private boolean mIsTerminated = false; - TestRunnerProcess(VMRunnerConfiguration runConfig, ILaunch launch, - AndroidJUnitLaunchInfo info) { + TestRunnerProcess(VMRunnerConfiguration runConfig, AndroidJUnitLaunchInfo info) { mRunConfig = runConfig; - mLaunch = launch; mJUnitInfo = info; } @@ -194,10 +183,9 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * {@inheritDoc} - * @throws DebugException * @see org.eclipse.debug.core.model.IProcess#getExitValue() */ - public int getExitValue() throws DebugException { + public int getExitValue() { return 0; } @@ -205,14 +193,14 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { * @see org.eclipse.debug.core.model.IProcess#getLabel() */ public String getLabel() { - return mLaunch.getLaunchMode(); + return mJUnitInfo.getLaunch().getLaunchMode(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IProcess#getLaunch() */ public ILaunch getLaunch() { - return mLaunch; + return mJUnitInfo.getLaunch(); } /* (non-Javadoc) @@ -254,10 +242,9 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * {@inheritDoc} - * @throws DebugException * @see org.eclipse.debug.core.model.ITerminate#terminate() */ - public void terminate() throws DebugException { + public void terminate() { if (mTestRunner != null) { mTestRunner.terminate(); } @@ -274,3 +261,4 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { } } } + 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 fa8e4b0..543daf0 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 @@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration; import com.android.ide.eclipse.adt.launch.AndroidLaunchController; import com.android.ide.eclipse.adt.launch.IAndroidLaunchAction; import com.android.ide.eclipse.adt.launch.LaunchConfigDelegate; +import com.android.ide.eclipse.adt.launch.junit.runtime.AndroidJUnitLaunchInfo; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.AndroidManifestParser; import com.android.ide.eclipse.common.project.BaseProjectHelper; @@ -32,8 +33,11 @@ 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.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; /** * Run configuration that can execute JUnit tests on an Android platform. @@ -47,6 +51,7 @@ 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$ + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ @Override @@ -55,7 +60,7 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { AndroidLaunchConfiguration config, AndroidLaunchController controller, IFile applicationPackage, AndroidManifestParser manifestParser) { - String testPackage = manifestParser.getPackage(); + String appPackage = manifestParser.getPackage(); String runner = getRunner(project, configuration, manifestParser); if (runner == null) { AdtPlugin.displayError("Android Launch", @@ -63,8 +68,13 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { androidLaunch.stopLaunch(); return; } + AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project, appPackage, + runner); + junitLaunchInfo.setTestClass(getTestClass(configuration)); + junitLaunchInfo.setTestPackage(getTestPackage(configuration)); + junitLaunchInfo.setTestMethod(getTestMethod(configuration)); - IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(testPackage, runner); + IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(junitLaunchInfo); controller.launch(project, mode, applicationPackage, manifestParser.getPackage(), manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), @@ -72,6 +82,49 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { } /** + * 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); + } + + /** * Gets a instrumentation runner for the launch. * <p/> * If a runner is stored in the given <code>configuration</code>, will return that. @@ -114,11 +167,29 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { } private String getRunnerFromConfig(ILaunchConfiguration configuration) throws CoreException { - String runner = configuration.getAttribute(ATTR_INSTR_NAME, EMPTY_STRING); - if (runner.length() < 1) { - return null; + 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 runner; + return null; } /** 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 eb57482..584d45e 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 @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.launch.junit; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.launch.MainLaunchConfigTab; import com.android.ide.eclipse.common.AndroidConstants; +import com.android.ide.eclipse.common.project.BaseProjectHelper; import com.android.ide.eclipse.common.project.ProjectChooserHelper; import org.eclipse.core.resources.IProject; @@ -241,7 +242,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private void createTestContainerSelectionGroup(Composite comp) { mTestContainerRadioButton = new Button(comp, SWT.RADIO); mTestContainerRadioButton.setText( - JUnitMessages.JUnitLaunchConfigurationTab_label_containerTest); + "Run all tests in the selected project, or package"); GridData gd = new GridData(); gd.horizontalSpan = 3; mTestContainerRadioButton.setLayoutData(gd); @@ -249,12 +250,12 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat public void widgetSelected(SelectionEvent e) { if (mTestContainerRadioButton.getSelection()) { testModeChanged(); - } + } } public void widgetDefaultSelected(SelectionEvent e) { } }); - + mContainerText = new Text(comp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalIndent = 25; @@ -265,7 +266,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat updateLaunchConfigurationDialog(); } }); - + mContainerSearchButton = new Button(comp, SWT.PUSH); mContainerSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); mContainerSearchButton.addSelectionListener(new SelectionAdapter() { @@ -821,7 +822,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat @SuppressWarnings("unchecked") private IJavaElement chooseContainer(IJavaElement initElement) { - Class[] acceptedClasses = new Class[] { IPackageFragmentRoot.class, IJavaProject.class, + Class[] acceptedClasses = new Class[] { IJavaProject.class, IPackageFragment.class }; TypedElementSelectionValidator validator = new TypedElementSelectionValidator( acceptedClasses, false) { @@ -839,7 +840,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat if (element instanceof IPackageFragmentRoot && ((IPackageFragmentRoot) element).isArchive()) { return false; - } + } try { if (element instanceof IPackageFragment && !((IPackageFragment) element).hasChildren()) { @@ -852,7 +853,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } }; - StandardJavaElementContentProvider provider = new StandardJavaElementContentProvider(); + AndroidJavaElementContentProvider provider = new AndroidJavaElementContentProvider(); ILabelProvider labelProvider = new JavaElementLabelProvider( JavaElementLabelProvider.SHOW_DEFAULT); ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), @@ -974,4 +975,23 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat mInstrumentations = null; mInstrumentationCombo.removeAll(); } + + /** + * Overrides the {@link StandardJavaElementContentProvider} to only display Android projects + */ + private static class AndroidJavaElementContentProvider + extends StandardJavaElementContentProvider { + + /** + * Override parent to return only Android projects if at the root. Otherwise, use parent + * functionality. + */ + @Override + public Object[] getChildren(Object element) { + if (element instanceof IJavaModel) { + return BaseProjectHelper.getAndroidProjects((IJavaModel) element); + } + return super.getChildren(element); + } + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java new file mode 100644 index 0000000..eadafee --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java @@ -0,0 +1,130 @@ +/* + * 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 org.eclipse.core.expressions.PropertyTester; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.junit.util.TestSearchEngine; + +/** + * A {@link PropertyTester} that checks if selected elements can be run as Android + * JUnit tests. + * <p/> + * Based on org.eclipse.jdt.internal.junit.JUnitPropertyTester. The only substantial difference in + * this implementation is source folders cannot be run as Android JUnit. + */ +@SuppressWarnings("restriction") +public class AndroidJUnitPropertyTester extends PropertyTester { + private static final String PROPERTY_IS_TEST = "isTest"; //$NON-NLS-1$ + + private static final String PROPERTY_CAN_LAUNCH_AS_JUNIT_TEST = "canLaunchAsJUnit"; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.refactoring.participants.properties.IPropertyEvaluator#test(java.lang.Object, java.lang.String, java.lang.String) + */ + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + if (!(receiver instanceof IAdaptable)) { + final String elementName = (receiver == null ? "null" : //$NON-NLS-1$ + receiver.getClass().getName()); + throw new IllegalArgumentException( + String.format("Element must be of type IAdaptable, is %s", //$NON-NLS-1$ + elementName)); + } + + IJavaElement element; + if (receiver instanceof IJavaElement) { + element = (IJavaElement) receiver; + } else if (receiver instanceof IResource) { + element = JavaCore.create((IResource) receiver); + if (element == null) { + return false; + } + } else { // is IAdaptable + element= (IJavaElement) ((IAdaptable) receiver).getAdapter(IJavaElement.class); + if (element == null) { + IResource resource = (IResource) ((IAdaptable) receiver).getAdapter( + IResource.class); + element = JavaCore.create(resource); + if (element == null) { + return false; + } + } + } + if (PROPERTY_IS_TEST.equals(property)) { + return isJUnitTest(element); + } else if (PROPERTY_CAN_LAUNCH_AS_JUNIT_TEST.equals(property)) { + return canLaunchAsJUnitTest(element); + } + throw new IllegalArgumentException( + String.format("Unknown test property '%s'", property)); //$NON-NLS-1$ + } + + private boolean canLaunchAsJUnitTest(IJavaElement element) { + try { + switch (element.getElementType()) { + case IJavaElement.JAVA_PROJECT: + return true; // can run, let JDT detect if there are tests + case IJavaElement.PACKAGE_FRAGMENT_ROOT: + return false; // not supported by Android test runner + case IJavaElement.PACKAGE_FRAGMENT: + return ((IPackageFragment) element).hasChildren(); + case IJavaElement.COMPILATION_UNIT: + case IJavaElement.CLASS_FILE: + case IJavaElement.TYPE: + case IJavaElement.METHOD: + return isJUnitTest(element); + default: + return false; + } + } catch (JavaModelException e) { + return false; + } + } + + /** + * Return whether the target resource is a JUnit test. + */ + private boolean isJUnitTest(IJavaElement element) { + try { + IType testType = null; + if (element instanceof ICompilationUnit) { + testType = (((ICompilationUnit) element)).findPrimaryType(); + } else if (element instanceof IClassFile) { + testType = (((IClassFile) element)).getType(); + } else if (element instanceof IType) { + testType = (IType) element; + } else if (element instanceof IMember) { + testType = ((IMember) element).getDeclaringType(); + } + if (testType != null && testType.exists()) { + return TestSearchEngine.isTestOrTestSuite(testType); + } + } catch (CoreException e) { + // ignore, return false + } + return false; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java index 89cad97..8ac80ca 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java @@ -15,35 +15,38 @@ */ package com.android.ide.eclipse.adt.launch.junit.runtime; -import org.eclipse.core.resources.IProject; - import com.android.ddmlib.IDevice; +import org.eclipse.core.resources.IProject; +import org.eclipse.debug.core.ILaunch; + /** * Contains info about Android JUnit launch */ public class AndroidJUnitLaunchInfo { private final IProject mProject; - private final String mTestPackage; + private final String mAppPackage; private final String mRunner; - private final boolean mDebugMode; - private final IDevice mDevice; - - public AndroidJUnitLaunchInfo(IProject project, String testPackage, String runner, - boolean debugMode, IDevice device) { + + private boolean mDebugMode = false; + private IDevice mDevice = null; + private String mTestPackage = null; + private String mTestClass = null; + private String mTestMethod = null; + private ILaunch mLaunch = null; + + public AndroidJUnitLaunchInfo(IProject project, String appPackage, String runner) { mProject = project; - mTestPackage = testPackage; + mAppPackage = appPackage; mRunner = runner; - mDebugMode = debugMode; - mDevice = device; } - + public IProject getProject() { return mProject; } - public String getTestPackage() { - return mTestPackage; + public String getAppPackage() { + return mAppPackage; } public String getRunner() { @@ -53,8 +56,80 @@ public class AndroidJUnitLaunchInfo { public boolean isDebugMode() { return mDebugMode; } + + public void setDebugMode(boolean debugMode) { + mDebugMode = debugMode; + } public IDevice getDevice() { return mDevice; } + + public void setDevice(IDevice device) { + mDevice = device; + } + + /** + * Specify to run all tests within given package. + * + * @param testPackage fully qualified java package + */ + public void setTestPackage(String testPackage) { + mTestPackage = testPackage; + } + + /** + * Return the package of tests to run. + * + * @return fully qualified java package. <code>null</code> if not specified. + */ + public String getTestPackage() { + return mTestPackage; + } + + /** + * Sets the test class to run. + * + * @param testClass fully qualfied test class to run + * Expected format: x.y.x.testclass + */ + public void setTestClass(String testClass) { + mTestClass = testClass; + } + + /** + * Returns the test class to run. + * + * @return fully qualfied test class to run. + * <code>null</code> if not specified. + */ + public String getTestClass() { + return mTestClass; + } + + /** + * Sets the test method to run. testClass must also be set. + * + * @param testMethod test method to run + */ + public void setTestMethod(String testMethod) { + mTestMethod = testMethod; + } + + /** + * Returns the test method to run. + * + * @return test method to run. <code>null</code> if not specified. + */ + public String getTestMethod() { + return mTestMethod; + } + + public ILaunch getLaunch() { + return mLaunch; + } + + public void setLaunch(ILaunch launch) { + mLaunch = launch; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java index 0a6a3da..962d761 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java @@ -69,8 +69,9 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { * executing the tests, and send it back to JDT JUnit. The second is the actual test execution, * whose results will be communicated back in real-time to JDT JUnit. * - * @param testClassNames array of fully qualified test class names to execute. Cannot be empty. - * @param testName test to execute. If null, will be ignored. + * @param testClassNames ignored - the AndroidJUnitLaunchInfo will be used to determine which + * tests to run. + * @param testName ignored * @param execution used to report test progress */ @Override @@ -78,16 +79,21 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { // hold onto this execution reference so it can be used to report test progress mExecution = execution; - RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getTestPackage(), + RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getAppPackage(), mLaunchInfo.getRunner(), mLaunchInfo.getDevice()); - if (testClassNames != null && testClassNames.length > 0) { - if (testName != null) { - runner.setMethodName(testClassNames[0], testName); - } else { - runner.setClassNames(testClassNames); - } + if (mLaunchInfo.getTestClass() != null) { + if (mLaunchInfo.getTestMethod() != null) { + runner.setMethodName(mLaunchInfo.getTestClass(), mLaunchInfo.getTestMethod()); + } else { + runner.setClassName(mLaunchInfo.getTestClass()); + } } + + if (mLaunchInfo.getTestPackage() != null) { + runner.setTestPackageName(mLaunchInfo.getTestPackage()); + } + // set log only to first collect test case info, so Eclipse has correct test case count/ // tree info runner.setLogOnly(true); |