View | Details | Raw Unified | Return to bug 372588 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java (-2 / +80 lines)
Lines 7-13 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Xavier Coulon <xcoulon@redhat.com> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512 - [JUnit] test method name cut off before (
10
 *     Xavier Coulon <xcoulon@redhat.com> 
11
 *     - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512 - [JUnit] test method name cut off before (
12
 *     - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588 - [JUnit] Add "Link with Editor" to JUnit view 
11
 *******************************************************************************/
13
 *******************************************************************************/
12
14
13
package org.eclipse.jdt.internal.junit.model;
15
package org.eclipse.jdt.internal.junit.model;
Lines 15-29 Link Here
15
import org.eclipse.jdt.junit.model.ITestCaseElement;
17
import org.eclipse.jdt.junit.model.ITestCaseElement;
16
18
17
import org.eclipse.core.runtime.Assert;
19
import org.eclipse.core.runtime.Assert;
20
import org.eclipse.core.runtime.IAdaptable;
18
21
22
import org.eclipse.jdt.core.IJavaElement;
23
import org.eclipse.jdt.core.IMethod;
24
import org.eclipse.jdt.core.IType;
25
import org.eclipse.jdt.core.JavaModelException;
19
26
20
public class TestCaseElement extends TestElement implements ITestCaseElement {
27
import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
28
29
/**
30
 * 
31
 * @since 3.7 implements {@link IAdaptable}
32
 */
33
public class TestCaseElement extends TestElement implements ITestCaseElement, IAdaptable {
34
35
	private IMethod fJavaMethod= null;
36
37
	private boolean fJavaMethodResolved= false;
21
38
22
	private boolean fIgnored;
39
	private boolean fIgnored;
23
40
24
	public TestCaseElement(TestSuiteElement parent, String id, String testName) {
41
	public TestCaseElement(TestSuiteElement parent, String id, String testName) {
25
		super(parent, id, testName);
42
		super(parent, id, testName);
26
		Assert.isNotNull(parent);
43
		Assert.isNotNull(parent);
44
	}
45
46
	/**
47
	 * @return the name of the Java Method associated with this {@link TestCaseElement}, ie, it
48
	 *         returns the valid java identifier part of the name (in particular, it removes the
49
	 *         brackets suffix for Parameterized JUnit tests).
50
	 * 
51
	 * 
52
	 */
53
	private String getJavaTestMethodName() {
54
		String testMethodName= getTestMethodName();
55
		for (int i= 0; i < testMethodName.length(); i++) {
56
			if (!Character.isJavaIdentifierPart(testMethodName.charAt(i))) {
57
				return testMethodName.substring(0, i);
58
			}
59
		}
60
		return testMethodName;
27
	}
61
	}
28
62
29
	/**
63
	/**
Lines 41-46 Link Here
41
		if (index > 0)
75
		if (index > 0)
42
			return testName.substring(0, index);
76
			return testName.substring(0, index);
43
		return testName;
77
		return testName;
78
	}
79
80
	/**
81
	 * Finds and returns the {@link IMethod} associated with this {@link TestCaseElement}.
82
	 * 
83
	 * @return the corresponding Java method element or null if not found.
84
	 */
85
	public IMethod getJavaMethod() {
86
		if (!fJavaMethodResolved) {
87
			try {
88
				final IType type= getJavaType();
89
				if (type != null) {
90
					final IMethod[] methods= type.getMethods();
91
					String testMethodName= getJavaTestMethodName();
92
					for (int i= 0; i < methods.length; i++) {
93
						if (methods[i].getElementName().equals(testMethodName)) {
94
							fJavaMethod= methods[i];
95
							return methods[i];
96
						}
97
					}
98
				}
99
				return null;
100
			} catch (JavaModelException e) {
101
				JUnitCorePlugin.log(e);
102
			} finally {
103
				fJavaMethodResolved= true;
104
			}
105
		}
106
		return fJavaMethod;
44
	}
107
	}
45
108
46
	/**
109
	/**
Lines 73-76 Link Here
73
	public String toString() {
136
	public String toString() {
74
		return "TestCase: " + getTestClassName() + "." + getTestMethodName() + " : " + super.toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
137
		return "TestCase: " + getTestClassName() + "." + getTestMethodName() + " : " + super.toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
75
	}
138
	}
139
140
	/**
141
	 * Provides support for converting this {@link TestCaseElement} into an {@link IMethod} when the
142
	 * given adapter class is {@link IJavaElement}.
143
	 * 
144
	 * @param adapter the class in which this {@link TestCaseElement} should be adapted.
145
	 * @return an object in the request type, or null if it could not be adapted.
146
	 * @since 3.7
147
	 */
148
	public Object getAdapter(Class adapter) {
149
		if (adapter != null && adapter.equals(IJavaElement.class)) {
150
			return getJavaMethod();
151
		}
152
		return null;
153
	}
76
}
154
}
(-)a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestElement.java (+27 lines)
Lines 20-25 Link Here
20
20
21
import org.eclipse.core.runtime.Assert;
21
import org.eclipse.core.runtime.Assert;
22
22
23
import org.eclipse.jdt.core.IType;
24
import org.eclipse.jdt.core.JavaModelException;
25
26
import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
27
23
28
24
public abstract class TestElement implements ITestElement {
29
public abstract class TestElement implements ITestElement {
25
	public final static class Status {
30
	public final static class Status {
Lines 175-180 Link Here
175
180
176
	private boolean fAssumptionFailed;
181
	private boolean fAssumptionFailed;
177
182
183
	private IType fJavaType= null;
184
185
	private boolean fJavaTypeResolved= false;
186
178
	/**
187
	/**
179
	 * Running time in seconds. Contents depend on the current {@link #getProgressState()}:
188
	 * Running time in seconds. Contents depend on the current {@link #getProgressState()}:
180
	 * <ul>
189
	 * <ul>
Lines 324-329 Link Here
324
		return extractClassName(getTestName());
333
		return extractClassName(getTestName());
325
	}
334
	}
326
335
336
	/**
337
	 * @return the Java {@link IType} associated with this {@link TestElement}.
338
	 */
339
	public IType getJavaType() {
340
		if (!fJavaTypeResolved) {
341
			try {
342
				fJavaType= getTestRunSession().getLaunchedProject().findType(getClassName());
343
			} catch (JavaModelException e) {
344
				JUnitCorePlugin.log(e);
345
			} finally {
346
				fJavaTypeResolved= true;
347
			}
348
		}
349
		return fJavaType;
350
	}
351
352
353
327
	private static String extractClassName(String testNameString) {
354
	private static String extractClassName(String testNameString) {
328
		testNameString= extractRawClassName(testNameString);
355
		testNameString= extractRawClassName(testNameString);
329
		testNameString= testNameString.replace('$', '.'); // see bug 178503
356
		testNameString= testNameString.replace('$', '.'); // see bug 178503
(-)a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestSuiteElement.java (-1 / +67 lines)
Lines 17-24 Link Here
17
import org.eclipse.jdt.junit.model.ITestElement;
17
import org.eclipse.jdt.junit.model.ITestElement;
18
import org.eclipse.jdt.junit.model.ITestSuiteElement;
18
import org.eclipse.jdt.junit.model.ITestSuiteElement;
19
19
20
import org.eclipse.core.runtime.IAdaptable;
20
21
21
public class TestSuiteElement extends TestElement implements ITestSuiteElement {
22
import org.eclipse.jdt.core.IJavaElement;
23
import org.eclipse.jdt.core.IMethod;
24
import org.eclipse.jdt.core.IType;
25
26
27
public class TestSuiteElement extends TestElement implements ITestSuiteElement, IAdaptable {
28
29
	private IJavaElement fJavaElement= null;
30
31
	private boolean fJavaElementResolved= false;
22
32
23
	private List/*<TestElement>*/ fChildren;
33
	private List/*<TestElement>*/ fChildren;
24
	private Status fChildrenStatus;
34
	private Status fChildrenStatus;
Lines 151-154 Link Here
151
		return "TestSuite: " + getSuiteTypeName() + " : " + super.toString() + " (" + fChildren.size() + ")";   //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
161
		return "TestSuite: " + getSuiteTypeName() + " : " + super.toString() + " (" + fChildren.size() + ")";   //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
152
	}
162
	}
153
163
164
	/**
165
	 * Provides support for converting this {@link TestSuiteElement} into an {@link IType} (or an
166
	 * {@link IMethod} when this {@link TestSuiteElement} matches a JUnit Parameterized Test) when
167
	 * the given adapter class is {@link IJavaElement}.
168
	 * 
169
	 * @param adapter the class in which this {@link TestSuiteElement} should be adapted.
170
	 * @return an object in the request type, or null if it could not be adapted.
171
	 * @since 3.7
172
	 */
173
	public Object getAdapter(Class adapter) {
174
		if (adapter != null && adapter.equals(IJavaElement.class)) {
175
			return getJavaElement();
176
		}
177
		return null;
178
	}
179
180
	/**
181
	 * Returns the closest {@link IJavaElement} for the given {@link TestSuiteElement}, including
182
	 * with a work-around for Parameterized tests by looking at the child elements: if there's only
183
	 * one, return its Java {@link IMethod}. Otherwise, return the {@link IType}
184
	 * 
185
	 * @return the {@link IJavaElement} found for this {@link TestSuiteElement}.
186
	 * 
187
	 * @see TestElement#getJavaType()
188
	 */
189
	public IJavaElement getJavaElement() {
190
		if (!fJavaElementResolved) {
191
			// whatever happens, let's consider that the Java Type has been resolved, to make sure we don't come back here again for this TestSuitElement.
192
			fJavaElementResolved= true;
193
			fJavaElement= super.getJavaType();
194
			if (fJavaElement == null) {
195
				if (getChildren().length == 1 && getChildren()[0] instanceof TestCaseElement) {
196
					fJavaElement= ((TestCaseElement)getChildren()[0]).getJavaMethod();
197
				}
198
			}
199
		}
200
		return fJavaElement;
201
	}
202
203
	/**
204
	 * Returns the {@link IType} associated with the given {@link TestSuiteElement}, or uses the
205
	 * work-around in {@link TestSuiteElement#getJavaElement()} to retrieve the {@link IType}
206
	 * associated with the single child {@link TestCaseElement} if this {@link TestSuiteElement}
207
	 * matches a Parameterized JUnit Test.
208
	 * 
209
	 * @see TestElement#getJavaType()
210
	 */
211
	public IType getJavaType() {
212
		final IType javaType= super.getJavaType();
213
		if (javaType != null) {
214
			return javaType;
215
		} else if (getJavaElement() != null) {
216
			return (IType)fJavaElement.getAncestor(IJavaElement.TYPE);
217
		}
218
		return null;
219
	}
154
}
220
}
(-)a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java (-1 / +109 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2013 IBM Corporation and others.
2
 * Copyright (c) 2000, 2014 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 16-21 Link Here
16
 *     Andrew Eisenberg <andrew@eisenberg.as> - [JUnit] Rerun failed first does not work with JUnit4 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140392
16
 *     Andrew Eisenberg <andrew@eisenberg.as> - [JUnit] Rerun failed first does not work with JUnit4 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140392
17
 *     Thirumala Reddy Mutchukota <thirumala@google.com> - [JUnit] Avoid rerun test launch on UI thread - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411841
17
 *     Thirumala Reddy Mutchukota <thirumala@google.com> - [JUnit] Avoid rerun test launch on UI thread - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411841
18
 *     Andrew Eisenberg <andrew@eisenberg.as> - [JUnit] Add a monospace font option for the junit results view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411794
18
 *     Andrew Eisenberg <andrew@eisenberg.as> - [JUnit] Add a monospace font option for the junit results view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411794
19
 *     Xavier Coulon <xcoulon@redhat.com> -  [JUnit] Add "Link with Editor" to JUnit view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588
19
 *******************************************************************************/
20
 *******************************************************************************/
20
package org.eclipse.jdt.internal.junit.ui;
21
package org.eclipse.jdt.internal.junit.ui;
21
22
Lines 96-101 Link Here
96
import org.eclipse.jface.dialogs.MessageDialog;
97
import org.eclipse.jface.dialogs.MessageDialog;
97
import org.eclipse.jface.operation.IRunnableWithProgress;
98
import org.eclipse.jface.operation.IRunnableWithProgress;
98
import org.eclipse.jface.resource.ImageDescriptor;
99
import org.eclipse.jface.resource.ImageDescriptor;
100
import org.eclipse.jface.viewers.ISelection;
99
101
100
import org.eclipse.ui.IActionBars;
102
import org.eclipse.ui.IActionBars;
101
import org.eclipse.ui.IEditorActionBarContributor;
103
import org.eclipse.ui.IEditorActionBarContributor;
Lines 149-154 Link Here
149
151
150
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
152
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
151
153
154
import org.eclipse.jdt.internal.ui.JavaPluginImages;
155
import org.eclipse.jdt.internal.ui.actions.AbstractToggleLinkingAction;
152
import org.eclipse.jdt.internal.ui.viewsupport.ViewHistory;
156
import org.eclipse.jdt.internal.ui.viewsupport.ViewHistory;
153
157
154
/**
158
/**
Lines 210-215 Link Here
210
	private Action fPreviousAction;
214
	private Action fPreviousAction;
211
215
212
	private StopAction fStopAction;
216
	private StopAction fStopAction;
217
218
219
	/**
220
	 * Helper to open and activate editors.
221
	 * 
222
	 * @since 3.7
223
	 */
224
	private LinkWithEditorAction fLinkWithEditorAction;
225
213
	private JUnitCopyAction fCopyAction;
226
	private JUnitCopyAction fCopyAction;
214
	private Action fPasteAction;
227
	private Action fPasteAction;
215
228
Lines 732-737 Link Here
732
						JavaCore.addElementChangedListener(fDirtyListener);
745
						JavaCore.addElementChangedListener(fDirtyListener);
733
					}
746
					}
734
					warnOfContentChange();
747
					warnOfContentChange();
748
					fLinkWithEditorAction.setEnabled(fTestRunSession != null);
749
					setLinkingWithEditorActive(fTestRunSession != null);
735
				}
750
				}
736
			});
751
			});
737
			stopUpdateJobs();
752
			stopUpdateJobs();
Lines 897-902 Link Here
897
			stopTest();
912
			stopTest();
898
			setEnabled(false);
913
			setEnabled(false);
899
		}
914
		}
915
	}
916
917
	/**
918
	 * This action toggles whether this {@link TestRunnerViewPart} links its selection to the active
919
	 * editor.
920
	 *
921
	 */
922
	private class LinkWithEditorAction extends AbstractToggleLinkingAction {
923
924
		/** Image to use when the sync is on.*/
925
		private static final String SYNCED_GIF= "synced.gif"; //$NON-NLS-1$
926
		
927
		/** Image to use when the sync is broken.*/
928
		private static final String SYNC_BROKEN_GIF= "sync_broken.gif"; //$NON-NLS-1$
929
		
930
		private String fIconName = SYNC_BROKEN_GIF;
931
		
932
		LinkWithEditorAction() {
933
			// enable by default
934
			setChecked(true);
935
		}
936
937
		@Override
938
		public void run() {
939
			setLinkingWithEditorActive(isChecked());
940
		}
941
		
942
		/**
943
		 * Updates the Link image with a "normal link" image if parameter is true, or a
944
		 * "broken link" image otherwise
945
		 * 
946
		 * @param isInSync the state of synchronization
947
		 */
948
		public void updateLinkImage(boolean isInSync) {
949
			String iconName= isInSync ? SYNCED_GIF : SYNC_BROKEN_GIF;
950
			if (!iconName.equals(fIconName)) {
951
				JavaPluginImages.setLocalImageDescriptors(fLinkWithEditorAction, iconName);
952
				fIconName= iconName;
953
			}
954
		}
955
956
	}
957
958
	/**
959
	 * @return {@code true} if the {@link LinkWithEditorAction} is checked, false otherwise.
960
	 * @since 3.7
961
	 */
962
	public boolean isLinkWithEditorActive() {
963
		return fLinkWithEditorAction.isChecked();
900
	}
964
	}
901
965
902
	private class RerunLastAction extends Action {
966
	private class RerunLastAction extends Action {
Lines 1198-1203 Link Here
1198
			}
1262
			}
1199
			fTestRunSession.stopTestRun();
1263
			fTestRunSession.stopTestRun();
1200
		}
1264
		}
1265
	}
1266
1267
	/**
1268
	 * Activate the 'Link with Editor' in the current {@link IWorkbenchPage}. (The
1269
	 * {@link TestViewer} will respond to {@link ISelection} changes.)
1270
	 * 
1271
	 * @param active boolean to indicate if the link with editor is active ({@code true}) or not (
1272
	 *            {@code false})
1273
	 * 
1274
	 * @since 3.7
1275
	 */
1276
	public void setLinkingWithEditorActive(final boolean active) {
1277
		if (active) {
1278
			getSite().getPage().addPostSelectionListener(fTestViewer);
1279
			fTestViewer.setSelection(getSite().getPage().getActiveEditor());
1280
		} else {
1281
			getSite().getPage().removePostSelectionListener(fTestViewer);
1282
		}
1283
	}
1284
	
1285
	/**
1286
	 * Updates the Link image with a "normal link" image if parameter is true, or a "broken link"
1287
	 * image otherwise
1288
	 * 
1289
	 * @param isInSync the state of synchronization
1290
	 * 
1291
	 * @since 3.7
1292
	 */
1293
	public void setLinkingWithEditorInSync(final boolean isInSync) {
1294
		fLinkWithEditorAction.updateLinkImage(isInSync);
1201
	}
1295
	}
1202
1296
1203
	private void startUpdateJobs() {
1297
	private void startUpdateJobs() {
Lines 1507-1517 Link Here
1507
				startUpdateJobs();
1601
				startUpdateJobs();
1508
1602
1509
				fStopAction.setEnabled(true);
1603
				fStopAction.setEnabled(true);
1604
				fLinkWithEditorAction.setEnabled(true);
1510
1605
1511
			} else /* old or fresh session: don't want jobs at this stage */ {
1606
			} else /* old or fresh session: don't want jobs at this stage */ {
1512
				stopUpdateJobs();
1607
				stopUpdateJobs();
1513
1608
1514
				fStopAction.setEnabled(fTestRunSession.isKeptAlive());
1609
				fStopAction.setEnabled(fTestRunSession.isKeptAlive());
1610
				fLinkWithEditorAction.setEnabled(fTestRunSession != null);
1611
				// if "Link with Editor" is active, register the listener
1612
				if (isLinkWithEditorActive()) {
1613
					getSite().getPage().addPostSelectionListener(fTestViewer);
1614
					fTestViewer.setSelection(getSite().getPage().getActiveEditor());
1615
				}
1616
1515
				fTestViewer.expandFirstLevel();
1617
				fTestViewer.expandFirstLevel();
1516
			}
1618
			}
1517
		}
1619
		}
Lines 1579-1584 Link Here
1579
		if (fFailureTrace != null) {
1681
		if (fFailureTrace != null) {
1580
			fFailureTrace.dispose();
1682
			fFailureTrace.dispose();
1581
		}
1683
		}
1684
		getSite().getPage().removePostSelectionListener(fTestViewer);
1582
	}
1685
	}
1583
1686
1584
	private void disposeImages() {
1687
	private void disposeImages() {
Lines 1887-1892 Link Here
1887
		fStopAction= new StopAction();
1990
		fStopAction= new StopAction();
1888
		fStopAction.setEnabled(false);
1991
		fStopAction.setEnabled(false);
1889
1992
1993
		fLinkWithEditorAction= new LinkWithEditorAction();
1994
		fLinkWithEditorAction.setEnabled(false);
1995
1890
		fRerunLastTestAction= new RerunLastAction();
1996
		fRerunLastTestAction= new RerunLastAction();
1891
		IHandlerService handlerService= (IHandlerService) getSite().getWorkbenchWindow().getService(IHandlerService.class);
1997
		IHandlerService handlerService= (IHandlerService) getSite().getWorkbenchWindow().getService(IHandlerService.class);
1892
		IHandler handler = new AbstractHandler() {
1998
		IHandler handler = new AbstractHandler() {
Lines 1937-1942 Link Here
1937
		toolBar.add(fRerunFailedFirstAction);
2043
		toolBar.add(fRerunFailedFirstAction);
1938
		toolBar.add(fStopAction);
2044
		toolBar.add(fStopAction);
1939
		toolBar.add(fViewHistory.createHistoryDropDownAction());
2045
		toolBar.add(fViewHistory.createHistoryDropDownAction());
2046
		toolBar.add(new Separator());
2047
		toolBar.add(fLinkWithEditorAction);
1940
2048
1941
2049
1942
		viewMenu.add(fShowTestHierarchyAction);
2050
		viewMenu.add(fShowTestHierarchyAction);
(-)a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java (-4 / +252 lines)
Lines 9-16 Link Here
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Brock Janiczak (brockj@tpg.com.au)
10
 *     Brock Janiczak (brockj@tpg.com.au)
11
 *         - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102236: [JUnit] display execution time next to each test
11
 *         - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102236: [JUnit] display execution time next to each test
12
 *     Xavier Coulon <xcoulon@redhat.com> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512 - [JUnit] test method name cut off before (
12
 *     Xavier Coulon <xcoulon@redhat.com> 
13
13
 *         - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512 - [JUnit] test method name cut off before (
14
 *         - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588 - [JUnit] Add "Link with Editor" to JUnit view 
14
 *******************************************************************************/
15
 *******************************************************************************/
15
16
16
package org.eclipse.jdt.internal.junit.ui;
17
package org.eclipse.jdt.internal.junit.ui;
Lines 23-29 Link Here
23
import java.util.List;
24
import java.util.List;
24
import java.util.ListIterator;
25
import java.util.ListIterator;
25
26
27
import org.eclipse.jdt.junit.model.ITestCaseElement;
26
import org.eclipse.jdt.junit.model.ITestElement;
28
import org.eclipse.jdt.junit.model.ITestElement;
29
import org.eclipse.jdt.junit.model.ITestSuiteElement;
27
30
28
import org.eclipse.swt.SWT;
31
import org.eclipse.swt.SWT;
29
import org.eclipse.swt.dnd.Clipboard;
32
import org.eclipse.swt.dnd.Clipboard;
Lines 40-47 Link Here
40
import org.eclipse.jface.action.MenuManager;
43
import org.eclipse.jface.action.MenuManager;
41
import org.eclipse.jface.action.Separator;
44
import org.eclipse.jface.action.Separator;
42
import org.eclipse.jface.viewers.AbstractTreeViewer;
45
import org.eclipse.jface.viewers.AbstractTreeViewer;
46
import org.eclipse.jface.viewers.ISelection;
43
import org.eclipse.jface.viewers.ISelectionChangedListener;
47
import org.eclipse.jface.viewers.ISelectionChangedListener;
44
import org.eclipse.jface.viewers.IStructuredSelection;
48
import org.eclipse.jface.viewers.IStructuredSelection;
49
import org.eclipse.jface.viewers.ITreeSelection;
45
import org.eclipse.jface.viewers.SelectionChangedEvent;
50
import org.eclipse.jface.viewers.SelectionChangedEvent;
46
import org.eclipse.jface.viewers.StructuredSelection;
51
import org.eclipse.jface.viewers.StructuredSelection;
47
import org.eclipse.jface.viewers.StructuredViewer;
52
import org.eclipse.jface.viewers.StructuredViewer;
Lines 50-61 Link Here
50
import org.eclipse.jface.viewers.Viewer;
55
import org.eclipse.jface.viewers.Viewer;
51
import org.eclipse.jface.viewers.ViewerFilter;
56
import org.eclipse.jface.viewers.ViewerFilter;
52
57
58
import org.eclipse.jface.text.ITextSelection;
59
60
import org.eclipse.ui.IEditorPart;
61
import org.eclipse.ui.ISelectionListener;
53
import org.eclipse.ui.IWorkbenchActionConstants;
62
import org.eclipse.ui.IWorkbenchActionConstants;
63
import org.eclipse.ui.IWorkbenchPart;
64
import org.eclipse.ui.PartInitException;
54
import org.eclipse.ui.part.PageBook;
65
import org.eclipse.ui.part.PageBook;
55
66
56
import org.eclipse.debug.core.ILaunchManager;
67
import org.eclipse.debug.core.ILaunchManager;
57
68
69
import org.eclipse.jdt.core.ICompilationUnit;
70
import org.eclipse.jdt.core.IJavaElement;
58
import org.eclipse.jdt.core.IJavaProject;
71
import org.eclipse.jdt.core.IJavaProject;
72
import org.eclipse.jdt.core.IMethod;
59
import org.eclipse.jdt.core.IType;
73
import org.eclipse.jdt.core.IType;
60
import org.eclipse.jdt.core.JavaModelException;
74
import org.eclipse.jdt.core.JavaModelException;
61
75
Lines 66-76 Link Here
66
import org.eclipse.jdt.internal.junit.model.TestRunSession;
80
import org.eclipse.jdt.internal.junit.model.TestRunSession;
67
import org.eclipse.jdt.internal.junit.model.TestSuiteElement;
81
import org.eclipse.jdt.internal.junit.model.TestSuiteElement;
68
82
83
import org.eclipse.jdt.ui.JavaUI;
84
85
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
86
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
87
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
69
import org.eclipse.jdt.internal.ui.viewsupport.ColoringLabelProvider;
88
import org.eclipse.jdt.internal.ui.viewsupport.ColoringLabelProvider;
70
import org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator;
89
import org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator;
71
90
72
91
73
public class TestViewer {
92
public class TestViewer implements ISelectionListener {
74
	private final class TestSelectionListener implements ISelectionChangedListener {
93
	private final class TestSelectionListener implements ISelectionChangedListener {
75
		public void selectionChanged(SelectionChangedEvent event) {
94
		public void selectionChanged(SelectionChangedEvent event) {
76
			handleSelected();
95
			handleSelected();
Lines 312-317 Link Here
312
			testElement= (TestElement) selection.getFirstElement();
331
			testElement= (TestElement) selection.getFirstElement();
313
		}
332
		}
314
		fTestRunnerPart.handleTestSelected(testElement);
333
		fTestRunnerPart.handleTestSelected(testElement);
334
		// if LinkWithEditor is active, reveal the JavaEditor and select the java type or method 
335
		// matching the selected test element, even if the JavaEditor is opened by not active.
336
		if (fTestRunnerPart.isLinkWithEditorActive()) {
337
			handleTestElementSelected(testElement);
338
		}
315
	}
339
	}
316
340
317
	public synchronized void setShowTime(boolean showTime) {
341
	public synchronized void setShowTime(boolean showTime) {
Lines 578-583 Link Here
578
			fTreeViewer.reveal(current);
602
			fTreeViewer.reveal(current);
579
	}
603
	}
580
604
605
	/**
606
	 * Sets the current selection from the given {@link IEditorPart} (if it is a
607
	 * {@link CompilationUnitEditor}) and its selection.
608
	 * 
609
	 * @param editor the selected Java Element in the active Compilation Unit Editor
610
	 * 
611
	 * @since 3.7
612
	 */
613
	public void setSelection(final IEditorPart editor) {
614
		final IJavaElement selectedJavaElement= getSelectedJavaElementInEditor(editor);
615
		setSelection(selectedJavaElement);
616
	}
617
	
618
	/**
619
	 * Sets the current selection from the given {@link IJavaElement} if it matches an
620
	 * {@link ITestCaseElement} and updates the LinkWithEditorAction image in the associated
621
	 * {@link TestRunnerViewPart}.
622
	 * 
623
	 * @param activeJavaElement the selected Java Element (or null) in the active
624
	 *            {@link IWorkbenchPart}
625
	 * 
626
	 */
627
	private void setSelection(final IJavaElement activeJavaElement) {
628
		final ITestElement activeTestCaseElement= findTestElement(activeJavaElement);
629
		if (activeTestCaseElement != null) {
630
			// selection is in-sync
631
			fTestRunnerPart.setLinkingWithEditorInSync(true);
632
			// update the current selection in the viewer if it does not match with the java element selected in the given part (if it's not the parent TestViewerPart)
633
			final Object currentSelection= getCurrentViewerSelection();
634
			if ((currentSelection instanceof TestCaseElement && ((TestCaseElement)currentSelection).getJavaMethod() != null && !((TestCaseElement)currentSelection).getJavaMethod().equals(
635
					activeJavaElement))
636
					|| (currentSelection instanceof TestSuiteElement && ((TestSuiteElement)currentSelection).getJavaType() != null && !((TestSuiteElement)currentSelection).getJavaType().equals(
637
							activeJavaElement))) {
638
				final IStructuredSelection selection= new StructuredSelection(activeTestCaseElement);
639
				fSelectionProvider.setSelection(selection, true);
640
			}
641
		}
642
		else {
643
			// selection is out-of-sync: show a different icon on the button.
644
			fTestRunnerPart.setLinkingWithEditorInSync(false);
645
		}
646
	}
647
648
	/**
649
	 * @return the current selection in the JUnit Viewer (provided by the underlying selection
650
	 *         provider), or {@code null} if the kind of selection is not an {@link ITreeSelection}
651
	 *         nor an {@link IStructuredSelection}.
652
	 */
653
	private Object getCurrentViewerSelection() {
654
		final ISelection currentSelection= fSelectionProvider.getSelection();
655
		if (currentSelection instanceof ITreeSelection) {
656
			return ((ITreeSelection)currentSelection).getFirstElement();
657
		} else if (currentSelection instanceof IStructuredSelection) {
658
			return ((IStructuredSelection)currentSelection).getFirstElement();
659
		}
660
		return null;
661
	}
662
663
	/**
664
	 * Finds the {@link ITestElement} from the given {@link IJavaElement}
665
	 * 
666
	 * @param javaElement the java element associated with the {@link ITestElement} to find.
667
	 * @return the {@link ITestElement} or null if it could not be found.
668
	 */
669
	private ITestElement findTestElement(final IJavaElement javaElement) {
670
		if (fTestRunSession == null || javaElement == null) {
671
			return null;
672
		}
673
		switch (javaElement.getElementType()) {
674
			case IJavaElement.METHOD:
675
				final IMethod javaMethod= (IMethod)javaElement;
676
				final IType javaType= (IType)javaMethod.getAncestor(IJavaElement.TYPE);
677
				final String testClassName= javaType.getFullyQualifiedName();
678
				final String testMethodName= javaMethod.getElementName();
679
				return findTestCaseElement(fTestRunSession.getTestRoot(), testClassName, testMethodName);
680
			case IJavaElement.TYPE:
681
				return findTestSuiteElement(fTestRunSession.getTestRoot(), ((IType)javaElement).getFullyQualifiedName());
682
			default:
683
				return null;
684
		}
685
	}
686
687
	/**
688
	 * Finds the {@link ITestCaseElement} with the given test class name and test method name in the
689
	 * given {@link ITestSuiteElement}
690
	 * 
691
	 * @param parentElement the parent Test Suite
692
	 * @param testClassName the name of the test class
693
	 * @param testMethodName the name of the test method
694
	 * 
695
	 * @return the {@link ITestCaseElement} or null if it could not be found.
696
	 */
697
	private ITestCaseElement findTestCaseElement(final ITestSuiteElement parentElement, final String testClassName, final String testMethodName) {
698
		for (ITestElement childElement : parentElement.getChildren()) {
699
			if (childElement instanceof ITestCaseElement) {
700
				final TestCaseElement testCaseElement= (TestCaseElement)childElement;
701
				if (testCaseElement.getJavaType() != null && testCaseElement.getJavaType().getFullyQualifiedName().equals(testClassName) && testCaseElement.getJavaMethod() != null
702
						&& testCaseElement.getJavaMethod() != null && testCaseElement.getJavaMethod().getElementName().equals(testMethodName)) {
703
					return testCaseElement;
704
				}
705
			} else if (childElement instanceof ITestSuiteElement) {
706
				final ITestCaseElement localResult= findTestCaseElement((ITestSuiteElement)childElement, testClassName, testMethodName);
707
				if (localResult != null) {
708
					return localResult;
709
				}
710
			}
711
		}
712
		return null;
713
	}
714
715
	/**
716
	 * Finds the {@link ITestSuiteElement} with the given test class name in the given
717
	 * {@link ITestSuiteElement}
718
	 * 
719
	 * @param parentElement the parent Test Suite
720
	 * @param testClassName the name of the test class
721
	 * 
722
	 * @return the {@link ITestSuiteElement} or null if it could not be found.
723
	 */
724
	private ITestSuiteElement findTestSuiteElement(final ITestSuiteElement parentElement, final String testClassName) {
725
		for (ITestElement childElement : parentElement.getChildren()) {
726
			if (childElement instanceof ITestSuiteElement) {
727
				final ITestSuiteElement childTestSuite= (ITestSuiteElement)childElement;
728
				if (childTestSuite.getSuiteTypeName().equals(testClassName)) {
729
					return childTestSuite;
730
				}
731
			}
732
		}
733
		return null;
734
	}
735
581
	public void selectFirstFailure() {
736
	public void selectFirstFailure() {
582
		TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true);
737
		TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true);
583
		if (firstFailure != null)
738
		if (firstFailure != null)
Lines 691-695 Link Here
691
		fTreeViewer.expandToLevel(2);
846
		fTreeViewer.expandToLevel(2);
692
	}
847
	}
693
848
694
}
849
	/**
850
	 * Reacts to a selection change in the active {@link IWorkbenchPart} (or when another part
851
	 * received the focus).
852
	 * 
853
	 * @param part the {@link IWorkbenchPart} in which the selection change occurred
854
	 * @param selection the selection in the given part
855
	 */
856
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
857
		if (part instanceof IEditorPart) {
858
			setSelection((IEditorPart)part);
859
		} else if (part instanceof TestRunnerViewPart) {
860
			fTestRunnerPart.setLinkingWithEditorInSync(true);
861
		}
862
	}
695
863
864
	/**
865
	 * @return the selected {@link IJavaElement} in the current editor if it is a {@link CompilationUnitEditor}, null otherwise. 
866
	 * @param editor the editor
867
	 */
868
	private IJavaElement getSelectedJavaElementInEditor(final IEditorPart editor) {
869
		if (editor instanceof CompilationUnitEditor) {
870
			final CompilationUnitEditor compilationUnitEditor = (CompilationUnitEditor)editor;
871
			try {
872
				final IJavaElement inputJavaElement= JavaUI.getEditorInputJavaElement(editor.getEditorInput());
873
				final ITextSelection selection= (ITextSelection)compilationUnitEditor.getSelectionProvider().getSelection();
874
				final ICompilationUnit compilationUnit= (ICompilationUnit)inputJavaElement.getAncestor(IJavaElement.COMPILATION_UNIT);
875
				return compilationUnit.getElementAt(selection.getOffset());
876
			} catch (JavaModelException e) {
877
				JUnitPlugin.log(e);
878
			}
879
		}
880
		return null;
881
	}
882
883
	/**
884
	 * Handles the case when a {@link TestCaseElement} has been selected: open the associated code
885
	 * in the Java Editor
886
	 * 
887
	 * @param testElement the new selected {@link TestCaseElement}
888
	 */
889
	private void handleTestElementSelected(final ITestElement testElement) {
890
		if (testElement instanceof TestCaseElement) {
891
			final IMethod selectedMethod= ((TestCaseElement)testElement).getJavaMethod();
892
			handleJavaElementSelected(selectedMethod);
893
		} else if (testElement instanceof TestSuiteElement) {
894
			final IJavaElement selectedElement= ((TestSuiteElement)testElement).getJavaElement();
895
			handleJavaElementSelected(selectedElement);
896
		}
897
	}
898
899
	/**
900
	 * Reveals the given {@link IJavaElement} in its associated Editor if this later is already
901
	 * open, and sets the "Link with Editor" button state accordingly.
902
	 * 
903
	 * @param selectedJavaElement the selected {@link IJavaElement} in the {@link TestViewer} that
904
	 *            should be revealed in its Java Editor.
905
	 */
906
	private void handleJavaElementSelected(final IJavaElement selectedJavaElement) {
907
		try {
908
			final IEditorPart editor= EditorUtility.isOpenInEditor(selectedJavaElement);
909
			if (selectedJavaElement != null && editor != null && editor instanceof JavaEditor) {
910
				final JavaEditor javaEditor= (JavaEditor)editor;
911
				final ITextSelection javaEditorSelection= (ITextSelection)javaEditor.getSelectionProvider().getSelection();
912
				final IEditorPart selectedMethodEditor= EditorUtility.isOpenInEditor(selectedJavaElement);
913
				// checks if the editor is already open or not
914
				if (selectedMethodEditor != null) {
915
					// Retrieve the current active editor
916
					final IEditorPart activeEditor= fTestRunnerPart.getSite().getPage().getActiveEditor();
917
					// open the required editor if it is not the active one   
918
					if (!selectedMethodEditor.equals(activeEditor)) {
919
						EditorUtility.openInEditor(selectedJavaElement, false);
920
					}
921
					// retrieve the current java element (unless the associated compilation unit cannot be retrieved)
922
					final ICompilationUnit compilationUnit= (ICompilationUnit)selectedJavaElement.getAncestor(IJavaElement.COMPILATION_UNIT);
923
					if (compilationUnit != null) {
924
						final IJavaElement javaEditorSelectedElement= compilationUnit.getElementAt(javaEditorSelection.getOffset());
925
						// force to reveal the selected element in case where the editor was not active
926
						if (!selectedMethodEditor.equals(activeEditor) || !selectedJavaElement.equals(javaEditorSelectedElement)) {
927
							EditorUtility.revealInEditor(selectedMethodEditor, selectedJavaElement);
928
						}
929
						fTestRunnerPart.setLinkingWithEditorInSync(true);
930
						return;
931
					}
932
				}
933
			}
934
		} catch (JavaModelException e) {
935
			JUnitPlugin.log(e);
936
		} catch (PartInitException e) {
937
			// occurs if the editor could not be opened or the input element is not valid Status code
938
			JUnitPlugin.log(e);
939
		}
940
		fTestRunnerPart.setLinkingWithEditorInSync(false);
941
	}
942
943
}

Return to bug 372588