/** * Copyright (C) 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package mujava; import openjava.mop.OJSystem; import openjava.mop.OJClass; import java.io.*; import mujava.util.*; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.net.URLClassLoader; import java.util.Vector; /** * <p>Description: Control an entire MuJava system -- * specify path of MuJava system; * specify path of Java source files which mutation is applied to; * specify path of classes of Java source files; * specify path which mutants, class mutants, traditional mutants, and * exception-related mutants are put into; * specify path where test cases are located; * list names of class mutation operators, traditional mutation operators, * and exception-related mutation operators; and * clean up previously generated mutants </p> * * <p> Requires: mujava.config must be stored in MuJava system home directory </p> * <p> Limitation: MuJava currently does not support interface, abstract, gui, * and applet. * * @author Yu-Seung Ma * @update by Nan Li May 2012 * @new function addURL: classes are added to the CLASSPATH dynamically so that users do not need to set up the CLASSPATH manually any more * @version 1.0 */ public class MutationSystem extends OJSystem { public static final int INTERFACE = 0; public static final int ABSTRACT = 1; public static final int GUI = 2; public static final int MAIN = 3; public static final int MAIN_ONLY = 4; public static final int NORMAL = 5; public static final int APPLET = 6; public static final int CM = 0; // Class Mutation Operator public static final int TM = 1; // Traditional Mutation Operator public static final int EM = 2; // Exceptional Mutation Operator /** home path where inputs and output of mujava system are located*/ //public static String SYSTEM_HOME = "C:/jmutation"; //public static String SYSTEM_HOME = "/Users/dmark/mujava"; // public static String SYSTEM_HOME = ""; public static String SYSTEM_HOME = System.getProperty("user.dir"); /** path of Java source files which mutation is applied to */ public static String SRC_PATH = SYSTEM_HOME + "/src"; /** path of classes of Java source files at SRC_PATH directory */ public static String CLASS_PATH = SYSTEM_HOME + "/classes"; /** home path which mutants are put into */ public static String MUTANT_HOME = SYSTEM_HOME + "/result"; /** path which class mutants are put into */ public static String CLASS_MUTANT_PATH = ""; /** path which traditional mutants are put into */ public static String TRADITIONAL_MUTANT_PATH = ""; /** path which exception-related mutants are put into */ public static String EXCEPTION_MUTANT_PATH = ""; /** ??? absolute path for ???*/ public static String MUTANT_PATH = ""; /** ??? absolute path for the original Java source*/ public static String ORIGINAL_PATH = ""; /** absolute path where test cases are located */ public static String TESTSET_PATH = SYSTEM_HOME + "/testset"; /** class name without package name that mutation is applied into */ public static String CLASS_NAME; public static String WHOLE_CLASS_NAME; /** path for */ public static String DIR_NAME; /** directory name for class mutants */ public static String CM_DIR_NAME = "class_mutants"; /** directory name for exception-related mutants */ public static String EM_DIR_NAME = "exception_mutants"; /** directory name for traditional mutants */ public static String TM_DIR_NAME = "traditional_mutants"; /** directory name for original class */ public static String ORIGINAL_DIR_NAME = "original"; public static String LOG_IDENTIFIER = ":"; /** List of names of class mutation operators */ public static String[] cm_operators = { "IHI","IHD","IOD","IOP","IOR","ISI","ISD","IPC", // 8�� "PNC","PMD","PPD","PCI","PCC","PCD","PRV", // 7�� "OMR","OMD","OAN", // 3�� "JTI","JTD","JSI","JSD","JID","JDC", // 6�� "EOA","EOC","EAM","EMM" }; // 4�� - �� 28�� // public static String[] first_tm_operators = { "ABS","AOR","LCR","ROR","UOI" }; /*public static String[] second_tm_operators = { "AOR","AOD","AOI","ROR", "COR","COD","COI","SOR","LOR","LOI","LOD" ,"SCR","SCI","SCD"};*/ /** List of names of traditional mutation operators */ // Upsorn: (04/06/2009) added Statement Deletion operator (SID, SWD, SFD, SSD) public static String[] tm_operators = { "AORB","AORS","AOIU","AOIS","AODU","AODS", "ROR","COR","COD","COI","SOR","LOR","LOI","LOD","ASRS","SDL","VDL","CDL","ODL"}; // "IBD", "WBD", "FBD", "SBD" }; // "SID", "SWD", "SFD", "SSD" }; // "SDL"}; /** List of names of exception-related mutation operators */ public static String[] em_operators = { "EFD", "EHC", "EHD", "EHI", "ETC", "ETD"}; // Upsorn: (05/18/2009) added mutation operators' description public static String[] op_desc = { "" }; /** * Return type of class. * @param name of class * @return type of class ( types: interface, abstract, GUI, main, normal, applet ) */ public static int getClassType (String class_name) { try { Class c = Class.forName (class_name); if (c.isInterface()) return INTERFACE; if (Modifier.isAbstract(c.getModifiers())) return ABSTRACT; Method[] ms = c.getDeclaredMethods(); if (ms != null) { if ( (ms.length == 1) && (ms[0].getName().equals("main"))) return MAIN_ONLY; for (int i=0; i<ms.length; i++) { if (ms[i].getName().equals("main")) return MAIN; } } if (isGUI(c)) return GUI; if (isApplet(c)) return APPLET; return NORMAL; } catch(Exception e) { return -1; } catch(Error e) { return -1; } } /** Examine if class <i>c</i> is a GUI class */ private static boolean isGUI (Class c) { while (c != null) { if ( (c.getName().indexOf("java.awt") == 0) || (c.getName().indexOf("javax.swing") == 0) ) return true; c = c.getSuperclass(); if (c.getName().indexOf("java.lang") == 0) return false; } return false; } /** Examine if class <i>c</i> is an applet class */ private static boolean isApplet(Class c) { while (c != null) { if ( c.getName().indexOf("java.applet")==0) return true; c = c.getSuperclass(); if (c.getName().indexOf("java.lang")==0) return false; } return false; } /** Inheritance Informations */ public static InheritanceINFO[] classInfo = null; /** Examine if type is of primitive types (boolean, byte, char, short, * int, long, double, void) */ public static boolean isPrimitive(OJClass type) { if (type.equals(BOOLEAN)) return true; if (type.equals(BYTE)) return true; if (type.equals(CHAR)) return true; if (type.equals(SHORT)) return true; if (type.equals(INT)) return true; if (type.equals(LONG)) return true; if (type.equals(DOUBLE)) return true; if (type.equals(VOID)) return true; return false; } /** Clear arranged original file made before*/ private static void clearPreviousOriginalFiles() { File original_class_dir = new File(MutationSystem.ORIGINAL_PATH); int i; File[] old_files = original_class_dir.listFiles(); if (old_files == null) return; for (i=0; i<old_files.length; i++) { old_files[i].delete(); } } /* Clear mutants generated from previous run (in class_mutants folder)*/ static void clearPreviousMutants(String path) { File mutant_classes_dir = new File(path); int i; // delete previous mutant files File[] old_files = mutant_classes_dir.listFiles(); if (old_files==null) return; for (i=0; i<old_files.length; i++) { if (old_files[i].isDirectory()) { File[] old_mutants = old_files[i].listFiles(); for (int j=0; j<old_mutants.length; j++) { old_mutants[j].delete(); } } old_files[i].delete(); } } /* Clear mutants generated from previous run (in traditional_mutants folder)*/ static void clearPreviousTraditionalMutants(String path) { File traditional_mutant_dir = new File(path); int i; // delete previous mutant files File[] methods = traditional_mutant_dir.listFiles(); if (methods == null) return; for (i=0; i<methods.length; i++) { if (methods[i].isDirectory()) { File[] mutant_dir = methods[i].listFiles(); for (int j=0; j<mutant_dir.length; j++) { if (mutant_dir[j].isDirectory()) { File[] old_mutants = mutant_dir[j].listFiles(); for (int k=0; k<old_mutants.length; k++) { old_mutants[k].delete(); } } mutant_dir[j].delete(); } } methods[i].delete(); } } /** Delete all traditional mutants generated before */ public static void clearPreviousTraditionalMutants() { clearPreviousTraditionalMutants(MutationSystem.TRADITIONAL_MUTANT_PATH); } /** Delete all class mutants generated before */ public static void clearPreviousClassMutants() { clearPreviousMutants(MutationSystem.CLASS_MUTANT_PATH); } /** Delete all mutants generated before */ public static void clearPreviousMutants() { clearPreviousOriginalFiles(); clearPreviousClassMutants(); clearPreviousTraditionalMutants(); } /* Set up target files (stored in src folder) to be tested */ public static Vector getNewTragetFiles() { Vector targetFiles = new Vector(); getJavacArgForDir (MutationSystem.SRC_PATH, "", targetFiles); return targetFiles; } protected static String getJavacArgForDir (String dir, String str, Vector targetFiles) { String result = str; String temp = ""; File dirF = new File(dir); File[] javaF = dirF.listFiles (new ExtensionFilter("java")); if (javaF.length > 0) { result = result + dir + "/*.java "; for (int k=0; k<javaF.length; k++) { temp = javaF[k].getAbsolutePath(); temp.replace('\\', '/'); targetFiles.add(temp.substring(MutationSystem.SRC_PATH.length()+1, temp.length())); } } File[] sub_dir = dirF.listFiles (new DirFileFilter()); if (sub_dir.length == 0) return result; for (int i=0; i<sub_dir.length; i++) { result = getJavacArgForDir(sub_dir[i].getAbsolutePath(), result, targetFiles); } return result; } /** Return list of class names = class name of <i>dir</i> directory + <i>result</i>*/ public static String[] getAllClassNames(String[] result,String dir) { String[] classes; String temp; File dirF = new File(dir); File[] classF = dirF.listFiles (new ExtensionFilter("class")); if (classF != null) { classes = new String[classF.length]; for(int k=0; k<classF.length; k++) { temp = classF[k].getAbsolutePath(); classes[k] = temp.substring(MutationSystem.CLASS_PATH.length()+1, temp.length()-".class".length()); classes[k] = classes[k].replace('\\', '.'); classes[k] = classes[k].replace('/', '.'); } result = addClassNames(result, classes); } File[] sub_dir = dirF.listFiles(new DirFileFilter()); if (sub_dir == null) return result; for (int i=0; i<sub_dir.length; i++) { result = getAllClassNames(result,sub_dir[i].getAbsolutePath()); } return result; } /** Return combine list of <i> list1 </i> and <i> list2</i> lists. * @param list1 String list * @param list2 String list * @return combined list of list1 and list2*/ private static final String[] addClassNames(String[] list1, String[] list2) { if (list1 == null) list1 = list2; else { int num = list1.length; String[] temp = new String[num]; for (int i=0; i<temp.length; i++) { temp[i] = list1[i]; } num = num + list2.length; list1 = new String[num]; for (int i=0; i<temp.length; i++) { list1[i] = temp[i]; } for (int i=temp.length; i<num; i++) { list1[i] = list2[i-temp.length]; } } return list1; } /** Return inheritance information for give class <br> * @param class_name name of class * @return inheritance information */ public static InheritanceINFO getInheritanceInfo(String class_name) { for (int i=0; i<classInfo.length; i++) { if (classInfo[i].getClassName().equals(class_name)) return classInfo[i]; } return null; } /** Recognize inheritance relation of all classes located at CLASS_PATH directory. <br> * <b>* CAUTION: </b> this function should be called before * using <i>MutantsGenerator</i> or sub-classes of <i>MutantsGenerator</i>. * @throws Exception * @see MutantsGenerator, AllMutantsGenerator, TraditionalMutantsGenerator, ClassMutantsGenerator, ExceptionMutantsGenerator*/ public static void recordInheritanceRelation() throws Exception { String[] classes = null; classes = MutationSystem.getAllClassNames(classes, MutationSystem.CLASS_PATH); if (classes == null) { System.err.println("[ERROR] There are no classes to mutate."); System.err.println(" Please check the directory " + MutationSystem.CLASS_PATH + " and be sure that MuJava_HOME is set correctly (without a trailing slash) in mujava.config."); Runtime.getRuntime().exit(0); } classInfo = new InheritanceINFO[classes.length]; boolean[] bad = new boolean[classes.length]; for (int i = 0; i < classes.length; i++) { bad[i] = false; try { String classpath = System.getProperty("java.class.path"); //add the class path dynamically addURL(MutationSystem.CLASS_PATH); //create a new class from the class name Class c = Class.forName(classes[i]); //create the parent class of the class above Class parent = c.getSuperclass(); if ( (parent == null) || (parent.getName().equals("java.lang.Object")) ) { classInfo[i] = new InheritanceINFO(classes[i], ""); } else { classInfo[i] = new InheritanceINFO(classes[i], parent.getName()); } } catch (ClassNotFoundException e) { System.err.println("[ERROR] Can't find the class: " + classes[i]); System.err.println("Please check that the compiled class for the code you want to mutate is in the classes/ directory. Also check that the MuJava_HOME variable in mujava.config does not end with a trailing slash. " ); bad[i] = true; classInfo[i] = new InheritanceINFO(classes[i], ""); Runtime.getRuntime().exit(0); } catch (Error er) { // Sometimes error occurred. However, I can't solve.. // To muJava users: try do your best to solve it. ^^; System.out.println ("[ERROR] for class " + classes[i] + " => "+ er.getMessage() ); bad[i] = true; classInfo[i] = new InheritanceINFO(classes[i], ""); } } for (int i=0; i<classes.length; i++) { if (bad[i]) continue; String parent_name = classInfo[i].getParentName(); for (int j=0; j<classes.length; j++) { if (bad[j]) continue; if (classInfo[j].getClassName().equals(parent_name)) { classInfo[i].setParent(classInfo[j]); classInfo[j].addChild(classInfo[i]); break; } } } } /** * add the class path dynamically * @param classPath * @throws Exception */ public static void addURL(String classPath) throws Exception { Method addClass = null; ClassLoader cl = null; File f = null; addClass = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] {URL.class}); addClass.setAccessible(true); f = new File(classPath); cl = ClassLoader.getSystemClassLoader(); addClass.invoke(cl, new Object[] { f.toURL() }); } /** Re-setting MuJava structure for give class name <br> * @param name of class (including package name) */ public static void setJMutationPaths(String whole_class_name) { int temp_start = whole_class_name.lastIndexOf(".") + 1; if (temp_start < 0) { temp_start=0; } int temp_end = whole_class_name.length(); MutationSystem.CLASS_NAME = whole_class_name.substring(temp_start, temp_end); MutationSystem.DIR_NAME = whole_class_name; MutationSystem.ORIGINAL_PATH = MutationSystem.MUTANT_HOME + "/" + whole_class_name + "/" + MutationSystem.ORIGINAL_DIR_NAME; MutationSystem.CLASS_MUTANT_PATH = MutationSystem.MUTANT_HOME + "/" + whole_class_name + "/" + MutationSystem.CM_DIR_NAME; MutationSystem.TRADITIONAL_MUTANT_PATH = MutationSystem.MUTANT_HOME + "/" + whole_class_name + "/" + MutationSystem.TM_DIR_NAME; MutationSystem.EXCEPTION_MUTANT_PATH = MutationSystem.MUTANT_HOME + "/" + whole_class_name + "/" + MutationSystem.EM_DIR_NAME; } /** <b> Default mujava system structure setting function </b> * <p> Recognize file structure for mutation system based on "mujava.config". </p> * <p> ** CAUTION : this function or `setJMutationStructure(String home_path)' should be called before generating and running mutants. */ public static void setJMutationStructure() { try { File f = new File (MutationSystem.SYSTEM_HOME + "/mujava.config"); FileReader r = new FileReader(f); BufferedReader reader = new BufferedReader(r); String str = reader.readLine(); String home_path = str.substring("MuJava_HOME=".length(), str.length()); SYSTEM_HOME = home_path; SRC_PATH = home_path + "/src"; CLASS_PATH = home_path + "/classes"; MUTANT_HOME = home_path + "/result"; TESTSET_PATH = home_path + "/testset"; } catch (FileNotFoundException e1) { System.err.println("[ERROR] Can't find mujava.config file"); e1.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** <p> Recognize file structure for mutation system from not "mujava.config" but from user directly </p>*/ public static void setJMutationStructure(String home_path) { SYSTEM_HOME = home_path; SRC_PATH = home_path + "/src"; CLASS_PATH = home_path + "/classes"; MUTANT_HOME = home_path + "/result"; TESTSET_PATH = home_path + "/testset"; } /* * Lin add for setting sessions * */ public static void setJMutationStructureAndSession (String sessionName) { try { File f = new File (MutationSystem.SYSTEM_HOME + "/mujava.config"); FileReader r = new FileReader(f); BufferedReader reader = new BufferedReader(r); String str = reader.readLine(); String home_path = str.substring("MuJava_HOME=".length(), str.length()); home_path = home_path+ "/" + sessionName; SYSTEM_HOME = home_path; SRC_PATH = home_path + "/src"; CLASS_PATH = home_path + "/classes"; MUTANT_HOME = home_path + "/result"; TESTSET_PATH = home_path + "/testset"; } catch (FileNotFoundException e1) { System.err.println("[ERROR] Can't find mujava.config file"); e1.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }