blob: c798224abb7071523c235c28e2892cf7590a178d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2021 Gayan Perera and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Gayan Perera - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.index.EntryResult;
import org.eclipse.jdt.internal.core.index.Index;
import org.eclipse.jdt.internal.core.index.MetaIndex;
import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor;
import junit.framework.Test;
public class IndexManagerTests extends ModifyingResourceTests {
private static final boolean SKIP_TESTS = Boolean.parseBoolean(System.getProperty("org.eclipse.jdt.disableMetaIndex", "false"));
private IJavaProject project;
private IndexManager indexManager;
public static Test suite() {
return buildModelTestSuite(IndexManagerTests.class, BYTECODE_DECLARATION_ORDER);
}
public IndexManagerTests(String name) {
super(name);
}
@Override
public void setUpSuite() throws Exception {
super.setUpSuite();
this.indexManager = JavaModelManager.getIndexManager();
}
@Override
public void tearDownSuite() throws Exception {
this.indexManager = null;
super.tearDownSuite();
}
@Override
protected void setUp() throws Exception {
this.indexDisabledForTest = false;
super.setUp();
this.project = createJavaProject("IndexProject", new String[] { "src" }, new String[0], "bin", "1.8");
addClasspathEntry(this.project, getJRTLibraryEntry());
}
@Override
protected void tearDown() throws Exception {
deleteProject(this.project);
super.tearDown();
}
public void testAddingNewSourceFile_ShouldUpdate_MetaIndex() throws CoreException {
if(SKIP_TESTS) return;
Optional<Set<String>> indexNames = searchInMetaIndex("java.util.ArrayList");
assertTrue("No meta index", indexNames.isPresent());
int size = indexNames.get().size();
createFile("/IndexProject/src/Q1.java", "public class Q1<E> extends java.util.ArrayList<E> {\n" + "}");
indexNames = searchInMetaIndex("java.util.ArrayList");
assertTrue("No meta index", indexNames.isPresent());
assertEquals("Expected number of indexes are not found for ArrayList", size + 1, indexNames.get().size());
}
public void testAddingRemoveSourceFile_ShouldUpdate_MetaIndex() throws CoreException {
if(SKIP_TESTS) return;
createFile("/IndexProject/src/Q1.java", "public class Q1<E> extends java.util.ArrayList<E> {\n" + "}");
Optional<Set<String>> indexNames = searchInMetaIndex("java.util.ArrayList");
assertTrue("No meta index", indexNames.isPresent());
int size = indexNames.get().size();
deleteFile("/IndexProject/src/Q1.java");
indexNames = searchInMetaIndex("java.util.ArrayList");
assertTrue("No meta index", indexNames.isPresent());
assertEquals("Expected number of indexes are not found for ArrayList", size - 1, indexNames.get().size());
}
public void testUpdateSourceFile_ShouldUpdate_MetaIndex() throws CoreException {
if(SKIP_TESTS) return;
Optional<Set<String>> indexNames = searchInMetaIndex("java.util.ArrayList");
assertTrue("No meta index", indexNames.isPresent());
int size = indexNames.get().size();
createFile("/IndexProject/src/Q1.java", "public class Q1<E> {\n" + "}");
waitUntilIndexesReady();
changeFile("/IndexProject/src/Q1.java", "public class Q1<E> extends java.util.ArrayList<E> {\n" + "}");
indexNames = searchInMetaIndex("java.util.ArrayList");
assertTrue("No meta index", indexNames.isPresent());
assertEquals("Expected number of indexes are not found for ArrayList", size + 1, indexNames.get().size());
}
public void testAddJarFile_ShouldUpdate_MetaIndex() throws CoreException {
if(SKIP_TESTS) return;
Optional<Set<String>> indexNames = searchInMetaIndex("binary.Deep");
assertTrue("No meta index", indexNames.isPresent());
addLibraryEntry(this.project,
Paths.get(getSourceWorkspacePath(), "TypeHierarchy", "lib.jar").toFile().getAbsolutePath(), false);
indexNames = searchInMetaIndex("binary.Deep");
assertTrue("No meta index", indexNames.isPresent());
assertEquals("Expected number of indexes are not found for binary.Deep", 1, indexNames.get().size());
}
public void testRemoveJarFile_ShouldUpdate_MetaIndex() throws CoreException {
if(SKIP_TESTS) return;
String jarPath = Paths.get(getSourceWorkspacePath(), "TypeHierarchy", "lib.jar").toFile().getAbsolutePath();
addLibraryEntry(this.project, jarPath, false);
Optional<Set<String>> indexNames = searchInMetaIndex("binary.Deep");
assertTrue("No meta index", indexNames.isPresent());
int size = indexNames.get().size();
removeClasspathEntry(this.project, new Path(jarPath));
indexNames = searchInMetaIndex("binary.Deep");
assertTrue("No meta index", indexNames.isPresent());
assertEquals("Expected number of indexes are not found for binary.Deep", size - 1, indexNames.get().size());
}
private void changeFile(String path, String content) {
IFile file = getFile(path);
if (!file.exists()) {
throw new AssertionError("File expected at path " + path);
}
try (ByteArrayInputStream stream = new ByteArrayInputStream(content.getBytes())) {
file.setContents(stream, IResource.FORCE, new NullProgressMonitor());
} catch (IOException | CoreException e) {
e.printStackTrace();
throw new AssertionError("Failed to update file " + e.getMessage());
}
}
private Optional<Set<String>> searchInMetaIndex(String indexQualifier) {
waitUntilIndexesReady();
Optional<MetaIndex> index = null;
try {
index = this.indexManager.getMetaIndex();
if (!index.isPresent()) {
return Optional.empty();
}
ReadWriteMonitor monitor = index.get().getMonitor();
if (monitor == null) {
return Optional.empty();
}
try {
monitor.enterRead();
index.get().startQuery();
List<EntryResult> results = new ArrayList<>(2);
results.addAll(safeList(index.get()
.query(new char[][] { IIndexConstants.META_INDEX_QUALIFIED_TYPE_QUALIFIER_REF,
IIndexConstants.META_INDEX_QUALIFIED_SUPER_TYPE_QUALIFIER_REF }, indexQualifier.toCharArray(),
SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE)));
results.addAll(safeList(index.get()
.query(new char[][] { IIndexConstants.META_INDEX_SIMPLE_SUPER_TYPE_QUALIFIER_REF,
IIndexConstants.META_INDEX_SIMPLE_TYPE_QUALIFIER_REF },
CharOperation.lastSegment(indexQualifier.toCharArray(), '.'),
SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE)));
final Index i = index.map(MetaIndex::getIndex).get();
return Optional.of(results.stream().flatMap(r -> {
try {
return Stream.of(r.getDocumentNames(i));
} catch (IOException e) {
return Stream.empty();
}
}).collect(Collectors.toSet()));
} finally {
index.get().stopQuery();
monitor.exitRead();
}
} catch (IOException e) {
e.printStackTrace();
throw new AssertionError(e.getMessage());
}
}
private List<EntryResult> safeList(EntryResult[] result) {
return result == null ? Collections.emptyList() : Arrays.asList(result);
}
}