Skip to content

Commit d3cfb52

Browse files
committed
Changes :
Fixes: - repair a NumberFormatException when replacing a number literal that contains a letter at the end (e.g.: 1l) in mujava.op.PRVO. Modifications: - mujava.loader.Reloader cleans up unused Reloader instances every 150 instances. - mujava.op.basic.LOI will only add ~ operator to unary expressions if the expression is not a statement. - replaced System.out.println with System.err.println when outputing errors in mujava.app.Console. - prints mutated file path in mujava.app.Mutator when a IOException is thrown while creating the new mutated file. Additions: - added mutation.advanced.generations argument to .properties file and -g flag to Console arguments to set how much mutant generations to generate and if mutation score is enabled it will be calculated on the last generation. - added mutation.basic.showSurvivingMutants argument to .properties file and -W flag to Console arguments to show surviving mutants (those which compiled and passed all tests) at the end of the mutation score process.
1 parent ce1148b commit d3cfb52

12 files changed

Lines changed: 423 additions & 117 deletions

File tree

default.properties

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,24 @@ path.original.bin= /home/stein/Proyects/NewMuJava/MuJava/test/
1010
path.tests.bin= /home/stein/Proyects/NewMuJava/MuJava/test/
1111

1212
//where to save mutants
13-
path.mutants= /home/stein/mutants/
13+
path.mutants= /home/stein/Desktop/mutants/
1414

1515
//class to mutate (full qualified name)
16-
mutation.basic.class= utils.BooleanOps
16+
mutation.basic.class= arithmetic.Smallest
1717

1818
//methods to mutate (separated by spaces)
19-
mutation.basic.methods= and
19+
mutation.basic.methods= smallest
2020

2121
//operators to use (separated by spaces)
22-
mutation.basic.operators= COR COI
22+
mutation.basic.operators= AODS AODU AOIS AOIU AORB AORS AORU ASRS COD COI COR LOD LOI LOR ROR SOR PRVOL_SMART PRVOR_REFINED PRVOU_REFINED AMC IHI EMM EOA_STRICT EOC IHD IPC ISI_SMART ISD_SMART EAM IOD IOP JDC JID JSD JSI JTD JTI_SMART OAN_RELAXED PNC OMR PPD
2323

2424
//if mutation score will be calculated
2525
mutation.basic.mutationScore= true
2626

2727
//test classes to run (fully qualified names separated by spaces)
28-
mutation.basic.tests= mutationScore.TestTest
28+
mutation.basic.tests= arithmetic.SmallestTests
29+
30+
mutation.basic.showSurvivingMutants= true
2931

3032
//methods that will not be used by PRVO (separated by spaces)
3133
mutation.advanced.bannedMethods=
@@ -43,10 +45,10 @@ mutation.advanced.allowFieldMutations= false
4345
mutation.advanced.allowClassMutations= false
4446

4547
//packages that will be marked to reload (separared by spaces, empty if all are allowed)
46-
mutation.advanced.allowedPackagesToReload= utils mutationScore
48+
mutation.advanced.allowedPackagesToReload= arithmetic
4749

4850
//allows PRVO to use numeric literal variations
49-
mutation.advanced.allowNumericLiteralVariations= false
51+
mutation.advanced.allowNumericLiteralVariations= true
5052

5153
//stop at the first failing test for each mutant
5254
mutation.advanced.quickDeath= true
@@ -61,4 +63,8 @@ mutation.advanced.disablePrimitiveToObjectAssignments= false
6163
mutation.advanced.wrapPrimitiveToObjectAssignments= false
6264

6365
//apply refined versions of PRVO to arguments in statements containing only a method call
64-
mutation.advanced.applyRefinedPRVOInMethodCallStatements= false
66+
mutation.advanced.applyRefinedPRVOInMethodCallStatements= true
67+
68+
mutation.advanced.generations= 2
69+
70+
mutation.basic.showSurvivingMutants= true

src/mujava/app/Console.java

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class Console {
3131
static String[] methodsToMutate = null;
3232
static boolean mutationScore = false;
3333
static String[] testClasses = new String[]{"mutationScore.BooleanOpsAndTests", "mutationScore.BooleanOpsXorTests", "mutationScore.BooleanOpsXnorTests", "mutationScore.BooleanOpsOrTests"};
34+
static int generations = 1;
3435

3536
public static void main(String[] args) {
3637

@@ -67,6 +68,8 @@ public static void main(String[] args) {
6768
flags.setNoValueFlag('p'); //disable mutations of the form a = b where a is of type Object and b is a primitive type expression
6869
flags.setNoValueFlag('w'); //wrap mutations of the form a = b to a = new T(b), where a is of type Object and b is a primitive type expression
6970
flags.setNoValueFlag('r'); //apply refined versions of PRVO to mutate arguments in statements containing only a method call
71+
flags.setOptionalFlag('g'); //define how many mutants generations to generate
72+
flags.setNoValueFlag('W'); //show surviving mutants
7073
flags.setDependence('T', 'S');
7174
flags.setDependence('S', 'T');
7275
flags.setDependence('t', 'T');
@@ -82,12 +85,14 @@ public static void main(String[] args) {
8285
flags.setDependence('p', 'm');
8386
flags.setDependence('w', 'm');
8487
flags.setDependence('r', 'm');
88+
flags.setDependence('W', 'S');
8589

8690

8791
System.out.println("Validating parameters...");
8892
//================================validate input================================================//
8993
if (!flags.validateInput(args)) {
90-
System.out.println("To get help on how to run mujava++ please run with only flag -H");
94+
System.err.println("Invalid Params");
95+
System.err.println("To get help on how to run mujava++ please run with only flag -H");
9196
return;
9297
}
9398

@@ -99,14 +104,14 @@ public static void main(String[] args) {
99104
if (flags.flagExist('x')) {
100105
for (String op : flags.getFlagValues('x')) {
101106
if (!mi.isSupported(Mutant.valueOf(op))) {
102-
System.out.println("Mutation operator ("+op+") is unsupported");
103-
System.out.println("To see a list with all mutation operators currently supported run mujava++ with only flag -h");
107+
System.err.println("Mutation operator ("+op+") is unsupported");
108+
System.err.println("To see a list with all mutation operators currently supported run mujava++ with only flag -h");
104109
return;
105110
}
106111
ops.add(Mutant.valueOf(op));
107112
}
108113
} else {
109-
ops.addAll(mi.listBasicOperators());
114+
ops.addAll(mi.allOps());
110115
}
111116
System.out.println("Operators: " + ops.toString());
112117

@@ -126,7 +131,7 @@ public static void main(String[] args) {
126131
//mutant source dir
127132
List<String> mutDir = flags.getFlagValues('M');
128133
if (mutDir.size() != 1) {
129-
System.out.println("-M flag must have only one value");
134+
System.err.println("-M flag must have only one value");
130135
return;
131136
}
132137
if (verifyDirectory(mutDir.get(0))) {
@@ -140,11 +145,11 @@ public static void main(String[] args) {
140145
//original source dir
141146
List<String> sourceDir = flags.getFlagValues('O');
142147
if (sourceDir.size() != 1) {
143-
System.out.println("-O flag must have only one value");
148+
System.err.println("-O flag must have only one value");
144149
return;
145150
}
146151
if (!verifyDirectory(sourceDir.get(0))) {
147-
System.out.println("Original source directory ("+sourceDir.get(0)+") doesn't exist");
152+
System.err.println("Original source directory ("+sourceDir.get(0)+") doesn't exist");
148153
return;
149154
}
150155
originalSourceDir = sourceDir.get(0);
@@ -154,11 +159,11 @@ public static void main(String[] args) {
154159
//original bin dir
155160
List<String> binDir = flags.getFlagValues('B');
156161
if (binDir.size() != 1) {
157-
System.out.println("-B flag must have only one value");
162+
System.err.println("-B flag must have only one value");
158163
return;
159164
}
160165
if (!verifyDirectory(binDir.get(0))) {
161-
System.out.println("Original bin directory ("+binDir.get(0)+") doesn't exist");
166+
System.err.println("Original bin directory ("+binDir.get(0)+") doesn't exist");
162167
return;
163168
}
164169
originalBinDir = binDir.get(0);
@@ -169,11 +174,11 @@ public static void main(String[] args) {
169174
if (mutationScore) {
170175
List<String> testDir = flags.getFlagValues('T');
171176
if (testDir.size() != 1) {
172-
System.out.println("-T flag must have only one value");
177+
System.err.println("-T flag must have only one value");
173178
return;
174179
}
175180
if (!verifyDirectory(testDir.get(0))) {
176-
System.out.println("Tests directory ("+testDir.get(0)+") doesn't exist");
181+
System.err.println("Tests directory ("+testDir.get(0)+") doesn't exist");
177182
return;
178183
}
179184
testBinDir = testDir.get(0);
@@ -183,7 +188,7 @@ public static void main(String[] args) {
183188
//=============================verify class to mutate============================================//
184189
List<String> ctm = flags.getFlagValues('m');
185190
if (ctm.size() != 1) {
186-
System.out.println("-m flag must have only one value");
191+
System.err.println("-m flag must have only one value");
187192
return;
188193
}
189194
System.out.println("\n\nVerifying class to mutate...");
@@ -193,7 +198,7 @@ public static void main(String[] args) {
193198
System.out.println("Class to mutate as path: "+ctm.get(0).replaceAll("\\.", Core.SEPARATOR));
194199
System.out.println("Class to mutate full path: "+originalSourceDir+ctm.get(0).replaceAll("\\.", Core.SEPARATOR)+".java\n");
195200
if (!verifyFile(originalSourceDir+ctm.get(0).replaceAll("\\.", Core.SEPARATOR)+".java")) {
196-
System.out.println("Class to mutate ("+(originalSourceDir+ctm.get(0).replaceAll("\\.", Core.SEPARATOR)+".java")+") doesn't exist");
201+
System.err.println("Class to mutate ("+(originalSourceDir+ctm.get(0).replaceAll("\\.", Core.SEPARATOR)+".java")+") doesn't exist");
197202
return;
198203
}
199204
classToMutate = ctm.get(0);
@@ -205,7 +210,7 @@ public static void main(String[] args) {
205210
List<String> tclasses = flags.getFlagValues('t');
206211
for (String tc : tclasses) {
207212
if (!verifyFile(testBinDir+tc.replaceAll("\\.", Core.SEPARATOR)+".class")) {
208-
System.out.println("Test class ("+(testBinDir+tc.replaceAll("\\.", Core.SEPARATOR)+".class")+") doesn't exist");
213+
System.err.println("Test class ("+(testBinDir+tc.replaceAll("\\.", Core.SEPARATOR)+".class")+") doesn't exist");
209214
return;
210215
}
211216
}
@@ -224,7 +229,7 @@ public static void main(String[] args) {
224229
mtm.addAll(flags.getFlagValues('s'));
225230
for (String m : mtm) {
226231
if (!verifyMethod(m)) {
227-
System.out.println("No such method ("+m+") on class to mutate ("+classToMutate+")");
232+
System.err.println("No such method ("+m+") on class to mutate ("+classToMutate+")");
228233
return;
229234
}
230235
}
@@ -350,24 +355,46 @@ public static void main(String[] args) {
350355
Configuration.add(Configuration.ENABLE_REFINEMENT_IN_METHOD_CALL_STATEMENTS, Boolean.FALSE);
351356
}
352357

358+
if (flags.flagExist('g')) {
359+
List<String> valuesForGeneration = flags.getFlagValues('g');
360+
if (valuesForGeneration.size() != 1) {
361+
System.err.println("Only one value is accepted for flag -g (values given : " + valuesForGeneration.size() + ")");
362+
return;
363+
}
364+
generations = Integer.valueOf(valuesForGeneration.get(0));
365+
if (generations <= 0) {
366+
System.err.println("Can't use a value <= 0 for generations (value used : " + generations + ")");
367+
return;
368+
}
369+
} else {
370+
generations = 1;
371+
}
372+
System.out.println("Generations to generate: " + generations);
373+
374+
if (flags.flagExist('W')) {
375+
System.out.println("Showing surviving mutants at the end of mutation score");
376+
Core.showSurvivingMutants = true;
377+
} else {
378+
Core.showSurvivingMutants = false;
379+
}
353380

354381

355382
System.out.println("Parameters validated\n\n");
356383

357384
//================================Mutants generation==============================================//
358385
System.out.println("Generating mutants...\n");
359386
//List<Mutant> basicMutants = mi.listBasicOperators();
360-
boolean result = core.generateMutants(classToMutate, methodsToMutate, ops.toArray(new Mutant[ops.size()]));
387+
boolean result = core.generateMutants(classToMutate, methodsToMutate, ops.toArray(new Mutant[ops.size()]), generations);
361388
if (!result) {
362-
core.lastError().printStackTrace();
389+
core.lastError().printStackTrace(System.err);
363390
} else {
364391
System.out.println(core.lastMutantsFolder().toString());
365392
}
366393
System.out.println("\nMutants generated\n\n");
367394

368395
//==============================Mutation score====================================================//;
369-
if (mutationScore && !core.lastMutantsFolder().isEmpty()) {
370-
System.out.println("Calculating mutation score\n");
396+
if (mutationScore && core.lastMutantsFolder() != null && !core.lastMutantsFolder().isEmpty()) {
397+
System.out.println("Calculating mutation score for generation (" + generations + ")\n");
371398
MutationScore ms = MutationScore.newInstance(mutantsSourceDir, originalBinDir, testBinDir);
372399
core.setMutationScore(ms);
373400
float mutationScoreResult = core.calculateMutationScore(testClasses, classToMutate);
@@ -405,6 +432,8 @@ private static void fullHelp() {
405432
System.out.println("-p | optional parameter | effect : disable mutations of the form a = b where a is of type Object and b is a primitive type expression");
406433
System.out.println("-w | optional parameter | effect : wrap mutations of the form a = b to a = new T(b), where a is of type Object and b is a primitive type expression");
407434
System.out.println("-r | optional parameter | effect : apply refined versions of PRVO to mutate arguments in statements containing only a method call");
435+
System.out.println("-g <generations> | optional parameter | effect : generate <generations> of mutants | e.g.: -g 2 will generate the first and second generations of mutants");
436+
System.out.println("-W | optional parameter | required : -S | effect : shows which mutants that compile and were not killed by any test");
408437
}
409438

410439
private static void mutopsHelp() {

src/mujava/app/Core.java

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@
88
import java.net.URLClassLoader;
99
import java.nio.file.FileSystems;
1010
import java.util.Arrays;
11-
import java.util.HashMap;
1211
import java.util.LinkedList;
1312
import java.util.List;
13+
import java.util.Map;
1414
import java.util.Set;
1515
import java.util.Map.Entry;
1616

1717
import org.junit.runner.notification.Failure;
1818

19-
import mujava.OpenJavaException;
2019
import mujava.api.Mutant;
21-
import mujava.api.MutantsInformationHolder;
20+
import mujava.generations.GenerationsGoalTester;
21+
import mujava.generations.GenerationsInformation;
22+
import mujava.generations.Generator;
23+
import mujava.generations.GoalTester;
24+
import mujava.generations.RequestGenerator;
25+
import mujava.generations.SameRequestGenerator;
2226

2327
/**
2428
* This class execute all commands either from console or from a GUI
@@ -28,15 +32,16 @@
2832
public class Core {
2933
public static String SEPARATOR = fixBackslash(FileSystems.getDefault().getSeparator());
3034
private static Core instance = null;
31-
private Mutator mutator = null;
35+
// private Mutator mutator = null;
3236
private static String inputDir;
3337
private static String outputDir;
3438
private String inputBinDir;
35-
private List<MutantsInformationHolder> mutantsInformationHolder;
36-
private HashMap<String, List<String>> mutantsFolders;
39+
private Map<String, List<String>> mutantsFolders;
3740
private Exception error;
3841
private MutationScore ms;
42+
private int generation = -1 ;
3943
public static boolean fullVerbose = false;
44+
public static boolean showSurvivingMutants = false;
4045
public static final int mujavappVersion = 20151008;
4146

4247
public static Core newInstance(String inputDirP, String outputDirP) {
@@ -74,33 +79,28 @@ private Core(String inputDir, String outputDir) {
7479
}
7580

7681
public boolean generateMutants(String className, String[] methods, Mutant[] mutOps) {
82+
return generateMutants(className, methods, mutOps, 1);
83+
}
84+
85+
public boolean generateMutants(String className, String[] methods, Mutant[] mutOps, int generation) {
7786
this.error = null;
7887
this.mutantsFolders = null;
79-
this.mutantsInformationHolder = null;
8088
if (methods == null) {
81-
Class<?> clazz = loadClass(className);
82-
if (clazz == null) {
83-
return false;
84-
} else {
85-
Method[] classMethods = clazz.getDeclaredMethods();
86-
methods = new String[classMethods.length];
87-
int i = 0;
88-
for (Method m : classMethods) {
89-
methods[i] = m.getName();
90-
i++;
91-
}
92-
}
89+
this.error = new IllegalArgumentException("mujava.app.Core#generateMutantsForGeneration: methods param is null");
90+
return false;
9391
}
94-
MutationRequest mutationRequest = new MutationRequest(className.replaceAll("\\.", SEPARATOR), methods, mutOps, Core.inputDir, Core.outputDir);
95-
this.mutator = new Mutator(mutationRequest);
92+
String classNameAsPath = className.replaceAll("\\.", SEPARATOR);
93+
MutationRequest originalRequest = new MutationRequest(classNameAsPath, methods, mutOps, Core.inputDir, Core.outputDir);
94+
GoalTester goalTester = new GenerationsGoalTester(generation);
95+
RequestGenerator requestGenerator = new SameRequestGenerator(originalRequest);
96+
Generator.useLowMemoryMode(true);
97+
Generator generator = new Generator(requestGenerator, goalTester, (Core.fullVerbose?Generator.VERBOSE_LEVEL.FULL_VERBOSE:Generator.VERBOSE_LEVEL.NO_VERBOSE));
9698
try {
97-
this.mutator.generateMutants();
98-
this.mutantsInformationHolder = this.mutator.getMIH();
99-
this.mutantsFolders = this.mutator.mutantsFolders;
100-
this.mutator.resetMutantFolders();
101-
} catch (ClassNotFoundException e) {
102-
this.error = e;
103-
} catch (OpenJavaException e) {
99+
GenerationsInformation generationsInfo= generator.generate(false, true);
100+
if (Core.fullVerbose) System.out.println(generationsInfo.showBasicInformation());
101+
this.mutantsFolders = generator.getMutantsFolderForGeneration(generation);
102+
this.generation = generation;
103+
} catch (Exception e) {
104104
this.error = e;
105105
}
106106
return this.error == null;
@@ -143,11 +143,7 @@ public Exception lastError() {
143143
return this.error;
144144
}
145145

146-
public List<MutantsInformationHolder> lastMutantInformationHolder() {
147-
return this.mutantsInformationHolder;
148-
}
149-
150-
public HashMap<String, List<String>> lastMutantsFolder() {
146+
public Map<String, List<String>> lastMutantsFolder() {
151147
return this.mutantsFolders;
152148
}
153149

@@ -160,15 +156,18 @@ public String getOutputDir() {
160156
}
161157

162158
public float calculateMutationScore(String[] testClasses, String className) {
159+
List<String> survivingMutantsPaths = new LinkedList<>();
163160
int failedToCompile = 0;
164161
int mutantsKilled = 0;
165162
int mutants = 0;
166163
int timedOut = 0;
167164
for (Entry<String, List<String>> entry : lastMutantsFolder().entrySet()) {
168165
for (String path : entry.getValue()) {
169166
mutants++;
170-
String pathToFile = entry.getKey() + SEPARATOR + path;
171-
if (!ms.compile(pathToFile + className.replaceAll("\\.", SEPARATOR)+".java")){
167+
String currGen = "generation-" + this.generation;
168+
String pathToFile = currGen + SEPARATOR + entry.getKey() + SEPARATOR + path;
169+
String fullPathToJavaFile = pathToFile + className.replaceAll("\\.", SEPARATOR)+".java";
170+
if (!ms.compile(fullPathToJavaFile)){
172171
System.out.println("File : " + Core.outputDir + pathToFile + className.replaceAll("\\.", SEPARATOR)+".java" + " didn't compile\n");
173172
failedToCompile++;
174173
continue;
@@ -196,9 +195,18 @@ public float calculateMutationScore(String[] testClasses, String className) {
196195
if (!killed && !r.wasSuccessful()) killed = true;
197196
}
198197
if (killed) mutantsKilled++;
198+
if (!killed && Core.showSurvivingMutants) {
199+
survivingMutantsPaths.add(fullPathToJavaFile);
200+
}
199201
}
200202
}
201203
System.out.println("Mutants : "+ mutants + " | didn't compile : " + failedToCompile + " | mutants killed by tests : "+ mutantsKilled + " | surviving mutants : " + (mutants-failedToCompile-mutantsKilled) + " | total tests that timedout : " + timedOut + " | mutation score : "+((mutantsKilled+failedToCompile)*100.0)/mutants+ " | mutation score (only compiling mutants) : " + (mutantsKilled*100.0)/(mutants-failedToCompile) + '\n');
204+
if (Core.showSurvivingMutants) {
205+
System.out.println("Surviving mutants paths:\n");
206+
for (String sm : survivingMutantsPaths) {
207+
System.out.println(sm);
208+
}
209+
}
202210
return ((mutantsKilled+failedToCompile)*(float)100.0)/mutants;
203211
}
204212

0 commit comments

Comments
 (0)