package fr.inria.diversify.processor.test;
import fr.inria.diversify.processor.ProcessorUtil;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.support.reflect.code.CtCodeSnippetStatementImpl;
import java.util.ArrayList;
import java.util.List;
public class TestCaseProcessor extends TestProcessor {
protected String testDir;
public static int monitorPointCount = 0;
protected boolean logAssert;
/*
* This processor removes all the assertions from a test case
* For future version:
* - we should validate first whether the assertion contains a call to a method under test. If yes, we should extract it.
* */
public TestCaseProcessor(String testDir, boolean logAssert) {
this.testDir = testDir;
this.logAssert = logAssert;
}
public boolean isToBeProcessed(CtMethod candidate) {
return candidate.getPosition().toString().contains(testDir);
}
@Override
public void process(CtMethod method) {
List<CtInvocation> stmts = Query.getElements(method, new TypeFilter(CtInvocation.class));
for(CtInvocation invocation: stmts){
try {
if (isAssert(invocation)) {
if(invocation.getParent() instanceof CtCase) {
CtCase ctCase = (CtCase) invocation.getParent();
int index = ctCase.getStatements().indexOf(invocation);
getArgs(invocation).stream()
.forEach(arg -> {
if(logAssert && !isArrayAccess(arg)) {
ctCase.getStatements().add(index, buildLogStatement(arg));
} else {
if(!(arg instanceof CtVariableAccess) && !(arg instanceof CtFieldAccess)) {
ctCase.getStatements().add(index, buildVarStatement(arg));
}
}
});
ctCase.getStatements().remove(invocation);
} else {
CtBlock block = (CtBlock) invocation.getParent();
getArgs(invocation).stream()
.forEach(arg -> {
if(logAssert && !isArrayAccess(arg)) {
invocation.insertBefore(buildLogStatement(arg));
} else {
if(!(arg instanceof CtVariableAccess) && !(arg instanceof CtFieldAccess)) {
invocation.insertBefore(buildVarStatement(arg));
}
}
});
block.removeStatement(invocation);
}
}
} catch (Exception e) {}
}
if(logAssert) {
if (!method.getModifiers().contains(ModifierKind.STATIC)) {
List<CtAssignment> assignments = Query.getElements(method, new TypeFilter(CtAssignment.class));
for (CtAssignment assignment : assignments) {
if (!(assignment.getParent() instanceof CtLoop) && !isArrayAccess(assignment.getAssigned())) {
try {
assignment.insertAfter(logAssignment(assignment.getAssigned()));
} catch (Exception e) {
}
}
}
List<CtLocalVariable> vars = Query.getElements(method, new TypeFilter(CtLocalVariable.class));
for (CtLocalVariable var : vars) {
if (var.getDefaultExpression() != null && !(var.getParent() instanceof CtLoop)) {
var.insertAfter(logLocalVar(var));
}
}
}
}
}
protected CtCodeSnippetStatement buildVarStatement(CtElement arg) {
CtCodeSnippetStatement stmt = new CtCodeSnippetStatementImpl();
stmt.setValue("Object o" + monitorPointCount + " = " + arg.toString());
monitorPointCount++;
return stmt;
}
protected CtCodeSnippetStatement logLocalVar(CtLocalVariable var) {
int id = ProcessorUtil.idFor(var.getPosition().getLine() + "_" + var.getReference());
return buildSnippet(id, var.getSimpleName());
}
protected CtCodeSnippetStatement logAssignment(CtElement expression) {
int id = ProcessorUtil.idFor(expression.getPosition().getLine() + "_" + expression.toString());
return buildSnippet(id, expression.toString());
}
protected CtCodeSnippetStatement buildSnippet(int id, String expression) {
monitorPointCount++;
CtCodeSnippetStatement stmt = new CtCodeSnippetStatementImpl();
String snippet = getLogName() + ".logAssertArgument(Thread.currentThread()," + id + ","+ expression + ")";
stmt.setValue(snippet);
return stmt;
}
protected List<CtElement> getArgs(CtInvocation invocation) {
List<CtElement> list = new ArrayList<>();
for(Object arg : invocation.getArguments()) {
if(!(arg instanceof CtLiteral)) {
CtElement i = (CtElement)arg;
list.add(i);
}
}
return list;
}
protected boolean isArrayAccess(CtElement element) {
return element instanceof CtArrayAccess;
}
protected CtCodeSnippetStatement buildLogStatement(CtElement arg) {
int id = ProcessorUtil.idFor(arg.getPosition().getLine() + "_" + arg.toString());
return buildSnippet(id, arg.toString());
}
}