/*******************************************************************************
* Copyright (c) 2004, 2008 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
* Markus Schorn (Wind River Systems)
*******************************************************************************/
/*
* Created on Oct 4, 2004
*/
package ch.hsr.ifs.cdttesting.cdttest;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.IPathEntry;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.FileManager;
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import ch.hsr.ifs.cdttesting.helpers.ExternalResourceHelper;
import ch.hsr.ifs.cdttesting.helpers.UIThreadSyncRunnable;
import junit.framework.TestCase;
abstract public class CDTProjectTest extends TestCase {
protected static final String EXPECTED_PREFIX = "expected_";
protected IWorkspace workspace;
protected IProject project;
protected ICProject cproject;
protected IProject expectedProject;
protected ICProject expectedCproject;
protected FileManager fileManager;
protected boolean indexDisabled = false;
/**
* If set to false, a C project will be created instead of a (default) C++
* project
*/
protected boolean instantiateCCProject = true;
/**
* If set to true, a project supporting the expected files will be
* instantiated.
*/
protected boolean instantiateExpectedProject = false;
protected ArrayList<ICProject> referencedProjects;
private List<String> externalIncudeDirPaths;
private List<String> inProjectIncudeDirPaths;
public CDTProjectTest() {
init();
}
public CDTProjectTest(final String name) {
super(name);
init();
}
private void init() {
referencedProjects = new ArrayList<>();
externalIncudeDirPaths = new ArrayList<>();
inProjectIncudeDirPaths = new ArrayList<>();
}
@Override
protected void setUp() throws Exception {
super.setUp();
initProject();
setupFiles();
initReferencedProjects();
setupProjectReferences();
addIncludePathDirs();
preSetupIndex();
setUpIndex();
}
protected abstract void setupFiles() throws Exception;
@Override
protected void tearDown() throws Exception {
closeOpenEditors();
TestScannerProvider.clear();
deleteReferencedProjects();
fileManager.closeAllFiles();
disposeProjMembers();
disposeCDTAstCache();
}
private void initProject() {
if (project != null && expectedProject != null) {
return;
}
if (CCorePlugin.getDefault() != null && CCorePlugin.getDefault().getCoreModel() != null) {
final String projectName = makeProjectName();
workspace = ResourcesPlugin.getWorkspace();
try {
if (instantiateCCProject) {
cproject = CProjectHelper.createCCProject(projectName, "bin", IPDOMManager.ID_NO_INDEXER); //$NON-NLS-1$ //$NON-NLS-2$
if (instantiateExpectedProject) {
expectedCproject = CProjectHelper.createCCProject(EXPECTED_PREFIX.concat(projectName), "bin", //$NON-NLS-1$ //$NON-NLS-2$
IPDOMManager.ID_NO_INDEXER);
}
} else {
cproject = CProjectHelper.createCProject(projectName, "bin", IPDOMManager.ID_NO_INDEXER); //$NON-NLS-1$ //$NON-NLS-2$
if (instantiateExpectedProject) {
expectedCproject = CProjectHelper.createCProject(EXPECTED_PREFIX.concat(projectName), "bin", //$NON-NLS-1$ //$NON-NLS-2$
IPDOMManager.ID_NO_INDEXER);
}
}
project = cproject.getProject();
if (instantiateExpectedProject) {
expectedProject = expectedCproject.getProject();
}
} catch (final CoreException ignored) {
}
if (project == null || (instantiateExpectedProject && expectedProject == null)) {
fail("Unable to create project"); //$NON-NLS-1$
}
fileManager = new FileManager();
}
}
private String makeProjectName() {
return getName().replaceAll("[^\\w]", "_") + "_project";
}
public void cleanupProject() throws Exception {
try {
project.delete(true, true, new NullProgressMonitor());
expectedProject.delete(true, true, new NullProgressMonitor());
} catch (final Throwable ignored) {
} finally {
project = null;
expectedProject = null;
}
}
private void disposeProjMembers() throws CoreException {
disposeProjMembers(project);
disposeProjMembers(expectedProject);
}
private void disposeProjMembers(final IProject proj) throws CoreException {
if (proj == null || !proj.exists()) {
return;
}
final IResource[] members = proj.members();
for (final IResource member : members) {
if (member.getName().equals(".project") || member.getName().equals(".cproject")) {
continue;
}
if (member.getName().equals(".settings")) {
continue;
}
try {
member.delete(false, new NullProgressMonitor());
} catch (final Throwable ignored) {
}
}
}
protected void preSetupIndex() {
// do nothing, extending classes can override
}
private void setupProjectReferences() throws CoreException {
if (referencedProjects.size() > 0) {
final ICProjectDescription des = CCorePlugin.getDefault().getProjectDescription(project, true);
final ICConfigurationDescription cfgs[] = des.getConfigurations();
for (final ICConfigurationDescription config : cfgs) {
final Map<String, String> refMap = config.getReferenceInfo();
for (final ICProject refProject : referencedProjects) {
refMap.put(refProject.getProject().getName(), "");
}
config.setReferenceInfo(refMap);
}
CCorePlugin.getDefault().setProjectDescription(project, des);
}
}
private void setUpIndex() throws CoreException {
disposeCDTAstCache();
project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
// reindexing will happen automatically after call of setIndexerId
CCorePlugin.getIndexManager().setIndexerId(cproject, IPDOMManager.ID_FAST_INDEXER);
for (final ICProject curProj : referencedProjects) {
CCorePlugin.getIndexManager().setIndexerId(curProj, IPDOMManager.ID_FAST_INDEXER);
}
ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
boolean joined = CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, new NullProgressMonitor());
if (!joined) {
System.err.println("Join on indexer failed. " + getName() + "might fail.");
joined = CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, new NullProgressMonitor());
if (!joined) {
System.err.println("Second join on indexer failed.");
}
}
try {
BaseTestCase.waitForIndexer(cproject);
} catch (final InterruptedException e) {
System.err.println("Wait for indexer has been interrupted.");
}
}
protected abstract void initReferencedProjects() throws Exception;
protected void addIncludeDirPath(final String path) {
externalIncudeDirPaths.add(path);
}
protected void addInProjectIncludeDirPath(final String projectRelativePath) {
inProjectIncudeDirPaths.add(projectRelativePath);
}
private void addIncludePathDirs() {
final int externalProjectOffset = externalIncudeDirPaths.size() + inProjectIncudeDirPaths.size();
final String[] array = new String[externalProjectOffset + referencedProjects.size()];
int i = 0;
for (; i < externalIncudeDirPaths.size(); i++) {
final String externalAbsolutePath = makeExternalResourceAbsolutePath(externalIncudeDirPaths.get(i));
final File folder = new File(externalAbsolutePath);
if (!folder.exists()) {
System.err.println("Adding external include path dir " + externalAbsolutePath + " to test " + getName()
+ " which does not exist.");
}
array[i] = externalAbsolutePath;
}
for (; i < externalProjectOffset; i++) {
final String inProjectAbsolutePath = makeProjectAbsolutePath(
inProjectIncudeDirPaths.get(i - externalIncudeDirPaths.size()));
final File folder = new File(inProjectAbsolutePath);
if (!folder.exists()) {
System.err.println("Adding external include path dir " + inProjectAbsolutePath + " to test " + getName()
+ " which does not exist.");
}
array[i] = inProjectAbsolutePath;
}
for (; i < array.length; i++) {
final ICProject referencedProj = referencedProjects.get(i - externalProjectOffset);
array[i] = referencedProj.getProject().getLocation().toOSString();
}
externalIncudeDirPaths.clear();
inProjectIncudeDirPaths.clear();
addIncludeRefs(array, externalProjectOffset);
TestScannerProvider.sIncludes = array;
}
private void addIncludeRefs(final String[] pathsToAdd, final int externalProjectOffset) {
try {
final IPathEntry[] allPathEntries = cproject.getRawPathEntries();
final IPathEntry[] newPathEntries = new IPathEntry[allPathEntries.length + pathsToAdd.length];
System.arraycopy(allPathEntries, 0, newPathEntries, 0, allPathEntries.length);
int i = 0;
for (; i < externalProjectOffset; i++) {
newPathEntries[allPathEntries.length + i] = CoreModel.newIncludeEntry(null, null,
new Path(pathsToAdd[i]));
}
for (; i < pathsToAdd.length; i++) {
final ICProject referencedProj = referencedProjects.get(i - externalProjectOffset);
newPathEntries[allPathEntries.length + i] = CoreModel.newIncludeEntry(null,
referencedProj.getPath().makeRelative(), null);
}
cproject.setRawPathEntries(newPathEntries, new NullProgressMonitor());
} catch (final CModelException e) {
e.printStackTrace();
}
}
protected IFile importFile(final String fileName, final String contents) throws Exception {
return importFile(fileName, contents, project);
}
protected IFile importFile(final String fileName, final String contents, final IProject project) throws Exception {
final IFile file = project.getFile(fileName);
final IPath projectRelativePath = file.getProjectRelativePath();
for (int i = projectRelativePath.segmentCount() - 1; i > 0; i--) {
final IPath folderPath = file.getProjectRelativePath().removeLastSegments(i);
final IFolder folder = project.getFolder(folderPath);
if (!folder.exists()) {
folder.create(false, true, new NullProgressMonitor());
}
}
final InputStream stream = new ByteArrayInputStream(contents.getBytes());
if (file.exists()) {
System.err.println("Overwriting existing file which should not yet exist: " + fileName);
file.setContents(stream, true, false, new NullProgressMonitor());
} else {
file.create(stream, true, new NullProgressMonitor());
}
fileManager.addFile(file);
checkFileContent(file.getLocation(), contents);
return file;
}
private void checkFileContent(final IPath location, final String expected) throws IOException {
Reader in = null;
try {
in = new FileReader(location.toOSString());
final StringBuilder existing = new StringBuilder();
final char[] buffer = new char[4096];
int read = 0;
do {
existing.append(buffer, 0, read);
read = in.read(buffer);
} while (read >= 0);
if (!expected.equals(existing.toString())) {
System.err.println("file " + location + " not yet written.");
}
} finally {
if (in != null) {
in.close();
}
}
}
@SuppressWarnings("restriction")
private void disposeCDTAstCache() {
CUIPlugin.getDefault().getASTProvider().dispose();
}
protected String makeExternalResourceAbsolutePath(final String relativePath) {
return ExternalResourceHelper.makeExternalResourceAbsolutePath(relativePath);
}
protected String makeProjectAbsolutePath(final String relativePath) {
return makeProjectAbsolutePath(relativePath, project);
}
protected String makeProjectAbsolutePath(final String relativePath, final IProject proj) {
final IPath projectPath = proj.getLocation();
return projectPath.append(relativePath).toOSString();
}
protected String makeWorkspaceAbsolutePath(final String relativePath) {
return ResourcesPlugin.getWorkspace().getRoot().getLocation().append(relativePath).toOSString();
}
protected String makeOSPath(final String path) {
return new Path(path).toOSString();
}
private void deleteReferencedProjects() {
for (final ICProject curProj : referencedProjects) {
try {
curProj.getProject().delete(true, false, new NullProgressMonitor());
} catch (final CoreException ignore) {
}
}
referencedProjects.clear();
}
protected IWorkbenchWindow getActiveWorkbenchWindow() {
IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow == null) {
final IWorkbenchWindow[] workbenchWindows = PlatformUI.getWorkbench().getWorkbenchWindows();
assertEquals("There should be exactly one workbench window. Includator test will thus fail.", 1,
workbenchWindows.length);
activeWorkbenchWindow = workbenchWindows[0];
}
return activeWorkbenchWindow;
}
protected void closeOpenEditors() throws Exception {
new UIThreadSyncRunnable() {
@Override
protected void runSave() throws Exception {
getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
}
}.runSyncOnUIThread();
}
}