org.eclipse.wb.tests.designer.TestUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wb.tests.designer.TestUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Google, Inc.
 * 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:
 *    Google, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.wb.tests.designer;

import com.google.common.collect.Lists;

import org.eclipse.wb.internal.core.DesignerPlugin;
import org.eclipse.wb.internal.core.utils.IOUtils2;
import org.eclipse.wb.internal.core.utils.external.ExternalFactoriesHelper;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.tests.designer.core.TestProject;
import org.eclipse.wb.tests.designer.tests.Activator;

import org.eclipse.core.internal.registry.ExtensionRegistry;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.ContributorFactoryOSGi;
import org.eclipse.core.runtime.IContributor;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWizard;

import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.apache.commons.lang.StringUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.EmptyVisitor;
import org.osgi.framework.Bundle;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Vector;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

/**
 * Some external utils for tests.
 * 
 * @author scheglov_ke
 */
public final class TestUtils {
    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor 
    //
    ////////////////////////////////////////////////////////////////////////////
    private TestUtils() {
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Utils
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Creates file with empty PNG image of given size.
     * 
     * @param testProject
     *          the {@link TestProject} to access {@link IProject} where to create image.
     * @param path
     *          the path relative to {@link IProject}, for example <code>"src/test/MyImage.png"</code>
     *          .
     * @param width
     *          the width of image.
     * @param height
     *          the height of image.
     */
    public static IFile createImagePNG(TestProject testProject, String path, int width, int height)
            throws Exception {
        byte[] bytes = createImagePNG(width, height);
        IFile file = testProject.getProject().getFile(new Path(path));
        IOUtils2.setFileContents(file, new ByteArrayInputStream(bytes));
        return file;
    }

    /**
     * @return the bytes of PNG image with given size.
     */
    public static byte[] createImagePNG(int width, int height) {
        Image image = new Image(null, width, height);
        ImageLoader imageLoader = new ImageLoader();
        imageLoader.data = new ImageData[] { image.getImageData() };
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        imageLoader.save(baos, SWT.IMAGE_PNG);
        return baos.toByteArray();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Workbench
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Closes all {@link IViewPart}s.
     */
    public static void closeAllViews() {
        // run event loop to allow any async's be executed
        while (Display.getCurrent().readAndDispatch()) {
            // do nothing
        }
        // do close
        IWorkbenchPage activePage = DesignerPlugin.getActivePage();
        IViewReference[] viewReferences = activePage.getViewReferences();
        if (viewReferences.length != 0) {
            for (IViewReference viewReference : viewReferences) {
                activePage.hideView(viewReference);
            }
            waitEventLoop(100);
        }
    }

    /**
     * Closes all editors.
     */
    public static void closeAllEditors() {
        // run event loop to allow any async's be executed
        while (Display.getCurrent().readAndDispatch()) {
            // do nothing
        }
        // close all editors
        {
            IWorkbenchPage activePage = DesignerPlugin.getActivePage();
            activePage.closeAllEditors(false);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Dynamic extensions
    //
    ////////////////////////////////////////////////////////////////////////////
    private static final String EXTENSION_ID = "testExtension";
    private static Bundle m_contributionBundle;

    /**
     * @return the {@link Bundle} from which contribution is performed, not <code>null</code>.
     */
    private static Bundle getContributorBundle() {
        if (m_contributionBundle != null) {
            return m_contributionBundle;
        }
        return Activator.getDefault().getBundle();
    }

    /**
     * Sets the {@link Bundle} from which contribution is performed, may be <code>null</code> to reset
     * to the WindowBuilder bundle.
     */
    public static void setContributionBundle(Bundle contributionBundle) {
        m_contributionBundle = contributionBundle;
    }

    /**
     * @return the qualified exception id, i.e. contributor bundle plus simpel ID.
     */
    private static String getQualifiedExtensionId(String simpleId) {
        return getContributorBundle().getSymbolicName() + "." + simpleId;
    }

    /**
     * Adds dynamic extension.
     * 
     * @param pointId
     *          the qualified extension point id, e.g. <code>"org.eclipse.wb.core.toolkits"</code>.
     * @param contribution
     *          the {@link String} with contribution, without <code>"plugin"</code> and
     *          <code>"extension"</code> tags.
     */
    public static void addDynamicExtension(String pointId, String contribution) {
        addDynamicExtension(pointId, EXTENSION_ID, contribution);
    }

    /**
     * Adds dynamic extension.
     * 
     * @param pointId
     *          the qualified extension point id, e.g. <code>"org.eclipse.wb.core.toolkits"</code>.
     * @param extensionId
     *          the (simple) id of added extension, for example <code>"myNature"</code>.
     * @param contribution
     *          the {@link String} with contribution, without <code>"plugin"</code> and
     *          <code>"extension"</code> tags.
     */
    public static void addDynamicExtension(String pointId, String extensionId, String contribution) {
        contribution = "<extension point='%pointId%' id='%extensionId%'>\n" + contribution + "\n</extension>";
        addDynamicExtension2(pointId, extensionId, contribution);
    }

    /**
     * Adds dynamic extension.<br>
     * In contrast to {@link #addDynamicExtension(String, String)}, this method accepts full
     * contribution, that should have <code>"point", "id"</code> and other attributes.
     * 
     * @param pointId
     *          the qualified extension point id, e.g. <code>"org.eclipse.wb.core.toolkits"</code>.
     * @param extensionId
     *          the (simple) id of added extension, for example <code>"myNature"</code>.
     * @param contribution
     *          the {@link String} with full contribution, without <code>"plugin"</code> tag, but with
     *          <code>"extension"</code> tag. It may use <code>"%pointId%"</code> and
     *          <code>"%extensionId%"</code> template variables.
     */
    public static void addDynamicExtension2(String pointId, String extensionId, String contribution) {
        // update contribution
        contribution = "<plugin>\n" + contribution + "\n</plugin>";
        contribution = StringUtils.replace(contribution, "%pointId%", pointId);
        contribution = StringUtils.replace(contribution, "%extensionId%", extensionId);
        // add extension into registry
        {
            Bundle bundle = getContributorBundle();
            IContributor contributor = ContributorFactoryOSGi.createContributor(bundle);
            IExtensionRegistry registry = Platform.getExtensionRegistry();
            Object userToken = ((ExtensionRegistry) registry).getTemporaryUserToken();
            // do add
            registry.addContribution(new ByteArrayInputStream(contribution.getBytes()), contributor, false, null,
                    null, userToken);
        }
        // wait for added extension
        {
            String qualifiedExtensionId = getQualifiedExtensionId(extensionId);
            while (ExternalFactoriesHelper.getExtension(pointId, qualifiedExtensionId) == null) {
                waitEventLoop(1);
            }
        }
    }

    /**
     * Removes the test dynamic extension, added previously by
     * {@link #addDynamicExtension(String, String)}.
     * 
     * @param pointId
     *          the qualified extension point id, e.g. <code>"org.eclipse.wb.core.toolkits"</code>.
     */
    public static void removeDynamicExtension(String pointId) {
        removeDynamicExtension(pointId, EXTENSION_ID);
    }

    /**
     * Removes the test dynamic extension, added previously by
     * {@link #addDynamicExtension(String, String)}. This methods <em>does not</em> wait for
     * processing asynchronous event by {@link ExternalFactoriesHelper}.
     */
    public static void removeDynamicExtension_noWait(String pointId) {
        doRemoveDynamicExtension(pointId, EXTENSION_ID);
    }

    /**
     * Removes dynamic extension from registry and waits until it will be removed also from
     * {@link ExternalFactoriesHelper}.
     * 
     * @param pointId
     *          the qualified extension point id, e.g. <code>"org.eclipse.wb.core.toolkits"</code>.
     * @param extensionId
     *          the (simple) id of extension to remove, for example <code>"myNature"</code>.
     */
    public static void removeDynamicExtension(String pointId, String extensionId) {
        String qualifiedExtensionId = getQualifiedExtensionId(extensionId);
        while (ExternalFactoriesHelper.getExtension(pointId, qualifiedExtensionId) != null) {
            doRemoveDynamicExtension(pointId, extensionId);
            waitEventLoop(1);
        }
    }

    /**
     * Removes dynamic extension from {@link IExtensionRegistry}.
     */
    private static void doRemoveDynamicExtension(String pointId, String extensionId) {
        IExtensionRegistry registry = Platform.getExtensionRegistry();
        IExtension extension = registry.getExtension(pointId, getQualifiedExtensionId(extensionId));
        // do remove
        Object userToken = ((ExtensionRegistry) registry).getTemporaryUserToken();
        registry.removeExtension(extension, userToken);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // UI utils
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Waits given number of milliseconds and runs events loop every 1 millisecond.<br>
     * At least one events loop will be executed.
     */
    public static void waitEventLoop(int time) {
        long start = System.currentTimeMillis();
        do {
            try {
                Thread.sleep(0);
            } catch (Throwable e) {
            }
            while (Display.getCurrent().readAndDispatch()) {
                // do nothing
            }
        } while (System.currentTimeMillis() - start < time);
    }

    public static void runWizard(final IWizard wizard, IStructuredSelection selection) {
        IWorkbenchWindow workbenchWindow = DesignerPlugin.getActiveWorkbenchWindow();
        // initialize IWorkbenchWizard
        if (wizard instanceof IWorkbenchWizard) {
            ((IWorkbenchWizard) wizard).init(workbenchWindow.getWorkbench(), selection);
        }
        // open Wizard UI
        WizardDialog dialog = new WizardDialog(workbenchWindow.getShell(), wizard);
        dialog.create();
        String title = wizard.getWindowTitle();
        if (title != null) {
            dialog.getShell().setText(title);
        }
        dialog.open();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Resources
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * @return the path to the temporary "jar" file with single entry.
     * 
     * @param entryName
     *          the name of entry, for example <code>"myFolder/subFolder/file.txt"</code>.
     * @param content
     *          the {@link String} content of entry.
     */
    public static String createTemporaryJar(String entryName, String content) throws Exception {
        File tempFile = File.createTempFile("wbpTests", ".jar");
        tempFile.deleteOnExit();
        // create "jar" with single entry
        {
            JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(tempFile));
            jarOutputStream.putNextEntry(new ZipEntry(entryName));
            jarOutputStream.write(content.getBytes());
            jarOutputStream.closeEntry();
            jarOutputStream.close();
        }
        // return path to "jar"
        return tempFile.getAbsolutePath();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // TestSuite
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Sorts test methods in the given {@link TestSuite} to same order as they are declared in source
     * of test class.
     */
    public static void sortTestSuiteMethods(Class<?> clazz, TestSuite suite) {
        try {
            final List<String> sourceMethodNames = getSourceMethodNames(clazz);
            Vector<TestCase> tests = getTestsVector(suite);
            Collections.sort(tests, new Comparator<TestCase>() {
                public int compare(TestCase o1, TestCase o2) {
                    String method_1 = o1.getName();
                    String method_2 = o2.getName();
                    if ("test_setUp".equals(method_1)) {
                        return -1;
                    }
                    if ("test_setUp".equals(method_2)) {
                        return 1;
                    }
                    if ("test_tearDown".equals(method_1)) {
                        return 1;
                    }
                    if ("test_tearDown".equals(method_2)) {
                        return -1;
                    }
                    return sourceMethodNames.indexOf(method_1) - sourceMethodNames.indexOf(method_2);
                }
            });
        } catch (Throwable e) {
            ReflectionUtils.propagate(e);
        }
    }

    /**
     * @return the names of methods declared in the given {@link Class}, in same order as in source.
     */
    private static List<String> getSourceMethodNames(Class<?> testClass) throws Exception {
        final List<String> sourceMethodNames = Lists.newArrayList();
        String classPath = testClass.getName().replace('.', '/') + ".class";
        InputStream classStream = testClass.getClassLoader().getResourceAsStream(classPath);
        ClassReader classReader = new ClassReader(classStream);
        classReader.accept(new EmptyVisitor() {
            @Override
            public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                    String[] exceptions) {
                sourceMethodNames.add(name);
                return new EmptyVisitor();
            }
        }, 0);
        return sourceMethodNames;
    }

    /**
     * @return the live {@link Vector} of tests in the given {@link TestSuite}.
     */
    private static Vector<TestCase> getTestsVector(TestSuite suite) throws Exception {
        Field testsField = TestSuite.class.getDeclaredField("fTests");
        testsField.setAccessible(true);
        @SuppressWarnings("unchecked")
        Vector<TestCase> tests = (Vector<TestCase>) testsField.get(suite);
        return tests;
    }
}