package org.absmodels.abs.plugin.actions;
import static org.absmodels.abs.plugin.util.Constants.ABSUNIT_TEST_ERROR;
import static org.absmodels.abs.plugin.util.Constants.ABSUNIT_TEST_OK;
import static org.absmodels.abs.plugin.util.Constants.ABSUNIT_TEST_USER_ABORT;
import static org.absmodels.abs.plugin.util.Constants.PLUGIN_ID;
import static org.absmodels.abs.plugin.util.UtilityFunctions.getAbsNature;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.absmodels.abs.plugin.builder.AbsNature;
import org.absmodels.abs.plugin.exceptions.ParseException;
import org.absmodels.abs.plugin.exceptions.TypeCheckerException;
import org.absmodels.abs.plugin.util.Constants;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
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.jobs.Job;
import abs.backend.tests.ABSTestRunnerGenerator;
import abs.backend.tests.ASTBasedABSTestRunnerGenerator;
import abs.common.WrongProgramArgumentException;
import abs.frontend.ast.Model;
import abs.frontend.delta.DeltaModellingException;
public abstract class ABSUnitTestExecutionJob extends Job {
private Process process;
private boolean abort;
private File destFile;
protected final IProject project;
protected final String productName;
protected ABSUnitTestExecutionJob(IProject project, String productName){
super("Executing ABSUnit tests");
this.project = project;
this.productName = productName;
setUser(true);
}
protected IStatus run(IProgressMonitor monitor) {
AbsNature nature = getAbsNature(project);
if(nature == null){
return new Status(IStatus.INFO, PLUGIN_ID, "Could not compile current selection. Project is not an ABS project.");
}
monitor.beginTask("ABSUnit Test Execution", 112);
//Parsing and Type Checking ABS model
monitor.subTask("Generating Test Runner");
try{
if(!abort) generateTestRunner(monitor,nature);
} catch(CoreException e1) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Fatal error while generating test runner", e1);
} catch (IOException e2) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Fatal error while generating test runner", e2);
} catch (ParseException e4) {
return new Status(IStatus.INFO, PLUGIN_ID, ABSUNIT_TEST_ERROR, "Could not generating test runnern. Code has parse errors.", e4);
} catch (TypeCheckerException e5) {
return new Status(IStatus.INFO, PLUGIN_ID, ABSUNIT_TEST_ERROR, "Could not generating test runner. Code has type errors.", e5);
}
monitor.worked(12);
try {
// make sure the generated testrunner file is parsed:
project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null);
} catch (CoreException e) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Fatal error while compiling tests", e);
}
monitor.subTask("Executing ABSUnit tests");
IStatus status = null;
try {
status = executeTest(monitor);
} catch (CoreException e) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Fatal error while executing tests", e);
}
if(abort){
monitor.setCanceled(true);
return new Status(IStatus.INFO, PLUGIN_ID, ABSUNIT_TEST_USER_ABORT, null, null);
}
return new Status(IStatus.OK, PLUGIN_ID, ABSUNIT_TEST_OK, status.getMessage(), null);
}
protected abstract IStatus executeTest(IProgressMonitor monitor) throws CoreException;
@Override
protected void canceling() {
abort = true;
if(process != null){
process.destroy();
}
super.cancel();
}
/**
* Generate an ABS file from an ABS project that can be used to execute unit tests
* @throws ParseException Is thrown, if the project which is compiled has parse errors
* @throws TypeCheckerException Is thrown, if the project which is compiled has type errors
* @throws DeltaModellingException
* @throws WrongProgramArgumentException
*/
private void generateTestRunner(IProgressMonitor monitor, AbsNature nature)
throws CoreException,
IOException,
ParseException,
TypeCheckerException {
PrintStream ps = null;
FileInputStream fis = null;
try{
String path = Constants.DEFAULT_MAVEN_TARGET_ABS_PATH; //find a way to change
IFolder folder = project.getFolder(path);
MaudeJob.prepareFolder(monitor, folder);
String fileName = "runner.abs";
final IFile wspaceFile = folder.getFile(fileName);
/* generateMaude only knows how to fill PrintStreams */
final File tmpFile = File.createTempFile(fileName,null);
ps = new PrintStream(tmpFile);
//Get model, check for errors and throw respective exception
Model model = nature.getCompleteModel();
if(model.hasParserErrors()){
throw new ParseException(model.getParserErrors());
}
if(model.hasTypeErrors()){
throw new TypeCheckerException(model.typeCheck());
}
String mb = abs.backend.tests.ABSTestRunnerGenerator.RUNNER_MAIN;
ABSTestRunnerGenerator gen = new ASTBasedABSTestRunnerGenerator(model);
gen.generateTestRunner(ps);
ps.close();
fis = new FileInputStream(tmpFile);
if (wspaceFile.exists())
wspaceFile.setContents(fis, true, false, monitor);
else
wspaceFile.create(fis, true, monitor);
fis.close();
tmpFile.delete();
destFile = new File(project.getLocation().append(path).toFile(),fileName);
} finally{
if (ps != null){
ps.flush();
ps.close();
}
if (fis != null) {
fis.close();
}
}
}
}