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