package org.overture.vdm2jml.tests.exec; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.overture.codegen.tests.exec.util.ProcessResult; import org.overture.codegen.tests.util.JavaToolsUtils; import org.overture.codegen.utils.GeneralUtils; import org.overture.codegen.vdm2java.IJavaConstants; import org.overture.codegen.vdm2java.JavaCodeGenUtil; import org.overture.test.framework.Properties; import org.overture.vdm2jml.tests.AnnotationTestsBase; import org.overture.vdm2jml.tests.OpenJmlValidationBase; import org.overture.vdm2jml.tests.util.IOpenJmlConsts; public abstract class JmlExecTestBase extends OpenJmlValidationBase { public static final String TEST_RES_DYNAMIC_ANALYSIS_ROOT = AnnotationTestsBase.TEST_RESOURCES_ROOT + "dynamic_analysis" + File.separatorChar; public static final String MAIN_CLASS_NAME = "Main"; public static final String MAIN_CLASS_RES = "exec_entry_point"; public static final String RESULT_FILE_EXT = ".result"; public static final String DEFAULT_JAVA_ROOT_PACKAGE = "project"; protected boolean isTypeChecked; public JmlExecTestBase(File inputFile) { super(inputFile); this.isTypeChecked = false; } @Before public void assumeTools() { Assume.assumeTrue(String.format("Execution test will only run if the " + "property '%s' is passed", EXEC_PROPERTY), System.getProperty(EXEC_PROPERTY) != null); assumeOpenJml(); assumeJmlRuntime(); } @Test public void execJml() { checkIfSkipped(inputFile.getName()); try { configureResultGeneration(); compileJmlJava(); String actualRes = processResultStr(execJmlJava().toString()); if (Properties.recordTestResults) { storeResult(actualRes.toString()); } else { try { checkOpenJmlOutput(actualRes); } catch (IOException e) { e.printStackTrace(); Assert.assertTrue("Could not read the expected result from the result file: " + e.getMessage(), false); } } } finally { unconfigureResultGeneration(); } } private void checkIfSkipped(String testName) { Assume.assumeFalse("OpenJML cannot compile this test - OpenJML has a bug", getSkippedTestsNames().contains(testName)); } protected List<String> getSkippedTestsNames() { return new LinkedList<>(); } protected void checkOpenJmlOutput(String actualRes) throws IOException { String expectedRes = GeneralUtils.readFromFile(getResultFile()).trim(); Assert.assertEquals("Expected result and actual result are different", expectedRes, actualRes); } protected void storeResult(String resultStr) { storeJmlOutput(resultStr); } protected void storeJmlOutput(String resultStr) { resultStr = processResultStr(resultStr); File resultFile = getResultFile(); PrintWriter printWriter = null; try { FileOutputStream fileOutStream = new FileOutputStream(resultFile, false); OutputStreamWriter outStream = new OutputStreamWriter(fileOutStream, "UTF-8"); printWriter = new PrintWriter(outStream); printWriter.write(resultStr); printWriter.flush(); } catch (UnsupportedEncodingException | FileNotFoundException e) { e.printStackTrace(); Assert.assertTrue("Could not store result: " + e.getMessage(), false); } finally { if (printWriter != null) { printWriter.close(); } } } protected String processResultStr(String resultStr) { resultStr = resultStr.trim(); resultStr = resultStr.replaceAll("\r", ""); String[] lines = resultStr.split("\n"); StringBuilder sb = new StringBuilder(); Pattern pattern = Pattern.compile("(?m)^.*?[^a-zA-Z]([a-zA-Z]+\\.java:[0-9]+:.*?)(:|$)"); for (String line : lines) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { sb.append(matcher.group(1)); } else { sb.append(line); } sb.append('\n'); } return sb.toString().trim(); } protected void createExecEntryPoint() { File mainClassRes = new File(AnnotationTestsBase.TEST_RESOURCES_ROOT, MAIN_CLASS_RES); File mainClassJavaFile = new File(genJavaFolder, MAIN_CLASS_NAME + IJavaConstants.JAVA_FILE_EXTENSION); try { // Create a Main.java (a class with a main method) FileUtils.copyFile(mainClassRes, mainClassJavaFile); } catch (IOException e) { Assume.assumeTrue("Problems generating execution entry point", false); } } protected void compileJmlJava() { ProcessResult processResult = runOpenJmlProcess(); assertNoProcessErrors(processResult); isTypeChecked = true; } protected StringBuilder execJmlJava() { ProcessResult processResult = runOpenJmlProcess(); assertNoProcessErrors(processResult); return processResult.getOutput(); } protected static String[] getTypeCheckArgs(File genJavaFolder, File cgRuntime, File vdm2jmlRuntime, File openJml) { // Compiles files with runtime assertions in preparation to execution // of the JML annotated Java code // java // -jar // $OPENJML/openjml.jar // -classpath // codegen-runtime.jar // -rac // -racCompileToJavaAssert (currently disabled) // -no-purityCheck // <javafiles> String[] openJmlConfig = new String[] { JavaToolsUtils.JAVA, JavaToolsUtils.JAR_ARG, openJml.getAbsolutePath(), IOpenJmlConsts.CP_ARG, "\"" + cgRuntime.getAbsolutePath() + File.pathSeparator + vdm2jmlRuntime.getAbsolutePath() + "\"", IOpenJmlConsts.RAC_ARG, /* IOpenJmlConsts.RAC_TO_ASSERT_ARG, */ IOpenJmlConsts.NO_PURITY_CHECKS_ARG }; String[] javaFiles = JavaCodeGenUtil.findJavaFilePathsRec(genJavaFolder); return GeneralUtils.concat(openJmlConfig, javaFiles); } protected static String[] getExecArgs(File genJavaFolder, File cgRuntime, File vdm2jmlRuntime, File openJml, File jmlRuntime) { // Executes the OpenJML runtime assertion checker // java // -classpath // ".:codegen-runtime.jar:jmlruntime.jar" // -ea (currently disabled) // Main // Note that use of File.pathSeparatorChar makes it a platform dependent construction // of the classpath String runtimes = jmlRuntime.getAbsolutePath() + File.pathSeparatorChar + openJml.getAbsolutePath() + File.pathSeparatorChar + genJavaFolder.getAbsolutePath() + File.pathSeparatorChar + cgRuntime.getAbsolutePath() + File.pathSeparatorChar + vdm2jmlRuntime.getAbsolutePath(); String[] args = new String[] { JavaToolsUtils.JAVA, JavaToolsUtils.CP_ARG, runtimes, /* JavaToolsUtils.ENABLE_ASSERTIONS_ARG, */ MAIN_CLASS_NAME }; return args; } protected File getResultFile() { File resultFile = new File(inputFile.getAbsolutePath() + RESULT_FILE_EXT); if (!resultFile.exists()) { resultFile.getParentFile().mkdirs(); try { resultFile.createNewFile(); } catch (IOException e) { Assert.assertTrue("Problems creating result file: " + e.getMessage(), false); e.printStackTrace(); return null; } } return resultFile; } @Override public void beforeRunningOpenJmlProcess() { if (!isTypeChecked) { clearCodeFolder(); createExecEntryPoint(); generateJavaJml(); } } @Override public String[] getProcessArgs() { if (!isTypeChecked) { return getTypeCheckArgs(genJavaFolder, cgRuntime, vdm2jmlRuntime, openJml); } else { return getExecArgs(genJavaFolder, cgRuntime, vdm2jmlRuntime, openJml, jmlRuntime); } } }