de.ovgu.featureide.ui.actions.generator.TestRunner.java Source code

Java tutorial

Introduction

Here is the source code for de.ovgu.featureide.ui.actions.generator.TestRunner.java

Source

/* FeatureIDE - A Framework for Feature-Oriented Software Development
 * Copyright (C) 2005-2016  FeatureIDE team, University of Magdeburg, Germany
 *
 * This file is part of FeatureIDE.
 * 
 * FeatureIDE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * FeatureIDE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with FeatureIDE.  If not, see <http://www.gnu.org/licenses/>.
 *
 * See http://featureide.cs.ovgu.de/ for further information.
 */
package de.ovgu.featureide.ui.actions.generator;

import static de.ovgu.featureide.fm.core.localization.StringTable.IS_NO_XML_FILE;
import static de.ovgu.featureide.fm.core.localization.StringTable.OPEN;
import static de.ovgu.featureide.fm.core.localization.StringTable.RESOURCE;
import static de.ovgu.featureide.fm.core.localization.StringTable.RESTRICTION;
import static de.ovgu.featureide.fm.core.localization.StringTable.SERIAL;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.Permission;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.progress.UIJob;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;

import de.ovgu.featureide.core.CorePlugin;
import de.ovgu.featureide.ui.UIPlugin;
import de.ovgu.featureide.ui.actions.generator.IConfigurationBuilderBasics.BuildType;

/**
 * Runs test cases of the generated product.
 * 
 * @author Jens Meinicke
 */
@SuppressWarnings(RESTRICTION)
public class TestRunner {

    private static final Object KEY = new Object();
    private final TestResults testResults;
    private static final UIPlugin LOGGER = UIPlugin.getDefault();
    int compiled = 0;

    private final IFolder tmp;
    private final ConfigurationBuilder builder;

    public TestRunner(IFolder tmp, TestResults testResults, final ConfigurationBuilder builder) {
        this.tmp = tmp;
        this.testResults = testResults;
        this.builder = builder;

    }

    @SuppressWarnings(RESOURCE)
    public void runTests(final BuilderConfiguration configuration) {
        URL[] url = getURLs();
        URLClassLoader classLoader = new URLClassLoader(url, Thread.currentThread().getContextClassLoader());
        for (final String file : getFiles(tmp)) {
            try {
                Class<?> clazz = classLoader.loadClass(file);

                if (isModuleTest(clazz)) {
                    synchronized (KEY) {
                        if (testResults.modulTests.contains(clazz.getName())) {
                            continue;
                        } else {
                            testResults.modulTests.add(clazz.getName());
                        }
                    }
                }

                JUnitCore core = new JUnitCore();
                core.addListener(new RunListener() {

                    long time = 0;

                    @Override
                    public void testStarted(Description description) throws Exception {
                        if (description.toString().startsWith("initializationError")) {
                            return;
                        }
                        time = System.currentTimeMillis();
                    }

                    @Override
                    public void testFinished(Description description) throws Exception {
                        if (time == -1) {
                            return;
                        }
                        time = System.currentTimeMillis() - time;
                        testResults.addTest(file,
                                (builder.buildType == BuildType.ALL_CURRENT ? ""
                                        : ConfigurationBuilder.FOLDER_NAME + "\\") + configuration.getName(),
                                new Test(description.toString(), time, file));
                    }

                    @Override
                    public void testFailure(Failure failure) throws Exception {
                        if (failure.getDescription().toString().startsWith("initializationError")
                                || "No runnable methods".equals(failure.getMessage())) {
                            time = -1;
                            return;
                        }
                        time = System.currentTimeMillis() - time;
                        testResults.addTest(file,
                                (builder.buildType == BuildType.ALL_CURRENT ? ""
                                        : ConfigurationBuilder.FOLDER_NAME + "\\") + configuration.getName(),
                                new Test(failure.getTestHeader(), time, file, failure));
                        time = -1;
                    }

                    @Override
                    public void testIgnored(Description description) throws Exception {
                        testResults.ignored++;
                    }

                });
                SecurityManager originalManager = System.getSecurityManager();
                try {
                    System.setSecurityManager(NO_EXIT_MANAGER);
                    core.run(clazz);
                } finally {
                    System.setSecurityManager(originalManager);
                }
            } catch (ClassNotFoundException e) {
                LOGGER.logError(e);
            }
        }

        IFile iResultsXML = CorePlugin.getFeatureProject(tmp).getProject().getFile("test.xml");
        saveResults(iResultsXML, testResults);

    }

    private URL[] getURLs() {
        ArrayList<URL> urls = new ArrayList<>();
        try {
            URL url = tmp.getLocationURI().toURL();
            url = new URL(url.toString() + "/");
            urls.add(url);

            JavaProject proj = new JavaProject(tmp.getProject(), null);
            IJavaElement[] elements = proj.getChildren();
            for (IJavaElement e : elements) {
                String path = e.getPath().toOSString();
                if (path.contains(":")) {
                    continue;
                }
                IResource resource = e.getResource();
                if (resource != null && "jar".equals(resource.getFileExtension())) {
                    urls.add(resource.getRawLocationURI().toURL());
                }
            }
        } catch (MalformedURLException | JavaModelException e) {
            UIPlugin.getDefault().logError(e);
        }

        return urls.toArray(new URL[urls.size()]);
    }

    /**
     * Checks whether the class is a module test.
     */
    private boolean isModuleTest(Class<?> clazz) {
        for (Annotation a : clazz.getAnnotations()) {
            if ("@de.ovgu.featureide.ModuleTest()".equals(a.toString())) {
                // somehow clazz.getAnnotation(ModulTest.class) does not work 
                return true;
            }
        }
        return false;
    }

    private static final NoExitSecurityManager NO_EXIT_MANAGER = new NoExitSecurityManager();

    private static class NoExitSecurityManager extends SecurityManager {
        @Override
        public void checkPermission(Permission perm) {
            // allow anything.
        }

        @Override
        public void checkPermission(Permission perm, Object context) {
            // allow anything.
        }

        @Override
        public void checkExit(int status) {
            super.checkExit(status);
            throw new SystemExitException(status);
        }
    }

    @SuppressWarnings(SERIAL)
    private static class SystemExitException extends RuntimeException {
        public SystemExitException(int status) {
            super("Systen.exit: " + status);
        }
    }

    private List<String> getFiles(IFolder folder) {
        try {
            folder.refreshLocal(IResource.DEPTH_INFINITE, null);
        } catch (CoreException e) {
            LOGGER.logError(e);
        }
        return getFiles(folder, null);
    }

    private List<String> getFiles(IFolder folder, String prefix) {
        List<String> files = new LinkedList<>();
        try {

            for (IResource child : folder.members()) {
                if (child instanceof IFolder) {
                    files.addAll(getFiles((IFolder) child, (prefix != null ? prefix + "." : "") + child.getName()));
                } else if (child instanceof IFile) {
                    if ("class".equals(child.getFileExtension())) {
                        files.add((prefix != null ? prefix + "." : "")
                                + child.getName().substring(0, child.getName().lastIndexOf('.')));
                    }
                }
            }
        } catch (CoreException e) {
            LOGGER.logError(e);
        }
        return files;
    }

    private static synchronized void saveResults(IFile iResultsXML, TestResults testResults) {
        File resultsXML = new File(iResultsXML.getLocationURI());
        try {
            new TestXMLWriter(testResults).writeToFile(resultsXML);
            iResultsXML.refreshLocal(IResource.DEPTH_INFINITE, null);
            openJunitView(iResultsXML);
        } catch (ParserConfigurationException | TransformerException | CoreException e) {
            LOGGER.logError(e);
        }
    }

    /**
     * Tries to open the given xml file on the JUnit view.
     * 
     * @param file The xml file to open.
     */
    private static void openJunitView(final IFile file) {
        if (!file.getFileExtension().equals("xml")) {
            throw new RuntimeException(file + IS_NO_XML_FILE);
        }
        final UIJob job = new UIJob(OPEN + file) {

            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
                IWorkbenchWindow window = UIPlugin.getDefault().getWorkbench().getWorkbenchWindows()[0];
                IWorkbenchPage page = window.getActivePage();
                if (page == null)
                    return Status.OK_STATUS;

                try {
                    IEditorDescriptor desc = getDescriptor(file);
                    if (desc != null) {
                        page.openEditor(new FileEditorInput(file), desc.getId());
                    }
                } catch (CoreException e) {
                    LOGGER.logError(e);
                }
                return Status.OK_STATUS;
            }
        };
        job.schedule();
        try {
            job.join();
        } catch (InterruptedException e) {
            LOGGER.logError(e);
        }
    }

    private static IEditorDescriptor getDescriptor(IFile file) throws CoreException {
        IContentType contentType = null;
        IContentDescription description = file.getContentDescription();
        if (description != null) {
            contentType = description.getContentType();
        }
        if (contentType != null) {
            return PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getName(), contentType);
        } else {
            return PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getName());
        }
    }
}