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.ITestElement.ProgressState; |
30 |
import org.eclipse.jdt.junit.model.ITestElementContainer; |
31 |
import org.eclipse.jdt.junit.model.ITestSuiteElement; |
27 |
|
32 |
|
28 |
import org.eclipse.swt.SWT; |
33 |
import org.eclipse.swt.SWT; |
29 |
import org.eclipse.swt.dnd.Clipboard; |
34 |
import org.eclipse.swt.dnd.Clipboard; |
Lines 42-49
Link Here
|
42 |
import org.eclipse.jface.action.MenuManager; |
47 |
import org.eclipse.jface.action.MenuManager; |
43 |
import org.eclipse.jface.action.Separator; |
48 |
import org.eclipse.jface.action.Separator; |
44 |
import org.eclipse.jface.viewers.AbstractTreeViewer; |
49 |
import org.eclipse.jface.viewers.AbstractTreeViewer; |
|
|
50 |
import org.eclipse.jface.viewers.ISelection; |
45 |
import org.eclipse.jface.viewers.ISelectionChangedListener; |
51 |
import org.eclipse.jface.viewers.ISelectionChangedListener; |
46 |
import org.eclipse.jface.viewers.IStructuredSelection; |
52 |
import org.eclipse.jface.viewers.IStructuredSelection; |
|
|
53 |
import org.eclipse.jface.viewers.ITreeSelection; |
47 |
import org.eclipse.jface.viewers.SelectionChangedEvent; |
54 |
import org.eclipse.jface.viewers.SelectionChangedEvent; |
48 |
import org.eclipse.jface.viewers.StructuredSelection; |
55 |
import org.eclipse.jface.viewers.StructuredSelection; |
49 |
import org.eclipse.jface.viewers.StructuredViewer; |
56 |
import org.eclipse.jface.viewers.StructuredViewer; |
Lines 52-64
Link Here
|
52 |
import org.eclipse.jface.viewers.Viewer; |
59 |
import org.eclipse.jface.viewers.Viewer; |
53 |
import org.eclipse.jface.viewers.ViewerFilter; |
60 |
import org.eclipse.jface.viewers.ViewerFilter; |
54 |
|
61 |
|
|
|
62 |
import org.eclipse.jface.text.ITextSelection; |
63 |
|
64 |
import org.eclipse.ui.IEditorPart; |
65 |
import org.eclipse.ui.ISelectionListener; |
55 |
import org.eclipse.ui.IWorkbenchActionConstants; |
66 |
import org.eclipse.ui.IWorkbenchActionConstants; |
|
|
67 |
import org.eclipse.ui.IWorkbenchPart; |
68 |
import org.eclipse.ui.PartInitException; |
56 |
import org.eclipse.ui.part.PageBook; |
69 |
import org.eclipse.ui.part.PageBook; |
57 |
|
70 |
|
58 |
import org.eclipse.debug.core.ILaunchConfiguration; |
71 |
import org.eclipse.debug.core.ILaunchConfiguration; |
59 |
import org.eclipse.debug.core.ILaunchManager; |
72 |
import org.eclipse.debug.core.ILaunchManager; |
60 |
|
73 |
|
|
|
74 |
import org.eclipse.jdt.core.IClassFile; |
75 |
import org.eclipse.jdt.core.ICompilationUnit; |
76 |
import org.eclipse.jdt.core.IJavaElement; |
61 |
import org.eclipse.jdt.core.IJavaProject; |
77 |
import org.eclipse.jdt.core.IJavaProject; |
|
|
78 |
import org.eclipse.jdt.core.IMethod; |
62 |
import org.eclipse.jdt.core.IType; |
79 |
import org.eclipse.jdt.core.IType; |
63 |
import org.eclipse.jdt.core.JavaModelException; |
80 |
import org.eclipse.jdt.core.JavaModelException; |
64 |
|
81 |
|
Lines 72-82
Link Here
|
72 |
|
89 |
|
73 |
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
90 |
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
74 |
|
91 |
|
|
|
92 |
import org.eclipse.jdt.ui.JavaUI; |
93 |
|
94 |
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor; |
95 |
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; |
96 |
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; |
75 |
import org.eclipse.jdt.internal.ui.viewsupport.ColoringLabelProvider; |
97 |
import org.eclipse.jdt.internal.ui.viewsupport.ColoringLabelProvider; |
76 |
import org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator; |
98 |
import org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator; |
77 |
|
99 |
|
78 |
|
100 |
|
79 |
public class TestViewer { |
101 |
public class TestViewer implements ISelectionListener { |
80 |
private final class TestSelectionListener implements ISelectionChangedListener { |
102 |
private final class TestSelectionListener implements ISelectionChangedListener { |
81 |
public void selectionChanged(SelectionChangedEvent event) { |
103 |
public void selectionChanged(SelectionChangedEvent event) { |
82 |
handleSelected(); |
104 |
handleSelected(); |
Lines 343-348
Link Here
|
343 |
testElement= (TestElement) selection.getFirstElement(); |
365 |
testElement= (TestElement) selection.getFirstElement(); |
344 |
} |
366 |
} |
345 |
fTestRunnerPart.handleTestSelected(testElement); |
367 |
fTestRunnerPart.handleTestSelected(testElement); |
|
|
368 |
// if LinkWithEditor is active, reveal the JavaEditor and select the java type or method |
369 |
// matching the selected test element, even if the JavaEditor is opened by not active. |
370 |
if (fTestRunnerPart.isLinkWithEditorActive()) { |
371 |
handleTestElementSelected(testElement); |
372 |
} |
346 |
} |
373 |
} |
347 |
|
374 |
|
348 |
public synchronized void setShowTime(boolean showTime) { |
375 |
public synchronized void setShowTime(boolean showTime) { |
Lines 609-614
Link Here
|
609 |
fTreeViewer.reveal(current); |
636 |
fTreeViewer.reveal(current); |
610 |
} |
637 |
} |
611 |
|
638 |
|
|
|
639 |
/** |
640 |
* Sets the current selection from the given {@link IEditorPart} (if it is a |
641 |
* {@link CompilationUnitEditor}) and its selection. |
642 |
* |
643 |
* @param editor the selected Java Element in the active Compilation Unit Editor |
644 |
* |
645 |
* @since 3.8 |
646 |
*/ |
647 |
public void setSelection(final IEditorPart editor) { |
648 |
if (editor != null) { |
649 |
final IJavaElement selectedJavaElement= getSelectedJavaElementInEditor(editor); |
650 |
setSelection(selectedJavaElement); |
651 |
} |
652 |
} |
653 |
|
654 |
/** |
655 |
* Sets the current selection from the given {@link IJavaElement} if it matches an |
656 |
* {@link ITestCaseElement} and updates the LinkWithEditorAction image in the associated |
657 |
* {@link TestRunnerViewPart}. |
658 |
* |
659 |
* @param activeJavaElement the selected Java Element (or null) in the active |
660 |
* {@link IWorkbenchPart} |
661 |
* |
662 |
*/ |
663 |
private void setSelection(final IJavaElement activeJavaElement) { |
664 |
final ITestElement activeTestCaseElement= findClosestTestElement(activeJavaElement, getCurrentViewerSelection()); |
665 |
if (activeTestCaseElement != null) { |
666 |
// 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) |
667 |
final Object currentSelection= getCurrentViewerSelection(); |
668 |
if (!activeTestCaseElement.equals(currentSelection)) { |
669 |
final IStructuredSelection selection= new StructuredSelection(activeTestCaseElement); |
670 |
fSelectionProvider.setSelection(selection, true); |
671 |
} |
672 |
// ensure link with editor is in 'synced' mode |
673 |
fTestRunnerPart.setLinkingWithEditorInSync(true); |
674 |
} |
675 |
else { |
676 |
// selection is out-of-sync: show a different icon on the button. |
677 |
fTestRunnerPart.setLinkingWithEditorInSync(false); |
678 |
} |
679 |
} |
680 |
|
681 |
/** |
682 |
* @return the current selection in the JUnit Viewer (provided by the underlying selection |
683 |
* provider), or {@code null} if the kind of selection is not an {@link ITreeSelection} |
684 |
* nor an {@link IStructuredSelection}. |
685 |
*/ |
686 |
private Object getCurrentViewerSelection() { |
687 |
final ISelection currentSelection= fSelectionProvider.getSelection(); |
688 |
if (currentSelection instanceof ITreeSelection) { |
689 |
return ((ITreeSelection)currentSelection).getFirstElement(); |
690 |
} else if (currentSelection instanceof IStructuredSelection) { |
691 |
return ((IStructuredSelection)currentSelection).getFirstElement(); |
692 |
} |
693 |
return null; |
694 |
} |
695 |
|
696 |
/** |
697 |
* Finds the closest {@link ITestElement} from the given {@link IJavaElement} |
698 |
* |
699 |
* @param javaElement the java element associated with the {@link ITestElement} to find. |
700 |
* @param currentSelection the current selection in the TestViewer |
701 |
* @return the {@link ITestElement} or null if it could not be found. |
702 |
*/ |
703 |
private ITestElement findClosestTestElement(final IJavaElement javaElement, final Object currentSelection) { |
704 |
// skip if JUnit is still running or if no Java element was selected |
705 |
if (fTestRunnerPart.getCurrentProgressState() != ProgressState.COMPLETED || javaElement == null) { |
706 |
return null; |
707 |
} |
708 |
final ITestElement currentTestElement= (ITestElement) currentSelection; |
709 |
// if the current selection already matches the given java element |
710 |
if ((currentSelection instanceof TestCaseElement && ((TestCaseElement) currentSelection).getJavaMethod() != null && ((TestCaseElement) currentSelection).getJavaMethod().equals( |
711 |
javaElement)) |
712 |
|| (currentSelection instanceof TestSuiteElement && ((TestSuiteElement) currentSelection).getJavaType() != null && ((TestSuiteElement) currentSelection).getJavaType().equals( |
713 |
javaElement))) { |
714 |
return currentTestElement; |
715 |
} |
716 |
// if current selection is a TestCaseElement / Java method, move to the parent |
717 |
ITestElementContainer currentElementContainer= fTestRunSession; |
718 |
if (currentTestElement instanceof ITestElementContainer) { |
719 |
currentElementContainer= (ITestElementContainer) currentTestElement; |
720 |
} else if (currentTestElement != null) { |
721 |
currentElementContainer= currentTestElement.getParentContainer(); |
722 |
} |
723 |
// now, look in the current test container, or move to parent container until root |
724 |
while (currentElementContainer != null) { |
725 |
switch (javaElement.getElementType()) { |
726 |
case IJavaElement.METHOD: |
727 |
final ITestCaseElement resultTestCaseElement= findTestCaseElement(currentElementContainer, (IMethod) javaElement); |
728 |
if (resultTestCaseElement != null) { |
729 |
return resultTestCaseElement; |
730 |
} |
731 |
break; |
732 |
case IJavaElement.TYPE: |
733 |
final ITestSuiteElement resultTestSuiteElement= findTestSuiteElement(currentElementContainer, (IType) javaElement); |
734 |
if (resultTestSuiteElement != null) { |
735 |
return resultTestSuiteElement; |
736 |
} |
737 |
break; |
738 |
default: |
739 |
// no result will be provided if the user selects anything else, including package declaration, imports and fields. |
740 |
break; |
741 |
} |
742 |
currentElementContainer= currentElementContainer.getParentContainer(); |
743 |
} |
744 |
return null; |
745 |
} |
746 |
|
747 |
/** |
748 |
* Finds the {@link ITestCaseElement} with the given test class name and test method name in the |
749 |
* given {@link ITestSuiteElement} |
750 |
* |
751 |
* @param parentElement the parent Test Suite |
752 |
* @param javaMethod the java method corresponding to the {@link ITestCaseElement} to find |
753 |
* |
754 |
* @return the {@link ITestCaseElement} or null if it could not be found. |
755 |
*/ |
756 |
private ITestCaseElement findTestCaseElement(final ITestElementContainer parentElement, final IMethod javaMethod) { |
757 |
final IType javaType= (IType) javaMethod.getAncestor(IJavaElement.TYPE); |
758 |
final String testClassName= javaType.getFullyQualifiedName(); |
759 |
final String testMethodName= javaMethod.getElementName(); |
760 |
for (ITestElement childElement : parentElement.getChildren()) { |
761 |
if (childElement instanceof ITestCaseElement) { |
762 |
final TestCaseElement testCaseElement= (TestCaseElement)childElement; |
763 |
if (testCaseElement.getJavaType() != null && testCaseElement.getJavaType().getFullyQualifiedName().equals(testClassName) && testCaseElement.getJavaMethod() != null |
764 |
&& testCaseElement.getJavaMethod() != null && testCaseElement.getJavaMethod().getElementName().equals(testMethodName)) { |
765 |
return testCaseElement; |
766 |
} |
767 |
} else if (childElement instanceof ITestSuiteElement) { |
768 |
final ITestCaseElement localResult= findTestCaseElement((ITestSuiteElement) childElement, javaMethod); |
769 |
if (localResult != null) { |
770 |
return localResult; |
771 |
} |
772 |
} |
773 |
} |
774 |
return null; |
775 |
} |
776 |
|
777 |
/** |
778 |
* Finds the {@link ITestSuiteElement} with the given test class name in the given |
779 |
* {@link ITestSuiteElement} |
780 |
* |
781 |
* @param parentElement the parent Test Suite |
782 |
* @param javaType the Java type corresponding to the {@link ITestSuiteElement} to find |
783 |
* |
784 |
* @return the {@link ITestSuiteElement} or null if it could not be found. |
785 |
*/ |
786 |
private ITestSuiteElement findTestSuiteElement(final ITestElementContainer parentElement, final IType javaType) { |
787 |
final String testClassName= javaType.getFullyQualifiedName(); |
788 |
if (parentElement instanceof ITestSuiteElement && ((ITestSuiteElement) parentElement).getSuiteTypeName().equals(testClassName)) { |
789 |
return (ITestSuiteElement) parentElement; |
790 |
} |
791 |
for (ITestElement childElement : parentElement.getChildren()) { |
792 |
if (childElement instanceof ITestSuiteElement) { |
793 |
final ITestSuiteElement childTestSuite= (ITestSuiteElement)childElement; |
794 |
if (childTestSuite.getSuiteTypeName().equals(testClassName)) { |
795 |
return childTestSuite; |
796 |
} |
797 |
final ITestSuiteElement matchingNestedTestSuiteElement= findTestSuiteElement(childTestSuite, javaType); |
798 |
if (matchingNestedTestSuiteElement != null) { |
799 |
return matchingNestedTestSuiteElement; |
800 |
} |
801 |
} |
802 |
} |
803 |
return null; |
804 |
} |
805 |
|
612 |
public void selectFirstFailure() { |
806 |
public void selectFirstFailure() { |
613 |
TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true); |
807 |
TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true); |
614 |
if (firstFailure != null) |
808 |
if (firstFailure != null) |
Lines 722-726
Link Here
|
722 |
fTreeViewer.expandToLevel(2); |
916 |
fTreeViewer.expandToLevel(2); |
723 |
} |
917 |
} |
724 |
|
918 |
|
725 |
} |
919 |
/** |
|
|
920 |
* Reacts to a selection change in the active {@link IWorkbenchPart} (or when another part |
921 |
* received the focus). |
922 |
* |
923 |
* @param part the {@link IWorkbenchPart} in which the selection change occurred |
924 |
* @param selection the selection in the given part |
925 |
* @since 3.8 |
926 |
*/ |
927 |
public void selectionChanged(IWorkbenchPart part, ISelection selection) { |
928 |
if (part instanceof IEditorPart) { |
929 |
setSelection((IEditorPart)part); |
930 |
} |
931 |
// any ITreeSelection (eg: Project Explorer, Package Explorer, Content Outline) should be considered, too. |
932 |
else if (selection instanceof ITreeSelection) { |
933 |
final ITreeSelection treeSelection= (ITreeSelection) selection; |
934 |
if (treeSelection.size() == 1) { |
935 |
setSelection((IJavaElement) treeSelection.getFirstElement()); |
936 |
} |
937 |
} |
938 |
} |
726 |
|
939 |
|
|
|
940 |
/** |
941 |
* @return the selected {@link IJavaElement} in the current editor if it is a {@link CompilationUnitEditor}, null otherwise. |
942 |
* @param editor the editor |
943 |
*/ |
944 |
private IJavaElement getSelectedJavaElementInEditor(final IEditorPart editor) { |
945 |
if (editor instanceof JavaEditor) { |
946 |
final JavaEditor javaEditor= (JavaEditor) editor; |
947 |
try { |
948 |
final IJavaElement inputJavaElement= JavaUI.getEditorInputJavaElement(editor.getEditorInput()); |
949 |
// when the editor is opened on a .class file, not a .java source file |
950 |
if (inputJavaElement.getElementType() == IJavaElement.CLASS_FILE) { |
951 |
final IClassFile classFile= (IClassFile) inputJavaElement; |
952 |
return classFile.getType(); |
953 |
} |
954 |
final ITextSelection selection= (ITextSelection) javaEditor.getSelectionProvider().getSelection(); |
955 |
final ICompilationUnit compilationUnit= (ICompilationUnit)inputJavaElement.getAncestor(IJavaElement.COMPILATION_UNIT); |
956 |
final IJavaElement selectedElement= compilationUnit.getElementAt(selection.getOffset()); |
957 |
return selectedElement; |
958 |
} catch (JavaModelException e) { |
959 |
JUnitPlugin.log(e); |
960 |
} |
961 |
} |
962 |
return null; |
963 |
} |
964 |
|
965 |
/** |
966 |
* Handles the case when a {@link TestCaseElement} has been selected, unless there's a |
967 |
* {@link TestRunSession} in progress. |
968 |
* |
969 |
* @param testElement the new selected {@link TestCaseElement} |
970 |
*/ |
971 |
private void handleTestElementSelected(final ITestElement testElement) { |
972 |
if (fTestRunnerPart.getCurrentProgressState().equals(ProgressState.RUNNING)) { |
973 |
return; |
974 |
} |
975 |
if (testElement instanceof TestCaseElement) { |
976 |
final IMethod selectedMethod= ((TestCaseElement)testElement).getJavaMethod(); |
977 |
handleJavaElementSelected(selectedMethod); |
978 |
} else if (testElement instanceof TestSuiteElement) { |
979 |
final IJavaElement selectedElement= ((TestSuiteElement)testElement).getJavaElement(); |
980 |
handleJavaElementSelected(selectedElement); |
981 |
} |
982 |
} |
983 |
|
984 |
/** |
985 |
* Reveals the given {@link IJavaElement} in its associated Editor if this later is already |
986 |
* open, and sets the "Link with Editor" button state accordingly. |
987 |
* |
988 |
* @param selectedJavaElement the selected {@link IJavaElement} in the {@link TestViewer} that |
989 |
* should be revealed in its Java Editor. |
990 |
*/ |
991 |
private void handleJavaElementSelected(final IJavaElement selectedJavaElement) { |
992 |
// skip if there's no editor open (yet) |
993 |
if (fTestRunnerPart.getSite().getPage().getActiveEditor() == null) { |
994 |
return; |
995 |
} |
996 |
try { |
997 |
final IEditorPart editor= EditorUtility.isOpenInEditor(selectedJavaElement); |
998 |
if (selectedJavaElement != null && editor != null && editor instanceof JavaEditor) { |
999 |
final JavaEditor javaEditor= (JavaEditor)editor; |
1000 |
final ITextSelection javaEditorSelection= (ITextSelection)javaEditor.getSelectionProvider().getSelection(); |
1001 |
final IEditorPart selectedMethodEditor= EditorUtility.isOpenInEditor(selectedJavaElement); |
1002 |
// checks if the editor is already open or not |
1003 |
if (selectedMethodEditor != null) { |
1004 |
// Retrieve the current active editor |
1005 |
final IEditorPart activeEditor= fTestRunnerPart.getSite().getPage().getActiveEditor(); |
1006 |
// open the required editor if it is not the active one |
1007 |
if (!selectedMethodEditor.equals(activeEditor)) { |
1008 |
EditorUtility.openInEditor(selectedJavaElement, false); |
1009 |
} |
1010 |
// retrieve the current java element (unless the associated compilation unit cannot be retrieved) |
1011 |
final ICompilationUnit compilationUnit= (ICompilationUnit)selectedJavaElement.getAncestor(IJavaElement.COMPILATION_UNIT); |
1012 |
fTestRunnerPart.setLinkingWithEditorInSync(true); |
1013 |
if (compilationUnit != null) { |
1014 |
final IJavaElement javaEditorSelectedElement= compilationUnit.getElementAt(javaEditorSelection.getOffset()); |
1015 |
// force to reveal the selected element in case where the editor was not active |
1016 |
if (!selectedMethodEditor.equals(activeEditor) || !selectedJavaElement.equals(javaEditorSelectedElement)) { |
1017 |
EditorUtility.revealInEditor(selectedMethodEditor, selectedJavaElement); |
1018 |
} |
1019 |
} |
1020 |
return; |
1021 |
} |
1022 |
} |
1023 |
} catch (JavaModelException e) { |
1024 |
JUnitPlugin.log(e); |
1025 |
} catch (PartInitException e) { |
1026 |
// occurs if the editor could not be opened or the input element is not valid Status code |
1027 |
JUnitPlugin.log(e); |
1028 |
} |
1029 |
fTestRunnerPart.setLinkingWithEditorInSync(false); |
1030 |
} |
1031 |
|
1032 |
} |