/******************************************************************************* * Copyright (c) 2007 Symbian Software Systems 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: * Andrew Ferguson (Symbian) - Initial implementation *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import junit.framework.Test; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.testplugin.CProjectHelper; import org.eclipse.cdt.core.testplugin.CTestPlugin; import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; /** * Tests the behavior of the IIndex API when dealing with multiple projects */ public class IndexCompositeTests extends BaseTestCase { public static Test suite() { return suite(IndexCompositeTests.class); } private static final int NONE = 0, REFS = IIndexManager.ADD_DEPENDENCIES; private static final int REFD = IIndexManager.ADD_DEPENDENT, BOTH = REFS | REFD; private static final IndexFilter FILTER= new IndexFilter() { @Override public boolean acceptBinding(IBinding binding) throws CoreException { if (binding instanceof ICPPMethod) { return !((ICPPMethod) binding).isImplicit(); } return true; } }; IIndex index; protected StringBuilder[] getContentsForTest(int blocks) throws IOException { return TestSourceReader.getContentsForTest( CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), blocks); } // class A {}; // class B {}; public void testPairDisjointContent() throws Exception { CharSequence[] contents = getContentsForTest(2); List projects = new ArrayList(); try { ProjectBuilder pb = new ProjectBuilder("projB"+System.currentTimeMillis(), true); pb.addFile("h1.h", contents[0]); ICProject cprojB = pb.create(); projects.add(cprojB); pb = new ProjectBuilder("projA"+System.currentTimeMillis(), true); pb.addFile("h2.h", contents[1]).addDependency(cprojB.getProject()); ICProject cprojA = pb.create(); projects.add(cprojA); setIndex(cprojB, NONE); assertBCount(1, 1); setIndex(cprojB, REFS); assertBCount(1, 1); setIndex(cprojB, REFD); assertBCount(2, 2); setIndex(cprojB, BOTH); assertBCount(2, 2); setIndex(cprojA, NONE); assertBCount(1, 1); setIndex(cprojA, REFS); assertBCount(2, 2); setIndex(cprojA, REFD); assertBCount(1, 1); setIndex(cprojA, BOTH); assertBCount(2, 2); } finally { for (Iterator i = projects.iterator(); i.hasNext();) ((ICProject)i.next()).getProject().delete(true, true, new NullProgressMonitor()); } } // class C1 {public: int i;}; // namespace X { class C2 {}; } // enum E {E1,E2}; // void foo(C1 c) {} // class B1 {}; // namespace X { class B2 {}; } // C1 c1; // X::C2 c2; // void foo(B1 c) {} // void foo(X::C2 c) {} // class A1 {}; // void foo(X::B2 c) {} // namespace X { class A2 {}; B2 b; C2 c; } public void testTripleLinear() throws Exception { CharSequence[] contents = getContentsForTest(3); List projects = new ArrayList(); try { ProjectBuilder pb = new ProjectBuilder("projC"+System.currentTimeMillis(), true); pb.addFile("h3.h", contents[0]); ICProject cprojC = pb.create(); projects.add(cprojC); pb = new ProjectBuilder("projB"+System.currentTimeMillis(), true); pb.addFile("h2.h", contents[1]).addDependency(cprojC.getProject()); ICProject cprojB = pb.create(); projects.add(cprojB); pb = new ProjectBuilder("projA"+System.currentTimeMillis(), true); pb.addFile("h1.h", contents[2]).addDependency(cprojB.getProject()); ICProject cprojA = pb.create(); projects.add(cprojA); /* Defines Global, Defines Namespace, References Global, References Namespace * projC: 6, 2, 0, 0 * projB: 6, 1, 1, 1 * projA: 3, 3, 0, 2 */ setIndex(cprojC, NONE); assertBCount(6, 6 +2); assertNamespaceXMemberCount(1); assertFieldCount("C1", 1); setIndex(cprojC, REFS); assertBCount(6, 6 +2); assertNamespaceXMemberCount(1); assertFieldCount("C1", 1); setIndex(cprojC, REFD); assertBCount((6+(6-1)+(3-1)), (6+2)+(6+1-1)+(3+3-1)); assertNamespaceXMemberCount(5); assertFieldCount("C1", 1); setIndex(cprojC, BOTH); assertBCount((6+(6-1)+(3-1)), (6+2)+(6+1-1)+(3+3-1)); assertNamespaceXMemberCount(5); assertFieldCount("C1", 1); setIndex(cprojB, NONE); assertBCount(6+1, 6+1+1+1); assertNamespaceXMemberCount(2); assertFieldCount("C1", 1); setIndex(cprojB, REFS); assertBCount(6+1+6-1-1, (6+1+1+1)-1-1 + (6+2) -1); assertNamespaceXMemberCount(2); assertFieldCount("C1", 1); setIndex(cprojB, REFD); assertBCount(6+1+3-1, (6+1+1+1) + (3+3) -1); assertNamespaceXMemberCount(5); assertFieldCount("C1", 1); setIndex(cprojB, BOTH); assertBCount((6+1)-1+3+6 -2, (6+1+1+1)-1-1 + (3+3+2)-2 + (6+2) -2); assertNamespaceXMemberCount(5); assertFieldCount("C1", 1); setIndex(cprojA, NONE); assertBCount(3, 8); assertNamespaceXMemberCount(5); // binding C1 is not referenced by cprojA setIndex(cprojA, REFS); assertBCount(6+6+3-1-1, (6+1+1+1)-1-1 + (3+3+2)-2 + (6+2) -2); assertNamespaceXMemberCount(5); assertFieldCount("C1", 1); setIndex(cprojA, REFD); assertBCount(3, 8); assertNamespaceXMemberCount(5); // binding C1 is not referenced by cprojA setIndex(cprojA, BOTH); assertBCount(6+6+3-1-1, (6+1+1+1)-1-1 + (3+3+2)-2 + (6+2) -2); assertNamespaceXMemberCount(5); assertFieldCount("C1", 1); } finally { for (Iterator i = projects.iterator(); i.hasNext();) ((ICProject)i.next()).getProject().delete(true, true, new NullProgressMonitor()); } } // class C1 {}; // namespace X { class C2 {}; B1 b; } // enum E {E1,E2}; // X::B2 cb; // void foo(C1 c) {} // class B1 {}; // namespace X { class B2 {}; } // void foo(B1 c) {} // void foo(X::B2 c, B1 c) {} // class A1 {}; // void foo(X::B2 c) {} // namespace X { class A2 {}; } // B1 ab; public void testTripleUpwardV() throws Exception { CharSequence[] contents = getContentsForTest(3); List projects = new ArrayList(); try { ProjectBuilder pb = new ProjectBuilder("projB"+System.currentTimeMillis(), true); pb.addFile("h2.h", contents[1]); ICProject cprojB = pb.create(); projects.add(cprojB); pb = new ProjectBuilder("projC"+System.currentTimeMillis(), true); pb.addFile("h3.h", contents[0]).addDependency(cprojB.getProject()); ICProject cprojC = pb.create(); projects.add(cprojC); pb = new ProjectBuilder("projB"+System.currentTimeMillis(), true); pb.addFile("h1.h", contents[2]).addDependency(cprojB.getProject()); ICProject cprojA = pb.create(); projects.add(cprojA); /* A C | * \ / | Depends On / References * B V * * Defines Global, Defines Namespace, Ext. References Global, Ext. References Namespace * projC: 7, 2, 1, 1 * projB: 4, 1, 0, 0 * projA: 4, 1, 1, 1 */ setIndex(cprojC, NONE); assertBCount(7+1, 7+2+1+1); assertNamespaceXMemberCount(3); setIndex(cprojC, REFS); assertBCount(7+1+4-1-1, 7+1+1+2+4+1-1-2); assertNamespaceXMemberCount(3); setIndex(cprojC, REFD); assertBCount(7+1, 7+1+1+2); assertNamespaceXMemberCount(3); setIndex(cprojC, BOTH); assertBCount(7+4+4-2, 7+4+4-2 +2+1+1); assertNamespaceXMemberCount(4); setIndex(cprojB, NONE); assertBCount(4, 4+1); assertNamespaceXMemberCount(1); setIndex(cprojB, REFS); assertBCount(4, 4+1); assertNamespaceXMemberCount(1); setIndex(cprojB, REFD); assertBCount(7+4+4-2, 7+4+4-2 +2+1+1); assertNamespaceXMemberCount(4); setIndex(cprojB, BOTH); assertBCount(7+4+4-2, 7+4+4-2 +2+1+1); assertNamespaceXMemberCount(4); setIndex(cprojA, NONE); assertBCount(4+1, 4+1+1+1); assertNamespaceXMemberCount(2); setIndex(cprojA, REFS); assertBCount(4+1+4-1-1, 4+1+4-1-1 +1+1); assertNamespaceXMemberCount(2); setIndex(cprojA, REFD); assertBCount(4+1, 4+1+1+1); assertNamespaceXMemberCount(2); setIndex(cprojA, BOTH); assertBCount(7+4+4-2, 7+4+4-2 +2+1+1); assertNamespaceXMemberCount(4); } finally { for (Iterator i = projects.iterator(); i.hasNext();) ((ICProject)i.next()).getProject().delete(true, true, new NullProgressMonitor()); } } // class C1 {}; // namespace X { class C2 {}; } // enum E {E1,E2}; // void foo(C1 c) {} // class B1 {}; // namespace X { class B2 {}; C1 c; } // void foo(A1 c) {} // void foo(X::A2 c, B1 c) {} // class A1 {}; // void foo(A1 a, A1 b) {} // namespace X { class A2 {}; } public void testTripleDownwardV() throws Exception { CharSequence[] contents = getContentsForTest(3); List projects = new ArrayList(); try { ProjectBuilder pb = new ProjectBuilder("projC"+System.currentTimeMillis(), true); pb.addFile("h3.h", contents[0]); ICProject cprojC = pb.create(); projects.add(cprojC); pb = new ProjectBuilder("projA"+System.currentTimeMillis(), true); pb.addFile("h1.h", contents[2]); ICProject cprojA = pb.create(); projects.add(cprojA); pb = new ProjectBuilder("projB"+System.currentTimeMillis(), true); pb.addFile("h2.h", contents[1]).addDependency(cprojC.getProject()).addDependency(cprojA.getProject()); ICProject cprojB = pb.create(); projects.add(cprojB); /* B | * / \ | Depends On / References * A C V * * Defines Global, Defines Namespace, References Global, References Namespace * projC: 6, 1, 0, 0 * projB: 4, 2, 2, 1 * projA: 3, 1, 0, 0 */ setIndex(cprojC, NONE); assertBCount(6, 6+1); assertNamespaceXMemberCount(1); setIndex(cprojC, REFS); assertBCount(6, 6+1); assertNamespaceXMemberCount(1); setIndex(cprojC, REFD); assertBCount(6+4+1-1, 6+4+1-1 +1+1+1+1); assertNamespaceXMemberCount(4); setIndex(cprojC, BOTH); assertBCount(6+4+3-2, 6+4+3-2 +1+2+1); assertNamespaceXMemberCount(4); setIndex(cprojB, NONE); assertBCount(4+2, 4+2 +2+1); assertNamespaceXMemberCount(4); setIndex(cprojB, REFS); assertBCount(6+4+3-2, 6+4+3-2 +1+2+1); assertNamespaceXMemberCount(4); setIndex(cprojB, REFD); assertBCount(4+2, 4+2 +2+1); assertNamespaceXMemberCount(4); setIndex(cprojB, BOTH); assertBCount(6+4+3-2, 6+4+3-2 +1+2+1); assertNamespaceXMemberCount(4); setIndex(cprojA, NONE); assertBCount(3, 3 +1); assertNamespaceXMemberCount(1); setIndex(cprojA, REFS); assertBCount(3, 3 +1); assertNamespaceXMemberCount(1); setIndex(cprojA, REFD); assertBCount(4+2+3-1-1, 4+2+3-1-1 +2+1); assertNamespaceXMemberCount(4); setIndex(cprojA, BOTH); assertBCount(6+4+3-2, 6+4+3-2 +1+2+1); assertNamespaceXMemberCount(4); } finally { for (Iterator i = projects.iterator(); i.hasNext();) ((ICProject)i.next()).getProject().delete(true, true, new NullProgressMonitor()); } } /** * Asserts binding counts, and returns the index tested against * @param global the number of bindings expected to be found at global scope * @param all the number of bindings expected to be found at all scopes * @return the index * @throws CoreException */ private IIndex assertBCount(int global, int all) throws CoreException { IBinding[] bindings = index.findBindings(Pattern.compile(".*"), true, FILTER, new NullProgressMonitor()); assertEquals(global, bindings.length); bindings = index.findBindings(Pattern.compile(".*"), false, FILTER, new NullProgressMonitor()); assertEquals(all, bindings.length); return index; } private void assertNamespaceXMemberCount(int count) throws CoreException, DOMException { IBinding[] bindings = index.findBindings(Pattern.compile("X"), true, FILTER, new NullProgressMonitor()); assertEquals(1, bindings.length); assertEquals(count, ((ICPPNamespace)bindings[0]).getMemberBindings().length); } private void assertFieldCount(String qnPattern, int count) throws CoreException, DOMException { IBinding[] bindings = index.findBindings(Pattern.compile(qnPattern), true, FILTER, new NullProgressMonitor()); assertEquals(1, bindings.length); assertEquals(count, ((ICompositeType)bindings[0]).getFields().length); } private void setIndex(ICProject project, int options) throws CoreException, InterruptedException { if (index != null) { index.releaseReadLock(); } index = CCorePlugin.getIndexManager().getIndex(project, options); index.acquireReadLock(); } @Override protected void tearDown() throws Exception { if (index != null) { index.releaseReadLock(); } super.tearDown(); } } /* * Convenience class for setting up projects. */ class ProjectBuilder { private String name; private List dependencies = new ArrayList(); private Map path2content = new HashMap(); private boolean cpp; ProjectBuilder(String name, boolean cpp) { this.name = name; this.cpp = cpp; } ProjectBuilder addDependency(IProject project) { dependencies.add(project); return this; } ProjectBuilder addFile(String relativePath, CharSequence content) { path2content.put(relativePath, content.toString()); return this; } ICProject create() throws Exception { ICProject result = cpp ? CProjectHelper.createCCProject(name, "bin", IPDOMManager.ID_NO_INDEXER) : CProjectHelper.createCCProject(name, "bin", IPDOMManager.ID_NO_INDEXER); for (Iterator i = path2content.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); TestSourceReader.createFile(result.getProject(), new Path((String)entry.getKey()), (String) entry.getValue()); } IProjectDescription desc = result.getProject().getDescription(); desc.setReferencedProjects((IProject[]) dependencies.toArray(new IProject[dependencies.size()])); result.getProject().setDescription(desc, new NullProgressMonitor()); CCorePlugin.getIndexManager().setIndexerId(result, IPDOMManager.ID_FAST_INDEXER); BaseTestCase.waitForIndexer(result); return result; } }