org.eclipse.pde.api.tools.builder.tests.ApiTestingEnvironment.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.pde.api.tools.builder.tests.ApiTestingEnvironment.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2014 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
 *******************************************************************************/
package org.eclipse.pde.api.tools.builder.tests;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
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.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.tests.builder.TestingEnvironment;
import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
import org.eclipse.pde.api.tools.internal.builder.ApiAnalysisBuilder;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
import org.eclipse.pde.api.tools.model.tests.TestSuiteHelper;
import org.eclipse.pde.api.tools.tests.util.ProjectUtils;
import org.eclipse.pde.internal.core.natures.PDE;

/**
 * Environment used to test the {@link ApiAnalysisBuilder}. This environment
 * emulates a typical workbench environment
 * 
 * @since 1.0.0
 */
public class ApiTestingEnvironment extends TestingEnvironment {

    protected static final IMarker[] NO_MARKERS = new IMarker[0];

    /**
     * Whether to revert vs. reset the workspace
     */
    private boolean fRevert = false;

    /**
     * The default path to be used to revert the workspace to (if revert is
     * enabled)
     */
    private IPath fRevertSourcePath = null;

    /**
     * Modified files for each build so that we can undo the changes
     * incrementally rather than recreating the workspace for each test.
     */
    private List<IPath> fAdded = new ArrayList<IPath>();
    private List<IPath> fChanged = new ArrayList<IPath>();
    private List<IPath> fRemoved = new ArrayList<IPath>();

    @Override
    public IPath addProject(String projectName, String compliance) throws UnsupportedOperationException {
        IJavaProject javaProject = createProject(projectName);
        IProject project = javaProject.getProject();
        if (compliance != null) {
            setProjectCompliance(javaProject, compliance);
        }
        return project != null ? project.getFullPath() : Path.EMPTY;
    }

    /**
     * Sets the given compliance on the given project.
     * 
     * @param project
     * @param compliance
     */
    public void setProjectCompliance(IJavaProject project, String compliance) {
        int requiredComplianceFlag = 0;
        String compilerVersion = null;
        if (JavaCore.VERSION_1_4.equals(compliance)) {
            requiredComplianceFlag = AbstractCompilerTest.F_1_4;
            compilerVersion = JavaCore.VERSION_1_4;
        } else if (JavaCore.VERSION_1_5.equals(compliance)) {
            requiredComplianceFlag = AbstractCompilerTest.F_1_5;
            compilerVersion = JavaCore.VERSION_1_5;
        } else if (JavaCore.VERSION_1_6.equals(compliance)) {
            requiredComplianceFlag = AbstractCompilerTest.F_1_6;
            compilerVersion = JavaCore.VERSION_1_6;
        } else if (JavaCore.VERSION_1_7.equals(compliance)) {
            requiredComplianceFlag = AbstractCompilerTest.F_1_7;
            compilerVersion = JavaCore.VERSION_1_7;
        } else if (JavaCore.VERSION_1_8.equals(compliance)) {
            requiredComplianceFlag = AbstractCompilerTest.F_1_8;
            compilerVersion = JavaCore.VERSION_1_8;
        } else if (!JavaCore.VERSION_1_4.equals(compliance) && !JavaCore.VERSION_1_3.equals(compliance)) {
            throw new UnsupportedOperationException(
                    "Test framework doesn't support compliance level: " + compliance); //$NON-NLS-1$
        }
        if (requiredComplianceFlag != 0) {
            if ((AbstractCompilerTest.getPossibleComplianceLevels() & requiredComplianceFlag) == 0) {
                throw new RuntimeException("This test requires a " + compliance + " JRE"); //$NON-NLS-1$ //$NON-NLS-2$
            }
            HashMap<String, String> options = new HashMap<String, String>();
            options.put(JavaCore.COMPILER_COMPLIANCE, compilerVersion);
            options.put(JavaCore.COMPILER_SOURCE, compilerVersion);
            options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, compilerVersion);
            project.setOptions(options);
        }
    }

    /**
     * Creates a new plug-in project with the given name. If a project with the
     * same name already exists in the testing workspace it will be deleted and
     * new project created.
     * 
     * @param projectName
     * @return the newly created {@link IJavaProject} or <code>null</code> if
     *         there is an exception creating the project
     */
    protected IJavaProject createProject(String projectName) {
        IJavaProject jproject = null;
        try {
            IProject project = getWorkspace().getRoot().getProject(projectName);
            if (project.exists()) {
                project.delete(true, new NullProgressMonitor());
            }
            jproject = ProjectUtils.createPluginProject(projectName,
                    new String[] { PDE.PLUGIN_NATURE, ApiPlugin.NATURE_ID });
            addProject(jproject.getProject());
        } catch (CoreException ce) {
            ApiPlugin.log(ce);
            ce.printStackTrace();
        }
        return jproject;
    }

    /**
     * Performs a clean build on the project using the builder with the given
     * builder id
     * 
     * @param project
     * @param builderid
     */
    public void cleanBuild(IProject project, String builderid) {
        try {
            getProject(project.getName()).build(IncrementalProjectBuilder.CLEAN_BUILD, builderid, null, null);
        } catch (CoreException e) {
        }
    }

    /**
     * Incrementally builds the given project using the builder with the given
     * builder id
     * 
     * @param project
     * @param builderid
     */
    public void incrementalBuild(IProject project, String builderid) {
        try {
            getProject(project.getName()).build(IncrementalProjectBuilder.INCREMENTAL_BUILD, builderid, null, null);
        } catch (CoreException e) {
        }
    }

    /**
     * Performs a full build on the given project using the builder with the
     * given builder id
     * 
     * @param project
     * @param builderid
     */
    public void fullBuild(IProject project, String builderid) {
        try {
            getProject(project.getName()).build(IncrementalProjectBuilder.FULL_BUILD, builderid, null, null);
        } catch (CoreException e) {
        }
    }

    /**
     * returns all of the usage markers for the specified resource and its
     * children
     * 
     * @param resource
     * @return all API usage problem markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#API_USAGE_PROBLEM_MARKER}
     */
    protected IMarker[] getAllUsageMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.API_USAGE_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
    }

    /**
     * returns all of the usage markers for the specified resource and its
     * children
     * 
     * @param resource
     * @return all JDT problem markers that are on the resource backing the
     *         given path
     * @throws CoreException
     */
    public IMarker[] getAllJDTMarkers(IPath path) throws CoreException {
        return getAllJDTMarkers(getResource(path));
    }

    /**
     * returns all of the usage markers for the specified resource and its
     * children
     * 
     * @param resource
     * @return all JDT problem markers on the given {@link IResource}
     * @throws CoreException
     */
    protected IMarker[] getAllJDTMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        IMarker[] javaModelMarkers = resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
        IMarker[] buildpathMarkers = resource.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
        int javaModelMarkersLength = javaModelMarkers.length;
        int buildpathMarkersLength = buildpathMarkers.length;
        if (javaModelMarkersLength == 0) {
            return buildpathMarkers;
        } else if (buildpathMarkersLength == 0) {
            return javaModelMarkers;
        }
        IMarker[] allMarkers = new IMarker[javaModelMarkersLength + buildpathMarkersLength];
        System.arraycopy(javaModelMarkers, 0, allMarkers, 0, javaModelMarkersLength);
        System.arraycopy(buildpathMarkers, 0, allMarkers, javaModelMarkersLength, buildpathMarkersLength);
        return allMarkers;
    }

    /**
     * Returns all of the unsupported Javadoc tag markers on the specified
     * resource and all of its children.
     * 
     * @param resource
     * @return all unsupported tag problem markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#UNSUPPORTED_TAG_PROBLEM_MARKER}
     */
    protected IMarker[] getAllUnsupportedTagMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.UNSUPPORTED_TAG_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the unsupported annotation markers on the given resource
     * and all of its children
     * 
     * @param resource
     * @return all unsupported annotation markers
     * @throws CoreException
     * @since 1.0.400
     */
    protected IMarker[] getAllUnsupportedAnnotationMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.UNSUPPORTED_ANNOTATION_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the compatibility markers on the given resource and its
     * children
     * 
     * @param resource
     * @return all compatibility problem markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#COMPATIBILITY_PROBLEM_MARKER}
     */
    protected IMarker[] getAllCompatibilityMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the API profile markers on the given resource and its
     * children
     * 
     * @param resource
     * @return all API baseline problem markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#DEFAULT_API_BASELINE_PROBLEM_MARKER}
     */
    protected IMarker[] getAllApiBaselineMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.DEFAULT_API_BASELINE_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the since tag markers on the given resource and its
     * children
     * 
     * @param resource
     * @return all since tag problem markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#SINCE_TAGS_PROBLEM_MARKER}
     */
    protected IMarker[] getAllSinceTagMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.SINCE_TAGS_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the version markers on the given resource and its children
     * 
     * @param resource
     * @return all version problem markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#VERSION_NUMBERING_PROBLEM_MARKER}
     */
    protected IMarker[] getAllVersionMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.VERSION_NUMBERING_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the unused API problem filters markers on the given
     * resource to infinite depth
     * 
     * @param resource
     * @return all unused problem filter markers
     * @throws CoreException
     * 
     * @see {@link IApiMarkerConstants#UNUSED_FILTER_PROBLEM_MARKER}
     */
    protected IMarker[] getAllUnusedApiProblemFilterMarkers(IResource resource) throws CoreException {
        if (resource == null) {
            return NO_MARKERS;
        }
        if (!resource.isAccessible()) {
            return NO_MARKERS;
        }
        return resource.findMarkers(IApiMarkerConstants.UNUSED_FILTER_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);
    }

    /**
     * Returns all of the markers from the testing workspace
     * 
     * @return all {@link IMarker}s currently set in the workspace
     */
    public IMarker[] getMarkers() {
        return getMarkersFor(getWorkspaceRootPath());
    }

    /**
     * Returns the collection of API problem markers for the given element
     * 
     * @param root
     * @return the array of {@link IMarker}s found on the resource that
     *         corresponds to the given path
     */
    public IMarker[] getMarkersFor(IPath root) {
        return getMarkersFor(root, null);
    }

    /**
     * Return all problems with the specified element.
     * 
     * @param path
     * @param additionalMarkerType
     * @return the array of {@link IMarker}s found on the resource that
     *         corresponds to the given path
     */
    public IMarker[] getMarkersFor(IPath path, String additionalMarkerType) {
        IResource resource = getResource(path);
        try {
            List<Object> problems = new ArrayList<Object>();
            addToList(problems, getAllUsageMarkers(resource));
            addToList(problems, getAllCompatibilityMarkers(resource));
            addToList(problems, getAllApiBaselineMarkers(resource));
            addToList(problems, getAllSinceTagMarkers(resource));
            addToList(problems, getAllVersionMarkers(resource));
            addToList(problems, getAllUnsupportedTagMarkers(resource));
            addToList(problems, getAllUnsupportedAnnotationMarkers(resource));
            addToList(problems, getAllUnusedApiProblemFilterMarkers(resource));

            // additional markers
            if (additionalMarkerType != null) {
                problems.addAll(
                        Arrays.asList(resource.findMarkers(additionalMarkerType, true, IResource.DEPTH_INFINITE)));
            }
            return problems.toArray(new IMarker[problems.size()]);
        } catch (CoreException e) {
            // ignore
        }
        return new IMarker[0];
    }

    /**
     * Looks up the {@link IResource} in the workspace from the given path
     * 
     * @param path
     * @return the {@link IResource} handle for the given path
     */
    public IResource getResource(IPath path) {
        IResource resource;
        if (path.equals(getWorkspaceRootPath())) {
            resource = getWorkspace().getRoot();
        } else {
            IProject p = getProject(path);
            if (p != null && path.equals(p.getFullPath())) {
                resource = getProject(path.lastSegment());
            } else if (path.getFileExtension() == null) {
                resource = getWorkspace().getRoot().getFolder(path);
            } else {
                resource = getWorkspace().getRoot().getFile(path);
            }
        }
        return resource;
    }

    /**
     * Adds the array of objects to the given list
     * 
     * @param list
     * @param objects
     */
    private void addToList(List<Object> list, Object[] objects) {
        if (list == null || objects == null) {
            return;
        }
        if (objects.length == 0) {
            return;
        }
        for (int i = 0; i < objects.length; i++) {
            list.add(objects[i]);
        }
    }

    @Override
    public ApiProblem[] getProblems() {
        return (ApiProblem[]) super.getProblems();
    }

    /**
     * Returns the current workspace {@link IApiProfile}
     * 
     * @return the workspace baseline
     */
    protected IApiBaseline getWorkspaceProfile() {
        return ApiPlugin.getDefault().getApiBaselineManager().getWorkspaceBaseline();
    }

    @Override
    public ApiProblem[] getProblemsFor(IPath path, String additionalMarkerType) {
        IMarker[] markers = getMarkersFor(path, additionalMarkerType);
        ArrayList<ApiProblem> problems = new ArrayList<ApiProblem>();
        for (int i = 0; i < markers.length; i++) {
            problems.add(new ApiProblem(markers[i]));
        }
        return problems.toArray(new ApiProblem[problems.size()]);
    }

    @Override
    public void removeProject(IPath projectPath) {
        IJavaProject project = getJavaProject(projectPath);
        if (project != null) {
            try {
                project.getProject().delete(true, new NullProgressMonitor());
            } catch (CoreException ce) {

            }
        }
    }

    @Override
    public void resetWorkspace() {
        try {
            if (fRevert) {
                try {
                    revertWorkspace();
                } catch (Exception e) {
                    // in case we have an exception reverting a file, just toast
                    // it all
                    deleteWorkspace();
                }
            } else {
                deleteWorkspace();
            }
        } catch (Exception e) {
            // dump the trace
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=275005
            e.printStackTrace();
        } finally {
            // clear all changes
            fAdded.clear();
            fChanged.clear();
            fRemoved.clear();
        }
    }

    /**
     * Completely deletes the workspace
     * 
     * @since 1.1
     */
    void deleteWorkspace() {
        super.resetWorkspace();
        // clean up any left over projects from other tests
        IProject[] projects = getWorkspace().getRoot().getProjects();
        for (int i = 0; i < projects.length; i++) {
            try {
                projects[i].delete(true, new NullProgressMonitor());
            } catch (CoreException ce) {
                // help with debugging
                ce.printStackTrace();
            }
        }
    }

    /**
     * Sets the default revert source path to the given path.
     * 
     * @param path
     */
    public void setRevertSourcePath(IPath path) {
        fRevertSourcePath = path;
    }

    /**
     * @return the currently set source path to use when reverting changes to
     *         the workspace.
     */
    public IPath getRevertSourcePath() {
        return fRevertSourcePath;
    }

    /**
     * Reverts changes in the workspace - added, removed, changed files
     * 
     * @throws Exception if something happens trying to revert the workspace
     *             contents
     */
    public void revertWorkspace() throws Exception {
        // remove each added file
        Iterator<IPath> iterator = fAdded.iterator();
        while (iterator.hasNext()) {
            IPath path = iterator.next();
            deleteWorkspaceFile(path);
        }

        // revert each changed file
        iterator = fChanged.iterator();
        IPath revert = getRevertSourcePath();
        if (revert != null) {
            IPath path = null;
            while (iterator.hasNext()) {
                path = iterator.next();
                updateWorkspaceFile(path, TestSuiteHelper.getPluginDirectoryPath()
                        .append(ApiBuilderTest.TEST_SOURCE_ROOT).append(getRevertSourcePath()).append(path));
            }

            // replace each deleted file
            iterator = fRemoved.iterator();
            while (iterator.hasNext()) {
                path = iterator.next();
                createWorkspaceFile(path, TestSuiteHelper.getPluginDirectoryPath()
                        .append(ApiBuilderTest.TEST_SOURCE_ROOT).append(getRevertSourcePath()).append(path));
            }
        }
    }

    /**
     * Deletes the workspace file at the specified location (full path).
     * 
     * @param workspaceLocation
     * @throws Exception
     */
    private void deleteWorkspaceFile(IPath workspaceLocation) throws Exception {
        IFile file = getWorkspace().getRoot().getFile(workspaceLocation);
        try {
            file.delete(true, null);
        } catch (CoreException e) {
            // try to bring the resource in to sync an re-delete
            file.refreshLocal(IResource.DEPTH_ONE, null);
            file.delete(true, null);
        }
    }

    /**
     * Updates the contents of a workspace file at the specified location (full
     * path), with the contents of a local file at the given replacement
     * location (absolute path).
     * 
     * @param workspaceLocation
     * @param replacementLocation
     * @throws Exception
     */
    private void updateWorkspaceFile(IPath workspaceLocation, IPath replacementLocation) throws Exception {
        IFile file = getWorkspace().getRoot().getFile(workspaceLocation);
        File replacement = replacementLocation.toFile();
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(replacement);
            file.setContents(stream, false, true, null);
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }

    /**
     * Updates the contents of a workspace file at the specified location (full
     * path), with the contents of a local file at the given replacement
     * location (absolute path).
     * 
     * @param workspaceLocation
     * @param replacementLocation
     * @throws Exception
     */
    private void createWorkspaceFile(IPath workspaceLocation, IPath replacementLocation) throws Exception {
        IFile file = getWorkspace().getRoot().getFile(workspaceLocation);
        File replacement = replacementLocation.toFile();
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(replacement);
            file.create(stream, false, null);
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }

    /**
     * Notes a file was added during the test, to be undone
     * 
     * @param path
     */
    public void added(IPath path) {
        fAdded.add(path);
    }

    public void changed(IPath path) {
        fChanged.add(path);
    }

    public void removed(IPath path) {
        fRemoved.add(path);
    }

    @Override
    public IPath addFile(IPath root, String fileName, String contents) {
        IPath path = root.append(fileName);
        IFile file = getWorkspace().getRoot().getFile(path);
        if (file.exists()) {
            changed(path);
        } else {
            added(path);
        }
        return super.addFile(root, fileName, contents);
    }

    /**
     * Returns the listing of projects in the order the workspace has computed
     * they should be built. This method calls out to
     * {@link org.eclipse.core.resources.IWorkspace#computeProjectOrder(IProject[])}
     * , which can slow down testing with successive calls.
     * 
     * @return a build-ordered listing of the workspace projects
     */
    public IProject[] getProjectBuildOrder() {
        return getWorkspace().computeProjectOrder(getWorkspace().getRoot().getProjects()).projects;
    }

    @Override
    public IPath addClass(IPath packagePath, String className, String contents) {
        IPath filePath = packagePath.append(className + ".java"); //$NON-NLS-1$
        if (getWorkspace().getRoot().getFile(filePath).exists()) {
            changed(filePath);
        } else {
            added(filePath);
        }
        return super.addClass(packagePath, className, contents);
    }

    /**
     * Sets whether to revert the workspace rather than reset.
     * 
     * @param revert
     */
    public void setRevert(boolean revert) {
        fRevert = revert;
    }
}