Skip to content

Commit

Permalink
Dev friendly amp improvements and windows support (#1004)
Browse files Browse the repository at this point in the history
* comment out junit extra in dependencies

* windows-compatible default configuration values

* fix checkstyle error

* more explanatory comments: null amplifier, method remover

* fully remove assertions on dev-friendly mode, rename to removeAssertion[s] for clarity

* adapt test cases to new comments + removing assertions fully

* remove commented out code
  • Loading branch information
lacinoire authored Nov 5, 2021
1 parent d07b4b2 commit 16bb716
Show file tree
Hide file tree
Showing 21 changed files with 127 additions and 121 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package eu.stamp_project.dspot.amplifier.amplifiers;

import eu.stamp_project.dspot.common.configuration.options.CommentEnum;
import eu.stamp_project.dspot.common.miscellaneous.CloneHelper;
import eu.stamp_project.dspot.common.miscellaneous.Counter;
import eu.stamp_project.dspot.common.miscellaneous.DSpotUtils;
import spoon.reflect.code.CtComment;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtMethod;

Expand Down Expand Up @@ -71,8 +74,12 @@ protected List<T> reduceAlreadyAmplifiedElements(List<T> elementsToBeReduced) {
protected CtMethod<?> replace(T originalElement, T amplifiedElement, CtMethod<?> testMethod) {
originalElement.replace(amplifiedElement);
amplifiedElement.putMetadata(this.METADATA_KEY, true);
CtMethod<?> clone = CloneHelper.cloneTestMethodForAmp(testMethod, getSuffix());
DSpotUtils.addComment(amplifiedElement,
getSuffix() + ": changed '" + originalElement + "' to '" + amplifiedElement + "'",
CtComment.CommentType.INLINE, CommentEnum.Amplifier);
CtMethod<?> clone = CloneHelper.cloneTestMethodForAmp(testMethod, "_" + getSuffix());
amplifiedElement.replace(originalElement);
DSpotUtils.removeComments(originalElement, getSuffix());
Counter.updateInputOf(clone, 1);
return clone;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package eu.stamp_project.dspot.amplifier.amplifiers;

import eu.stamp_project.dspot.common.configuration.options.CommentEnum;
import eu.stamp_project.dspot.common.miscellaneous.DSpotUtils;
import eu.stamp_project.dspot.common.test_framework.TestFramework;
import eu.stamp_project.dspot.common.miscellaneous.AmplificationHelper;
import eu.stamp_project.dspot.common.miscellaneous.CloneHelper;
import eu.stamp_project.dspot.common.miscellaneous.Counter;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtStatementList;
import spoon.reflect.code.CtTry;
import spoon.reflect.code.CtWhile;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtType;
import spoon.reflect.visitor.filter.TypeFilter;
Expand Down Expand Up @@ -54,6 +51,8 @@ private CtMethod<?> apply(CtMethod<?> method, CtInvocation<?> invocation) {
ctStatementList.getStatements().get(indexOfInvocation).insertAfter(invocation);
}
Counter.updateInputOf(cloned, 1);
DSpotUtils.addComment(ctStatementList,"MethodCallRemover: removed call '" + invocation + "'",
CtComment.CommentType.INLINE, CommentEnum.Amplifier);
return cloned;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,36 +106,37 @@ public TestTuple removeAssertions(CtType<?> testClass, List<CtMethod<?>> tests)
CtType<?> cloneClass = testClass.clone();
testClass.getPackage().addType(cloneClass);
if (devFriendlyAmplification) {
return new TestTuple(cloneClass, removeAssertionsAndTrailingInvocations(tests,cloneClass));
return new TestTuple(cloneClass, removeAssertionsCompletely(tests,cloneClass));
} else {
return new TestTuple(cloneClass, removeAssertions(tests, cloneClass));
}
}

/**
* Uses {@link AssertionRemover#removeAssertion(CtMethod)} to remove existing assertions from cloned test methods
* Uses {@link AssertionRemover#removeAssertions(CtMethod, boolean)} to remove existing assertions from cloned
* test methods, but leaves the arguments of the assertions
* @param tests
* @param cloneClass
* @return
*/
private List<CtMethod<?>> removeAssertions(List<CtMethod<?>> tests, CtType<?> cloneClass){
List<CtMethod<?>> testsWithoutAssertions = tests.stream()
.map(this.assertionRemover::removeAssertion)
.map(test -> this.assertionRemover.removeAssertions(test, true))
.collect(Collectors.toList());
testsWithoutAssertions.forEach(cloneClass::addMethod);
return testsWithoutAssertions;
}

/**
* Uses {@link AssertionRemover#removeAssertion(CtMethod)} to remove existing assertions from cloned test methods
* Uses {@link AssertionRemover#removeAssertions(CtMethod, boolean)} to remove existing assertions and their
* arguments from cloned test methods
* @param tests
* @param cloneClass
* @return
*/
private List<CtMethod<?>> removeAssertionsAndTrailingInvocations(List<CtMethod<?>> tests, CtType<?> cloneClass){
private List<CtMethod<?>> removeAssertionsCompletely(List<CtMethod<?>> tests, CtType<?> cloneClass){
List<CtMethod<?>> testsWithoutAssertions = tests.stream()
.map(this.assertionRemover::removeAssertion)
.map(this.assertionRemover::removeArgumentsOfTrailingAssertions)
.map(test -> this.assertionRemover.removeAssertions(test, false))
.collect(Collectors.toList());
testsWithoutAssertions.forEach(cloneClass::addMethod);
return testsWithoutAssertions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ public Map<CtMethod<?>, List<CtLocalVariable<?>>> getVariableAssertedPerTestMeth
* @param testMethod Test method
* @return Test's clone without any assertion
*/
public CtMethod<?> removeAssertion(CtMethod<?> testMethod) {
public CtMethod<?> removeAssertions(CtMethod<?> testMethod, boolean leaveArguments) {
CtMethod<?> testWithoutAssertion = CloneHelper.cloneTestMethodNoAmp(testMethod);
variableAssertedPerTestMethod.put(testWithoutAssertion,
testWithoutAssertion
.getElements(TestFramework.ASSERTIONS_FILTER)
.stream()
.filter(invocation -> !(invocation.getParent() instanceof CtRHSReceiver)) // it means that the return type is used in the test.
.flatMap(invocation -> this.removeAssertion(invocation).stream())
.flatMap(invocation -> this.removeAssertion(invocation, leaveArguments).stream())
.collect(Collectors.toList())
);

Expand All @@ -64,34 +64,13 @@ public boolean matches(CtTry element) {
}

/**
* Can be called after {@link AssertionRemover#removeAssertion(CtMethod)} to remove the statements that
* previously were arguments of assertions all the way at
* @param testMethod
* @return
*/
public CtMethod<?> removeArgumentsOfTrailingAssertions(CtMethod<?> testMethod) {
List<CtStatement> testStatements = testMethod.getElements(new TypeFilter<>(CtStatement.class));

for (int i = testStatements.size() - 1; i >= 0; i--) {
CtStatement statement = testStatements.get(i);
Object metadata = statement.getMetadata(AssertionGeneratorUtils.METADATA_WAS_IN_ASSERTION);
if (metadata != null && (Boolean) metadata) {
testMethod.getBody().removeStatement(statement);
} else {
break;
}
}

return testMethod;
}

/**
* Replaces an invocation with its arguments.
* Remove an invocation and optionally replace with its arguments
*
* @param invocation Invocation
* @param leaveArguments if true: replace the invocation with its arguments
* @return the list of local variables extracted from assertions
*/
public List<CtLocalVariable<?>> removeAssertion(CtInvocation<?> invocation) {
public List<CtLocalVariable<?>> removeAssertion(CtInvocation<?> invocation, boolean leaveArguments) {
List<CtLocalVariable<?>> variableReadsAsserted = new ArrayList<>();
final Factory factory = invocation.getFactory();
final TypeFilter<CtStatement> statementTypeFilter = new TypeFilter<CtStatement>(CtStatement.class) {
Expand All @@ -108,42 +87,40 @@ public boolean matches(CtStatement element) {
if (clone instanceof CtUnaryOperator) {
clone = ((CtUnaryOperator) clone).getOperand();
}
if (clone instanceof CtLambda) {
CtLambda lambda = ((CtLambda) clone);
if (lambda.getBody() != null) {
invocation.getParent(CtStatementList.class).insertBefore(
statementTypeFilter,
factory.createStatementList(lambda.getBody())
);
} else {
// in case of we have something like () -> "string"
if (lambda.getExpression() instanceof CtLiteral) {
continue;
if (leaveArguments) {
if (clone instanceof CtLambda) {
CtLambda lambda = ((CtLambda) clone);
if (lambda.getBody() != null) {
invocation.getParent(CtStatementList.class)
.insertBefore(statementTypeFilter, factory.createStatementList(lambda.getBody()));
} else {
// in case of we have something like () -> "string"
if (lambda.getExpression() instanceof CtLiteral) {
continue;
}
// TODO check that we support all cases by casting into CtInvocation
final CtBlock block = factory.createBlock();
block.setStatements(Collections.singletonList((CtInvocation) lambda.getExpression().clone()));
invocation.getParent(CtStatementList.class).insertBefore(statementTypeFilter,
factory.createStatementList(block));
}
// TODO check that we support all cases by casting into CtInvocation
final CtBlock block = factory.createBlock();
block.setStatements(Collections.singletonList((CtInvocation)lambda.getExpression().clone()));
invocation.getParent(CtStatementList.class).insertBefore(
statementTypeFilter, factory.createStatementList(block)
);
}
} else if (clone instanceof CtStatement) {
invocation.getParent(CtStatementList.class).insertBefore(statementTypeFilter, (CtStatement) clone);
clone.putMetadata(AssertionGeneratorUtils.METADATA_WAS_IN_ASSERTION, true);
} else if (!(clone instanceof CtLiteral || clone instanceof CtVariableRead)) {
// TODO EXPLAIN
CtTypeReference<?> typeOfParameter = clone.getType();
if (clone.getType() == null || factory.Type().NULL_TYPE.equals(clone.getType())) {
typeOfParameter = factory.Type().createReference(Object.class);
} else if (clone instanceof CtStatement) {
invocation.getParent(CtStatementList.class).insertBefore(statementTypeFilter,
(CtStatement) clone);
clone.putMetadata(AssertionGeneratorUtils.METADATA_WAS_IN_ASSERTION, true);
} else if (!(clone instanceof CtLiteral || clone instanceof CtVariableRead)) {
// TODO EXPLAIN
CtTypeReference<?> typeOfParameter = clone.getType();
if (clone.getType() == null || factory.Type().NULL_TYPE.equals(clone.getType())) {
typeOfParameter = factory.Type().createReference(Object.class);
}
final CtLocalVariable localVariable = factory.createLocalVariable(typeOfParameter,
toCorrectJavaIdentifier(typeOfParameter.getSimpleName()) + "_" + counter[0]++, clone);
invocation.getParent(CtStatementList.class).insertBefore(statementTypeFilter, localVariable);
localVariable.putMetadata(AssertionGeneratorUtils.METADATA_WAS_IN_ASSERTION, true);
}
final CtLocalVariable localVariable = factory.createLocalVariable(
typeOfParameter,
toCorrectJavaIdentifier(typeOfParameter.getSimpleName()) + "_" + counter[0]++,
clone
);
invocation.getParent(CtStatementList.class).insertBefore(statementTypeFilter, localVariable);
localVariable.putMetadata(AssertionGeneratorUtils.METADATA_WAS_IN_ASSERTION, true);
} else if (clone instanceof CtVariableRead && !(clone instanceof CtFieldRead)) {
}
if (clone instanceof CtVariableRead && !(clone instanceof CtFieldRead)) {
final CtVariableReference variable = ((CtVariableRead) clone).getVariable();
final List<CtLocalVariable> assertedVariables = invocation.getParent(CtBlock.class).getElements(
localVariable -> localVariable.getSimpleName().equals(variable.getSimpleName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import eu.stamp_project.dspot.common.collector.smtp.EmailSender;
import eu.stamp_project.dspot.common.configuration.test_finder.TestFinder;
import org.apache.commons.io.FileUtils;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -149,15 +148,6 @@ public String completeDependencies(UserInput configuration, AutomaticBuilder aut
dependencies = automaticBuilder.compileAndBuildClasspath();
configuration.setDependencies(dependencies);
}
// TODO checks this. Since we support different Test Support, we may not need to add artificially junit in the classpath
if (!dependencies.contains("junit" + File.separator + "junit" + File.separator + "4")) {
dependencies = Test.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.getFile() +
AmplificationHelper.PATH_SEPARATOR + dependencies;
}
if (!additionalClasspathElements.isEmpty()) {
String pathToAdditionalClasspathElements = additionalClasspathElements;
if (!Paths.get(additionalClasspathElements).isAbsolute()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class UserInput {
"that points to the folder that contains sources (.java)." +
" Default value: ${DEFAULT-VALUE}"
)
private String pathToSourceCode = "src/main/java/";
private String pathToSourceCode = "src" + File.separator + "main" + File.separator + "java" + File.separator;

@CommandLine.Option(
names = "--relative-path-to-test-code",
Expand All @@ -71,7 +71,7 @@ public class UserInput {
"that points to the folder that contains test sources (.java)." +
" Default value: ${DEFAULT-VALUE}"
)
private String pathToTestSourceCode = "src/test/java/";
private String pathToTestSourceCode = "src" + File.separator + "test" + File.separator + "java" + File.separator;

@CommandLine.Option(
names = "--relative-path-to-classes",
Expand All @@ -80,7 +80,7 @@ public class UserInput {
"that points to the folder that contains binaries of the source (.class)." +
" Default value: ${DEFAULT-VALUE}"
)
private String pathToClasses = "target/classes/";
private String pathToClasses = "target" + File.separator + "classes" + File.separator;

@CommandLine.Option(
names = "--relative-path-to-test-classes",
Expand All @@ -89,7 +89,7 @@ public class UserInput {
"that points to the folder that contains binaries of the test source (.class)." +
" Default value: ${DEFAULT-VALUE}"
)
private String pathToTestClasses = "target/test-classes/";
private String pathToTestClasses = "target" + File.separator + "test-classes" + File.separator;

/*
Amplification process configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -197,6 +198,26 @@ public static void addComment(CtElement element, String content, CtComment.Comme
}
}
}
public static void removeComments(CtElement element, String suffixOfComment) {
if (element instanceof CtLiteral) {
try {
CtElement parentLine = element.getParent(new LineFilter());
if (parentLine != null) {
element = parentLine;
}
} catch (ParentNotInitializedException ignored) {

}
}

List<CtComment> ampComments = element.getComments().stream()
.filter(ctComment -> ctComment.getContent().startsWith(suffixOfComment))
.collect(Collectors.toList());
for (CtComment ampComment : ampComments) {
element.removeComment(ampComment);
}

}

public static final String PATH_TO_DSPOT_DEPENDENCIES = "target/dspot/dependencies/";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package eu.stamp_project.dspot.common.test_framework.implementations.junit;

import eu.stamp_project.dspot.common.configuration.options.CommentEnum;
import eu.stamp_project.dspot.common.miscellaneous.DSpotUtils;
import eu.stamp_project.testrunner.runner.Failure;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtFieldRead;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtLambda;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtExecutableReference;
Expand Down Expand Up @@ -72,6 +71,10 @@ public CtMethod<?> generateExpectedExceptionsBlock(CtMethod<?> test, Failure fai
);
CtBlock body = factory.Core().createBlock();
body.addStatement(invocation);
DSpotUtils.addComment(invocation,
"AssertionGenerator generate try/catch block with fail statement",
CtComment.CommentType.INLINE,
CommentEnum.Amplifier);

test.setBody(body);
test.setSimpleName(test.getSimpleName() + "_failAssert" + (numberOfFail));
Expand Down
2 changes: 1 addition & 1 deletion dspot/src/test/java/eu/stamp_project/MainTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public void testDevFriendlyAmplification() throws Exception {
Main.main(new String[]{
"--verbose",
"--absolute-path-to-project-root", new File("src/test/resources/test-projects/").getAbsolutePath() + "/",
"--amplifiers", "FastLiteralAmplifier",
"--amplifiers", "MethodAdderOnExistingObjectsAmplifier",
"--test-criterion", "ExtendedCoverageSelector",
"--test", "example.TestSuiteExample2",
"--dev-friendly",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package eu.stamp_project.dspot;

import eu.stamp_project.dspot.assertiongenerator.assertiongenerator.AssertionGeneratorUtils;
import eu.stamp_project.dspot.common.configuration.options.CommentEnum;
import eu.stamp_project.dspot.common.miscellaneous.DSpotUtils;
import eu.stamp_project.dspot.common.test_framework.TestFramework;
import eu.stamp_project.dspot.common.miscellaneous.CloneHelper;
Expand Down Expand Up @@ -46,6 +47,7 @@ public void setUp() {
TestFramework.init(launcher.getFactory());
DSpotCache.init(10000);
RandomHelper.setSeedRandom(72L);
DSpotUtils.init(CommentEnum.None, null,null,null);
this.testRunner = new TestRunner(getPathToProjectRoot(), "", false);
}

Expand Down
Loading

0 comments on commit 16bb716

Please sign in to comment.