de.unisb.cs.st.javalanche.mutation.util.AddOffutt96Sufficient.java Source code

Java tutorial

Introduction

Here is the source code for de.unisb.cs.st.javalanche.mutation.util.AddOffutt96Sufficient.java

Source

/*
 * Copyright (C) 2011 Saarland University
 * 
 * This file is part of Javalanche.
 * 
 * Javalanche is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Javalanche 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser Public License
 * along with Javalanche.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.unisb.cs.st.javalanche.mutation.util;

import static org.objectweb.asm.Opcodes.*;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.objectweb.asm.Opcodes;

import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.arithmetic.AbstractArithmeticMethodAdapter;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.arithmetic.ReplaceMap;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.negateJumps.AbstractNegateJumpsAdapter;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.negateJumps.JumpReplacements;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.negateJumps.NegateJumpsMethodAdapter;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.replaceIntegerConstant.PossibilitiesRicMethodAdapter;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.replaceIntegerConstant.PossibilitiesRicMethodAdapter.TypeInfo;
import de.unisb.cs.st.javalanche.mutation.properties.ConfigurationLocator;
import de.unisb.cs.st.javalanche.mutation.results.Mutation;
import de.unisb.cs.st.javalanche.mutation.results.Mutation.MutationType;
import de.unisb.cs.st.javalanche.mutation.results.MutationCoverageFile;
import de.unisb.cs.st.javalanche.mutation.results.persistence.HibernateUtil;
import de.unisb.cs.st.javalanche.mutation.results.persistence.QueryManager;

import static de.unisb.cs.st.javalanche.mutation.bytecodeMutations.negateJumps.NegateJumpsMethodAdapter.*;
import static de.unisb.cs.st.javalanche.mutation.bytecodeMutations.arithmetic.AbstractArithmeticMethodAdapter.*;

/**
 * 
 * @author David Schuler
 * 
 */
public class AddOffutt96Sufficient {

    private static final Logger logger = Logger.getLogger(AddOffutt96Sufficient.class);

    private static Random r = new Random();

    private static SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

    private static final boolean createAllMutations = true;

    private static final int[] aorIntOpcodes = new int[] { IADD, ISUB, IMUL, IDIV, IREM, REMOVE_LEFT_VALUE_SINGLE,
            REMOVE_RIGHT_VALUE_SINGLE };
    // ISHL, ISHR, IUSHR, IAND, IOR, IXOR };

    private static final int[] aorLongOpcodes = new int[] { LADD, LSUB, LMUL, LDIV, LREM, REMOVE_RIGHT_VALUE_DOUBLE,
            REMOVE_LEFT_VALUE_DOUBLE };
    // , LAND LOR, LXOR };

    private static final int[] aorFloatOpcodes = new int[] { FADD, FSUB, FMUL, FDIV, FREM, REMOVE_LEFT_VALUE_SINGLE,
            REMOVE_RIGHT_VALUE_SINGLE };

    private static final int[] aorDoubleOpcodes = new int[] { DADD, DSUB, DMUL, DDIV, DREM,
            REMOVE_RIGHT_VALUE_DOUBLE, REMOVE_LEFT_VALUE_DOUBLE };
    private static final int[] longShiftOpcodes = new int[] { LSHL, LSHR, LUSHR };

    public static final int[] rorSingleOpcodes = new int[] { IFEQ, IFNE, IFLT, IFGT, IFLE, IFGE, POP_ONCE_TRUE,
            POP_ONCE_FALSE };

    public static final int[] rorObjectNullOpcodes = new int[] { IFNULL, IFNONNULL, POP_ONCE_TRUE, POP_ONCE_FALSE }; // Not needed as this
    // replacement
    // corresponds to the
    // Javalanche standard replacement

    public static final int[] rorObjectCompareOpcodes = new int[] { IF_ACMPEQ, IF_ACMPNE }; // Not needed (see above)

    public static final int[] rorIntegerCompareOpcodes = new int[] { IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGT,
            IF_ICMPLE, IF_ICMPGE, POP_TWICE_TRUE, POP_TWICE_FALSE };

    public static final int[] lorIntegerOpcodes = new int[] { IAND, IOR, IXOR, REMOVE_LEFT_VALUE_SINGLE,
            REMOVE_RIGHT_VALUE_SINGLE };
    public static final int[] lorLongOpcodes = new int[] { LOR, LAND, LXOR, REMOVE_RIGHT_VALUE_DOUBLE,
            REMOVE_LEFT_VALUE_DOUBLE };

    public static final List<String> shiftOpcodes = Arrays.asList(ISHL + "", ISHR + "", LSHL + "", LSHR + "",
            IUSHR + "", LUSHR + "");

    public static void addUoiForConstants() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", MutationType.REPLACE_CONSTANT);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        for (Mutation m : results) {
            // System.out.println("Mutation " + m);
            if (checkCovered(m) && m.getBaseMutationId() == null) {
                String addInfo = m.getAddInfo();
                String origValue = getRicOriginalValue(addInfo);
                TypeInfo type = getTypeInfo(addInfo);
                String[] replaceValues = null;
                if (type.equals(TypeInfo.DOUBLE)) {
                    Double d = Double.valueOf(origValue);
                    replaceValues = new String[] { -d + "" };
                } else if (type.equals(TypeInfo.FLOAT)) {
                    Float f = Float.valueOf(origValue);
                    replaceValues = new String[] { -f + "" };

                } else if (type.equals(TypeInfo.INT)) {
                    Integer i = Integer.valueOf(origValue);
                    replaceValues = new String[] { -i + "", ~i + "" };
                } else if (type.equals(TypeInfo.LONG)) {
                    Long l = Long.valueOf(origValue);
                    replaceValues = new String[] { -l + "", ~l + "" };
                } else {
                    throw new RuntimeException("Did not expect value of type " + type);
                }

                boolean baseMutationUsed = false;
                for (String replaceVal : replaceValues) {

                    if (baseMutationUsed) {
                        Mutation m2 = Mutation.copyMutation(m);
                        PossibilitiesRicMethodAdapter.setAddInfo(m2, origValue, replaceVal, type);
                        if (QueryManager.getMutationOrNull(m2) == null) {
                            // System.out.println("New mutation " + m2);
                            QueryManager.saveMutation(m2);

                            MutationCoverageFile.addDerivedMutation(m.getId(), m2.getId());
                        }
                    } else {
                        Mutation m2 = Mutation.copyMutation(m);
                        PossibilitiesRicMethodAdapter.setAddInfo(m2, origValue, replaceVal, type);
                        if (QueryManager.getMutationOrNull(m2) == null) {
                            PossibilitiesRicMethodAdapter.setAddInfo(m, origValue, replaceVal, type);
                            // QueryManager.updateMutation(m, null);
                            // System.out.println("Updated mutation " + m);
                            session.update(m);
                            baseMutationUsed = true;
                        }
                    }
                }
            } else {
                session.delete(m);
            }
            session.flush();
        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();
    }

    private static TypeInfo getTypeInfo(String addInfo) {
        int start = addInfo.indexOf('(');
        int end = addInfo.indexOf(')');
        String sub = addInfo.substring(start + 1, end);
        return TypeInfo.valueOf(sub);
    }

    public static boolean checkCovered(Mutation m) {
        if (createAllMutations) {
            return true;
        }
        return MutationCoverageFile.isCovered(m.getId());
    }

    private static String getRicOriginalValue(String addInfo) {
        String s = addInfo.substring("Replace ".length());
        int end = s.indexOf(' ');
        String result = s.substring(0, end);
        return result;
    }

    // TODO currently only covered mutations are considered
    public static void addRorMutations() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", MutationType.NEGATE_JUMP);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        for (Mutation m : results) {
            if (checkCovered(m) && m.getBaseMutationId() == null) {
                String operatorAddinfo = m.getOperatorAddInfo();
                int standardReplaceOpcode = Integer.parseInt(operatorAddinfo);
                int originalOpcode = JumpReplacements.getReplacementMap().get(standardReplaceOpcode);
                int[] rorOpcodes = getRorOpcodes(standardReplaceOpcode);
                for (int replaceOpcode : rorOpcodes) {
                    if (replaceOpcode != standardReplaceOpcode && replaceOpcode != originalOpcode) {
                        Mutation m2 = new Mutation(m.getClassName(), m.getMethodName(), m.getLineNumber(),
                                m.getMutationForLine(), m.getMutationType());
                        AbstractNegateJumpsAdapter.generateAddInfo(m2, originalOpcode, replaceOpcode);
                        logger.info("Adding mutation" + m2);
                        m2.setBaseMutationId(m.getId());
                        QueryManager.saveMutation(m2);
                        MutationCoverageFile.addDerivedMutation(m.getId(), m2.getId());

                    }
                }
            }
        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();

    }

    private static int[] getRorOpcodes(int opcode) {
        if (ArrayUtils.contains(rorSingleOpcodes, opcode)) {
            return rorSingleOpcodes;
        }
        if (ArrayUtils.contains(rorIntegerCompareOpcodes, opcode)) {
            return rorIntegerCompareOpcodes;
        }
        return new int[0];

    }

    /**
     * Adds new mutations of type REPLACE_CONSTANT for project.
     */
    public static void addReplaceConstantMutations() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", MutationType.REPLACE_CONSTANT);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        for (Mutation m : results) {
            if (checkCovered(m) && m.getBaseMutationId() == null) {
                String addInfo = m.getAddInfo();
                int originalValue = getOriginalValue(addInfo);
                System.out.println(originalValue);
                Set<Integer> values = getRandomValues(originalValue, 10);
                for (Integer val : values) {
                    Mutation m2 = new Mutation(m.getClassName(), m.getMethodName(), m.getLineNumber(),
                            m.getMutationForLine(), m.getMutationType());
                    m2.setOperatorAddInfo(val + "");
                    m2.setAddInfo("Replace " + originalValue + " with " + val);
                    m2.setBaseMutationId(m.getId());

                    logger.info("Adding mutation" + m2);
                    QueryManager.saveMutation(m2);
                    MutationCoverageFile.addDerivedMutation(m.getId(), m2.getId());
                }
            }

        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();
    }

    public static void addAorMutations() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", MutationType.ARITHMETIC_REPLACE);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        for (Mutation m : results) {
            if (checkCovered(m)
                    // for not covered
                    && m.getBaseMutationId() == null) {
                String addInfo = m.getAddInfo();
                int originalValue = getOriginalValue(addInfo);

                Set<Integer> values = getAorReplacements(originalValue);
                for (Integer val : values) {
                    Mutation m2 = new Mutation(m.getClassName(), m.getMethodName(), m.getLineNumber(),
                            m.getMutationForLine(), m.getMutationType());
                    AbstractArithmeticMethodAdapter.addInfoToMutation(m2, originalValue, val);
                    // m2.setOperatorAddInfo(val + "");
                    // m2.setAddInfo("Replace " + originalValue + " with " +
                    // val);
                    m2.setBaseMutationId(m.getId());
                    logger.info("Adding mutation" + m2);
                    QueryManager.saveMutation(m2);
                    if (m2.getId() == null) {
                        throw new RuntimeException("Got null as id for " + m2);
                    }
                    MutationCoverageFile.addDerivedMutation(m.getId(), m2.getId());
                }
            }

        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();
    }

    private static Set<Integer> getAorReplacements(int operator) {
        int[] replaceOperators = getAorReplaceOperators(operator);
        Integer standardReplaceOperator = ReplaceMap.getReplaceMap().get(operator);
        return getReplacments(operator, standardReplaceOperator, replaceOperators);
    }

    private static Set<Integer> getReplacments(int operator, int standardReplaceOperator, int[] replaceOperators) {
        Set<Integer> result = new HashSet<Integer>();
        for (int i : replaceOperators) {
            result.add(i);
        }
        result.remove(operator);
        result.remove(standardReplaceOperator);
        return result;
    }

    private static int[] getAorReplaceOperators(int operator) {
        return getContainingArray(operator, aorIntOpcodes, aorLongOpcodes, aorFloatOpcodes, aorDoubleOpcodes);

    }

    private static int[] getContainingArray(int operator, int[]... arrays) {
        for (int[] array : arrays) {
            if (ArrayUtils.contains(array, operator)) {
                return array;
            }
        }
        return new int[0];
    }

    public static void addLorMutations() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", MutationType.ARITHMETIC_REPLACE);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        for (Mutation m : results) {
            if (checkCovered(m)
                    // for not covered
                    && m.getBaseMutationId() == null) {
                String addInfo = m.getAddInfo();
                int originalValue = getOriginalValue(addInfo);

                Set<Integer> values = getLorReplacements(originalValue);
                for (Integer val : values) {
                    Mutation m2 = new Mutation(m.getClassName(), m.getMethodName(), m.getLineNumber(),
                            m.getMutationForLine(), m.getMutationType());
                    AbstractArithmeticMethodAdapter.addInfoToMutation(m2, originalValue, val);
                    // m2.setOperatorAddInfo(val + "");
                    // m2.setAddInfo("Replace " + originalValue + " with " +
                    // val);
                    m2.setBaseMutationId(m.getId());
                    logger.info("Adding mutation" + m2);
                    QueryManager.saveMutation(m2);
                    MutationCoverageFile.addDerivedMutation(m.getId(), m2.getId());
                }
            }

        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();
    }

    private static Set<Integer> getLorReplacements(int operator) {
        int[] replaceOperators = getLorReplaceOperators(operator);
        Integer standardReplaceOperator = ReplaceMap.getReplaceMap().get(operator);
        return getReplacments(operator, standardReplaceOperator, replaceOperators);
    }

    private static int[] getLorReplaceOperators(int operator) {
        return getContainingArray(operator, lorIntegerOpcodes, lorLongOpcodes);
    }

    private static Set<Integer> getRandomValues(int originalValue, int i) {
        Set<Integer> result = new HashSet<Integer>();
        while (result.size() < i) {
            int nextInt = r.nextInt();
            if (nextInt != originalValue && nextInt != 0 && nextInt != originalValue + 1
                    && nextInt != originalValue - 1) {
                result.add(nextInt);
            }
        }
        return result;
    }

    private static int getOriginalValue(String addInfo) {
        String substring = addInfo.substring("Replace ".length());
        int index = substring.indexOf(' ');
        String s = substring.substring(0, index);
        try {
            Field field = Opcodes.class.getField(s);
            int val = (Integer) field.get(null);
            return val;
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return Integer.parseInt(s);
    }

    public static void main(String[] args) {

        generateOffutt96Sufficient();
    }

    public static void generateOffutt96Sufficient() {
        addRorMutations();
        addAorMutations();
        addLorMutations();
        addUoiForConstants();
        removeUnecessaryOperators();
    }

    public static void removeUnecessaryOperators() {
        deleteMutations(MutationType.REMOVE_CALL);
        deleteMutations(MutationType.REPLACE_VARIABLE);
        deleteShiftMutations();
    }

    private static void deleteShiftMutations() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", MutationType.ARITHMETIC_REPLACE);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        int deletes = 0;
        int flushs = 0;
        for (Mutation m : results) {
            if (shiftOpcodes.contains(m.getOperatorAddInfo())) {
                session.delete(m);
                deletes++;
                if (deletes % 20 == 0) {
                    // 20, same as the JDBC batch size
                    // flush a batch of inserts and release memory:
                    // see
                    // http://www.hibernate.org/hib_docs/reference/en/html/batch.html
                    long startFlush = System.currentTimeMillis();
                    flushs++;
                    logger.info("Doing temporary flush " + flushs);
                    session.flush();
                }
            }
        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();
    }

    private static void deleteMutations(MutationType type) {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        String projectPrefix = ConfigurationLocator.getJavalancheConfiguration().getProjectPrefix();
        Query query = session.createQuery(
                "from Mutation as m where className LIKE '" + projectPrefix + "%' and m.mutationType=:type");
        query.setParameter("type", type);
        @SuppressWarnings("unchecked")
        List<Mutation> results = query.list();
        int deletes = 0;
        int flushs = 0;
        for (Mutation m : results) {
            session.delete(m);
            deletes++;
            if (deletes % 20 == 0) {
                // 20, same as the JDBC batch size
                // flush a batch of inserts and release memory:
                // see
                // http://www.hibernate.org/hib_docs/reference/en/html/batch.html
                long startFlush = System.currentTimeMillis();
                flushs++;
                logger.info("Doing temporary flush " + flushs);
                session.flush();
            }
        }
        tx.commit();
        session.close();
        MutationCoverageFile.update();
    }
}