edu.odu.cs.cs350.yellow1.mutationgeneration.JavaFile.java Source code

Java tutorial

Introduction

Here is the source code for edu.odu.cs.cs350.yellow1.mutationgeneration.JavaFile.java

Source

/**
 *   Copyright (C) 2014  Michael Soliman
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see http://www.gnu.org/licenses/
 */

package edu.odu.cs.cs350.yellow1.mutationgeneration;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * Antlr Library imports
 */
import org.antlr.runtime.TokenRewriteStream;
import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_ctx;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

/**
 * antlr generated java files imports
 */
import edu.odu.cs.cs350.yellow1.grammar.java.JavaLexer;
import edu.odu.cs.cs350.yellow1.grammar.java.JavaParser;

/**
 * apache common lang imports
 */
import org.apache.commons.lang3.math.NumberUtils;

/**
 log4j imports
 */
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 
 * @author Michael Soliman <msoliman@cs.odu.edu> This object is responsible for
 *         generating mutuants for given javafile
 * 
 * 
 *         It is expected from this class to generate mutations that is
 *         incorrect in syntax and leads to compilation failure
 *
 */
public class JavaFile implements ICommonMutationOperations {
    private String filePath = new String();
    private String fileContents = new String();
    MutantCaseVector mvc = null;
    /** see the constructor */

    private static final Logger log = LogManager.getLogger(JavaFile.class);

    /**
     * @return file name
     */
    public String getFileName() {
        return Paths.get(this.filePath).getFileName().toString();
    }

    /**
     * Initializes new mutant case vector
     */
    public JavaFile() {
        mvc = new MutantCaseVector();
    }

    /**
     * if one have a group of mutant cases, one can use it and to it more mutant
     * cases
     * 
     * @param _mvc
     */

    public JavaFile(MutantCaseVector _mvc) {
        this.mvc = _mvc;
    }

    /**
     * @author msoliman
     *
     */
    public enum EOL {
        DOS, NIX;
    }

    /**
     * changes file EOL to Windows/Dos Format
     */
    public void setWindowsLineEnd() {
        /**
         * preserve original CRLFs
         */
        this.fileContents = this.fileContents.replaceAll("\\r\\n", "cat45413xdsfgds");

        /**
         * Changes all EOLs to CRLFs
         */
        this.fileContents = this.fileContents.replaceAll("\\n", "cat45413xdsfgds");
        this.fileContents = this.fileContents.replaceAll("\\r", "cat45413xdsfgds");

        /**
         * Restore original CRLFs
         */
        this.fileContents = this.fileContents.replaceAll("cat45413xdsfgds", "\r\n");
    }

    public void setNixLineEnd() {
        this.fileContents = this.fileContents.replaceAll("\\r\\n", "\n");
        this.fileContents = this.fileContents.replaceAll("\\r", "\n");
    }

    /**
     * 
     * @return a vector for Mutant Cases
     */
    public MutantCaseVector getMutantCaseVector() {
        return mvc;
    }

    /**
     * 
     * @param i
     *            the index of the mutant case
     * @return one mutant case given its index
     */
    public MutantCase getMutantCase(int i) {
        return mvc.get(i);
    }

    public MutantCase.Operations getMutantCaseOperations(int i) {
        return mvc.get(i).applyAgainst(fileContents);
    }

    /**
     * Open the file and load its contents to this class
     * 
     * @param path
     *            path the absolute path or relative path
     * @param provides
     *            encoding the file encoding method
     * @throws IOException
     */

    public void readFile(String path, Charset encoding) throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(path));
        this.fileContents = new String(encoded, encoding);
        this.filePath = path;
    }

    /**
     * Open the file and load its contents to this class
     * 
     * @param path
     *            the absolute path or relative path
     * @throws IOException
     */
    public void readFile(String path) throws IOException {
        readFile(path, Charset.defaultCharset());

    }

    /**
     * Open the file and load its contents to this class then forces the line
     * endings to NIX or DOS
     * 
     * @param path
     *            the absolute path or relative path
     * @throws IOException
     */
    public void readFile(String path, EOL a) throws IOException {
        readFile(path, Charset.defaultCharset());
        if (a == EOL.DOS)
            this.setWindowsLineEnd();
        else if (a == EOL.NIX)
            this.setNixLineEnd();

    }

    /**
     * change tokens and add the mutuant cases to the mutant case vector
     * 
     * @param originalthe
     *            original token
     * 
     * @param by
     *            the replacement token
     * 
     * @param operation
     *            the operation name
     * 
     * 
     *            it is acceptable int y = +10; to be converted to int y = /10;
     *            because it will make the mutant project compilation fail and
     *            this mutation will be discarded because the compilation has
     *            failed
     * 
     * 
     */
    private boolean applyTokenTransformation(String original, String by, String operation) throws Exception {
        ANTLRInputStream input = new ANTLRInputStream(fileContents.toString());
        JavaLexer lexer = new JavaLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        JavaParser parser = new JavaParser(tokens);

        ParseTree tree = parser.compilationUnit();

        TokenRewriteStream trs = new TokenRewriteStream();

        ParseTreeWalker walker = new ParseTreeWalker(); // create standard

        for (Integer i = 0; i < tokens.size(); i++) {
            if (tokens.get(i).getText().toString().equals(original)) {
                int startIndex = tokens.get(i).getStartIndex();
                int stopIndex = tokens.get(i).getStopIndex() + 1;
                mvc.add(startIndex, stopIndex, by);

            }
        }
        return true;
    }

    /**
     * 
     * @param text
     * @return if the token was in the shape of "string" it returns true
     */
    private boolean isTokenString(String text) {
        return String.valueOf(text.charAt(0)).equals('"')
                && String.valueOf(text.charAt(text.length() - 1)).equals('"');
    }

    /**
     * returns the file contents which have loaded
     */
    public String toString() {
        return fileContents;
    }

    /**
     * Changes addition with subtraction and add the mutant cases to the mutant
     * case vector
     */
    @Override
    public void addSub() {
        try {
            String original = "" + '+';
            String by = "" + '-';
            applyTokenTransformation(original, by, "addSub");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Changes addition with multiplication
     * 
     */
    @Override
    public void addMul() {
        try {
            String original = "" + '+';
            String by = "" + '*';
            applyTokenTransformation(original, by, "addMul");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Changes addition with division
     */
    @Override
    public void addDiv() {
        try {
            String original = "" + '+';
            String by = "" + '/';
            applyTokenTransformation(original, by, "addDiv");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Changes subtraction with addition
     */
    @Override
    public void subAdd() {
        try {
            String original = "" + '-';
            String by = "" + '+';
            applyTokenTransformation(original, by, "subAdd");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void subMul() {
        try {
            String original = "" + '-';
            String by = "" + '*';
            applyTokenTransformation(original, by, "subMul");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void subDiv() {
        try {
            String original = "" + '-';
            String by = "" + '/';
            applyTokenTransformation(original, by, "subDiv");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void mulAdd() {
        try {
            String original = "" + '*';
            String by = "" + '+';
            applyTokenTransformation(original, by, "mulAdd");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void mulSub() {
        try {
            String original = "" + '*';
            String by = "" + '-';
            applyTokenTransformation(original, by, "mulSub");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void mulDiv() {
        try {
            String original = "" + '*';
            String by = "" + '/';
            applyTokenTransformation(original, by, "mulDiv");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void divAdd() {
        try {
            String original = "" + '/';
            String by = "" + '+';
            applyTokenTransformation(original, by, "divAdd");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void divSub() {
        try {
            String original = "" + '/';
            String by = "" + '-';
            applyTokenTransformation(original, by, "divSub");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void divMul() {
        try {
            String original = "" + '/';
            String by = "" + '*';
            applyTokenTransformation(original, by, "divMul");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Replaces the < to <=
     */
    @Override
    public void ltLe() {
        try {
            String original = "" + "<";
            String by = "" + "<=";
            applyTokenTransformation(original, by, "ltLe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces the < to >
     */
    @Override
    public void ltGt() {
        try {
            String original = "" + "<";
            String by = "" + ">";
            applyTokenTransformation(original, by, "ltLe");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Replaces < by >=
     */
    @Override
    public void ltGe() {
        try {
            String original = "" + "<";
            String by = "" + ">=";
            applyTokenTransformation(original, by, "ltLe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces < by ==
     */
    @Override
    public void ltEqual() {
        try {
            String original = "" + "<";
            String by = "" + "==";
            applyTokenTransformation(original, by, "ltEqual");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Replaces > by <
     */
    @Override
    public void gtLt() {
        try {
            String original = "" + ">";
            String by = "" + "<";
            applyTokenTransformation(original, by, "gtLt");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces > by <=
     */
    @Override
    public void gtle() {
        try {
            String original = "" + ">";
            String by = "" + "<=";
            applyTokenTransformation(original, by, "gtle");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces > by >=
     */
    @Override
    public void gtGe() {
        try {
            String original = "" + ">";
            String by = "" + ">=";
            applyTokenTransformation(original, by, "gtGe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces > by ==
     */
    @Override
    public void gtEqual() {
        try {
            String original = "" + ">";
            String by = "" + "==";
            applyTokenTransformation(original, by, "gtEqual");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces >= by <
     */
    @Override
    public void geLt() {
        try {
            String original = "" + ">=";
            String by = "" + "<";
            applyTokenTransformation(original, by, "geLt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Replaces >= by >
     */
    @Override
    public void geGt() {
        try {
            String original = "" + ">=";
            String by = "" + ">";
            applyTokenTransformation(original, by, "geGt");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces >= by <=
     */
    @Override
    public void geLe() {
        try {
            String original = "" + ">=";
            String by = "" + "<=";
            applyTokenTransformation(original, by, "geLe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces >= by ==
     */
    @Override
    public void geEqual() {
        try {
            String original = "" + ">=";
            String by = "" + "==";
            applyTokenTransformation(original, by, "geEqual");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * replaces <= to <
     */
    @Override
    public void leLt() {
        try {
            String original = "" + "<=";
            String by = "" + "<";
            applyTokenTransformation(original, by, "leLt");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces <= by >
     */
    @Override
    public void leGt() {
        try {
            String original = "" + "<=";
            String by = "" + ">";
            applyTokenTransformation(original, by, "leGt");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces <= by >=
     */
    @Override
    public void leGe() {
        try {
            String original = "" + "<=";
            String by = "" + ">=";
            applyTokenTransformation(original, by, "leGe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces <= by ==
     */
    @Override
    public void leEqual() {
        try {
            String original = "" + "<=";
            String by = "" + "==";
            applyTokenTransformation(original, by, "leEqual");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces == by <
     */
    @Override
    public void equalLt() {
        try {
            String original = "" + "==";
            String by = "" + "<";
            applyTokenTransformation(original, by, "equalLt");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces == by >
     */
    @Override
    public void equalGt() {
        try {
            String original = "" + "==";
            String by = "" + ">";
            applyTokenTransformation(original, by, "equalGt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Replaces == by >=
     */
    @Override
    public void equalGe() {
        try {
            String original = "" + "==";
            String by = "" + ">=";
            applyTokenTransformation(original, by, "equalGe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Replaces == by <=
     */
    @Override
    public void equalLe() {
        try {
            String original = "" + "==";
            String by = "" + "<=";
            applyTokenTransformation(original, by, "equalLe");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Changes boolean and operator with boolean or operator
     */
    @Override
    public void andOr() {
        try {
            String original = "" + "&&";
            String by = "" + "||";
            applyTokenTransformation(original, by, "andOr");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * changes boolean Or operator with boolean And operator
     */
    @Override
    public void orAnd() {
        try {
            String original = "" + "||";
            String by = "" + "&&";
            applyTokenTransformation(original, by, "orAnd");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void removeNot() {
        // TODO Auto-generated method stub

    }

    /**
     * @param blockstart
     *            accepts if or while
     * 
     * @param set
     *            accepts true or false
     * 
     *            Replaces the condition after [blockstart] by [set]
     */
    private void applyConditionTransformation(String blockstart, String set) {
        int lparen = 0;
        int rparen = 0;
        int startIndex = -1;
        int stopIndex = -1;
        boolean ifLock = false;

        ANTLRInputStream input = new ANTLRInputStream(fileContents.toString());
        JavaLexer lexer = new JavaLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        JavaParser parser = new JavaParser(tokens);
        ParseTree tree = parser.compilationUnit();
        ParseTreeWalker walker = new ParseTreeWalker(); // create standard
        for (Integer i = 0; i < tokens.size(); i++) {

            if (tokens.get(i).getText().toString().equals(blockstart)) {
                ifLock = true;
            }

            if (ifLock == true && tokens.get(i).getText().toString().equals("(")) {
                lparen++;

                if (startIndex == -1)
                    startIndex = tokens.get(i).getStartIndex();
            }

            if (ifLock == true && tokens.get(i).getText().toString().equals(")"))

            {

                rparen++;

            }

            if (lparen != 0 && rparen != 0 && lparen == rparen && ifLock == true) {
                ifLock = false;
                lparen = 0;
                rparen = 0;

                stopIndex = tokens.get(i).getStopIndex() + 1;

                String by = "(" + set + ")";

                this.mvc.add(startIndex, stopIndex, by);
                startIndex = -1;
                stopIndex = -1;
            }

        }

    }

    /**
     * this function loads the mutation log and intialize the class
     * 
     * @param mutationLogFilePath
     *            the file path of the mutation log
     * @param eol
     *            is not related to the mutation log by any way. It is related
     *            to how one wants to read the source code file.
     * @throws Exception
     */
    public void readMutationsLog(String mutationLogFilePath, EOL eol) throws Exception {
        /**
         * remove all line endings
         */
        String mutationsLog = new String(Files.readAllBytes(Paths.get(mutationLogFilePath))).replaceAll("\\n", "")
                .replaceAll("\\r", "");
        /**
         * set the file path of the file
         */
        this.filePath = mutationsLog.split(";;")[0].split(",,")[0];
        /**
         * read the file and set the file contents
         */
        this.readFile(this.filePath, eol);

        String[] lines = mutationsLog.split(";;");
        for (int i = 0; i < lines.length; i++) {
            String[] parts = lines[i].split(",,");
            if (!this.filePath.equals(parts[0].toString()))
                throw new Exception("M-S corrupted mutation log file ");

            mvc.add((int) Integer.parseInt(parts[1].toString()), (int) Integer.parseInt(parts[2].toString()),
                    parts[4].toString());
        }

    }

    /**
     * 
     * @param filePath
     *            relative or absolute file path where one wants the report to
     *            be saved. one must apply the file name within the file path
     * @param eol
     *            Line ending either DOS or *NIX. It is asks one how does one
     *            want the mutation log line ending format to be either nix or
     *            dos.
     * 
     * @throws Exception
     */
    public void writeMutationsLog(String filePath, EOL eol) throws Exception {
        java.lang.StringBuilder sb = new java.lang.StringBuilder();
        for (int i = 0; i < mvc.getSize(); i++) {
            sb.append(this.filePath);
            sb.append(",,");
            sb.append(this.getMutantCase(i).getStartIndex());
            sb.append(",,");
            sb.append(this.getMutantCase(i).getStopIndex());
            sb.append(",,");
            sb.append(this.getMutantCaseOperations(i).getOriginalToken());
            sb.append(",,");
            sb.append(this.getMutantCase(i).getReplacment());
            sb.append(";; ");
            sb.append(i + 1);
            if (i < mvc.getSize() - 1)
                if (eol == EOL.DOS)
                    sb.append("\r\n");
                else if (eol == EOL.NIX)
                    sb.append("\n");

            BufferedWriter output = new BufferedWriter(new FileWriter(new File(filePath)));
            output.write(sb.toString());
            output.close();
        }
        log.debug(sb.toString());
    }

    @Override
    public void ifConditionTrue() {
        this.applyConditionTransformation("if", "true");
    }

    @Override
    public void ifConditionFalse() {
        this.applyConditionTransformation("if", "false");

    }

    @Override
    public void whileConditionTrue() {
        this.applyConditionTransformation("while", "true");

    }

    @Override
    public void whileConditionFalse() {
        this.applyConditionTransformation("while", "false");

    }

    /**
     * executes all the mutations operations sequentially
     */
    @Override
    public void executeAll() {
        this.addSub();
        this.addMul();
        this.addDiv();

        this.subAdd();
        this.subMul();
        this.subDiv();

        this.mulAdd();
        this.mulSub();
        this.mulDiv();

        this.divAdd();
        this.divSub();
        this.divMul();

        // < <=
        this.ltLe();

        // < >
        this.ltGt();

        // < >=
        this.ltGe();

        // < ==
        this.ltEqual();

        // > <
        this.gtLt();

        // > <=
        this.gtle();

        // > >=
        this.gtGe();

        // > ==
        this.gtEqual();

        // >= <
        this.geLt();

        // >= >
        this.geGt();

        // >= <=
        this.geLe();

        // >= ==
        this.geEqual();

        // <= <
        this.leLt();

        // <= >
        this.leGt();

        // <= >=
        this.leGe();

        // <= ==
        this.leEqual();

        // == <
        this.equalLt();

        // == >
        this.equalGt();

        // == >=
        this.equalGe();

        // == <=
        this.equalLe();

        this.andOr();
        this.orAnd();
        this.removeNot();

        this.ifConditionTrue();
        this.ifConditionFalse();

        this.whileConditionTrue();
        this.whileConditionFalse();
        this.whileIf();
        this.constantPlusOne();
        this.constantMinusOne();
        this.constantBy1001();
        this.constantBy0999();
    }

    /**
     * changes while token to If
     */
    @Override
    public void whileIf() {
        try {
            String original = "while";
            String by = "if";
            applyTokenTransformation(original, by, "whileIf");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void constantOperations(String required) {
        ANTLRInputStream input = new ANTLRInputStream(fileContents.toString());
        JavaLexer lexer = new JavaLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        JavaParser parser = new JavaParser(tokens);

        ParseTree tree = parser.compilationUnit();

        TokenRewriteStream trs = new TokenRewriteStream();

        ParseTreeWalker walker = new ParseTreeWalker(); // create standard

        for (Integer i = 0; i < tokens.size(); i++) {
            if (NumberUtils.isNumber(tokens.get(i).getText().toString())) {
                int startIndex = tokens.get(i).getStartIndex();
                int stopIndex = tokens.get(i).getStopIndex() + 1;
                String by = fileContents.substring(startIndex, stopIndex) + required;
                mvc.add(startIndex, stopIndex, by);
            }
        }
    }

    /**
     * Generate mutant cases where every constant has one added to it
     */
    @Override
    public void constantPlusOne() {
        this.constantOperations(" + 1");

    }

    /**
     * Generate mutant cases where every constant has one subtracted from it
     */
    @Override
    public void constantMinusOne() {
        this.constantOperations(" - 1");
    }

    /**
     * Generate mutant cases where every constant has 1.001 multiplied to it
     */
    @Override
    public void constantBy1001() {
        this.constantOperations(" * 1.001");

    }

    /**
     * Generate mutant cases where every constant has 0.999 multiplied to it
     */
    @Override
    public void constantBy0999() {
        this.constantOperations(" * 0.999");

    }
}