blob: d8759148208d4f8f68640925bf3f27cb89f47b20 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2019 Chalmers | University of Gothenburg, rt-labs and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Chalmers | University of Gothenburg and rt-labs - initial API and implementation and/or initial documentation
* Chalmers | University of Gothenburg - additional features, updated API
*******************************************************************************/
package org.eclipse.capra.testsuite;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.eclipse.capra.core.adapters.TraceMetaModelAdapter;
import org.eclipse.capra.core.adapters.TracePersistenceAdapter;
import org.eclipse.capra.core.helpers.ArtifactHelper;
import org.eclipse.capra.core.helpers.ExtensionPointHelper;
import org.eclipse.capra.ui.operations.CreateTraceOperation;
import org.eclipse.capra.ui.plantuml.ToggleTransitivityHandler;
import org.eclipse.capra.ui.views.SelectionView;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ISourceRoot;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.internal.core.Configuration;
import org.eclipse.cdt.managedbuilder.internal.core.ManagedProject;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
/**
* A helper class for writing JUnit tests for the Capra tool.
*/
@SuppressWarnings("restriction")
public class TestHelper {
private TestHelper() {
// Deliberately do nothing
}
/**
* ID of Capra custom marker for reporting a generic problem.
*/
public static final String CAPRA_PROBLEM_MARKER_ID = "org.eclipse.capra.ui.notification.capraProblemMarker";
/**
* Creates an empty project
*
* @param projectName the name of the project
* @throws CoreException
*/
public static IProject createSimpleProject(String projectName) throws CoreException {
IProject project = getProject(projectName);
IProgressMonitor progressMonitor = new NullProgressMonitor();
project.create(progressMonitor);
project.open(progressMonitor);
return project;
}
/**
* Creates a Java project and a Java class declaration inside it.
*
* @param projectName the name of the project
* @return the created Java class
* @throws CoreException
*/
public static IType createJavaProjectWithASingleJavaClass(String projectName) throws CoreException {
IProject project = getProject(projectName);
// Create project
IProgressMonitor progressMonitor = new NullProgressMonitor();
project.create(progressMonitor);
project.open(progressMonitor);
// Add Java nature
IProjectDescription description = project.getDescription();
description.setNatureIds(new String[] { JavaCore.NATURE_ID });
project.setDescription(description, null);
// Create as Java project and set up build path etc.
IJavaProject javaProject = JavaCore.create(project);
IFolder binFolder = project.getFolder("bin");
binFolder.create(false, true, null);
javaProject.setOutputLocation(binFolder.getFullPath(), null);
List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[entries.size()]), null);
// Create a src file
IFolder sourceFolder = project.getFolder("src");
sourceFolder.create(false, true, null);
IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(sourceFolder);
IClasspathEntry[] oldEntries = javaProject.getRawClasspath();
IClasspathEntry[] newEntries = new IClasspathEntry[oldEntries.length + 1];
System.arraycopy(oldEntries, 0, newEntries, 0, oldEntries.length);
newEntries[oldEntries.length] = JavaCore.newSourceEntry(root.getPath());
javaProject.setRawClasspath(newEntries, null);
IPackageFragment pack = javaProject.getPackageFragmentRoot(sourceFolder)
.createPackageFragment("org.eclipse.capra.test", false, null);
StringBuffer buffer = new StringBuffer();
buffer.append("package " + pack.getElementName() + ";\n");
buffer.append("\n");
buffer.append("public class TestClass { public void doNothing(){ } }");
ICompilationUnit icu = pack.createCompilationUnit("TestClass.java", buffer.toString(), false, null);
return icu.getType("TestClass");
}
/**
* Clears the active workspace by deleting all the contents.
*
* @throws CoreException
*/
public static void clearWorkspace() throws CoreException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
for (IProject p : root.getProjects()) {
p.delete(true, new NullProgressMonitor());
}
}
/**
* Checks if the project with the provided name exists.
*
* @param projectName the name of the project
* @return true if the project exists in the active workspace, false otherwise
*/
public static boolean projectExists(String projectName) {
return getProject(projectName).exists();
}
/**
* Returns a handle to the project resource with the given name.
*
* @param projectName the name of the project
* @return a handle to the project resource
*/
public static IProject getProject(String projectName) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
return root.getProject(projectName);
}
/**
* Creates an empty Ecore model.
*
* @param name the name of the model
* @return
*/
public static EPackage createEcoreModel(String name) {
EPackage p = EcoreFactory.eINSTANCE.createEPackage();
p.setName(name);
return p;
}
/**
* Creates an EClass entity in the provided model.
*
* @param p an Ecore model
* @param name the name of the created EClass entity
*/
public static void createEClassInEPackage(EPackage p, String name) {
EClass c = EcoreFactory.eINSTANCE.createEClass();
c.setName(name);
p.getEClassifiers().add(c);
}
/**
* Nests a new EPackage inside the provided EPackage.
*
* @param p a new EPackage
* @param name the name of the created EPackage
*/
public static void createEPackageInEPackage(EPackage p, String name) {
EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
pkg.setName(name);
p.getESubpackages().add(pkg);
}
/**
* Persists (saves) the provided Ecore model in the specified project.
*
* @param project a handle to the project in which the model is to be persisted
* @param pack the Ecore model to be persisted
* @throws IOException
*/
public static void save(IProject project, EPackage pack) throws IOException {
ResourceSet rs = new ResourceSetImpl();
URI path = URI.createFileURI(project.getLocation().toString() + "/" + pack.getName() + ".ecore");
Resource r = rs.createResource(path);
r.getContents().add(pack);
r.save(null);
}
/**
* Returns an Ecore model entity from the specified project.
*
* @param project the project containing the model
* @param p the name of the model
* @param rs the provided ResourceSet instance
* @return an Ecore model entity
* @throws IOException
*/
public static EPackage load(IProject project, String p, ResourceSet rs) throws IOException {
URI path = URI.createFileURI(project.getLocation().toString() + "/" + p);
return (EPackage) rs.getResource(path, true).getContents().get(0);
}
/**
* Creates a trace between the objects that are in the Selection view.
*
* @param traceType the type of the trace that is to connect the objects
*/
public static void createTraceForCurrentSelectionOfType(EClass traceType) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
CreateTraceOperation operation = new CreateTraceOperation("Create trace link",
SelectionView.getOpenedView().getSelection());
operation.createTrace(shell, (traceTypes, selection) -> {
if (traceTypes.contains(traceType)) {
return Optional.of(traceType);
} else {
return Optional.empty();
}
});
}
/**
* Checks if there is a trace between the provided Objects.
*
* @param a first EObject
* @param b second EObject
* @return true if a trace exists between the two objects, false otherwise
*/
public static boolean thereIsATraceBetween(Object firstObject, Object secondObject) {
TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().get();
TraceMetaModelAdapter traceAdapter = ExtensionPointHelper.getTraceMetamodelAdapter().get();
if (firstObject instanceof EObject && secondObject instanceof EObject) {
EObject traceModel = persistenceAdapter.getTraceModel(((EObject) firstObject).eResource().getResourceSet());
if (traceModel != null) {
return traceAdapter.isThereATraceBetween((EObject) firstObject, (EObject) secondObject, traceModel);
}
}
if (firstObject instanceof EObject && !(secondObject instanceof EObject)) {
ResourceSet resource = ((EObject) firstObject).eResource().getResourceSet();
ArtifactHelper artifactHelper = new ArtifactHelper(persistenceAdapter.getArtifactWrappers(resource));
EObject wrapper_b = artifactHelper.createWrapper(secondObject);
EObject traceModel = persistenceAdapter.getTraceModel(resource);
if (traceModel != null) {
return traceAdapter.isThereATraceBetween((EObject) firstObject, wrapper_b, traceModel);
}
}
if (!(firstObject instanceof EObject) && secondObject instanceof EObject) {
ResourceSet resource = ((EObject) secondObject).eResource().getResourceSet();
ArtifactHelper artifactHelper = new ArtifactHelper(persistenceAdapter.getArtifactWrappers(resource));
EObject wrapper_a = artifactHelper.createWrapper(firstObject);
EObject traceModel = persistenceAdapter.getTraceModel(resource);
if (traceModel != null) {
return traceAdapter.isThereATraceBetween(wrapper_a, (EObject) secondObject, traceModel);
}
}
if (!(firstObject instanceof EObject) && !(secondObject instanceof EObject)) {
ResourceSet resource = new ResourceSetImpl();
ArtifactHelper artifactHelper = new ArtifactHelper(persistenceAdapter.getArtifactWrappers(resource));
EObject wrapper_a = artifactHelper.createWrapper(firstObject);
EObject wrapper_b = artifactHelper.createWrapper(secondObject);
EObject traceModel = persistenceAdapter.getTraceModel(resource);
if (traceModel != null) {
return traceAdapter.isThereATraceBetween(wrapper_a, wrapper_b, traceModel);
}
}
return false;
}
/**
* Creates an empty C or C++ project.
*
* @param projectName the name of the project to be created
* @return a handle to the created project
* @throws CoreException
* @throws BuildException
*/
public static ICProject createCDTProject(String projectName) throws CoreException, BuildException {
IProject project = getProject(projectName);
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProjectDescription description = workspace.newProjectDescription(projectName);
project = CCorePlugin.getDefault().createCDTProject(description, project, new NullProgressMonitor());
// Create build info and managed project
ICProjectDescription cProjectDescription = CoreModel.getDefault().createProjectDescription(project, false);
ManagedBuildManager.createBuildInfo(project);
Configuration config = new Configuration(new ManagedProject(cProjectDescription), null, "myId", "myName");
config.getEditableBuilder().setManagedBuildOn(false);
cProjectDescription.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID,
config.getConfigurationData());
CoreModel.getDefault().setProjectDescription(project, cProjectDescription);
CProjectNature.addCNature(project, new NullProgressMonitor());
return CoreModel.getDefault().create(project);
}
/**
* Creates a C source file in the provided C project.
*
* @param fileName the name of the C source file to be created in the project
* @param cProject the project in which the file is to be created
* @return the created TranslationUnit
* @throws CoreException
*/
public static ITranslationUnit createCSourceFileInProject(String fileName, ICProject cProject)
throws CoreException {
StringBuffer buffer = new StringBuffer();
buffer.append("#include <stdio.h>\n");
buffer.append("\n");
buffer.append("int main() {\n");
buffer.append("\tprintf(\"Hello, World!\");\n");
buffer.append("\treturn 0;\n");
buffer.append("}\n");
IFile cSourceFile = cProject.getProject().getFile(fileName);
cSourceFile.create(new ByteArrayInputStream(buffer.toString().getBytes()), true, new NullProgressMonitor());
return ((ISourceRoot) (cProject.getChildren()[0])).getTranslationUnits()[0];
}
/**
* Creates an empty file in the project with the provided name.
*
* @param fileName the name of the created file
* @param projectName the name of the project in which the file is to be created
* @return a handle to the created file
* @throws CoreException
*/
public static IFile createEmptyFileInProject(String fileName, String projectName) throws CoreException {
IProject project = getProject(projectName);
IFile f = project.getFile(fileName);
f.create(new ByteArrayInputStream("hello world!".getBytes()), true, new NullProgressMonitor());
return f;
}
/**
* Resets the selection view by emptying it.
*/
public static void resetSelectionView() {
SelectionView.getOpenedView().clearSelection();
ToggleTransitivityHandler.setTraceViewTransitive(true);
assertTrue(SelectionView.getOpenedView().getSelection().isEmpty());
}
}