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 package com.android.ide.eclipse.adt.internal.launch.junit; 17 18 import com.android.SdkConstants; 19 import com.android.ide.eclipse.adt.AdtConstants; 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 import com.android.ide.eclipse.adt.internal.editors.IconFactory; 22 import com.android.ide.eclipse.adt.internal.launch.LaunchMessages; 23 import com.android.ide.eclipse.adt.internal.launch.MainLaunchConfigTab; 24 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 25 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; 26 27 import org.eclipse.core.resources.IProject; 28 import org.eclipse.core.resources.IResource; 29 import org.eclipse.core.resources.IWorkspaceRoot; 30 import org.eclipse.core.resources.ResourcesPlugin; 31 import org.eclipse.core.runtime.CoreException; 32 import org.eclipse.core.runtime.IPath; 33 import org.eclipse.core.runtime.IStatus; 34 import org.eclipse.core.runtime.Path; 35 import org.eclipse.debug.core.ILaunchConfiguration; 36 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; 37 import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; 38 import org.eclipse.jdt.core.IJavaElement; 39 import org.eclipse.jdt.core.IJavaModel; 40 import org.eclipse.jdt.core.IJavaProject; 41 import org.eclipse.jdt.core.IPackageFragment; 42 import org.eclipse.jdt.core.IPackageFragmentRoot; 43 import org.eclipse.jdt.core.ISourceReference; 44 import org.eclipse.jdt.core.IType; 45 import org.eclipse.jdt.core.JavaCore; 46 import org.eclipse.jdt.core.JavaModelException; 47 import org.eclipse.jdt.internal.junit.Messages; 48 import org.eclipse.jdt.internal.junit.launcher.ITestKind; 49 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants; 50 import org.eclipse.jdt.internal.junit.launcher.JUnitMigrationDelegate; 51 import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; 52 import org.eclipse.jdt.internal.junit.launcher.TestSelectionDialog; 53 import org.eclipse.jdt.internal.junit.ui.JUnitMessages; 54 import org.eclipse.jdt.internal.junit.util.LayoutUtil; 55 import org.eclipse.jdt.internal.junit.util.TestSearchEngine; 56 import org.eclipse.jdt.internal.ui.wizards.TypedElementSelectionValidator; 57 import org.eclipse.jdt.internal.ui.wizards.TypedViewerFilter; 58 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; 59 import org.eclipse.jdt.ui.JavaElementComparator; 60 import org.eclipse.jdt.ui.JavaElementLabelProvider; 61 import org.eclipse.jdt.ui.StandardJavaElementContentProvider; 62 import org.eclipse.jface.dialogs.Dialog; 63 import org.eclipse.jface.layout.GridDataFactory; 64 import org.eclipse.jface.viewers.ILabelProvider; 65 import org.eclipse.jface.viewers.ISelection; 66 import org.eclipse.jface.viewers.IStructuredSelection; 67 import org.eclipse.jface.viewers.Viewer; 68 import org.eclipse.jface.viewers.ViewerFilter; 69 import org.eclipse.jface.window.Window; 70 import org.eclipse.swt.SWT; 71 import org.eclipse.swt.events.ModifyEvent; 72 import org.eclipse.swt.events.ModifyListener; 73 import org.eclipse.swt.events.SelectionAdapter; 74 import org.eclipse.swt.events.SelectionEvent; 75 import org.eclipse.swt.graphics.Image; 76 import org.eclipse.swt.layout.GridData; 77 import org.eclipse.swt.layout.GridLayout; 78 import org.eclipse.swt.widgets.Button; 79 import org.eclipse.swt.widgets.Combo; 80 import org.eclipse.swt.widgets.Composite; 81 import org.eclipse.swt.widgets.Label; 82 import org.eclipse.swt.widgets.Shell; 83 import org.eclipse.swt.widgets.Text; 84 import org.eclipse.ui.IEditorInput; 85 import org.eclipse.ui.IEditorPart; 86 import org.eclipse.ui.IWorkbenchPage; 87 import org.eclipse.ui.IWorkbenchWindow; 88 import org.eclipse.ui.PlatformUI; 89 import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; 90 import org.eclipse.ui.dialogs.SelectionDialog; 91 92 import java.lang.reflect.InvocationTargetException; 93 import java.util.Arrays; 94 import java.util.List; 95 96 /** 97 * The launch config UI tab for Android JUnit 98 * <p/> 99 * Based on org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationTab 100 */ 101 @SuppressWarnings("restriction") 102 public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurationTab { 103 104 // Project UI widgets 105 private Label mProjLabel; 106 private Text mProjText; 107 private Button mProjButton; 108 109 // Test class UI widgets 110 private Text mTestText; 111 private Button mSearchButton; 112 private String mOriginalTestMethodName; 113 private Label mTestMethodLabel; 114 private Text mContainerText; 115 private IJavaElement mContainerElement; 116 private final ILabelProvider mJavaElementLabelProvider = new JavaElementLabelProvider(); 117 118 private Button mContainerSearchButton; 119 private Button mTestContainerRadioButton; 120 private Button mTestRadioButton; 121 private Label mTestLabel; 122 123 // Android specific members 124 private Image mTabIcon = null; 125 private Combo mInstrumentationCombo; 126 private Combo mTestSizeCombo; 127 private static final String EMPTY_STRING = ""; //$NON-NLS-1$ 128 private static final String TAG = "AndroidJUnitLaunchConfigurationTab"; //$NON-NLS-1$ 129 private String[] mInstrumentations = null; 130 private InstrumentationRunnerValidator mInstrValidator = null; 131 private ProjectChooserHelper mProjectChooserHelper; 132 133 public static final String SMALL_TEST_ANNOTATION = "@SmallTest"; //$NON-NLS-1$ 134 public static final String MEDIUM_TEST_ANNOTATION = "@MediumTest"; //$NON-NLS-1$ 135 public static final String LARGE_TEST_ANNOTATION = "@LargeTest"; //$NON-NLS-1$ 136 private static final List<String> TEST_SIZE_OPTIONS = Arrays.asList( 137 "All Tests", 138 SMALL_TEST_ANNOTATION, 139 MEDIUM_TEST_ANNOTATION, 140 LARGE_TEST_ANNOTATION 141 ); 142 143 /* (non-Javadoc) 144 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite) 145 */ 146 @Override 147 public void createControl(Composite parent) { 148 mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), null /*filter*/); 149 150 Composite comp = new Composite(parent, SWT.NONE); 151 setControl(comp); 152 153 GridLayout topLayout = new GridLayout(); 154 topLayout.numColumns = 3; 155 comp.setLayout(topLayout); 156 157 createSingleTestSection(comp); 158 createTestContainerSelectionGroup(comp); 159 160 createSpacer(comp); 161 162 createInstrumentationGroup(comp); 163 createSizeSelector(comp); 164 165 Dialog.applyDialogFont(comp); 166 // TODO: add help link here when available 167 //PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), 168 // IJUnitHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_JUNIT_MAIN_TAB); 169 validatePage(); 170 } 171 172 173 private void createSpacer(Composite comp) { 174 Label label = new Label(comp, SWT.NONE); 175 GridData gd = new GridData(); 176 gd.horizontalSpan = 3; 177 label.setLayoutData(gd); 178 } 179 180 private void createSingleTestSection(Composite comp) { 181 mTestRadioButton = new Button(comp, SWT.RADIO); 182 mTestRadioButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_oneTest); 183 GridData gd = new GridData(); 184 gd.horizontalSpan = 3; 185 mTestRadioButton.setLayoutData(gd); 186 mTestRadioButton.addSelectionListener(new SelectionAdapter() { 187 @Override 188 public void widgetSelected(SelectionEvent e) { 189 if (mTestRadioButton.getSelection()) { 190 testModeChanged(); 191 } 192 } 193 }); 194 195 mProjLabel = new Label(comp, SWT.NONE); 196 mProjLabel.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_project); 197 gd = new GridData(); 198 gd.horizontalIndent = 25; 199 mProjLabel.setLayoutData(gd); 200 201 mProjText = new Text(comp, SWT.SINGLE | SWT.BORDER); 202 mProjText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 203 mProjText.addModifyListener(new ModifyListener() { 204 @Override 205 public void modifyText(ModifyEvent evt) { 206 validatePage(); 207 updateLaunchConfigurationDialog(); 208 mSearchButton.setEnabled(mTestRadioButton.getSelection() && 209 mProjText.getText().length() > 0); 210 } 211 }); 212 213 mProjButton = new Button(comp, SWT.PUSH); 214 mProjButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_browse); 215 mProjButton.addSelectionListener(new SelectionAdapter() { 216 @Override 217 public void widgetSelected(SelectionEvent evt) { 218 handleProjectButtonSelected(); 219 } 220 }); 221 setButtonGridData(mProjButton); 222 223 mTestLabel = new Label(comp, SWT.NONE); 224 gd = new GridData(); 225 gd.horizontalIndent = 25; 226 mTestLabel.setLayoutData(gd); 227 mTestLabel.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_test); 228 229 230 mTestText = new Text(comp, SWT.SINGLE | SWT.BORDER); 231 mTestText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 232 mTestText.addModifyListener(new ModifyListener() { 233 @Override 234 public void modifyText(ModifyEvent evt) { 235 validatePage(); 236 updateLaunchConfigurationDialog(); 237 } 238 }); 239 240 mSearchButton = new Button(comp, SWT.PUSH); 241 mSearchButton.setEnabled(mProjText.getText().length() > 0); 242 mSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); 243 mSearchButton.addSelectionListener(new SelectionAdapter() { 244 @Override 245 public void widgetSelected(SelectionEvent evt) { 246 handleSearchButtonSelected(); 247 } 248 }); 249 setButtonGridData(mSearchButton); 250 251 new Label(comp, SWT.NONE); 252 253 mTestMethodLabel = new Label(comp, SWT.NONE); 254 mTestMethodLabel.setText(""); //$NON-NLS-1$ 255 gd = new GridData(); 256 gd.horizontalSpan = 2; 257 mTestMethodLabel.setLayoutData(gd); 258 } 259 260 private void createTestContainerSelectionGroup(Composite comp) { 261 mTestContainerRadioButton = new Button(comp, SWT.RADIO); 262 mTestContainerRadioButton.setText( 263 LaunchMessages.AndroidJUnitTab_TestContainerText); 264 GridData gd = new GridData(); 265 gd.horizontalSpan = 3; 266 mTestContainerRadioButton.setLayoutData(gd); 267 mTestContainerRadioButton.addSelectionListener(new SelectionAdapter() { 268 @Override 269 public void widgetSelected(SelectionEvent e) { 270 if (mTestContainerRadioButton.getSelection()) { 271 testModeChanged(); 272 } 273 } 274 }); 275 276 mContainerText = new Text(comp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); 277 gd = new GridData(GridData.FILL_HORIZONTAL); 278 gd.horizontalIndent = 25; 279 gd.horizontalSpan = 2; 280 mContainerText.setLayoutData(gd); 281 mContainerText.addModifyListener(new ModifyListener() { 282 @Override 283 public void modifyText(ModifyEvent evt) { 284 updateLaunchConfigurationDialog(); 285 } 286 }); 287 288 mContainerSearchButton = new Button(comp, SWT.PUSH); 289 mContainerSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); 290 mContainerSearchButton.addSelectionListener(new SelectionAdapter() { 291 @Override 292 public void widgetSelected(SelectionEvent evt) { 293 handleContainerSearchButtonSelected(); 294 } 295 }); 296 setButtonGridData(mContainerSearchButton); 297 } 298 299 private void createInstrumentationGroup(Composite comp) { 300 Label loaderLabel = new Label(comp, SWT.NONE); 301 loaderLabel.setText(LaunchMessages.AndroidJUnitTab_LoaderLabel); 302 GridData gd = new GridData(); 303 gd.horizontalIndent = 0; 304 loaderLabel.setLayoutData(gd); 305 306 mInstrumentationCombo = new Combo(comp, SWT.DROP_DOWN | SWT.READ_ONLY); 307 GridDataFactory.defaultsFor(mInstrumentationCombo) 308 .span(2, 1) 309 .applyTo(mInstrumentationCombo); 310 mInstrumentationCombo.clearSelection(); 311 mInstrumentationCombo.addSelectionListener(new SelectionAdapter() { 312 @Override 313 public void widgetSelected(SelectionEvent e) { 314 validatePage(); 315 updateLaunchConfigurationDialog(); 316 } 317 }); 318 } 319 320 private void createSizeSelector(Composite comp) { 321 Label l = new Label(comp, SWT.NONE); 322 l.setText(LaunchMessages.AndroidJUnitTab_SizeLabel); 323 GridData gd = new GridData(); 324 gd.horizontalIndent = 0; 325 l.setLayoutData(gd); 326 327 mTestSizeCombo = new Combo(comp, SWT.DROP_DOWN | SWT.READ_ONLY); 328 mTestSizeCombo.setItems(TEST_SIZE_OPTIONS.toArray(new String[TEST_SIZE_OPTIONS.size()])); 329 mTestSizeCombo.select(0); 330 mTestSizeCombo.addSelectionListener(new SelectionAdapter() { 331 @Override 332 public void widgetSelected(SelectionEvent e) { 333 updateLaunchConfigurationDialog(); 334 } 335 }); 336 } 337 338 private void handleContainerSearchButtonSelected() { 339 IJavaElement javaElement = chooseContainer(mContainerElement); 340 if (javaElement != null) { 341 setContainerElement(javaElement); 342 } 343 } 344 345 private void setContainerElement(IJavaElement javaElement) { 346 mContainerElement = javaElement; 347 mContainerText.setText(getPresentationName(javaElement)); 348 validatePage(); 349 updateLaunchConfigurationDialog(); 350 } 351 352 /* (non-Javadoc) 353 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) 354 */ 355 @Override 356 public void initializeFrom(ILaunchConfiguration config) { 357 String projectName = updateProjectFromConfig(config); 358 String containerHandle = EMPTY_STRING; 359 try { 360 containerHandle = config.getAttribute( 361 JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, EMPTY_STRING); 362 } catch (CoreException ce) { 363 // ignore 364 } 365 366 if (containerHandle.length() > 0) { 367 updateTestContainerFromConfig(config); 368 } else { 369 updateTestTypeFromConfig(config); 370 } 371 372 IProject proj = mProjectChooserHelper.getAndroidProject(projectName); 373 loadInstrumentations(proj); 374 updateInstrumentationFromConfig(config); 375 updateTestSizeFromConfig(config); 376 377 validatePage(); 378 } 379 380 private void updateInstrumentationFromConfig(ILaunchConfiguration config) { 381 boolean found = false; 382 try { 383 String currentInstrumentation = config.getAttribute( 384 AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, EMPTY_STRING); 385 if (mInstrumentations != null) { 386 // look for the name of the instrumentation in the combo. 387 for (int i = 0; i < mInstrumentations.length; i++) { 388 if (currentInstrumentation.equals(mInstrumentations[i])) { 389 found = true; 390 mInstrumentationCombo.select(i); 391 break; 392 } 393 } 394 } 395 } catch (CoreException ce) { 396 // ignore 397 } 398 if (!found) { 399 mInstrumentationCombo.clearSelection(); 400 } 401 } 402 403 private void updateTestSizeFromConfig(ILaunchConfiguration config) { 404 try { 405 String testSize = config.getAttribute( 406 AndroidJUnitLaunchConfigDelegate.ATTR_TEST_SIZE, EMPTY_STRING); 407 int index = TEST_SIZE_OPTIONS.indexOf(testSize); 408 if (index >= 0 && mTestSizeCombo != null) { 409 mTestSizeCombo.select(index); 410 } 411 } catch (CoreException e) { 412 // ignore 413 } 414 } 415 416 private String updateProjectFromConfig(ILaunchConfiguration config) { 417 String projectName = EMPTY_STRING; 418 try { 419 projectName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, 420 EMPTY_STRING); 421 } catch (CoreException ce) { 422 // ignore 423 } 424 mProjText.setText(projectName); 425 return projectName; 426 } 427 428 private void updateTestTypeFromConfig(ILaunchConfiguration config) { 429 String testTypeName = EMPTY_STRING; 430 mOriginalTestMethodName = EMPTY_STRING; 431 try { 432 testTypeName = config.getAttribute( 433 IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, ""); //$NON-NLS-1$ 434 mOriginalTestMethodName = config.getAttribute( 435 JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, ""); //$NON-NLS-1$ 436 } catch (CoreException ce) { 437 // ignore 438 } 439 mTestRadioButton.setSelection(true); 440 setEnableSingleTestGroup(true); 441 setEnableContainerTestGroup(false); 442 mTestContainerRadioButton.setSelection(false); 443 mTestText.setText(testTypeName); 444 mContainerText.setText(EMPTY_STRING); 445 setTestMethodLabel(mOriginalTestMethodName); 446 } 447 448 private void setTestMethodLabel(String testMethodName) { 449 if (!EMPTY_STRING.equals(testMethodName)) { 450 mTestMethodLabel.setText( 451 JUnitMessages.JUnitLaunchConfigurationTab_label_method + 452 mOriginalTestMethodName); 453 } else { 454 mTestMethodLabel.setText(EMPTY_STRING); 455 } 456 } 457 458 private void updateTestContainerFromConfig(ILaunchConfiguration config) { 459 String containerHandle = EMPTY_STRING; 460 IJavaElement containerElement = null; 461 try { 462 containerHandle = config.getAttribute( 463 JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, EMPTY_STRING); 464 if (containerHandle.length() > 0) { 465 containerElement = JavaCore.create(containerHandle); 466 } 467 } catch (CoreException ce) { 468 // ignore 469 } 470 if (containerElement != null) { 471 mContainerElement = containerElement; 472 } 473 mTestContainerRadioButton.setSelection(true); 474 setEnableSingleTestGroup(false); 475 setEnableContainerTestGroup(true); 476 mTestRadioButton.setSelection(false); 477 if (mContainerElement != null) { 478 mContainerText.setText(getPresentationName(mContainerElement)); 479 } 480 mTestText.setText(EMPTY_STRING); 481 } 482 483 /* 484 * (non-Javadoc) 485 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) 486 */ 487 @Override 488 public void performApply(ILaunchConfigurationWorkingCopy config) { 489 if (mTestContainerRadioButton.getSelection() && mContainerElement != null) { 490 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, 491 mContainerElement.getJavaProject().getElementName()); 492 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, 493 mContainerElement.getHandleIdentifier()); 494 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, 495 EMPTY_STRING); 496 //workaround for Eclipse bug 65399 497 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, 498 EMPTY_STRING); 499 } else { 500 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, 501 mProjText.getText()); 502 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, 503 mTestText.getText()); 504 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, 505 EMPTY_STRING); 506 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, 507 mOriginalTestMethodName); 508 } 509 try { 510 mapResources(config); 511 } catch (CoreException e) { 512 // TODO: does the real error need to be extracted out of CoreException 513 AdtPlugin.log(e, "Error occurred saving configuration"); //$NON-NLS-1$ 514 } 515 AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config); 516 517 config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, 518 getSelectedInstrumentation()); 519 config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_TEST_SIZE, 520 getSelectedTestSize()); 521 } 522 523 private void mapResources(ILaunchConfigurationWorkingCopy config) throws CoreException { 524 JUnitMigrationDelegate.mapResources(config); 525 } 526 527 /* (non-Javadoc) 528 * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#dispose() 529 */ 530 @Override 531 public void dispose() { 532 super.dispose(); 533 mTabIcon = null; 534 mJavaElementLabelProvider.dispose(); 535 } 536 537 /* (non-Javadoc) 538 * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getImage() 539 */ 540 @Override 541 public Image getImage() { 542 // reuse icon from the Android App Launch config tab 543 if (mTabIcon == null) { 544 mTabIcon = IconFactory.getInstance().getIcon(MainLaunchConfigTab.LAUNCH_TAB_IMAGE); 545 } 546 return mTabIcon; 547 } 548 549 /** 550 * Show a dialog that lists all main types 551 */ 552 private void handleSearchButtonSelected() { 553 Shell shell = getShell(); 554 555 IJavaProject javaProject = getJavaProject(); 556 557 IType[] types = new IType[0]; 558 boolean[] radioSetting = new boolean[2]; 559 try { 560 // fix for Eclipse bug 66922 Wrong radio behaviour when switching 561 // remember the selected radio button 562 radioSetting[0] = mTestRadioButton.getSelection(); 563 radioSetting[1] = mTestContainerRadioButton.getSelection(); 564 565 types = TestSearchEngine.findTests(getLaunchConfigurationDialog(), javaProject, 566 getTestKind()); 567 } catch (InterruptedException e) { 568 setErrorMessage(e.getMessage()); 569 return; 570 } catch (InvocationTargetException e) { 571 AdtPlugin.log(e.getTargetException(), "Error finding test types"); //$NON-NLS-1$ 572 return; 573 } finally { 574 mTestRadioButton.setSelection(radioSetting[0]); 575 mTestContainerRadioButton.setSelection(radioSetting[1]); 576 } 577 578 SelectionDialog dialog = new TestSelectionDialog(shell, types); 579 dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_testdialog_title); 580 dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_testdialog_message); 581 if (dialog.open() == Window.CANCEL) { 582 return; 583 } 584 585 Object[] results = dialog.getResult(); 586 if ((results == null) || (results.length < 1)) { 587 return; 588 } 589 IType type = (IType) results[0]; 590 591 if (type != null) { 592 mTestText.setText(type.getFullyQualifiedName('.')); 593 javaProject = type.getJavaProject(); 594 mProjText.setText(javaProject.getElementName()); 595 } 596 } 597 598 private ITestKind getTestKind() { 599 // harddcode this to JUnit 3 600 return TestKindRegistry.getDefault().getKind(TestKindRegistry.JUNIT3_TEST_KIND_ID); 601 } 602 603 /** 604 * Show a dialog that lets the user select a Android project. This in turn provides 605 * context for the main type, allowing the user to key a main type name, or 606 * constraining the search for main types to the specified project. 607 */ 608 private void handleProjectButtonSelected() { 609 IJavaProject project = mProjectChooserHelper.chooseJavaProject(getProjectName(), 610 "Please select a project to launch"); 611 if (project == null) { 612 return; 613 } 614 615 String projectName = project.getElementName(); 616 mProjText.setText(projectName); 617 loadInstrumentations(project.getProject()); 618 } 619 620 /** 621 * Return the IJavaProject corresponding to the project name in the project name 622 * text field, or null if the text does not match a Android project name. 623 */ 624 private IJavaProject getJavaProject() { 625 String projectName = getProjectName(); 626 return getJavaModel().getJavaProject(projectName); 627 } 628 629 /** 630 * Returns the name of the currently specified project. Null if no project is selected. 631 */ 632 private String getProjectName() { 633 String projectName = mProjText.getText().trim(); 634 if (projectName.length() < 1) { 635 return null; 636 } 637 return projectName; 638 } 639 640 /** 641 * Convenience method to get the workspace root. 642 */ 643 private IWorkspaceRoot getWorkspaceRoot() { 644 return ResourcesPlugin.getWorkspace().getRoot(); 645 } 646 647 /** 648 * Convenience method to get access to the java model. 649 */ 650 private IJavaModel getJavaModel() { 651 return JavaCore.create(getWorkspaceRoot()); 652 } 653 654 /* (non-Javadoc) 655 * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#isValid(org.eclipse.debug.core.ILaunchConfiguration) 656 */ 657 @Override 658 public boolean isValid(ILaunchConfiguration config) { 659 validatePage(); 660 return getErrorMessage() == null; 661 } 662 663 private void testModeChanged() { 664 boolean isSingleTestMode = mTestRadioButton.getSelection(); 665 setEnableSingleTestGroup(isSingleTestMode); 666 setEnableContainerTestGroup(!isSingleTestMode); 667 if (!isSingleTestMode && mContainerText.getText().length() == 0) { 668 String projText = mProjText.getText(); 669 if (Path.EMPTY.isValidSegment(projText)) { 670 IJavaProject javaProject = getJavaModel().getJavaProject(projText); 671 if (javaProject != null && javaProject.exists()) { 672 setContainerElement(javaProject); 673 } 674 } 675 } 676 validatePage(); 677 updateLaunchConfigurationDialog(); 678 } 679 680 private void validatePage() { 681 setErrorMessage(null); 682 setMessage(null); 683 684 if (mTestContainerRadioButton.getSelection()) { 685 if (mContainerElement == null) { 686 setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_noContainer); 687 return; 688 } 689 validateJavaProject(mContainerElement.getJavaProject()); 690 return; 691 } 692 693 String projectName = mProjText.getText().trim(); 694 if (projectName.length() == 0) { 695 setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_projectnotdefined); 696 return; 697 } 698 699 IStatus status = ResourcesPlugin.getWorkspace().validatePath(IPath.SEPARATOR + projectName, 700 IResource.PROJECT); 701 if (!status.isOK() || !Path.ROOT.isValidSegment(projectName)) { 702 setErrorMessage(Messages.format( 703 JUnitMessages.JUnitLaunchConfigurationTab_error_invalidProjectName, 704 projectName)); 705 return; 706 } 707 708 IProject project = getWorkspaceRoot().getProject(projectName); 709 if (!project.exists()) { 710 setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_projectnotexists); 711 return; 712 } 713 IJavaProject javaProject = JavaCore.create(project); 714 validateJavaProject(javaProject); 715 716 try { 717 if (!project.hasNature(AdtConstants.NATURE_DEFAULT)) { 718 setErrorMessage( 719 LaunchMessages.NonAndroidProjectError); 720 return; 721 } 722 String className = mTestText.getText().trim(); 723 if (className.length() == 0) { 724 setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testnotdefined); 725 return; 726 } 727 if (javaProject.findType(className) == null) { 728 setErrorMessage(Messages.format( 729 JUnitMessages.JUnitLaunchConfigurationTab_error_test_class_not_found, 730 new String[] { className, projectName })); 731 return; 732 } 733 } catch (CoreException e) { 734 AdtPlugin.log(e, "validatePage failed"); //$NON-NLS-1$ 735 } 736 737 validateInstrumentation(); 738 } 739 740 private void validateJavaProject(IJavaProject javaProject) { 741 if (!TestSearchEngine.hasTestCaseType(javaProject)) { 742 setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testcasenotonpath); 743 return; 744 } 745 } 746 747 private void validateInstrumentation() { 748 String instrumentation = getSelectedInstrumentation(); 749 if (instrumentation == null) { 750 setErrorMessage(LaunchMessages.AndroidJUnitTab_NoRunnerError); 751 return; 752 } 753 String result = mInstrValidator.validateInstrumentationRunner(instrumentation); 754 if (result != InstrumentationRunnerValidator.INSTRUMENTATION_OK) { 755 setErrorMessage(result); 756 return; 757 } 758 } 759 760 private String getSelectedInstrumentation() { 761 int selectionIndex = mInstrumentationCombo.getSelectionIndex(); 762 if (mInstrumentations != null && selectionIndex >= 0 && 763 selectionIndex < mInstrumentations.length) { 764 return mInstrumentations[selectionIndex]; 765 } 766 return null; 767 } 768 769 private String getSelectedTestSize() { 770 if (mTestSizeCombo != null) { 771 int index = mTestSizeCombo.getSelectionIndex(); 772 return TEST_SIZE_OPTIONS.get(index); 773 } else { 774 return null; 775 } 776 } 777 778 private void setEnableContainerTestGroup(boolean enabled) { 779 mContainerSearchButton.setEnabled(enabled); 780 mContainerText.setEnabled(enabled); 781 } 782 783 private void setEnableSingleTestGroup(boolean enabled) { 784 mProjLabel.setEnabled(enabled); 785 mProjText.setEnabled(enabled); 786 mProjButton.setEnabled(enabled); 787 mTestLabel.setEnabled(enabled); 788 mTestText.setEnabled(enabled); 789 mSearchButton.setEnabled(enabled && mProjText.getText().length() > 0); 790 mTestMethodLabel.setEnabled(enabled); 791 } 792 793 /* (non-Javadoc) 794 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) 795 */ 796 @Override 797 public void setDefaults(ILaunchConfigurationWorkingCopy config) { 798 IJavaElement javaElement = getContext(); 799 if (javaElement != null) { 800 initializeJavaProject(javaElement, config); 801 } else { 802 // We set empty attributes for project & main type so that when one config is 803 // compared to another, the existence of empty attributes doesn't cause an 804 // incorrect result (the performApply() method can result in empty values 805 // for these attributes being set on a config if there is nothing in the 806 // corresponding text boxes) 807 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, EMPTY_STRING); 808 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, 809 EMPTY_STRING); 810 } 811 initializeTestAttributes(javaElement, config); 812 } 813 814 private void initializeTestAttributes(IJavaElement javaElement, 815 ILaunchConfigurationWorkingCopy config) { 816 if (javaElement != null && javaElement.getElementType() < IJavaElement.COMPILATION_UNIT) { 817 initializeTestContainer(javaElement, config); 818 } else { 819 initializeTestType(javaElement, config); 820 } 821 } 822 823 private void initializeTestContainer(IJavaElement javaElement, 824 ILaunchConfigurationWorkingCopy config) { 825 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, 826 javaElement.getHandleIdentifier()); 827 initializeName(config, javaElement.getElementName()); 828 } 829 830 private void initializeName(ILaunchConfigurationWorkingCopy config, String name) { 831 if (name == null) { 832 name = EMPTY_STRING; 833 } 834 if (name.length() > 0) { 835 int index = name.lastIndexOf('.'); 836 if (index > 0) { 837 name = name.substring(index + 1); 838 } 839 name = getLaunchConfigurationDialog().generateName(name); 840 config.rename(name); 841 } 842 } 843 844 /** 845 * Sets the main type & name attributes on the working copy based on the IJavaElement 846 */ 847 private void initializeTestType(IJavaElement javaElement, 848 ILaunchConfigurationWorkingCopy config) { 849 String name = EMPTY_STRING; 850 String testKindId = null; 851 try { 852 // only do a search for compilation units or class files or source references 853 if (javaElement instanceof ISourceReference) { 854 ITestKind testKind = TestKindRegistry.getContainerTestKind(javaElement); 855 testKindId = testKind.getId(); 856 857 IType[] types = TestSearchEngine.findTests(getLaunchConfigurationDialog(), 858 javaElement, testKind); 859 if ((types == null) || (types.length < 1)) { 860 return; 861 } 862 // Simply grab the first main type found in the searched element 863 name = types[0].getFullyQualifiedName('.'); 864 865 } 866 } catch (InterruptedException ie) { 867 // ignore 868 } catch (InvocationTargetException ite) { 869 // ignore 870 } 871 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, name); 872 if (testKindId != null) { 873 config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, 874 testKindId); 875 } 876 initializeName(config, name); 877 } 878 879 /* (non-Javadoc) 880 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() 881 */ 882 @Override 883 public String getName() { 884 return JUnitMessages.JUnitLaunchConfigurationTab_tab_label; 885 } 886 887 private IJavaElement chooseContainer(IJavaElement initElement) { 888 @SuppressWarnings("rawtypes") 889 Class[] acceptedClasses = new Class[] { IJavaProject.class, 890 IPackageFragment.class }; 891 TypedElementSelectionValidator validator = new TypedElementSelectionValidator( 892 acceptedClasses, false) { 893 @Override 894 public boolean isSelectedValid(Object element) { 895 return true; 896 } 897 }; 898 899 acceptedClasses = new Class[] { IJavaModel.class, IPackageFragmentRoot.class, 900 IJavaProject.class, IPackageFragment.class }; 901 ViewerFilter filter = new TypedViewerFilter(acceptedClasses) { 902 @Override 903 public boolean select(Viewer viewer, Object parent, Object element) { 904 if (element instanceof IPackageFragmentRoot && 905 ((IPackageFragmentRoot) element).isArchive()) { 906 return false; 907 } 908 try { 909 if (element instanceof IPackageFragment && 910 !((IPackageFragment) element).hasChildren()) { 911 return false; 912 } 913 } catch (JavaModelException e) { 914 return false; 915 } 916 return super.select(viewer, parent, element); 917 } 918 }; 919 920 AndroidJavaElementContentProvider provider = new AndroidJavaElementContentProvider(); 921 ILabelProvider labelProvider = new JavaElementLabelProvider( 922 JavaElementLabelProvider.SHOW_DEFAULT); 923 ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), 924 labelProvider, provider); 925 dialog.setValidator(validator); 926 dialog.setComparator(new JavaElementComparator()); 927 dialog.setTitle(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_title); 928 dialog.setMessage(JUnitMessages.JUnitLaunchConfigurationTab_folderdialog_message); 929 dialog.addFilter(filter); 930 dialog.setInput(JavaCore.create(getWorkspaceRoot())); 931 dialog.setInitialSelection(initElement); 932 dialog.setAllowMultiple(false); 933 934 if (dialog.open() == Window.OK) { 935 Object element = dialog.getFirstResult(); 936 return (IJavaElement) element; 937 } 938 return null; 939 } 940 941 private String getPresentationName(IJavaElement element) { 942 return mJavaElementLabelProvider.getText(element); 943 } 944 945 /** 946 * Returns the current Java element context from which to initialize 947 * default settings, or <code>null</code> if none. 948 * 949 * @return Java element context. 950 */ 951 private IJavaElement getContext() { 952 IWorkbenchWindow activeWorkbenchWindow = 953 PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 954 if (activeWorkbenchWindow == null) { 955 return null; 956 } 957 IWorkbenchPage page = activeWorkbenchWindow.getActivePage(); 958 if (page != null) { 959 ISelection selection = page.getSelection(); 960 if (selection instanceof IStructuredSelection) { 961 IStructuredSelection ss = (IStructuredSelection) selection; 962 if (!ss.isEmpty()) { 963 Object obj = ss.getFirstElement(); 964 if (obj instanceof IJavaElement) { 965 return (IJavaElement) obj; 966 } 967 if (obj instanceof IResource) { 968 IJavaElement je = JavaCore.create((IResource) obj); 969 if (je == null) { 970 IProject pro = ((IResource) obj).getProject(); 971 je = JavaCore.create(pro); 972 } 973 if (je != null) { 974 return je; 975 } 976 } 977 } 978 } 979 IEditorPart part = page.getActiveEditor(); 980 if (part != null) { 981 IEditorInput input = part.getEditorInput(); 982 return (IJavaElement) input.getAdapter(IJavaElement.class); 983 } 984 } 985 return null; 986 } 987 988 private void initializeJavaProject(IJavaElement javaElement, 989 ILaunchConfigurationWorkingCopy config) { 990 IJavaProject javaProject = javaElement.getJavaProject(); 991 String name = null; 992 if (javaProject != null && javaProject.exists()) { 993 name = javaProject.getElementName(); 994 } 995 config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, name); 996 } 997 998 private void setButtonGridData(Button button) { 999 GridData gridData = new GridData(); 1000 button.setLayoutData(gridData); 1001 LayoutUtil.setButtonDimensionHint(button); 1002 } 1003 1004 /* (non-Javadoc) 1005 * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getId() 1006 */ 1007 @Override 1008 public String getId() { 1009 return "com.android.ide.eclipse.adt.launch.AndroidJUnitLaunchConfigurationTab"; //$NON-NLS-1$ 1010 } 1011 1012 /** 1013 * Loads the UI with the instrumentations of the specified project, and stores the 1014 * instrumentations in <code>mInstrumentations</code>. 1015 * 1016 * @param project the {@link IProject} to load the instrumentations from. 1017 */ 1018 private void loadInstrumentations(IProject project) { 1019 try { 1020 mInstrValidator = new InstrumentationRunnerValidator(project); 1021 mInstrumentations = (mInstrValidator == null ? null : 1022 mInstrValidator.getInstrumentationNames()); 1023 if (mInstrumentations != null) { 1024 mInstrumentationCombo.removeAll(); 1025 for (String instrumentation : mInstrumentations) { 1026 mInstrumentationCombo.add(instrumentation); 1027 } 1028 // the selection will be set when we update the ui from the current 1029 // config object. 1030 return; 1031 } 1032 } catch (CoreException e) { 1033 AdtPlugin.logAndPrintError(e, project.getName(), 1034 LaunchMessages.AndroidJUnitTab_LoadInstrError_s, 1035 SdkConstants.FN_ANDROID_MANIFEST_XML); 1036 } 1037 // if we reach this point, either project is null, or we got an exception during 1038 // the parsing. In either case, we empty the instrumentation list. 1039 mInstrValidator = null; 1040 mInstrumentations = null; 1041 mInstrumentationCombo.removeAll(); 1042 } 1043 1044 /** 1045 * Overrides the {@link StandardJavaElementContentProvider} to only display Android projects 1046 */ 1047 private static class AndroidJavaElementContentProvider 1048 extends StandardJavaElementContentProvider { 1049 1050 /** 1051 * Override parent to return only Android projects if at the root. Otherwise, use parent 1052 * functionality. 1053 */ 1054 @Override 1055 public Object[] getChildren(Object element) { 1056 if (element instanceof IJavaModel) { 1057 return BaseProjectHelper.getAndroidProjects((IJavaModel) element, null /*filter*/); 1058 } 1059 return super.getChildren(element); 1060 } 1061 } 1062 } 1063