/**
* 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.cli;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.sun.tools.classfile.Opcode.Set;
/**
* <p>
* Description: The Class doRandomGivenPercentMutants.
* Overview: This class is used to get random mutants, given a percentage
* </p>
*
* @author Lin Deng
* @version 1.0 $Date: 06/10/2014 $
*/
public class doRandomGivenPercentMutants {
/**
* The main method.
*
* @param args
* the arguments
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void main(String[] args) throws IOException {
// need result file name
// String[] argv = { "/Users/dmark/COVDLsExpCopy/Triangle/result_list_2014_7_22_11_13_35.csv", "100", "10",
// "/Users/dmark/COVDLsExpCopy/Triangle/result/" };
String path = args[0];
double percent = Double.valueOf(args[1])/100.0;
int numOfRandom = Integer.valueOf(args[2]);
if (numOfRandom < 1) {
System.out.println("need more random times");
return;
}
String resultPath = args[3];
ArrayList<String> targets = new ArrayList<>();
//targets.add("VDL");
// read in file into data structure
HashMap<String, ArrayList<String>> result = readResultsFromFile(path);
// get all tests names
ArrayList<String> testNames = result.get("Mutant");
// randomly get N adequate test set
ArrayList<ArrayList<String>> randomedTestSet = new ArrayList<>();
for(int i = 0; i < numOfRandom; i++)
{
// need a fltered map based on target
HashMap<String, ArrayList<String>> filtered_data = getRandomMutants(result, percent);
randomedTestSet.add(getAdequateTestSets4(filtered_data, testNames));
}
// calculate each one with mutation score
ArrayList<Pair> mutationScores = getMutationScores(randomedTestSet, path);
double totalMS = 0.0;
for (Pair ms : mutationScores)
{
System.out.println(ms.testSet + ": " + ms.mutationScore);
totalMS=totalMS+ms.mutationScore;
}
double avgMS = totalMS / mutationScores.size();
System.out.println("avg: " + avgMS);
// write files
writeResultToFiles(mutationScores, resultPath, Double.toString(percent));
}
private static void writeResultToFiles(ArrayList<Pair> mutationScores, String resultPath, String percent)
throws UnsupportedEncodingException, IOException {
resultPath=resultPath+"ResultOfRandomPercent_"+percent+".txt";
// set the output file
File file = new File(resultPath);
FileOutputStream fout = new FileOutputStream(file);
StringBuffer fileContent = new StringBuffer();
double totalMS = 0.0;
for (Pair pair : mutationScores) {
totalMS = totalMS + pair.mutationScore;
fileContent.append(pair.testSet + ": " + pair.mutationScore);
fileContent.append("\r\n");
}
double avgMS = totalMS / mutationScores.size();
fileContent.append("Avg: " + avgMS);
fout.write(fileContent.toString().getBytes("utf-8"));
fout.close();
}
/**
* Gets the filtered data based on random percentage.
*
* @param result
* the result
* @param percent
* the random percentage
* @return the filtered data based on percentage
*/
private static HashMap<String, ArrayList<String>> getRandomMutants(
HashMap<String, ArrayList<String>> result, double percent) {
HashMap<String, ArrayList<String>> filtered_data = new HashMap<String, ArrayList<String>>();
// calculate how many mutants needed
int numOfTotalMutants = result.size() - 1;
int numOfRandomMutants = (int) (numOfTotalMutants * percent+0.5);
// put all keys into a list
List<String> keysList = new ArrayList<String>(result.keySet());
while (filtered_data.size()<numOfRandomMutants) // randomly fill in the data
{
SecureRandom secureRandom = new SecureRandom();
String randomKey = keysList.get(secureRandom.nextInt(keysList.size()));
if (!randomKey.equals("Mutant") && !filtered_data.keySet().contains(randomKey))
{// if not the top title line, not already added into result, then add it
filtered_data.put(randomKey, result.get(randomKey));
}
}
return filtered_data;
}
/**
* Read results from file. Note: This result include the fist title line.
* e.g. {VDL_3=[, 1, 1, 1, 2], Mutant=[test4, test1, test2, test3, Total,
* Equiv?], VDL_4=[1, 1, 1, , 3, y], VDL_5=[1, , 1, , 2]}
*
* @param path
* the path
* @return the hash map
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private static HashMap<String, ArrayList<String>> readResultsFromFile(String path) throws IOException {
// read the file
File f = new File(path);
if (!f.exists()) {
System.out.println("Can't find file at: " + path);
return null;
}
// read in file into data structure
HashMap<String, ArrayList<String>> result = new HashMap<>();
String s = null;
StringBuffer sb = new StringBuffer();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
while ((s = br.readLine()) != null) {
// split line
List<String> tests = Arrays.asList(s.split(",\\s*"));
// System.out.println(tests.get(1));
ArrayList<String> list = new ArrayList<>();
for (int i = 1; i < tests.size(); i++) {
list.add(tests.get(i));
}
result.put(tests.get(0), list);
}
return result;
}
/**
* Gets the mutation scores.
*
* @param randomedTestSet
* the randomed test set
* @param path
* @return the mutation scores
* @throws IOException
*/
private static ArrayList<Pair> getMutationScores(ArrayList<ArrayList<String>> randomedTestSet, String path)
throws IOException {
// read in file into data structure, this result includes title line
HashMap<String, ArrayList<String>> result = readResultsFromFile(path);
// get all tests names
ArrayList<String> testNames = result.get("Mutant");
// build result with names, i.e. VDL_3=[test1, test2, test3],
// VDL_4=[test4, test1, test2], VDL_5=[test4, test2]
HashMap<String, ArrayList<String>> resultWithTestNames = getResultsWithNames(result);
// calculate
// get total number
int totalNumOfMutants = resultWithTestNames.size();
// get equiv number
int numOfEq = 0;
for (Object key : result.keySet()) {
if (result.get(key).contains("y") || result.get(key).contains("Y")) // has
// an
// equiv
{
numOfEq++;
}
}
ArrayList<Pair> mutationScores = new ArrayList<>();
// get killed number
// for each test test set, calculate how many killed mutants
for (ArrayList<String> tests : randomedTestSet) {
int numOfKilledMutants = 0;
for (Object key : resultWithTestNames.keySet()) // for each mutant
{
for (String test : tests) // for each test in current test set
{
if (resultWithTestNames.get(key).contains(test)) // current
// test
// kills
// current
// mutant
{
numOfKilledMutants++;
break; // directly go to the next mutant
}
}
}
// save mutation score
double ms = (double)numOfKilledMutants / (double)(totalNumOfMutants - numOfEq);
mutationScores.add(new Pair(tests, ms));
}
return mutationScores;
}
private static HashMap<String, ArrayList<String>> getResultsWithNames(HashMap<String, ArrayList<String>> result) {
// get all tests names
ArrayList<String> testNames = result.get("Mutant");
// build result with names
HashMap<String, ArrayList<String>> resultWithTestNames = new HashMap<>();
HashMap<String, Integer> resultStat = new HashMap<>();
for (Object key : result.keySet()) {
ArrayList<String> temp = result.get(key);
ArrayList<String> testStrings = new ArrayList<>();
for (int i = 0; i < temp.size(); i++) {
if (temp.get(i).equals("1") && !testNames.get(i).equals("Total")) // current test kills the current
// mutant
{
testStrings.add(testNames.get(i));
if (resultStat.containsKey(testNames.get(i)))
resultStat.put(testNames.get(i), resultStat.get(testNames.get(i)) + 1);
else {
resultStat.put(testNames.get(i), 1);
}
}
}
if (!key.toString().equals("Mutant"))
resultWithTestNames.put(key.toString(), testStrings);
}
return resultWithTestNames;
}
/**
* Gets the randomed test set.
*
* @param adequateTestSet
* the adequate test set
* @param numOfRandom
* the num of random
* @return the randomed test set
*/
private static ArrayList<ArrayList<String>> getRandomedTestSet(CopyOnWriteArrayList<ArrayList<String>> adequateTestSet,
int numOfRandom) {
ArrayList<ArrayList<String>> result = new ArrayList<>();
for (int i = 0; i < numOfRandom; i++) // random N times
{
SecureRandom random = new SecureRandom();
ArrayList<String> randomTest = adequateTestSet.get(random.nextInt(adequateTestSet.size()));
result.add(randomTest);
}
return result;
}
/**
* Gets the adequate test sets.
*
* @param filtered_data
* the filtered_data
* @param testNames
* the test names
* @return the adequate test sets
*/
public static CopyOnWriteArrayList<ArrayList<String>> getAdequateTestSets(HashMap<String, ArrayList<String>> filtered_data,
ArrayList<String> testNames) {
CopyOnWriteArrayList<ArrayList<String>> testSets = new CopyOnWriteArrayList<ArrayList<String>>();
// ArrayList<String> tt = new ArrayList<>();
// tt.add("a");
// testSets.add(tt);
HashMap<String, ArrayList<String>> resultWithTestNames = new HashMap<>();
HashMap<String, Integer> resultStat = new HashMap<>();
for (Object key : filtered_data.keySet()) {
ArrayList<String> temp = filtered_data.get(key);
ArrayList<String> testStrings = new ArrayList<>();
for (int i = 0; i < temp.size(); i++) {
if (temp.get(i).equals("1")&& !testNames.get(i).equals("Total")) // current test kills the current
// mutant
{
testStrings.add(testNames.get(i));
if (resultStat.containsKey(testNames.get(i)))
resultStat.put(testNames.get(i), resultStat.get(testNames.get(i)) + 1);
else {
resultStat.put(testNames.get(i), 1);
}
}
}
resultWithTestNames.put(key.toString(), testStrings);
}
// check if there is an equivalent
int numOfEq = 0;
int numOfTotalMutants = filtered_data.size();
// filtered_data has y, need to count y for equiv
for (Object key : filtered_data.keySet()) {
if (filtered_data.get(key).contains("y") || filtered_data.get(key).contains("Y")) // has
// an
// equiv
{
numOfEq++;
}
}
// for (Object key : resultWithTestNames.keySet()) {
// if(resultWithTestNames.get(key).size()==0)
// numOfEq ++;
// }
int non_equiv = numOfTotalMutants - numOfEq;
// for (Object key : resultStat.keySet()) {
// if (resultStat.get(key)==non_equiv) // find a single test can kill
// all
// {
// ArrayList<String> t = new ArrayList<>();
// t.add(key.toString());
// testSets.add(t);
// }
// }
// testSets= new ArrayList<ArrayList<String>>();
for (Object key : resultWithTestNames.keySet()) {
ArrayList<String> line = resultWithTestNames.get(key);
if (line.size() == 0) // equiv mutant, go next one
continue;
if (testSets.size() == 0) { // first time, initiate new sets
for (String str : line) {
ArrayList<String> t = new ArrayList<>();
t.add(str);
testSets.add(t);
System.out.println("add test "+t);
}
} else { // not the first time, need to extend everyone, and add
// back
// load last line's tests
ArrayList<ArrayList<String>> temp = new ArrayList<>();
for (ArrayList<String> tests : testSets)
temp.add(tests);
// empty the result set
// ArrayList<ArrayList<String>> tempTestSets = new
// ArrayList<>();
testSets = new CopyOnWriteArrayList<>();
// add and save back
for (String str : line) {
for (ArrayList<String> tests : temp) {
ArrayList<String> t = new ArrayList<>();
t.addAll(tests);
t.add(str);
testSets.add(t);
System.out.println("add test "+t);
}
}
// testSets = new ArrayList<>();
// testSets.addAll(tempTestSets);
}
}
testSets = removeDuplicate(testSets);
testSets = getMinimalTests(testSets);
// System.out.println(non_equiv);
return testSets;
}
/**
* Gets the minimal tests.
*
* @param testSets
* the test sets
* @return the minimal tests
*/
private static CopyOnWriteArrayList<ArrayList<String>> getMinimalTests(CopyOnWriteArrayList<ArrayList<String>> testSets) {
CopyOnWriteArrayList<ArrayList<String>> result = new CopyOnWriteArrayList<>();
List<ArrayList<String>> testSets2 = new CopyOnWriteArrayList<ArrayList<String>>();
List<ArrayList<String>> testSets3 = new CopyOnWriteArrayList<ArrayList<String>>();
testSets2.addAll(testSets);
testSets3.addAll(testSets);
for (ArrayList<String> test : testSets3) {
for (ArrayList<String> test2 : testSets2) {
if (test.containsAll(test2) && !test2.containsAll(test)) {
testSets.remove(test);
testSets2.remove(test);
testSets3.remove(test);
System.out.println("remove test "+test);
break;
}
}
}
result.addAll(testSets);
return result;
}
/**
* Removes the duplicate.
*
* @param testSets
* the test sets
* @return the array list
*/
private static CopyOnWriteArrayList<ArrayList<String>> removeDuplicate(CopyOnWriteArrayList<ArrayList<String>> testSets) {
ArrayList<ArrayList<String>> testSetNoDupInEachTest = new ArrayList<>();
CopyOnWriteArrayList<ArrayList<String>> result = new CopyOnWriteArrayList<>();
// remove dup in each test
for (ArrayList<String> test : testSets) {
HashSet<String> hs = new HashSet<>();
hs.addAll(test);
test.clear();
test.addAll(hs);
testSetNoDupInEachTest.add(test);
}
// remove dup tests
for (ArrayList<String> test : testSetNoDupInEachTest)
{
if (!result.contains(test))
result.add(test);
}
return result;
}
public static CopyOnWriteArrayList<ArrayList<String>> getAdequateTestSets2(HashMap<String, ArrayList<String>> filtered_data,
ArrayList<String> testNames) {
CopyOnWriteArrayList<ArrayList<String>> testSets = new CopyOnWriteArrayList<ArrayList<String>>();
CopyOnWriteArrayList<String> mutantStrings = new CopyOnWriteArrayList<>();
// ArrayList<String> tt = new ArrayList<>();
// tt.add("a");
// testSets.add(tt);
HashMap<String, ArrayList<String>> resultWithTestNames = new HashMap<>();
HashMap<String, Integer> resultStat = new HashMap<>();
for (Object key : filtered_data.keySet()) {
mutantStrings.add(key.toString());
ArrayList<String> temp = filtered_data.get(key);
ArrayList<String> testStrings = new ArrayList<>();
for (int i = 0; i < temp.size(); i++) {
if (temp.get(i).equals("1")&& !testNames.get(i).equals("Total")) // current test kills the current
// mutant
{
testStrings.add(testNames.get(i));
if (resultStat.containsKey(testNames.get(i)))
resultStat.put(testNames.get(i), resultStat.get(testNames.get(i)) + 1);
else {
resultStat.put(testNames.get(i), 1);
}
}
}
resultWithTestNames.put(key.toString(), testStrings);
}
// check if there is an equivalent
int numOfEq = 0;
int numOfTotalMutants = filtered_data.size();
ArrayList<String> nonEquivNonKilled = new ArrayList<>();
// filtered_data has y, need to count y for equiv
for (Object key : filtered_data.keySet()) {
if (filtered_data.get(key).contains("y") || filtered_data.get(key).contains("Y")) // has
// an
// equiv
{
numOfEq++;
}
if (filtered_data.get(key).contains("n") || filtered_data.get(key).contains("N") || filtered_data.get(key).contains("?")) // there is a mutant that can't be killed, but not equiv
{
nonEquivNonKilled.add(key.toString());
}
}
// remove those can't be killed
mutantStrings.removeAll(nonEquivNonKilled);
int non_equiv = numOfTotalMutants - numOfEq;
testNames.remove("Total");
testNames.remove("Equiv?");
// convert testNames into an array
String [] stockArr = testNames.toArray(new String[testNames.size()]);
// get all possible test combinations
int all = stockArr.length;
int nbit = 1 << all;
for (int i = 0; i < nbit; i++) {
ArrayList<String> test = new ArrayList<>();
for (int j = 0; j < all; j++) {
if ((i & (1 << j)) != 0) {
test.add(stockArr[j]);
}
}
if (test.size()!=0)
{testSets.add(test);
System.out.println("add test: "+test);}
}
// remove non-adequate tests
for (ArrayList<String> tests : testSets) // for each test set
{
ArrayList<String> liveMutants = new ArrayList<>(mutantStrings);
for (String test : tests) // for each single test
{
for (String mutant : mutantStrings) // for each single mutant
{
if (resultWithTestNames.get(mutant).contains(test)) // if current test kills current mutant
{
liveMutants.remove(mutant); // the current is killed, remove from live
}
}
}
if (liveMutants.size() > numOfEq) // have more live mutants left than equiv mutants
{
testSets.remove(tests); // not adequate tests, remove it from test Sets
System.out.println("remove test: "+tests);
}
}
testSets = removeDuplicate(testSets);
testSets = getMinimalTests(testSets);
// System.out.println(non_equiv);
return testSets;
}
/**
* Gets the adequate test sets.
*
* @param filtered_data the filtered_data
* @param testNamesCopy the test names copy
* @return the adequate test sets4
*/
public static ArrayList<String> getAdequateTestSets4 (HashMap<String, ArrayList<String>> filtered_data,
ArrayList<String> testNamesCopy) {
CopyOnWriteArrayList<ArrayList<String>> testSets = new CopyOnWriteArrayList<ArrayList<String>>();
CopyOnWriteArrayList<String> mutantStrings = new CopyOnWriteArrayList<>();
HashMap<String, ArrayList<String>> resultWithTestNames = new HashMap<>();
HashMap<String, Integer> resultStat = new HashMap<>();
ArrayList<String> testNames = new ArrayList<>(testNamesCopy);
// get all mutants name in filtered data
for (Object key : filtered_data.keySet()) {
mutantStrings.add(key.toString());
ArrayList<String> temp = filtered_data.get(key);
ArrayList<String> testStrings = new ArrayList<>();
for (int i = 0; i < temp.size(); i++) {
if (temp.get(i).equals("1") && !testNames.get(i).equals("Total")) // current test kills the current
// mutant
{
testStrings.add(testNames.get(i));
if (resultStat.containsKey(testNames.get(i)))
resultStat.put(testNames.get(i), resultStat.get(testNames.get(i)) + 1);
else {
resultStat.put(testNames.get(i), 1);
}
}
}
resultWithTestNames.put(key.toString(), testStrings);
}
// check if there is an equivalent
int numOfEq = 0;
int numOfTotalMutants = filtered_data.size();
ArrayList<String> nonEquivNonKilled = new ArrayList<>();
// remove those weren't be killed
for (Object key : filtered_data.keySet()) {
if (filtered_data.get(key).contains("y") ||
filtered_data.get(key).contains("Y") ||
filtered_data.get(key).contains("n") ||
filtered_data.get(key).contains("N")||
filtered_data.get(key).contains("?")
)
{
mutantStrings.remove(key.toString());
}
}
testNames.remove("Total");
testNames.remove("Equiv?");
ArrayList<String> result = new ArrayList<>();
int[] mutants = new int[mutantStrings.size()];
// for each mutant, randomly find a test that kills it
for(int i =0; i<mutantStrings.size();i++)
{
if(mutants[i]==1)
continue;
// get all tests that kill it
ArrayList<String> testsKillCurrentMutant = resultWithTestNames.get(mutantStrings.get(i));
// randomly choose one
SecureRandom random = new SecureRandom();
String randomTest = testsKillCurrentMutant.get(random.nextInt(testsKillCurrentMutant.size()));
result.add(randomTest);
// remove this mutant by marking the array to 1
mutants[i] = 1;
// remove other mutants that killed by the same test
for (int j =0; j<mutantStrings.size();j++)
{
if(mutants[j]==1)
continue;
if(resultWithTestNames.get(mutantStrings.get(j)).contains(randomTest))
// the test selected killed this m
{
mutants[j] = 1;
}
}
}
// System.out.println(result);
return result;
}
}