public class Minimize extends CommandHandler
The minimizer will only attempt to minimize methods that are annotated with the @Test annotation. In a method that contains a failing assertion, the minimizer will iterate through the statements of the method, from last to first. For each statement, it tries possible replacement statements, from most minimized to least minimized. Removing the statement is the most a statement can be minimized. Leaving the statement unchanged is the least that the statement can be minimized.
If a replacement causes the output test suite to fail differently than the original test suite, the algorithm tries a different replacement. If no replacement allows the output test suite to fail in the same way as the original test suite, the algorithm adds back the original version of the current statement and continues.
| Modifier and Type | Class and Description |
|---|---|
private static class |
Minimize.ClassOrInterfaceTypeComparator
Sorts a type by its simple name.
|
private static class |
Minimize.ImportDeclarationComparator
Sorts ImportDeclaration objects by their name.
|
static class |
Minimize.Outputs
Contains the command line, exit status, standard output, and standard error from running a
process.
|
| Modifier and Type | Field and Description |
|---|---|
private static Minimize.ClassOrInterfaceTypeComparator |
classOrInterfaceTypeComparator
Sorts a type by its simple name.
|
private static Minimize.ImportDeclarationComparator |
importDeclarationComparator
Sorts ImportDeclaration objects by their name.
|
private static com.github.javaparser.JavaParser |
javaParser
An instance of a Java parser.
|
static int |
minimizetimeout
The maximum number of seconds allowed for the entire minimization process.
|
private static java.lang.String |
PATH_SEPARATOR
Path separator as defined by the system, used to separate elements of the classpath.
|
private static java.lang.String |
SUFFIX
The suffix to postpend onto the name of the minimized file and class.
|
static java.lang.String |
suiteclasspath
Classpath that includes dependencies needed to compile and run the JUnit test suite being
minimized.
|
static java.lang.String |
suitepath
The Java file whose failing tests will be minimized.
|
static int |
testsuitetimeout
The maximum number of seconds allowed for the entire test suite to run.
|
static boolean |
verboseminimizer
Produce verbose diagnostics to standard output if true.
|
| Constructor and Description |
|---|
Minimize()
Create the handler for Randoop's
minimize command. |
| Modifier and Type | Method and Description |
|---|---|
private static void |
addImport(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String importName)
Add an import to the list of
ImportDeclarations of the compilation unit. |
private static boolean |
checkCorrectlyMinimized(java.nio.file.Path file,
java.lang.String classpath,
java.lang.String packageName,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit)
Check if a Java file has been correctly minimized.
|
private static void |
cleanUp(java.nio.file.Path outputFile,
boolean verboseOutput)
Deletes the .class file associated with the outputFile.
|
private static Minimize.Outputs |
compileJavaFile(java.nio.file.Path file,
java.lang.String classpath,
java.lang.String packageName,
int timeoutLimit)
Compile a Java file and return the compilation exit value.
|
private static java.nio.file.Path |
getExecutionDirectory(java.nio.file.Path file,
java.lang.String packageName)
Get directory to execute command in, given file path and package name.
|
private static int |
getFileLength(java.nio.file.Path file)
Calculate the length of a file, by number of lines.
|
private static com.github.javaparser.ast.expr.LiteralExpr |
getLiteralExpression(java.lang.String value,
com.github.javaparser.ast.type.PrimitiveType.Primitive type)
Return a literal expression with the value that is passed in.
|
private static int |
getNumberOfTestMethods(com.github.javaparser.ast.CompilationUnit compilationUnit)
Return the number of JUnit test methods in a compilation unit.
|
private static void |
getOrphanCommentsBeforeThisChildNode(com.github.javaparser.ast.Node node,
java.util.List<com.github.javaparser.ast.comments.Comment> result)
This is stolen from JavaParser's PrettyPrintVisitor.printOrphanCommentsBeforeThisChildNode,
with light modifications.
|
private static java.util.List<com.github.javaparser.ast.stmt.Statement> |
getStatementReplacements(com.github.javaparser.ast.stmt.Statement currStmt,
java.util.Map<java.lang.String,java.lang.String> primitiveValues)
Return a list of statements that are a simplification of a given statement, in order from most
to least minimized.
|
boolean |
handle(java.lang.String[] args)
Check that the required parameters have been specified by the command-line options and then
call the mainMinimize method.
|
private static boolean |
isTestMethod(com.github.javaparser.ast.body.MethodDeclaration methodDeclaration)
Check if the method is a JUnit test method.
|
static boolean |
mainMinimize(java.nio.file.Path file,
java.lang.String classPath,
int timeoutLimit,
boolean verboseOutput)
Minimize the input test file.
|
static java.lang.String |
minimizedClassName(java.nio.file.Path file)
Given a .java filename for non-minimized tests, returns the simple name of the class containing
the minimized tests.
|
private static void |
minimizeMethod(com.github.javaparser.ast.body.MethodDeclaration method,
com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String packageName,
java.nio.file.Path file,
java.lang.String classpath,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit)
Minimize a method by minimizing each statement in turn.
|
private static void |
minimizeTestSuite(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String packageName,
java.nio.file.Path file,
java.lang.String classpath,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit)
Visit and minimize every JUnit test method within a compilation unit.
|
private static java.util.Map<java.lang.String,java.lang.String> |
normalizeJUnitOutput(java.lang.String input)
Normalize the standard output obtained from running a JUnit test suite.
|
private static void |
primitiveVarEquality(com.github.javaparser.ast.expr.Expression exp1,
com.github.javaparser.ast.expr.Expression exp2,
java.util.Map<java.lang.String,java.lang.String> primitiveValues,
java.util.Set<java.lang.String> primitiveAndWrappedTypeVars)
If one of the arguments is a NamxExpr and the other is a LiteralExpr, put them in
primitiveValues. |
private static void |
printProgress(int currentTestIndex,
int totalTests,
com.github.javaparser.ast.expr.SimpleName testName)
Output the minimizer's current progress.
|
private static com.github.javaparser.ast.stmt.Statement |
removeLeftHandSideSimplification(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr)
Return a statement that contains only the right hand side of a given statement.
|
private static com.github.javaparser.ast.stmt.Statement |
rhsAssignValueFromPassingAssertion(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr,
java.util.Map<java.lang.String,java.lang.String> primitiveValues)
Return a variable declaration statement that simplifies the right hand side by a calculated
value for primitive types.
|
private static com.github.javaparser.ast.stmt.Statement |
rhsAssignWithValue(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr,
com.github.javaparser.ast.type.Type exprType,
java.lang.String value)
Return a variable declaration statement that sets the right hand side of a variable declaration
to the value that is passed in.
|
private static java.util.List<com.github.javaparser.ast.stmt.Statement> |
rhsAssignZeroValue(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr)
Return a list of variable declaration statements that could replace the right hand side by 0,
false, or null, whichever is type correct.
|
private static java.lang.String |
runJavaFile(java.nio.file.Path file,
java.lang.String userClassPath,
java.lang.String packageName,
int timeoutLimit)
Run a Java file and return the standard output.
|
static Minimize.Outputs |
runProcess(java.lang.String command,
java.nio.file.Path executionDir,
int timeoutLimit)
Run a command given as a String and return the output and error results in an Outputs object.
|
private static com.github.javaparser.ast.CompilationUnit |
simplifyTypeNames(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String packageName,
java.nio.file.Path file,
java.lang.String classpath,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit,
boolean verboseOutput)
Simplify the type names in a compilation unit.
|
private static void |
sortImports(com.github.javaparser.ast.CompilationUnit compilationUnit)
Sort a compilation unit's imports by name.
|
private static void |
storeValueFromAssertion(com.github.javaparser.ast.stmt.Statement currStmt,
java.util.Map<java.lang.String,java.lang.String> primitiveValues,
java.util.Set<java.lang.String> primitiveAndWrappedTypeVars)
If
currStmt is an assertion about a primitive value, store the value associated with
the variable in the primitiveValues map. |
static void |
writeToFile(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.nio.file.Path file)
Write a compilation unit to a Java file.
|
handles, printHTML, usageMessagepublic static java.lang.String suitepath
public static java.lang.String suiteclasspath
public static int minimizetimeout
public static int testsuitetimeout
public static boolean verboseminimizer
private static final com.github.javaparser.JavaParser javaParser
private static final java.lang.String PATH_SEPARATOR
private static final java.lang.String SUFFIX
private static Minimize.ClassOrInterfaceTypeComparator classOrInterfaceTypeComparator
private static Minimize.ImportDeclarationComparator importDeclarationComparator
public static java.lang.String minimizedClassName(java.nio.file.Path file)
file - the .java filename for non-minimized testspublic boolean handle(java.lang.String[] args)
handle in class CommandHandlerargs - parameters, specified in command-line style, for the input file, the classpath, the
timeout value, and the verbose flagpublic static boolean mainMinimize(java.nio.file.Path file,
java.lang.String classPath,
int timeoutLimit,
boolean verboseOutput)
throws java.io.IOException
Given an input Java file, minimization produces a smaller file that fails in the same way as the original, having the same failing assertions with the same stack trace.
The original input Java file will be compiled and run once. The "expected output" derived from the standard output from running the input file is a map from test method name to failure stack trace. A method is included in the map only if the method contains a failing assertion. Thus, the "expected output" of running a test suite with no failing tests will be an empty map. The "expected output" will be used during subsequent runs of the modified test suite to determine whether or not the test suite still fails in the same way.
file - the Java file that is being minimizedclassPath - classpath used to compile and run the Java filetimeoutLimit - number of seconds allowed for the whole test suite to runverboseOutput - whether to produce verbose outputjava.io.IOException - if write to file failsprivate static void minimizeTestSuite(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String packageName,
java.nio.file.Path file,
java.lang.String classpath,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit)
throws java.io.IOException
compilationUnit - the compilation unit to minimize; is modified by side effectpackageName - the package that the Java file is infile - the Java file that is being minimized; is modified by side effectclasspath - classpath used to compile and run the Java fileexpectedOutput - expected JUnit output when the Java file is compiled and runtimeoutLimit - number of seconds allowed for the whole test suite to runjava.io.IOException - thrown if minimized method can't be written to fileprivate static boolean isTestMethod(com.github.javaparser.ast.body.MethodDeclaration methodDeclaration)
methodDeclaration - the method declaration to checkprivate static void minimizeMethod(com.github.javaparser.ast.body.MethodDeclaration method,
com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String packageName,
java.nio.file.Path file,
java.lang.String classpath,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit)
throws java.io.IOException
method - the method to minimize; is modified by side effectcompilationUnit - compilation unit for the Java file that we are minimizing; is modified
by side effectpackageName - the package that the Java file is infile - the Java file that is being minimized; is modified by side effectclasspath - classpath needed to compile and run the Java fileexpectedOutput - expected output from running the JUnit test suitetimeoutLimit - number of seconds allowed for the whole test suite to runjava.io.IOException - thrown if write to file failsprivate static void storeValueFromAssertion(com.github.javaparser.ast.stmt.Statement currStmt,
java.util.Map<java.lang.String,java.lang.String> primitiveValues,
java.util.Set<java.lang.String> primitiveAndWrappedTypeVars)
currStmt is an assertion about a primitive value, store the value associated with
the variable in the primitiveValues map.
currStmt might be an assertTrue statement using an '==' operator, or an assertEquals
statement.
currStmt - a statementprimitiveValues - a map of variable names to variable values; modified if currStmt
is a passing assertion, asserting a variable's valueprimitiveAndWrappedTypeVars - set containing the names of all primitive and wrapped type
variablesprivate static void primitiveVarEquality(com.github.javaparser.ast.expr.Expression exp1,
com.github.javaparser.ast.expr.Expression exp2,
java.util.Map<java.lang.String,java.lang.String> primitiveValues,
java.util.Set<java.lang.String> primitiveAndWrappedTypeVars)
primitiveValues.exp1 - the first expressionexp2 - the second expressionprimitiveValues - a map of variable names to variable values; modified if currStmt
is a passing assertion, asserting a variable's valueprimitiveAndWrappedTypeVars - set containing the names of all primitive and wrapped type
variablesprivate static java.util.List<com.github.javaparser.ast.stmt.Statement> getStatementReplacements(com.github.javaparser.ast.stmt.Statement currStmt,
java.util.Map<java.lang.String,java.lang.String> primitiveValues)
0, false, or null.
Assertions are never simplified, only removed completely.
currStmt - statement to simplifyprimitiveValues - map of primitive variable names to expressions representing their valuescurrStmtprivate static java.util.List<com.github.javaparser.ast.stmt.Statement> rhsAssignZeroValue(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr)
int i, j, k; .vdExpr - variable declaration expression representing the current statement to simplifyStatement objects representing the simplified variable declaration
expressionprivate static com.github.javaparser.ast.stmt.Statement rhsAssignValueFromPassingAssertion(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr,
java.util.Map<java.lang.String,java.lang.String> primitiveValues)
int i, j, k; .vdExpr - variable declaration expression representing the current statement to simplifyprimitiveValues - a map of primitive variable names to expressions representing their
valuesStatement object representing the simplified variable declaration expression
if the type of the variable is a primitive and a value has been previously calculated.
Otherwise, returns null. Also returns null if more than one variable is
declared in the VariableDeclarationExpr.private static com.github.javaparser.ast.stmt.Statement rhsAssignWithValue(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr,
com.github.javaparser.ast.type.Type exprType,
java.lang.String value)
vdExpr - variable declaration expression representing the current statement to simplifyexprType - type of the variable declaration expression, should not be nullvalue - value that will be assigned to the variable being declared. If the value is null,
then the right hand side will have the zero value of the variable declaration's type.Statement object representing the simplified variable declaration expression.
Returns null if more than one variable is declared in the VariableDeclarationExpr.private static com.github.javaparser.ast.expr.LiteralExpr getLiteralExpression(java.lang.String value,
com.github.javaparser.ast.type.PrimitiveType.Primitive type)
value - the value for the literal expression. If null, the value of the literal expression
will be the zero value for the type that is passed in.type - the type of the expression, needs to be one of the eight primitive typesprivate static com.github.javaparser.ast.stmt.Statement removeLeftHandSideSimplification(com.github.javaparser.ast.expr.VariableDeclarationExpr vdExpr)
int i=1, j=2,
k=3; , or if there are no initializers, as in int i;.vdExpr - variable declaration expression that represents the statement to simplifyStatement object that is equal to the right-hand-side of vdExpr.
Returns null if more than one variable is declared in the VariableDeclarationExpr.private static com.github.javaparser.ast.CompilationUnit simplifyTypeNames(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String packageName,
java.nio.file.Path file,
java.lang.String classpath,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit,
boolean verboseOutput)
throws java.io.IOException
java.lang.String should be
simplified to String. If two different types have the same simple type name, then the
lexicographically first one is simplified and the other is left unchanged.
Additionally, sort the import statements of the compilation unit.
compilationUnit - compilation unit containing an AST for a Java file, the compilation unit
will be modified if a correct minimization of the method is foundpackageName - the package that the Java file is infile - the Java file to simplify; is modified by side effectclasspath - classpath needed to compile and run the Java fileexpectedOutput - expected standard output from running the JUnit test suitetimeoutLimit - number of seconds allowed for the whole test suite to runverboseOutput - whether or not to output information about minimization statusCompilationUnit with fully-qualified type names simplified to simple type namesjava.io.IOException - thrown if write to file failsprivate static boolean checkCorrectlyMinimized(java.nio.file.Path file,
java.lang.String classpath,
java.lang.String packageName,
java.util.Map<java.lang.String,java.lang.String> expectedOutput,
int timeoutLimit)
file - the file being checkedclasspath - classpath needed to compile/run the Java filepackageName - the package that the Java file is inexpectedOutput - expected output of running the JUnit test suitetimeoutLimit - number of seconds allowed for the whole test suite to runprivate static Minimize.Outputs compileJavaFile(java.nio.file.Path file, java.lang.String classpath, java.lang.String packageName, int timeoutLimit)
file - the file to be compiled and executedclasspath - dependencies and complete classpath to compile and run the Java programpackageName - the package that the Java file is intimeoutLimit - number of seconds allowed for the whole test suite to runprivate static java.lang.String runJavaFile(java.nio.file.Path file,
java.lang.String userClassPath,
java.lang.String packageName,
int timeoutLimit)
file - the file to be compiled and executeduserClassPath - dependencies and complete classpath to compile and run the Java programpackageName - the package that the Java file is intimeoutLimit - number of seconds allowed for the Java program to runprivate static java.nio.file.Path getExecutionDirectory(java.nio.file.Path file,
java.lang.String packageName)
Path
pointing to the directory that the Java file should be executed in.
For the simplest case where the Java file is nested in a single package layer, i.e. MyJavaFile.java is in the package mypackage, the folder structure would be src/mypackage/MyJavaFile.java. Here, we need to execute the Java file in the src/ directory. We go up 2 layers from the directory of the Java file to get to the parent directory of the directory for the package. For the general case where MyJavaFile.java is nested within multiple layers of packages, we count the number of separators, i.e. ".", and add 2 to get the number of layers to go up from the Java file's directory.
file - the Java file to be executedpackageName - package name of input Java filepublic static Minimize.Outputs runProcess(java.lang.String command, java.nio.file.Path executionDir, int timeoutLimit)
command - the input command to be runexecutionDir - the directory where the process commands should be executedtimeoutLimit - number of seconds allowed for the command to runOutputs object containing the standard and error outputprivate static java.util.Map<java.lang.String,java.lang.String> normalizeJUnitOutput(java.lang.String input)
String representation of the output, we remove any extraneous information such as line
numbers. The resulting output is a map from method name to the method's failure stack trace.input - the String produced from running a JUnit test suitepublic static void writeToFile(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.nio.file.Path file)
throws java.io.IOException
compilationUnit - the compilation unit to write to filefile - file to write tojava.io.IOException - thrown if write to file failsprivate static void addImport(com.github.javaparser.ast.CompilationUnit compilationUnit,
java.lang.String importName)
ImportDeclarations of the compilation unit. This method
adds the import statement if it has not been yet included in the list of current imports of the
compilation unit.compilationUnit - compilation unit to add import toimportName - the name of the importprivate static void sortImports(com.github.javaparser.ast.CompilationUnit compilationUnit)
compilationUnit - the compilation unit whose imports will be sorted by nameprivate static int getFileLength(java.nio.file.Path file)
throws java.io.IOException
file - the file to compute the length ofjava.io.IOException - thrown if error reading fileprivate static void cleanUp(java.nio.file.Path outputFile,
boolean verboseOutput)
outputFile - the source file for the class file to be removedverboseOutput - whether to print information about minimization statusprivate static int getNumberOfTestMethods(com.github.javaparser.ast.CompilationUnit compilationUnit)
compilationUnit - the compilation unit to count the number of unit test methodsprivate static void printProgress(int currentTestIndex,
int totalTests,
com.github.javaparser.ast.expr.SimpleName testName)
currentTestIndex - the number of tests that have been minimized so fartotalTests - the total number of tests in the input test suitetestName - the current test method being minimizedprivate static void getOrphanCommentsBeforeThisChildNode(com.github.javaparser.ast.Node node,
java.util.List<com.github.javaparser.ast.comments.Comment> result)
node - the node whose orphan comments to collectresult - the list to add orphan comments to. Is side-effected by this method. The
implementation uses this to minimize the diffs against upstream.