| /* |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
| * |
| * Copyright 2011 Oracle and/or its affiliates. All rights reserved. |
| * |
| * Oracle and Java are registered trademarks of Oracle and/or its affiliates. |
| * Other names may be trademarks of their respective owners. |
| * |
| * The contents of this file are subject to the terms of either the GNU |
| * General Public License Version 2 only ("GPL") or the Common |
| * Development and Distribution License("CDDL") (collectively, the |
| * "License"). You may not use this file except in compliance with the |
| * License. You can obtain a copy of the License at |
| * http://www.netbeans.org/cddl-gplv2.html |
| * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
| * specific language governing permissions and limitations under the |
| * License. When distributing the software, include this License Header |
| * Notice in each file and include the License file at |
| * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the GPL Version 2 section of the License file that |
| * accompanied this code. If applicable, add the following below the |
| * License Header, with the fields enclosed by brackets [] replaced by |
| * your own identifying information: |
| * "Portions Copyrighted [year] [name of copyright owner]" |
| * |
| * If you wish your version of this file to be governed by only the CDDL |
| * or only the GPL Version 2, indicate your decision by adding |
| * "[Contributor] elects to include this software in this distribution |
| * under the [CDDL or GPL Version 2] license." If you do not indicate a |
| * single choice of license, a recipient has the option to distribute |
| * your version of this file under either the CDDL, the GPL Version 2 or |
| * to extend the choice of license to its licensees as provided above. |
| * However, if you add GPL Version 2 code and therefore, elected the GPL |
| * Version 2 license, then the option applies only if the new code is |
| * made subject to such option by the copyright holder. |
| * |
| * Contributor(s): |
| * |
| * Portions Copyrighted 2011 Sun Microsystems, Inc. |
| */ |
| package org.netbeans.modules.jackpot30.indexer.usages; |
| |
| import com.sun.source.util.TreePath; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.util.ElementFilter; |
| import org.apache.lucene.analysis.KeywordAnalyzer; |
| import org.apache.lucene.document.Document; |
| import org.apache.lucene.document.Field; |
| import org.apache.lucene.document.Field.Index; |
| import org.apache.lucene.document.Field.Store; |
| import org.apache.lucene.document.Fieldable; |
| import org.apache.lucene.index.IndexReader; |
| import org.apache.lucene.index.IndexWriter; |
| import org.apache.lucene.store.Directory; |
| import org.apache.lucene.store.RAMDirectory; |
| import org.netbeans.api.editor.mimelookup.MimePath; |
| import org.netbeans.api.java.source.CompilationController; |
| import org.netbeans.api.java.source.ElementHandle; |
| import org.netbeans.api.java.source.JavaSource; |
| import org.netbeans.api.java.source.Task; |
| import org.netbeans.junit.NbTestCase; |
| import org.netbeans.modules.jackpot30.backend.impl.spi.IndexAccessor; |
| import org.netbeans.modules.java.source.indexing.JavaCustomIndexer; |
| import org.netbeans.modules.java.source.parsing.JavacParser; |
| import org.netbeans.modules.java.source.parsing.JavacParserFactory; |
| import org.netbeans.modules.parsing.impl.indexing.CacheFolder; |
| import org.netbeans.modules.parsing.impl.indexing.FileObjectIndexable; |
| import org.netbeans.modules.parsing.impl.indexing.MimeTypes; |
| import org.netbeans.modules.parsing.impl.indexing.SPIAccessor; |
| import org.netbeans.spi.editor.mimelookup.MimeDataProvider; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.filesystems.MIMEResolver; |
| import org.openide.util.Lookup; |
| import org.openide.util.lookup.Lookups; |
| import org.openide.util.lookup.ServiceProvider; |
| |
| /** |
| * |
| * @author lahvac |
| */ |
| public class IndexerImplTest extends NbTestCase { |
| |
| public IndexerImplTest(String testName) { |
| super(testName); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| Set<String> mimeTypes = MimeTypes.getAllMimeTypes(); |
| if (mimeTypes == null) { |
| mimeTypes = new HashSet<String>(); |
| } else { |
| mimeTypes = new HashSet<String>(mimeTypes); |
| } |
| |
| mimeTypes.add("text/x-java"); |
| MimeTypes.setAllMimeTypes(mimeTypes); |
| |
| org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects(); |
| clearWorkDir(); |
| CacheFolder.setCacheFolder(FileUtil.toFileObject(getWorkDir())); |
| super.setUp(); |
| } |
| |
| public void testMethodSignatures() throws IOException { |
| doMethodSignatureTest("package test; public class Test { public void test() {} }", "()V;"); |
| doMethodSignatureTest("package test; public class Test { public <T extends String> void test(java.util.Map<java.util.List<String>, T> m, boolean p) {} }", "<T:Ljava/lang/String;>(Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;TT;>;Z)V;"); |
| doMethodSignatureTest("package test; public class Test <T extends String> { public void test(java.util.Map<java.util.List<String>, T> m, boolean p) {} }", "(Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;TT;>;Z)V;"); |
| doMethodSignatureTest("package test; public class Test { public void test() throws java.io.IOException {} }", "()V^Ljava/io/IOException;;"); |
| doMethodSignatureTest("package test; public class Test { public void test(java.util.List<? extends String> l) {} }", "(Ljava/util/List<+Ljava/lang/String;>;)V;"); |
| doMethodSignatureTest("package test; public class Test <T extends String> { public <P extends T> void test(P p) {} }", "<P:TT;>(TP;)V;"); |
| } |
| |
| protected void doMethodSignatureTest(String code, final String signature) throws IOException { |
| FileObject testFile = FileUtil.createData(new File(getWorkDir(), "Test.java")); |
| |
| copyToFile(testFile, code); |
| |
| final boolean[] invoked = new boolean[1]; |
| |
| JavaSource.forFileObject(testFile).runUserActionTask(new Task<CompilationController>() { |
| @Override public void run(CompilationController parameter) throws Exception { |
| parameter.toPhase(JavaSource.Phase.RESOLVED); |
| |
| ExecutableElement method = ElementFilter.methodsIn(parameter.getTopLevelElements().get(0).getEnclosedElements()).iterator().next(); |
| |
| assertEquals(signature, IndexerImpl.methodTypeSignature(parameter.getElements(), method)); |
| invoked[0] = true; |
| } |
| }, true); |
| |
| assertTrue(invoked[0]); |
| } |
| |
| public void testOverriddenMethods() throws IOException { |
| doOverriddenMethodsTest("package test; public class Test { public String toStr|ing() { return null; } }", |
| "METHOD:java.lang.Object:toString:()Ljava/lang/String;"); |
| doOverriddenMethodsTest("package test; public class Test extends A implements B { public void t|t() { } } class A implements B { public void tt() {} } interface B { public void tt(); }", |
| "METHOD:test.A:tt:()V", |
| "METHOD:test.B:tt:()V"); |
| } |
| |
| protected void doOverriddenMethodsTest(String code, final String... signature) throws IOException { |
| final int pos = code.indexOf('|'); |
| |
| code = code.replace("|", ""); |
| FileObject testFile = FileUtil.createData(new File(getWorkDir(), "Test.java")); |
| |
| copyToFile(testFile, code); |
| |
| final boolean[] invoked = new boolean[1]; |
| |
| JavaSource.forFileObject(testFile).runUserActionTask(new Task<CompilationController>() { |
| @Override public void run(CompilationController parameter) throws Exception { |
| parameter.toPhase(JavaSource.Phase.RESOLVED); |
| |
| TreePath selected = parameter.getTreeUtilities().pathFor(pos); |
| ExecutableElement method = (ExecutableElement) parameter.getTrees().getElement(selected); |
| List<String> result = new ArrayList<String>(); |
| |
| for (ExecutableElement ee : IndexerImpl.overrides(parameter.getTypes(), parameter.getElements(), method)) { |
| result.add(Common.serialize(ElementHandle.create(ee))); |
| } |
| |
| assertEquals(Arrays.asList(signature), result); |
| invoked[0] = true; |
| } |
| }, true); |
| |
| assertTrue(invoked[0]); |
| } |
| |
| public void testRepeatedIndexing() throws IOException { |
| final FileObject root = FileUtil.toFileObject(getWorkDir()); |
| FileObject testFile = FileUtil.createData(root, "Test.java"); |
| copyToFile(testFile, "public class Test {}"); |
| |
| Directory store = new RAMDirectory(); |
| IndexWriter iw = new IndexWriter(store, new KeywordAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); |
| IndexAccessor.current = new IndexAccessor(iw, root); |
| |
| iw.addDocument(fakeDocument(testFile)); |
| |
| doIndex(root, testFile); |
| |
| iw.close(); |
| IndexReader ir = IndexReader.open(store); |
| |
| int expectedDocumentsCount = ir.numDocs(); |
| |
| assertEquals(3 + 1, expectedDocumentsCount); |
| |
| store = new RAMDirectory(); |
| iw = new IndexWriter(store, new KeywordAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); |
| IndexAccessor.current = new IndexAccessor(iw, root); |
| |
| iw.addDocument(fakeDocument(testFile)); |
| |
| doIndex(root, testFile); |
| doIndex(root, testFile); |
| |
| iw.close(); |
| ir = IndexReader.open(store); |
| |
| assertEquals(expectedDocumentsCount, ir.numDocs()); |
| } |
| |
| public void testSubdirIndexing() throws IOException { |
| final FileObject root = FileUtil.toFileObject(getWorkDir()); |
| FileObject aFile = FileUtil.createData(root, "a/A.java"); |
| copyToFile(aFile, "public class A {}"); |
| FileObject bFile = FileUtil.createData(root, "b/B.java"); |
| copyToFile(bFile, "public class B {}"); |
| |
| Directory store = new RAMDirectory(); |
| IndexWriter iw = new IndexWriter(store, new KeywordAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); |
| IndexAccessor.current = new IndexAccessor(iw, root.getFileObject("a")); |
| |
| doIndex(root, aFile, bFile); |
| |
| iw.close(); |
| |
| IndexReader ir = IndexReader.open(store); |
| int maxDocs = ir.maxDoc(); |
| boolean foundA = false; |
| |
| for (int i = 0; i < maxDocs; i++) { |
| Fieldable f = ir.document(i).getFieldable("file"); |
| |
| if (f != null) { |
| assertFalse(f.stringValue(), f.stringValue().contains("B")); |
| if (f.stringValue().contains("A.java")) { |
| foundA = true; |
| } |
| } |
| } |
| |
| assertTrue(foundA); |
| } |
| |
| public void testTreePositions() throws IOException { |
| doPositionTests("package test; public class Test { private Test() { ^Sy|stem.err.println(1); } }"); |
| doPositionTests("package test; public class Test { private Test() { System.^e|rr.println(1); } }"); |
| doPositionTests("package test; public class Test { private Test() { System.err.^p|rintln(1); } }"); |
| } |
| |
| private void doPositionTests(String code) throws IOException { |
| final int caret = code.replace("^", "").indexOf('|'); |
| |
| assertTrue("" + caret, caret != (-1)); |
| |
| code = code.replace("|", ""); |
| |
| final int expected = code.indexOf('^'); |
| |
| assertTrue("" + expected, expected != (-1)); |
| |
| FileObject testFile = FileUtil.createData(new File(getWorkDir(), "Test.java")); |
| |
| copyToFile(testFile, code.replace("^", "")); |
| |
| final boolean[] invoked = new boolean[1]; |
| |
| JavaSource.forFileObject(testFile).runUserActionTask(new Task<CompilationController>() { |
| @Override public void run(CompilationController parameter) throws Exception { |
| parameter.toPhase(JavaSource.Phase.RESOLVED); |
| |
| TreePath tp = parameter.getTreeUtilities().pathFor(caret); |
| |
| assertEquals(expected, IndexerImpl.treePosition(parameter.getTrees(), tp)); |
| |
| invoked[0] = true; |
| } |
| }, true); |
| |
| assertTrue(invoked[0]); |
| } |
| |
| private void copyToFile(FileObject testFile, String code) throws IOException { |
| OutputStream out = testFile.getOutputStream(); |
| |
| try { |
| out.write(code.getBytes()); |
| } finally { |
| out.close(); |
| } |
| } |
| |
| private Document fakeDocument(FileObject testFile) { |
| //to test that unrelated document are not deleted: |
| Document doc = new Document(); |
| |
| doc.add(new Field("file", IndexAccessor.getCurrent().getPath(testFile.toURL()), Store.YES, Index.NOT_ANALYZED)); |
| |
| return doc; |
| } |
| |
| private void doIndex(final FileObject root, FileObject... testFiles) throws IOException, IllegalArgumentException { |
| final boolean[] invoked = new boolean[1]; |
| |
| for (FileObject testFile : testFiles) { |
| JavaSource.forFileObject(testFile).runUserActionTask(new Task<CompilationController>() { |
| @Override public void run(CompilationController parameter) throws Exception { |
| parameter.toPhase(JavaSource.Phase.RESOLVED); |
| |
| new IndexerImpl(root.toURL()).process(parameter.getCompilationUnit(), SPIAccessor.getInstance().create(new FileObjectIndexable(root, parameter.getFileObject())), Lookups.fixed(parameter.getTrees(), parameter.getElements(), parameter.getTypes())); |
| invoked[0] = true; |
| } |
| }, true); |
| } |
| |
| assertTrue(invoked[0]); |
| } |
| |
| @ServiceProvider(service=MimeDataProvider.class) |
| public static final class JavacParserProvider implements MimeDataProvider { |
| |
| private Lookup javaLookup = Lookups.fixed(new JavacParserFactory(), new JavaCustomIndexer.Factory()); |
| |
| public Lookup getLookup(MimePath mimePath) { |
| if (mimePath.getPath().endsWith(JavacParser.MIME_TYPE)) { |
| return javaLookup; |
| } |
| |
| return Lookup.EMPTY; |
| } |
| |
| } |
| |
| @ServiceProvider(service=MIMEResolver.class) |
| public static final class JavaMimeResolver extends MIMEResolver { |
| |
| public JavaMimeResolver() { |
| super(JavacParser.MIME_TYPE); |
| } |
| |
| @Override |
| public String findMIMEType(FileObject fo) { |
| if ("java".equals(fo.getExt())) { |
| return JavacParser.MIME_TYPE; |
| } |
| |
| return null; |
| } |
| |
| } |
| } |