package ca.uwaterloo.ece.qhanam.jrsrepair.mutation;
import ca.uwaterloo.ece.qhanam.jrsrepair.DocumentASTRewrite;
import ca.uwaterloo.ece.qhanam.jrsrepair.SourceStatement;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jface.text.IDocument;
import java.util.HashMap;
public abstract class Mutation {
protected HashMap<String, DocumentASTRewrite> sourceMap;
protected DocumentASTRewrite docrwt;
protected SourceStatement faulty;
protected SourceStatement seed;
protected IDocument document;
protected ASTRewrite rewrite;
private boolean mutated;
/**
* Creates a new Mutation object.
* @param sourceMap The map of source file paths to source file contents.
* @param faulty A potentially faulty statement.
* @param seed A seed statement (from somewhere in the program source).
*/
public Mutation(HashMap<String, DocumentASTRewrite> sourceMap, SourceStatement faulty, SourceStatement seed){
this.docrwt = sourceMap.get(faulty.sourceFile);
this.rewrite = docrwt.rewriter;
this.document = docrwt.document;
this.sourceMap = sourceMap;
this.faulty = faulty;
this.seed = seed;
this.mutated = false;
}
/**
* Uses the seed statement to apply a mutation to the faulty statement.
* @throws Exception
*/
public void mutate() throws Exception {
if(mutated) throw new Exception("A mutate operation has allready been applied. Must call undo() before mutating again.");
/* The subclass will perform its mutation. */
this.concreteMutate();
this.mutated = true;
}
/**
* Each concrete mutator will perform its own mutation to the AST and
* write the new AST to a document in DocumentASTRewrite.
* @throws Exception
*/
protected abstract void concreteMutate() throws Exception;
/**
* Undoes the mutation that was applied in mutate().
*
* This will undo both the change to the text file (Document) as
* well as the change to the AST.
*
* Best used with memento pattern.
*/
public void undo() throws Exception {
if(!mutated) throw new Exception("The mutate operation has not been applied. Must call mutate() before undo().");
/* Undo the operation applied to the AST. */
this.concreteUndo();
/* Set the status to not mutated. */
this.mutated = false;
/* Relinquish use of the statements. */
this.faulty.inUse = false;
if(this.seed != null) this.seed.inUse = false;
}
/**
* Each concrete mutator must also be able to undo its mutation. Because
* mutation operations are recursive, the concrete mutator must undo its
* own AST mutation, then re-write the document.
* @throws Exception
*/
protected abstract void concreteUndo() throws Exception;
/**
* Returns the document modified by the mutation.
* @return
*/
public DocumentASTRewrite getRewriter() throws Exception{
if(!mutated) throw new Exception("No mutation operation has been applied. Must call mutate() before getMutatedDocument().");
return this.docrwt;
}
/**
* Returns true if a mutation operation has been applied.
*/
public boolean mutated(){
return this.mutated;
}
@Override
public String toString(){
String s = "\nFaulty = " + this.faulty.sourceFile + "@" + this.faulty.statement.getStartPosition() + ": " + this.faulty.statement + "\n\n";
s += "Seed = ";
if(this.seed == null) s += "null" + ": " + "\n============================\n";
else s += this.seed.sourceFile + "@" + this.seed.statement.getStartPosition() + ": " + this.seed.statement + "\n============================\n";
return s;
}
}