org.eclipse.xtend.ide.tests.WorkbenchTestHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtend.ide.tests.WorkbenchTestHelper.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2017 itemis AG (http://www.itemis.eu) 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
 *******************************************************************************/
package org.eclipse.xtend.ide.tests;

import static com.google.common.collect.ImmutableList.*;
import static com.google.common.collect.Lists.*;
import static com.google.common.collect.Sets.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.xtext.util.MergeableManifest.Attributes;

import org.apache.log4j.Logger;
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.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
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.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
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.XtendFile;
import org.eclipse.xtend.ide.internal.XtendActivator;
import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil;
import org.eclipse.xtext.ui.testing.util.JavaProjectSetupUtil;
import org.eclipse.xtext.resource.FileExtensionProvider;
import org.eclipse.xtext.ui.XtextProjectHelper;
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.JREContainerProvider;
import org.eclipse.xtext.ui.util.PluginProjectFactory;
import org.eclipse.xtext.util.JavaVersion;
import org.eclipse.xtext.util.MergeableManifest;
import org.eclipse.xtext.util.StringInputStream;
import org.eclipse.xtext.xbase.lib.Functions;
import org.eclipse.xtext.xbase.lib.Pair;
import org.junit.Assert;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
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;

/**
 * @author Jan Koehnlein - Initial contribution and API
 */
@Singleton
public class WorkbenchTestHelper extends Assert {

    public static final Logger log = Logger.getLogger(WorkbenchTestHelper.class);

    public static final String TESTPROJECT_NAME = "test.project";

    public static final ImmutableList<String> DEFAULT_REQ_BUNDLES = of("com.google.inject", "org.eclipse.xtend.lib",
            "org.eclipse.xtext.xbase.lib", "org.eclipse.xtend.ide.tests.data", "org.junit");

    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;

    private boolean isLazyCreatedProject = false;

    public void tearDown() throws Exception {
        if (workbench.getActiveWorkbenchWindow() != null)
            workbench.getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
        new WorkspaceModifyOperation() {

            @Override
            protected void execute(IProgressMonitor monitor)
                    throws CoreException, InvocationTargetException, InterruptedException {
                for (IFile file : getFiles()) {
                    try {
                        file.delete(true, null);
                    } catch (Exception exc) {
                        throw new RuntimeException(exc);
                    }
                }
                getFiles().clear();
                IFolder binFolder = getProject(false).getFolder("bin");
                if (binFolder.exists()) {
                    for (IResource binMember : binFolder.members()) {
                        try {
                            binMember.delete(true, null);
                        } catch (Exception exc) {
                            throw new RuntimeException(exc);
                        }
                    }
                }
                if (isLazyCreatedProject) {
                    deleteProject(getProject(false));
                    isLazyCreatedProject = false;
                }
            }
        }.run(null);
        IResourcesSetupUtil.waitForBuild();
    }

    public Set<IFile> getFiles() {
        return files;
    }

    public IProject getProject() {
        return getProject(true);
    }

    protected IProject getProject(boolean createOnDemand) {
        IProject project = workspace.getRoot().getProject(TESTPROJECT_NAME);
        if (createOnDemand && !project.exists()) {
            try {
                isLazyCreatedProject = true;
                project = createPluginProject(TESTPROJECT_NAME);
            } catch (CoreException e) {
                throw new RuntimeException(e);
            }
        }
        return project;
    }

    public XtextEditor openEditor(String fileName, String content) throws Exception {
        int cursor = content.indexOf('|');
        IFile file = createFile(fileName, content.replace("|", ""));
        IResourcesSetupUtil.waitForBuild();
        XtextEditor editor = openEditor(file);
        editor.getInternalSourceViewer().setSelectedRange(cursor, 0);
        editor.getInternalSourceViewer().getTextWidget().setFocus();
        return editor;
    }

    public IFile createFile(String fileName, String content) throws Exception {
        String fullFileName = getFullFileName(fileName);
        return createFileImpl(fullFileName, content);
    }

    public IFile createFileImpl(String fullFileName, String content) throws Exception {
        IFile file = IResourcesSetupUtil.createFile(fullFileName, content);
        getFiles().add(file);
        return file;
    }

    public IFile getFile(String fileName) {
        return workspace.getRoot().getFile(new Path(getFullFileName(fileName)));
    }

    protected String getFullFileName(String fileName) {
        String extension = (fileName.indexOf(".") != -1) ? "" : "." + getFileExtension();
        String fullFileName = getProject().getName() + "/src/" + fileName + extension;
        return fullFileName;
    }

    public String getFileExtension() {
        return fileExtensionProvider.getFileExtensions().iterator().next();
    }

    public URI uri(IFile file) {
        return URI.createPlatformResourceURI(file.getFullPath().toString(), true);
    }

    public XtendFile xtendFile(String fileName, String content) throws Exception {
        IFile file = createFile(fileName, content);
        Resource resource = getResourceSet().createResource(uri(file));
        resource.load(new StringInputStream(content), null);
        assertEquals(resource.getErrors().toString(), 0, resource.getErrors().size());
        XtendFile xtendFile = (XtendFile) resource.getContents().get(0);
        return xtendFile;
    }

    public XtendFile xtendFile(IProject project, String fileName, String content) throws Exception {
        IFile file = createFileImpl(project.getName() + "/src/" + fileName, content);
        Resource resource = resourceSetProvider.get(project).createResource(uri(file));
        resource.load(new StringInputStream(content), null);
        assertEquals(resource.getErrors().toString(), 0, resource.getErrors().size());
        XtendFile xtendFile = (XtendFile) resource.getContents().get(0);
        return xtendFile;
    }

    public ResourceSet getResourceSet() {
        ResourceSet resourceSet = resourceSetProvider.get(getProject());
        return resourceSet;
    }

    public String getEditorID() {
        return editorInfo.getEditorId();
    }

    public static String getContentsAsString(IFile file) throws Exception {
        InputStream inputStream = file.getContents();
        try {
            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();
        } finally {
            inputStream.close();
        }
    }

    public void closeWelcomePage() throws InterruptedException {
        if (PlatformUI.getWorkbench().getIntroManager().getIntro() != null) {
            PlatformUI.getWorkbench().getIntroManager()
                    .closeIntro(PlatformUI.getWorkbench().getIntroManager().getIntro());
        }
    }

    public static IProject createPluginProject(String name) throws CoreException {
        return createPluginProject(name, DEFAULT_REQ_BUNDLES.toArray(new String[DEFAULT_REQ_BUNDLES.size()]));
    }

    public static IProject createPluginProject(String name, JavaVersion javaVersion) throws CoreException {
        return createPluginProject(name, javaVersion,
                DEFAULT_REQ_BUNDLES.toArray(new String[DEFAULT_REQ_BUNDLES.size()]));
    }

    public static IProject createPluginProject(String name, String... requiredBundles) throws CoreException {
        return createPluginProject(name, null, requiredBundles);
    }

    public static IProject createPluginProject(String name, JavaVersion javaVersion, String... requiredBundles)
            throws CoreException {
        Injector injector = XtendActivator.getInstance().getInjector("org.eclipse.xtend.core.Xtend");
        PluginProjectFactory projectFactory = injector.getInstance(PluginProjectFactory.class);
        projectFactory.setProjectName(name);
        projectFactory.setBreeToUse(getBree(javaVersion));
        projectFactory.addFolders(Collections.singletonList("src"));
        projectFactory.addBuilderIds(XtextProjectHelper.BUILDER_ID, JavaCore.BUILDER_ID,
                "org.eclipse.pde.ManifestBuilder", "org.eclipse.pde.SchemaBuilder");
        projectFactory.addProjectNatures(XtextProjectHelper.NATURE_ID, JavaCore.NATURE_ID,
                "org.eclipse.pde.PluginNature");
        projectFactory.addRequiredBundles(newArrayList(requiredBundles));
        IProject result = projectFactory.createProject(new NullProgressMonitor(), null);
        IJavaProject javaProject = JavaCore.create(result);
        if (javaVersion == null)
            JavaProjectSetupUtil.makeJava5Compliant(javaProject);
        else
            makeCompliantFor(javaProject, javaVersion);
        JavaProjectSetupUtil.addJreClasspathEntry(javaProject);
        return result;
    }

    private static String getBree(JavaVersion javaVersion) {
        if (javaVersion == null) {
            return JREContainerProvider.PREFERRED_BREE;
        } else {
            return javaVersion.getBree();
        }
    }

    public static void makeCompliantFor(IJavaProject javaProject, JavaVersion javaVersion) {
        @SuppressWarnings("unchecked")
        Map<String, String> options = javaProject.getOptions(false);
        String jreLevel = javaVersion.getQualifier();
        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);
    }

    /**
     * @return a {@link Pair}, where the <code>key</code> is the BREE that was set and the <code>value</code> indicates that the BREE was changed.
     */
    public static Pair<String, Boolean> changeBree(IJavaProject javaProject, final JavaVersion javaVersion)
            throws Exception {
        final AtomicReference<String> bree = new AtomicReference<String>();
        boolean changed = changeManifest(javaProject.getProject(), new Function<MergeableManifest, Boolean>() {
            @Override
            public Boolean apply(MergeableManifest mf) {
                mf.setBREE(getBree(javaVersion));
                return mf.isModified();
            }
        });
        if (changed) {
            JavaProjectSetupUtil.addJreClasspathEntry(javaProject, bree.get());
        }
        return Pair.of(bree.get(), changed);
    }

    public static boolean addExportedPackages(IProject project, final String... exportedPackages) throws Exception {
        return changeManifest(project, new Function<MergeableManifest, Boolean>() {
            @Override
            public Boolean apply(MergeableManifest mf) {
                mf.addExportedPackages(exportedPackages);
                return mf.isModified();
            }
        });
    }

    public static boolean removeExportedPackages(IProject project, final String... exportedPackages)
            throws Exception {
        return changeManifest(project, new Function<MergeableManifest, Boolean>() {
            @Override
            public Boolean apply(MergeableManifest mf) {
                Attributes attrs = mf.getMainAttributes();
                Attributes.Name expPackKey = new Attributes.Name("Export-Package");
                String oldValue = attrs.getValue(expPackKey);
                if (!Strings.isNullOrEmpty(oldValue)) {
                    String[] existingExports = oldValue.split(",(\\s+)?");
                    System.out.println(Arrays.toString(existingExports));
                    List<String> exportsToKeep = new ArrayList<String>();
                    for (String string : existingExports) {
                        exportsToKeep.add(string.trim());
                    }
                    boolean changed = exportsToKeep.removeAll(Arrays.asList(exportedPackages));
                    String valueToSet = Joiner.on(',').join(exportsToKeep);
                    if (changed) {
                        if (valueToSet.isEmpty()) {
                            attrs.remove(expPackKey);
                        } else {
                            attrs.put(expPackKey, valueToSet);
                        }
                        return true;
                    }
                }
                return false;
            }
        });
    }

    public static boolean changeManifest(IProject project, Function<MergeableManifest, Boolean> config)
            throws Exception {
        IFile manifest = project.getFile("META-INF/MANIFEST.MF");
        InputStream content = manifest.getContents();
        MergeableManifest mf;
        try {
            mf = new MergeableManifest(content);
        } finally {
            content.close();
        }
        if (config.apply(mf)) {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            mf.write(stream);
            manifest.setContents(new ByteArrayInputStream(stream.toByteArray()), true, false, null);
            return true;
        }
        return false;
    }

    public static void deleteProject(IProject project) throws CoreException {
        if (project != null && project.exists()) {
            project.delete(true, true, null);
        }
    }

    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");
            field.setAccessible(true);
            throw new IllegalStateException("Couldn't open the editor.",
                    ((Status) field.get(openEditor)).getException());
        } else {
            fail("Opened Editor with id:" + getEditorID() + ", is not an XtextEditor");
        }
        return null;
    }

    public IEditorPart openEditor(IFile file, String editorId) throws PartInitException {
        return workbench.getActiveWorkbenchWindow().getActivePage().openEditor(new FileEditorInput(file), editorId);
    }

    public ITextEditor openLikeTextEditor(IFile file) throws PartInitException {
        IEditorPart editor = IDE.openEditor(workbench.getActiveWorkbenchWindow().getActivePage(), file);
        if (editor instanceof ITextEditor) {
            return (ITextEditor) editor;
        }
        return null;
    }

    public boolean closeEditor(IEditorPart editor, boolean save) {
        return workbench.getActiveWorkbenchWindow().getActivePage().closeEditor(editor, save);
    }

    public boolean closeAllEditors(boolean save) {
        return workbench.getActiveWorkbenchWindow().getActivePage().closeAllEditors(save);
    }

    public boolean saveEditor(IEditorPart editor, boolean confirm) {
        return 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") {
            @Override
            public void run() {
                try {
                    Thread.sleep(timeout);
                    if (!display.isDisposed())
                        display.wake();
                } catch (InterruptedException e) {
                }
            }
        }.start();
        while (!test.apply() && System.currentTimeMillis() - startTime < timeout) {
            boolean hasWork = display.sleep();
            while (hasWork) {
                hasWork = display.readAndDispatch();
            }
        }
    }

}