KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > junit > launcher > JUnit4TestFinder


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * David Saff (saff@mit.edu) - initial API and implementation
10  * (bug 102632: [JUnit] Support for JUnit 4.)
11  *******************************************************************************/

12
13 package org.eclipse.jdt.internal.junit.launcher;
14
15 import java.util.Collection JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.Set JavaDoc;
19
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.NullProgressMonitor;
23 import org.eclipse.core.runtime.SubProgressMonitor;
24
25 import org.eclipse.jdt.core.Flags;
26 import org.eclipse.jdt.core.IJavaElement;
27 import org.eclipse.jdt.core.IMember;
28 import org.eclipse.jdt.core.IMethod;
29 import org.eclipse.jdt.core.IRegion;
30 import org.eclipse.jdt.core.IType;
31 import org.eclipse.jdt.core.ITypeHierarchy;
32 import org.eclipse.jdt.core.JavaCore;
33 import org.eclipse.jdt.core.JavaModelException;
34 import org.eclipse.jdt.core.dom.AST;
35 import org.eclipse.jdt.core.dom.ASTNode;
36 import org.eclipse.jdt.core.dom.ASTParser;
37 import org.eclipse.jdt.core.dom.CompilationUnit;
38 import org.eclipse.jdt.core.dom.IAnnotationBinding;
39 import org.eclipse.jdt.core.dom.IBinding;
40 import org.eclipse.jdt.core.dom.IMethodBinding;
41 import org.eclipse.jdt.core.dom.ITypeBinding;
42 import org.eclipse.jdt.core.dom.Modifier;
43 import org.eclipse.jdt.core.dom.TypeDeclaration;
44 import org.eclipse.jdt.core.search.IJavaSearchConstants;
45 import org.eclipse.jdt.core.search.IJavaSearchScope;
46 import org.eclipse.jdt.core.search.SearchEngine;
47 import org.eclipse.jdt.core.search.SearchMatch;
48 import org.eclipse.jdt.core.search.SearchParticipant;
49 import org.eclipse.jdt.core.search.SearchPattern;
50 import org.eclipse.jdt.core.search.SearchRequestor;
51
52 import org.eclipse.jdt.internal.corext.SourceRange;
53
54 import org.eclipse.jdt.internal.junit.ui.JUnitMessages;
55 import org.eclipse.jdt.internal.junit.ui.JUnitPlugin;
56 import org.eclipse.jdt.internal.junit.util.TestSearchEngine;
57
58
59 public class JUnit4TestFinder implements ITestFinder {
60         
61     private static class Annotation {
62
63         private static final Annotation RUN_WITH= new Annotation("org.junit.runner.RunWith"); //$NON-NLS-1$
64
private static final Annotation TEST= new Annotation("org.junit.Test"); //$NON-NLS-1$
65

66         private final String JavaDoc fName;
67
68         private Annotation(String JavaDoc name) {
69             fName= name;
70         }
71         
72         public String JavaDoc getName() {
73             return fName;
74         }
75         
76         private boolean annotates(IAnnotationBinding[] annotations) throws JavaModelException {
77             for (int i= 0; i < annotations.length; i++) {
78                 ITypeBinding annotationType= annotations[i].getAnnotationType();
79                 if (annotationType != null && (annotationType.getQualifiedName().equals(fName))) {
80                     return true;
81                 }
82             }
83             return false;
84         }
85         
86         public boolean annotatesTypeOrSuperTypes(ITypeBinding type) throws JavaModelException {
87             while (type != null) {
88                 if (annotates(type.getAnnotations())) {
89                     return true;
90                 }
91                 type= type.getSuperclass();
92             }
93             return false;
94         }
95         
96         public boolean annotatesAtLeastOneMethod(ITypeBinding type) throws JavaModelException {
97             while (type != null) {
98                 IMethodBinding[] declaredMethods= type.getDeclaredMethods();
99                 for (int i= 0; i < declaredMethods.length; i++) {
100                     IMethodBinding curr= declaredMethods[i];
101                     if (annotates(curr.getAnnotations())) {
102                         return true;
103                     }
104                 }
105                 type= type.getSuperclass();
106             }
107             return false;
108         }
109     }
110
111     public void findTestsInContainer(IJavaElement element, Set JavaDoc result, IProgressMonitor pm) throws CoreException {
112         if (element == null || result == null) {
113             throw new IllegalArgumentException JavaDoc();
114         }
115         
116         if (element instanceof IType) {
117             if (internalIsTest((IType) element, pm)) {
118                 result.add(element);
119                 return;
120             }
121         }
122
123         if (pm == null)
124             pm= new NullProgressMonitor();
125         
126         try {
127             pm.beginTask(JUnitMessages.JUnit4TestFinder_searching_description, 4);
128             
129             IRegion region= TestSearchEngine.getRegion(element);
130             ITypeHierarchy hierarchy= JavaCore.newTypeHierarchy(region, null, new SubProgressMonitor(pm, 1));
131             IType[] allClasses= hierarchy.getAllClasses();
132             
133             // search for all types with references to RunWith and Test and all subclasses
134
HashSet JavaDoc candidates= new HashSet JavaDoc(allClasses.length);
135             SearchRequestor requestor= new AnnotationSearchRequestor(hierarchy, candidates);
136             
137             IJavaSearchScope scope= SearchEngine.createJavaSearchScope(allClasses, IJavaSearchScope.SOURCES);
138             int matchRule= SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
139             SearchPattern runWithPattern= SearchPattern.createPattern(Annotation.RUN_WITH.getName(), IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.REFERENCES, matchRule);
140             SearchPattern testPattern= SearchPattern.createPattern(Annotation.TEST.getName(), IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.REFERENCES, matchRule);
141             
142             // TODO: Core bug (no results with OR pattern):
143
// SearchPattern annotationsPattern= SearchPattern.createOrPattern(runWithPattern, testPattern);
144
// SearchParticipant[] searchParticipants= new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
145
// new SearchEngine().search(annotationsPattern, searchParticipants, scope, requestor, new SubProgressMonitor(pm, 2));
146

147             SearchParticipant[] searchParticipants= new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
148             new SearchEngine().search(runWithPattern, searchParticipants, scope, requestor, new SubProgressMonitor(pm, 1));
149             new SearchEngine().search(testPattern, searchParticipants, scope, requestor, new SubProgressMonitor(pm, 1));
150             
151             // find all classes in the region
152
for (Iterator JavaDoc iterator= candidates.iterator(); iterator.hasNext();) {
153                 IType curr= (IType) iterator.next();
154                 if (TestSearchEngine.isAccessibleClass(curr) && !Flags.isAbstract(curr.getFlags()) && region.contains(curr)) {
155                     result.add(curr);
156                 }
157             }
158             
159             // add all classes implementing JUnit 3.8's Test interface in the region
160
IType testInterface= element.getJavaProject().findType(JUnitPlugin.TEST_INTERFACE_NAME);
161             if (testInterface != null) {
162                 TestSearchEngine.findTestImplementorClasses(hierarchy, testInterface, region, result);
163             }
164             
165             //JUnit 4.3 can also run JUnit-3.8-style public static Test suite() methods:
166
TestSearchEngine.findSuiteMethods(element, result, new SubProgressMonitor(pm, 1));
167         } finally {
168             pm.done();
169         }
170     }
171
172     private static class AnnotationSearchRequestor extends SearchRequestor {
173         
174         private final Collection JavaDoc fResult;
175         private final ITypeHierarchy fHierarchy;
176
177         public AnnotationSearchRequestor(ITypeHierarchy hierarchy, Collection JavaDoc result) {
178             fHierarchy= hierarchy;
179             fResult= result;
180         }
181
182         public void acceptSearchMatch(SearchMatch match) throws CoreException {
183             if (match.getAccuracy() == SearchMatch.A_ACCURATE && !match.isInsideDocComment()) {
184                 Object JavaDoc element= match.getElement();
185                 if (element instanceof IType || element instanceof IMethod) {
186                     IMember member= (IMember) element;
187                     if (member.getNameRange().getOffset() > match.getOffset()) {
188                         IType type= member.getElementType() == IJavaElement.TYPE ? (IType) member : member.getDeclaringType();
189                         addTypeAndSubtypes(type);
190                     }
191                 }
192             }
193         }
194
195         private void addTypeAndSubtypes(IType type) {
196             if (fResult.add(type)) {
197                 IType[] subclasses= fHierarchy.getSubclasses(type);
198                 for (int i= 0; i < subclasses.length; i++) {
199                     addTypeAndSubtypes(subclasses[i]);
200                 }
201             }
202         }
203     }
204
205     public boolean isTest(IType type) throws JavaModelException {
206         return internalIsTest(type, null);
207     }
208     
209     private boolean internalIsTest(IType type, IProgressMonitor monitor) throws JavaModelException {
210         if (TestSearchEngine.isAccessibleClass(type)) {
211             if (TestSearchEngine.hasSuiteMethod(type)) { // since JUnit 4.3.1
212
return true;
213             }
214             ASTParser parser= ASTParser.newParser(AST.JLS3);
215             /* TODO: When bug 156352 is fixed:
216             parser.setProject(type.getJavaProject());
217             IBinding[] bindings= parser.createBindings(new IJavaElement[] { type }, monitor);
218             if (bindings.length == 1 && bindings[0] instanceof ITypeBinding) {
219                 ITypeBinding binding= (ITypeBinding) bindings[0];
220                 return isTest(binding);
221             }*/

222             
223             if (type.getCompilationUnit() != null) {
224                 parser.setSource(type.getCompilationUnit());
225             } else if (! SourceRange.isAvailable(type.getSourceRange())) { // class file with no source
226
parser.setProject(type.getJavaProject());
227                 IBinding[] bindings= parser.createBindings(new IJavaElement[] { type }, monitor);
228                 if (bindings.length == 1 && bindings[0] instanceof ITypeBinding) {
229                     ITypeBinding binding= (ITypeBinding) bindings[0];
230                     return isTest(binding);
231                 }
232                 return false;
233             } else {
234                 parser.setSource(type.getClassFile());
235             }
236             parser.setFocalPosition(0);
237             parser.setResolveBindings(true);
238             CompilationUnit root= (CompilationUnit) parser.createAST(monitor);
239             ASTNode node= root.findDeclaringNode(type.getKey());
240             if (node instanceof TypeDeclaration) {
241                 ITypeBinding binding= ((TypeDeclaration) node).resolveBinding();
242                 if (binding != null) {
243                     return isTest(binding);
244                 }
245             }
246         }
247         return false;
248         
249     }
250     
251     
252     private boolean isTest(ITypeBinding binding) throws JavaModelException {
253         if (Modifier.isAbstract(binding.getModifiers()))
254             return false;
255         
256         if (Annotation.RUN_WITH.annotatesTypeOrSuperTypes(binding) || Annotation.TEST.annotatesAtLeastOneMethod(binding)) {
257             return true;
258         }
259         return TestSearchEngine.isTestImplementor(binding);
260     }
261 }
262
Popular Tags