/******************************************************************************* * 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()); } }