package fr.inria.diversify.processor.test;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.TypeFilter;
import java.util.*;
/* This processor is meant to replace all literal values in test cases by other literal values
* */
public class TestDataMutator extends TestProcessor {
public static int dataCount = 0;
public void process(CtMethod method) {
try{
//get the list of literals in the method
List<CtLiteral> l = Query.getElements(method, new TypeFilter(CtLiteral.class));
//this index serves to replace ith literal is replaced by zero in the ith clone of the method
int lit_index = 0;
for(CtLiteral lit : l) {
if (!literalInAssert(lit) && !isCase(lit)) {
if (lit.getValue() instanceof Number) {
createNumberMutant(method, lit, lit_index);
} if(lit.getValue() instanceof String) {
createStringMutant(method, lit, lit_index);
} else {
dataCount++;
//clone the method
CtMethod cloned_method = cloneMethod(method, "_literalMutation");
//add the cloned method in the same class as the original method
((CtClass) method.getDeclaringType()).addMethod(cloned_method);
//get the lit_indexth literal of the cloned method
CtLiteral literal = Query.getElements(cloned_method, new TypeFilter<CtLiteral>(CtLiteral.class))
.get(lit_index);
//set the value of the selected literal
if (!replaceByRandom(literal)) {
((CtClass) method.getDeclaringType()).removeMethod(cloned_method);
mutatedMethod.remove(cloned_method);
}
notHarmanTest.add(cloned_method);
}
}
lit_index++;
}
}
catch(Exception e){
//let's be plastic, the transforms that work will work, for the rest 'anything goes'
}
}
protected List<CtMethod> createNumberMutant(CtMethod method, CtLiteral literal, int lit_index) {
List<CtMethod> mutants = new ArrayList<>();
for(Number literalMutated : literalMutated(literal)) {
dataCount++;
//clone the method
CtMethod cloned_method = cloneMethod(method, "_literalMutation");
//add the cloned method in the same class as the original method
((CtClass) method.getDeclaringType()).addMethod(cloned_method);
//get the lit_indexth literal of the cloned method
CtLiteral newLiteral = Query.getElements(cloned_method, new TypeFilter<CtLiteral>(CtLiteral.class))
.get(lit_index);
CtElement toReplace = newLiteral;
if(literal.getValue() instanceof Integer) {
newLiteral.setValue(literalMutated.intValue());
} else if(literal.getValue() instanceof Long) {
newLiteral.setValue(literalMutated.longValue());
} else if(literal.getValue() instanceof Double) {
newLiteral.setValue(literalMutated.doubleValue());
} else if(literal.getValue() instanceof Short) {
newLiteral.setValue(literalMutated.shortValue());
} else if(literal.getValue() instanceof Float) {
newLiteral.setValue(literalMutated.floatValue());
} else if(literal.getValue() instanceof Byte) {
newLiteral.setValue(literalMutated.byteValue());
}
if(literal.getParent() instanceof CtUnaryOperator) {
CtUnaryOperator parent = (CtUnaryOperator)literal.getParent();
if(parent.getKind().equals(UnaryOperatorKind.NEG)) {
toReplace = parent;
}
}
toReplace.replace(newLiteral);
mutants.add(cloned_method);
}
return mutants;
}
protected List<CtMethod> createStringMutant(CtMethod method, CtLiteral literal, int lit_index) {
List<CtMethod> mutants = new ArrayList<>();
String string = ((String) literal.getValue());
Random r = new Random();
String[] array = new String[3];
int index = r.nextInt(string.length() -2) +1;
array[0] = string.substring(0,index - 1) + (char)r.nextInt(256) + string.substring(index , string.length());
index = r.nextInt(string.length() -2) +1;
array[1] = string.substring(0,index) + (char)r.nextInt(256) + string.substring(index, string.length());
index = r.nextInt(string.length() -2) +1;
array[2] = string.substring(0,index ) + string.substring(index +1, string.length());
for(String literalMutated : array) {
dataCount++;
//clone the method
CtMethod cloned_method = cloneMethod(method, "_literalMutation");
//add the cloned method in the same class as the original method
((CtClass) method.getDeclaringType()).addMethod(cloned_method);
//get the lit_indexth literal of the cloned method
CtLiteral newLiteral = Query.getElements(cloned_method, new TypeFilter<CtLiteral>(CtLiteral.class))
.get(lit_index);
newLiteral.setValue(literalMutated);
notHarmanTest.add(cloned_method);
mutants.add(cloned_method);
}
return mutants;
}
protected Set<? extends Number> literalMutated(CtLiteral literal) {
Set<Number> values = new HashSet<>();
Double value = ((Number) literal.getValue()).doubleValue();
values.add(value + 1);
values.add(value - 1);
values.add(value / 2);
// values.add(value * 2);
return values;
}
protected boolean literalInAssert(CtLiteral lit) {
CtInvocation invocation = lit.getParent(CtInvocation.class);
while (invocation != null && !(invocation.getParent() instanceof CtBlock)) {
invocation = invocation.getParent(CtInvocation.class);
}
if(invocation == null)
return false;
return isAssert(invocation);
}
protected boolean replaceByRandom(CtLiteral literal) {
Object value = literal.getValue();
CtElement toReplace = literal;
CtLiteral newLiteral = literal.getFactory().Core().createLiteral();
newLiteral.setTypeCasts(literal.getTypeCasts());
if(value instanceof Boolean) {
Boolean b = (Boolean) value;
if(b) {
if(!(literal.getParent() instanceof CtWhile)) {
newLiteral.setValue(false);
return false;
}
} else {
newLiteral.setValue(true);
}
}
if(newLiteral.getValue() == null) {
return false;
}
toReplace.replace(newLiteral);
return true;
}
protected boolean isCase(CtLiteral literal) {
return literal.getParent(CtCase.class) != null;
}
public List<CtMethod> apply(CtMethod method) {
List<CtMethod> methods = new ArrayList<>();
try{
//get the list of literals in the method
List<CtLiteral> l = Query.getElements(method, new TypeFilter(CtLiteral.class));
//this index serves to replace ith literal is replaced by zero in the ith clone of the method
int lit_index = 0;
for(CtLiteral lit : l) {
if (!literalInAssert(lit) && !isCase(lit)) {
if (lit.getValue() instanceof Number) {
methods.addAll(createNumberMutant(method, lit, lit_index));
} if(lit.getValue() instanceof String) {
methods.addAll(createStringMutant(method, lit, lit_index));
} else {
dataCount++;
//clone the method
CtMethod cloned_method = cloneMethod(method, "_literalMutation");
//get the lit_indexth literal of the cloned method
CtLiteral literal = Query.getElements(cloned_method, new TypeFilter<CtLiteral>(CtLiteral.class))
.get(lit_index);
//set the value of the selected literal
replaceByRandom(literal);
methods.add(cloned_method);
}
}
lit_index++;
}
}
catch(Exception e){}
return methods;
}
}