package metamutator; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; public class MutantSearchSpaceExplorator { static URL url; static URL[] urls; static ClassLoader cl; static int failures; static int successes; static final long maxMutants = System.getProperty("MutantSearchSpaceExplorator.maxMutants")!=null?Long.parseLong(System.getProperty("MutantSearchSpaceExplorator.maxMutants")):Long.MAX_VALUE; /** * this function launch a parallel class * @param classes * @param core * @return Core Result or null on blocking */ public static Result runWithThread(Class<?> classes, JUnitCore core) { int i = 0; // Define Runner RunnerThreaded runner = new RunnerThreaded(classes,core); runner.start(); try { runner.join(); } catch (InterruptedException e) { throw new RuntimeException("interrupted"); } if (runner.getResult()==null) { throw new RuntimeException("interrupted"); } return runner.getResult(); } public static void runMetaProgramIn(String target, String repertory) throws Exception { File filep = new File(target); File file = new File(target+"/"+repertory); // this function doesn't work for a file and for inexistant file if (!file.exists() || !filep.exists()) { throw new Exception("no such directory"); } if (file.isFile() || filep.isFile()) throw new Exception("not a directory"); failures = 0; successes = 0; // make urls for classloader url = filep.toURI().toURL(); urls = new URL[]{url}; // create classloader cl = new URLClassLoader(urls); // finally run program runMetaProgramWith(file, getPackage(repertory)); System.out.println("******************"+file.getName()+"******************"); System.out.println("total killed "+failures); System.out.println("total alive "+successes); } public static void runMetaProgramWith(File target, String _package) throws Exception { // if the target is a file, so load the class and apply the initial function if (target.isFile()) { Class<?> clazz = cl.loadClass(_package+"."+target.getName().replace(".class", "")); int[] val = runMetaProgramWith(clazz); failures += val[0]; successes += val[1]; } // if the target is a directory, do stuff for each under file else if (target.isDirectory()) { for (File file : target.listFiles()) { if (!_package.isEmpty()) runMetaProgramWith(file, _package+"."+target.getName()); else runMetaProgramWith(file, target.getName()); } } } static void resetAllSelectors() { List<Selector> selectors = Selector.getAllSelectors(); for (int sel = 0; sel < selectors.size(); sel++) { selectors.get(sel).choose(0); } } public static int[] runMetaProgramWith(Class<?> TEST_CLASS) throws Exception { System.out.println("******************"+TEST_CLASS.getName()+"******************"); boolean debug = false; JUnitCore core = new JUnitCore(); //output folder File fail = new File("results/fail/"+TEST_CLASS.getName().replace(".", "/")); fail.mkdirs(); File success = new File("results/success/"+TEST_CLASS.getName().replace(".", "/")); success.mkdirs(); // we first run the test suite once to load all classes and their static // fields // this registers only the executed ifs, so indirectly // it collects a kind of trace checkThatAllTestsPass(TEST_CLASS); List<Selector> selectors = Selector.getAllSelectors(); // if (selectors.isEmpty()) // // There's no hot spot in program. Add one to run it at least once // selectors = ImmutableList.of(Selector.of(0, "n/a")); List<String> successes = Lists.newArrayList(); List<String> failures = Lists.newArrayList(); Multimap<Integer, String> failures2 = Multimaps.newListMultimap( Maps.newHashMap(), Lists::newArrayList); String[] strOptions = new String[selectors.size()]; // Execute the test for each hot spot permutation // for (int[] options : // permutations(selectors.stream().map(Selector::getOptionCount).collect(Collectors.toList()))) // { int nattempts=0; for (int sel = 0; sel < selectors.size(); sel++) { if (nattempts++>maxMutants) break; //int k=0; Selector currentSelector = selectors.get(sel); System.out.println(currentSelector.getAlternativeCount()); // k should always start at one otherwise we explore the original code as well for (int k = 1; k < currentSelector.getAlternativeCount(); k++) { Config conf = Config.getInitInstance(); int[] options = new int[selectors.size()]; // System.out.println(Arrays.toString(options)); // resetting all selectors to 0 resetAllSelectors(); checkThatAllTestsPass(TEST_CLASS); // checking that the test is running again for (int i = options.length - 1; i >= 0; i--) { // saving the info for(int o = 0; o < selectors.get(i).getAlternativeCount();o++ ){ boolean value =(o == 0)?true:false; if(i == sel && o ==k){ conf.write(currentSelector.getLocationClass().getName()+":"+currentSelector.getIdentifier()+":"+currentSelector.getAlternatives()[k]+":true"); }else{ if(i == sel) value = false; conf.write(selectors.get(i).getLocationClass().getName()+":"+selectors.get(i).getIdentifier()+":"+selectors.get(i).getAlternatives()[o]+":"+value); } } } currentSelector.choose(k); if (debug) System.out.println("Checking options: " + Arrays.toString(options)); Result result; result = runWithThread(TEST_CLASS,core); // result is null if interrupted if (result.wasSuccessful()) { successes.add(" Worked !!! -> " + Arrays.toString(options) + " / " + Arrays.toString(strOptions)); // On essaye avec renameTo File dest = new File(success.getPath()+"/mutant"+currentSelector.getIdentifier()+"_Op"+(k+1)+".txt"); new File("config.txt").renameTo(dest); } else { String txt; // txt = String // .format("%s / %s -> It has %s failures out of %s runs in %s ms", // Arrays.toString(options), // Arrays.toString(strOptions), // result.getFailureCount(), // result.getRunCount(), result.getRunTime()); txt = sel+ "_"+k+" "+result.getFailures().get(0).getMessage(); String txt_trace = String.format("%s", Arrays.toString(strOptions)); failures.add(txt); failures2.put(result.getFailureCount(), txt); System.out.println(result.getFailures().get(0).getException()); File dest = new File(fail.getPath()+"/mutant"+currentSelector.getIdentifier()+"_Op"+(k+1)+".txt"); new File("config.txt").renameTo(dest); } } } for (String s : failures ) { System.out.println(s); } System.out.println("killed "+failures.size()); System.out.println("alive "+successes.size()); Selector.reset(); int[] val = {failures.size(),successes.size()}; return val; } private static void checkThatAllTestsPass(Class<?> TEST_CLASS) { resetAllSelectors(); JUnitCore core = new JUnitCore(); Result result = core.run(TEST_CLASS); if (result.getFailureCount()>0) { // oops the tests are not valid before throw new RuntimeException("oops it does not pass anymore", result.getFailures().get(0).getException()); } } /** * Computes an iterable though all the permutations or the values in the * ranges provided * * @param sizes * the number of elements in each range (from 0 to size - 1) * @return an Iterable */ private static Iterable<int[]> permutations(List<Integer> sizes) { int limits[] = new int[sizes.size()]; int last = sizes.size() - 1; for (int i = last; i >= 0; i--) limits[i] = sizes.get(i) - 1; return () -> new Iterator<int[]>() { int current[] = new int[last + 1]; { current[last]--; // Force the first element } @Override public boolean hasNext() { return !Arrays.equals(limits, current); } @Override public int[] next() { for (int i = last; i >= 0; i--) { if (current[i] < limits[i]) { current[i]++; return current.clone(); } current[i] = 0; } return new int[0]; } @Override public void remove() { // TODO Auto-generated method stub } }; } public static String getPackage(String path){ int endIndex = path.lastIndexOf("/"); if(endIndex == -1) return ""; path = path.substring(0, endIndex); path = path.replace("/", "."); return path; } }