blob: 027aae7b7b96c32a6b7ebe3e63feb2dfc255a0f6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.core.tests.search;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.wst.jsdt.core.IIncludePathEntry;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchConstants;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchScope;
import org.eclipse.wst.jsdt.core.search.SearchEngine;
import org.eclipse.wst.jsdt.core.search.SearchMatch;
import org.eclipse.wst.jsdt.core.search.SearchParticipant;
import org.eclipse.wst.jsdt.core.search.SearchPattern;
import org.eclipse.wst.jsdt.core.search.SearchRequestor;
import org.eclipse.wst.jsdt.internal.core.JavaModelManager;
import org.eclipse.wst.jsdt.internal.core.JavaProject;
public class AbstractSearchTest extends TestCase {
private String fRootProjectName;
protected String getRootProjectName() {
if (fRootProjectName == null) {
fRootProjectName = new String(CharOperation.lastSegment(getClass().getName().toCharArray(), '.')) + "_";
}
return fRootProjectName;
}
protected JavaProject setupMinimalProject(String name, String fileNames[], String[] sources) throws CoreException {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
if (!project.exists()) {
project.create(new NullProgressMonitor());
}
if (!project.isOpen()) {
project.open(null);
}
IProjectDescription desc = project.getDescription();
List natures = new ArrayList(Arrays.asList(desc.getNatureIds()));
if (!natures.contains(JavaScriptCore.NATURE_ID))
natures.add(JavaScriptCore.NATURE_ID);
desc.setNatureIds((String[]) natures.toArray(new String[0]));
project.setDescription(desc, new NullProgressMonitor());
JavaProject jsProject = (JavaProject) JavaScriptCore.create(project);
jsProject.setRawIncludepath(new IIncludePathEntry[]{JavaScriptCore.newSourceEntry(project.getFullPath()), JavaScriptCore.newContainerEntry(new Path("org.eclipse.wst.jsdt.launching.JRE_CONTAINER"))}, null);
jsProject.setOutputLocation(project.getFullPath(), null);
for (int i = 0; i < sources.length; i++) {
project.getFile(fileNames[i]).create(new ByteArrayInputStream(sources[i].getBytes()), true, null);
}
long time0 = System.currentTimeMillis();
while (JavaModelManager.getJavaModelManager().getIndexManager().awaitingJobsCount() > 0 && System.currentTimeMillis() - time0 < 2000) {
Thread.yield();
}
return jsProject;
}
/**
* @param queryString - the search query string
* @param elementsInScope - the IJavaScriptElements to search through
* @param searchFor determines the nature of the searched elements
* <ul>
* <li>{@link IJavaScriptSearchConstants#CLASS}: only look for classes</li>
* <li>{@link IJavaScriptSearchConstants#INTERFACE}: only look for interfaces</li>
* <li>{@link IJavaScriptSearchConstants#ENUM}: only look for enumeration</li>
* <li>{@link IJavaScriptSearchConstants#ANNOTATION_TYPE}: only look for annotation type</li>
* <li>{@link IJavaScriptSearchConstants#CLASS_AND_ENUM}: only look for classes and enumerations</li>
* <li>{@link IJavaScriptSearchConstants#CLASS_AND_INTERFACE}: only look for classes and interfaces</li>
* <li>{@link IJavaScriptSearchConstants#TYPE}: look for all types (ie. classes, interfaces, enum and annotation types)</li>
* <li>{@link IJavaScriptSearchConstants#FIELD}: look for fields</li>
* <li>{@link IJavaScriptSearchConstants#METHOD}: look for methods</li>
* <li>{@link IJavaScriptSearchConstants#CONSTRUCTOR}: look for constructors</li>
* <li>{@link IJavaScriptSearchConstants#PACKAGE}: look for packages</li>
* </ul>
* @param limitTo determines the nature of the expected matches
* <ul>
* <li>{@link IJavaScriptSearchConstants#DECLARATIONS}: will search declarations matching
* with the corresponding element. In case the element is a method, declarations of matching
* methods in subtypes will also be found, allowing to find declarations of abstract methods, etc.<br>
* Note that additional flags {@link IJavaScriptSearchConstants#IGNORE_DECLARING_TYPE} and
* {@link IJavaScriptSearchConstants#IGNORE_RETURN_TYPE} are ignored for string patterns.
* This is due to the fact that client may omit to define them in string pattern to have same behavior.
* </li>
* <li>{@link IJavaScriptSearchConstants#REFERENCES}: will search references to the given element.</li>
* <li>{@link IJavaScriptSearchConstants#ALL_OCCURRENCES}: will search for either declarations or
* references as specified above.
* </li>
* <li>{@link IJavaScriptSearchConstants#IMPLEMENTORS}: for types, will find all types
* which directly implement/extend a given interface.
* Note that types may be only classes or only interfaces if {@link IJavaScriptSearchConstants#CLASS } or
* {@link IJavaScriptSearchConstants#INTERFACE} is respectively used instead of {@link IJavaScriptSearchConstants#TYPE}.
* </li>
* </ul>
* @param matchRule one of {@link SearchPattern#R_EXACT_MATCH}, {@link SearchPattern#R_PREFIX_MATCH}, {@link SearchPattern#R_PATTERN_MATCH},
* {@link SearchPattern#R_REGEXP_MATCH}, {@link SearchPattern#R_CAMELCASE_MATCH} combined with one of following values:
* {@link SearchPattern#R_CASE_SENSITIVE}, {@link SearchPattern#R_ERASURE_MATCH} or {@link SearchPattern#R_EQUIVALENT_MATCH}.
* e.g. {@link SearchPattern#R_EXACT_MATCH} | {@link SearchPattern#R_CASE_SENSITIVE} if an exact and case sensitive match is requested,
* {@link SearchPattern#R_PREFIX_MATCH} if a prefix non case sensitive match is requested or {@link SearchPattern#R_EXACT_MATCH} | {@link SearchPattern#R_ERASURE_MATCH}
* if a non case sensitive and erasure match is requested.<br>
* Note that {@link SearchPattern#R_ERASURE_MATCH} or {@link SearchPattern#R_EQUIVALENT_MATCH} have no effect
* on non-generic types/methods search.<br>
* Note also that default behavior for generic types/methods search is to find exact matches.
* @return the {@link SearchMatch} instances found
* @throws Exception
*/
public SearchMatch[] runSearchTest(String queryString, IJavaScriptElement[] elementsInScope, int searchFor, int limitTo, int matchRule) throws Exception {
IJavaScriptSearchScope scope = SearchEngine.createJavaSearchScope(elementsInScope);
final List results = new ArrayList();
SearchEngine searchEngine = new SearchEngine();
final SearchPattern searchPattern = SearchPattern.createPattern(queryString, searchFor, limitTo, matchRule);
assertNotNull("search pattern was not created", searchPattern);
SearchRequestor requestor = new SearchRequestor() {
public void acceptSearchMatch(SearchMatch match) throws CoreException {
results.add(match);
}
};
searchEngine.search(searchPattern, new SearchParticipant[]{SearchEngine.getDefaultSearchParticipant()}, scope, requestor, new NullProgressMonitor());
return (SearchMatch[])results.toArray(new SearchMatch[results.size()]);
}
/**
* @param projectQualifier - a unique qualifier to append to the name of the project being created
* @param queryString - the search query string
* @param fileNames - the names of the source files to include within the search scope
* @param fileSources - the respective contents of the source files included within the search scope
* @param searchFor determines the nature of the searched elements
* <ul>
* <li>{@link IJavaScriptSearchConstants#CLASS}: only look for classes</li>
* <li>{@link IJavaScriptSearchConstants#INTERFACE}: only look for interfaces</li>
* <li>{@link IJavaScriptSearchConstants#ENUM}: only look for enumeration</li>
* <li>{@link IJavaScriptSearchConstants#ANNOTATION_TYPE}: only look for annotation type</li>
* <li>{@link IJavaScriptSearchConstants#CLASS_AND_ENUM}: only look for classes and enumerations</li>
* <li>{@link IJavaScriptSearchConstants#CLASS_AND_INTERFACE}: only look for classes and interfaces</li>
* <li>{@link IJavaScriptSearchConstants#TYPE}: look for all types (ie. classes, interfaces, enum and annotation types)</li>
* <li>{@link IJavaScriptSearchConstants#FIELD}: look for fields</li>
* <li>{@link IJavaScriptSearchConstants#METHOD}: look for methods</li>
* <li>{@link IJavaScriptSearchConstants#CONSTRUCTOR}: look for constructors</li>
* <li>{@link IJavaScriptSearchConstants#PACKAGE}: look for packages</li>
* </ul>
* @param limitTo determines the nature of the expected matches
* <ul>
* <li>{@link IJavaScriptSearchConstants#DECLARATIONS}: will search declarations matching
* with the corresponding element. In case the element is a method, declarations of matching
* methods in subtypes will also be found, allowing to find declarations of abstract methods, etc.<br>
* Note that additional flags {@link IJavaScriptSearchConstants#IGNORE_DECLARING_TYPE} and
* {@link IJavaScriptSearchConstants#IGNORE_RETURN_TYPE} are ignored for string patterns.
* This is due to the fact that client may omit to define them in string pattern to have same behavior.
* </li>
* <li>{@link IJavaScriptSearchConstants#REFERENCES}: will search references to the given element.</li>
* <li>{@link IJavaScriptSearchConstants#ALL_OCCURRENCES}: will search for either declarations or
* references as specified above.
* </li>
* <li>{@link IJavaScriptSearchConstants#IMPLEMENTORS}: for types, will find all types
* which directly implement/extend a given interface.
* Note that types may be only classes or only interfaces if {@link IJavaScriptSearchConstants#CLASS } or
* {@link IJavaScriptSearchConstants#INTERFACE} is respectively used instead of {@link IJavaScriptSearchConstants#TYPE}.
* </li>
* </ul>
* @param matchRule one of {@link #R_EXACT_MATCH}, {@link #R_PREFIX_MATCH}, {@link #R_PATTERN_MATCH},
* {@link #R_REGEXP_MATCH}, {@link #R_CAMELCASE_MATCH} combined with one of following values:
* {@link #R_CASE_SENSITIVE}, {@link #R_ERASURE_MATCH} or {@link #R_EQUIVALENT_MATCH}.
* e.g. {@link #R_EXACT_MATCH} | {@link #R_CASE_SENSITIVE} if an exact and case sensitive match is requested,
* {@link #R_PREFIX_MATCH} if a prefix non case sensitive match is requested or {@link #R_EXACT_MATCH} | {@link #R_ERASURE_MATCH}
* if a non case sensitive and erasure match is requested.<br>
* Note that {@link #R_ERASURE_MATCH} or {@link #R_EQUIVALENT_MATCH} have no effect
* on non-generic types/methods search.<br>
* Note also that default behavior for generic types/methods search is to find exact matches.
* @return the {@link SearchMatch} instances found
* @throws Exception
*/
protected SearchMatch[] runSearchTest(String projectQualifier, String queryString, String[] fileNames, String[] fileSources, int searchFor, int limitTo, int matchRule) throws Exception {
IJavaScriptProject project = setupMinimalProject(getRootProjectName()+projectQualifier, fileNames, fileSources);
return runSearchTest(queryString, new IJavaScriptElement[]{project}, searchFor, limitTo, matchRule);
}
public void verifyMatches(String expected, SearchMatch[] matches) {
StringBuffer b = new StringBuffer();
for (int i = 0; i < matches.length; i++) {
char[] value = CharOperation.replace(matches[i].toString().toCharArray(), new char[]{'\r','\n'}, new char[]{'\n'});
value = CharOperation.replace(value, new char[]{'\r'}, new char[]{'\n'});
b.append(value);
}
assertEquals("Unexpected search results", expected, b.toString());
}
}