/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.sarl.tests.api;
import static com.google.common.collect.Sets.newHashSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.jar.Manifest;
import java.util.logging.Logger;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import org.eclipse.core.filesystem.URIUtil;
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.IWorkspaceDescription;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.ErrorEditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
import org.eclipse.xtext.resource.FileExtensionProvider;
import org.eclipse.xtext.ui.editor.XtextEditor;
import org.eclipse.xtext.ui.editor.XtextEditorInfo;
import org.eclipse.xtext.ui.editor.utils.EditorUtils;
import org.eclipse.xtext.ui.resource.IResourceSetProvider;
import org.eclipse.xtext.ui.util.PluginProjectFactory;
import org.eclipse.xtext.util.JavaVersion;
import org.eclipse.xtext.util.StringInputStream;
import org.eclipse.xtext.xbase.lib.Functions;
import org.osgi.framework.Bundle;
import io.sarl.lang.sarl.SarlScript;
import io.sarl.lang.ui.preferences.SARLPreferences;
/** Provides tools for setting up and managing the Eclipse workspace.
* This class was adapted from the Xtend test suite.
*
* @author $Author: sgalland$
* @author $Author: ngaud$
* @author Jan Koehnlein - Xtend contributor
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@Singleton
@SuppressWarnings("static-method")
public class WorkbenchTestHelper {
/** Logger.
*/
public static final Logger log = Logger.getLogger(WorkbenchTestHelper.class.getName());
/** Name of the project that is generated during unit tests.
*/
public static final String TESTPROJECT_NAME = "test.project"; //$NON-NLS-1$
/**
* ID of this nature.
*/
public static final String NATURE_ID = "io.sarl.eclipse.SARLProjectNature"; //$NON-NLS-1$
/** List of the bundles that are required for created a testing project.
*/
public static final ImmutableList<String> DEFAULT_REQ_BUNDLES = ImmutableList.of(
"com.google.inject", //$NON-NLS-1$
"org.eclipse.xtend.lib", //$NON-NLS-1$
"org.eclipse.xtext.xbase.lib", //$NON-NLS-1$
"javax.inject", //$NON-NLS-1$
"io.sarl.lang", //$NON-NLS-1$
"io.sarl.lang.core", //$NON-NLS-1$
"io.sarl.lang.ui", //$NON-NLS-1$
"io.sarl.tests.testdata", //$NON-NLS-1$
"org.junit"); //$NON-NLS-1$
private Set<IFile> files = newHashSet();
@Inject
private XtextEditorInfo editorInfo;
@Inject
private FileExtensionProvider fileExtensionProvider;
@Inject
private IWorkbench workbench;
@Inject
private IWorkspace workspace;
@Inject
private IResourceSetProvider resourceSetProvider;
@Inject
private ProjectCreator projectCreator;
private boolean isLazyCreatedProject = false;
private String lastProjectName = null;
/** Init the helper for the unit test.
*
* @throws Exception
*/
public void setUp() throws Exception {
//
}
/** Dispose the helper for the unit test.
*
* @throws Exception
*/
public void tearDown() throws Exception {
this.lastProjectName = null;
// Close the editors safely.
if (this.workbench != null) {
try {
final IWorkbenchWindow window = this.workbench.getActiveWorkbenchWindow();
if (window != null) {
window.getActivePage().closeAllEditors(false);
}
} catch (Throwable e) {
//
}
}
new WorkspaceModifyOperation() {
@SuppressWarnings("synthetic-access")
@Override
protected void execute(IProgressMonitor monitor) throws CoreException,
InvocationTargetException, InterruptedException {
for (IFile file : getFiles()) {
try {
file.delete(true, null);
} catch (Exception exc) {
// Be silent because it is outside the scope of the tests
}
}
getFiles().clear();
IFolder binFolder = getProject(false).getFolder("bin"); //$NON-NLS-1$
if (binFolder.exists()) {
for (IResource binMember : binFolder.members()) {
try {
binMember.delete(true, null);
} catch (Exception exc) {
// Be silent because it is outside the scope of the tests
}
}
}
if (WorkbenchTestHelper.this.isLazyCreatedProject) {
deleteProject(getProject(false));
WorkbenchTestHelper.this.isLazyCreatedProject = false;
}
}
}.run(null);
awaitAutoBuild();
}
private static void deleteProjects(IProject[] projects) throws CoreException {
for (IProject iProject : projects) {
if (iProject.exists()) {
iProject.delete(true,true, new NullProgressMonitor());
}
}
}
/** Clear the workspace.
*/
public void clearWorkspace() {
try {
IProject[] visibleProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
deleteProjects(visibleProjects);
IProject[] hiddenProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(org.eclipse.core.resources.IContainer.INCLUDE_HIDDEN);
deleteProjects(hiddenProjects);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/** Replies the ccreated files.
*
* @return the created files.
*/
public Set<IFile> getFiles() {
return this.files;
}
/** Replies the current project.
*
* @return the project.
*/
public IProject getProject() {
return getProject(true);
}
/** Replies the current Java project.
*
* @return the Java project.
*/
public IJavaProject getJavaProject() {
return JavaCore.create(getProject());
}
/** Replies the Java project for the given resource.
*
* @param resource the resource to search for.
* @return the Java project.
*/
public IJavaProject getJavaProject(Resource resource) {
return JavaCore.create(getProject(resource, true));
}
/** Replies the current project.
*
* @param createOnDemand - create the project if it does not exist yet.
* @return the project.
*/
public IProject getProject(boolean createOnDemand) {
return getProject(this.lastProjectName, createOnDemand);
}
/** Replies the project with the given name.
*
* @param projectName the name of the project.
* @param createOnDemand - create the project if it does not exist yet.
* @return the project.
*/
public IProject getProject(String projectName, boolean createOnDemand) {
String prjName = projectName;
if (Strings.isNullOrEmpty(prjName)) {
prjName = TESTPROJECT_NAME;
}
IProject project = this.workspace.getRoot().getProject(prjName);
if (createOnDemand && !project.exists()) {
try {
this.isLazyCreatedProject = true;
project = createPluginProject(prjName, this.projectCreator);
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
return project;
}
/** Replies the project for the given resource.
*
* @param resource the resource to search for.
* @param createOnDemand - create the project if it does not exist yet.
* @return the project.
*/
public IProject getProject(Resource resource, boolean createOnDemand) {
if (resource != null) {
final URI uri = resource.getURI();
final String platformString = uri.toPlatformString(true);
final IPath resourcePath = new Path(platformString);
final IFile file = this.workspace.getRoot().getFile(resourcePath);
if (file != null) {
final IProject project = file.getProject();
if (project != null && project.exists()) {
return project;
}
}
}
return getProject(createOnDemand);
}
/** Open the Xtext editor.
*
* @param fileName the name of the file to open.
* @param content the content of the file.
* @return the editor.
* @throws Exception
*/
public XtextEditor openEditor(String fileName, String content) throws Exception {
int cursor = content.indexOf('|');
IFile file = createFile(fileName, content.replace("|", "")); //$NON-NLS-1$//$NON-NLS-2$
XtextEditor editor = openEditor(file);
editor.getInternalSourceViewer().setSelectedRange(cursor, 0);
editor.getInternalSourceViewer().getTextWidget().setFocus();
return editor;
}
/** Create a file in the source folder.
*
* @param fileName the name of the file to create.
* @param content the content of the file.
* @return the file.
* @throws Exception
* see {@link #getFullFileNameInSources(String)}
*/
public IFile createFile(String fileName, String content) throws Exception {
String fullFileName = getFullFileNameInSources(fileName);
return createFileImpl(fullFileName, content);
}
private static IProject createProject(IProject project) throws CoreException {
if (!project.exists())
project.create(new NullProgressMonitor());
project.open(new NullProgressMonitor());
return project;
}
/** Create the container tree.
*
* @param container the container
* @throws InvocationTargetException in case of error.
* @throws InterruptedException in case of errir.
*/
public static void create(org.eclipse.core.resources.IContainer container)
throws InvocationTargetException, InterruptedException {
new WorkspaceModifyOperation() {
@SuppressWarnings("synthetic-access")
@Override
protected void execute(IProgressMonitor monitor)
throws CoreException, InvocationTargetException,
InterruptedException {
if (!container.exists()) {
create(container.getParent());
if (container instanceof IFolder) {
((IFolder) container).create(true, true, new NullProgressMonitor());
} else {
IProject iProject = (IProject) container;
createProject(iProject);
}
}
}
}.run(new NullProgressMonitor());
}
/** Create a file.
*
* @param fullFileName the name of the file to create.
* @param content the content of the file.
* @return the file.
* @throws Exception
*/
public IFile createFileImpl(String fullFileName, String content) throws Exception {
final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(fullFileName));
new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor)
throws CoreException, InvocationTargetException,
InterruptedException {
create(file.getParent());
file.delete(true, new NullProgressMonitor());
try (final InputStream is = new StringInputStream(content)) {
file.create(is, true, new NullProgressMonitor());
} catch (Exception exception) {
//
}
}
}.run(new NullProgressMonitor());
getFiles().add(file);
return file;
}
/** Create a file.
*
* @param file the name of the file to create.
* @param content the content of the file.
* @return the file.
* @throws Exception
*/
public IFile createFileImpl(IFile file, InputStream content) throws Exception {
new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor)
throws CoreException, InvocationTargetException,
InterruptedException {
create(file.getParent());
file.delete(true, new NullProgressMonitor());
file.create(content, true, new NullProgressMonitor());
}
}.run(new NullProgressMonitor());
getFiles().add(file);
return file;
}
/** Replies the file with the given name.
*
* @param fileName the name without the file extension.
* @return the file.
*/
public IFile getFile(String fileName) {
return this.workspace.getRoot().getFile(new Path(getFullFileNameInSources(fileName)));
}
/** Compute the full filename.
*
* @param fileName the name with the file extension.
* @return the full filename.
* @see #getFullFileNameInProject(String)
*/
public String getFullFileNameInSources(String fileName) {
final String extension = (fileName.indexOf(".") != -1) ? "" : "." + getFileExtension(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
final String fullFileName = getProject().getName() + "/src/" + fileName + extension; //$NON-NLS-1$
return fullFileName;
}
/** Replies the file with the given name.
*
* @param fileName the name.
* @return the file.
*/
public IFile getFileInProject(String fileName) {
return getFileInRoot(getProject().getName(), fileName);
}
/** Replies the file with the given name.
*
* @param projectName the name of the project
* @param fileName the name.
* @return the file.
*/
public IFile getFileInRoot(String projectName, String fileName) {
String fullFileName = projectName + "/" + fileName; //$NON-NLS-1$
return getFile(new Path(fullFileName));
}
/** Replies the file with the given name.
*
* @param path the name of the file.
* @return the file.
*/
public IFile getFile(IPath path) {
return this.workspace.getRoot().getFile(path);
}
/** Replies the folder with the given name.
*
* @param path the name of the folder.
* @return the folder.
*/
public IFolder getFolder(IPath path) {
return this.workspace.getRoot().getFolder(path);
}
/** Compute the full filename inside the proejct root directory.
*
* @param fileName the name without the file extension.
* @return the full filename.
* @see #getFullFileNameInSources(String)
*/
public String getFullFileNameInProject(String fileName) {
String extension = (fileName.indexOf(".") != -1) ? "" : "." + getFileExtension(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
String fullFileName = getProject().getName() + "/" + fileName + extension; //$NON-NLS-1$
return fullFileName;
}
/** Replies the file extension.
*
* @return the file extension.
*/
public String getFileExtension() {
return this.fileExtensionProvider.getFileExtensions().iterator().next();
}
/** Compute the URI of the given file.
*
* @param file the file.
* @return the uri.
*/
public URI uri(IFile file) {
return URI.createPlatformResourceURI(file.getFullPath().toString(), true);
}
/** Create a SARL file.
*
* @param fileName the filename.
* @param content the content.
* @return the SARL script.
* @throws Exception
*/
public SarlScript sarlScript(String fileName, String content) throws Exception {
return sarlScript(fileName, content, true);
}
/** Create a SARL file.
*
* @param fileName the filename.
* @param content the content.
* @param assertNoError indicates if this function asserts no error in the content.
* If <code>true</code> this function may fail. Otherwise, it never fails on syntax errors.
* @return the SARL script.
* @throws Exception
*/
public SarlScript sarlScript(String fileName, String content, boolean assertNoError) throws Exception {
IFile file = createFile(fileName, content);
Resource resource = getResourceSet().createResource(uri(file));
try (InputStream is = new StringInputStream(content)) {
resource.load(is, null);
if (assertNoError) {
assertEquals(resource.getErrors().toString(), 0, resource.getErrors().size());
}
SarlScript xtendFile = (SarlScript) resource.getContents().get(0);
return xtendFile;
}
}
/** Create a SARL file.
*
* @param file the file.
* @return the SARL script.
* @throws Exception
*/
public SarlScript sarlScript(IFile file) throws Exception {
Resource resource = getResourceSet().createResource(uri(file));
resource.load(null);
return (SarlScript) resource.getContents().get(0);
}
/** Create a SARL file.
*
* @param project the project.
* @param fileName the filename in the project.
* @param content the content.
* @return the SARL script.
* @throws Exception
*/
public SarlScript sarlScript(IProject project, String fileName, String content) throws Exception {
IFile file = createFileImpl(project.getName() + "/src/" + fileName, content); //$NON-NLS-1$
Resource resource = this.resourceSetProvider.get(project).createResource(uri(file));
try (InputStream is = new StringInputStream(content)) {
resource.load(is, null);
assertEquals(resource.getErrors().toString(), 0, resource.getErrors().size());
SarlScript xtendFile = (SarlScript) resource.getContents().get(0);
return xtendFile;
}
}
/** Replies the resource associated to the given file in the given project.
*
* @param file the file in the project.
* @return the resource.
*/
public Resource getResourceFor(IFile file) {
return getResourceFor(getProject(), file);
}
/** Replies the resource associated to the given file in the given project.
*
* @param project the project.
* @param file the file in the project.
* @return the resource.
*/
public Resource getResourceFor(IProject project, IFile file) {
URI uri = uri(file);
ResourceSet resourceSet = this.resourceSetProvider.get(project);
Resource resource = resourceSet.getResource(uri, false);
if (resource == null) {
resource = resourceSet.createResource(uri);
}
return resource;
}
/** Create a SARL file with a SARL agent inside.
*
* @param fileName the filename.
* @param type the type of the expected element.
* @param content the content.
* @return the SARL script.
* @throws Exception
*/
public <T extends XtendTypeDeclaration> T sarlTypeDeclaration(
String fileName, Class<T> type,
String content) throws Exception {
SarlScript script = sarlScript(fileName, content);
Object latest = null;
for (XtendTypeDeclaration declaration : script.getXtendTypes()) {
if (type.isInstance(declaration)) {
latest = declaration;
}
}
if (latest != null) {
return type.cast(latest);
}
throw new NoSuchElementException();
}
/** Create a SARL file with a SARL agent inside.
*
* @param type the type of the expected element.
* @param content the content.
* @return the SARL script.
* @throws Exception
*/
public <T extends XtendTypeDeclaration> T sarlTypeDeclaration(
Class<T> type,
String content) throws Exception {
return sarlTypeDeclaration(generateFilename(), type, content);
}
/** Replies the resource set for the testing project.
*
* @return the resource set.
*/
public ResourceSet getResourceSet() {
return this.resourceSetProvider.get(getProject());
}
/** Replies the identifier of the editor.
*
* @return the identifier of the editor.
*/
public String getEditorID() {
return this.editorInfo.getEditorId();
}
/** Replies the content of the given file.
*
* @param file the name of the file.
* @return the content of the file.
* @throws Exception
*/
public String getContents(IFile file) throws Exception {
try (InputStream inputStream = file.getContents()) {
byte[] buffer = new byte[2048];
int bytesRead = 0;
StringBuffer b = new StringBuffer();
do {
bytesRead = inputStream.read(buffer);
if (bytesRead != -1)
b.append(new String(buffer, 0, bytesRead));
} while (bytesRead != -1);
return b.toString();
}
}
/** Close the welcome page.
*
* @throws InterruptedException
*/
public void closeWelcomePage() throws InterruptedException {
if (PlatformUI.getWorkbench().getIntroManager().getIntro() != null) {
PlatformUI.getWorkbench().getIntroManager().closeIntro(
PlatformUI.getWorkbench().getIntroManager().getIntro());
}
}
/** Create a project.
*
* @param name the name of the project.
* @param creator the creator of project.
* @param requiredBundles the bundles to add into the build path.
* @return the project.
* @throws CoreException
*/
public IProject createPluginProject(String name, ProjectCreator creator, String... requiredBundles) throws CoreException {
// If no required bundle is given, use the defaults.
String[] bundleDependencies;
if (requiredBundles == null || requiredBundles.length == 0) {
bundleDependencies = new String[WorkbenchTestHelper.DEFAULT_REQ_BUNDLES.size()];
WorkbenchTestHelper.DEFAULT_REQ_BUNDLES.toArray(bundleDependencies);
} else {
bundleDependencies = requiredBundles;
}
// Disable "Build automatically"
try {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription workspaceDescription = workspace.getDescription();
workspaceDescription.setAutoBuilding(false);
workspace.setDescription(workspaceDescription);
} catch (Throwable exception) {
throw new CoreException(new Status(IStatus.ERROR, "io.sarl.tests.api", //$NON-NLS-1$
exception.getLocalizedMessage(), exception));
}
PluginProjectFactory projectFactory = creator.getProjectFactory();
projectFactory.setProjectName(name);
this.lastProjectName = name;
JavaVersion jVersion = creator.getJavaVersion();
if (jVersion == null) {
jVersion = JavaVersion.JAVA7;
}
String jseVersion;
switch (jVersion) {
case JAVA8:
jseVersion = JavaCore.VERSION_1_8;
break;
case JAVA6:
jseVersion = JavaCore.VERSION_1_6;
break;
case JAVA5:
jseVersion = JavaCore.VERSION_1_5;
break;
case JAVA7:
default:
jseVersion = JavaCore.VERSION_1_7;
break;
}
projectFactory.setBreeToUse("JavaSE-" + jseVersion); //$NON-NLS-1$
projectFactory.addFolders(creator.getSourceFolders());
IPath srcGenFolder = Path.fromPortableString(creator.getGenerationFolder());
projectFactory.addBuilderIds(creator.getBuilderIds());
projectFactory.addProjectNatures(creator.getNatures());
IProject result = projectFactory.createProject(null, null);
IJavaProject javaProject = JavaCore.create(result);
makeCompliantFor(javaProject, jVersion);
creator.addJreClasspathEntry(javaProject);
IPath workspaceRoot;
IPath platformLocation;
try {
workspaceRoot = ResourcesPlugin.getWorkspace().getRoot().getLocation();
Location location = Platform.getInstallLocation();
java.net.URI uri = org.eclipse.core.runtime.URIUtil.toURI(location.getURL());
platformLocation = URIUtil.toPath(uri);
} catch (Exception e) {
throw new RuntimeException(e);
}
// Retreive the bundles
List<IClasspathEntry> classpathEntries = new ArrayList<>(bundleDependencies.length);
for(String bundleName : bundleDependencies) {
URL url;
try {
url = new URL(bundleName);
} catch (Throwable exception) {
url = null;
}
if (url != null) {
URL newUrl;
try {
newUrl = FileLocator.toFileURL(url);
} catch (Exception exception) {
throw new RuntimeException("Reference library not found: " + url, exception); //$NON-NLS-1$
}
if (newUrl == null) {
throw new RuntimeException("Reference library not found: " + url); //$NON-NLS-1$
}
IPath path = Path.fromPortableString(newUrl.getPath());
IClasspathEntry classPathEntry = JavaCore.newLibraryEntry(
path,
null,
null);
classpathEntries.add(classPathEntry);
} else {
Bundle bundle = Platform.getBundle(bundleName);
if (bundle == null) {
throw new RuntimeException("Reference library not found: " + bundleName); //$NON-NLS-1$
}
IPath bundlePath = computeBundlePath(bundle, workspaceRoot, platformLocation);
if (bundlePath == null) {
throw new RuntimeException("Reference library not found: " + bundleName); //$NON-NLS-1$
}
IPath binPath = computeBinaryPathForBundle(bundlePath, workspaceRoot);
if (binPath == null) {
throw new RuntimeException("Reference library not found: " + bundleName); //$NON-NLS-1$
}
IClasspathEntry classPathEntry = JavaCore.newLibraryEntry(
binPath,
null,
null);
classpathEntries.add(classPathEntry);
}
}
if (!classpathEntries.isEmpty()) {
creator.addToClasspath(javaProject, false, classpathEntries);
}
// Configure SARL source folder
SARLPreferences.setSpecificSARLConfigurationFor(result, srcGenFolder);
// Enable "Build automatically"
try {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription workspaceDescription = workspace.getDescription();
workspaceDescription.setAutoBuilding(true);
workspace.setDescription(workspaceDescription);
} catch (Throwable exception) {
throw new CoreException(new Status(IStatus.ERROR, "io.sarl.tests.api", //$NON-NLS-1$
exception.getLocalizedMessage(), exception));
}
awaitAutoBuild();
return result;
}
private static IPath computeBundlePath(Bundle bundle, IPath workspaceRoot, IPath platformLocation) {
IPath bundlePath;
try {
File file = FileLocator.getBundleFile(bundle);
bundlePath = Path.fromOSString(file.getPath());
} catch (IOException e1) {
throw new RuntimeException(e1);
}
// Ensure that the bundle path is absolute (mandatory for beeing a classpath entry)
if (!bundlePath.isAbsolute()) {
IPath newBundlePath = workspaceRoot.append(bundlePath);
if (!newBundlePath.toFile().exists()) {
newBundlePath = platformLocation.append(bundlePath);
}
bundlePath = newBundlePath;
}
assert (bundlePath.isAbsolute()) : "The bundle path is not absolute: " + bundlePath; //$NON-NLS-1$
return bundlePath;
}
private static IPath computeBinaryPathForBundle(IPath bundlePath, IPath workspaceRoot) {
// Determine the path from the output folders of the Java projects in the current workspace.
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(bundlePath.lastSegment());
IPath newBundlePath = null;
try {
if (project != null && project.hasNature(JavaCore.NATURE_ID)) {
IJavaProject javaProject = JavaCore.create(project);
newBundlePath = javaProject.getOutputLocation();
if (newBundlePath != null) {
newBundlePath = workspaceRoot.append(newBundlePath);
// Test if the bundle path exists
if (newBundlePath != null && !newBundlePath.toFile().exists()) {
newBundlePath = null;
}
}
}
} catch (Exception e) {
// Ignore the exceptions since they are not useful (hopefully)
}
if (newBundlePath != null) {
assert (newBundlePath.isAbsolute()) : "The bundle path is not absolute: " + newBundlePath; //$NON-NLS-1$
return newBundlePath;
}
// Detect the binary folder in the bundle.
//
// TODO: Replace by a dynamic detection based on Jdt API.
File localFile = bundlePath.toFile();
File binFolder = new File(new File(localFile, "target"), "classes"); //$NON-NLS-1$//$NON-NLS-2$
if (binFolder.exists()) {
newBundlePath = bundlePath.append("target").append("classes"); //$NON-NLS-1$//$NON-NLS-2$
} else {
binFolder = new File(localFile, "bin"); //$NON-NLS-1$
if (binFolder.exists()) {
newBundlePath = bundlePath.append("bin"); //$NON-NLS-1$
} else {
newBundlePath = bundlePath;
}
}
assert (newBundlePath.isAbsolute()) : "The bundle path is not absolute: " + bundlePath; //$NON-NLS-1$
return newBundlePath;
}
/** Make the given project compliant for the given version.
*
* @param javaProject the project.
* @param javaVersion the Java version.
*/
public static void makeCompliantFor(IJavaProject javaProject, JavaVersion javaVersion) {
Map<String, String> options = javaProject.getOptions(false);
String jreLevel;
switch (javaVersion) {
case JAVA8:
jreLevel = JavaCore.VERSION_1_8;
break;
case JAVA6:
jreLevel = JavaCore.VERSION_1_6;
break;
case JAVA5:
jreLevel = JavaCore.VERSION_1_5;
break;
case JAVA7:
default:
jreLevel = JavaCore.VERSION_1_7;
}
options.put(JavaCore.COMPILER_COMPLIANCE, jreLevel);
options.put(JavaCore.COMPILER_SOURCE, jreLevel);
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, jreLevel);
options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
options.put(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
options.put(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, JavaCore.GENERATE);
options.put(JavaCore.COMPILER_LINE_NUMBER_ATTR, JavaCore.GENERATE);
options.put(JavaCore.COMPILER_SOURCE_FILE_ATTR, JavaCore.GENERATE);
options.put(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL, JavaCore.PRESERVE);
javaProject.setOptions(options);
}
/** Add exported packages into the project.
*
* @param project the project.
* @param exportedPackages the exported packages.
* @throws Exception
*/
public static void addExportedPackages(IProject project, String ... exportedPackages) throws Exception{
IFile manifest = project.getFile("META-INF/MANIFEST.MF"); //$NON-NLS-1$
Manifest mf = new Manifest(manifest.getContents());
String value = mf.getMainAttributes().getValue("Export-Package"); //$NON-NLS-1$
for (String exported : exportedPackages) {
if (value == null) {
value = exported;
} else {
value += ","+exported; //$NON-NLS-1$
}
}
mf.getMainAttributes().putValue("Export-Package", value); //$NON-NLS-1$
ByteArrayOutputStream stream = new ByteArrayOutputStream();
mf.write(stream);
manifest.setContents(new ByteArrayInputStream(stream.toByteArray()), true, true, null);
}
/** Add required plugin into the project.
*
* @param project the project.
* @param requiredBundles the required bundles.
* @throws Exception
*/
public static void addRequiredBundle(IProject project, Iterable<String> requiredBundles) throws Exception{
IFile manifest = project.getFile("META-INF/MANIFEST.MF"); //$NON-NLS-1$
Manifest mf = new Manifest(manifest.getContents());
String value = mf.getMainAttributes().getValue("Required-Bundles"); //$NON-NLS-1$
for (String required : requiredBundles) {
if (value == null) {
value = required;
} else {
value += ","+required; //$NON-NLS-1$
}
}
mf.getMainAttributes().putValue("Required-Bundles", value); //$NON-NLS-1$
ByteArrayOutputStream stream = new ByteArrayOutputStream();
mf.write(stream);
manifest.setContents(new ByteArrayInputStream(stream.toByteArray()), true, true, null);
}
/** Delete the given project.
*
* @param project the project to delete.
* @throws CoreException
*/
public static void deleteProject(IProject project) throws CoreException {
if (project != null && project.exists()) {
project.delete(true, true, null);
}
}
/** Open the default editor for the given file.
*
* @param file the file to open.
* @return the editor.
* @throws Exception
*/
public XtextEditor openEditor(IFile file) throws Exception {
IEditorPart openEditor = openEditor(file, getEditorID());
XtextEditor xtextEditor = EditorUtils.getXtextEditor(openEditor);
if (xtextEditor != null) {
xtextEditor.selectAndReveal(0, 0);
return xtextEditor;
} else if (openEditor instanceof ErrorEditorPart) {
Field field = openEditor.getClass().getDeclaredField("error"); //$NON-NLS-1$
field.setAccessible(true);
throw new IllegalStateException("Couldn't open the editor.", //$NON-NLS-1$
((Status) field.get(openEditor)).getException());
} else {
fail("Opened Editor with id:" + getEditorID() + ", is not an XtextEditor"); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
}
/** Open the specific editor for the given file.
*
* @param file the file to open.
* @param editorId the identifier of the editor.
* @return the editor.
* @throws PartInitException
*/
public IEditorPart openEditor(IFile file, String editorId) throws PartInitException {
return this.workbench.getActiveWorkbenchWindow().getActivePage().openEditor(new FileEditorInput(file), editorId);
}
/** Open the text editor for the given file.
*
* @param file the file to open.
* @return the editor.
* @throws PartInitException
*/
public ITextEditor openLikeTextEditor(IFile file) throws PartInitException {
IEditorPart editor = IDE.openEditor(this.workbench.getActiveWorkbenchWindow().getActivePage(), file);
if (editor instanceof ITextEditor) {
return (ITextEditor) editor;
}
return null;
}
/** Close the editor.
*
* @param editor the editor.
* @param save indicates if the content must be saved before closing.
* @return success state.
*/
public boolean closeEditor(IEditorPart editor, boolean save) {
return this.workbench.getActiveWorkbenchWindow().getActivePage().closeEditor(editor, save);
}
/** Close all the editors.
*
* @param save indicates if the contents must be saved before closing.
* @return success state.
*/
public boolean closeAllEditors(boolean save) {
return this.workbench.getActiveWorkbenchWindow().getActivePage().closeAllEditors(save);
}
/** Save the content of the given editor.
*
* @param editor the editor.
* @param confirm indicates if the confirmation box must be shown.
* @return success state.
*/
public boolean saveEditor(IEditorPart editor, boolean confirm) {
return this.workbench.getActiveWorkbenchWindow().getActivePage().saveEditor(editor, confirm);
}
/**
* Wait for an update in the UI.
*
* @param test
* tester function that returns true if the target state of the UI has been reached
* @param timeout
* the time after which waiting is canceled
*/
public void awaitUIUpdate(Functions.Function0<Boolean> test, final long timeout) {
long startTime = System.currentTimeMillis();
final Display display = Display.getCurrent();
new Thread("Display alarm") { //$NON-NLS-1$
@Override public void run() {
try {
Thread.sleep(timeout);
display.wake();
} catch (InterruptedException e) {
//
}
}
}.start();
while (!test.apply() && System.currentTimeMillis() - startTime < timeout) {
boolean hasWork = display.sleep();
while (hasWork) {
hasWork = display.readAndDispatch();
}
}
}
/** Wait for the end of auto-build.
*/
public void awaitAutoBuild() {
boolean wasInterrupted = false;
do {
try {
Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD,
null);
wasInterrupted = false;
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (InterruptedException e) {
wasInterrupted = true;
}
} while (wasInterrupted);
}
/** Do a full build.
*
* @param resources the resources that should be build before launching ann Eclipse full build.
* @throws CoreException if the build cannot be done.
*/
public void fullBuild(Resource... resources) throws CoreException {
if (resources != null) {
for (final Resource resource : resources) {
resource.getContents();
}
}
ResourcesPlugin.getWorkspace().build(
IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
boolean wasInterrupted = false;
do {
try {
Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_BUILD,
null);
wasInterrupted = false;
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (InterruptedException e) {
wasInterrupted = true;
}
} while (wasInterrupted);
}
/** Generate a filename for a resource that does not exist yet.
*
* @param pathElements - the elements of the path (directories and basename), without the extension.
* @return the filename.
*/
public String generateFilename(String... pathElements) {
int filenameCounter = 0;
String oFilename = pathStr(pathElements);
String filename = oFilename;
boolean foundFile = isFileInSourceFolder(filename);
while (foundFile) {
++filenameCounter;
filename = oFilename + Integer.toString(filenameCounter);
foundFile = isFileInSourceFolder(filename);
}
return filename;
}
/** Generate a filename for a resource that does not exist yet.
*
* @return the filename.
*/
public String generateFilename() {
String p = getDefaultTestPackage() + ".unittest"; //$NON-NLS-1$
return generateFilename(p.split("\\.")); //$NON-NLS-1$
}
/** Replies the default package name where unit test files are located.
*
* @return the package name.
*/
public String getDefaultTestPackage() {
return "io.sarl.tests"; //$NON-NLS-1$
}
/** Replies if a file exists in the source folder.
*
* @param basename - the basename of the file in the source folder.
* @return <code>true</code> if the file exists, otherwise <code>false</code>.
*/
public boolean isFileInSourceFolder(String basename) {
String fullFileName = getFullFileNameInSources(basename);
return this.workspace.getRoot().exists(new Path(fullFileName));
}
/** Build a path.
*
* @param path - path elements.
* @return the path.
*/
public static IPath path(String... path) {
assert(path != null && path.length > 0);
IPath p = new Path(path[0]);
for(int i=1; i<path.length; ++i) {
p = p.append(path[i]);
}
return p;
}
/** Build a path.
*
* @param path - path elements.
* @return the path.
*/
public static String pathStr(String... path) {
return path(path).toOSString();
}
/** Replies the Eclipse shell used by this workbench.
*
* @return the shell.
*/
public Shell getShell() {
return this.workbench.getActiveWorkbenchWindow().getShell();
}
/** Factory of a project.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public interface ProjectCreator {
/** Replies the injector.
*
* @return the injector.
*/
Injector getInjector();
/** Replies the project factory.
*
* @return the factory.
*/
PluginProjectFactory getProjectFactory();
/** Replies the version of Java that is supported by the project.
*
* @return the java version.
*/
JavaVersion getJavaVersion();
/** Replies the source folders.
*
* @return the source folders.
*/
List<String> getSourceFolders();
/** Replies the folder in which the sources are generated.
*
* @return the generation folder.
*/
String getGenerationFolder();
/** Replies the identifiers of the builders.
*
* @return the identifiers.
*/
String[] getBuilderIds();
/** Replies the identifiers of the natures
*
* @return the identifiers.
*/
String[] getNatures();
/** Add a JRE library to the class path.
*
* @param javaProject the proejct to update.
* @throws JavaModelException
*/
void addJreClasspathEntry(IJavaProject javaProject) throws JavaModelException;
/** Add a library to the class path.
*
* @param javaProject the proejct to update.
* @param newClassPathEntry the entry to add.
* @throws JavaModelException
*/
void addToClasspath(IJavaProject javaProject, IClasspathEntry newClassPathEntry) throws JavaModelException;
/** Add libraries to the class path.
*
* @param javaProject the proejct to update.
* @param autobuild indicates if the function should wait for end of autobuild.
* @param newClassPathEntry the entry to add.
* @throws JavaModelException
*/
void addToClasspath(IJavaProject javaProject,
boolean autobuild,
Iterable<IClasspathEntry> newClassPathEntry) throws JavaModelException;
}
}