/** * 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.*; import openjava.ptree.*; import openjava.tools.parser.*; import openjava.ptree.util.*; import java.io.*; import java.util.*; import java.lang.reflect.Constructor; import mujava.cli.Util; import mujava.op.util.*; import mujava.util.*; import com.sun.tools.javac.Main; /** * <p>Generate mutants according to selected mutation * operator(s) from gui.GenMutantsMain. * The original version is loaded, mutated, and compiled. * Outputs (mutated source and class files) are in the * -mutants folder. </p> * @author Yu-Seung Ma * @version 1.0 */ public abstract class MutantsGenerator { //private boolean debug = false; // static int counter; /** Java source file where mutation operators are applied to */ File original_file; // mutation�� ������ file /** mutation operators to apply */ String[] operators = null; FileEnvironment file_env = null; CompilationUnit comp_unit = null; public MutantsGenerator(File f) { this.original_file = f; initPrimitiveTypes(); } public MutantsGenerator(File f, boolean debug_flag) { this(f); //debug = debug_flag; } public MutantsGenerator(File f, String[] operator_list) { this(f); operators = operator_list; } public MutantsGenerator(File f, String[] operator_list, boolean debug_flag) { this(f, operator_list); //debug = debug_flag; } /** * Generate and initialize parse tree from the original Java source file. * Generate mutants. Arrange and compile the original Java source file. * @return * @throws OpenJavaException */ public boolean makeMutants() throws OpenJavaException { Debug.print("-------------------------------------------------------\n"); Debug.print("* Generating parse tree. \n" ); generateParseTree(); Debug.print("..done. \n" ); //System.out.println("0"); Debug.print("* Initializing parse tree. \n" ); initParseTree(); Debug.print("..done. \n" ); //System.out.println("1"); Debug.print("* Generating Mutants \n" ); genMutants(); Debug.print("..done.\n" ); //System.out.println("2"); Debug.print("* Arranging original soure code. \n" ); arrangeOriginal(); //System.out.println("3"); compileOriginal(); Debug.print("..done. \n" ); Debug.flush(); return true; } abstract void genMutants(); /*void generateMutant(OJClass mutant_op){ try { mutant_op.translateDefinition(comp_unit); }catch (Exception ex){ System.err.println("fail to translate " +mutant_op.getName()+" : " + ex); ex.printStackTrace(); } }*/ /** * Generate mutants from Java bytecode */ void generateMutant(DeclAnalyzer mutant_op) { try { mutant_op.translateDefinition(comp_unit); } catch (Exception ex) { System.err.println("fail to translate " + mutant_op.getName() + " : " + ex); ex.printStackTrace(); } } /** * Arrange the original source file into an appropriate directory */ private void arrangeOriginal() { if (comp_unit == null) { System.err.println(original_file + " is skipped."); } ClassDeclarationList cdecls = comp_unit.getClassDeclarations(); for (int j=0; j<cdecls.size(); ++j) { ClassDeclaration cdecl = cdecls.get(j); File outfile = null; try { outfile = new File(MutationSystem.ORIGINAL_PATH, MutationSystem.CLASS_NAME + ".java"); FileWriter fout = new FileWriter( outfile ); PrintWriter out = new PrintWriter( fout ); MutantCodeWriter writer = new MutantCodeWriter( out ); writer.setClassName(cdecl.getName()); comp_unit.accept( writer ); out.flush(); out.close(); } catch ( IOException e ) { System.err.println( "fails to create " + outfile ); } catch ( ParseTreeException e ) { System.err.println( "errors during printing " + outfile ); e.printStackTrace(); } } } /** * Initialize parse tree * @throws OpenJavaException */ private void initParseTree() throws OpenJavaException { try { //System.out.println("OJSystem.env0 :" + OJSystem.env ); comp_unit.accept(new TypeNameQualifier (file_env)); //System.out.println("OJSystem.env1 :" + OJSystem.env ); MemberAccessCorrector corrector = new MemberAccessCorrector(file_env); // System.out.println("OJSystem.env2 :" + OJSystem.env ); comp_unit.accept(corrector); //System.out.println("OJSystem.env3 :" + OJSystem.env ); } catch (ParseTreeException e) { throw new OpenJavaException("can't initialize parse tree"); } } /** * Initialize parse tree * @param parent_comp_unit * @param parent_file_env */ void initParseTree(CompilationUnit[] parent_comp_unit,FileEnvironment[] parent_file_env) { try { parent_comp_unit[0].accept(new TypeNameQualifier(parent_file_env[0])); MemberAccessCorrector corrector = new MemberAccessCorrector(parent_file_env[0]); parent_comp_unit[0].accept(corrector); } catch (ParseTreeException e) { System.err.println("Encountered errors during analysis."); e.printStackTrace(); } } /** * Generate parse tree * @throws OpenJavaException */ private void generateParseTree() throws OpenJavaException { try { comp_unit = parse(original_file); String pubcls_name = getMainClassName(file_env, comp_unit); if (pubcls_name == null) { int len = original_file.getName().length(); pubcls_name = original_file.getName().substring(0, len-6); } file_env = new FileEnvironment(OJSystem.env, comp_unit, pubcls_name); ClassDeclarationList typedecls = comp_unit.getClassDeclarations(); for (int j = 0; j < typedecls.size(); ++j) { ClassDeclaration class_decl = typedecls.get(j); OJClass c = makeOJClass(file_env, class_decl); OJSystem.env.record(c.getName(), c); recordInnerClasses(c); } } catch (OpenJavaException e1) { throw e1; } catch (Exception e) { System.err.println("errors during parsing. " + e); System.out.println(e); e.printStackTrace(); } } /** * Evaluate whether a parse tree is successfully generated * @param f * @param comp_unit * @param file_env * @return */ boolean generateParseTree(File f, CompilationUnit[] comp_unit, FileEnvironment[] file_env) { try { comp_unit[0] = parse(f); String pubcls_name = getMainClassName(file_env[0], comp_unit[0]); if (pubcls_name == null) { int len = f.getName().length(); pubcls_name = f.getName().substring(0, len-6); } file_env[0] = new FileEnvironment(OJSystem.env, comp_unit[0], pubcls_name); ClassDeclarationList typedecls = comp_unit[0].getClassDeclarations(); for (int j=0; j<typedecls.size(); ++j) { ClassDeclaration class_decl = typedecls.get(j); if ( class_decl.getName().equals(MutationSystem.CLASS_NAME) ) { if ( class_decl.isInterface() || class_decl.getModifiers().contains(ModifierList.ABSTRACT) ) { return false; } } OJClass c = makeOJClass(file_env[0], class_decl); OJSystem.env.record(c.getName(), c); recordInnerClasses(c); } } catch (Exception e) { System.err.println("errors during parsing. " + e); e.printStackTrace(); return false; } return true; } /** * Record inner-classes * @param c */ private static void recordInnerClasses( OJClass c ) { OJClass[] inners = c.getDeclaredClasses(); for (int i = 0; i < inners.length; ++i) { OJSystem.env.record( inners[i].getName(), inners[i] ); recordInnerClasses( inners[i] ); } } /** -> to move to OJClass.forParseTree() **/ private OJClass makeOJClass( Environment env, ClassDeclaration cdecl ) { OJClass result; String qname = env.toQualifiedName( cdecl.getName() ); Class meta = OJSystem.getMetabind( qname ); try { Constructor constr = meta.getConstructor( new Class[]{ Environment . class,OJClass . class, ClassDeclaration . class } ); Object[] args = new Object[]{env, null, cdecl}; result = (OJClass) constr.newInstance(args); } catch (Exception ex) { System.err.println("errors during gererating a metaobject for " + qname); ex.printStackTrace(); result = new OJClass( env, null, cdecl ); } return result; } /** * Prepare a compilation unit * @param file * @return * @throws OpenJavaException */ private static CompilationUnit parse( File file ) throws OpenJavaException { Parser parser; try { parser = new Parser(new java.io.FileInputStream( file ) ); } catch ( java.io.FileNotFoundException e ) { System.err.println( "File " + file + " not found." ); return null; } catch (UnsupportedClassVersionError e) { System.err.println("[ERROR] Unable to use the OpenJava Parser because the class version is unsupported. It may be that the openjava.jar file was compiled with a version of Java later than the one you're using."); System.err.println(); e.printStackTrace(); return null; } CompilationUnit result; try { System.out.println( "File " + file ); result = parser.CompilationUnit( OJSystem.env ); } catch (ParseException e) { throw new OpenJavaException(" can't generate parse tree"); } catch (Exception e) { e.printStackTrace(); result = null; } return result; } /** * * @param env * @param comp_unit * @return * @throws ParseTreeException */ private static String getMainClassName(FileEnvironment env, CompilationUnit comp_unit) throws ParseTreeException { ClassDeclaration cd = comp_unit.getPublicClass(); if (cd != null) { return cd.getName(); } else return null; } /** * Compile mutants */ public void compileMutants() { // Lin add a counter 12/12/13 int counter = 0; String fileName = new String(); File f = new File(MutationSystem.MUTANT_PATH); String[] s = f.list(new MutantDirFilter()); for (int i=0; i<s.length; i++) { File target_dir = new File(MutationSystem.MUTANT_PATH + "/" + s[i]); String[] target_file = target_dir.list(new ExtensionFilter("java")); fileName = target_file[0]; Vector v = new Vector(); for (int j=0; j<target_file.length; j++) { v.add(MutationSystem.MUTANT_PATH + "/" + s[i] + "/" + target_file[j]); } String[] pars = new String[v.size()+2]; pars[0] = "-classpath"; pars[1] = MutationSystem.CLASS_PATH; for (int j=0; j<v.size(); j++) { pars[2+j] = v.get(j).toString(); } try { // result = 0 : SUCCESS, result = 1 : FALSE //int result = Main.compile(pars,new PrintWriter(new FileOutputStream("temp"))); /* * 12/19/13 Lin modified: * if not in debug mode, for not showing the compile result when some * mutants can't pass compiler * if in debug mode, display */ int result; if (Util.debug) result = Main.compile(pars); else { File tempCompileResultFile = new File( MutationSystem.SYSTEM_HOME + "/compile_output"); PrintWriter out = new PrintWriter(tempCompileResultFile); result = Main.compile(pars, out); tempCompileResultFile.delete(); } if (result == 0) { Debug.print("+" + s[i] + " "); counter++; } else { Debug.print("-" + s[i] + " "); // delete directory File dir_name = new File(MutationSystem.MUTANT_PATH + "/" + s[i]); File[] mutants = dir_name.listFiles(); boolean tr = false; for (int j=0; j<mutants.length; j++) { // [tricky solution] It can produce loop -_-;; while (!tr) { tr = mutants[j].delete(); } tr = false; } while (!tr) { tr = dir_name.delete(); } } } catch (Exception e) { System.err.println(e); } } Debug.println(); // Lin add printer total mutants Util.Total = Util.Total+counter; // System.out // .println("------------------------------------------------------------------"); // System.out.println("Total mutants gnerated for " + fileName +": " + Integer.toString(counter)); } /** * Compile original java source file */ private void compileOriginal() { String[] pars= { "-classpath", MutationSystem.CLASS_PATH, MutationSystem.ORIGINAL_PATH + "/" + MutationSystem.CLASS_NAME + ".java"}; try { // result = 0 : SUCCESS, result = 1 : FALSE //int result = Main.compile(pars,new PrintWriter(new FileOutputStream("temp"))); Main.compile(pars); } catch (NoClassDefFoundError e) { System.err.println("[ERROR] Could not compile the generated mutants. Make sure that tools.jar is in your classpath."); System.err.println("You may also need to delete the mutants that were generated (but not compiled) in the result/ directory of the muJava installation."); System.err.println(); e.printStackTrace(); System.exit(1); } catch (Exception e) { System.err.println(e); } } private static void initPrimitiveTypes() { OJSystem.initConstants(); } /** * Determine whether a string contain a certain operator * @param list * @param item * @return true if a string contain the operator, false otherwise */ protected boolean hasOperator (String[] list, String item) { for (int i=0; i<list.length; i++) { if (list[i].equals(item)) return true; } return false; } }