org.evosuite.junit.TestSuiteWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.evosuite.junit.TestSuiteWriter.java

Source

/**
 * Copyright (C) 2011,2012 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 * 
 * This file is part of EvoSuite.
 * 
 * EvoSuite is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 * 
 * EvoSuite 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 Public License for more details.
 * 
 * You should have received a copy of the GNU Public License along with
 * EvoSuite. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * 
 */
package org.evosuite.junit;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.DebugGraphics;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.evosuite.Properties;
import org.evosuite.Properties.AssertionStrategy;
import org.evosuite.Properties.Criterion;
import org.evosuite.Properties.OutputFormat;
import org.evosuite.Properties.OutputGranularity;
import org.evosuite.coverage.dataflow.DefUseCoverageTestFitness;
import org.evosuite.instrumentation.BytecodeInstrumentation;
import org.evosuite.reset.ClassResetter;
import org.evosuite.reset.ResetManager;
import org.evosuite.result.TestGenerationResultBuilder;
import org.evosuite.sandbox.Sandbox;
import org.evosuite.testcase.CodeUnderTestException;
import org.evosuite.testcase.ExecutionResult;
import org.evosuite.testcase.StatementInterface;
import org.evosuite.testcase.StructuredTestCase;
import org.evosuite.testcase.StructuredTestCodeVisitor;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.TestCaseExecutor;
import org.evosuite.testcase.TestCodeVisitor;
import org.evosuite.testcase.TestFitnessFunction;
import org.evosuite.utils.SystemInUtil;
import org.evosuite.utils.Utils;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * TestSuiteWriter class.
 * </p>
 * 
 * @author Gordon Fraser
 */
public class TestSuiteWriter implements Opcodes {

    /** Constant <code>logger</code> */
    protected final static Logger logger = LoggerFactory.getLogger(TestSuiteWriter.class);

    protected TestCaseExecutor executor = TestCaseExecutor.getInstance();

    protected List<TestCase> testCases = new ArrayList<TestCase>();

    protected Map<Integer, String> testComment = new HashMap<Integer, String>();

    private final UnitTestAdapter adapter = TestSuiteWriter.getAdapter();

    private TestCodeVisitor visitor = Properties.ASSERTION_STRATEGY == AssertionStrategy.STRUCTURED
            ? visitor = new StructuredTestCodeVisitor()
            : new TestCodeVisitor();

    private static final String METHOD_SPACE = "  ";
    private static final String BLOCK_SPACE = "    ";
    private static final String INNER_BLOCK_SPACE = "      ";
    private static final String INNER_INNER_BLOCK_SPACE = "        ";
    private static final String INNER_INNER_INNER_BLOCK_SPACE = "          ";

    private final String EXECUTOR_SERVICE = "executor";

    private final String DEFAULT_PROPERTIES = "defaultProperties";

    /**
     * FIXME: this filter assumes "Test" as prefix, but would be better to have
     * it as postfix (and as a variable)
     * 
     */
    class TestFilter implements IOFileFilter {
        @Override
        public boolean accept(File f, String s) {
            return s.toLowerCase().endsWith(".java") && s.startsWith("Test");
        }

        /*
         * (non-Javadoc)
         * 
         * @see
         * org.apache.commons.io.filefilter.IOFileFilter#accept(java.io.File)
         */
        @Override
        public boolean accept(File file) {
            return file.getName().toLowerCase().endsWith(".java") && file.getName().startsWith("Test");
        }
    }

    /**
     * Check if there are test cases
     * 
     * @return True if there are no test cases
     */
    public boolean isEmpty() {
        return testCases.isEmpty();
    }

    /**
     * <p>
     * size
     * </p>
     * 
     * @return a int.
     */
    public int size() {
        return testCases.size();
    }

    /**
     * Check if test suite has a test case that is a prefix of test.
     * 
     * @param test
     *            a {@link org.evosuite.testcase.TestCase} object.
     * @return a boolean.
     */
    public boolean hasPrefix(TestCase test) {
        for (TestCase t : testCases) {
            if (t.isPrefix(test))
                return true;
        }
        return false;
    }

    /**
     * Add test to suite. If the test is a prefix of an existing test, just keep
     * existing test. If an existing test is a prefix of the test, replace the
     * existing test.
     * 
     * @param test
     *            a {@link org.evosuite.testcase.TestCase} object.
     * @return Index of the test case
     */
    public int insertTest(TestCase test) {
        if (Properties.CALL_PROBABILITY <= 0) {
            for (int i = 0; i < testCases.size(); i++) {
                if (test.isPrefix(testCases.get(i))) {
                    // It's shorter than an existing one
                    // test_cases.set(i, test);
                    logger.info("This is a prefix of an existing test");
                    testCases.get(i).addAssertions(test);
                    return i;
                } else {
                    // Already have that one...
                    if (testCases.get(i).isPrefix(test)) {
                        test.addAssertions(testCases.get(i));
                        testCases.set(i, test);
                        logger.info("We have a prefix of this one");
                        return i;
                    }
                }
            }
        }
        logger.info("Adding new test case:");
        if (logger.isDebugEnabled()) {
            logger.debug(test.toCode());
        }
        testCases.add(test);
        return testCases.size() - 1;
    }

    /**
     * <p>
     * insertTest
     * </p>
     * 
     * @param test
     *            a {@link org.evosuite.testcase.TestCase} object.
     * @param comment
     *            a {@link java.lang.String} object.
     * @return a int.
     */
    public int insertTest(TestCase test, String comment) {
        int id = insertTest(test);
        if (testComment.containsKey(id)) {
            if (!testComment.get(id).contains(comment))
                testComment.put(id, testComment.get(id) + "\n" + METHOD_SPACE + "//" + comment);
        } else
            testComment.put(id, comment);
        return id;
    }

    /**
     * <p>
     * insertTests
     * </p>
     * 
     * @param tests
     *            a {@link java.util.List} object.
     */
    public void insertTests(List<TestCase> tests) {
        for (TestCase test : tests)
            insertTest(test);
    }

    /**
     * <p>
     * insertTests
     * </p>
     * 
     * @param tests
     *            a {@link java.util.List} object.
     */
    public void insertAllTests(List<TestCase> tests) {
        testCases.addAll(tests);
    }

    /**
     * Get all test cases
     * 
     * @return a {@link java.util.List} object.
     */
    public List<TestCase> getTestCases() {
        return testCases;
    }

    /**
     * <p>
     * runTest
     * </p>
     * 
     * @param test
     *            a {@link org.evosuite.testcase.TestCase} object.
     * @return a {@link org.evosuite.testcase.ExecutionResult} object.
     */
    ExecutionResult runTest(TestCase test) {

        ExecutionResult result = new ExecutionResult(test, null);

        try {
            logger.debug("Executing test");
            result = executor.execute(test);
        } catch (Exception e) {
            throw new Error(e);
        }

        return result;
    }

    /**
     * Create subdirectory for package in test directory
     * 
     * @param directory
     *            a {@link java.lang.String} object.
     * @return a {@link java.lang.String} object.
     */
    protected String makeDirectory(String directory) {
        String dirname = directory + File.separator + Properties.CLASS_PREFIX.replace('.', File.separatorChar); // +"/GeneratedTests";
        File dir = new File(dirname);
        logger.debug("Target directory: {}", dirname);
        dir.mkdirs();
        return dirname;
    }

    /**
     * Create subdirectory for package in test directory
     * 
     * @param directory
     *            a {@link java.lang.String} object.
     * @return a {@link java.lang.String} object.
     */
    protected String mainDirectory(String directory) {
        String dirname = directory + File.separator + Properties.PROJECT_PREFIX.replace('.', File.separatorChar); // +"/GeneratedTests";
        File dir = new File(dirname);
        logger.debug("Target directory: {}", dirname);
        dir.mkdirs();
        return dirname;
    }

    protected static boolean hasAnySecurityException(List<ExecutionResult> results) {
        for (ExecutionResult result : results) {
            if (result.hasSecurityException()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Determine packages that need to be imported in the JUnit file
     * 
     * @param results
     *            a {@link java.util.List} object.
     * @return a {@link java.lang.String} object.
     */
    protected String getImports(List<ExecutionResult> results) {
        StringBuilder builder = new StringBuilder();
        Set<Class<?>> imports = new HashSet<Class<?>>();
        boolean wasSecurityException = hasAnySecurityException(results);

        for (ExecutionResult result : results) {
            result.test.accept(visitor);

            // TODO: This should be unnecessary 
            // Iterate over declared exceptions to make sure they are known to the visitor
            /*
            Set<Class<?>> exceptions = result.test.getDeclaredExceptions();
            if (!exceptions.isEmpty()) {
               for (Class<?> exception : exceptions) {
                  visitor.getClassName(exception);
               }
            }
             */

            // Also include thrown exceptions
            for (Throwable t : result.getAllThrownExceptions()) {
                visitor.getClassName(t.getClass());
            }

            imports.addAll(visitor.getImports());
        }

        if (Properties.RESET_STANDARD_STREAMS) {
            imports.add(PrintStream.class);
            imports.add(DebugGraphics.class);
        }

        Set<String> import_names = new HashSet<String>();
        for (Class<?> imp : imports) {
            while (imp.isArray())
                imp = imp.getComponentType();
            if (imp.isPrimitive())
                continue;
            if (imp.getName().startsWith("java.lang")) {
                String name = imp.getName().replace("java.lang.", "");
                if (!name.contains("."))
                    continue;
            }
            if (!imp.getName().contains("."))
                continue;
            // TODO: Check for anonymous type?
            if (imp.getName().contains("$"))
                //   import_names.add(imp.getName().substring(0, imp.getName().indexOf("$")));
                import_names.add(imp.getName().replace("$", "."));
            else
                import_names.add(imp.getName());
        }
        List<String> imports_sorted = new ArrayList<String>(import_names);

        // FIXME: I disagree - it should be covered by the below branches
        //we always need this one, due to for example logging setup

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS
                || wasSecurityException || SystemInUtil.getInstance().hasBeenUsed()) {
            imports_sorted.add(org.junit.BeforeClass.class.getCanonicalName());
            imports_sorted.add(org.junit.Before.class.getCanonicalName());
            imports_sorted.add(org.junit.After.class.getCanonicalName());
        }

        if (wasSecurityException || shouldResetProperties(results)) {
            imports_sorted.add(org.junit.AfterClass.class.getCanonicalName());
        }

        if (Properties.VIRTUAL_FS) {
            imports_sorted.add(org.evosuite.runtime.EvoSuiteFile.class.getCanonicalName());
        }

        if (wasSecurityException) {
            //Add import info for EvoSuite classes used in the generated test suite
            imports_sorted.add(Sandbox.class.getCanonicalName());
            // imports_sorted.add(Properties.class.getCanonicalName());
            imports_sorted.add(Properties.SandboxMode.class.getCanonicalName());
            imports_sorted.add(java.util.concurrent.ExecutorService.class.getCanonicalName());
            imports_sorted.add(java.util.concurrent.Executors.class.getCanonicalName());
            imports_sorted.add(java.util.concurrent.Future.class.getCanonicalName());
            imports_sorted.add(java.util.concurrent.TimeUnit.class.getCanonicalName());

        }

        Collections.sort(imports_sorted);
        for (String imp : imports_sorted) {
            builder.append("import ");
            builder.append(imp);
            builder.append(";\n");
        }
        builder.append("\n");
        return builder.toString();
    }

    /**
     * When writing out the JUnit test file, each test can have a text comment
     * 
     * @param num
     *            Index of test case
     * @return Comment for test case
     */
    protected String getInformation(int num) {

        if (testComment.containsKey(num)) {
            String comment = testComment.get(num);
            if (!comment.endsWith("\n"))
                comment = comment + "\n";
            return comment;
        }

        TestCase test = testCases.get(num);
        Set<TestFitnessFunction> coveredGoals = test.getCoveredGoals();

        StringBuilder builder = new StringBuilder();
        builder.append("Test case number: " + num);

        if (!coveredGoals.isEmpty()) {
            builder.append("\n  /*\n");
            builder.append("   * ");
            builder.append(coveredGoals.size() + " covered goal");
            if (coveredGoals.size() != 1)
                builder.append("s");
            builder.append(":");
            int nr = 1;
            for (TestFitnessFunction goal : coveredGoals) {
                builder.append("\n   * " + nr + " " + goal.toString());
                // TODO only for debugging purposes
                if (Properties.CRITERION == Criterion.DEFUSE && (goal instanceof DefUseCoverageTestFitness)) {
                    DefUseCoverageTestFitness duGoal = (DefUseCoverageTestFitness) goal;
                    if (duGoal.getCoveringTrace() != null) {
                        String traceInformation = duGoal.getCoveringTrace()
                                .toDefUseTraceInformation(duGoal.getGoalVariable(), duGoal.getCoveringObjectId());
                        traceInformation = traceInformation.replaceAll("\n", "");
                        builder.append("\n     * DUTrace: " + traceInformation);
                    }
                }
                nr++;
            }

            builder.append("\n   */\n");
        }

        return builder.toString();
    }

    private static UnitTestAdapter getAdapter() {
        if (Properties.TEST_FORMAT == OutputFormat.JUNIT3)
            return new JUnit3TestAdapter();
        else if (Properties.TEST_FORMAT == OutputFormat.JUNIT4)
            return new JUnit4TestAdapter();
        else
            throw new RuntimeException("Unknown output format: " + Properties.TEST_FORMAT);
    }

    /**
     * JUnit file header
     * 
     * @param name
     *            a {@link java.lang.String} object.
     * @param results
     *            a {@link java.util.List} object.
     * @return a {@link java.lang.String} object.
     */
    protected String getHeader(String name, List<ExecutionResult> results) {
        StringBuilder builder = new StringBuilder();
        builder.append("/*\n");
        builder.append(" * This file was automatically generated by EvoSuite\n");
        builder.append(" */\n\n");

        if (!Properties.CLASS_PREFIX.equals("")) {
            builder.append("package ");
            builder.append(Properties.CLASS_PREFIX);
            builder.append(";\n");
        }
        builder.append("\n");

        builder.append(adapter.getImports());
        builder.append(getImports(results));

        builder.append(adapter.getClassDefinition(name));
        builder.append(" {\n");
        return builder.toString();
    }

    /**
     * JUnit file footer
     * 
     * @return a {@link java.lang.String} object.
     */
    protected String getFooter() {
        return "}\n";
    }

    /**
     * Create JUnit file for given class name
     * 
     * @param name
     *            Name of the class file
     * @return String representation of JUnit test file
     */
    public String getUnitTest(String name) {
        List<ExecutionResult> results = new ArrayList<ExecutionResult>();

        for (int i = 0; i < testCases.size(); i++) {
            ExecutionResult result = runTest(testCases.get(i));
            results.add(result);
        }

        /*
         * if there was any security exception, then we need to scaffold the
         * test cases with a sandbox
         */
        boolean wasSecurityException = hasAnySecurityException(results);

        StringBuilder builder = new StringBuilder();

        builder.append(getHeader(name, results));
        builder.append(getBeforeAndAfterMethods(name, wasSecurityException, results));

        for (int i = 0; i < testCases.size(); i++) {
            builder.append(testToString(i, i, results.get(i)));
        }
        builder.append(getFooter());

        return builder.toString();
    }

    /**
     * Create JUnit file for given class name
     * 
     * @param name
     *            Name of the class file
     * @return String representation of JUnit test file
     * @param testId
     *            a int.
     */
    public String getUnitTest(String name, int testId) {
        List<ExecutionResult> results = new ArrayList<ExecutionResult>();
        ExecutionResult result = runTest(testCases.get(testId));
        results.add(result);
        boolean wasSecurityException = result.hasSecurityException();

        StringBuilder builder = new StringBuilder();

        builder.append(getHeader(name + "_" + testId, results));
        builder.append(getBeforeAndAfterMethods(name, wasSecurityException, results));
        builder.append(testToString(testId, testId, results.get(0)));
        builder.append(getFooter());

        return builder.toString();
    }

    /**
     * Get the code of methods for @BeforeClass, @Before, @AfterClass and
     * 
     * @After.
     * 
     *         <p>
     *         In those methods, the EvoSuite framework for running the
     *         generated test cases is handled (e.g., use of customized
     *         SecurityManager and runtime bytecode replacement)
     * 
     * @return
     */
    protected String getBeforeAndAfterMethods(String name, boolean wasSecurityException,
            List<ExecutionResult> results) {

        /*
         * Usually, we need support methods (ie @BeforeClass,@Before,@After and @AfterClass)
         * only if there was a security exception (and so we need EvoSuite security manager,
         * and test runs on separated thread) or if we are doing bytecode replacement (and
         * so we need to activate JavaAgent).
         * 
         * But there are cases that we might always want: eg, setup logging
         */

        StringBuilder bd = new StringBuilder("");
        bd.append("\n");

        /*
         * Because this method is perhaps called only once per SUT,
         * not much of the point to try to optimize it 
         */

        generateFields(bd, wasSecurityException, results);

        generateBeforeClass(bd, wasSecurityException);

        generateAfterClass(bd, wasSecurityException, results);

        generateBefore(bd, wasSecurityException, results);

        generateAfter(bd, wasSecurityException);

        generateSetSystemProperties(bd, results);

        if (Properties.RESET_STATIC_FIELDS) {
            generateInitializeClasses(name, bd);

            generateResetClasses(bd);
        }

        return bd.toString();
    }

    private void generateResetClasses(StringBuilder bd) {
        List<String> classesToReset = ResetManager.getInstance().getClassResetOrder();

        bd.append(METHOD_SPACE);
        bd.append("private static void resetClasses() {\n");

        bd.append(BLOCK_SPACE);
        bd.append("String[] classNames = new String[" + classesToReset.size() + "];\n");

        for (int i = 0; i < classesToReset.size(); i++) {
            String className = classesToReset.get(i);
            bd.append(BLOCK_SPACE);
            bd.append(String.format("classNames[%s] =\"%s\";\n", i, className));
        }

        bd.append(BLOCK_SPACE);
        bd.append("for (int i=0; i< classNames.length;i++) {\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("String classNameToReset = classNames[i];\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("try {" + "\n");

        bd.append(INNER_INNER_BLOCK_SPACE);
        bd.append(ClassResetter.class.getCanonicalName() + ".getInstance().reset(classNameToReset); \n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("} catch (Throwable t) {" + "\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("}\n");

        bd.append(BLOCK_SPACE);
        bd.append("}\n");

        bd.append(METHOD_SPACE);
        bd.append("}" + "\n");

    }

    private void generateInitializeClasses(String testClassName, StringBuilder bd) {

        List<String> classesToBeReset = ResetManager.getInstance().getClassResetOrder();
        bd.append(METHOD_SPACE);
        bd.append("private static void initializeClasses() {\n");

        bd.append(BLOCK_SPACE);
        bd.append("String[] classNames = new String[" + classesToBeReset.size() + "];\n");

        for (int i = 0; i < classesToBeReset.size(); i++) {
            String className = classesToBeReset.get(i);
            if (BytecodeInstrumentation.checkIfCanInstrument(className)) {
                bd.append(BLOCK_SPACE);
                bd.append(String.format("classNames[%s] =\"%s\";\n", i, className));
            }
        }

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.agent.InstrumentingAgent.activate(); \n");
        }

        bd.append(BLOCK_SPACE);
        bd.append("for (int i=0; i< classNames.length;i++) {\n");

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            bd.append(INNER_BLOCK_SPACE);
            bd.append("org.evosuite.runtime.Runtime.getInstance().resetRuntime(); \n");
        }

        bd.append(INNER_BLOCK_SPACE);
        bd.append("String classNameToLoad = classNames[i];\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("ClassLoader classLoader = " + testClassName + ".class.getClassLoader();\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("try {" + "\n");

        bd.append(INNER_INNER_BLOCK_SPACE);
        bd.append("Class.forName(classNameToLoad, true, classLoader);\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("} catch (ExceptionInInitializerError ex) {" + "\n");

        bd.append(INNER_INNER_BLOCK_SPACE);
        bd.append("java.lang.System.err.println(\"Could not initialize \" + classNameToLoad);\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("} catch (Throwable t) {" + "\n");

        bd.append(INNER_BLOCK_SPACE);
        bd.append("}\n");

        bd.append(BLOCK_SPACE);
        bd.append("}\n");

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.agent.InstrumentingAgent.deactivate(); \n");
        }

        bd.append(METHOD_SPACE);
        bd.append("}" + "\n");

    }

    private void generateAfter(StringBuilder bd, boolean wasSecurityException) {

        if (!Properties.RESET_STANDARD_STREAMS && !wasSecurityException && !Properties.REPLACE_CALLS
                && !Properties.VIRTUAL_FS && !Properties.RESET_STATIC_FIELDS) {
            return;
        }

        bd.append(METHOD_SPACE);
        bd.append("@After \n");
        bd.append(METHOD_SPACE);
        bd.append("public void doneWithTestCase(){ \n");

        if (Properties.RESET_STANDARD_STREAMS) {
            bd.append(BLOCK_SPACE);
            bd.append("java.lang.System.setErr(systemErr); \n");

            bd.append(BLOCK_SPACE);
            bd.append("java.lang.System.setOut(systemOut); \n");

            bd.append(BLOCK_SPACE);
            bd.append("DebugGraphics.setLogStream(logStream); \n");
        }

        if (wasSecurityException) {
            bd.append(BLOCK_SPACE);
            bd.append("Sandbox.doneWithExecutingSUTCode(); \n");
        }

        if (Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("resetClasses(); \n");
        }

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.agent.InstrumentingAgent.deactivate(); \n");
        }

        bd.append(METHOD_SPACE);
        bd.append("} \n");

        bd.append("\n");
    }

    private void generateBefore(StringBuilder bd, boolean wasSecurityException, List<ExecutionResult> results) {

        if (!Properties.RESET_STANDARD_STREAMS && !shouldResetProperties(results) && !wasSecurityException
                && !Properties.REPLACE_CALLS && !Properties.VIRTUAL_FS && !Properties.RESET_STATIC_FIELDS
                && !SystemInUtil.getInstance().hasBeenUsed()) {
            return;
        }

        bd.append(METHOD_SPACE);
        bd.append("@Before \n");
        bd.append(METHOD_SPACE);
        bd.append("public void initTestCase(){ \n");

        if (Properties.RESET_STANDARD_STREAMS) {
            bd.append(BLOCK_SPACE);
            bd.append("systemErr = java.lang.System.err;");
            bd.append(" \n");

            bd.append(BLOCK_SPACE);
            bd.append("systemOut = java.lang.System.out;");
            bd.append(" \n");

            bd.append(BLOCK_SPACE);
            bd.append("logStream = DebugGraphics.logStream();");
            bd.append(" \n");
        }

        if (shouldResetProperties(results)) {
            bd.append(BLOCK_SPACE);
            bd.append("setSystemProperties();");
            bd.append(" \n");
        }

        if (wasSecurityException) {
            bd.append(BLOCK_SPACE);
            bd.append("Sandbox.goingToExecuteSUTCode(); \n");
        }

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.runtime.Runtime.getInstance().resetRuntime(); \n");
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.agent.InstrumentingAgent.activate(); \n");
        }

        if (SystemInUtil.getInstance().hasBeenUsed()) {
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.utils.SystemInUtil.getInstance().initForTestCase(); \n");
        }

        bd.append(METHOD_SPACE);
        bd.append("} \n");

        bd.append("\n");
    }

    private boolean shouldResetProperties(List<ExecutionResult> results) {
        /*
         * Note: we need to reset the properties even if the SUT only read them. Reason is
         * that we are modifying them in the test case in the @Before method
         */
        Set<String> readProperties = null;
        if (Properties.REPLACE_CALLS) {
            readProperties = mergeProperties(results);
            if (readProperties.isEmpty()) {
                readProperties = null;
            }
        }

        boolean shouldResetProperties = Properties.REPLACE_CALLS
                && (wasAnyWrittenProperty(results) || readProperties != null);

        return shouldResetProperties;
    }

    private String getResetPropertiesCommand() {
        return "java.lang.System.setProperties((java.util.Properties)" + " " + DEFAULT_PROPERTIES + ".clone());";
    }

    private void generateAfterClass(StringBuilder bd, boolean wasSecurityException, List<ExecutionResult> results) {

        if (wasSecurityException || shouldResetProperties(results)) {
            bd.append(METHOD_SPACE);
            bd.append("@AfterClass \n");
            bd.append(METHOD_SPACE);
            bd.append("public static void clearEvoSuiteFramework(){ \n");

            if (wasSecurityException) {
                bd.append(BLOCK_SPACE);
                bd.append(EXECUTOR_SERVICE + ".shutdownNow(); \n");
                bd.append(BLOCK_SPACE);
                bd.append("Sandbox.resetDefaultSecurityManager(); \n");
            }

            if (shouldResetProperties(results)) {
                bd.append(BLOCK_SPACE);
                bd.append(getResetPropertiesCommand());
                bd.append(" \n");
            }

            bd.append(METHOD_SPACE);
            bd.append("} \n");

            bd.append("\n");
        }

    }

    private void generateSetSystemProperties(StringBuilder bd, List<ExecutionResult> results) {

        if (!Properties.REPLACE_CALLS) {
            return;
        }

        bd.append(METHOD_SPACE);
        bd.append("public void setSystemProperties() {\n");
        bd.append(" \n");
        if (shouldResetProperties(results)) {
            /*
             * even if we set all the properties that were read, we still need
             * to reset everything to handle the properties that were written 
             */
            bd.append(BLOCK_SPACE);
            bd.append(getResetPropertiesCommand());
            bd.append(" \n");

            Set<String> readProperties = mergeProperties(results);
            for (String prop : readProperties) {
                bd.append(BLOCK_SPACE);
                String currentValue = System.getProperty(prop);
                String escaped_prop = StringEscapeUtils.escapeJava(prop);
                if (currentValue != null) {
                    String escaped_currentValue = StringEscapeUtils.escapeJava(currentValue);
                    bd.append("java.lang.System.setProperty(\"" + escaped_prop + "\", \"" + escaped_currentValue
                            + "\"); \n");
                } else {
                    bd.append("java.lang.System.clearProperty(\"" + escaped_prop + "\"); \n");
                }
            }
        } else {
            bd.append(BLOCK_SPACE + "/*No java.lang.System property to set*/\n");
        }

        bd.append(METHOD_SPACE);
        bd.append("}\n");

    }

    private void generateBeforeClass(StringBuilder bd, boolean wasSecurityException) {

        if (!wasSecurityException && !Properties.REPLACE_CALLS && !Properties.VIRTUAL_FS
                && !Properties.RESET_STATIC_FIELDS) {
            return;
        }

        bd.append(METHOD_SPACE);
        bd.append("@BeforeClass \n");

        bd.append(METHOD_SPACE);
        bd.append("public static void initEvoSuiteFramework() { \n");

        // FIXME: This is just commented out for experiments
        //bd.append("org.evosuite.utils.LoggingUtils.setLoggingForJUnit(); \n");

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            //need to setup REPLACE_CALLS and instrumentator

            if (Properties.REPLACE_CALLS) {
                bd.append(BLOCK_SPACE);
                bd.append("org.evosuite.Properties.REPLACE_CALLS = true; \n");
            }

            if (Properties.VIRTUAL_FS) {
                bd.append(BLOCK_SPACE);
                bd.append("org.evosuite.Properties.VIRTUAL_FS = true; \n");
            }

            if (Properties.RESET_STATIC_FIELDS) {
                bd.append(BLOCK_SPACE);
                bd.append("org.evosuite.Properties.RESET_STATIC_FIELDS = true; \n");
            }

            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.agent.InstrumentingAgent.initialize(); \n");

        }

        if (wasSecurityException) {
            //need to setup the Sandbox mode
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.Properties.SANDBOX_MODE = SandboxMode." + Properties.SANDBOX_MODE + "; \n");

            bd.append(BLOCK_SPACE);
            bd.append("Sandbox.initializeSecurityManagerForSUT(); \n");

            bd.append(BLOCK_SPACE);
            bd.append(EXECUTOR_SERVICE + " = Executors.newCachedThreadPool(); \n");
        }

        if (Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("initializeClasses();" + "\n");
        }

        if (Properties.REPLACE_CALLS || Properties.VIRTUAL_FS || Properties.RESET_STATIC_FIELDS) {
            bd.append(BLOCK_SPACE);
            bd.append("org.evosuite.runtime.Runtime.getInstance().resetRuntime(); \n");
        }

        bd.append(METHOD_SPACE);
        bd.append("} \n");

        bd.append("\n");
    }

    private void generateFields(StringBuilder bd, boolean wasSecurityException, List<ExecutionResult> results) {

        if (Properties.RESET_STANDARD_STREAMS) {
            bd.append(METHOD_SPACE);
            bd.append("private PrintStream systemOut = null;" + '\n');

            bd.append(METHOD_SPACE);
            bd.append("private PrintStream systemErr = null;" + '\n');

            bd.append(METHOD_SPACE);
            bd.append("private PrintStream logStream = null;" + '\n');
        }

        if (wasSecurityException) {
            bd.append(METHOD_SPACE);
            bd.append("private static ExecutorService " + EXECUTOR_SERVICE + "; \n");

            bd.append("\n");
        }

        if (shouldResetProperties(results)) {
            /*
             * some System properties were read/written. so, let's be sure we ll have the same
             * properties in the generated JUnit file, regardless of where it will be executed
             * (eg on a remote CI server). This is essential, as generated assertions might
             * depend on those properties
             */
            bd.append(METHOD_SPACE);
            bd.append("private static final java.util.Properties " + DEFAULT_PROPERTIES);
            bd.append(" = (java.util.Properties) java.lang.System.getProperties().clone(); \n");

            bd.append("\n");
        }
    }

    private boolean wasAnyWrittenProperty(List<ExecutionResult> results) {
        for (ExecutionResult res : results) {
            if (res.wasAnyPropertyWritten()) {
                return true;
            }
        }
        return false;
    }

    private Set<String> mergeProperties(List<ExecutionResult> results) {
        if (results == null) {
            return null;
        }
        Set<String> set = new LinkedHashSet<String>();
        for (ExecutionResult res : results) {
            Set<String> props = res.getReadProperties();
            if (props != null) {
                set.addAll(props);
            }
        }
        return set;
    }

    private final Map<String, Integer> testMethodNumber = new HashMap<String, Integer>();

    /**
     * Convert one test case to a Java method
     * 
     * @param id
     *            Index of the test case
     * @return String representation of test case
     * @param result
     *            a {@link org.evosuite.testcase.ExecutionResult} object.
     */
    protected String testToString(int number, int id, ExecutionResult result) {

        boolean wasSecurityException = result.hasSecurityException();

        StringBuilder builder = new StringBuilder();
        builder.append("\n");
        if (Properties.TEST_COMMENTS || testComment.containsKey(id)) {
            builder.append(METHOD_SPACE);
            builder.append("//");
            builder.append(getInformation(id));
            builder.append("\n");
        }
        String methodName;
        if (Properties.ASSERTION_STRATEGY == AssertionStrategy.STRUCTURED) {
            StructuredTestCase structuredTest = (StructuredTestCase) testCases.get(id);
            String targetMethod = structuredTest.getTargetMethods().iterator().next();
            targetMethod = targetMethod.replace("<init>", "Constructor");
            if (targetMethod.indexOf('(') != -1)
                targetMethod = targetMethod.substring(0, targetMethod.indexOf('('));
            targetMethod = StringUtils.capitalize(targetMethod);
            int num = 0;
            if (testMethodNumber.containsKey(targetMethod)) {
                num = testMethodNumber.get(targetMethod);
                testMethodNumber.put(targetMethod, num + 1);
            } else {
                testMethodNumber.put(targetMethod, 1);
            }
            methodName = "test" + targetMethod + num;
            builder.append(adapter.getMethodDefinition(methodName));
        } else {
            methodName = getNameOfTest(testCases, number);
            builder.append(adapter.getMethodDefinition(methodName));
        }

        /*
         * A test case might throw a lot of different kinds of exceptions. 
         * These might come from SUT, and might also come from the framework itself (eg, see ExecutorService.submit).
         * Regardless of whether they are declared or not, an exception that propagates to the JUnit framework will
         * result in a failure for the test case. However, there might be some checked exceptions, and for those 
         * we need to declare them in the signature with "throws". So, the easiest (but still correct) option
         * is to just declare once to throw any genetic Exception, and be done with it once and for all
         */
        builder.append(" throws Throwable ");
        builder.append(" {\n");

        // ---------   start with the body -------------------------
        String CODE_SPACE = INNER_BLOCK_SPACE;

        // No code after an exception should be printed as it would break compilability
        TestCase test = testCases.get(id);
        Integer pos = result.getFirstPositionOfThrownException();
        if (pos != null) {
            if (result.getExceptionThrownAtPosition(pos) instanceof CodeUnderTestException) {
                test.chop(pos);
            } else {
                test.chop(pos + 1);
            }
        }

        if (wasSecurityException) {
            builder.append(BLOCK_SPACE);
            builder.append("Future<?> future = " + EXECUTOR_SERVICE + ".submit(new Runnable(){ \n");
            builder.append(INNER_BLOCK_SPACE);
            // Doesn't seem to need override?
            // builder.append("@Override \n");
            builder.append(INNER_BLOCK_SPACE);
            builder.append("public void run() { \n");
            Set<Class<?>> exceptions = test.getDeclaredExceptions();
            if (!exceptions.isEmpty()) {
                builder.append(INNER_INNER_BLOCK_SPACE);
                builder.append("try {\n");
            }
            CODE_SPACE = INNER_INNER_INNER_BLOCK_SPACE;
        }

        for (String line : adapter.getTestString(id, test, result.exposeExceptionMapping(), visitor)
                .split("\\r?\\n")) {
            builder.append(CODE_SPACE);
            builder.append(line);
            builder.append("\n");
        }

        if (wasSecurityException) {
            Set<Class<?>> exceptions = test.getDeclaredExceptions();
            if (!exceptions.isEmpty()) {
                builder.append(INNER_INNER_BLOCK_SPACE);
                builder.append("} catch(Throwable t) {\n");
                builder.append(INNER_INNER_INNER_BLOCK_SPACE);
                builder.append("  // Need to catch declared exceptions\n");
                builder.append(INNER_INNER_BLOCK_SPACE);
                builder.append("}\n");
            }

            builder.append(INNER_BLOCK_SPACE);
            builder.append("} \n"); //closing run(){
            builder.append(BLOCK_SPACE);
            builder.append("}); \n"); //closing submit

            long time = Properties.TIMEOUT + 1000; // we add one second just to be sure, that to avoid issues with test cases taking exactly TIMEOUT ms
            builder.append(BLOCK_SPACE);
            builder.append("future.get(" + time + ", TimeUnit.MILLISECONDS); \n");
        }

        // ---------   end of the body ----------------------------

        builder.append(METHOD_SPACE);
        builder.append("}\n");

        String testCode = builder.toString();
        TestGenerationResultBuilder.getInstance().setTestCase(methodName, testCode, test, getInformation(id),
                result);
        return testCode;
    }

    public static String getNameOfTest(List<TestCase> tests, int position) {

        if (Properties.ASSERTION_STRATEGY == AssertionStrategy.STRUCTURED) {
            throw new IllegalStateException("For the moment, structured tests are not supported");
        }

        int totalNumberOfTests = tests.size();
        String totalNumberOfTestsString = String.valueOf(totalNumberOfTests - 1);
        String testNumber = StringUtils.leftPad(String.valueOf(position), totalNumberOfTestsString.length(), "0");
        String testName = "test" + testNumber;
        return testName;
    }

    /**
     * Update/create the main file of the test suite. The main test file simply
     * includes all automatically generated test suites in the same directory
     * 
     * @param directory
     *            Directory of generated test files
     */
    public void writeTestSuiteMainFile(String directory) {

        File file = new File(mainDirectory(directory) + "/GeneratedTestSuite.java");

        StringBuilder builder = new StringBuilder();
        if (!Properties.PROJECT_PREFIX.equals("")) {
            builder.append("package ");
            builder.append(Properties.PROJECT_PREFIX);
            // builder.append(".GeneratedTests;");
            builder.append(";\n\n");
        }
        List<String> suites = new ArrayList<String>();

        File basedir = new File(directory);
        Iterator<File> i = FileUtils.iterateFiles(basedir, new TestFilter(), TrueFileFilter.INSTANCE);
        while (i.hasNext()) {
            File f = i.next();
            String name = f.getPath().replace(directory, "").replace(".java", "").replace("/", ".");

            if (name.startsWith("."))
                name = name.substring(1);
            suites.add(name);
        }
        builder.append(adapter.getSuite(suites));
        Utils.writeFile(builder.toString(), file);
    }

    /**
     * Create JUnit test suite for class
     * 
     * @param name
     *            Name of the class
     * @param directory
     *            Output directory
     */
    public List<File> writeTestSuite(String name, String directory) {
        List<File> generated = new ArrayList<File>();
        String dir = makeDirectory(directory);
        String content = "";

        if (Properties.OUTPUT_GRANULARITY == OutputGranularity.MERGED) {
            File file = new File(dir + "/" + name + ".java");
            executor.newObservers();
            content = getUnitTest(name);
            Utils.writeFile(content, file);
            generated.add(file);
        } else {
            for (int i = 0; i < testCases.size(); i++) {
                String testSuiteName = name + "_" + i;
                File file = new File(dir + "/" + testSuiteName + ".java");
                executor.newObservers();
                String testCode = getUnitTest(name, i);
                Utils.writeFile(testCode, file);
                content += testCode;
                generated.add(file);
            }
        }
        TestGenerationResultBuilder.getInstance().setTestSuiteCode(content);
        return generated;
    }

    private void testToBytecode(TestCase test, GeneratorAdapter mg, Map<Integer, Throwable> exceptions) {
        Map<Integer, Integer> locals = new HashMap<Integer, Integer>();
        mg.visitAnnotation("Lorg/junit/Test;", true);
        int num = 0;
        for (StatementInterface statement : test) {
            logger.debug("Current statement: {}", statement.getCode());
            statement.getBytecode(mg, locals, exceptions.get(num));
            num++;
        }
        mg.visitInsn(Opcodes.RETURN);
        mg.endMethod();

    }

    /**
     * Get bytecode representation of test class
     * 
     * @param name
     *            a {@link java.lang.String} object.
     * @return an array of byte.
     */
    public byte[] getBytecode(String name) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        String prefix = Properties.TARGET_CLASS.substring(0, Properties.TARGET_CLASS.lastIndexOf(".")).replace(".",
                "/");
        cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, prefix + "/" + name, null, "junit/framework/TestCase", null);

        Method m = Method.getMethod("void <init> ()");
        GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
        mg.loadThis();
        mg.invokeConstructor(Type.getType(junit.framework.TestCase.class), m);
        mg.returnValue();
        mg.endMethod();

        int num = 0;
        for (TestCase test : testCases) {
            ExecutionResult result = runTest(test);
            m = Method.getMethod("void test" + num + " ()");
            mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
            testToBytecode(test, mg, result.exposeExceptionMapping());
            num++;
        }

        // main method
        m = Method.getMethod("void main (String[])");
        mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
        mg.push(1);
        mg.newArray(Type.getType(String.class));
        mg.dup();
        mg.push(0);
        mg.push(Properties.CLASS_PREFIX + "." + name);
        mg.arrayStore(Type.getType(String.class));
        // mg.invokeStatic(Type.getType(org.junit.runner.JUnitCore.class),
        // Method.getMethod("void main (String[])"));
        mg.invokeStatic(Type.getType(junit.textui.TestRunner.class), Method.getMethod("void main (String[])"));
        mg.returnValue();
        mg.endMethod();

        cw.visitEnd();
        return cw.toByteArray();
    }

    /**
     * Create JUnit test suite in bytecode
     * 
     * @param name
     *            a {@link java.lang.String} object.
     * @param directory
     *            a {@link java.lang.String} object.
     */
    public void writeTestSuiteClass(String name, String directory) {
        String dir = makeDirectory(directory);
        File file = new File(dir + "/" + name + ".class");
        byte[] bytecode = getBytecode(name);
        try {
            FileOutputStream stream = new FileOutputStream(file);
            try {
                stream.write(bytecode);
            } finally {
                stream.close();
            }
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
        }

        /*
         * ClassReader reader = new ClassReader(bytecode); ClassVisitor cv = new
         * TraceClassVisitor(new PrintWriter(System.out)); cv = new
         * CheckClassAdapter(cv); reader.accept(cv, ClassReader.SKIP_FRAMES);
         */

        // getBytecode(name);
    }
}