├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── checkstyle.xml ├── core ├── pom.xml └── src │ ├── main │ └── java │ │ └── cmu │ │ └── pasta │ │ └── mu2 │ │ ├── diff │ │ ├── guidance │ │ │ └── DiffMutationReproGuidance.java │ │ └── plugin │ │ │ ├── DiffGoal.java │ │ │ ├── MutateDiffGoal.java │ │ │ └── ReproDiffGoal.java │ │ ├── fuzz │ │ ├── DeadMutantsFilter.java │ │ ├── FileMutantFilter.java │ │ ├── KLeastExecutedFilter.java │ │ ├── KRandomFilter.java │ │ ├── MutantFilter.java │ │ ├── MutationCoverage.java │ │ ├── MutationGuidance.java │ │ ├── MutationRunInfo.java │ │ └── PIEMutantFilter.java │ │ ├── instrument │ │ ├── Cartographer.java │ │ ├── CartographyClassLoader.java │ │ ├── Filter.java │ │ ├── InstructionCall.java │ │ ├── MutationClassLoader.java │ │ ├── MutationClassLoaders.java │ │ ├── MutationInstance.java │ │ ├── MutationSnoop.java │ │ ├── MutationTimeoutException.java │ │ └── OptLevel.java │ │ ├── mutators │ │ ├── DoubleBinaryOperatorMutator.java │ │ ├── DoubleUnaryOperatorMutator.java │ │ ├── FloatBinaryOperatorMutator.java │ │ ├── FloatUnaryOperatorMutator.java │ │ ├── FunctionalInterfaces.java │ │ ├── IntBinaryOperatorMutator.java │ │ ├── IntBinaryPredicateMutator.java │ │ ├── IntUnaryOperatorMutator.java │ │ ├── IntUnaryPredicateMutator.java │ │ ├── LongBinaryOperatorMutator.java │ │ ├── LongUnaryOperatorMutator.java │ │ ├── Mutator.java │ │ ├── NoOpMutator.java │ │ ├── ObjectUnaryOperatorMutator.java │ │ └── ObjectUnaryPredicateMutator.java │ │ └── util │ │ └── ArraySet.java │ └── test │ └── java │ └── cmu │ └── pasta │ └── mu2 │ ├── fuzz │ ├── FileMutantFilterTest.java │ ├── KLeastExecutedFilterTest.java │ └── KRandomFilterTest.java │ └── instrument │ └── CartographyTest.java ├── examples ├── a.txt ├── pom.xml └── src │ ├── main │ └── java │ │ └── cmu │ │ └── pasta │ │ └── mu2 │ │ └── examples │ │ └── sort │ │ ├── BubbleSort.java │ │ ├── CocktailShakerSort.java │ │ ├── CombSort.java │ │ ├── CycleSort.java │ │ ├── GnomeSort.java │ │ ├── HeapSort.java │ │ ├── InsertionSort.java │ │ ├── MergeSort.java │ │ ├── PancakeSort.java │ │ ├── QuickSort.java │ │ ├── SelectionSort.java │ │ ├── ShellSort.java │ │ ├── SortAlgorithm.java │ │ ├── SortUtils.java │ │ └── TimSort.java │ └── test │ ├── java │ └── cmu │ │ └── pasta │ │ └── mu2 │ │ └── examples │ │ ├── chocopy │ │ └── ChocoPyTarget.java │ │ ├── closure │ │ └── ClosureTest.java │ │ ├── commons │ │ └── PatriciaTrieTest.java │ │ ├── gson │ │ └── JsonTest.java │ │ ├── jackson │ │ └── JsonTest.java │ │ ├── sort │ │ ├── DiffTest.java │ │ ├── SortTest.java │ │ └── TimSortTest.java │ │ └── tomcat │ │ └── ApacheTomcatTest.java │ └── resources │ └── dictionaries │ ├── ant-project-afl.dict │ ├── ant-project.dict │ ├── fen.dict │ ├── javaclass.dict │ ├── javascript.dict │ ├── maven-model-afl.dict │ ├── maven-model.dict │ ├── tomcat-webxml-afl.dict │ └── tomcat-webxml.dict ├── integration-tests ├── pom.xml └── src │ └── test │ └── java │ └── cmu │ └── pasta │ └── mu2 │ ├── AbstractMutationTest.java │ ├── DiffMutationGuidanceIT.java │ └── MutationTestingIT.java ├── pom.xml ├── requirements.txt └── scripts ├── getMutants.sh ├── graph_log.py ├── plot_mutant_data.py ├── run_benchmarks.sh └── venn.py /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | workflow_dispatch: 8 | jobs: 9 | build-and-test: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | packages: read 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v3 18 | with: 19 | java-version: '11' 20 | distribution: 'adopt' 21 | - name: Cache Maven dependencies 22 | uses: actions/cache@v2 23 | with: 24 | path: ~/.m2/repository 25 | key: ${{ runner.os }}-maven-${{ hashFiles('pom.xml') }} 26 | restore-keys: | 27 | ${{ runner.os }}-maven- 28 | - name: Make settings.xml file 29 | uses: s4u/maven-settings-action@v2.6.0 30 | - name: Build and test mu2 31 | run: mvn -B verify -P github 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .DS_Store 10 | .java-version 11 | .cache 12 | .idea 13 | *.iml 14 | *.log 15 | *-results 16 | *.swp 17 | *~ 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rohan Padhye 4 | Copyright (c) 2022 Bella Laybourn 5 | Copyright (c) 2022 Rafaello Sanna 6 | Copyright (c) 2022 Vasudev Vikram 7 | Copyright (c) 2022 Ao Li 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | mu2 8 | cmu.pasta.mu2 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 4.0.0 13 | 14 | mu2-core 15 | 16 | 17 | 18 | 19 | maven-plugin-plugin 20 | 3.6.0 21 | 22 | mu2 23 | 24 | 25 | 26 | 27 | 28 | maven-plugin 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/diff/guidance/DiffMutationReproGuidance.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.diff.guidance; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.fuzz.MutationRunInfo; 5 | import cmu.pasta.mu2.instrument.MutationSnoop; 6 | import cmu.pasta.mu2.instrument.OptLevel; 7 | import cmu.pasta.mu2.util.ArraySet; 8 | import cmu.pasta.mu2.instrument.MutationClassLoaders; 9 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffException; 10 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzzReproGuidance; 11 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Outcome; 12 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Serializer; 13 | import edu.berkeley.cs.jqf.fuzz.guidance.GuidanceException; 14 | import edu.berkeley.cs.jqf.instrument.InstrumentationException; 15 | import org.junit.runners.model.FrameworkMethod; 16 | import org.junit.runners.model.TestClass; 17 | 18 | import java.io.File; 19 | import java.io.FileOutputStream; 20 | import java.io.IOException; 21 | import java.io.PrintWriter; 22 | import java.util.List; 23 | import java.util.ArrayList; 24 | import java.util.function.BiConsumer; 25 | 26 | /** 27 | * to avoid the problem of the generator type registry not updating for each ClassLoader 28 | */ 29 | public class DiffMutationReproGuidance extends DiffFuzzReproGuidance { 30 | public List cclOutcomes; 31 | 32 | /** 33 | * mutation analysis results for each MutationInstance 34 | * paired with the index of the outcome that killed the mutant 35 | */ 36 | 37 | private final MutationClassLoaders MCLs; 38 | private int ind; 39 | 40 | /** 41 | * The mutants killed so far 42 | */ 43 | public final ArraySet deadMutants = new ArraySet(); 44 | 45 | /** 46 | * Current optimization level 47 | */ 48 | private final OptLevel optLevel; 49 | 50 | /** 51 | * The set of mutants to execute for a given trial. 52 | * 53 | * This is used when the optLevel is set to something higher than NONE, 54 | * in order to selectively choose which mutants are interesting for a given 55 | * input. This may include already killed mutants; those are skipped separately. 56 | * 57 | * This set must be reset/cleared before execution of every new input. 58 | */ 59 | private static ArraySet runMutants = new ArraySet(); 60 | private static Object infectedValue; 61 | private static boolean infectedValueStored; 62 | 63 | private File reportFile; 64 | 65 | public DiffMutationReproGuidance(File inputFile, File traceDir, MutationClassLoaders mcls, File resultsDir) throws IOException { 66 | super(inputFile, traceDir); 67 | cclOutcomes = new ArrayList<>(); 68 | MCLs = mcls; 69 | ind = -1; 70 | 71 | reportFile = new File(resultsDir, "mutate-repro-out.txt"); 72 | this.optLevel = MCLs.getCartographyClassLoader().getOptLevel(); 73 | } 74 | 75 | @Override 76 | public void run(TestClass testClass, FrameworkMethod method, Object[] args) throws Throwable { 77 | runMutants.reset(); 78 | MutationSnoop.setMutantExecutionCallback(m -> runMutants.add(m.id)); 79 | BiConsumer infectionCallback = (m, value) -> { 80 | if (!infectedValueStored) { 81 | infectedValue = value; 82 | infectedValueStored = true; 83 | } else { 84 | if (infectedValue == null) { 85 | if (value != null) { 86 | runMutants.add(m.id); 87 | } 88 | } else if (!infectedValue.equals(value)) { 89 | runMutants.add(m.id); 90 | } 91 | infectedValueStored = false; 92 | } 93 | }; 94 | MutationSnoop.setMutantInfectionCallback(infectionCallback); 95 | 96 | recentOutcomes.clear(); 97 | cmpTo = null; 98 | 99 | ind++; 100 | 101 | // run CCL 102 | try { 103 | super.run(testClass, method, args); 104 | } catch(InstrumentationException e) { 105 | throw new GuidanceException(e); 106 | } catch (GuidanceException e) { 107 | throw e; 108 | } catch (Throwable e) {} 109 | 110 | System.out.println("CCL Outcome for input " + ind + ": " + recentOutcomes.get(0)); 111 | try (PrintWriter pw = new PrintWriter(new FileOutputStream(reportFile, true))) { 112 | pw.printf("CCL Outcome for input %d: %s\n", ind, recentOutcomes.get(0).toString()); 113 | } 114 | 115 | // set up info 116 | cmpTo = new ArrayList<>(recentOutcomes); 117 | cclOutcomes.add(cmpTo.get(0)); 118 | byte[] argBytes = Serializer.serialize(args); 119 | recentOutcomes.clear(); 120 | 121 | for (MutationInstance mutationInstance : MCLs.getCartographyClassLoader().getMutationInstances()) { 122 | if (deadMutants.contains(mutationInstance.id)) { 123 | continue; 124 | } 125 | if (optLevel != OptLevel.NONE && 126 | !runMutants.contains(mutationInstance.id)) { 127 | continue; 128 | } 129 | 130 | MutationRunInfo mri = new MutationRunInfo(MCLs, mutationInstance, testClass, argBytes, args, method); 131 | mutationInstance.resetTimer(); 132 | 133 | // run with MCL 134 | System.out.println("Running Mutant " + mutationInstance); 135 | try (PrintWriter pw = new PrintWriter(new FileOutputStream(reportFile, true))) { 136 | pw.printf("Running Mutant %s\n", mutationInstance.toString()); 137 | } 138 | 139 | try { 140 | super.run(new TestClass(mri.clazz), mri.method, mri.args); 141 | } catch (DiffException e) { 142 | deadMutants.add(mutationInstance.id); 143 | System.out.println("FAILURE: killed by input " + ind + ": " + e); 144 | try (PrintWriter pw = new PrintWriter(new FileOutputStream(reportFile, true))) { 145 | pw.printf("FAILURE: killed by input %d: %s\n", ind, e.toString()); 146 | } 147 | } catch(InstrumentationException e) { 148 | throw new GuidanceException(e); 149 | } catch (GuidanceException e) { 150 | throw e; 151 | } catch (Throwable e) {} 152 | 153 | recentOutcomes.clear(); 154 | } 155 | if(cclOutcomes.get(cclOutcomes.size() - 1).thrown != null) throw cclOutcomes.get(cclOutcomes.size() - 1).thrown; 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/diff/plugin/MutateDiffGoal.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.diff.plugin; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.diff.guidance.DiffMutationReproGuidance; 5 | import cmu.pasta.mu2.instrument.CartographyClassLoader; 6 | import cmu.pasta.mu2.instrument.MutationClassLoaders; 7 | import cmu.pasta.mu2.instrument.OptLevel; 8 | import edu.berkeley.cs.jqf.fuzz.junit.GuidedFuzzing; 9 | import edu.berkeley.cs.jqf.fuzz.util.IOUtils; 10 | import org.apache.maven.plugin.AbstractMojo; 11 | import org.apache.maven.plugin.AbstractMojoExecutionException; 12 | import org.apache.maven.plugin.MojoExecutionException; 13 | import org.apache.maven.plugin.MojoFailureException; 14 | import org.apache.maven.plugin.logging.Log; 15 | import org.apache.maven.plugins.annotations.Mojo; 16 | import org.apache.maven.plugins.annotations.Parameter; 17 | import org.apache.maven.plugins.annotations.ResolutionScope; 18 | import org.apache.maven.project.MavenProject; 19 | import org.junit.runner.Result; 20 | 21 | import java.io.File; 22 | import java.io.PrintWriter; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * Repro goal for mu2. Performs mutation testing to calculate 28 | * mutation score for a saved test input corpus. 29 | * 30 | * @author Bella Laybourn 31 | */ 32 | @Mojo(name="mutate", 33 | requiresDependencyResolution= ResolutionScope.TEST) 34 | public class MutateDiffGoal extends AbstractMojo { 35 | @Parameter(defaultValue="${project}", required=true, readonly=true) 36 | MavenProject project; 37 | 38 | @Parameter(property="resultsDir", defaultValue="${project.build.directory}", readonly=true) 39 | private File resultsDir; 40 | 41 | /** 42 | * The corpus of inputs to repro 43 | */ 44 | @Parameter(property="input", required=true) 45 | private File input; 46 | 47 | /** 48 | * Test class 49 | */ 50 | @Parameter(property = "class", required=true) 51 | String testClassName; 52 | 53 | /** 54 | * Test method 55 | */ 56 | @Parameter(property = "method", required=true) 57 | private String testMethod; 58 | 59 | /** 60 | * classes to be mutated 61 | */ 62 | @Parameter(property = "includes") 63 | String includes; 64 | 65 | @Parameter(property="targetIncludes") 66 | private String targetIncludes; 67 | 68 | /** 69 | * Allows user to set optimization level for mutation-guided fuzzing. 70 | */ 71 | @Parameter(property="optLevel", defaultValue = "execution") 72 | private String optLevel; 73 | 74 | @Override 75 | public void execute() throws MojoExecutionException, MojoFailureException { 76 | Log log = getLog(); 77 | 78 | OptLevel ol; 79 | try { 80 | ol = OptLevel.valueOf(optLevel.toUpperCase()); 81 | } catch (IllegalArgumentException e) { 82 | throw new MojoExecutionException("Invalid Mutation OptLevel!"); 83 | } 84 | 85 | if(targetIncludes == null) { 86 | targetIncludes = ""; 87 | } 88 | 89 | try { 90 | // Get project-specific classpath and output directory 91 | List classpathElements = project.getTestClasspathElements(); 92 | String[] classPath = classpathElements.toArray(new String[0]); 93 | IOUtils.createDirectory(resultsDir); 94 | 95 | // Create mu2 classloaders from the test classpath 96 | MutationClassLoaders mcls = new MutationClassLoaders(classPath, includes, targetIncludes, ol); 97 | CartographyClassLoader ccl = mcls.getCartographyClassLoader(); 98 | 99 | // Run initial test to compute mutants dynamically 100 | System.out.println("Starting Initial Run:"); 101 | DiffMutationReproGuidance dmrg = new DiffMutationReproGuidance(input, null, mcls, resultsDir); 102 | dmrg.setStopOnFailure(true); 103 | Result result = GuidedFuzzing.run(testClassName, testMethod, ccl, dmrg, null); 104 | if (!result.wasSuccessful()) { 105 | throw new MojoFailureException("Test run failed", 106 | result.getFailures().get(0).getException()); 107 | } 108 | List mutationInstances = mcls.getMutationInstances(); 109 | List killedMutants = new ArrayList<>(); 110 | for(MutationInstance mi : mcls.getMutationInstances()) { 111 | if(dmrg.deadMutants.contains(mi.id)) killedMutants.add(mi); 112 | } 113 | 114 | File mutantReport = new File(resultsDir, "mutant-report.csv"); 115 | try (PrintWriter pw = new PrintWriter(mutantReport)) { 116 | for (MutationInstance mi : mutationInstances) { 117 | pw.printf("%s,%s\n", 118 | mi.toString(), 119 | killedMutants.contains(mi) ? "Killed" : "Alive"); 120 | } 121 | } 122 | 123 | String ls = String.format("Mutants Run: %d, Killed Mutants: %d", 124 | mutationInstances.size(), 125 | killedMutants.size()); 126 | System.out.println(ls); 127 | } catch (AbstractMojoExecutionException e) { 128 | throw e; // Propagate as is 129 | } catch (Exception e) { 130 | throw new MojoExecutionException(e.toString(), e); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/diff/plugin/ReproDiffGoal.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.diff.plugin; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.PrintStream; 7 | import java.io.PrintWriter; 8 | import java.net.MalformedURLException; 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.SortedSet; 12 | import java.util.TreeSet; 13 | 14 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzzReproGuidance; 15 | import edu.berkeley.cs.jqf.fuzz.junit.GuidedFuzzing; 16 | import edu.berkeley.cs.jqf.instrument.InstrumentingClassLoader; 17 | import org.apache.maven.artifact.DependencyResolutionRequiredException; 18 | import org.apache.maven.plugin.AbstractMojo; 19 | import org.apache.maven.plugin.MojoExecutionException; 20 | import org.apache.maven.plugin.MojoFailureException; 21 | import org.apache.maven.plugin.logging.Log; 22 | import org.apache.maven.plugins.annotations.Mojo; 23 | import org.apache.maven.plugins.annotations.Parameter; 24 | import org.apache.maven.plugins.annotations.ResolutionScope; 25 | import org.apache.maven.project.MavenProject; 26 | import org.junit.runner.Result; 27 | 28 | /** version of repro for diffuzzing*/ 29 | @Mojo(name="repro", 30 | requiresDependencyResolution=ResolutionScope.TEST) 31 | public class ReproDiffGoal extends AbstractMojo { 32 | 33 | @Parameter(defaultValue="${project}", required=true, readonly=true) 34 | MavenProject project; 35 | 36 | @Parameter(defaultValue="${project.build.directory}", readonly=true) 37 | private File target; 38 | 39 | /** 40 | * The fully-qualified name of the test class containing methods 41 | * to fuzz. 42 | * 43 | *

This class will be loaded using the Maven project's test 44 | * classpath. It must be annotated with {@code @RunWith(JQF.class)}

45 | */ 46 | @Parameter(property="class", required=true) 47 | private String testClassName; 48 | 49 | /** 50 | * The name of the method to fuzz. 51 | * 52 | *

This method must be annotated with {@code @Fuzz}, and take 53 | * one or more arguments (with optional junit-quickcheck 54 | * annotations) whose values will be fuzzed by JQF.

55 | * 56 | *

If more than one method of this name exists in the 57 | * test class or if the method is not declared 58 | * {@code public void}, then the fuzzer will not launch.

59 | */ 60 | @Parameter(property="method", required=true) 61 | private String testMethod; 62 | 63 | /** 64 | * Input file or directory to reproduce test case(s). 65 | * 66 | *

These files will typically be taken from the test corpus 67 | * ("queue") directory or the failures ("crashes") directory 68 | * generated by JQF in a previous fuzzing run, for the same 69 | * test class and method.

70 | * 71 | */ 72 | @Parameter(property="input", required=true) 73 | private String input; 74 | 75 | /** 76 | * Output file to dump coverage info. 77 | * 78 | *

This is an optional parameter. If set, the value is the name 79 | * of a file where JQF will dump code coverage information for 80 | * the test inputs being replayed.

81 | */ 82 | @Parameter(property="logCoverage") 83 | private String logCoverage; 84 | 85 | /** 86 | * Comma-separated list of FQN prefixes to exclude from 87 | * coverage instrumentation. 88 | * 89 | *

This property is only useful if {@link #logCoverage} is 90 | * set. The semantics are similar to the similarly named 91 | * property in the goal jqf:fuzz.

92 | */ 93 | @Parameter(property="excludes") 94 | private String excludes; 95 | 96 | /** 97 | * Comma-separated list of FQN prefixes to forcibly include, 98 | * even if they match an exclude. 99 | * 100 | *

Typically, these will be a longer prefix than a prefix 101 | * in the excludes clauses.

102 | * 103 | *

This property is only useful if {@link #logCoverage} is 104 | * set. The semantics are similar to the similarly named 105 | * property in the goal jqf:fuzz.

106 | */ 107 | @Parameter(property="includes") 108 | private String includes; 109 | 110 | /** 111 | * Whether to print the args to each test case. 112 | * 113 | *

The input file being repro'd is usually a sequence of bytes 114 | * that is decoded by the junit-quickcheck generators corresponding 115 | * to the parameters declared in the test method. Unless the test method 116 | * contains just one arg of type InputStream, the input file itself 117 | * does not directly correspond to the args sent to the test method.

118 | * 119 | *

If this flag is set, then the args decoded from a repro'd input 120 | * file are first printed to standard output before invoking the test 121 | * method.

122 | */ 123 | @Parameter(property="printArgs") 124 | private boolean printArgs; 125 | 126 | /** 127 | * Whether to dump the args to each test case to file(s). 128 | * 129 | *

The input file being repro'd is usually a sequence of bytes 130 | * that is decoded by the junit-quickcheck generators corresponding 131 | * to the parameters declared in the test method. Unless the test method 132 | * contains just one arg of type InputStream, the input file itself 133 | * does not directly correspond to the args sent to the test method.

134 | * 135 | *

If provided, then the args decoded from a repro'd input 136 | * file are dumped to corresponding files 137 | * in this directory before invoking the test method.

138 | */ 139 | @Parameter(property="dumpArgsDir") 140 | private String dumpArgsDir; 141 | 142 | @Override 143 | public void execute() throws MojoExecutionException, MojoFailureException { 144 | ClassLoader loader; 145 | DiffFuzzReproGuidance guidance; 146 | Log log = getLog(); 147 | PrintStream out = System.out; // TODO: Re-route to logger from super.getLog() 148 | Result result; 149 | 150 | // Configure classes to instrument 151 | if (excludes != null) { 152 | System.setProperty("janala.excludes", excludes); 153 | } 154 | if (includes != null) { 155 | System.setProperty("janala.includes", includes); 156 | } 157 | 158 | try { 159 | List classpathElements = project.getTestClasspathElements(); 160 | 161 | loader = new InstrumentingClassLoader( 162 | classpathElements.toArray(new String[0]), 163 | getClass().getClassLoader()); 164 | } catch (DependencyResolutionRequiredException|MalformedURLException e) { 165 | throw new MojoExecutionException("Could not get project classpath", e); 166 | } 167 | 168 | // If a coverage dump file was provided, enable logging via system property 169 | if (logCoverage != null) { 170 | System.setProperty("jqf.repro.logUniqueBranches", "true"); 171 | } 172 | 173 | // If args should be printed, set system property 174 | if (printArgs) { 175 | System.setProperty("jqf.repro.printArgs", "true"); 176 | } 177 | 178 | // If args should be dumped, set system property 179 | if (dumpArgsDir != null) { 180 | System.setProperty("jqf.repro.dumpArgsDir", dumpArgsDir); 181 | } 182 | 183 | File inputFile = new File(input); 184 | if (!inputFile.exists() || !inputFile.canRead()) { 185 | throw new MojoExecutionException("Cannot find or open file " + input); 186 | } 187 | 188 | try { 189 | guidance = new DiffFuzzReproGuidance(inputFile, null); 190 | result = GuidedFuzzing.run(testClassName, testMethod, loader, guidance, out); 191 | } catch (ClassNotFoundException e) { 192 | throw new MojoExecutionException("Could not load test class", e); 193 | } catch (IllegalArgumentException e) { 194 | throw new MojoExecutionException("Bad request", e); 195 | } catch (FileNotFoundException e) { 196 | throw new MojoExecutionException("File not found", e); 197 | } catch (IOException e) { 198 | throw new MojoExecutionException("I/O error", e); 199 | } catch (RuntimeException e) { 200 | throw new MojoExecutionException("Internal error", e); 201 | } 202 | 203 | // If a coverage dump file was provided, then dump coverage 204 | if (logCoverage != null) { 205 | Set coverageSet = guidance.getBranchesCovered(); 206 | assert (coverageSet != null); // Should not happen if we set the system property above 207 | SortedSet sortedCoverage = new TreeSet<>(coverageSet); 208 | try (PrintWriter covOut = new PrintWriter(new File(logCoverage))) { 209 | for (String b : sortedCoverage) { 210 | covOut.println(b); 211 | } 212 | } catch (IOException e) { 213 | log.error("Could not dump coverage info.", e); 214 | } 215 | } 216 | 217 | if (!result.wasSuccessful()) { 218 | throw new MojoFailureException("Test case produces a failure."); 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/DeadMutantsFilter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class DeadMutantsFilter implements MutantFilter { 9 | private MutationGuidance mutationGuidance; 10 | DeadMutantsFilter(MutationGuidance mutationGuidance){ 11 | this.mutationGuidance = mutationGuidance; 12 | } 13 | @Override 14 | public List filterMutants(List toFilter) { 15 | List aliveMuts = new ArrayList<>(); 16 | for(MutationInstance m : toFilter){ 17 | if(!mutationGuidance.deadMutants.contains(m.id)){ 18 | aliveMuts.add(m); 19 | } 20 | } 21 | return aliveMuts; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/FileMutantFilter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.util.ArraySet; 5 | 6 | import java.io.File; 7 | import java.io.FileNotFoundException; 8 | import java.util.*; 9 | 10 | /** 11 | * Filters an input list of MutationInstances based on if they are in a given file or not. 12 | * Each line in the file can either take the form of ClassName:MutatorName:sequenceIdx or FileName:LineNumber 13 | * e.g, an example of a valid file is 14 | *
15 |  * {@code
16 |  *  TimSort.java:593
17 |  *  sort.TimSort$ComparableTimSort:I_ADD_TO_SUB:28
18 |  * }
19 |  * 
20 | */ 21 | public class FileMutantFilter implements MutantFilter{ 22 | //used for memoizing lookup into the file 23 | ArraySet haveSeen = new ArraySet(); 24 | ArraySet allowed = new ArraySet(); 25 | 26 | //lines that have not been associated with a mutation instance 27 | List unAccountedForLines = new LinkedList<>(); 28 | 29 | 30 | public FileMutantFilter(String fileName) throws FileNotFoundException { 31 | Scanner scanner = new Scanner(new File(fileName)); 32 | while(scanner.hasNextLine()){ 33 | unAccountedForLines.add(scanner.nextLine()); 34 | } 35 | scanner.close(); 36 | } 37 | 38 | @Override 39 | public List filterMutants(List toFilter) { 40 | List muts = new ArrayList<>(); 41 | for(MutationInstance m : toFilter){ 42 | if(haveSeen.contains(m.id)){ 43 | if(allowed.contains(m.id)){ 44 | muts.add(m); 45 | } 46 | } else { 47 | haveSeen.add(m.id); 48 | ListIterator iterator = unAccountedForLines.listIterator(); 49 | while(iterator.hasNext()){ 50 | String currLine = iterator.next(); 51 | if(currLine.equals(m.className + ":" + m.mutator + ":" + m.sequenceIdx) 52 | || currLine.equals(m.getFileName() +":" + m.getLineNum())) { 53 | allowed.add(m.id); 54 | muts.add(m); 55 | iterator.remove(); 56 | } 57 | } 58 | } 59 | } 60 | return muts; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/KLeastExecutedFilter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | 10 | import org.apache.maven.plugin.MojoExecutionException; 11 | 12 | /** 13 | * MutantFilter that filters a list of MutationInstances 14 | * by choosing the k (or k%) least-executed mutants. 15 | */ 16 | public class KLeastExecutedFilter implements MutantFilter { 17 | /** 18 | * The number of MutationInstances the filtered list should contain, 19 | * as set in the constructor. 20 | */ 21 | private int k; 22 | private boolean percent; 23 | private MutationGuidance guidance; 24 | /** 25 | * A map of MutationInstances to the number of times they have been executed. 26 | */ 27 | HashMap executionCounts; 28 | 29 | /** 30 | * Constructor for KLeastExecutedFilter (sets percent to False by default) 31 | * @param k the number of MutationInstances the filtered list should contain 32 | */ 33 | public KLeastExecutedFilter(int k) { 34 | this.k = k; 35 | this.executionCounts = new HashMap(); 36 | this.percent = false; 37 | this.guidance = null; 38 | } 39 | 40 | /** 41 | * Another constructor for KLeastExecutedFilter 42 | * @param k the number/percentage of MutationInstances the filtered list should contain 43 | * @param percent True if k is percentage, False if k is number 44 | */ 45 | public KLeastExecutedFilter(int k, boolean percent, MutationGuidance guidance) { 46 | 47 | this.k = k; 48 | this.executionCounts = new HashMap(); 49 | this.percent = percent; 50 | this.guidance = guidance; 51 | } 52 | 53 | /** 54 | * Filter method that takes in a list of MutationInstances to be filtered 55 | * and returns a filter list of the k least-executed MutationInstances. 56 | * @param toFilter the list of MutationInstances to be filtered 57 | * @return the filtered list of k least-executed MutationInstances 58 | */ 59 | @Override 60 | public List filterMutants(List toFilter) { 61 | 62 | // determine number of mutants to run 63 | int n = this.percent ? (guidance.getSeenMutants() * k / 100) : k; 64 | 65 | // initialize filtered list to be returned 66 | ArrayList filteredList = new ArrayList(); 67 | ArrayList executedMutants = new ArrayList(); 68 | 69 | // add (up to n) mutants in toFilter that have not been executed before to filteredList 70 | int numMutants = 0; 71 | for (MutationInstance mutant : toFilter){ 72 | if (numMutants < n && !executionCounts.containsKey(mutant)){ 73 | filteredList.add(mutant); 74 | numMutants++; 75 | } 76 | // add all mutants that have already been executed before to a list 77 | else if (executionCounts.containsKey(mutant)){ 78 | executedMutants.add(mutant); 79 | } 80 | } 81 | 82 | // if numMutants < n mutants have never been executed, add the next (n - numMutants) least executed mutants to filtered list 83 | if (numMutants < n){ 84 | 85 | // sort list of already executed MutationInstances by execution count 86 | Collections.sort(executedMutants, (e1, e2) -> executionCounts.get(e1).compareTo(executionCounts.get(e2))); 87 | 88 | // add least executed to filteredList until |filteredList| = n 89 | int size = executedMutants.size(); 90 | for(int i = 0; i < size && numMutants < n; i++){ 91 | MutationInstance mutant = executedMutants.get(i); 92 | filteredList.add(mutant); 93 | numMutants++; 94 | } 95 | } 96 | 97 | // increment execution count for each mutant in filteredList 98 | for (MutationInstance mutant: filteredList) { 99 | if (!executionCounts.containsKey(mutant)){ 100 | executionCounts.put(mutant, 1); 101 | } else { 102 | executionCounts.put(mutant, executionCounts.get(mutant)+1); 103 | } 104 | } 105 | 106 | return filteredList; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/KRandomFilter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import org.apache.maven.plugin.MojoExecutionException; 8 | 9 | import cmu.pasta.mu2.instrument.MutationInstance; 10 | 11 | /** 12 | * MutantFilter that filters a list of MutationInstances 13 | * by choosing a random subset of size k. 14 | */ 15 | public class KRandomFilter implements MutantFilter { 16 | private int k; 17 | private boolean percent; 18 | private MutationGuidance guidance; 19 | 20 | /** 21 | * Constructor for KRandomFilter (sets percent to False by default) 22 | * @param k the number of MutationInstances the filtered list should contain 23 | */ 24 | public KRandomFilter (int k){ 25 | this.k = k; 26 | this.percent = false; 27 | } 28 | 29 | /** 30 | * Another constructor for KRandomFilter 31 | * @param k the number of MutationInstances the filtered list should contain 32 | * @param percent True if k is percentage, False if k is number 33 | */ 34 | public KRandomFilter (int k, boolean percent, MutationGuidance guidance) { 35 | this.k = k; 36 | this.percent = percent; 37 | this.guidance = guidance; 38 | } 39 | 40 | /** 41 | * Filter method that takes in a list of MutationInstances to be filtered 42 | * and returns a filter list of k random MutationInstances. 43 | * @param toFilter the list of MutationInstances to be filtered 44 | * @return the filtered list of k random MutationInstances 45 | */ 46 | @Override 47 | public List filterMutants(List toFilter) { 48 | 49 | // determine number of mutants to run 50 | int n = this.percent ? (guidance.getSeenMutants() * k / 100) : k; 51 | 52 | // shuffle list of mutants to randomize first n elements 53 | Collections.shuffle(toFilter); 54 | 55 | // add first k mutants in list to filtered list 56 | List filtered = new ArrayList<>(); 57 | for(int i = 0; i < n && i < toFilter.size(); i++){ 58 | filtered.add(toFilter.get(i)); 59 | } 60 | 61 | return filtered; 62 | } 63 | 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/MutantFilter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | 5 | import java.util.List; 6 | 7 | public interface MutantFilter { 8 | List filterMutants(List toFilter); 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/MutationCoverage.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import edu.berkeley.cs.jqf.fuzz.util.Coverage; 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | /** 9 | * Utility class to collect mutation coverage 10 | * 11 | * @author Bella Laybourn 12 | */ 13 | public class MutationCoverage extends Coverage { 14 | 15 | private Set caughtMutants = new HashSet<>(); 16 | private Set seenMutants = new HashSet<>(); 17 | 18 | 19 | public void see(MutationInstance mi) { 20 | seenMutants.add(mi); 21 | } 22 | 23 | public void kill(MutationInstance mi) { 24 | caughtMutants.add(mi); 25 | } 26 | 27 | @Override 28 | public void clear() { 29 | super.clear(); 30 | clearMutants(); 31 | } 32 | 33 | public void clearMutants() { 34 | caughtMutants = new HashSet<>(); 35 | } 36 | 37 | public int numCaughtMutants() { 38 | return caughtMutants.size(); 39 | } 40 | 41 | public int updateMutants(MutationCoverage that) { 42 | int prevSize = caughtMutants.size(); 43 | caughtMutants.addAll(that.caughtMutants); 44 | seenMutants.addAll(that.seenMutants); 45 | return caughtMutants.size() - prevSize; 46 | } 47 | 48 | public int numSeenMutants() { 49 | return seenMutants.size(); 50 | } 51 | 52 | public Set getMutants() { 53 | return new HashSet<>(caughtMutants); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/MutationRunInfo.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.instrument.MutationClassLoader; 5 | import cmu.pasta.mu2.instrument.MutationClassLoaders; 6 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Serializer; 7 | import org.junit.runners.model.FrameworkMethod; 8 | import org.junit.runners.model.TestClass; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** separate functionality for loading with a particular MCL */ 15 | public class MutationRunInfo { 16 | public Class clazz; 17 | public FrameworkMethod method; 18 | public Object[] args; 19 | 20 | public MutationRunInfo(MutationClassLoaders MCLs, MutationInstance mutationInstance, TestClass testClass, byte[] argBytes, Object[] oArgs, FrameworkMethod fm) throws ClassNotFoundException, NoSuchMethodException, IOException { 21 | // load class with MCL 22 | MutationClassLoader mcl = MCLs.getMutationClassLoader(mutationInstance); 23 | clazz = Class.forName(testClass.getName(), true, mcl); 24 | 25 | // load method with MCL 26 | List> paramTypes = new ArrayList<>(); 27 | for (Class clz : fm.getMethod().getParameterTypes()) { 28 | paramTypes.add(Class.forName(clz.getName(), true, mcl)); 29 | } 30 | method = new FrameworkMethod(clazz.getMethod(fm.getName(), 31 | paramTypes.toArray(new Class[]{}))); 32 | 33 | // load args with MCL 34 | args = Serializer.deserialize(argBytes, mcl, oArgs); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/fuzz/PIEMutantFilter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.instrument.MutationSnoop; 5 | import cmu.pasta.mu2.instrument.OptLevel; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.function.BiConsumer; 10 | 11 | public class PIEMutantFilter implements MutantFilter { 12 | 13 | private Object infectedValue; 14 | private boolean infectedValueStored; 15 | private MutationGuidance mutationGuidance; 16 | 17 | PIEMutantFilter(MutationGuidance mutationGuidance, OptLevel optLevel) { 18 | this.mutationGuidance = mutationGuidance; 19 | MutationSnoop.setMutantExecutionCallback(m -> mutationGuidance.mutantsToRun.add(m.id)); 20 | if(optLevel == OptLevel.INFECTION){ 21 | BiConsumer infectionCallback = (m, value) -> { 22 | if (!infectedValueStored) { 23 | infectedValue = value; 24 | infectedValueStored = true; 25 | } else { 26 | if (infectedValue == null) { 27 | if (value != null) { 28 | mutationGuidance.mutantsToRun.add(m.id); 29 | } 30 | } else if (!infectedValue.equals(value)) { 31 | mutationGuidance.mutantsToRun.add(m.id); 32 | } 33 | infectedValueStored = false; 34 | } 35 | }; 36 | MutationSnoop.setMutantInfectionCallback(infectionCallback); 37 | } 38 | } 39 | @Override 40 | public List filterMutants(List toFilter) { 41 | List runMuts = new ArrayList<>(); 42 | for(MutationInstance m : toFilter){ 43 | if(mutationGuidance.mutantsToRun.contains(m.id)){ 44 | runMuts.add(m); 45 | } 46 | } 47 | return runMuts; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/CartographyClassLoader.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | import edu.berkeley.cs.jqf.fuzz.guidance.GuidanceException; 4 | import cmu.pasta.mu2.mutators.Mutator; 5 | import edu.berkeley.cs.jqf.instrument.InstrumentingClassLoader; 6 | import janala.instrument.SnoopInstructionTransformer; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.lang.instrument.ClassFileTransformer; 10 | import java.lang.instrument.IllegalClassFormatException; 11 | import java.net.URL; 12 | import java.net.URLClassLoader; 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | /** 18 | * ClassLoader for initial run in mutation guidance Runs like InstrumentingClassLoader while also 19 | * prepping MutationInstances 20 | * 21 | * @author Bella Laybourn 22 | */ 23 | public class CartographyClassLoader extends URLClassLoader { 24 | 25 | /** 26 | * List of available MutationInstances 27 | */ 28 | private final List mutationInstances; 29 | 30 | /** 31 | * List of prefixes of fully-qualified class names that are mutable 32 | */ 33 | private final List mutableClasses; 34 | 35 | /** 36 | * see {@link InstrumentingClassLoader} 37 | */ 38 | private final ClassFileTransformer lineCoverageTransformer = new SnoopInstructionTransformer(); 39 | 40 | /** The optimization level to be applied. */ 41 | private final OptLevel optLevel; 42 | 43 | /** 44 | * Constructor 45 | */ 46 | public CartographyClassLoader(URL[] paths, String[] mutableClasses, ClassLoader parent, 47 | OptLevel opt) { 48 | super(paths, parent); 49 | this.mutableClasses = Arrays.asList(mutableClasses); 50 | this.mutationInstances = new ArrayList<>(); 51 | this.optLevel = opt; 52 | Mutator.initializeMutators(); 53 | } 54 | 55 | public List getMutationInstances() { 56 | return mutationInstances; 57 | } 58 | 59 | @Override 60 | public Class findClass(String name) throws ClassNotFoundException, GuidanceException { 61 | try { 62 | byte[] bytes; 63 | 64 | String internalName = name.replace('.', '/'); 65 | String path = internalName.concat(".class"); 66 | try (InputStream in = super.getResourceAsStream(path)) { 67 | if (in == null) { 68 | throw new ClassNotFoundException("Cannot find class " + name); 69 | } 70 | bytes = in.readAllBytes(); 71 | } catch (IOException e) { 72 | throw new ClassNotFoundException("I/O exception while loading class.", e); 73 | } 74 | 75 | // Instrument class to measure both line coverage and mutation coverage 76 | // 77 | try { 78 | byte[] instrumented; 79 | instrumented = lineCoverageTransformer 80 | .transform(this, internalName, null, null, bytes.clone()); 81 | if (instrumented != null) { 82 | bytes = instrumented; 83 | } 84 | } catch (IllegalClassFormatException __) { 85 | } 86 | 87 | // Check whether this class is mutable 88 | boolean mutable = false; 89 | 90 | for (String s : mutableClasses) { 91 | if (name.startsWith(s)) { 92 | mutable = true; 93 | break; 94 | } 95 | } 96 | 97 | // Make cartograph 98 | if (mutable) { 99 | Cartographer c = Cartographer.explore(bytes.clone(), this); 100 | for (List opportunities : c.getOpportunities().values()) { 101 | for (MutationInstance mi : opportunities) { 102 | mutationInstances.add(mi); 103 | } 104 | } 105 | 106 | bytes = c.toByteArray(); 107 | } 108 | 109 | return defineClass(name, bytes, 0, bytes.length); 110 | } catch (OutOfMemoryError e) { 111 | throw new GuidanceException(e); 112 | } 113 | } 114 | 115 | public OptLevel getOptLevel() { 116 | return optLevel; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/Filter.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | /** 4 | * Filter selection used by DiffGoal.java 5 | */ 6 | public enum Filter { 7 | KRANDOM, 8 | KLEASTEXEC, 9 | FILE, 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/InstructionCall.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | import org.objectweb.asm.Label; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Opcodes; 6 | 7 | /** 8 | * Describes an instruction call in bytecode using ASM 9 | * 10 | * @author Bella Laybourn 11 | */ 12 | public class InstructionCall implements Opcodes { 13 | 14 | public enum CallType { 15 | INSN, 16 | METHOD_INSN, 17 | LDC_INSN, 18 | JUMP_INSN 19 | } 20 | 21 | //for any insn: 22 | private final CallType type; 23 | private final int opcode; 24 | 25 | //for methodInsn: 26 | private String owner; 27 | private String name; 28 | private String descriptor; 29 | private boolean isInterface; 30 | 31 | //for ldcInsn: 32 | private Object argument; 33 | 34 | /** 35 | * use for default insn 36 | */ 37 | public InstructionCall(int op) { 38 | type = CallType.INSN; 39 | opcode = op; 40 | } 41 | 42 | /** 43 | * use if methodInsn 44 | */ 45 | public InstructionCall(int op, String ow, String n, String d, boolean i) { 46 | type = CallType.METHOD_INSN; 47 | opcode = op; 48 | owner = ow; 49 | name = n; 50 | descriptor = d; 51 | isInterface = i; 52 | } 53 | 54 | /** 55 | * use if ldcInsn 56 | */ 57 | public InstructionCall(int op, Object arg) { 58 | if (op == Opcodes.LDC) { 59 | type = CallType.LDC_INSN; 60 | opcode = op; 61 | argument = arg; 62 | } else { 63 | type = CallType.JUMP_INSN; 64 | opcode = op; 65 | } 66 | } 67 | 68 | public void call(MethodVisitor mv, Label l) { 69 | switch (type) { 70 | case INSN: 71 | mv.visitInsn(opcode); 72 | break; 73 | case METHOD_INSN: 74 | mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 75 | break; 76 | case LDC_INSN: 77 | mv.visitLdcInsn(argument); 78 | break; 79 | case JUMP_INSN: 80 | mv.visitJumpInsn(opcode, l); 81 | } 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "InstructionCall " + type + " - " + opcode; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/MutationClassLoader.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | import edu.berkeley.cs.jqf.fuzz.guidance.GuidanceException; 4 | import cmu.pasta.mu2.mutators.Mutator; 5 | import janala.instrument.SafeClassWriter; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.net.URL; 9 | import java.net.URLClassLoader; 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | import java.util.concurrent.atomic.AtomicLong; 13 | import org.objectweb.asm.ClassReader; 14 | import org.objectweb.asm.ClassVisitor; 15 | import org.objectweb.asm.ClassWriter; 16 | import org.objectweb.asm.Label; 17 | import org.objectweb.asm.MethodVisitor; 18 | import org.objectweb.asm.Opcodes; 19 | import org.objectweb.asm.Type; 20 | 21 | /** 22 | * Classloader that loads test classes and performs exactly one mutation. 23 | *

24 | * Mostly exported from InstrumentingClassLoader with additions to FindClass. 25 | * 26 | * @author Bella Laybourn 27 | */ 28 | public class MutationClassLoader extends URLClassLoader { 29 | 30 | /** 31 | * The mutation instance this class loads 32 | */ 33 | private final MutationInstance mutationInstance; 34 | 35 | public MutationClassLoader(MutationInstance mutationInstance, URL[] paths, ClassLoader parent) { 36 | super(paths, parent); 37 | this.mutationInstance = mutationInstance; 38 | } 39 | 40 | @Override 41 | public Class findClass(String name) throws ClassNotFoundException, GuidanceException { 42 | try { 43 | byte[] bytes; 44 | 45 | String internalName = name.replace('.', '/'); 46 | String path = internalName.concat(".class"); 47 | try (InputStream in = super.getResourceAsStream(path)) { 48 | if (in == null) { 49 | throw new ClassNotFoundException("Cannot find class " + name); 50 | } 51 | bytes = in.readAllBytes(); 52 | } catch (IOException e) { 53 | throw new ClassNotFoundException("I/O exception while loading class.", e); 54 | } 55 | 56 | String findingClass = name; 57 | AtomicLong found = new AtomicLong(0); 58 | ClassReader cr = new ClassReader(bytes); 59 | ClassWriter cw = new SafeClassWriter(cr, this, 60 | ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); 61 | cr.accept(new ClassVisitor(Mutator.cvArg, cw) { 62 | @Override 63 | public MethodVisitor visitMethod(int access, String name, String signature, 64 | String superName, 65 | String[] interfaces) { 66 | return new MethodVisitor(Mutator.cvArg, 67 | cv.visitMethod(access, name, signature, superName, interfaces)) { 68 | final Set

A mutation instance is uniquely represented by the class being mutated, 11 | * the type of mutator, and the index of that mutation operation within the class.

12 | * 13 | *

Each mutation instance is also assigned a globally unique identifier, which allows 14 | * other classes to store information about mutation instances without having a reference 15 | * to the object itself. This is useful for referencing a mutation instance from instrumented 16 | * code, which typically only makes static method calls.

17 | */ 18 | public class MutationInstance { 19 | 20 | /** 21 | * Globally unique identifier for this mutation instance 22 | */ 23 | public final int id; 24 | 25 | /** 26 | * Static list of all registered mutation instances. 27 | */ 28 | private static final ArrayList mutationInstances = new ArrayList<>(); 29 | 30 | /** 31 | * The type of mutation represented by a mutator 32 | */ 33 | public final Mutator mutator; 34 | 35 | /** 36 | * Name of the class to mutate 37 | */ 38 | public final String className; 39 | 40 | /** 41 | * Numbered instance of the opportunity for mutation this classloader uses 42 | */ 43 | public final long sequenceIdx; 44 | 45 | /** 46 | * Counter that is incremented during execution of this mutation instance to catch infinite 47 | * loops. 48 | */ 49 | private long timeoutCounter = 0; 50 | 51 | private final int lineNum; 52 | private final String fileName; 53 | 54 | // TODO potential for more information: 55 | // line number 56 | // who's seen it 57 | // whether this mutation is likely to be killed by a particular input 58 | 59 | /** 60 | * Creates a new mutation instance. 61 | * 62 | * @param className the fully-qualified name of the class being mutated 63 | * @param mutator the mutator being applied 64 | * @param sequenceIdx the index of the mutator being applied on this class 65 | */ 66 | public MutationInstance(String className, Mutator mutator, long sequenceIdx, int lineNum, String fileName) { 67 | this.id = mutationInstances.size(); 68 | this.className = className; 69 | this.mutator = mutator; 70 | this.sequenceIdx = sequenceIdx; 71 | this.lineNum = lineNum; 72 | this.fileName = fileName; 73 | 74 | // Register mutation instance 75 | mutationInstances.add(this); 76 | } 77 | 78 | public void resetTimer() { 79 | this.timeoutCounter = 0; 80 | } 81 | 82 | public long getTimeoutCounter() { 83 | return this.timeoutCounter; 84 | } 85 | 86 | public long incrementTimeoutCounter() { 87 | return ++this.timeoutCounter; 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | return String.format("%s::%s::%d (%s:L%d)", className, mutator, sequenceIdx, fileName, lineNum); 93 | } 94 | 95 | public static MutationInstance getInstance(int id) { 96 | return mutationInstances.get(id); 97 | } 98 | 99 | public static int getNumInstances() { 100 | return mutationInstances.size(); 101 | } 102 | 103 | public int getLineNum() { 104 | return lineNum; 105 | } 106 | public String getFileName() { 107 | return fileName; 108 | } 109 | 110 | @Override 111 | public boolean equals(Object that) { 112 | // Mutation instances are globally unique 113 | return this == that; 114 | } 115 | 116 | @Override 117 | public int hashCode() { 118 | return id; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/MutationSnoop.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | import java.util.function.BiConsumer; 4 | import java.util.function.Consumer; 5 | 6 | /** 7 | * This is a class with static methods that are invoked from instrumentation in mutated test 8 | * methods. 9 | *

10 | * {@see {@link edu.berkeley.cs.jqf.instrument.tracing.SingleSnoop}} 11 | */ 12 | public class MutationSnoop { 13 | 14 | public static final long TIMEOUT_TICKS = Integer 15 | .getInteger("jqf.mutation.TIMEOUT_TICKS", 10000000); 16 | 17 | /** 18 | * Validates whether or not a timeout has occurred. 19 | *

20 | * This method is invoked periodically from mutated test classes, in order to keep track of time. 21 | * Each invocation of this method increments a counter. 22 | * 23 | * @param id the unique identifier of the mutation instance 24 | * @throws MutationTimeoutException 25 | */ 26 | public static void checkTimeout(int id) throws MutationTimeoutException { 27 | if (MutationInstance.getInstance(id).incrementTimeoutCounter() > TIMEOUT_TICKS) { 28 | throw new MutationTimeoutException(MutationInstance.getInstance(id).getTimeoutCounter()); 29 | } 30 | } 31 | 32 | /** 33 | * The callback which must be run upon invoking a mutant 34 | */ 35 | private static Consumer callback = x -> { 36 | }; 37 | private static BiConsumer infectionCallback = (x, id) -> { 38 | }; 39 | 40 | /** 41 | * Called when a mutant is run in the intial run 42 | * 43 | * @param id The id of the {@link MutationInstance} 44 | * @see Cartographer 45 | */ 46 | public static void logMutant(int id) { 47 | callback.accept(MutationInstance.getInstance(id)); 48 | } 49 | 50 | /** 51 | * Called when logging infection values for a mutant 52 | * 53 | * @param value The resulting value of mutator function 54 | * @param id The id of the {@link MutationInstance} 55 | */ 56 | public static void logValue(int value, int id) { 57 | infectionCallback.accept(MutationInstance.getInstance(id), value); 58 | } 59 | 60 | public static void logValue(float value, int id) { 61 | infectionCallback.accept(MutationInstance.getInstance(id), value); 62 | } 63 | 64 | public static void logValue(double value, int id) { 65 | infectionCallback.accept(MutationInstance.getInstance(id), value); 66 | } 67 | 68 | public static void logValue(long value, int id) { 69 | infectionCallback.accept(MutationInstance.getInstance(id), value); 70 | } 71 | 72 | public static void logValue(boolean value, int id) { 73 | infectionCallback.accept(MutationInstance.getInstance(id), value); 74 | } 75 | 76 | public static void logValue(Object value, int id) { 77 | infectionCallback.accept(MutationInstance.getInstance(id), value); 78 | } 79 | 80 | /** 81 | * Sets the execution callback which will be run each time a mutant is run in the initial run of the tested 82 | * class 83 | * 84 | * @param cb The new callback 85 | */ 86 | public static void setMutantExecutionCallback(Consumer cb) { 87 | callback = cb; 88 | } 89 | 90 | /** 91 | * Sets the infection callback which will be run each time a mutant is run in the initial run of the tested 92 | * class 93 | * 94 | * @param cb The new callback 95 | */ 96 | public static void setMutantInfectionCallback(BiConsumer cb) { 97 | infectionCallback = cb; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/MutationTimeoutException.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | /** 4 | * Class for instrumenting timeouts 5 | * 6 | * @author Bella Laybourn 7 | */ 8 | public class MutationTimeoutException extends Exception { 9 | 10 | public MutationTimeoutException(long ticks) { 11 | super(String.format("Timeout due to execution of %d ticks", ticks)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/instrument/OptLevel.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | /** 4 | * An optimization level to be used by the cartographer. 5 | */ 6 | public enum OptLevel { 7 | NONE, 8 | EXECUTION, 9 | INFECTION, 10 | PROPAGATION, // Not yet implemented 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/DoubleBinaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.DoubleBinaryOperator; 7 | 8 | public class DoubleBinaryOperatorMutator extends Mutator { 9 | 10 | private DoubleBinaryOperator originalFunction; 11 | private DoubleBinaryOperator mutatorFunction; 12 | private double secondArg; 13 | 14 | DoubleBinaryOperatorMutator(String name, boolean useInfection, DoubleBinaryOperator originalFunction, DoubleBinaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 15 | super(name, useInfection, toReplace, returnType, replaceWith); 16 | this.originalFunction = originalFunction; 17 | this.mutatorFunction = mutatorFunction; 18 | } 19 | 20 | @Override 21 | public Type getOperandType() { 22 | return Type.DOUBLE_TYPE; 23 | } 24 | 25 | @Override 26 | public Type getReturnType() { 27 | return Type.DOUBLE_TYPE; 28 | } 29 | 30 | @Override 31 | public int getNumArgs() { 32 | return 2; 33 | } 34 | 35 | // Method descriptor uses one argument since second argument is read beforehand. 36 | @Override 37 | public String getMethodDescriptor() { 38 | return "(D)D"; 39 | } 40 | 41 | public static DoubleBinaryOperatorMutator getMutator(int id) { 42 | return (DoubleBinaryOperatorMutator) Mutator.allMutators.get(id); 43 | } 44 | 45 | public void readSecondArg(double arg) { 46 | this.secondArg = arg; 47 | } 48 | 49 | public double writeSecondArg() { 50 | return secondArg; 51 | } 52 | 53 | public double runOriginal(double arg1) { 54 | return originalFunction.applyAsDouble(arg1, secondArg); 55 | } 56 | 57 | public double runMutated(double arg1) { 58 | return mutatorFunction.applyAsDouble(arg1, secondArg); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/DoubleUnaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.DoubleUnaryOperator; 7 | 8 | public class DoubleUnaryOperatorMutator extends Mutator { 9 | 10 | private DoubleUnaryOperator originalFunction; 11 | private DoubleUnaryOperator mutatorFunction; 12 | 13 | DoubleUnaryOperatorMutator(String name, boolean useInfection, DoubleUnaryOperator originalFunction, DoubleUnaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatorFunction = mutatorFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.DOUBLE_TYPE; 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.DOUBLE_TYPE; 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(D)D"; 37 | } 38 | 39 | public static DoubleUnaryOperatorMutator getMutator(int id) { 40 | return (DoubleUnaryOperatorMutator) Mutator.allMutators.get(id); 41 | } 42 | 43 | public double runOriginal(double arg) { 44 | return originalFunction.applyAsDouble(arg); 45 | } 46 | 47 | public double runMutated(double arg) { 48 | return mutatorFunction.applyAsDouble(arg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/FloatBinaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | public class FloatBinaryOperatorMutator extends Mutator { 7 | 8 | private FloatBinaryOperator originalOperator; 9 | private FloatBinaryOperator mutatedOperator; 10 | 11 | public FloatBinaryOperatorMutator(String name, boolean useInfection, FloatBinaryOperator originalOperator, FloatBinaryOperator mutatedOperator, int toReplace, String returnType, InstructionCall... replaceWith) { 12 | super(name, useInfection, toReplace, returnType, replaceWith); 13 | this.originalOperator = originalOperator; 14 | this.mutatedOperator = mutatedOperator; 15 | } 16 | 17 | @Override 18 | public Type getOperandType() { 19 | return Type.FLOAT_TYPE; 20 | } 21 | 22 | @Override 23 | public Type getReturnType() { 24 | return Type.FLOAT_TYPE; 25 | } 26 | 27 | @Override 28 | public int getNumArgs() { 29 | return 2; 30 | } 31 | 32 | @Override 33 | public String getMethodDescriptor() { 34 | return "(FF)F"; 35 | } 36 | 37 | public static FloatBinaryOperatorMutator getMutator(int id) { 38 | return (FloatBinaryOperatorMutator) Mutator.allMutators.get(id); 39 | } 40 | 41 | public float runOriginal(float arg1, float arg2) { 42 | return originalOperator.applyAsFloat(arg1, arg2); 43 | } 44 | 45 | public float runMutated(float arg1, float arg2) { 46 | return mutatedOperator.applyAsFloat(arg1, arg2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/FloatUnaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | public class FloatUnaryOperatorMutator extends Mutator { 7 | 8 | private FloatUnaryOperator originalFunction; 9 | private FloatUnaryOperator mutatorFunction; 10 | 11 | FloatUnaryOperatorMutator(String name, boolean useInfection, FloatUnaryOperator originalFunction, FloatUnaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 12 | super(name, useInfection, toReplace, returnType, replaceWith); 13 | this.originalFunction = originalFunction; 14 | this.mutatorFunction = mutatorFunction; 15 | } 16 | 17 | @Override 18 | public Type getOperandType() { 19 | return Type.DOUBLE_TYPE; 20 | } 21 | 22 | @Override 23 | public Type getReturnType() { 24 | return Type.DOUBLE_TYPE; 25 | } 26 | 27 | @Override 28 | public int getNumArgs() { 29 | return 1; 30 | } 31 | 32 | @Override 33 | public String getMethodDescriptor() { 34 | return "(F)F"; 35 | } 36 | 37 | public static FloatUnaryOperatorMutator getMutator(int id) { 38 | return (FloatUnaryOperatorMutator) Mutator.allMutators.get(id); 39 | } 40 | 41 | public float runOriginal(float arg) { 42 | return originalFunction.applyAsFloat(arg); 43 | } 44 | 45 | public float runMutated(float arg) { 46 | return mutatorFunction.applyAsFloat(arg); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/FunctionalInterfaces.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | @FunctionalInterface 4 | interface IntBinaryPredicate { 5 | boolean test(int a, int b); 6 | } 7 | 8 | @FunctionalInterface 9 | interface FloatBinaryOperator { 10 | float applyAsFloat(float a, float b); 11 | } 12 | 13 | @FunctionalInterface 14 | interface FloatUnaryOperator { 15 | float applyAsFloat(float a); 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/IntBinaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.IntBinaryOperator; 7 | 8 | public class IntBinaryOperatorMutator extends Mutator { 9 | 10 | private IntBinaryOperator originalFunction; 11 | private IntBinaryOperator mutatedFunction; 12 | 13 | public IntBinaryOperatorMutator(String name, boolean useInfection, IntBinaryOperator originalFunction, IntBinaryOperator mutatedFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatedFunction = mutatedFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.INT_TYPE; 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.INT_TYPE; 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 2; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(II)I"; 37 | } 38 | 39 | public static IntBinaryOperatorMutator getMutator(int id) { 40 | return (IntBinaryOperatorMutator) Mutator.allMutators.get(id); 41 | } 42 | 43 | public int runOriginal(int arg1, int arg2) { 44 | return originalFunction.applyAsInt(arg1, arg2); 45 | } 46 | 47 | public int runMutated(int arg1, int arg2) { 48 | return mutatedFunction.applyAsInt(arg1, arg2); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/IntBinaryPredicateMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | public class IntBinaryPredicateMutator extends Mutator { 7 | 8 | private IntBinaryPredicate originalOperator; 9 | private IntBinaryPredicate mutatedOperator; 10 | 11 | public IntBinaryPredicateMutator(String name, boolean useInfection, IntBinaryPredicate originalOperator, IntBinaryPredicate mutatedOperator, int toReplace, String returnType, InstructionCall... replaceWith) { 12 | super(name, useInfection, toReplace, returnType, replaceWith); 13 | this.originalOperator = originalOperator; 14 | this.mutatedOperator = mutatedOperator; 15 | } 16 | 17 | @Override 18 | public Type getOperandType() { 19 | return Type.INT_TYPE; 20 | } 21 | 22 | @Override 23 | public Type getReturnType() { 24 | return Type.BOOLEAN_TYPE; 25 | } 26 | 27 | @Override 28 | public int getNumArgs() { 29 | return 2; 30 | } 31 | 32 | @Override 33 | public String getMethodDescriptor() { 34 | return "(II)Z"; 35 | } 36 | 37 | public static IntBinaryPredicateMutator getMutator(int id) { 38 | return (IntBinaryPredicateMutator) Mutator.allMutators.get(id); 39 | } 40 | 41 | public boolean runOriginal(int arg1, int arg2) { 42 | return originalOperator.test(arg1, arg2); 43 | } 44 | 45 | public boolean runMutated(int arg1, int arg2) { 46 | return mutatedOperator.test(arg1, arg2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/IntUnaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.IntUnaryOperator; 7 | 8 | public class IntUnaryOperatorMutator extends Mutator { 9 | 10 | private IntUnaryOperator originalFunction; 11 | private IntUnaryOperator mutatorFunction; 12 | 13 | IntUnaryOperatorMutator(String name, boolean useInfection, IntUnaryOperator originalFunction, IntUnaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatorFunction = mutatorFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.INT_TYPE; 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.INT_TYPE; 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(I)I"; 37 | } 38 | 39 | public static IntUnaryOperatorMutator getMutator(int id) { 40 | return (IntUnaryOperatorMutator) Mutator.allMutators.get(id); 41 | } 42 | 43 | public int runOriginal(int arg) { 44 | return originalFunction.applyAsInt(arg); 45 | } 46 | 47 | public int runMutated(int arg) { 48 | return mutatorFunction.applyAsInt(arg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/IntUnaryPredicateMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.IntPredicate; 7 | 8 | public class IntUnaryPredicateMutator extends Mutator { 9 | 10 | private IntPredicate originalFunction; 11 | private IntPredicate mutatorFunction; 12 | 13 | IntUnaryPredicateMutator(String name, boolean useInfection, IntPredicate originalFunction, IntPredicate mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatorFunction = mutatorFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.INT_TYPE; 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.BOOLEAN_TYPE; 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(I)Z"; 37 | } 38 | 39 | public static IntUnaryPredicateMutator getMutator(int id) { 40 | return (IntUnaryPredicateMutator) Mutator.allMutators.get(id); 41 | } 42 | 43 | public boolean runOriginal(int arg) { 44 | return originalFunction.test(arg); 45 | } 46 | 47 | public boolean runMutated(int arg) { 48 | return mutatorFunction.test(arg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/LongBinaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.LongBinaryOperator; 7 | 8 | public class LongBinaryOperatorMutator extends Mutator { 9 | 10 | private LongBinaryOperator originalFunction; 11 | private LongBinaryOperator mutatorFunction; 12 | private long secondArg; 13 | 14 | LongBinaryOperatorMutator(String name, boolean useInfection, LongBinaryOperator originalFunction, LongBinaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 15 | super(name, useInfection, toReplace, returnType, replaceWith); 16 | this.originalFunction = originalFunction; 17 | this.mutatorFunction = mutatorFunction; 18 | } 19 | 20 | @Override 21 | public Type getOperandType() { 22 | return Type.LONG_TYPE; 23 | } 24 | 25 | @Override 26 | public Type getReturnType() { 27 | return Type.LONG_TYPE; 28 | } 29 | 30 | @Override 31 | public int getNumArgs() { 32 | return 2; 33 | } 34 | 35 | // Method descriptor uses one argument since second argument is read beforehand. 36 | @Override 37 | public String getMethodDescriptor() { 38 | return "(J)J"; 39 | } 40 | 41 | public static LongBinaryOperatorMutator getMutator(int id) { 42 | return (LongBinaryOperatorMutator) Mutator.allMutators.get(id); 43 | } 44 | 45 | public void readSecondArg(long arg) { 46 | this.secondArg = arg; 47 | } 48 | 49 | public long writeSecondArg() { 50 | return secondArg; 51 | } 52 | 53 | public long runOriginal(long arg) { 54 | return originalFunction.applyAsLong(arg, secondArg); 55 | } 56 | 57 | public long runMutated(long arg) { 58 | return mutatorFunction.applyAsLong(arg, secondArg); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/LongUnaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.LongUnaryOperator; 7 | 8 | public class LongUnaryOperatorMutator extends Mutator { 9 | 10 | private LongUnaryOperator originalFunction; 11 | private LongUnaryOperator mutatorFunction; 12 | 13 | LongUnaryOperatorMutator(String name, boolean useInfection, LongUnaryOperator originalFunction, LongUnaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatorFunction = mutatorFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.LONG_TYPE; 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.LONG_TYPE; 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(J)J"; 37 | } 38 | 39 | public static LongUnaryOperatorMutator getMutator(int id) { 40 | return (LongUnaryOperatorMutator) Mutator.allMutators.get(id); 41 | } 42 | 43 | public long runOriginal(long arg) { 44 | return originalFunction.applyAsLong(arg); 45 | } 46 | 47 | public long runMutated(long arg) { 48 | return mutatorFunction.applyAsLong(arg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/NoOpMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.IntBinaryOperator; 7 | 8 | public class NoOpMutator extends Mutator { 9 | 10 | public NoOpMutator(String name, int toReplace, String returnType, InstructionCall... replaceWith) { 11 | super(name, false, toReplace, returnType, replaceWith); 12 | } 13 | 14 | @Override 15 | public Type getOperandType() { 16 | return null; 17 | } 18 | 19 | @Override 20 | public Type getReturnType() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public int getNumArgs() { 26 | return 0; 27 | } 28 | 29 | @Override 30 | public String getMethodDescriptor() { 31 | return null; 32 | } 33 | 34 | public static NoOpMutator getMutator(int id) { 35 | return (NoOpMutator) Mutator.allMutators.get(id); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/ObjectUnaryOperatorMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.UnaryOperator; 7 | 8 | public class ObjectUnaryOperatorMutator extends Mutator { 9 | 10 | private UnaryOperator originalFunction; 11 | private UnaryOperator mutatorFunction; 12 | 13 | ObjectUnaryOperatorMutator(String name, boolean useInfection, UnaryOperator originalFunction, UnaryOperator mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatorFunction = mutatorFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.getObjectType("java/lang/Object"); 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.getObjectType("java/lang/Object"); 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(Ljava/lang/Object;)Ljava/lang/Object;"; 37 | } 38 | 39 | public static ObjectUnaryOperatorMutator getMutator(int id) { 40 | return (ObjectUnaryOperatorMutator) Mutator.allMutators.get(id); 41 | } 42 | 43 | public Object runOriginal(Object arg) { 44 | return originalFunction.apply(arg); 45 | } 46 | 47 | public Object runMutated(Object arg) { 48 | return mutatorFunction.apply(arg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/mutators/ObjectUnaryPredicateMutator.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.mutators; 2 | 3 | import cmu.pasta.mu2.instrument.InstructionCall; 4 | import org.objectweb.asm.Type; 5 | 6 | import java.util.function.Predicate; 7 | 8 | public class ObjectUnaryPredicateMutator extends Mutator { 9 | 10 | private Predicate originalFunction; 11 | private Predicate mutatorFunction; 12 | 13 | ObjectUnaryPredicateMutator(String name, boolean useInfection, Predicate originalFunction, Predicate mutatorFunction, int toReplace, String returnType, InstructionCall... replaceWith) { 14 | super(name, useInfection, toReplace, returnType, replaceWith); 15 | this.originalFunction = originalFunction; 16 | this.mutatorFunction = mutatorFunction; 17 | } 18 | 19 | @Override 20 | public Type getOperandType() { 21 | return Type.getObjectType("java/lang/Object"); 22 | } 23 | 24 | @Override 25 | public Type getReturnType() { 26 | return Type.BOOLEAN_TYPE; 27 | } 28 | 29 | @Override 30 | public int getNumArgs() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public String getMethodDescriptor() { 36 | return "(Ljava/lang/Object;)Z"; 37 | } 38 | 39 | public boolean runOriginal(Object arg) { 40 | return originalFunction.test(arg); 41 | } 42 | 43 | public boolean runMutated(Object arg) { 44 | return mutatorFunction.test(arg); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/cmu/pasta/mu2/util/ArraySet.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.util; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * ArraySet - an integer set backed by an array 7 | */ 8 | public class ArraySet { 9 | 10 | private static final int INITIAL_ARRAYSET_SIZE = 10; 11 | 12 | boolean[] bs = new boolean[INITIAL_ARRAYSET_SIZE]; 13 | 14 | public void reset() { 15 | for (int i = 0; i < bs.length; i++) { 16 | bs[i] = false; 17 | } 18 | } 19 | 20 | public void add(int i) { 21 | ensureHas(i); 22 | bs[i] = true; 23 | } 24 | 25 | public boolean contains(int i) { 26 | return i < bs.length && bs[i]; 27 | } 28 | 29 | private void ensureHas(int i) { 30 | if (bs.length > i) { 31 | return; 32 | } 33 | 34 | int len = bs.length; 35 | 36 | while (len <= i) { 37 | len *= 2; 38 | } 39 | 40 | if (len != bs.length) { 41 | bs = Arrays.copyOf(bs, len); 42 | } 43 | } 44 | 45 | public int size() { 46 | int s = 0; 47 | for (int i = 0; i < bs.length; i++) { 48 | if (bs[i]) { 49 | s++; 50 | } 51 | } 52 | return s; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/test/java/cmu/pasta/mu2/fuzz/FileMutantFilterTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.mutators.Mutator; 5 | import org.junit.After; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.io.FileWriter; 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class FileMutantFilterTest { 18 | 19 | static final String fileName = "testFileForFilter.txt"; 20 | static File testFile; 21 | static FileWriter writer; 22 | 23 | List muts; 24 | @Before 25 | public void createFile() throws IOException { 26 | Mutator.initializeMutators(); 27 | muts = new ArrayList<>(Arrays.asList( 28 | //add to sub 29 | new MutationInstance("ExampleClass", Mutator.allMutators.get(0), 1, 1, "ExampleClass.java"), 30 | //mul to div 31 | new MutationInstance("ExampleClass", Mutator.allMutators.get(2), 2, 2, "ExampleClass.java"), 32 | //div to mul 33 | new MutationInstance("ExampleClass2",Mutator.allMutators.get(3), 3, 2, "ExampleClass2.java"), 34 | //sub to add 35 | new MutationInstance("ExampleClass2",Mutator.allMutators.get(1), 4, 42, "ExampleClass2.java") 36 | )); 37 | testFile = File.createTempFile("test",null); 38 | writer = new FileWriter(testFile.getAbsolutePath()); 39 | } 40 | 41 | @After 42 | public void deleteFile(){ 43 | testFile.delete(); 44 | } 45 | 46 | 47 | @Test 48 | public void testFileNum() throws IOException { 49 | writer.write("ExampleClass2.java:42\nExampleClass.java:2\nClassThatDoesNotExist.java:1444"); 50 | writer.close(); 51 | FileMutantFilter filter = new FileMutantFilter(testFile.getAbsolutePath()); 52 | List filteredMutants = filter.filterMutants(muts); 53 | Assert.assertTrue(filteredMutants.contains(muts.get(3))); 54 | Assert.assertTrue(filteredMutants.contains(muts.get(1))); 55 | } 56 | @Test 57 | public void testUniqId() throws IOException { 58 | writer.write("ExampleClass2:I_SUB_TO_ADD:4\nExampleClass:I_MUL_TO_DIV:2\nClassThatDoesNotExist.java:1444"); 59 | writer.close(); 60 | FileMutantFilter filter = new FileMutantFilter(testFile.getAbsolutePath()); 61 | List filteredMutants = filter.filterMutants(muts); 62 | System.out.println(filteredMutants); 63 | Assert.assertTrue(filteredMutants.contains(muts.get(1))); 64 | Assert.assertTrue(filteredMutants.contains(muts.get(3))); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /core/src/test/java/cmu/pasta/mu2/fuzz/KLeastExecutedFilterTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | import cmu.pasta.mu2.instrument.MutationInstance; 10 | 11 | import cmu.pasta.mu2.mutators.Mutator; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.junit.runners.JUnit4; 17 | 18 | import static org.junit.Assert.*; 19 | 20 | @RunWith(JUnit4.class) 21 | public class KLeastExecutedFilterTest { 22 | 23 | List toFilter; 24 | @Before 25 | public void initMutators() { 26 | Mutator.initializeMutators(); 27 | toFilter = new ArrayList<>(Arrays.asList( 28 | //add to sub 29 | new MutationInstance("ExampleClass", Mutator.allMutators.get(0), 1, 1, "ExampleClass.java"), 30 | //mul to div 31 | new MutationInstance("ExampleClass", Mutator.allMutators.get(2), 2, 2, "ExampleClass.java"), 32 | //div to mul 33 | new MutationInstance("ExampleClass2", Mutator.allMutators.get(3), 3, 2, "ExampleClass2.java"), 34 | //sub to add 35 | new MutationInstance("ExampleClass2", Mutator.allMutators.get(1), 4, 42, "ExampleClass2.java"), 36 | //sub to add 37 | new MutationInstance("ExampleClass3", Mutator.allMutators.get(1), 5, 42, "ExampleClass3.java") 38 | )); 39 | } 40 | 41 | @Test 42 | public void filteredListSizeIsCorrect1(){ 43 | int k = 3; 44 | // instantiate random filter with parameter k 45 | KLeastExecutedFilter filter = new KLeastExecutedFilter(k); 46 | // call filter method to obtain filtered list 47 | List filteredList = filter.filterMutants(toFilter); 48 | // filtered list should be of size k 49 | assertEquals(k, filteredList.size()); 50 | } 51 | 52 | @Test 53 | public void filteredListSizeIsCorrect2(){ 54 | int k = 5; 55 | // instantiate random filter with parameter k 56 | KLeastExecutedFilter filter = new KLeastExecutedFilter(k); 57 | // call filter method to obtain filtered list 58 | List filteredList = filter.filterMutants(toFilter); 59 | // filtered list should be of size k 60 | assertEquals(k, filteredList.size()); 61 | } 62 | 63 | @Test 64 | public void filteredListSizeIsCorrect3(){ 65 | int k = 7; 66 | // instantiate random filter with parameter k 67 | KLeastExecutedFilter filter = new KLeastExecutedFilter(k); 68 | // call filter method to obtain filtered list 69 | List filteredList = filter.filterMutants(toFilter); 70 | // filtered list should be of same size as toFilter 71 | assertEquals(toFilter.size(), filteredList.size()); 72 | } 73 | 74 | @Test 75 | public void leastExecutedLogicWorks(){ 76 | 77 | //TODO 78 | Set newMutants = new HashSet<>(Arrays.asList( 79 | //add to sub 80 | new MutationInstance("New1", Mutator.allMutators.get(0), 6, 1, "New1.java"), 81 | //sub to add 82 | new MutationInstance("New2", Mutator.allMutators.get(1), 7, 1, "New2.java"), 83 | //div to mul 84 | new MutationInstance("New3", Mutator.allMutators.get(3), 8, 1, "New3.java") 85 | )); 86 | 87 | KLeastExecutedFilter filter = new KLeastExecutedFilter(5); 88 | 89 | // Filter original mutants so that all are executed once 90 | List originalMutants = filter.filterMutants(toFilter); 91 | // All mutants should be contained in filtered list 92 | assertEquals(5, originalMutants.size()); 93 | // Add new mutants to combined list 94 | List allMutants = new ArrayList<>(toFilter); 95 | allMutants.addAll(newMutants); 96 | 97 | // Filter list again 98 | List filtered1 = filter.filterMutants(allMutants); 99 | // New (never-executed) mutants should all be in filtered list to be executed 100 | assertTrue(filtered1.containsAll(newMutants)); 101 | // Count number of original mutants in filtered list, add to set of mutants that have been executed twice 102 | int count = 0; 103 | Set executedTwice = new HashSet<>(); 104 | for (MutationInstance mutant: filtered1){ 105 | if (originalMutants.contains(mutant)) { 106 | count += 1; 107 | executedTwice.add(mutant); 108 | } 109 | } 110 | // Filtered list should contain 5-3=2 original mutants 111 | assertEquals(2, count); 112 | 113 | // Filter list again 114 | List filtered2 = filter.filterMutants(allMutants); 115 | // Filtered list should not contain any of the 2 mutants that have been executed twice 116 | for (MutationInstance mutant : executedTwice) { 117 | assertFalse(filtered2.contains(mutant)); 118 | } 119 | // Add all recently executed mutants to executedTwice 120 | for (MutationInstance mutant : filtered2) { 121 | executedTwice.add(mutant); 122 | } 123 | // All mutants except 1 should now have been executed twice 124 | assertEquals(7,executedTwice.size()); 125 | 126 | // Filter list again 127 | List filtered3 = filter.filterMutants(allMutants); 128 | // The 1 remaining once-executed should be contained (the rest have all been executed twice) 129 | boolean found = false; 130 | for (MutationInstance mutant : filtered3) { 131 | if (!executedTwice.contains(mutant)){ 132 | found = true; 133 | break; 134 | } 135 | } 136 | assertTrue(found); 137 | 138 | } 139 | 140 | /** 141 | * 142 | */ 143 | @Test 144 | public void filteringDoesNotAddNewMutants(){ 145 | 146 | 147 | Set newMutants = new HashSet<>(Arrays.asList( 148 | //add to sub 149 | new MutationInstance("New1", Mutator.allMutators.get(0), 6, 1, "New1.java"), 150 | //sub to add 151 | new MutationInstance("New2", Mutator.allMutators.get(1), 7, 1, "New2.java"), 152 | //div to mul 153 | new MutationInstance("New3", Mutator.allMutators.get(3), 8, 1, "New3.java") 154 | )); 155 | 156 | KLeastExecutedFilter filter = new KLeastExecutedFilter(5); 157 | 158 | // Filter original mutants twice so that all are executed twice 159 | List originalMutants = filter.filterMutants(filter.filterMutants(toFilter)); 160 | // Check that execution counts are correctly incremented 161 | for (MutationInstance mutant : originalMutants){ 162 | assertEquals(2, filter.executionCounts.get(mutant).intValue()); 163 | } 164 | // Filter newMutants so all are executed once (new 1, old 2, if filter old, should not contain any new) 165 | List newMutantsList = new ArrayList<>(newMutants); 166 | newMutantsList = filter.filterMutants(newMutantsList); 167 | // Check that execution counts are correctly incremented 168 | for (MutationInstance mutant : newMutantsList) { 169 | assertEquals(1, filter.executionCounts.get(mutant).intValue()); 170 | } 171 | 172 | // Filter original mutants with k = 5 173 | originalMutants = filter.filterMutants(originalMutants); 174 | // Check that all original mutants and no new mutants are in filtered list 175 | for (MutationInstance mutant : originalMutants){ 176 | assertEquals(3, filter.executionCounts.get(mutant).intValue()); 177 | } 178 | for (MutationInstance mutant : newMutantsList){ 179 | assertEquals(1, filter.executionCounts.get(mutant).intValue()); 180 | } 181 | 182 | // Filter original mutants 183 | originalMutants.remove(4); 184 | originalMutants.remove(3); 185 | List filteredOriginalMutants = filter.filterMutants(originalMutants); 186 | // Check that the filtered list is of correct size 187 | assertEquals(3, filteredOriginalMutants.size()); 188 | // Check that all original mutants and no new mutants are in filtered list 189 | for (MutationInstance mutant : filteredOriginalMutants){ 190 | assertEquals(4, filter.executionCounts.get(mutant).intValue()); 191 | } 192 | for (MutationInstance mutant : newMutantsList){ 193 | assertEquals(1, filter.executionCounts.get(mutant).intValue()); 194 | } 195 | } 196 | } 197 | 198 | -------------------------------------------------------------------------------- /core/src/test/java/cmu/pasta/mu2/fuzz/KRandomFilterTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.fuzz; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import cmu.pasta.mu2.instrument.MutationInstance; 8 | import cmu.pasta.mu2.mutators.Mutator; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.junit.runners.JUnit4; 14 | 15 | import static org.junit.Assert.*; 16 | 17 | @RunWith(JUnit4.class) 18 | public class KRandomFilterTest{ 19 | 20 | List toFilter; 21 | 22 | @Before 23 | public void initMutators() { 24 | Mutator.initializeMutators(); 25 | toFilter = new ArrayList<>(Arrays.asList( 26 | //add to sub 27 | new MutationInstance("ExampleClass", Mutator.allMutators.get(0), 1, 1, "ExampleClass.java"), 28 | //mul to div 29 | new MutationInstance("ExampleClass", Mutator.allMutators.get(2), 2, 2, "ExampleClass.java"), 30 | //div to mul 31 | new MutationInstance("ExampleClass2", Mutator.allMutators.get(3), 3, 2, "ExampleClass2.java"), 32 | //sub to add 33 | new MutationInstance("ExampleClass2", Mutator.allMutators.get(1), 4, 42, "ExampleClass2.java"), 34 | //sub to add 35 | new MutationInstance("ExampleClass3", Mutator.allMutators.get(1), 5, 42, "ExampleClass3.java") 36 | )); 37 | } 38 | 39 | @Test 40 | public void filteredListSizeIsCorrect1(){ 41 | int k = 3; 42 | // instantiate random filter with parameter k 43 | KRandomFilter filter = new KRandomFilter(k); 44 | // call filter method to obtain filtered list 45 | List filteredList = filter.filterMutants(toFilter); 46 | // filtered list should be of size k 47 | assertEquals(k, filteredList.size()); 48 | } 49 | 50 | @Test 51 | public void filteredListSizeIsCorrect2(){ 52 | int k = 5; 53 | // instantiate random filter with parameter k 54 | KRandomFilter filter = new KRandomFilter(k); 55 | // call filter method to obtain filtered list 56 | List filteredList = filter.filterMutants(toFilter); 57 | // filtered list should be of size k 58 | assertEquals(k, filteredList.size()); 59 | } 60 | 61 | @Test 62 | public void filteredListSizeIsCorrect3(){ 63 | int k = 7; 64 | // instantiate random filter with parameter k 65 | KRandomFilter filter = new KRandomFilter(k); 66 | // call filter method to obtain filtered list 67 | List filteredList = filter.filterMutants(toFilter); 68 | // filtered list should be of same size as toFilter 69 | assertEquals(toFilter.size(), filteredList.size()); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /core/src/test/java/cmu/pasta/mu2/instrument/CartographyTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.instrument; 2 | 3 | public class CartographyTest { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mu2 7 | cmu.pasta.mu2 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mu2-examples 13 | 14 | 15 | central 16 | https://repo1.maven.org/maven2 17 | 18 | 19 | chocopy-artifacts 20 | chocopy/chocopy artifacts 21 | https://raw.githubusercontent.com/chocopy/artifacts/main 22 | 23 | 24 | 25 | 26 | 27 | cmu.pasta.mu2 28 | mu2-core 29 | 1.0-SNAPSHOT 30 | 31 | 32 | junit 33 | junit 34 | 4.13.1 35 | test 36 | 37 | 38 | edu.berkeley.cs.jqf 39 | jqf-fuzz 40 | 2.0 41 | test 42 | 43 | 44 | edu.berkeley.cs.jqf 45 | jqf-examples 46 | 2.0 47 | test 48 | 49 | 50 | org.apache.commons 51 | commons-collections4 52 | 4.3 53 | test 54 | 55 | 56 | com.google.code.gson 57 | gson 58 | 2.8.9 59 | test 60 | 61 | 62 | com.fasterxml.jackson.core 63 | jackson-databind 64 | 2.13.0 65 | test 66 | 67 | 68 | org.chocopy 69 | chocopy-artifacts 70 | 2.2 71 | test 72 | 73 | 74 | org.apache.tomcat 75 | tomcat-catalina 76 | 10.1.0-M10 77 | test 78 | 79 | 80 | com.google.javascript 81 | closure-compiler 82 | v20220202 83 | test 84 | 85 | 86 | 87 | 88 | 89 | 90 | edu.berkeley.cs.jqf 91 | jqf-maven-plugin 92 | 2.0 93 | 94 | 95 | cmu.pasta.mu2 96 | mu2-core 97 | 1.0-SNAPSHOT 98 | 99 | 100 | cmu.pasta.mu2 101 | mu2-core 102 | 1.0-SNAPSHOT 103 | 104 | 105 | org.apache.maven.plugins 106 | maven-surefire-plugin 107 | 2.22.2 108 | true 109 | 110 | 111 | org.apache.maven.plugins 112 | maven-jar-plugin 113 | 3.3.0 114 | 115 | 116 | 117 | test-jar 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * @author Varun Upadhyay (https://github.com/varunu28) 7 | * @author Podshivalov Nikita (https://github.com/nikitap492) 8 | * @see SortAlgorithm 9 | */ 10 | public class BubbleSort implements SortAlgorithm { 11 | 12 | /** 13 | * This method implements the Generic Bubble Sort 14 | * 15 | * @param array The array to be sorted Sorts the array in ascending order 16 | */ 17 | @Override 18 | public > T[] sort(T[] array) { 19 | for (int i = 0, size = array.length; i < size - 1; ++i) { 20 | boolean swapped = false; 21 | for (int j = 0; j < size - 1 - i; ++j) { 22 | if (greater(array[j], array[j + 1])) { 23 | swap(array, j, j + 1); 24 | swapped = true; 25 | } 26 | } 27 | if (!swapped) { 28 | break; 29 | } 30 | } 31 | return array; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/CocktailShakerSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | /** 4 | * @author Mateus Bizzo (https://github.com/MattBizzo) 5 | * @author Podshivalov Nikita (https://github.com/nikitap492) 6 | */ 7 | class CocktailShakerSort implements SortAlgorithm { 8 | 9 | /** 10 | * This method implements the Generic Cocktail Shaker Sort 11 | * 12 | * @param array The array to be sorted Sorts the array in increasing order 13 | */ 14 | @Override 15 | public > T[] sort(T[] array) { 16 | 17 | int length = array.length; 18 | int left = 0; 19 | int right = length - 1; 20 | int swappedLeft, swappedRight; 21 | while (left < right) { 22 | // front 23 | swappedRight = 0; 24 | for (int i = left; i < right; i++) { 25 | if (SortUtils.less(array[i + 1], array[i])) { 26 | SortUtils.swap(array, i, i + 1); 27 | swappedRight = i; 28 | } 29 | } 30 | // back 31 | right = swappedRight; 32 | swappedLeft = length - 1; 33 | for (int j = right; j > left; j--) { 34 | if (SortUtils.less(array[j], array[j - 1])) { 35 | SortUtils.swap(array, j - 1, j); 36 | swappedLeft = j; 37 | } 38 | } 39 | left = swappedLeft; 40 | } 41 | return array; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/CombSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * Comb Sort algorithm implementation 7 | * 8 | *

Best-case performance O(n * log(n)) Worst-case performance O(n ^ 2) Worst-case space 9 | * complexity O(1) 10 | * 11 | *

Comb sort improves on bubble sort. 12 | * 13 | * @author Sandeep Roy (https://github.com/sandeeproy99) 14 | * @author Podshivalov Nikita (https://github.com/nikitap492) 15 | * @see BubbleSort 16 | * @see SortAlgorithm 17 | */ 18 | class CombSort implements SortAlgorithm { 19 | 20 | // To find gap between elements 21 | private int nextGap(int gap) { 22 | // Shrink gap by Shrink factor 23 | gap = (gap * 10) / 13; 24 | return (gap < 1) ? 1 : gap; 25 | } 26 | 27 | /** 28 | * Function to sort arr[] using Comb 29 | * 30 | * @param arr - an array should be sorted 31 | * @return sorted array 32 | */ 33 | @Override 34 | public > T[] sort(T[] arr) { 35 | int size = arr.length; 36 | 37 | // initialize gap 38 | int gap = size; 39 | 40 | // Initialize swapped as true to make sure that loop runs 41 | boolean swapped = true; 42 | 43 | // Keep running while gap is more than 1 and last iteration caused a swap 44 | while (gap != 1 || swapped) { 45 | // Find next gap 46 | gap = nextGap(gap); 47 | 48 | // Initialize swapped as false so that we can check if swap happened or not 49 | swapped = false; 50 | 51 | // Compare all elements with current gap 52 | for (int i = 0; i < size - gap; i++) { 53 | if (less(arr[i + gap], arr[i])) { 54 | // Swap arr[i] and arr[i+gap] 55 | swapped = swap(arr, i, i + gap); 56 | } 57 | } 58 | } 59 | return arr; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/CycleSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** @author Podshivalov Nikita (https://github.com/nikitap492) */ 6 | class CycleSort implements SortAlgorithm { 7 | 8 | @Override 9 | public > T[] sort(T[] arr) { 10 | int n = arr.length; 11 | 12 | // traverse array elements 13 | for (int j = 0; j <= n - 2; j++) { 14 | // initialize item as starting point 15 | T item = arr[j]; 16 | 17 | // Find position where we put the item. 18 | int pos = j; 19 | for (int i = j + 1; i < n; i++) if (less(arr[i], item)) pos++; 20 | 21 | // If item is already in correct position 22 | if (pos == j) continue; 23 | 24 | // ignore all duplicate elements 25 | while (item.compareTo(arr[pos]) == 0) pos += 1; 26 | 27 | // put the item to it's right position 28 | if (pos != j) { 29 | item = replace(arr, pos, item); 30 | } 31 | 32 | // Rotate rest of the cycle 33 | while (pos != j) { 34 | pos = j; 35 | 36 | // Find position where we put the element 37 | for (int i = j + 1; i < n; i++) 38 | if (less(arr[i], item)) { 39 | pos += 1; 40 | } 41 | 42 | // ignore all duplicate elements 43 | while (item.compareTo(arr[pos]) == 0) pos += 1; 44 | 45 | // put the item to it's right position 46 | if (item != arr[pos]) { 47 | item = replace(arr, pos, item); 48 | } 49 | } 50 | } 51 | 52 | return arr; 53 | } 54 | 55 | private > T replace(T[] arr, int pos, T item) { 56 | T temp = item; 57 | item = arr[pos]; 58 | arr[pos] = temp; 59 | return item; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/GnomeSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * Implementation of gnome sort 7 | * 8 | * @author Podshivalov Nikita (https://github.com/nikitap492) 9 | * @since 2018-04-10 10 | */ 11 | public class GnomeSort implements SortAlgorithm { 12 | 13 | @Override 14 | public > T[] sort(T[] arr) { 15 | int i = 1; 16 | int j = 2; 17 | while (i < arr.length) { 18 | if (less(arr[i - 1], arr[i])) i = j++; 19 | else { 20 | swap(arr, i - 1, i); 21 | if (--i == 0) { 22 | i = j++; 23 | } 24 | } 25 | } 26 | 27 | return arr; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/HeapSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * Heap Sort Algorithm Implements MinHeap 11 | * 12 | * @author Podshivalov Nikita (https://github.com/nikitap492) 13 | */ 14 | public class HeapSort implements SortAlgorithm { 15 | 16 | private static class Heap> { 17 | /** Array to store heap */ 18 | private T[] heap; 19 | 20 | /** 21 | * Constructor 22 | * 23 | * @param heap array of unordered integers 24 | */ 25 | public Heap(T[] heap) { 26 | this.heap = heap; 27 | } 28 | 29 | /** 30 | * Heapifies subtree from top as root to last as last child 31 | * 32 | * @param rootIndex index of root 33 | * @param lastChild index of last child 34 | */ 35 | private void heapSubtree(int rootIndex, int lastChild) { 36 | int leftIndex = rootIndex * 2 + 1; 37 | int rightIndex = rootIndex * 2 + 2; 38 | T root = heap[rootIndex]; 39 | if (rightIndex <= lastChild) { // if has right and left children 40 | T left = heap[leftIndex]; 41 | T right = heap[rightIndex]; 42 | if (less(left, right) && less(left, root)) { 43 | swap(heap, leftIndex, rootIndex); 44 | heapSubtree(leftIndex, lastChild); 45 | } else if (less(right, root)) { 46 | swap(heap, rightIndex, rootIndex); 47 | heapSubtree(rightIndex, lastChild); 48 | } 49 | } else if (leftIndex <= lastChild) { // if no right child, but has left child 50 | T left = heap[leftIndex]; 51 | if (less(left, root)) { 52 | swap(heap, leftIndex, rootIndex); 53 | heapSubtree(leftIndex, lastChild); 54 | } 55 | } 56 | } 57 | 58 | /** 59 | * Makes heap with root as root 60 | * 61 | * @param root index of root of heap 62 | */ 63 | private void makeMinHeap(int root) { 64 | int leftIndex = root * 2 + 1; 65 | int rightIndex = root * 2 + 2; 66 | boolean hasLeftChild = leftIndex < heap.length; 67 | boolean hasRightChild = rightIndex < heap.length; 68 | if (hasRightChild) { // if has left and right 69 | makeMinHeap(leftIndex); 70 | makeMinHeap(rightIndex); 71 | heapSubtree(root, heap.length - 1); 72 | } else if (hasLeftChild) { 73 | heapSubtree(root, heap.length - 1); 74 | } 75 | } 76 | 77 | /** 78 | * Gets the root of heap 79 | * 80 | * @return root of heap 81 | */ 82 | private T getRoot(int size) { 83 | swap(heap, 0, size); 84 | heapSubtree(0, size - 1); 85 | return heap[size]; // return old root 86 | } 87 | } 88 | 89 | // @Override 90 | // public > T[] sort(T[] unsorted) { 91 | // return sort(Arrays.asList(unsorted)).toArray(unsorted); 92 | // } 93 | 94 | @Override 95 | public > List sort(List unsorted) { 96 | int size = unsorted.size(); 97 | 98 | @SuppressWarnings("unchecked") 99 | Heap heap = new Heap<>(unsorted.toArray((T[]) new Comparable[unsorted.size()])); 100 | 101 | heap.makeMinHeap(0); // make min heap using index 0 as root. 102 | List sorted = new ArrayList<>(size); 103 | while (size > 0) { 104 | T min = heap.getRoot(--size); 105 | sorted.add(min); 106 | } 107 | 108 | return sorted; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/InsertionSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * @author Varun Upadhyay (https://github.com/varunu28) 7 | * @author Podshivalov Nikita (https://github.com/nikitap492) 8 | */ 9 | class InsertionSort implements SortAlgorithm { 10 | 11 | /** 12 | * This method implements the Generic Insertion Sort Sorts the array in increasing order 13 | * 14 | * @param array The array to be sorted 15 | */ 16 | @Override 17 | public > T[] sort(T[] array) { 18 | for (int j = 1; j < array.length; j++) { 19 | 20 | // Picking up the key(Card) 21 | T key = array[j]; 22 | int i = j - 1; 23 | 24 | while (i >= 0 && less(key, array[i])) { 25 | array[i + 1] = array[i]; 26 | i--; 27 | } 28 | // Placing the key (Card) at its correct position in the sorted subarray 29 | array[i + 1] = key; 30 | } 31 | return array; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/MergeSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * This method implements the Generic Merge Sort 7 | * 8 | * @author Varun Upadhyay (https://github.com/varunu28) 9 | * @author Podshivalov Nikita (https://github.com/nikitap492) 10 | * @see SortAlgorithm 11 | */ 12 | class MergeSort implements SortAlgorithm { 13 | 14 | /** 15 | * This method implements the Generic Merge Sort 16 | * 17 | * @param unsorted the array which should be sorted 18 | * @param Comparable class 19 | * @return sorted array 20 | */ 21 | @Override 22 | public > T[] sort(T[] unsorted) { 23 | doSort(unsorted, 0, unsorted.length - 1); 24 | return unsorted; 25 | } 26 | 27 | /** 28 | * @param arr The array to be sorted 29 | * @param left The first index of the array 30 | * @param right The last index of the array Recursively sorts the array in increasing order 31 | */ 32 | private static > void doSort(T[] arr, int left, int right) { 33 | if (left < right) { 34 | int mid = left + (right - left) / 2; 35 | doSort(arr, left, mid); 36 | doSort(arr, mid + 1, right); 37 | merge(arr, left, mid, right); 38 | } 39 | } 40 | 41 | /** 42 | * This method implements the merge step of the merge sort 43 | * 44 | * @param arr The array to be sorted 45 | * @param left The first index of the array 46 | * @param mid The middle index of the array 47 | * @param right The last index of the array merges two parts of an array in increasing order 48 | */ 49 | private static > void merge(T[] arr, int left, int mid, int right) { 50 | int length = right - left + 1; 51 | T[] temp = (T[]) new Comparable[length]; 52 | int i = left; 53 | int j = mid + 1; 54 | int k = 0; 55 | 56 | while (i <= mid && j <= right) { 57 | if (arr[i].compareTo(arr[j]) <= 0) { 58 | temp[k++] = arr[i++]; 59 | } else { 60 | temp[k++] = arr[j++]; 61 | } 62 | } 63 | 64 | while (i <= mid) { 65 | temp[k++] = arr[i++]; 66 | } 67 | 68 | while (j <= right) { 69 | temp[k++] = arr[j++]; 70 | } 71 | 72 | System.arraycopy(temp, 0, arr, left, length); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/PancakeSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * Implementation of gnome sort 7 | * 8 | * @author Podshivalov Nikita (https://github.com/nikitap492) 9 | * @since 2018-04-10 10 | */ 11 | public class PancakeSort implements SortAlgorithm { 12 | 13 | @Override 14 | public > T[] sort(T[] array) { 15 | int size = array.length; 16 | 17 | for (int i = 0; i < size; i++) { 18 | T max = array[0]; 19 | int index = 0; 20 | for (int j = 0; j < size - i; j++) { 21 | if (less(max, array[j])) { 22 | max = array[j]; 23 | index = j; 24 | } 25 | } 26 | flip(array, index, array.length - 1 - i); 27 | } 28 | return array; 29 | } 30 | 31 | /** 32 | * Swaps all position from {@param left} to @{@param right} for {@param array} 33 | * 34 | * @param array is an array 35 | * @param left is a left flip border of the array 36 | * @param right is a right flip border of the array 37 | */ 38 | private static > void flip(T[] array, int left, int right) { 39 | while (left <= right) { 40 | swap(array, left++, right--); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/QuickSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * @author Varun Upadhyay (https://github.com/varunu28) 7 | * @author Podshivalov Nikita (https://github.com/nikitap492) 8 | * @see SortAlgorithm 9 | */ 10 | class QuickSort implements SortAlgorithm { 11 | 12 | /** 13 | * This method implements the Generic Quick Sort 14 | * 15 | * @param array The array to be sorted Sorts the array in increasing order 16 | */ 17 | @Override 18 | public > T[] sort(T[] array) { 19 | doSort(array, 0, array.length - 1); 20 | return array; 21 | } 22 | 23 | /** 24 | * The sorting process 25 | * 26 | * @param left The first index of an array 27 | * @param right The last index of an array 28 | * @param array The array to be sorted 29 | */ 30 | private static > void doSort(T[] array, int left, int right) { 31 | if (left < right) { 32 | int pivot = randomPartition(array, left, right); 33 | doSort(array, left, pivot - 1); 34 | doSort(array, pivot, right); 35 | } 36 | } 37 | 38 | /** 39 | * Ramdomize the array to avoid the basically ordered sequences 40 | * 41 | * @param array The array to be sorted 42 | * @param left The first index of an array 43 | * @param right The last index of an array 44 | * @return the partition index of the array 45 | */ 46 | private static > int randomPartition(T[] array, int left, int right) { 47 | int randomIndex = left + (int) (Math.random() * (right - left + 1)); 48 | swap(array, randomIndex, right); 49 | return partition(array, left, right); 50 | } 51 | 52 | /** 53 | * This method finds the partition index for an array 54 | * 55 | * @param array The array to be sorted 56 | * @param left The first index of an array 57 | * @param right The last index of an array Finds the partition index of an array 58 | */ 59 | private static > int partition(T[] array, int left, int right) { 60 | int mid = (left + right) >>> 1; 61 | T pivot = array[mid]; 62 | 63 | while (left <= right) { 64 | while (less(array[left], pivot)) { 65 | ++left; 66 | } 67 | while (less(pivot, array[right])) { 68 | --right; 69 | } 70 | if (left <= right) { 71 | swap(array, left, right); 72 | ++left; 73 | --right; 74 | } 75 | } 76 | return left; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | /** 6 | * @author Varun Upadhyay (https://github.com/varunu28) 7 | * @author Podshivalov Nikita (https://github.com/nikitap492) 8 | * @see SortAlgorithm 9 | */ 10 | public class SelectionSort implements SortAlgorithm { 11 | 12 | /** 13 | * This method swaps the two elements in the array 14 | * 15 | * @param 16 | * @param arr, i, j The array for the swap and the indexes of the to-swap elements 17 | */ 18 | public void swap(T[] arr, int i, int j) { 19 | T temp = arr[i]; 20 | arr[i] = arr[j]; 21 | arr[j] = temp; 22 | } 23 | 24 | /** 25 | * This method implements the Generic Selection Sort 26 | * 27 | * @param arr The array to be sorted Sorts the array in increasing order 28 | */ 29 | @Override 30 | public > T[] sort(T[] arr) { 31 | int n = arr.length; 32 | for (int i = 0; i < n - 1; i++) { 33 | // Initial index of min 34 | int min = i; 35 | 36 | for (int j = i + 1; j < n; j++) { 37 | if (arr[min].compareTo(arr[j]) > 0) { 38 | min = j; 39 | } 40 | } 41 | 42 | // Swapping if index of min is changed 43 | if (min != i) { 44 | swap(arr, i, min); 45 | } 46 | } 47 | 48 | return arr; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/ShellSort.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import static cmu.pasta.mu2.examples.sort.SortUtils.*; 4 | 5 | public class ShellSort implements SortAlgorithm { 6 | 7 | /** 8 | * This method implements Generic Shell Sort. 9 | * 10 | * @param array the array to be sorted 11 | */ 12 | @Override 13 | public > T[] sort(T[] array) { 14 | int length = array.length; 15 | int gap = 1; 16 | 17 | /* Calculate gap for optimization purpose */ 18 | while (gap < length / 3) { 19 | gap = 3 * gap + 1; 20 | } 21 | 22 | for (; gap > 0; gap /= 3) { 23 | for (int i = gap; i < length; i++) { 24 | int j; 25 | T temp = array[i]; 26 | for (j = i; j >= gap && less(temp, array[j - gap]); j -= gap) { 27 | array[j] = array[j - gap]; 28 | } 29 | array[j] = temp; 30 | } 31 | } 32 | return array; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/SortAlgorithm.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * The common interface of most sorting algorithms. 8 | * 9 | * At least one of the two sort methods must be overridden. 10 | * 11 | * @author Podshivalov Nikita (https://github.com/nikitap492) 12 | */ 13 | public interface SortAlgorithm { 14 | 15 | /** 16 | * Method to sort arrays 17 | * 18 | * @param unsorted - an array should be sorted 19 | * @return a sorted array 20 | */ 21 | default > T[] sort(T[] unsorted) { 22 | return sort(Arrays.asList(unsorted)).toArray(unsorted); 23 | } 24 | 25 | /** 26 | * Method for algorithms what wanted to work with lists from JCF 27 | * 28 | * @param unsorted - a list should be sorted 29 | * @return a sorted list 30 | */ 31 | @SuppressWarnings("unchecked") 32 | default > List sort(List unsorted) { 33 | return Arrays.asList(sort(unsorted.toArray((T[]) new Comparable[unsorted.size()]))); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /examples/src/main/java/cmu/pasta/mu2/examples/sort/SortUtils.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * The class contains util methods 8 | * 9 | * @author Podshivalov Nikita (https://github.com/nikitap492) 10 | */ 11 | final class SortUtils { 12 | 13 | /** 14 | * Helper method for swapping places in array 15 | * 16 | * @param array The array which elements we want to swap 17 | * @param idx index of the first element 18 | * @param idy index of the second element 19 | */ 20 | static boolean swap(T[] array, int idx, int idy) { 21 | T swap = array[idx]; 22 | array[idx] = array[idy]; 23 | array[idy] = swap; 24 | return true; 25 | } 26 | 27 | /** 28 | * This method checks if first element is less than the other element 29 | * 30 | * @param v first element 31 | * @param w second element 32 | * @return true if the first element is less than the second element 33 | */ 34 | static > boolean less(T v, T w) { 35 | return v.compareTo(w) < 0; 36 | } 37 | 38 | /** 39 | * This method checks if first element is greater than the other element 40 | * 41 | * @param v first element 42 | * @param w second element 43 | * @return true if the first element is greater than the second element 44 | */ 45 | static > boolean greater(T v, T w) { 46 | return v.compareTo(w) > 0; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/chocopy/ChocoPyTarget.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.chocopy; 2 | 3 | import chocopy.ChocoPy; 4 | import chocopy.common.astnodes.Program; 5 | import chocopy.common.astnodes.Node; 6 | import chocopy.reference.RefAnalysis; 7 | import chocopy.reference.RefParser; 8 | import com.pholser.junit.quickcheck.From; 9 | import org.junit.runner.RunWith; 10 | 11 | import com.fasterxml.jackson.databind.JsonNode; 12 | import com.fasterxml.jackson.core.JsonProcessingException; 13 | 14 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 15 | import edu.berkeley.cs.jqf.fuzz.JQF; 16 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 17 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 18 | 19 | import edu.berkeley.cs.jqf.examples.chocopy.ChocoPySemanticGenerator; 20 | import java.io.IOException; 21 | 22 | import static org.junit.Assert.assertTrue; 23 | import static org.junit.Assume.assumeTrue; 24 | import static org.junit.Assume.assumeNoException; 25 | 26 | @RunWith(JQF.class) 27 | public class ChocoPyTarget { 28 | 29 | @Fuzz(repro="${repro}") 30 | public void fuzzSemanticAnalysis(@From(ChocoPySemanticGenerator.class) String code) { 31 | Program program = RefParser.process(code, false); 32 | assumeTrue(!program.hasErrors()); 33 | Program refTypedProgram = RefAnalysis.process(program); 34 | try { 35 | Node.readTree(refTypedProgram.toJSON()); 36 | } catch (IOException e) { 37 | assumeNoException(e); 38 | } 39 | } 40 | 41 | @DiffFuzz 42 | public JsonNode testSemanticAnalysis(@From(ChocoPySemanticGenerator.class) String code) { 43 | Program program = RefParser.process(code, false); 44 | assumeTrue(!program.hasErrors()); 45 | Program refTypedProgram = RefAnalysis.process(program); 46 | JsonNode outputNode = null; 47 | try { 48 | outputNode = Node.readTree(refTypedProgram.toJSON()); 49 | } catch (IOException e) { 50 | assumeNoException(e); 51 | } 52 | return outputNode; 53 | } 54 | 55 | @DiffFuzz(cmp = "noncompare") 56 | public JsonNode testSemanticAnalysisNoncompare(@From(ChocoPySemanticGenerator.class) String code) { 57 | Program program = RefParser.process(code, false); 58 | assumeTrue(!program.hasErrors()); 59 | Program refTypedProgram = RefAnalysis.process(program); 60 | JsonNode outputNode = null; 61 | try { 62 | outputNode = Node.readTree(refTypedProgram.toJSON()); 63 | } catch (IOException e) { 64 | assumeNoException(e); 65 | } 66 | return outputNode; 67 | } 68 | 69 | @Comparison 70 | public static Boolean noncompare(JsonNode j1, JsonNode j2) { 71 | return true; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/closure/ClosureTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.closure; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.PrintStream; 7 | import java.nio.charset.StandardCharsets; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.logging.LogManager; 12 | 13 | import com.google.javascript.jscomp.CompilationLevel; 14 | import com.google.javascript.jscomp.Compiler; 15 | import com.google.javascript.jscomp.CompilerOptions; 16 | import com.google.javascript.jscomp.Result; 17 | import com.google.javascript.jscomp.SourceFile; 18 | import com.pholser.junit.quickcheck.From; 19 | import edu.berkeley.cs.jqf.examples.common.AsciiStringGenerator; 20 | import edu.berkeley.cs.jqf.examples.js.JavaScriptCodeGenerator; 21 | import org.apache.commons.io.IOUtils; 22 | import org.junit.Assume; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | 27 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 28 | import edu.berkeley.cs.jqf.fuzz.JQF; 29 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 30 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 31 | 32 | import static org.junit.Assume.assumeTrue; 33 | 34 | @RunWith(JQF.class) 35 | public class ClosureTest { 36 | 37 | static { 38 | // Disable all logging by Closure passes 39 | LogManager.getLogManager().reset(); 40 | } 41 | 42 | private Compiler compiler = new Compiler(new PrintStream(new ByteArrayOutputStream(), false)); 43 | private CompilerOptions options = new CompilerOptions(); 44 | private SourceFile externs = SourceFile.fromCode("externs", ""); 45 | 46 | @Before 47 | public void initCompiler() { 48 | // Don't use threads 49 | compiler.disableThreads(); 50 | // Don't print things 51 | options.setPrintConfig(false); 52 | // Enable all safe optimizations 53 | CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options); 54 | } 55 | 56 | private void doCompile(SourceFile input) { 57 | Result result = compiler.compile(externs, input, options); 58 | Assume.assumeTrue(result.success); 59 | } 60 | 61 | public void testWithString(@From(AsciiStringGenerator.class) String code) { 62 | SourceFile input = SourceFile.fromCode("input", code); 63 | doCompile(input); 64 | } 65 | 66 | @DiffFuzz 67 | public String testWithGenerator(@From(JavaScriptCodeGenerator.class) String code) { 68 | testWithString(code); 69 | return compiler.toSource(); 70 | } 71 | 72 | @DiffFuzz(cmp = "noncompare") 73 | public String testWithGeneratorNoncompare(@From(JavaScriptCodeGenerator.class) String code) { 74 | testWithString(code); 75 | return compiler.toSource(); 76 | } 77 | 78 | @Fuzz(repro="${repro}") 79 | public void fuzzWithGenerator(@From(JavaScriptCodeGenerator.class) String code) { 80 | testWithString(code); 81 | compiler.toSource(); 82 | } 83 | 84 | @Comparison 85 | public static Boolean noncompare(String s1, String s2) { 86 | return true; 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/commons/PatriciaTrieTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.commons; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import edu.berkeley.cs.jqf.fuzz.JQF; 9 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 10 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 11 | import org.apache.commons.collections4.trie.PatriciaTrie; 12 | import org.junit.runner.RunWith; 13 | 14 | import static org.junit.Assert.assertTrue; 15 | import static org.junit.Assume.assumeTrue; 16 | 17 | @RunWith(JQF.class) 18 | public class PatriciaTrieTest { 19 | 20 | @DiffFuzz(cmp = "compare") 21 | public List> testPrefixMap(HashMap map, String prefix) { 22 | assumeTrue(prefix.length() > 0); 23 | PatriciaTrie trie = new PatriciaTrie(map); 24 | Map tmp = new HashMap<>(); 25 | tmp.put(prefix, 0); 26 | return Arrays.asList(trie.prefixMap(prefix), tmp); 27 | } 28 | 29 | @DiffFuzz(cmp = "noncompare") 30 | public List> otherPrefixMap(HashMap map, String prefix) { 31 | assumeTrue(prefix.length() > 0); 32 | // Create new trie with input `map` 33 | PatriciaTrie trie = new PatriciaTrie(map); 34 | // Get sub-map whose keys start with `prefix` 35 | Map prefixMap = trie.prefixMap(prefix); 36 | // Ensure that it contains all keys that start with `prefix` 37 | for (String key : map.keySet()) { 38 | if (key.startsWith(prefix)) { 39 | assertTrue(prefixMap.containsKey(key)); 40 | } 41 | } 42 | return null; 43 | } 44 | 45 | @Comparison 46 | public static Boolean noncompare(List l1, List l2) { 47 | return true; 48 | } 49 | 50 | @Comparison 51 | public static Boolean compare(List> l1, List> l2) { 52 | if(l1.get(1) != l2.get(1)) return false; 53 | for (String key : l1.get(0).keySet()) { 54 | if (key.startsWith((String) l1.get(1).keySet().toArray()[0])) { 55 | if(l1.get(0).containsKey(key) != l1.get(1).containsKey(key)) 56 | return false; 57 | } 58 | } 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/gson/JsonTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.gson; 2 | 3 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 4 | import edu.berkeley.cs.jqf.fuzz.JQF; 5 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 6 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 7 | 8 | import com.google.gson.Gson; 9 | import com.google.gson.GsonBuilder; 10 | import com.google.gson.JsonIOException; 11 | import com.google.gson.JsonSyntaxException; 12 | import com.pholser.junit.quickcheck.From; 13 | import edu.berkeley.cs.jqf.examples.common.AsciiStringGenerator; 14 | import org.junit.Assume; 15 | import org.junit.runner.RunWith; 16 | 17 | @RunWith(JQF.class) 18 | public class JsonTest { 19 | 20 | private GsonBuilder builder = new GsonBuilder(); 21 | private Gson gson = builder.setLenient().create(); 22 | 23 | @DiffFuzz 24 | public Object testJSONParser(@From(AsciiStringGenerator.class) String input) { 25 | Object out = null; 26 | try { 27 | out = gson.fromJson(input, Object.class); 28 | } catch (JsonSyntaxException e) { 29 | Assume.assumeNoException(e); 30 | } catch (JsonIOException e) { 31 | Assume.assumeNoException(e); 32 | } 33 | return out; 34 | } 35 | 36 | @Fuzz(repro="${repro}") 37 | public void fuzzJSONParser(@From(AsciiStringGenerator.class) String input) { 38 | Object out = null; 39 | try { 40 | out = gson.fromJson(input, Object.class); 41 | } catch (JsonSyntaxException e) { 42 | Assume.assumeNoException(e); 43 | } catch (JsonIOException e) { 44 | Assume.assumeNoException(e); 45 | } 46 | } 47 | 48 | @DiffFuzz(cmp = "noncompare") 49 | public Object testJSONParserNoncompare(@From(AsciiStringGenerator.class) String input) { 50 | Object out = null; 51 | try { 52 | out = gson.fromJson(input, Object.class); 53 | } catch (JsonSyntaxException e) { 54 | Assume.assumeNoException(e); 55 | } catch (JsonIOException e) { 56 | Assume.assumeNoException(e); 57 | } 58 | return out; 59 | } 60 | 61 | @Comparison 62 | public static Boolean noncompare(Object o1, Object o2) { 63 | return true; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/jackson/JsonTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.jackson; 2 | 3 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 4 | import edu.berkeley.cs.jqf.fuzz.JQF; 5 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 6 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 7 | 8 | import com.fasterxml.jackson.core.JsonProcessingException; 9 | import com.fasterxml.jackson.databind.ObjectMapper; 10 | import com.pholser.junit.quickcheck.From; 11 | import edu.berkeley.cs.jqf.examples.common.AsciiStringGenerator; 12 | 13 | import java.io.IOException; 14 | 15 | import org.junit.Assume; 16 | import org.junit.runner.RunWith; 17 | 18 | @RunWith(JQF.class) 19 | public class JsonTest { 20 | 21 | private ObjectMapper objectMapper = new ObjectMapper(); 22 | 23 | @DiffFuzz 24 | public Object testJsonReadValue(@From(AsciiStringGenerator.class) String input) { 25 | Object output = null; 26 | try { 27 | output = objectMapper.readValue(input, Object.class); 28 | } catch (JsonProcessingException e) { 29 | Assume.assumeNoException(e); 30 | } catch (IOException e) { 31 | Assume.assumeNoException(e); 32 | } 33 | return output; 34 | } 35 | 36 | @Fuzz(repro="${repro}") 37 | public void fuzzJsonReadValue(@From(AsciiStringGenerator.class) String input) { 38 | Object output = null; 39 | try { 40 | output = objectMapper.readValue(input, Object.class); 41 | } catch (JsonProcessingException e) { 42 | Assume.assumeNoException(e); 43 | } catch (IOException e) { 44 | Assume.assumeNoException(e); 45 | } 46 | } 47 | 48 | @DiffFuzz(cmp = "noncompare") 49 | public Object testJsonReadValueNoncompare(@From(AsciiStringGenerator.class) String input) { 50 | Object output = null; 51 | try { 52 | output = objectMapper.readValue(input, Object.class); 53 | } catch (JsonProcessingException e) { 54 | Assume.assumeNoException(e); 55 | } catch (IOException e) { 56 | Assume.assumeNoException(e); 57 | } 58 | return output; 59 | } 60 | 61 | @Comparison 62 | public static Boolean noncompare(Object o1, Object o2) { 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/sort/DiffTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import com.pholser.junit.quickcheck.generator.InRange; 4 | import com.pholser.junit.quickcheck.generator.Size; 5 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 6 | import edu.berkeley.cs.jqf.fuzz.JQF; 7 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 8 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 9 | import org.junit.runner.RunWith; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static cmu.pasta.mu2.examples.sort.SortTest.testSort; 16 | 17 | @RunWith(JQF.class) 18 | public class DiffTest { 19 | protected static final int MAX_SIZE = 160; 20 | protected static final int MIN_ELEMENT = 0; 21 | protected static final int MAX_ELEMENT = 10; 22 | 23 | @DiffFuzz(cmp = "compare") 24 | public List testBubbleSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 25 | List toReturn = new BubbleSort().sort(input); 26 | return toReturn; 27 | } 28 | 29 | @Fuzz 30 | public void fuzzBubbleSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 31 | new BubbleSort().sort(input); 32 | } 33 | 34 | @Fuzz 35 | public void fuzzBubbleSortWithOracle(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 36 | testSort(new BubbleSort(), input); 37 | } 38 | 39 | 40 | @DiffFuzz(cmp = "noncompare") 41 | public List testBubbleSortNonCompare(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 42 | List toReturn = new BubbleSort().sort(input); 43 | return toReturn; 44 | } 45 | 46 | @DiffFuzz(cmp = "compare") 47 | public List testTimSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 48 | List toReturn = new TimSort().sort(input); 49 | return toReturn; 50 | } 51 | 52 | @DiffFuzz(cmp = "noncompare") 53 | public List testTimSortNonCompare(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 54 | List toReturn = new TimSort().sort(input); 55 | return toReturn; 56 | } 57 | 58 | @Fuzz 59 | public void fuzzTimSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 60 | new TimSort().sort(input); 61 | } 62 | 63 | @Fuzz 64 | public void fuzzTimSortWithOracle(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 65 | testSort(new TimSort(), input); 66 | } 67 | 68 | @Comparison 69 | public static Boolean compare(List l1, List l2) { 70 | if(l1 == null || l2 == null) return false; 71 | if(l1.size() != l2.size()) return false; 72 | for(int c = 0; c < l1.size(); c++) { 73 | if(!l1.equals(l2)) return false; 74 | } 75 | return true; 76 | } 77 | 78 | @Comparison 79 | public static Boolean noncompare(List l1, List l2) { 80 | return true; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/sort/SortTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import com.pholser.junit.quickcheck.generator.InRange; 4 | import com.pholser.junit.quickcheck.generator.Size; 5 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 6 | import edu.berkeley.cs.jqf.fuzz.JQF; 7 | import org.junit.runner.RunWith; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | import static org.hamcrest.Matchers.lessThanOrEqualTo; 13 | import static org.junit.Assert.*; 14 | 15 | @RunWith(JQF.class) 16 | public class SortTest { 17 | 18 | protected static final int MAX_SIZE = 160; 19 | protected static final int MIN_ELEMENT = 0; 20 | protected static final int MAX_ELEMENT = 10; 21 | 22 | @Fuzz 23 | public void testBubbleSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 24 | testSort(new BubbleSort(), input); 25 | } 26 | 27 | @Fuzz 28 | public void fuzzBubbleSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 29 | List l1 = new BubbleSort().sort(input); 30 | input.sort(Integer::compareTo); 31 | assertEquals(l1, input); 32 | //this can kill 18 where testBubbleSort kills 24 - why? 33 | } 34 | 35 | @Fuzz 36 | public void testCocktailShakerSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 37 | testSort(new CocktailShakerSort(), input); 38 | } 39 | 40 | @Fuzz 41 | public void testCombSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 42 | testSort(new CombSort(), input); 43 | } 44 | 45 | @Fuzz 46 | public void testCycleSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 47 | testSort(new CycleSort(), input); 48 | } 49 | 50 | @Fuzz 51 | public void testGnomeSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 52 | testSort(new GnomeSort(), input); 53 | } 54 | 55 | @Fuzz 56 | public void testHeapSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 57 | testSort(new HeapSort(), input); 58 | } 59 | 60 | @Fuzz 61 | public void testInsertionSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 62 | testSort(new InsertionSort(), input); 63 | } 64 | 65 | @Fuzz 66 | public void testMergeSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 67 | testSort(new MergeSort(), input); 68 | } 69 | 70 | @Fuzz 71 | public void testPancakeSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 72 | testSort(new PancakeSort(), input); 73 | } 74 | 75 | @Fuzz 76 | public void testQuickSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 77 | testSort(new QuickSort(), input); 78 | } 79 | 80 | @Fuzz 81 | public void testSelectionSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 82 | testSort(new SelectionSort(), input); 83 | } 84 | 85 | @Fuzz 86 | public void testShellSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 87 | testSort(new ShellSort(), input); 88 | } 89 | 90 | @Fuzz 91 | public void testTimSort(@Size(max=MAX_SIZE) List<@InRange(minInt=MIN_ELEMENT, maxInt=MAX_ELEMENT) Integer> input) { 92 | testSort(new TimSort(), input); 93 | } 94 | 95 | public static > void testSort(SortAlgorithm algorithm, List input) { 96 | List output = algorithm.sort(input); 97 | int n = input.size(); 98 | // Check length 99 | assertEquals("Length should match", 100 | n, output.size()); 101 | // Check integrity 102 | for(T x : input) { 103 | assertTrue("Output should contain same elements as input", 104 | output.contains(x)); 105 | } 106 | // Check sortedness 107 | for (int i = 0; i < n-1; i++) { 108 | assertThat(output.get(i), lessThanOrEqualTo(output.get(i+1))); 109 | } 110 | } 111 | 112 | public static > void testSort(SortAlgorithm algorithm, T... input) { 113 | testSort(algorithm, Arrays.asList(input)); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/sort/TimSortTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.sort; 2 | 3 | import com.pholser.junit.quickcheck.generator.InRange; 4 | import com.pholser.junit.quickcheck.generator.Size; 5 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 6 | import edu.berkeley.cs.jqf.fuzz.JQF; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import java.util.List; 11 | 12 | @RunWith(JQF.class) 13 | public class TimSortTest { 14 | 15 | @Fuzz 16 | public void fuzzTimSort(@Size(max=SortTest.MAX_SIZE) List input) { 17 | SortTest.testSort(new TimSort(), input); 18 | } 19 | 20 | @Test 21 | public void testTimSort() { 22 | TimSort sort = new TimSort(); 23 | SortTest.testSort(sort, 4, 8, 15, 16, 23, 42); 24 | SortTest.testSort(sort, 4, 8, 15, 16, 23, 42, 108); 25 | SortTest.testSort(sort, 48, 15, 162, 342); 26 | SortTest.testSort(sort, 481, 5, 16, 2, 34, 2); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/src/test/java/cmu/pasta/mu2/examples/tomcat/ApacheTomcatTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2.examples.tomcat; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.InputStream; 5 | 6 | import com.pholser.junit.quickcheck.From; 7 | import edu.berkeley.cs.jqf.examples.xml.XMLDocumentUtils; 8 | import edu.berkeley.cs.jqf.examples.xml.XmlDocumentGenerator; 9 | import edu.berkeley.cs.jqf.examples.common.Dictionary; 10 | import org.apache.tomcat.util.descriptor.web.WebXml; 11 | import org.apache.tomcat.util.descriptor.web.WebXmlParser; 12 | 13 | import org.junit.Assume; 14 | import org.junit.runner.RunWith; 15 | import org.w3c.dom.Document; 16 | import org.xml.sax.InputSource; 17 | 18 | import edu.berkeley.cs.jqf.fuzz.Fuzz; 19 | import edu.berkeley.cs.jqf.fuzz.JQF; 20 | import edu.berkeley.cs.jqf.fuzz.difffuzz.Comparison; 21 | import edu.berkeley.cs.jqf.fuzz.difffuzz.DiffFuzz; 22 | 23 | @RunWith(JQF.class) 24 | public class ApacheTomcatTest { 25 | 26 | public String testWithInputStream(InputStream in) { 27 | InputSource inputSource = new InputSource(in); 28 | WebXml webXml = new WebXml(); 29 | WebXmlParser parser = new WebXmlParser(false, false, true); 30 | boolean success = parser.parseWebXml(inputSource, webXml, false); 31 | Assume.assumeTrue(success); 32 | return webXml.toXml(); 33 | } 34 | 35 | @Fuzz(repro="${repro}") 36 | public void fuzzWithGenerator(@From(XmlDocumentGenerator.class) @Dictionary("dictionaries/tomcat-webxml.dict") Document dom) { 37 | testWithInputStream(XMLDocumentUtils.documentToInputStream(dom)); 38 | } 39 | 40 | @DiffFuzz 41 | public String testWithGenerator(@From(XmlDocumentGenerator.class) @Dictionary("dictionaries/tomcat-webxml.dict") Document dom) { 42 | return testWithInputStream(XMLDocumentUtils.documentToInputStream(dom)); 43 | } 44 | 45 | @Fuzz 46 | public void debugWithGenerator(@From(XmlDocumentGenerator.class) @Dictionary("dictionaries/tomcat-webxml.dict") Document dom) { 47 | System.out.println(XMLDocumentUtils.documentToString(dom)); 48 | testWithGenerator(dom); 49 | } 50 | 51 | @Fuzz 52 | public void testWithString(String input){ 53 | testWithInputStream(new ByteArrayInputStream(input.getBytes())); 54 | } 55 | 56 | @DiffFuzz(cmp = "noncompare") 57 | public String testWithGeneratorNoncompare(@From(XmlDocumentGenerator.class) @Dictionary("dictionaries/tomcat-webxml.dict") Document dom) { 58 | return testWithInputStream(XMLDocumentUtils.documentToInputStream(dom)); 59 | } 60 | 61 | @Comparison 62 | public static Boolean noncompare(String s1, String s2) { 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/ant-project-afl.dict: -------------------------------------------------------------------------------- 1 | token="basedir" 2 | token="default" 3 | token="depends" 4 | token="description" 5 | token="file:" 6 | token="id" 7 | token="if" 8 | token="name" 9 | token="name attribute must not be empty" 10 | token="parsing buildfile" 11 | token="project" 12 | token="resolving systemId:" 13 | token="target" 14 | token="target element appears without a name attribute" 15 | token="unless" 16 | token="ant" 17 | token="antcall" 18 | token="antstructure" 19 | token="antversion" 20 | token="apply" 21 | token="attributenamespacedef" 22 | token="augment" 23 | token="available" 24 | token="basename" 25 | token="bindtargets" 26 | token="buildnumber" 27 | token="bunzip2" 28 | token="bzip2" 29 | token="checksum" 30 | token="chmod" 31 | token="classloader" 32 | token="commandlauncher" 33 | token="componentdef" 34 | token="concat" 35 | token="condition" 36 | token="copy" 37 | token="cvs" 38 | token="cvschangelog" 39 | token="cvspass" 40 | token="cvstagdiff" 41 | token="cvsversion" 42 | token="defaultexcludes" 43 | token="delete" 44 | token="dependset" 45 | token="diagnostics" 46 | token="dirname" 47 | token="ear" 48 | token="echo" 49 | token="echoproperties" 50 | token="echoxml" 51 | token="exec" 52 | token="fail" 53 | token="filter" 54 | token="fixcrlf" 55 | token="genkey" 56 | token="get" 57 | token="gunzip" 58 | token="gzip" 59 | token="hostinfo" 60 | token="import" 61 | token="include" 62 | token="input" 63 | token="jar" 64 | token="java" 65 | token="javac" 66 | token="javadoc" 67 | token="length" 68 | token="loadfile" 69 | token="loadproperties" 70 | token="loadresource" 71 | token="local" 72 | token="macrodef" 73 | token="mail" 74 | token="makeurl" 75 | token="manifest" 76 | token="manifestclasspath" 77 | token="mkdir" 78 | token="move" 79 | token="nice" 80 | token="parallel" 81 | token="patch" 82 | token="pathconvert" 83 | token="presetdef" 84 | token="projecthelper" 85 | token="property" 86 | token="propertyhelper" 87 | token="record" 88 | token="replace" 89 | token="resourcecount" 90 | token="retry" 91 | token="rmic" 92 | token="setpermissions" 93 | token="sequential" 94 | token="signjar" 95 | token="sleep" 96 | token="sql" 97 | token="subant" 98 | token="sync" 99 | token="tar" 100 | token="taskdef" 101 | token="tempfile" 102 | token="touch" 103 | token="tstamp" 104 | token="truncate" 105 | token="typedef" 106 | token="unjar" 107 | token="untar" 108 | token="unwar" 109 | token="unxz" 110 | token="unzip" 111 | token="uptodate" 112 | token="waitfor" 113 | token="war" 114 | token="whichresource" 115 | token="xmlproperty" 116 | token="xslt" 117 | token="xz" 118 | token="zip" 119 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/ant-project.dict: -------------------------------------------------------------------------------- 1 | basedir 2 | default 3 | depends 4 | description 5 | file 6 | id 7 | if 8 | name 9 | parsing buildfile 10 | project 11 | resolving systemId 12 | target 13 | unless 14 | ant 15 | antcall 16 | antstructure 17 | antversion 18 | apply 19 | attributenamespacedef 20 | augment 21 | available 22 | basename 23 | bindtargets 24 | buildnumber 25 | bunzip2 26 | bzip2 27 | checksum 28 | chmod 29 | classloader 30 | commandlauncher 31 | componentdef 32 | concat 33 | condition 34 | copy 35 | cvs 36 | cvschangelog 37 | cvspass 38 | cvstagdiff 39 | cvsversion 40 | defaultexcludes 41 | delete 42 | dependset 43 | diagnostics 44 | dirname 45 | ear 46 | echo 47 | echoproperties 48 | echoxml 49 | exec 50 | fail 51 | filter 52 | fixcrlf 53 | 54 | genkey 55 | get 56 | gunzip 57 | gzip 58 | hostinfo 59 | import 60 | include 61 | input 62 | jar 63 | java 64 | javac 65 | javadoc 66 | length 67 | loadfile 68 | loadproperties 69 | loadresource 70 | local 71 | macrodef 72 | mail 73 | makeurl 74 | manifest 75 | manifestclasspath 76 | mkdir 77 | move 78 | nice 79 | parallel 80 | patch 81 | pathconvert 82 | presetdef 83 | projecthelper 84 | property 85 | propertyhelper 86 | record 87 | replace 88 | resourcecount 89 | retry 90 | rmic 91 | setpermissions 92 | sequential 93 | signjar 94 | sleep 95 | sql 96 | subant 97 | sync 98 | tar 99 | taskdef 100 | tempfile 101 | touch 102 | tstamp 103 | truncate 104 | typedef 105 | unjar 106 | untar 107 | unwar 108 | unxz 109 | unzip 110 | uptodate 111 | waitfor 112 | war 113 | whichresource 114 | xmlproperty 115 | xslt 116 | xz 117 | zip 118 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/fen.dict: -------------------------------------------------------------------------------- 1 | token="KQkq" 2 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/javaclass.dict: -------------------------------------------------------------------------------- 1 | header="\xca\xfe\xba\xbe" 2 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/javascript.dict: -------------------------------------------------------------------------------- 1 | token="^!" 2 | token="!=" 3 | token="!==" 4 | token="%" 5 | token="%=" 6 | token="&" 7 | token="&&" 8 | token="&=" 9 | token="(" 10 | token=")" 11 | token="*" 12 | token="*=" 13 | token="+" 14 | token="++" 15 | token="+=" 16 | token="," 17 | token="-" 18 | token="--" 19 | token="-=" 20 | token="." 21 | token="/" 22 | token="/=" 23 | token=":" 24 | token=";" 25 | token="<" 26 | token="<<" 27 | token="<<=" 28 | token="<=" 29 | token="=" 30 | token="==" 31 | token="===" 32 | token="=>" 33 | token=">" 34 | token=">=" 35 | token=">>" 36 | token=">>=" 37 | token=">>>" 38 | token=">>>=" 39 | token="?" 40 | token="[" 41 | token="]" 42 | token="^" 43 | token="^=" 44 | token="{" 45 | token="|" 46 | token="|=" 47 | token="||" 48 | token="}" 49 | token="~" 50 | token="break" 51 | token="case" 52 | token="catch" 53 | token="class" 54 | token="const" 55 | token="continue" 56 | token="debugger" 57 | token="default" 58 | token="delete" 59 | token="do" 60 | token="else" 61 | token="enum" 62 | token="export" 63 | token="extends" 64 | token="false" 65 | token="finally" 66 | token="for" 67 | token="function" 68 | token="if" 69 | token="implements" 70 | token="import" 71 | token="in" 72 | token="instanceof" 73 | token="interface" 74 | token="let" 75 | token="new" 76 | token="null" 77 | token="package" 78 | token="private" 79 | token="protected" 80 | token="public" 81 | token="return" 82 | token="static" 83 | token="super" 84 | token="switch" 85 | token="this" 86 | token="throw" 87 | token="true" 88 | token="try" 89 | token="typeof" 90 | token="var" 91 | token="void" 92 | token="while" 93 | token="with" 94 | token="yield" 95 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/maven-model-afl.dict: -------------------------------------------------------------------------------- 1 | token="activation" 2 | token="activeByDefault" 3 | token="address" 4 | token="arch" 5 | token="archive" 6 | token="artifactId" 7 | token="build" 8 | token="checksumPolicy" 9 | token="ciManagement" 10 | token="classifier" 11 | token="comments" 12 | token="configuration" 13 | token="connection" 14 | token="contributor" 15 | token="contributors" 16 | token="defaultGoal" 17 | token="dependencies" 18 | token="dependency" 19 | token="dependencyManagement" 20 | token="description" 21 | token="developer" 22 | token="developerConnection" 23 | token="developers" 24 | token="directory" 25 | token="distribution" 26 | token="distributionManagement" 27 | token="downloadUrl" 28 | token="email" 29 | token="enabled" 30 | token="exclude" 31 | token="excludeDefaults" 32 | token="excludes" 33 | token="exclusion" 34 | token="exclusions" 35 | token="execution" 36 | token="executions" 37 | token="exists" 38 | token="expected START_TAG or END_TAG not" 39 | token="extension" 40 | token="extensions" 41 | token="false" 42 | token="family" 43 | token="file" 44 | token="filter" 45 | token="filtering" 46 | token="filters" 47 | token="finalName" 48 | token="goal" 49 | token="goals" 50 | token="groupId" 51 | token="id" 52 | token="inceptionYear" 53 | token="include" 54 | token="includes" 55 | token="inherited" 56 | token="issueManagement" 57 | token="jdk" 58 | token="layout" 59 | token="license" 60 | token="licenses" 61 | token="long" 62 | token="mailingList" 63 | token="mailingLists" 64 | token="maven" 65 | token="message" 66 | token="missing" 67 | token="modelVersion" 68 | token="module" 69 | token="modules" 70 | token="name" 71 | token="notifier" 72 | token="notifiers" 73 | token="optional" 74 | token="organisation" 75 | token="organisationUrl" 76 | token="organization" 77 | token="organizationUrl" 78 | token="os" 79 | token="otherArchive" 80 | token="otherArchives" 81 | token="outputDirectory" 82 | token="packaging" 83 | token="parent" 84 | token="phase" 85 | token="plugin" 86 | token="pluginManagement" 87 | token="pluginRepositories" 88 | token="pluginRepository" 89 | token="plugins" 90 | token="post" 91 | token="prerequisites" 92 | token="profile" 93 | token="profiles" 94 | token="project" 95 | token="properties" 96 | token="property" 97 | token="relativePath" 98 | token="releases" 99 | token="relocation" 100 | token="report" 101 | token="reportSet" 102 | token="reportSets" 103 | token="reporting" 104 | token="reports" 105 | token="repositories" 106 | token="repository" 107 | token="resource" 108 | token="resources" 109 | token="role" 110 | token="roles" 111 | token="scm" 112 | token="scope" 113 | token="scriptSourceDirectory" 114 | token="sendOnError" 115 | token="sendOnFailure" 116 | token="sendOnSuccess" 117 | token="sendOnWarning" 118 | token="site" 119 | token="snapshotRepository" 120 | token="snapshots" 121 | token="sourceDirectory" 122 | token="status" 123 | token="subscribe" 124 | token="system" 125 | token="systemPath" 126 | token="tag" 127 | token="targetPath" 128 | token="testOutputDirectory" 129 | token="testResource" 130 | token="testResources" 131 | token="testSourceDirectory" 132 | token="timezone" 133 | token="true" 134 | token="type" 135 | token="uniqueVersion" 136 | token="unsubscribe" 137 | token="updatePolicy" 138 | token="url" 139 | token="value" 140 | token="version" 141 | token="xmlns" 142 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/maven-model.dict: -------------------------------------------------------------------------------- 1 | activation 2 | activeByDefault 3 | address 4 | arch 5 | archive 6 | artifactId 7 | build 8 | checksumPolicy 9 | ciManagement 10 | classifier 11 | comments 12 | configuration 13 | connection 14 | contributor 15 | contributors 16 | defaultGoal 17 | dependencies 18 | dependency 19 | dependencyManagement 20 | description 21 | developer 22 | developerConnection 23 | developers 24 | directory 25 | distribution 26 | distributionManagement 27 | downloadUrl 28 | email 29 | enabled 30 | exclude 31 | excludeDefaults 32 | excludes 33 | exclusion 34 | exclusions 35 | execution 36 | executions 37 | exists 38 | expected START_TAG or END_TAG not 39 | extension 40 | extensions 41 | false 42 | family 43 | file 44 | filter 45 | filtering 46 | filters 47 | finalName 48 | goal 49 | goals 50 | groupId 51 | id 52 | inceptionYear 53 | include 54 | includes 55 | inherited 56 | issueManagement 57 | jdk 58 | layout 59 | license 60 | licenses 61 | long 62 | mailingList 63 | mailingLists 64 | maven 65 | message 66 | missing 67 | modelVersion 68 | module 69 | modules 70 | name 71 | notifier 72 | notifiers 73 | optional 74 | organisation 75 | organisationUrl 76 | organization 77 | organizationUrl 78 | os 79 | otherArchive 80 | otherArchives 81 | outputDirectory 82 | packaging 83 | parent 84 | phase 85 | plugin 86 | pluginManagement 87 | pluginRepositories 88 | pluginRepository 89 | plugins 90 | post 91 | prerequisites 92 | profile 93 | profiles 94 | project 95 | properties 96 | property 97 | relativePath 98 | releases 99 | relocation 100 | report 101 | reportSet 102 | reportSets 103 | reporting 104 | reports 105 | repositories 106 | repository 107 | resource 108 | resources 109 | role 110 | roles 111 | scm 112 | scope 113 | scriptSourceDirectory 114 | sendOnError 115 | sendOnFailure 116 | sendOnSuccess 117 | sendOnWarning 118 | site 119 | snapshotRepository 120 | snapshots 121 | sourceDirectory 122 | status 123 | subscribe 124 | system 125 | systemPath 126 | tag 127 | targetPath 128 | testOutputDirectory 129 | testResource 130 | testResources 131 | testSourceDirectory 132 | timezone 133 | true 134 | type 135 | uniqueVersion 136 | unsubscribe 137 | updatePolicy 138 | url 139 | value 140 | version 141 | xmlns 142 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/tomcat-webxml-afl.dict: -------------------------------------------------------------------------------- 1 | token="absolute-ordering" 2 | token="addAbsoluteOrdering" 3 | token="addAbsoluteOrderingOthers" 4 | token="addAfterOrdering" 5 | token="addAfterOrderingOthers" 6 | token="addAuthRole" 7 | token="addBeforeOrdering" 8 | token="addBeforeOrderingOthers" 9 | token="addCollection" 10 | token="addContextParam" 11 | token="addEjbLocalRef" 12 | token="addEjbRef" 13 | token="addEnvEntry" 14 | token="addErrorPage" 15 | token="addFilter" 16 | token="addFilterMapping" 17 | token="addHandler" 18 | token="addIncludeCoda" 19 | token="addIncludePrelude" 20 | token="addInitParameter" 21 | token="addInjectionTarget" 22 | token="addJspPropertyGroup" 23 | token="addListener" 24 | token="addLocaleEncodingMapping" 25 | token="addMessageDestination" 26 | token="addMessageDestinationRef" 27 | token="addMethod" 28 | token="addMimeMapping" 29 | token="addOmittedMethod" 30 | token="addPattern" 31 | token="addPortName" 32 | token="addPortcomponent" 33 | token="addPostConstructMethods" 34 | token="addPreDestroyMethods" 35 | token="addResourceEnvRef" 36 | token="addResourceRef" 37 | token="addSecurityConstraint" 38 | token="addSecurityRole" 39 | token="addSecurityRoleRef" 40 | token="addServiceRef" 41 | token="addServlet" 42 | token="addServletMapping" 43 | token="addServletName" 44 | token="addSessionTrackingMode" 45 | token="addSoapRole" 46 | token="addTaglib" 47 | token="addURLPattern" 48 | token="addUrlPattern" 49 | token="addWelcomeFile" 50 | token="after" 51 | token="async-supported" 52 | token="auth-constraint" 53 | token="auth-method" 54 | token="before" 55 | token="buffer" 56 | token="comment" 57 | token="context-param" 58 | token="cookie-config" 59 | token="default-content-type" 60 | token="deferred-syntax-allowed-as-literal" 61 | token="deny-uncovered-http-methods" 62 | token="description" 63 | token="dispatcher" 64 | token="display-name" 65 | token="distributable" 66 | token="domain" 67 | token="ejb-link" 68 | token="ejb-local-ref" 69 | token="ejb-ref" 70 | token="ejb-ref-name" 71 | token="ejb-ref-type" 72 | token="el-ignored" 73 | token="enabled" 74 | token="encoding" 75 | token="env-entry" 76 | token="env-entry-name" 77 | token="env-entry-type" 78 | token="env-entry-value" 79 | token="error-code" 80 | token="error-on-undeclared-namespace" 81 | token="error-page" 82 | token="exception-type" 83 | token="extension" 84 | token="file-size-threshold" 85 | token="filter" 86 | token="filter-class" 87 | token="filter-mapping" 88 | token="filter-name" 89 | token="form-error-page" 90 | token="form-login-config" 91 | token="form-login-page" 92 | token="handler" 93 | token="handler-class" 94 | token="handler-name" 95 | token="home" 96 | token="http-method" 97 | token="http-method-omission" 98 | token="http-only" 99 | token="icon" 100 | token="include-coda" 101 | token="include-prelude" 102 | token="init-param" 103 | token="injection-target" 104 | token="injection-target-class" 105 | token="injection-target-name" 106 | token="is-xml" 107 | token="jaxrpc-mapping-file" 108 | token="jsp-config" 109 | token="jsp-file" 110 | token="jsp-property-group" 111 | token="large-icon" 112 | token="lifecycle-callback-class" 113 | token="lifecycle-callback-method" 114 | token="listener" 115 | token="listener-class" 116 | token="load-on-startup" 117 | token="local" 118 | token="local-home" 119 | token="locale" 120 | token="locale-encoding-mapping" 121 | token="locale-encoding-mapping-list" 122 | token="location" 123 | token="login-config" 124 | token="mapped-name" 125 | token="max-age" 126 | token="max-file-size" 127 | token="max-request-size" 128 | token="message-destination" 129 | token="message-destination-link" 130 | token="message-destination-name" 131 | token="message-destination-ref" 132 | token="message-destination-ref-name" 133 | token="message-destination-type" 134 | token="message-destination-usage" 135 | token="mime-mapping" 136 | token="mime-type" 137 | token="multipart-config" 138 | token="name" 139 | token="ordering" 140 | token="org.apache.tomcat.util.descriptor.web.ContextEjb" 141 | token="org.apache.tomcat.util.descriptor.web.ContextEnvironment" 142 | token="org.apache.tomcat.util.descriptor.web.ContextHandler" 143 | token="org.apache.tomcat.util.descriptor.web.ContextLocalEjb" 144 | token="org.apache.tomcat.util.descriptor.web.ContextResource" 145 | token="org.apache.tomcat.util.descriptor.web.ContextResourceEnvRef" 146 | token="org.apache.tomcat.util.descriptor.web.ContextService" 147 | token="org.apache.tomcat.util.descriptor.web.ErrorPage" 148 | token="org.apache.tomcat.util.descriptor.web.FilterDef" 149 | token="org.apache.tomcat.util.descriptor.web.FilterMap" 150 | token="org.apache.tomcat.util.descriptor.web.JspPropertyGroup" 151 | token="org.apache.tomcat.util.descriptor.web.LoginConfig" 152 | token="org.apache.tomcat.util.descriptor.web.MessageDestination" 153 | token="org.apache.tomcat.util.descriptor.web.MessageDestinationRef" 154 | token="org.apache.tomcat.util.descriptor.web.MultipartDef" 155 | token="org.apache.tomcat.util.descriptor.web.SecurityCollection" 156 | token="org.apache.tomcat.util.descriptor.web.SecurityConstraint" 157 | token="org.apache.tomcat.util.descriptor.web.SecurityRoleRef" 158 | token="org.apache.tomcat.util.descriptor.web.ServletDef" 159 | token="org.apache.tomcat.util.descriptor.web.SessionConfig" 160 | token="others" 161 | token="page-encoding" 162 | token="param-name" 163 | token="param-value" 164 | token="path" 165 | token="port-component-link" 166 | token="port-component-ref" 167 | token="port-name" 168 | token="post-construct" 169 | token="pre-destroy" 170 | token="realm-name" 171 | token="remote" 172 | token="request-character-encoding" 173 | token="res-auth" 174 | token="res-ref-name" 175 | token="res-sharing-scope" 176 | token="res-type" 177 | token="resource-env-ref" 178 | token="resource-env-ref-name" 179 | token="resource-env-ref-type" 180 | token="resource-ref" 181 | token="response-character-encoding" 182 | token="role-link" 183 | token="role-name" 184 | token="run-as" 185 | token="scripting-invalid" 186 | token="secure" 187 | token="security-constraint" 188 | token="security-role" 189 | token="security-role-ref" 190 | token="service-endpoint-interface" 191 | token="service-interface" 192 | token="service-qname" 193 | token="service-ref" 194 | token="service-ref-name" 195 | token="service-ref-type" 196 | token="servlet" 197 | token="servlet-class" 198 | token="servlet-mapping" 199 | token="servlet-name" 200 | token="session-config" 201 | token="session-timeout" 202 | token="setAsyncSupported" 203 | token="setAuth" 204 | token="setAuthMethod" 205 | token="setBuffer" 206 | token="setCookieComment" 207 | token="setCookieDomain" 208 | token="setCookieHttpOnly" 209 | token="setCookieMaxAge" 210 | token="setCookieName" 211 | token="setCookiePath" 212 | token="setCookieSecure" 213 | token="setDefaultContentType" 214 | token="setDeferredSyntax" 215 | token="setDescription" 216 | token="setDispatcher" 217 | token="setDisplayName" 218 | token="setDisplayname" 219 | token="setElIgnored" 220 | token="setEnabled" 221 | token="setErrorCode" 222 | token="setErrorOnUndeclaredNamespace" 223 | token="setErrorPage" 224 | token="setExceptionType" 225 | token="setFileSizeThreshold" 226 | token="setFilterClass" 227 | token="setFilterName" 228 | token="setHandlerclass" 229 | token="setHome" 230 | token="setInterface" 231 | token="setIsXml" 232 | token="setJaxrpcmappingfile" 233 | token="setJspFile" 234 | token="setLargeIcon" 235 | token="setLink" 236 | token="setLoadOnStartup" 237 | token="setLocal" 238 | token="setLocation" 239 | token="setLoginConfig" 240 | token="setLoginPage" 241 | token="setMaxFileSize" 242 | token="setMaxRequestSize" 243 | token="setMultipartDef" 244 | token="setName" 245 | token="setPageEncoding" 246 | token="setProperty" 247 | token="setPublicId" 248 | token="setRealmName" 249 | token="setRemote" 250 | token="setRequestCharacterEncoding" 251 | token="setResponseCharacterEncoding" 252 | token="setRunAs" 253 | token="setScope" 254 | token="setScriptingInvalid" 255 | token="setServletClass" 256 | token="setServletName" 257 | token="setSessionConfig" 258 | token="setSessionTimeout" 259 | token="setSmallIcon" 260 | token="setTrimWhitespace" 261 | token="setType" 262 | token="setUsage" 263 | token="setUserConstraint" 264 | token="setValue" 265 | token="setWsdlfile" 266 | token="small-icon" 267 | token="soap-header" 268 | token="soap-role" 269 | token="taglib" 270 | token="taglib-location" 271 | token="taglib-uri" 272 | token="tracking-mode" 273 | token="transport-guarantee" 274 | token="trim-directive-whitespaces" 275 | token="url-pattern" 276 | token="user-data-constraint" 277 | token="web-app" 278 | token="web-fragment" 279 | token="web-resource-collection" 280 | token="web-resource-name" 281 | token="welcome-file" 282 | token="welcome-file-list" 283 | token="wsdl-file" 284 | -------------------------------------------------------------------------------- /examples/src/test/resources/dictionaries/tomcat-webxml.dict: -------------------------------------------------------------------------------- 1 | 2 | absolute-ordering 3 | addAbsoluteOrdering 4 | addAbsoluteOrderingOthers 5 | addAfterOrdering 6 | addAfterOrderingOthers 7 | addAuthRole 8 | addBeforeOrdering 9 | addBeforeOrderingOthers 10 | addCollection 11 | addContextParam 12 | addEjbLocalRef 13 | addEjbRef 14 | addEnvEntry 15 | addErrorPage 16 | addFilter 17 | addFilterMapping 18 | addHandler 19 | addIncludeCoda 20 | addIncludePrelude 21 | addInitParameter 22 | addInjectionTarget 23 | addJspPropertyGroup 24 | addListener 25 | addLocaleEncodingMapping 26 | addMessageDestination 27 | addMessageDestinationRef 28 | addMethod 29 | addMimeMapping 30 | addOmittedMethod 31 | addPattern 32 | addPortName 33 | addPortcomponent 34 | addPostConstructMethods 35 | addPreDestroyMethods 36 | addResourceEnvRef 37 | addResourceRef 38 | addSecurityConstraint 39 | addSecurityRole 40 | addSecurityRoleRef 41 | addServiceRef 42 | addServlet 43 | addServletMapping 44 | addServletName 45 | addSessionTrackingMode 46 | addSoapRole 47 | addTaglib 48 | addURLPattern 49 | addUrlPattern 50 | addWelcomeFile 51 | after 52 | async-supported 53 | auth-constraint 54 | auth-method 55 | before 56 | buffer 57 | comment 58 | context-param 59 | cookie-config 60 | default-content-type 61 | deferred-syntax-allowed-as-literal 62 | deny-uncovered-http-methods 63 | description 64 | dispatcher 65 | display-name 66 | distributable 67 | domain 68 | ejb-link 69 | ejb-local-ref 70 | ejb-ref 71 | ejb-ref-name 72 | ejb-ref-type 73 | el-ignored 74 | enabled 75 | encoding 76 | env-entry 77 | env-entry-name 78 | env-entry-type 79 | env-entry-value 80 | error-code 81 | error-on-undeclared-namespace 82 | error-page 83 | exception-type 84 | extension 85 | file-size-threshold 86 | filter 87 | filter-class 88 | filter-mapping 89 | filter-name 90 | form-error-page 91 | form-login-config 92 | form-login-page 93 | handler 94 | handler-class 95 | handler-name 96 | home 97 | http-method 98 | http-method-omission 99 | http-only 100 | icon 101 | include-coda 102 | include-prelude 103 | init-param 104 | injection-target 105 | injection-target-class 106 | injection-target-name 107 | is-xml 108 | jaxrpc-mapping-file 109 | jsp-config 110 | jsp-file 111 | jsp-property-group 112 | large-icon 113 | lifecycle-callback-class 114 | lifecycle-callback-method 115 | listener 116 | listener-class 117 | load-on-startup 118 | local 119 | local-home 120 | locale 121 | locale-encoding-mapping 122 | locale-encoding-mapping-list 123 | location 124 | login-config 125 | mapped-name 126 | max-age 127 | max-file-size 128 | max-request-size 129 | message-destination 130 | message-destination-link 131 | message-destination-name 132 | message-destination-ref 133 | message-destination-ref-name 134 | message-destination-type 135 | message-destination-usage 136 | mime-mapping 137 | mime-type 138 | multipart-config 139 | name 140 | ordering 141 | org.apache.tomcat.util.descriptor.web.ContextEjb 142 | org.apache.tomcat.util.descriptor.web.ContextEnvironment 143 | org.apache.tomcat.util.descriptor.web.ContextHandler 144 | org.apache.tomcat.util.descriptor.web.ContextLocalEjb 145 | org.apache.tomcat.util.descriptor.web.ContextResource 146 | org.apache.tomcat.util.descriptor.web.ContextResourceEnvRef 147 | org.apache.tomcat.util.descriptor.web.ContextService 148 | org.apache.tomcat.util.descriptor.web.ErrorPage 149 | org.apache.tomcat.util.descriptor.web.FilterDef 150 | org.apache.tomcat.util.descriptor.web.FilterMap 151 | org.apache.tomcat.util.descriptor.web.JspPropertyGroup 152 | org.apache.tomcat.util.descriptor.web.LoginConfig 153 | org.apache.tomcat.util.descriptor.web.MessageDestination 154 | org.apache.tomcat.util.descriptor.web.MessageDestinationRef 155 | org.apache.tomcat.util.descriptor.web.MultipartDef 156 | org.apache.tomcat.util.descriptor.web.SecurityCollection 157 | org.apache.tomcat.util.descriptor.web.SecurityConstraint 158 | org.apache.tomcat.util.descriptor.web.SecurityRoleRef 159 | org.apache.tomcat.util.descriptor.web.ServletDef 160 | org.apache.tomcat.util.descriptor.web.SessionConfig 161 | others 162 | page-encoding 163 | param-name 164 | param-value 165 | path 166 | port-component-link 167 | port-component-ref 168 | port-name 169 | post-construct 170 | pre-destroy 171 | realm-name 172 | remote 173 | request-character-encoding 174 | res-auth 175 | res-ref-name 176 | res-sharing-scope 177 | res-type 178 | resource-env-ref 179 | resource-env-ref-name 180 | resource-env-ref-type 181 | resource-ref 182 | response-character-encoding 183 | role-link 184 | role-name 185 | run-as 186 | scripting-invalid 187 | secure 188 | security-constraint 189 | security-role 190 | security-role-ref 191 | service-endpoint-interface 192 | service-interface 193 | service-qname 194 | service-ref 195 | service-ref-name 196 | service-ref-type 197 | servlet 198 | servlet-class 199 | servlet-mapping 200 | servlet-name 201 | session-config 202 | session-timeout 203 | setAsyncSupported 204 | setAuth 205 | setAuthMethod 206 | setBuffer 207 | setCookieComment 208 | setCookieDomain 209 | setCookieHttpOnly 210 | setCookieMaxAge 211 | setCookieName 212 | setCookiePath 213 | setCookieSecure 214 | setDefaultContentType 215 | setDeferredSyntax 216 | setDescription 217 | setDispatcher 218 | setDisplayName 219 | setDisplayname 220 | setElIgnored 221 | setEnabled 222 | setErrorCode 223 | setErrorOnUndeclaredNamespace 224 | setErrorPage 225 | setExceptionType 226 | setFileSizeThreshold 227 | setFilterClass 228 | setFilterName 229 | setHandlerclass 230 | setHome 231 | setInterface 232 | setIsXml 233 | setJaxrpcmappingfile 234 | setJspFile 235 | setLargeIcon 236 | setLink 237 | setLoadOnStartup 238 | setLocal 239 | setLocation 240 | setLoginConfig 241 | setLoginPage 242 | setMaxFileSize 243 | setMaxRequestSize 244 | setMultipartDef 245 | setName 246 | setPageEncoding 247 | setProperty 248 | setPublicId 249 | setRealmName 250 | setRemote 251 | setRequestCharacterEncoding 252 | setResponseCharacterEncoding 253 | setRunAs 254 | setScope 255 | setScriptingInvalid 256 | setServletClass 257 | setServletName 258 | setSessionConfig 259 | setSessionTimeout 260 | setSmallIcon 261 | setTrimWhitespace 262 | setType 263 | setUsage 264 | setUserConstraint 265 | setValue 266 | setWsdlfile 267 | small-icon 268 | soap-header 269 | soap-role 270 | taglib 271 | taglib-location 272 | taglib-uri 273 | tracking-mode 274 | transport-guarantee 275 | trim-directive-whitespaces 276 | url-pattern 277 | user-data-constraint 278 | web-app 279 | web-fragment 280 | web-resource-collection 281 | web-resource-name 282 | welcome-file 283 | welcome-file-list 284 | wsdl-file 285 | -------------------------------------------------------------------------------- /integration-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mu2 7 | cmu.pasta.mu2 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mu2-integration-tests 13 | 14 | 15 | 16 | cmu.pasta.mu2 17 | mu2-core 18 | 1.0-SNAPSHOT 19 | test 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-dependency-plugin 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-surefire-plugin 32 | 2.22.2 33 | 34 | 35 | org.jacoco 36 | jacoco-maven-plugin 37 | 0.8.6 38 | 39 | 40 | before-integration-test-execution 41 | pre-integration-test 42 | 43 | prepare-agent 44 | 45 | 46 | ${project.build.directory}/jacoco-output/jacoco-integration-tests.exec 47 | failsafe.jacoco.args 48 | 49 | 50 | 51 | after-integration-test-execution 52 | post-integration-test 53 | 54 | report 55 | 56 | 57 | ${project.build.directory}/jacoco-output/jacoco-integration-tests.exec 58 | ${project.reporting.outputDirectory}/jacoco-integration-test-coverage-report 59 | 60 | 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-failsafe-plugin 66 | 3.0.0-M5 67 | 68 | 69 | 70 | integration-test 71 | verify 72 | 73 | 74 | 75 | 76 | ${failsafe.jacoco.args} 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/cmu/pasta/mu2/AbstractMutationTest.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2; 2 | 3 | import cmu.pasta.mu2.instrument.OptLevel; 4 | import cmu.pasta.mu2.instrument.MutationClassLoaders; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | import org.junit.Before; 14 | 15 | /** 16 | * Abstract class containing common functionality for testing Mu2. This class provides methods 17 | * to set-up up the classpath for instrumentable classes before running tests and provides 18 | * utility methods to create mutation classloaders. 19 | */ 20 | public class AbstractMutationTest { 21 | 22 | /** Class path for target application classes. */ 23 | protected String[] instrumentablesClassPath; 24 | 25 | @Before 26 | public void initClassPath() throws IOException { 27 | // Walk dependency tree to get all instrumentable JARs, e.g. jqf-examples. 28 | // Anything that's in this directory should not actually be on 29 | // the test classpath, so it will have to be loaded with the loader defined below 30 | 31 | List instrumentableClassDirectories = new ArrayList(); 32 | instrumentableClassDirectories.add("../examples/target/classes/"); 33 | instrumentableClassDirectories.add("../examples/target/test-classes/"); 34 | this.instrumentablesClassPath = instrumentableClassDirectories.stream() 35 | .flatMap(dir -> { 36 | try { 37 | return Files.walk(Paths.get(dir)); 38 | } catch (IOException e) { 39 | throw new RuntimeException(e); 40 | } 41 | }) 42 | .map(Path::toString) 43 | .toArray(String[]::new); 44 | } 45 | 46 | /** 47 | * Creates mutation classloaders for this test. 48 | * 49 | * @param mutableClasses comma-separated include list for target app classes 50 | * @param opt the optimization level 51 | * @return the classloaders 52 | * @throws IOException if classpath is malformed 53 | */ 54 | protected MutationClassLoaders initClassLoaders(String mutableClasses, String targetClasses, OptLevel opt) 55 | throws IOException { 56 | return new MutationClassLoaders(instrumentablesClassPath, mutableClasses, targetClasses, opt); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/cmu/pasta/mu2/DiffMutationGuidanceIT.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2; 2 | 3 | import cmu.pasta.mu2.fuzz.MutationGuidance; 4 | import cmu.pasta.mu2.instrument.MutationClassLoaders; 5 | import cmu.pasta.mu2.instrument.OptLevel; 6 | import edu.berkeley.cs.jqf.fuzz.junit.GuidedFuzzing; 7 | import org.junit.After; 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.nio.file.Files; 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | import java.util.Random; 19 | 20 | public class DiffMutationGuidanceIT extends AbstractMutationTest { 21 | // Temp directory to store fuzz results 22 | protected static File resultsDir; 23 | 24 | @Before 25 | public void initTempDir() throws IOException { 26 | resultsDir = Files.createTempDirectory("fuzz-results").toFile(); 27 | } 28 | 29 | @After 30 | public void clearTempDir() { 31 | resultsDir.delete(); 32 | } 33 | 34 | private static class ProbedMutationGuidance extends MutationGuidance { 35 | List inputHashes = new ArrayList<>(); 36 | 37 | ProbedMutationGuidance(MutationClassLoaders mcls, long trials, Random rnd) throws IOException { 38 | super(null, mcls,null, trials, resultsDir, null, rnd); 39 | } 40 | 41 | @Override 42 | public void observeGeneratedArgs(Object[] args) { 43 | this.inputHashes.add(Arrays.hashCode(args)); 44 | } 45 | 46 | int hashInputHashes() { 47 | return inputHashes.hashCode(); 48 | } 49 | 50 | int corpusCount() { 51 | return savedInputs.size(); 52 | } 53 | 54 | int hashTotalCoverage() { 55 | return totalCoverage.hashCode(); 56 | } 57 | 58 | int hashValidCoverage() { 59 | return validCoverage.hashCode(); 60 | } 61 | } 62 | 63 | @Test 64 | public void compareBubbleSort() throws Exception { 65 | // Set up test params 66 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 67 | String testMethod = "testBubbleSort"; 68 | String targetInst = "cmu.pasta.mu2.examples.sort.BubbleSort"; 69 | long trials = 100; 70 | Random rnd = new Random(42); 71 | 72 | // Create guidance 73 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 74 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 75 | 76 | // Fuzz 77 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 78 | 79 | Assert.assertEquals(9, mu2.corpusCount()); 80 | } 81 | 82 | @Test 83 | public void noncompareBubbleSort() throws Exception { 84 | // Set up test params 85 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 86 | String testMethod = "testBubbleSortNonCompare"; 87 | String targetInst = "cmu.pasta.mu2.examples.sort.BubbleSort"; 88 | long trials = 100; 89 | Random rnd = new Random(42); 90 | 91 | // Create guidance 92 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 93 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 94 | 95 | // Fuzz 96 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 97 | 98 | Assert.assertEquals(8, mu2.corpusCount()); 99 | } 100 | 101 | @Test 102 | public void fuzzBubbleSort() throws Exception { 103 | // Set up test params 104 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 105 | String testMethod = "fuzzBubbleSort"; 106 | String targetInst = "cmu.pasta.mu2.examples.sort.BubbleSort"; 107 | long trials = 100; 108 | Random rnd = new Random(42); 109 | 110 | // Create guidance 111 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 112 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 113 | 114 | // Fuzz 115 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 116 | 117 | Assert.assertEquals(8, mu2.corpusCount()); 118 | } 119 | 120 | @Test 121 | public void fuzzBubbleSortWithOracle() throws Exception { 122 | // Set up test params 123 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 124 | String testMethod = "fuzzBubbleSortWithOracle"; 125 | String targetInst = "cmu.pasta.mu2.examples.sort.BubbleSort"; 126 | long trials = 100; 127 | Random rnd = new Random(42); 128 | 129 | // Create guidance 130 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 131 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 132 | 133 | // Fuzz 134 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 135 | 136 | Assert.assertEquals(8, mu2.corpusCount()); 137 | } 138 | 139 | @Test 140 | public void compareTimSort() throws Exception { 141 | // Set up test params 142 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 143 | String testMethod = "testTimSort"; 144 | String targetInst = "cmu.pasta.mu2.examples.sort.TimSort"; 145 | long trials = 100; 146 | Random rnd = new Random(42); 147 | 148 | // Create guidance 149 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 150 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 151 | 152 | // Fuzz 153 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 154 | 155 | Assert.assertEquals(36, mu2.corpusCount()); 156 | } 157 | 158 | @Test 159 | public void noncompareTimSort() throws Exception { 160 | // Set up test params 161 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 162 | String testMethod = "testTimSortNonCompare"; 163 | String targetInst = "cmu.pasta.mu2.examples.sort.TimSort"; 164 | long trials = 100; 165 | Random rnd = new Random(42); 166 | 167 | // Create guidance 168 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 169 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 170 | 171 | // Fuzz 172 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 173 | 174 | // With a dummy compare method, more inputs are saved since later candidates 175 | // kill mutants that would not survive from earlier inputs with the proper compare method. 176 | Assert.assertEquals(38, mu2.corpusCount()); 177 | } 178 | 179 | @Test 180 | public void fuzzTimSort() throws Exception { 181 | // Set up test params 182 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 183 | String testMethod = "fuzzTimSort"; 184 | String targetInst = "cmu.pasta.mu2.examples.sort.TimSort"; 185 | long trials = 100; 186 | Random rnd = new Random(42); 187 | 188 | // Create guidance 189 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 190 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 191 | 192 | // Fuzz 193 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 194 | 195 | // Since this fuzz driver has no return object, this should act the same as a nonCompare method. 196 | Assert.assertEquals(38, mu2.corpusCount()); 197 | } 198 | 199 | @Test 200 | public void fuzzTimSortWithOracle() throws Exception { 201 | // Set up test params 202 | String testClassName = "cmu.pasta.mu2.examples.sort.DiffTest"; 203 | String testMethod = "fuzzTimSortWithOracle"; 204 | String targetInst = "cmu.pasta.mu2.examples.sort.TimSort"; 205 | long trials = 100; 206 | Random rnd = new Random(42); 207 | 208 | // Create guidance 209 | MutationClassLoaders mcls = initClassLoaders(targetInst, "cmu.pasta.mu2.examples.sort", OptLevel.NONE); 210 | ProbedMutationGuidance mu2 = new ProbedMutationGuidance(mcls, trials, rnd); 211 | 212 | // Fuzz 213 | GuidedFuzzing.run(testClassName, testMethod, mcls.getCartographyClassLoader(), mu2, null); 214 | 215 | Assert.assertEquals(36, mu2.corpusCount()); 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/cmu/pasta/mu2/MutationTestingIT.java: -------------------------------------------------------------------------------- 1 | package cmu.pasta.mu2; 2 | 3 | import cmu.pasta.mu2.instrument.MutationInstance; 4 | import cmu.pasta.mu2.instrument.OptLevel; 5 | import cmu.pasta.mu2.instrument.MutationSnoop; 6 | import cmu.pasta.mu2.instrument.MutationClassLoaders; 7 | 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Set; 12 | import java.util.function.BiConsumer; 13 | 14 | import org.junit.Assert; 15 | import org.junit.Test; 16 | import org.junit.runner.JUnitCore; 17 | import org.junit.runner.Request; 18 | import org.junit.runner.Result; 19 | import org.junit.runner.Runner; 20 | 21 | /** 22 | * Integration test for validating the basic mutation testing functionality 23 | */ 24 | public class MutationTestingIT extends AbstractMutationTest { 25 | 26 | protected JUnitCore junit = new JUnitCore(); 27 | 28 | protected Result runTest(String testClassName, String testMethod, ClassLoader loader) throws ClassNotFoundException { 29 | Class testClass = Class.forName(testClassName, true, loader); 30 | Runner testRunner = Request.method(testClass, testMethod).getRunner(); 31 | return junit.run(testRunner); 32 | } 33 | 34 | protected void validateMutationScores(String testClassName, String testMethod, 35 | String targetInst, OptLevel opt, int expectedMutants, int expectedRun, int expectedKilled) throws Exception { 36 | 37 | final Set mutantsToRun = new HashSet<>(); 38 | final HashMap mutantValueMap = new HashMap<>(); 39 | BiConsumer infectionCallback = (m, value) -> { 40 | if (!mutantValueMap.containsKey(m)) { 41 | mutantValueMap.put(m, value); 42 | } else { 43 | if (mutantValueMap.get(m) == null) { 44 | if (value != null) { 45 | mutantsToRun.add(m); 46 | } 47 | } else if (!mutantValueMap.get(m).equals(value)) { 48 | mutantsToRun.add(m); 49 | } 50 | mutantValueMap.remove(m); 51 | } 52 | }; 53 | MutationSnoop.setMutantExecutionCallback(m -> mutantsToRun.add(m)); 54 | MutationSnoop.setMutantInfectionCallback(infectionCallback); 55 | 56 | // Create the JUnit test runner 57 | MutationClassLoaders mcls = initClassLoaders(targetInst, "", opt); 58 | Result r2 = runTest(testClassName, testMethod, mcls.getCartographyClassLoader()); 59 | 60 | // Retrieve dynamically collected mutation instances 61 | List mutants = mcls.getMutationInstances(); 62 | Assert.assertEquals(expectedMutants, mutants.size()); 63 | 64 | // Run mutants and compute mutation score 65 | int run = 0; 66 | int killed = 0; 67 | for (MutationInstance mutant : mutants) { 68 | // Skip if optimization is enabled 69 | if (opt != OptLevel.NONE && !mutantsToRun.contains(mutant)) { 70 | continue; 71 | } 72 | 73 | // Run select mutants 74 | run++; 75 | Result r = runTest(testClassName, testMethod, mcls.getMutationClassLoader(mutant)); 76 | if (!r.wasSuccessful()) { 77 | killed++; 78 | } 79 | } 80 | Assert.assertEquals(expectedRun, run); 81 | Assert.assertEquals(expectedKilled, killed); 82 | 83 | } 84 | 85 | @Test 86 | public void mutateTimSortNoOpt() throws Exception { 87 | validateMutationScores("cmu.pasta.mu2.examples.sort.TimSortTest", "testTimSort", 88 | "cmu.pasta.mu2.examples.sort.TimSort", OptLevel.NONE, 503, 503, 27); 89 | } 90 | 91 | 92 | @Test 93 | public void mutateTimSortO1() throws Exception { 94 | validateMutationScores("cmu.pasta.mu2.examples.sort.TimSortTest", "testTimSort", 95 | "cmu.pasta.mu2.examples.sort.TimSort", OptLevel.EXECUTION, 503, 50,27); 96 | } 97 | 98 | @Test 99 | public void mutateTimSortInfection() throws Exception { 100 | validateMutationScores("cmu.pasta.mu2.examples.sort.TimSortTest", "testTimSort", 101 | "cmu.pasta.mu2.examples.sort.TimSort", OptLevel.INFECTION, 503, 41,27); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cmu.pasta.mu2 8 | mu2 9 | 1.0-SNAPSHOT 10 | 11 | Mu2 12 | Mutation-guided Mutation-based Fuzz Testing 13 | https://github.com/cmu-pasta/mu2 14 | 15 | 16 | MIT License 17 | https://opensource.org/licenses/MIT 18 | 19 | 20 | 21 | 22 | core 23 | examples 24 | integration-tests 25 | 26 | 27 | pom 28 | 29 | 30 | 31 | 32 | edu.berkeley.cs.jqf 33 | jqf-fuzz 34 | 2.0 35 | 36 | 37 | org.hamcrest 38 | hamcrest 39 | 2.2 40 | 41 | 42 | org.apache.maven 43 | maven-plugin-api 44 | 3.5.3 45 | 46 | 47 | org.apache.maven.plugin-tools 48 | maven-plugin-annotations 49 | 3.5.1 50 | provided 51 | 52 | 53 | org.apache.maven 54 | maven-core 55 | 3.5.3 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-compiler-plugin 64 | 3.8.1 65 | 66 | 9 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-surefire-plugin 72 | 2.22.2 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-plugin-plugin 77 | 3.6.1 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-deploy-plugin 82 | 2.8.2 83 | 84 | 85 | org.apache.maven.plugins 86 | maven-site-plugin 87 | 3.9.1 88 | 89 | 90 | org.apache.maven.plugins 91 | maven-checkstyle-plugin 92 | 3.1.2 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | org.apache.maven.plugins 101 | maven-checkstyle-plugin 102 | 3.1.2 103 | 104 | checkstyle.xml 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | github 113 | 114 | 115 | central 116 | https://repo1.maven.org/maven2 117 | 118 | 119 | github 120 | https://maven.pkg.github.com/cmu-pasta/sort-benchmarks 121 | 122 | true 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cycler==0.10.0 2 | kiwisolver==1.3.2 3 | matplotlib==3.4.3 4 | matplotlib-venn==0.11.6 5 | numpy==1.21.2 6 | pandas==1.3.3 7 | Pillow==8.3.2 8 | pyparsing==2.4.7 9 | python-dateutil==2.8.2 10 | pytz==2021.1 11 | scipy==1.7.1 12 | six==1.16.0 13 | -------------------------------------------------------------------------------- /scripts/getMutants.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Leaves a venn diagram of Zest's mutant finding vs. Mu2's mutant finding in the output directory. 4 | #example usage: 5 | # ./getMutants.sh diff.DiffTest fuzzTimSort testTimSort sort.TimSort diff.DiffTest,sort \ 6 | # 3 1000 ../../sort-benchmarks timsort 7 | 8 | fuzzZest() { 9 | echo mvn jqf:fuzz -Dclass=$1 -Dmethod=$2 -Dout=$3-fuzz-results/tmpZest/exp_$4 -Dengine=zest -DrandomSeed=$4 -Dtrials=$5 10 | mvn jqf:fuzz -Dclass=$1 -Dmethod=$2 -Dout=$3-fuzz-results/tmpZest/exp_$4 -Dengine=zest -DrandomSeed=$4 -Dtrials=$5 11 | } 12 | 13 | fuzzMu2() { 14 | echo mvn mu2:diff -Dclass=$1 -Dmethod=$2 -Dincludes=$3 -DtargetIncludes=$4 -Dout=$5-fuzz-results/tmpMu2/exp_$6 -DrandomSeed=$6 -Dtrials=$7 15 | mvn mu2:diff -Dclass=$1 -Dmethod=$2 -Dincludes=$3 -DtargetIncludes=$4 -Dout=$5-fuzz-results/tmpMu2/exp_$6 -DrandomSeed=$6 -Dtrials=$7 -DoptLevel=EXECUTION 16 | } 17 | 18 | getResults() { 19 | 20 | # Debug purposes - dump args to look at actual files 21 | mvn jqf:repro -Dclass=$1 -Dmethod=$2 -Dinput=target/$7-fuzz-results/tmpZest/exp_$6/corpus -Djqf.repro.dumpArgsDir=target/$7-fuzz-results/tmpZest/exp_$6/args_corpus/ 22 | mvn jqf:repro -Dclass=$1 -Dmethod=$2 -Dinput=target/$7-fuzz-results/tmpMu2/exp_$6/corpus -Djqf.repro.dumpArgsDir=target/$7-fuzz-results/tmpMu2/exp_$6/args_corpus/ 23 | 24 | mvn mu2:mutate -Dclass=$1 -Dmethod=$3 -Dincludes=$4 -DtargetIncludes=$5 -Dinput=target/$7-fuzz-results/tmpZest/exp_$6/corpus -DresultsDir=$7-results/zest-results-$6 #> $7-results/zest-results-$6.txt 25 | mvn mu2:mutate -Dclass=$1 -Dmethod=$3 -Dincludes=$4 -DtargetIncludes=$5 -Dinput=target/$7-fuzz-results/tmpMu2/exp_$6/corpus -DresultsDir=$7-results/mutate-results-$6 #> $7-results/mutate-results-$6.txt 26 | 27 | cat $7-results/zest-results-$6/mutate-repro-out.txt | grep -a "Running Mutant\|FAILURE" > $7-filters/zest-filter-$6.txt 28 | cat $7-results/mutate-results-$6/mutate-repro-out.txt | grep -a "Running Mutant\|FAILURE" > $7-filters/mutate-filter-$6.txt 29 | 30 | } 31 | 32 | CLASS=$1 33 | FUZZMETHOD=$2 34 | DIFFMETHOD=$3 35 | INCLUDES=$4 36 | TARGETINCLUDES=$5 37 | REPS=$6 38 | TRIALS=$7 39 | DIR=$8 40 | TARGETNAME=$9 41 | 42 | CURDIR=$(pwd) 43 | cd $DIR 44 | mkdir $TARGETNAME-filters 45 | mkdir $TARGETNAME-results 46 | mkdir $TARGETNAME-mutant-plots 47 | 48 | N=1 49 | for i in $(seq 1 1 $REPS) 50 | do 51 | ((j=j%N)); ((j++==0)) && wait 52 | fuzzZest $CLASS $FUZZMETHOD $TARGETNAME $i $TRIALS & 53 | done 54 | wait 55 | 56 | N=1 57 | for i in $(seq 1 1 $REPS) 58 | do 59 | ((j=j%N)); ((j++==0)) && wait 60 | fuzzMu2 $CLASS $DIFFMETHOD $INCLUDES $TARGETINCLUDES $TARGETNAME $i $TRIALS & 61 | done 62 | wait 63 | 64 | N=1 65 | for i in $(seq 1 1 $6) 66 | do 67 | ((j=i%N)); ((j++==0)) && wait 68 | getResults $CLASS $FUZZMETHOD $DIFFMETHOD $INCLUDES $TARGETINCLUDES $i $TARGETNAME & 69 | done 70 | wait 71 | 72 | cd $CURDIR 73 | python venn.py --filters_dir $DIR/$TARGETNAME-filters --num_experiments $REPS --output_img $DIR/$TARGETNAME-venn.png 74 | 75 | for i in $(seq 1 1 $6) 76 | do 77 | python plot_mutant_data.py $DIR/target/$TARGETNAME-fuzz-results/tmpMu2/exp_$i/plot_data $DIR/$TARGETNAME-mutant-plots/exp_$i.png 78 | done 79 | 80 | 81 | #comment the below lines to not remove the created files 82 | # rm -r filters 83 | # rm -r results 84 | # rm -r target/tmpZest 85 | # rm -r target/tmpMu2 86 | -------------------------------------------------------------------------------- /scripts/graph_log.py: -------------------------------------------------------------------------------- 1 | #emits graph(s) interpretations of the fuzz.log output 2 | import argparse 3 | import re 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | import subprocess 7 | 8 | #dumb "parser" that picks out the current input and its source 9 | def parseFile(file_name): 10 | source_info = {} 11 | reason_info = {} 12 | mutant_info = {} 13 | with open(file_name, 'r') as file: 14 | for line in file.readlines(): 15 | #takes all relevant information (id, source, reasons, mutants) and places them into capture groups 16 | res = re.search(r"Saved - .*id_(\d+) src:(\d+),havoc:\d+ ((?:\+[a-zA-Z]*(?: |$))*)(?:$|\+\d+ (mutants) \[(\(.*\))\])",line) 17 | if res is not None: 18 | info = res.groups() 19 | try: 20 | source_info[int(info[1])].append(int(info[0])) 21 | except KeyError: 22 | source_info[int(info[1])] = [int(info[0])] 23 | reasons = "" 24 | if info[2] is not None: 25 | reasons = info[2] 26 | #if one of the reasons is killed mutants 27 | if info[3] is not None: 28 | reasons+= "+mutants" 29 | #collect mutants 30 | mutants = re.findall(r"\(([^,]*),[^\)]*\)",info[4]) 31 | mutant_info[int(info[0])] = mutants 32 | try: 33 | reason_info[reasons].append(int(info[0])) 34 | except KeyError: 35 | reason_info[reasons] = [int(info[0])] 36 | 37 | return source_info, reason_info, mutant_info 38 | 39 | def emit_dot(data,dot_file,out_file): 40 | with open(dot_file,"w") as file: 41 | file.write("digraph D { \n") 42 | for src in data: 43 | for res in data[src]: 44 | file.write(f" {src}->{res}\n") 45 | file.write("}") 46 | try: 47 | subprocess.call(f"dot {dot_file} -Tpng -o {out_file}",shell=True) 48 | except FileNotFoundError: 49 | print("ERROR: graphviz dot does not appear to be installed") 50 | 51 | def emit_inputs(reasons,mutants,repro): 52 | print("listing all +mutants inputs and the mutants they kill") 53 | pm = reasons["+mutants"] 54 | for i in pm: 55 | print(f"input {i} is") 56 | with open(f"{repro if repro[-1]=='/' else repro+'/'}id_{str(i).zfill(6)}.0","r") as file: 57 | for line in file.readlines(): 58 | print(line) 59 | print(f"input {i} kills the following mutants:") 60 | for mut in mutants[i]: 61 | print(mut) 62 | 63 | def plot_freq_data(sources,reasons,out_file): 64 | reason_total_children = dict.fromkeys(reasons.keys(),0) 65 | for key in reasons: 66 | for i in reasons[key]: 67 | try: 68 | reason_total_children[key] += len(sources[i]) 69 | except KeyError: 70 | pass 71 | labels = list(reasons.keys()) 72 | children_per_reason = list(reason_total_children.values()) 73 | inputs_per_reason = list(map(len,reasons.values())) 74 | x = list(np.arange(len(labels))) 75 | plt.figure(figsize=(12,3)) 76 | plt.bar(list(map(lambda y: y-0.20,x)),children_per_reason, width=0.4,label='Number of children inputs generated with this reason have') 77 | plt.bar(list(map(lambda y: y+0.20,x)),inputs_per_reason, width=0.4,label='Number inputs saved for this reason') 78 | plt.xticks(x, labels) 79 | 80 | plt.legend() 81 | plt.ylabel('# inputs') 82 | plt.savefig(out_file) 83 | 84 | 85 | if __name__ == "__main__": 86 | #the argument parsing takes much more time than the rest of the program (for small-ish inputs), annoyingly 87 | parser = argparse.ArgumentParser() 88 | parser.add_argument("input_log", type=str,help="log to be parsed and graphed") 89 | parser.add_argument('-oc', '--chartout', nargs='?', const='chart.png', default="chart.png", help='output for the bar chart representation of the logs') 90 | parser.add_argument('-og', '--graphout', nargs='?', const='graph.png', help='output for digraph representation of the logs') 91 | parser.add_argument('-od', '--dotout', nargs='?', const='/tmp/graph.dot', help='intermediate output for graphiv dot representation of the logs') 92 | parser.add_argument('-r', '--reproout', nargs='?', const='arg_corpus', help='The directory of the result of calling repro. Used for showing the inputs that killed mutants.') 93 | args = parser.parse_args() 94 | 95 | sources,reasons, mutants = parseFile(args.input_log) 96 | if args.graphout is not None or args.dotout is not None: 97 | emit_dot(sources,args.dotout,args.graphout) 98 | 99 | if args.reproout is not None: 100 | emit_inputs(reasons,mutants,args.reproout) 101 | plot_freq_data(sources,reasons,args.chartout) 102 | -------------------------------------------------------------------------------- /scripts/plot_mutant_data.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import numpy as np 3 | import pandas as pd 4 | import matplotlib.pyplot as plt 5 | 6 | def read_plot_data(input_plot_data): 7 | return pd.read_csv(input_plot_data, skipinitialspace=True) 8 | 9 | 10 | def plot_mutants(df, output_file): 11 | plt.plot(df['total_time'], df['found_muts'], label="Found Mutants") 12 | plt.plot(df['total_time'], df['seen_muts'], label="Seen Mutants") 13 | plt.plot(df['total_time'], df['dead_muts'], label="Killed Mutants") 14 | plt.plot(df['total_time'], df['run_muts'], label="Run Mutants (moving average)") 15 | 16 | func_of_best_fit = np.poly1d(np.polyfit(df['total_time'], df['run_muts'], deg=1)) 17 | plt.plot(df['total_time'], list(map(func_of_best_fit,df['total_time'])),label="Run Mutants (Line Of Best Fit)") 18 | 19 | plt.title("Mutant Plots") 20 | plt.xlabel("Total Time (ms)") 21 | plt.ylabel("Number of Mutants") 22 | plt.legend(loc='upper right', bbox_to_anchor=(1.6, 1.02), fancybox=True) 23 | plt.savefig(output_file, bbox_inches='tight') 24 | 25 | def print_summary_data(df): 26 | print(f"Total Found Mutants: {df['found_muts'].iloc[-1]}") 27 | print(f"Total Seen Mutants: {df['seen_muts'].iloc[-1]}") 28 | 29 | time = df['total_time'] .iloc[-1] 30 | ms = time % 1000 31 | total_s = time // 1000 32 | s = total_s % 60 33 | total_m = total_s // 60 34 | m = total_m % 60 35 | h = total_m // 60 36 | print(f"Total Time For Campaign (H:M:S:ms): {h}:{m}:{s}:{ms}") 37 | 38 | total_trials = df['valid_inputs'].iloc[-1] + df['invalid_inputs'].iloc[-1] 39 | map_time = df['map_time'].iloc[-1] 40 | print(f"Average mapping time per trial (mS): {map_time/total_trials}") 41 | print(f"Average total time per trial (mS): {time/total_trials}") 42 | 43 | if __name__ == "__main__": 44 | parser = argparse.ArgumentParser() 45 | parser.add_argument("input_plot_data", type=str) 46 | parser.add_argument("output_file", type=str) 47 | args = parser.parse_args() 48 | 49 | df = read_plot_data(args.input_plot_data) 50 | plot_mutants(df, args.output_file) 51 | print_summary_data(df) 52 | -------------------------------------------------------------------------------- /scripts/run_benchmarks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #runs each benchmark, graphs/plots them with the other scripts in the directory. 3 | #ARGS: $1 - time per run 4 | # $2 - location of results 5 | # $3 - filters 6 | 7 | MYPATH=$(dirname "$0") 8 | 9 | mkdir -p $2 10 | 11 | mvn mu2:diff -Dclass=sort.TimSortTest -Dmethod=fuzzTimSort -Dincludes=sort.TimSort -Dout=fuzz-results-timsort -Dtime=$1 -Dfilters=$3 12 | 13 | python $MYPATH/plot_mutant_data.py target/fuzz-results-timsort/plot_data $2/timsortPlot 14 | python $MYPATH/graph_log.py target/fuzz-results-timsort/fuzz.log --chartout $2/timsortLogChart.png 15 | 16 | mvn mu2:diff -Dclass=diff.GsonTest -Dmethod=testJSONParser -Dincludes=com.google.gson.stream,com.google.gson.Gson,com.google.gson.Json -Dout=fuzz-results-gson -Dtime=$1 -Dfilters=$3 17 | 18 | python $MYPATH/plot_mutant_data.py target/fuzz-results-gson/plot_data $2/gsonPlot 19 | python $MYPATH/graph_log.py target/fuzz-results-gson/fuzz.log --chartout $2/gsonLogChart.png 20 | 21 | mvn mu2:diff -Dclass=diff.JacksonDatabindTest -Dmethod=testJsonReadValue -Dincludes=com.fasterxml.jackson.core.json,com.fasterxml.jackson.databind.json -Dout=fuzz-results-jackson -Dtime=$1 -Dfilters=$3 22 | 23 | python $MYPATH/plot_mutant_data.py target/fuzz-results-jackson/plot_data $2/jacksonPlot 24 | python $MYPATH/graph_log.py target/fuzz-results-jackson/fuzz.log --chartout $2/jacksonLogChart.png 25 | 26 | mvn mu2:diff -Dclass=diff.ApacheTomcatTest -Dmethod=testWithGenerator -Dincludes=org.apache.tomcat.util.descriptor,org.apache.tomcat.util.digester -Dout=fuzz-results-tomcat -Dtime=$1 -Dfilters=$3 27 | 28 | python $MYPATH/plot_mutant_data.py target/fuzz-results-tomcat/plot_data $2/tomcatPlot 29 | python $MYPATH/graph_log.py target/fuzz-results-tomcat/fuzz.log --chartout $2/tomcatLogChart.png 30 | 31 | mvn mu2:diff -Dclass=diff.ClosureTest -Dmethod=testWithGenerator -Dincludes=com.google.javascript.jscomp.Compiler -Dout=fuzz-results-closure -Dtime=$1 -Dfilters=$3 32 | 33 | python $MYPATH/plot_mutant_data.py target/fuzz-results-closure/plot_data $2/closurePlot 34 | python $MYPATH/graph_log.py target/fuzz-results-closure/fuzz.log --chartout $2/closureLogChart.png 35 | -------------------------------------------------------------------------------- /scripts/venn.py: -------------------------------------------------------------------------------- 1 | from matplotlib_venn import venn2 2 | from scipy import stats 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import argparse 6 | import os 7 | import math 8 | 9 | def get_killed_mutants(file_name): 10 | with open(file_name, "r") as f: 11 | lines = f.readlines() 12 | 13 | i = 0 14 | killed_mutants = set() 15 | while i < len(lines): 16 | if "Running Mutant" in lines[i]: 17 | killed = False 18 | mutant_name = lines[i][lines[i].index("Mutant"):].strip() 19 | i += 1 20 | while i < len(lines) and "Running Mutant" not in lines[i]: 21 | if "FAILURE" in lines[i]: 22 | killed = True 23 | i += 1 24 | if killed: 25 | killed_mutants.add(mutant_name) 26 | return killed_mutants 27 | 28 | def get_unique(zest_killed, mutate_killed): 29 | 30 | zest_uniq = zest_killed - mutate_killed 31 | mutate_uniq = mutate_killed - zest_killed 32 | both_found = zest_killed.intersection(mutate_killed) 33 | 34 | print("\nUnique to Zest:") 35 | print(*list(zest_uniq), sep = "\n") 36 | print("\nUnique to Mu2:") 37 | print(*list(mutate_uniq), sep = "\n") 38 | print("\nBoth found another", len(both_found)) 39 | 40 | return len(zest_uniq), len(mutate_uniq), len(both_found) 41 | 42 | if __name__ == "__main__": 43 | parser = argparse.ArgumentParser() 44 | parser.add_argument("--filters_dir", required=True, type=str) 45 | parser.add_argument("--num_experiments", required=True, type=int) 46 | parser.add_argument("--output_img", required=True, type=str) 47 | parser.add_argument("--target_name", required=False, type=str) 48 | 49 | args = parser.parse_args() 50 | zest_killed = [] 51 | mutate_killed = [] 52 | 53 | zest_unique_count = [] 54 | mutate_unique_count = [] 55 | both_found = [] 56 | for i in range(1, args.num_experiments + 1): 57 | zest = get_killed_mutants(os.path.join(args.filters_dir, "zest-filter-" + str(i) + ".txt")) 58 | mutate = get_killed_mutants(os.path.join(args.filters_dir, "mutate-filter-" + str(i) + ".txt")) 59 | 60 | zest_killed.append(len(zest)) 61 | mutate_killed.append(len(mutate)) 62 | 63 | zest_unique, mutate_unique, both = get_unique(zest, mutate) 64 | 65 | zest_unique_count.append(zest_unique) 66 | mutate_unique_count.append(mutate_unique) 67 | both_found.append(both) 68 | 69 | 70 | zest_stats = stats.describe(zest_killed) 71 | mu2_stats = stats.describe(mutate_killed) 72 | 73 | print("---------------------------------------------------\n\n") 74 | print("Zest Killed Counts: ") 75 | print(zest_killed) 76 | print("Mu2 Killed Counts: ") 77 | print(mutate_killed) 78 | print("Zest Mutant Killed Summary: ") 79 | print("Experiments: %d" % zest_stats.nobs) 80 | print("Mean: %f" % zest_stats.mean) 81 | print("Stddev: %f" % np.sqrt(zest_stats.variance)) 82 | print(stats.describe(zest_killed)) 83 | print("Mu2 Mutant Killed Summary: ") 84 | print("Experiments: %d" % mu2_stats.nobs) 85 | print("Mean: %f" % mu2_stats.mean) 86 | print("Stddev: %f" % np.sqrt(mu2_stats.variance)) 87 | print(stats.describe(mutate_killed)) 88 | print("Zest Unique Mutant Killed Summary: ") 89 | print(stats.describe(zest_unique_count)) 90 | print("Mu2 Unique Mutant Killed Summary: ") 91 | print(stats.describe(mutate_unique_count)) 92 | print("Both Killed Summary: ") 93 | print(stats.describe(both_found)) 94 | print("T-test between Killed Counts: ") 95 | print(stats.ttest_ind(zest_killed, mutate_killed)) 96 | 97 | 98 | fig = venn2(subsets = (math.floor((np.mean(zest_unique_count)) * 100) / 100.0, math.floor((np.mean(mutate_unique_count)) * 100) / 100.0, math.floor((np.mean(both_found)) * 100) / 100.0), set_labels = ["Zest ", " Mu2"]) 99 | if (args.target_name): 100 | plt.title(args.target_name) 101 | plt.savefig(args.output_img) 102 | 103 | --------------------------------------------------------------------------------