forked from JavaTX/JavaCompilerCore
447 lines
20 KiB
Java
Executable File
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;
|
|
}
|
|
}
|