JavaCompilerCore/test/mycompiler/test/AbstractInferenceTest.java
2013-10-18 13:33:46 +02:00

447 lines
20 KiB
Java
Executable File

package mycompiler.test;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
import junit.framework.TestCase;
import mycompiler.MyCompiler;
import mycompiler.MyCompilerAPI;
import mycompiler.mytype.BoundedGenericTypeVar;
import mycompiler.mytype.GenericTypeVar;
import mycompiler.mytype.RefType;
import mycompiler.mytype.Type;
import mycompiler.mytype.TypePlaceholder;
import mycompiler.mytypereconstruction.CIntersectionType;
import mycompiler.mytypereconstruction.CSubstitution;
import mycompiler.mytypereconstruction.CTypeReconstructionResult;
import mycompiler.mytypereconstruction.typeassumption.CInstVarTypeAssumption;
import mycompiler.mytypereconstruction.typeassumption.CLocalVarTypeAssumption;
import mycompiler.mytypereconstruction.typeassumption.CMethodTypeAssumption;
import mycompiler.mytypereconstruction.typeassumption.CParaTypeAssumption;
import mycompiler.mytypereconstruction.typeassumption.CTypeAssumption;
import mycompiler.mytypereconstruction.typeassumptionkey.CMethodKey;
import mycompiler.test.expectationTypes.BlockExpect;
import mycompiler.test.expectationTypes.ClassExpect;
import mycompiler.test.expectationTypes.Expectation;
import mycompiler.test.expectationTypes.GenericTypeVarExpect;
import mycompiler.test.expectationTypes.IExpectation;
import mycompiler.test.expectationTypes.IUnknownTypeExpect;
import mycompiler.test.expectationTypes.MethodExpect;
import mycompiler.test.expectationTypes.TypePlaceholderExpect;
import mycompiler.test.expectationTypes.VarExpect;
import org.apache.log4j.Logger;
/** Todo:
* - exception handling cannot verify correct exception yet
*
* done: - exception handling
* - commented asserts
* - log4j
* - cmethodkey usage
* - Typeplaceholder support
* @author
* last change: 26-05-08
*/
public abstract class AbstractInferenceTest extends TestCase {
private static Logger testlog = Logger.getLogger("funcTest");
private File javFile=null;
private Expectation expectation=null;
private MyCompilerAPI compiler = MyCompiler.getAPI();
protected AbstractInferenceTest(String name, String javFilename) {
super(name);
javFile = new File(javFilename);
//retrieve Expectation object from specific Testcase for comparisons
this.expectation = getExpectations();
}
/**
* runs the JUnit-Test, calls all compiler steps
* @throws Throwable
*/
public void testSetup() throws Throwable {
//runs all compiler steps, any exception will cause the Test to fail, if not expected
//enable Logging
Log4jWrapper.getInstance().configureLog4j();
try {
testlog.info("Parsing...");
parseFile();
testlog.info("Type reconstruction...");
typeReconstruction();
testlog.info("Code generation...");
codeGeneration();
//checks whether there is an expected exception that has not been thrown
AbstractInferenceTest.assertTrue("exception expected but not found",this.expectation.getExceptions().isEmpty());
} catch (Exception e) {
testlog.info("Error during compiler step: " + e);
checkForExpectedException(e);
}
}
/**
* calls parse() from Compiler-API
* @throws Throwable
*/
protected void parseFile()
throws Throwable
{
// Parse file
compiler.parse(javFile);
}
/**
* calls typeReconstruction() from Compiler-API, checks result against expectations and substitutes all types according to first assumption
* @throws Exception
*/
protected void typeReconstruction()
throws Exception
{
// Typ-Rekonstruktion
Vector<CTypeReconstructionResult> resultSet = compiler.typeReconstruction();
testlog.info("Type reconstruction completed...");
// Keine Typ-Rekonstruktion erforderlich
if (resultSet == null || resultSet.size() == 0) throw new Exception("Type reconstruction could not be done!");
if (this.expectation!=null) {
if(this.expectation.getClasses()!=null)
checkResults(resultSet,this.expectation);
}
else
testlog.info("An Error has occurred receiving the expectations for this testcase: "+ this.javFile);
CTypeReconstructionResult onePossibility = resultSet.firstElement();
Iterator substIt = onePossibility.getSubstitutions().getIterator();
while(substIt.hasNext()){
CSubstitution subst = (CSubstitution)substIt.next();
// Substition machen
subst.execute();
}
}
/**
* calls codeGeneration from Compiler-API
* @throws Exception
*/
protected void codeGeneration()
throws Exception
{
// Code generieren
compiler.codeGeneration();
}
/**
* compares resultSet from compiler to expectations
* @param resultSet
* @param expect
*/
protected void checkResults(Vector<CTypeReconstructionResult> resultSet, Expectation expect) {
//iterates thru all available assumption-sets
testlog.info("Starting checking for valid type assumptions...");
for (int resIndex=0; resIndex < resultSet.size(); resIndex++) {
//checks whether all expected classes, methods, members are available
checkClasses(resultSet.get(resIndex),expect);
//--------------
//Methods
//--------------
//iterates through all found methods
for (CIntersectionType vecAssumpt : resultSet.get(resIndex).getMethodIntersectionTypes().values()) {
//for (int i=0; i<vecAssumpt.size();i++) {
CMethodTypeAssumption assumpt = vecAssumpt.getMethodTypeAssumptions().get(0);
CMethodKey assumptKey = vecAssumpt.getIntersectionTypeKey();
//filter: own classes only
if (expect.getClasses().containsKey(assumpt.getClassName())){
//current method to compare assumption to:
testlog.debug("checking method of class "+ assumpt.getClassName());
MethodExpect method = expect.getClasses().get(assumpt.getClassName()).getMethods().get(assumptKey);
AbstractInferenceTest.assertTrue("no expectation has been defined for this method: '" + assumpt.getIdentifier() +"'", method!=null);
testlog.debug("comparing assumption to method "+method.getName());
//check parameter first, in case an undefined parameter type must be added to expected generics
checkParameters(assumpt,method);
testlog.debug("assumption return type: '"+assumpt.getAssumedType()+"'");
checkReturnType(assumpt.getAssumedType(), method);
testlog.debug("assumption generics: '"+assumpt.getGenericMethodParameters()+"'");
checkFoundGenerics(assumpt.getGenericMethodParameters(), method.getGenerics());
}
//}
}
//---------------------------
//Local and member variables:
//---------------------------
//Iterator<CTypeAssumption> iter2 = resultSet.get(resIndex).getFieldAndLocalVarAssumptions().values().iterator();
//while (iter2.hasNext()) {
//CTypeAssumption assumption = iter2.next();
for (CTypeAssumption assumption : resultSet.get(resIndex).getFieldAndLocalVarAssumptions().values()) {
// local variable
if (assumption instanceof CLocalVarTypeAssumption) {
CLocalVarTypeAssumption assu = (CLocalVarTypeAssumption)assumption;
if (expect.getClasses().containsKey(assu.getClassName())){
//current method to compare assumption to:
MethodExpect method = expect.getClasses().get(assu.getClassName()).getMethods().get(new CMethodKey(assu.getClassName(),assu.getMethodName(),assu.getMethodParaCount(),assu.getMethodOverloadedID()));
testlog.debug("assumption: local variable '"+assu.getIdentifier()+"' of '"+assu.getClassName()+":"+assu.getMethodName()+"'");
testlog.debug("searching in: '"+method.getName()+"'");
AbstractInferenceTest.assertTrue("block variable '" + assu.getIdentifier() + "' in '" + assu.getMethodName()+ "' not valid or not found!",checkFoundVariable(assu, method.getBlock()));
}
}
// member variable
else if (assumption instanceof CInstVarTypeAssumption) {
CInstVarTypeAssumption assu = (CInstVarTypeAssumption)assumption;
if (expect.getClasses().containsKey(assu.getClassName())){
//current class to compare assumption to:
ClassExpect classexpect = expect.getClasses().get(assu.getClassName());
testlog.debug("assumption: member variable '"+assu.getIdentifier()+"' of '"+assu.getClassName()+"'");
testlog.debug("searching in: '"+classexpect.getName()+"'");
checkFoundMembers(assu, classexpect.getMembers());
}
}
}
}
//verify that every single type assumption that was expected has been detected by the compiler
testlog.info("verifying all expectations have been met");
AbstractInferenceTest.assertTrue("not all expected types have been found", expectation.verifyTypeExpectationsCompletelyMet());
}
/**
* @return returns a vector of class names of tested file
*/
protected abstract Expectation getExpectations();
/**
* checks the return type of a method comparing it to the expectation
* @param assumpt
* @param expect
*/
protected void checkReturnType(Type assumpt, MethodExpect expect) {
if (!expect.getReturntypes().isEmpty()) {
AbstractInferenceTest.assertTrue("found return type " + assumpt.getName() + " is not in expected list", expect.getReturntypes().contains(assumpt));
checkBoundedTypes(assumpt,expect.getReturntypes().get(expect.getReturntypes().indexOf(assumpt)));
//remove this expectation to assure, all expectations have been met at least once
if (expect.getReturntypesCopy().contains(assumpt))
expect.getReturntypesCopy().remove(assumpt);
}
else if ((assumpt instanceof GenericTypeVar || assumpt instanceof TypePlaceholder) && expect.getUnknownReturnType()!=null) {
//expect.addGeneric((GenericTypeVar) assumpt);
checkUnknownTypes(assumpt, expect.getUnknownReturnType());
}
else
AbstractInferenceTest.fail("no return type for " + assumpt.getName() +" has been defined in expectation");
}
/**
* checks for generic methods comparing them to the expectation
* @param assumpt
* @param expect
*/
protected void checkFoundGenerics(Vector<GenericTypeVar> assumpt, Vector<GenericTypeVar> expect) {
AbstractInferenceTest.assertTrue("amount of generic variables expected != assumed",((assumpt==null || assumpt.size()==0) && (expect==null || expect.size()==0)) || assumpt.size()==expect.size());
for (GenericTypeVar typ : assumpt) {
//System.out.println("Generics: " + typ.get_Name() + ((BoundedGenericTypeVar)typ).getBounds() + ", " + expect.indexOf(typ));
AbstractInferenceTest.assertTrue("Generic " + typ.getName() + " has not been expected",expect.contains(typ));
checkBoundedTypes(typ,expect.get(expect.indexOf(typ)));
}
}
protected void checkBoundedTypes(Type assumed, Type expected) {
if (assumed instanceof BoundedGenericTypeVar) {
AbstractInferenceTest.assertTrue("assumed: BoundedGenericTypeVar, expected:' "+expected.getClass()+"'",expected instanceof BoundedGenericTypeVar);
BoundedGenericTypeVar typBound = (BoundedGenericTypeVar)assumed;
BoundedGenericTypeVar expBound = (BoundedGenericTypeVar)expected;
for (Type t : typBound.getBounds()) {
boolean ret = false;
for (Type e : expBound.getBounds()) {
//System.out.println(" here " + t + " -- " + e);
if (e.equals(t)) {
ret=true;
}
}
AbstractInferenceTest.assertTrue("Bounded generic's type is not equal", ret);
}
}
else if (assumed instanceof GenericTypeVar) {
// System.out.println("GENERICTYPEVAR");
}
}
protected void checkUnknownTypes(Type assumed, IUnknownTypeExpect expect) {
if (assumed instanceof GenericTypeVar) {
AbstractInferenceTest.assertTrue("Assumed type is of GenericTypeVar",expect instanceof GenericTypeVarExpect);
}
else if (assumed instanceof TypePlaceholder) {
AbstractInferenceTest.assertTrue("Assumed type is of TypePlaceholder",expect instanceof TypePlaceholderExpect);
}
String mappedType=this.expectation.getMappings().getMappedType(expect.getName());
if (mappedType!=null) {
AbstractInferenceTest.assertEquals("Same expected UnknownType mapped to different assumed types",mappedType,assumed.getName());
}
else
this.expectation.getMappings().addMapping(expect.getName(), assumed.getName());
}
/**
* searches recursively for the matching block in the expectation set and compares found variables to the expectation
* @param assumpt
* @param expect
* @return
*/
protected boolean checkFoundVariable(CLocalVarTypeAssumption assumpt, BlockExpect expect) {
//there is an expectation for a variable
AbstractInferenceTest.assertTrue(expect!=null);
boolean ret=false;
if (expect.getBlockID().equals(assumpt.getBlockId())) {
AbstractInferenceTest.assertTrue("Variable "+assumpt.getIdentifier() + " is not defined in expectation",expect.getLocalVar().containsKey(assumpt.getIdentifier()));
VarExpect varExpect = expect.getLocalVar().get(assumpt.getIdentifier());
Vector<Type> expTypes = varExpect.getExpectedType();
//check if a specific type for this variable is expected or whether it should be a typeplaceholder/generictypevar
if (!expTypes.isEmpty()) {
AbstractInferenceTest.assertTrue("Type " + assumpt.getAssumedType() + " for variable " + assumpt.getIdentifier() + " is not found in expectations", expTypes.contains(assumpt.getAssumedType()));
checkBoundedTypes(assumpt.getAssumedType(), expTypes.get(expTypes.indexOf(assumpt.getAssumedType())));
//remove this expectation to assure, all expectations have been met at least once
expect.getLocalVar().get(assumpt.getIdentifier()).getExpectedTypeCopy().remove(assumpt.getAssumedType());
}
else if ((assumpt.getAssumedType() instanceof GenericTypeVar || assumpt.getAssumedType() instanceof TypePlaceholder) && varExpect.getExpectedUnknownType()!=null) {
checkUnknownTypes(assumpt.getAssumedType(),varExpect.getExpectedUnknownType());
}
else
AbstractInferenceTest.fail("no type for variable "+ assumpt.getIdentifier() + " has been defined");
return true;
}
else if (expect.getContainedBlocks()!=null){
//dig one block deeper in hierarchy
for (BlockExpect exp : expect.getContainedBlocks())
ret |= checkFoundVariable(assumpt,exp);
return ret;
}
return false;
}
/**
* checks method parameters comparing them to the expectation
* @param assumpt
* @param expect
*/
protected void checkParameters(CMethodTypeAssumption methodAssumpt, MethodExpect methodExpect) {
Vector<CParaTypeAssumption> assumpt = methodAssumpt.getParaAssumptions();
HashMap<String,VarExpect> expect = methodExpect.getParameter();
//amount of parameter - not needed anymore since methodkey contains amount of parameters already
//AbstractInferenceTest.assertEquals("amount of parameters not equal!", assumpt.size(),expect.size());
for (CParaTypeAssumption paraAssumpt : assumpt) {
//check if variable is expected
AbstractInferenceTest.assertTrue("variable " + paraAssumpt.getIdentifier() + " is not expected!", expect.containsKey(paraAssumpt.getIdentifier()));
Vector<Type> expectedTypes = expect.get(paraAssumpt.getIdentifier()).getExpectedType();
//check if variable's type is expected
if (!expectedTypes.isEmpty()) {
AbstractInferenceTest.assertTrue("type " + paraAssumpt.getAssumedType() + " for variable " + paraAssumpt.getIdentifier() + " is not expected!", expectedTypes.contains(paraAssumpt.getAssumedType()));
AbstractInferenceTest.assertEquals("type " + paraAssumpt.getAssumedType() + " for variable " + paraAssumpt.getIdentifier() + " is not expected!", expectedTypes.get(expectedTypes.indexOf(paraAssumpt.getAssumedType())).getClass(),paraAssumpt.getAssumedType().getClass());
checkBoundedTypes(paraAssumpt.getAssumedType(), expectedTypes.get(expectedTypes.indexOf(paraAssumpt.getAssumedType())));
//remove this expectation to assure, all expectations have been met at least once
expect.get(paraAssumpt.getIdentifier()).getExpectedTypeCopy().remove(paraAssumpt.getAssumedType());
}
else if (paraAssumpt.getAssumedType() instanceof GenericTypeVar && expect.get(paraAssumpt.getIdentifier()).getExpectedUnknownType()!=null) {
//case of undefined type (generic variable), add generic to generic list
if (!methodExpect.getGenerics().contains((GenericTypeVar)paraAssumpt.getAssumedType()))
methodExpect.addGeneric((GenericTypeVar) paraAssumpt.getAssumedType());
checkUnknownTypes(paraAssumpt.getAssumedType(),expect.get(paraAssumpt.getIdentifier()).getExpectedUnknownType() );
}
else if (paraAssumpt.getAssumedType() instanceof TypePlaceholder && expect.get(paraAssumpt.getIdentifier()).getExpectedUnknownType()!=null)
checkUnknownTypes(paraAssumpt.getAssumedType(),expect.get(paraAssumpt.getIdentifier()).getExpectedUnknownType() );
else
AbstractInferenceTest.fail("no type for " + paraAssumpt.getIdentifier() +" has been defined in expectation");
}
}
/**
* checks every class expected is included in compiler assumption + available generics
* @param assumption
* @param expectation
*/
protected void checkClasses(CTypeReconstructionResult assumption, Expectation expectation) {
for (String expect : expectation.getClasses().keySet()) {
//class exists
AbstractInferenceTest.assertTrue("class " + expect + " is not found in assumption!", assumption.getClassNameList().contains(expect));
//generics
checkFoundGenerics(assumption.getGenerics(expect), expectation.getClasses().get(expect).getGenerics());
}
}
/**
* members found are compared to the expectation
* @param assumpt
* @param expect
*/
protected void checkFoundMembers(CInstVarTypeAssumption assumpt, HashMap<String,VarExpect> expect) {
AbstractInferenceTest.assertTrue("Member " + assumpt.getIdentifier() + " is not found in expectation!", expect.containsKey(assumpt.getIdentifier()));
AbstractInferenceTest.assertTrue("Type " + assumpt.getAssumedType() + " for member " + assumpt.getIdentifier() + " is not found in expectation",expect.get(assumpt.getIdentifier()).getExpectedType().contains(assumpt.getAssumedType()));
//
//remove this expectation to assure, all expectations have been met at least once
if (expect.get(assumpt.getIdentifier()).getExpectedTypeCopy().contains(assumpt.getAssumedType()))
expect.get(assumpt.getIdentifier()).getExpectedTypeCopy().remove(assumpt.getAssumedType());
}
/**
* called to verify whether thrown exception from compiler calls is expected
* @param e
* @throws Throwable
*/
protected void checkForExpectedException (Exception e) throws Throwable {
if (!this.expectation.getExceptions().isEmpty()) {
//check if thrown exception has been expected
e.printStackTrace();
// System.out.println(e.getClass());
//AbstractInferenceTest2.assertTrue("Exception " + e.getMessage() + " is not same as expected", e.getClass().equals(this.expectation.getExceptions().firstElement()));
AbstractInferenceTest.assertTrue("Exception " + e.getMessage() + " is not expected", !this.expectation.getExceptions().isEmpty());
}
else
throw e;
}
// @Deprecated
// protected void checkForValidMethodTypes(CMethodTypeAssumption assumpt) {}
// protected void setUp() {}
// protected void tearDown() {}
protected Vector<Type> createVectorAllNumberTypes() {
Vector<Type> ret = new Vector<Type>();
ret.add(new RefType("java.lang.Integer",-1));
ret.add(new RefType("java.lang.Long",-1));
ret.add(new RefType("java.lang.Double",-1));
ret.add(new RefType("java.lang.Float",-1));
// ret.add(new RefType("java.lang.Short",-1));
// ret.add(new RefType("java.lang.Byte",-1));
// ret.add(new RefType("java.lang.Character",-1));
return ret;
}
}