gt: 		for (MethodDef methodDef : afterClassMethods) {
context: /**
   * Copyright (C) 2010-2017 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 Lesser General Public License as published
   * by the Free Software Foundation, either version 3.0 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
   * Lesser Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>.
   */
  package org.evosuite.junit;
  
  import java.io.PrintStream;
  import java.io.Serializable;
  import java.lang.reflect.InvocationTargetException;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.jdt.core.dom.IVariableBinding;
  import org.evosuite.testcase.AbstractStatement;
  import org.evosuite.testcase.AssignmentStatement;
  import org.evosuite.testcase.DefaultTestCase;
  import org.evosuite.testcase.PrimitiveExpression;
  import org.evosuite.testcase.Scope;
  import org.evosuite.testcase.StatementInterface;
  import org.evosuite.testcase.TestCase;
  import org.evosuite.testcase.VariableReference;
  import org.evosuite.utils.GenericAccessibleObject;
  import org.objectweb.asm.commons.GeneratorAdapter;
  
  /**
   * A compound test case is a test case that is read from an existing JUnit test
   * file, and may have a complex structure. It contains static code sections,
   * fields, constructors, @BeforeClass, @Before, @After, @AfterClass annotated
   * methods and possibly a class hierarchy. A CompoundTestCase is used to gather
   * all those statements to eventually combine them into a normal
   * {@link TestCase} when {@link #finalizeTestCase()} is called.
   * 
   * @author roessler
   */
  public class CompoundTestCase implements Serializable {
  	public static class MethodDef {
  		private final String name;
  		private final List<VariableReference> params = new ArrayList<VariableReference>();
  		final List<StatementInterface> code = new ArrayList<StatementInterface>();
  
  		public MethodDef(String name) {
  			super();
  			this.name = name;
  		}
  
  		public void add(StatementInterface statement) {
  			code.add(statement);
  		}
  
  		public List<StatementInterface> getCode() {
  			return code;
  		}
  
  		public String getName() {
  			return name;
  		}
  
  		public List<VariableReference> getParams() {
  			return params;
  		}
  
  		@Override
  		public String toString() {
  			return name;
  		}
  	}
  
  	public static class ReturnStatementPlaceholder extends AbstractStatement {
  
  		private static final long serialVersionUID = 1L;
  
  		protected ReturnStatementPlaceholder(TestCase tc, VariableReference returnValue) {
  			super(tc, returnValue.getType());
  			retval = returnValue;
  		}
  
  		@Override
  		public StatementInterface copy(TestCase newTestCase, int offset) {
  			throw new UnsupportedOperationException("Method copy not implemented!");
  		}
  
  		@Override
  		public Throwable execute(Scope scope, PrintStream out)
  		        throws InvocationTargetException, IllegalArgumentException,
  		        IllegalAccessException, InstantiationException {
  			throw new UnsupportedOperationException("Method execute not implemented!");
  		}
  
  		@Override
  		public GenericAccessibleObject getAccessibleObject() {
  			throw new UnsupportedOperationException(
  			        "Method getAccessibleObject not implemented!");
  		}
  
  		@Override
  		public void getBytecode(GeneratorAdapter mg, Map<Integer, Integer> locals,
  		        Throwable exception) {
  			throw new UnsupportedOperationException("Method getBytecode not implemented!");
  		}
  
  		@Override
  		public List<VariableReference> getUniqueVariableReferences() {
  			throw new UnsupportedOperationException(
  			        "Method getUniqueVariableReferences not implemented!");
  		}
  
  		@Override
  		public Set<VariableReference> getVariableReferences() {
  			throw new UnsupportedOperationException(
  			        "Method getVariableReferences not implemented!");
  		}
  
  		@Override
  		public boolean isAssignmentStatement() {
  			return false;
  		}
  
  		@Override
  		public void replace(VariableReference oldVar, VariableReference newVar) {
  			if (retval.equals(oldVar)) {
  				retval = newVar;
  			}
  		}
  
  		@Override
  		public boolean same(StatementInterface s) {
  			throw new UnsupportedOperationException("Method same not implemented!");
  		}
  
  	}
  
  	public static enum TestScope {
  		BEFORE_CLASS,
  		STATIC,
  		STATICFIELDS,
  		BEFORE,
  		FIELDS,
  		CONSTRUCTOR,
  		AFTER,
  		AFTER_CLASS,
  		METHOD;
  	}
  
  	/** Constant <code>STATIC_BLOCK_METHODNAME="<static block>"</code> */
  	public static final String STATIC_BLOCK_METHODNAME = "<static block>";
  
  	private static final long serialVersionUID = 1L;
  
  	private final Map<String, MethodDef> methodDefs = new LinkedHashMap<String, MethodDef>();
  	private final Map<String, VariableReference> currentMethodVars = new HashMap<String, VariableReference>();
  	private final Map<String, VariableReference> fieldVars = new HashMap<String, VariableReference>();
  	private final List<MethodDef> constructors = new ArrayList<MethodDef>();
  	private final List<MethodDef> afterMethods = new ArrayList<MethodDef>();
  	private final List<MethodDef> afterClassMethods = new ArrayList<MethodDef>();
  	private final List<MethodDef> beforeMethods = new ArrayList<MethodDef>();
  	private final List<MethodDef> beforeClassMethods = new ArrayList<MethodDef>();
  	private final List<StatementInterface> staticFields = new ArrayList<StatementInterface>();
  	private final List<StatementInterface> fields = new ArrayList<StatementInterface>();
  	private final List<StatementInterface> staticCode = new ArrayList<StatementInterface>();
  	private final String className;
  	private final String testMethod;
  	// find here or up the hierarchy
  	private CompoundTestCase parent;
  	// Needed for methods and fields:
  	// find method in actual class or up the hierarchy
  	private final CompoundTestCase originalDescendant;
  	private TestScope currentScope = TestScope.FIELDS;
  	private MethodDef currentMethod = null;
  
  	private final DelegatingTestCase delegate;
  
  	/**
  	 * <p>
  	 * Constructor for CompoundTestCase.
  	 * </p>
  	 * 
  	 * @param className
  	 *            a {@link java.lang.String} object.
  	 * @param child
  	 *            a {@link org.evosuite.junit.CompoundTestCase} object.
  	 */
  	public CompoundTestCase(String className, CompoundTestCase child) {
  		child.parent = this;
  		delegate = child.getReference();
  		originalDescendant = child.originalDescendant;
  		this.testMethod = null;
  		this.className = className;
  	}
  
  	/**
  	 * <p>
  	 * Constructor for CompoundTestCase.
  	 * </p>
  	 * 
  	 * @param className
  	 *            a {@link java.lang.String} object.
  	 * @param methodName
  	 *            a {@link java.lang.String} object.
  	 */
  	public CompoundTestCase(String className, String methodName) {
  		this.testMethod = methodName;
  		this.className = className;
  		delegate = new DelegatingTestCase();
  		originalDescendant = this;
  	}
  
  	/**
  	 * <p>
  	 * addParameter
  	 * </p>
  	 * 
  	 * @param varRef
  	 *            a {@link org.evosuite.testcase.VariableReference} object.
  	 */
  	public void addParameter(VariableReference varRef) {
  		currentMethod.getParams().add(varRef);
  	}
  
  	/**
  	 * <p>
  	 * addStatement
  	 * </p>
  	 * 
  	 * @param statement
  	 *            a {@link org.evosuite.testcase.StatementInterface} object.
  	 */
  	public void addStatement(StatementInterface statement) {
  		if (currentScope == TestScope.FIELDS) {
  			fields.add(statement);
  			return;
  		}
  		if (currentScope == TestScope.STATICFIELDS) {
  			staticFields.add(statement);
  			return;
  		}
  		if (currentScope == TestScope.STATIC) {
  			staticCode.add(statement);
  			return;
  		}
  		currentMethod.add(statement);
  	}
  
  	/**
  	 * <p>
  	 * addVariable
  	 * </p>
  	 * 
  	 * @param varBinding
  	 *            a {@link org.eclipse.jdt.core.dom.IVariableBinding} object.
  	 * @param varRef
  	 *            a {@link org.evosuite.testcase.VariableReference} object.
  	 */
  	public void addVariable(IVariableBinding varBinding, VariableReference varRef) {
  		if ((currentScope == TestScope.FIELDS)
  		        || (currentScope == TestScope.STATICFIELDS)) {
  			fieldVars.put(varBinding.toString(), varRef);
  			return;
  		}
  		currentMethodVars.put(varBinding.toString(), varRef);
  	}
  
  	/**
  	 * <p>
  	 * convertMethod
  	 * </p>
  	 * 
  	 * @param methodDef
  	 *            a {@link org.evosuite.junit.CompoundTestCase.MethodDef}
  	 *            object.
  	 * @param params
  	 *            a {@link java.util.List} object.
  	 * @param retVal
  	 *            a {@link org.evosuite.testcase.VariableReference} object.
  	 */
  	public void convertMethod(MethodDef methodDef, List<VariableReference> params,
  	        VariableReference retVal) {
  		assert methodDef.getParams().size() == params.size();
  		Map<VariableReference, VariableReference> methodVarsMap = new HashMap<VariableReference, VariableReference>();
  		for (StatementInterface statement : methodDef.getCode()) {
  			for (int idx = 0; idx < params.size(); idx++) {
  				statement.replace(methodDef.getParams().get(idx), params.get(idx));
  			}
  			if (statement instanceof ReturnStatementPlaceholder) {
  				VariableReference resultVal = methodVarsMap.get(statement.getReturnValue());
  				if (resultVal == null) {
  					throw new IllegalStateException();
  				}
  				AssignmentStatement assignmentStatement = new AssignmentStatement(
  				        delegate, retVal, resultVal);
  				addStatement(assignmentStatement);
  				return;
  			}
  			StatementInterface newStmt = statement;
  			if (!(statement instanceof PrimitiveExpression)) {
  				// Since the delegate code is not yet finished,
  				// cloning of PrimitiveExpressions does not work.
  				newStmt = statement.clone(delegate);
  			}
  			addReplacementVariable(statement.getReturnValue(), newStmt.getReturnValue());
  			methodVarsMap.put(statement.getReturnValue(), newStmt.getReturnValue());
  			addStatement(newStmt);
  		}
  	}
  
  	/**
  	 * <p>
  	 * discardMethod
  	 * </p>
  	 */
  	public void discardMethod() {
  		currentScope = TestScope.FIELDS;
  		currentMethod = null;
  		currentMethodVars.clear();
  	}
  
  	/**
  	 * <p>
  	 * finalizeMethod
  	 * </p>
  	 */
  	public void finalizeMethod() {
  		String currentMethodName = currentMethod.getName();
  		methodDefs.put(currentMethodName, currentMethod);
  		switch (currentScope) {
  		case AFTER:
  			afterMethods.add(currentMethod);
  			break;
  		case AFTER_CLASS:
  			afterClassMethods.add(currentMethod);
  			break;
  		case BEFORE:
  			beforeMethods.add(currentMethod);
  			break;
  		case BEFORE_CLASS:
  			beforeClassMethods.add(currentMethod);
  			break;
  		case CONSTRUCTOR:
  			constructors.add(currentMethod);
  			break;
  		default:
  			break;
  		}
  		currentScope = TestScope.FIELDS;
  		currentMethod = null;
  		currentMethodVars.clear();
  	}
  
  	/**
  	 * <p>
  	 * finalizeTestCase
  	 * </p>
  	 * 
  	 * @return a {@link org.evosuite.testcase.TestCase} object.
  	 */
  	public TestCase finalizeTestCase() {
  		Set<String> overridenMethods = Collections.emptySet();
  		delegate.setDelegate(new DefaultTestCase());
  		delegate.addStatements(getStaticInitializationBeforeClassMethods(overridenMethods));
  		delegate.addStatements(getInitializationCode());
  		delegate.addStatements(getBeforeMethods(overridenMethods));
  		if (testMethod == null) {
  			throw new RuntimeException("Test did not contain any statements!");
  		}
  		if (methodDefs.get(testMethod) == null) {
  			throw new RuntimeException("Error reading test method " + testMethod + "!");
  		}
  		delegate.addStatements(methodDefs.get(testMethod).getCode());
  		delegate.addStatements(getAfterMethods(overridenMethods));
  		delegate.addStatements(getAfterClassMethods(overridenMethods));
  		assert delegate.clone().toCode().equals(delegate.toCode());
  		return delegate;
  	}
  
  	/**
  	 * <p>
  	 * Getter for the field <code>className</code>.
  	 * </p>
  	 * 
  	 * @return a {@link java.lang.String} object.
  	 */
  	public String getClassName() {
  		return className;
  	}
  
  	/**
  	 * <p>
  	 * Getter for the field <code>currentMethod</code>.
  	 * </p>
  	 * 
  	 * @return a {@link java.lang.Object} object.
  	 */
  	public Object getCurrentMethod() {
  		return currentMethod.getName();
  	}
  
  	/**
  	 * <p>
  	 * Getter for the field <code>currentScope</code>.
  	 * </p>
  	 * 
  	 * @return a {@link org.evosuite.junit.CompoundTestCase.TestScope} object.
  	 */
  	public TestScope getCurrentScope() {
  		return currentScope;
  	}
  
  	/**
  	 * <p>
  	 * getLastStatement
  	 * </p>
  	 * 
  	 * @return a {@link org.evosuite.testcase.StatementInterface} object.
  	 */
  	public StatementInterface getLastStatement() {
  		assert currentScope == TestScope.METHOD;
  		return currentMethod.code.get(currentMethod.code.size() - 1);
  	}
  
  	/**
  	 * <p>
  	 * getMethod
  	 * </p>
  	 * 
  	 * @param name
  	 *            a {@link java.lang.String} object.
  	 * @return a {@link org.evosuite.junit.CompoundTestCase.MethodDef} object.
  	 */
  	public MethodDef getMethod(String name) {
  		if (originalDescendant != this) {
  			return originalDescendant.getMethodInternally(name);
  		}
  		return getMethodInternally(name);
  	}
  
  	/**
  	 * <p>
  	 * Getter for the field <code>parent</code>.
  	 * </p>
  	 * 
  	 * @return a {@link org.evosuite.junit.CompoundTestCase} object.
  	 */
  	public CompoundTestCase getParent() {
  		return parent;
  	}
  
  	/**
  	 * <p>
  	 * getReference
  	 * </p>
  	 * 
  	 * @return a {@link org.evosuite.junit.DelegatingTestCase} object.
  	 */
  	public DelegatingTestCase getReference() {
  		return delegate;
  	}
  
  	/**
  	 * <p>
  	 * getVariableReference
  	 * </p>
  	 * 
  	 * @param varBinding
  	 *            a {@link org.eclipse.jdt.core.dom.IVariableBinding} object.
  	 * @return a {@link org.evosuite.testcase.VariableReference} object.
  	 */
  	public VariableReference getVariableReference(IVariableBinding varBinding) {
  		if (originalDescendant != this) {
  			return originalDescendant.getVariableReferenceInternally(varBinding);
  		}
  		return getVariableReferenceInternally(varBinding);
  	}
  
  	/**
  	 * <p>
  	 * isDescendantOf
  	 * </p>
  	 * 
  	 * @param declaringClass
  	 *            a {@link java.lang.Class} object.
  	 * @return a boolean.
  	 */
  	public boolean isDescendantOf(Class<?> declaringClass) {
  		if (parent == null) {
  			return false;
  		}
  		if (parent.className.equals(declaringClass.getName())) {
  			return true;
  		}
  		return parent.isDescendantOf(declaringClass);
  	}
  
  	/**
  	 * <p>
  	 * newMethod
  	 * </p>
  	 * 
  	 * @param methodName
  	 *            a {@link java.lang.String} object.
  	 */
  	public void newMethod(String methodName) {
  		assert (currentMethod == null) || currentMethod.getCode().isEmpty();
  		assert currentMethodVars.isEmpty();
  		currentScope = TestScope.METHOD;
  		currentMethod = new MethodDef(methodName);
  	}
  
  	/**
  	 * <p>
  	 * Setter for the field <code>currentScope</code>.
  	 * </p>
  	 * 
  	 * @param scope
  	 *            a {@link org.evosuite.junit.CompoundTestCase.TestScope}
  	 *            object.
  	 */
  	public void setCurrentScope(TestScope scope) {
  		this.currentScope = scope;
  	}
  
  	/** {@inheritDoc} */
  	@Override
  	public String toString() {
  		return className;
  	}
  
  	/**
  	 * <p>
  	 * variableAssignment
  	 * </p>
  	 * 
  	 * @param varRef
  	 *            a {@link org.evosuite.testcase.VariableReference} object.
  	 * @param newAssignment
  	 *            a {@link org.evosuite.testcase.VariableReference} object.
  	 */
  	public void variableAssignment(VariableReference varRef,
  	        VariableReference newAssignment) {
  		for (Map.Entry<String, VariableReference> entry : currentMethodVars.entrySet()) {
  			if (entry.getValue() == varRef) {
  				currentMethodVars.put(entry.getKey(), newAssignment);
  				return;
  			}
  		}
  		for (Map.Entry<String, VariableReference> entry : fieldVars.entrySet()) {
  			if (entry.getValue() == varRef) {
  				fieldVars.put(entry.getKey(), newAssignment);
  				return;
  			}
  		}
  		if (parent != null) {
  			for (Map.Entry<String, VariableReference> entry : parent.fieldVars.entrySet()) {
  				if (entry.getValue() == varRef) {
  					parent.fieldVars.put(entry.getKey(), newAssignment);
  					return;
  				}
  			}
  		}
  		throw new RuntimeException("Assignment " + varRef + " not found!");
  	}
  
  	private void addReplacementVariable(VariableReference oldValue,
  	        VariableReference newValue) {
  		String variable = getVariableFromCurrentScope(oldValue);
  		fieldVars.put(variable, newValue);
  	}
  
  	private List<StatementInterface> getAfterClassMethods(Set<String> overridenMethods) {
  		List<StatementInterface> result = new ArrayList<StatementInterface>();
  