Skip to content

Commit

Permalink
fix STAMP-project#602: support list of regex for test classes and tes…
Browse files Browse the repository at this point in the history
…t methods. (STAMP-project#604)

* fix: refactor API. Now supports regex for everythin (list of test classes and test methods)

* test: update the tests using the new API

* style: remove unused import
  • Loading branch information
danglotb authored Oct 24, 2018
1 parent 73f2323 commit db7b5ff
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 117 deletions.
18 changes: 6 additions & 12 deletions dspot/src/main/java/eu/stamp_project/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,18 @@ public static void run(InputConfiguration configuration) throws Exception {
createOutputDirectories(configuration);
final long startTime = System.currentTimeMillis();
final List<CtType> amplifiedTestClasses;
if ("all".equals(configuration.getTestClasses().get(0))) {
if (configuration.getTestClasses().isEmpty() || "all".equals(configuration.getTestClasses().get(0))) {
amplifiedTestClasses = dspot.amplifyAllTests();
} else if ("diff".equals(configuration.getTestClasses().get(0))) {
final Map<String, List<String>> testMethodsAccordingToADiff = SelectorOnDiff
.findTestMethodsAccordingToADiff(configuration);
amplifiedTestClasses = testMethodsAccordingToADiff.keySet().stream()
.map(ctType -> dspot.amplifyTest(ctType, testMethodsAccordingToADiff.get(ctType)))
.filter(Objects::nonNull)
.flatMap(ctType ->
dspot.amplifyTestClassesTestMethods(Collections.singletonList(ctType), testMethodsAccordingToADiff.get(ctType)).stream()
).filter(Objects::nonNull)
.collect(Collectors.toList());
} else {
if (configuration.getTestClasses().isEmpty()) {
amplifiedTestClasses = dspot.amplifyAllTests();
} else {
amplifiedTestClasses = configuration.getTestClasses().stream()
.map(testClasses -> dspot.amplifyTest(testClasses, configuration.getTestCases()))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
amplifiedTestClasses = dspot.amplifyTestClassesTestMethods(configuration.getTestClasses(), configuration.getTestCases());
}
LOGGER.info("Amplification {}.", amplifiedTestClasses.isEmpty() ? "failed" : "succeed");
final long elapsedTime = System.currentTimeMillis() - startTime;
Expand All @@ -96,7 +90,7 @@ static void runExample() {
configuration.setAmplifiers(Collections.singletonList(new TestDataMutator()));
DSpot dSpot = new DSpot(configuration, 1, configuration.getAmplifiers(),
new JacocoCoverageSelector());
dSpot.amplifyTest("example.TestSuiteExample");
dSpot.amplifyTestClassesTestMethods(Collections.singletonList("example.TestSuiteExample"), Collections.emptyList());
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down
152 changes: 102 additions & 50 deletions dspot/src/main/java/eu/stamp_project/dspot/DSpot.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* User: Simon
Expand Down Expand Up @@ -91,7 +91,7 @@ public DSpot(InputConfiguration inputConfiguration,
this.testSelector = testSelector;
this.testSelector.init(this.inputConfiguration);

String splitter = File.separator.equals("/")?"/":"\\\\";
String splitter = File.separator.equals("/") ? "/" : "\\\\";
final String[] splittedPath = this.inputConfiguration.getAbsolutePathToProjectRoot().split(splitter);
final File projectJsonFile = new File(this.inputConfiguration.getOutputDirectory() +
File.separator + splittedPath[splittedPath.length - 1] + ".json");
Expand All @@ -103,8 +103,43 @@ public DSpot(InputConfiguration inputConfiguration,
}
}

private Stream<CtType<?>> findTestClasses(String targetTestClasses) {
if (!targetTestClasses.contains("\\")) {
targetTestClasses = targetTestClasses.replaceAll("\\.", "\\\\\\.").replaceAll("\\*", ".*");
}
Pattern pattern = Pattern.compile(targetTestClasses);
return this.compiler.getFactory().Class().getAll().stream()
.filter(ctType -> pattern.matcher(ctType.getQualifiedName()).matches())
.filter(ctClass ->
ctClass.getMethods()
.stream()
.anyMatch(AmplificationChecker::isTest))
.filter(InputConfiguration.isNotExcluded);
}

private List<CtMethod<?>> buildListOfTestMethodsToBeAmplified(CtType<?> testClass, List<String> targetTestMethods) {
if (targetTestMethods.isEmpty()) {
return testClass.getMethods()
.stream()
.filter(AmplificationChecker::isTest)
.collect(Collectors.toList());
} else {
return targetTestMethods.stream().flatMap(pattern ->
testClass.getMethods().stream()
.filter(ctMethod -> Pattern.compile(pattern).matcher(ctMethod.getSimpleName()).matches())
.collect(Collectors.toList()).stream()
).collect(Collectors.toList());
}
}

/**
* Amplify all the test methods of all the test classes that DSpot can find.
* A class is considered as a test class if it contains at least one test method.
* A method is considred as test method if it matches {@link AmplificationChecker#isTest(CtMethod)}
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyAllTests() {
return this.amplifyAllTests(this.inputConfiguration.getFactory().Class().getAll().stream()
return this._amplifyTestClasses(this.inputConfiguration.getFactory().Class().getAll().stream()
.filter(ctClass -> !ctClass.getModifiers().contains(ModifierKind.ABSTRACT))
.filter(ctClass ->
ctClass.getMethods()
Expand All @@ -113,63 +148,80 @@ public List<CtType> amplifyAllTests() {
).collect(Collectors.toList()));
}

public List<CtType> amplifyAllTestsNames(List<String> fullQualifiedNameTestClasses) {
return fullQualifiedNameTestClasses.stream()
.flatMap(fullQualifiedNameTestClass -> this.amplifyTest(fullQualifiedNameTestClass).stream())
.collect(Collectors.toList());
/**
* Amplify the given test methods of the given test classes.
* @param testClassToBeAmplified the test class to be amplified. It can be a java regex.
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyTestClass(String testClassToBeAmplified) {
return this.amplifyTestClassesTestMethods(Collections.singletonList(testClassToBeAmplified), Collections.emptyList());
}

public List<CtType> amplifyAllTests(List<CtType> testClasses) {
final List<CtType> amplifiedTestClasses = testClasses.stream()
.filter(InputConfiguration.isNotExcluded)
.map(this::amplifyTest)
/**
* Amplify the given test methods of the given test classes.
* @param testClassToBeAmplified the test class to be amplified. It can be a java regex.
* @param testMethod the test method to be amplified. It can be a java regex.
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyTestClassTestMethod(String testClassToBeAmplified, String testMethod) {
return this.amplifyTestClassesTestMethods(Collections.singletonList(testClassToBeAmplified), Collections.singletonList(testMethod));
}

/**
* Amplify the given test methods of the given test classes.
* @param testClassToBeAmplified the test class to be amplified. It can be a java regex.
* @param testMethods the list of test methods to be amplified. This list can be a list of java regex.
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyTestClassTestMethods(String testClassToBeAmplified, List<String> testMethods) {
return this.amplifyTestClassesTestMethods(Collections.singletonList(testClassToBeAmplified), testMethods);
}

/**
* Amplify the given test methods of the given test classes.
* @param testClassesToBeAmplified the list of test classes to be amplified. This list can be a list of java regex.
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyTestClasses(List<String> testClassesToBeAmplified) {
return this.amplifyTestClassesTestMethods(testClassesToBeAmplified, Collections.emptyList());
}

/**
* Amplify the given test methods of the given test classes.
* @param testClassesToBeAmplified the list of test classes to be amplified. This list can be a list of java regex.
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyTestClassesTestMethod(List<String> testClassesToBeAmplified, String testMethod) {
return this.amplifyTestClassesTestMethods(testClassesToBeAmplified, Collections.singletonList(testMethod));
}

/**
* Amplify the given test methods of the given test classes.
* @param testClassesToBeAmplified the list of test classes to be amplified. This list can be a list of java regex.
* @param testMethods the list of test methods to be amplified. This list can be a list of java regex.
* @return a list of amplified test classes with amplified test methods.
*/
public List<CtType> amplifyTestClassesTestMethods(List<String> testClassesToBeAmplified, List<String> testMethods) {
final List<CtType<?>> testClassesToBeAmplifiedModel = testClassesToBeAmplified.stream()
.flatMap(this::findTestClasses)
.collect(Collectors.toList());
writeTimeJson();
return amplifiedTestClasses;
return testClassesToBeAmplifiedModel.stream()
.map(ctType ->
this._amplify(ctType, this.buildListOfTestMethodsToBeAmplified(ctType, testMethods))
).collect(Collectors.toList());
}

public List<CtType> amplifyTest(String targetTestClasses) {
if (!targetTestClasses.contains("\\")) {
targetTestClasses = targetTestClasses.replaceAll("\\.", "\\\\\\.").replaceAll("\\*", ".*");
}
Pattern pattern = Pattern.compile(targetTestClasses);
return this.compiler.getFactory().Class().getAll().stream()
.filter(ctType -> pattern.matcher(ctType.getQualifiedName()).matches())
.filter(ctClass ->
ctClass.getMethods()
.stream()
.anyMatch(AmplificationChecker::isTest))
.filter(InputConfiguration.isNotExcluded)
.map(this::amplifyTest)
private List<CtType> _amplifyTestClasses(List<CtType> testClassesToBeAmplified) {
return testClassesToBeAmplified.stream()
.map(this::_amplifyTestClass)
.collect(Collectors.toList());
}

public CtType amplifyTest(CtType test) {
return this.amplifyTest(test, AmplificationHelper.getAllTest(test));
}

public CtType amplifyTest(String fullQualifiedName, List<String> methods) {
final CtType<?> testClass = this.compiler.getLauncher().getFactory().Type().get(fullQualifiedName);
final List<CtMethod<?>> testMethods =
(methods.isEmpty() ?
testClass.getMethods().stream() :
methods.stream().map(methodName ->
testClass.getMethods()
.stream()
.filter(ctMethod -> methodName.equals(ctMethod.getSimpleName()))
.findFirst()
.orElse(null)
).filter(Objects::nonNull)
).filter(AmplificationChecker::isTest)
.collect(Collectors.toList());
if (testMethods.isEmpty()) {
LOGGER.warn("Could not match any test methods");
return null;
}
return amplifyTest(testClass, testMethods);
private CtType _amplifyTestClass(CtType test) {
return this._amplify(test, AmplificationHelper.getAllTest(test));
}

public CtType amplifyTest(CtType test, List<CtMethod<?>> methods) {
protected CtType _amplify(CtType test, List<CtMethod<?>> methods) {
try {
test = JUnit3Support.convertToJUnit4(test, this.inputConfiguration);
Counter.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public boolean matches(CtInvocation<?> element) {

EntryPoint.verbose = true;

CtType<?> amplifiedTest = dspot.amplifyTest("info.sanaulla.dal.BookDALTest", Collections.singletonList("testGetBook"));
CtType<?> amplifiedTest = dspot.amplifyTestClassTestMethod("info.sanaulla.dal.BookDALTest", "testGetBook").get(0);

final List<CtMethod<?>> amplifiedTestMethods = AmplificationHelper.getAllTest(amplifiedTest);
assertEquals(6, amplifiedTestMethods.size());
Expand Down
51 changes: 6 additions & 45 deletions dspot/src/test/java/eu/stamp_project/dspot/DSpotSelectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -40,7 +41,7 @@ public MockedDSpot(InputConfiguration inputConfiguration,
}

@Override
public CtType amplifyTest(CtType test, List<CtMethod<?>> methods) {
protected CtType _amplify(CtType test, List<CtMethod<?>> methods) {
methodsToBeAmplified.addAll(methods);
typesToBeAmplified.add(test);
return test;
Expand Down Expand Up @@ -76,7 +77,7 @@ public void testOnTwoClass2() throws Exception {
Can match several test classes
*/

dspotUnderTest.amplifyAllTestsNames(
dspotUnderTest.amplifyTestClasses(
Arrays.asList(
"example.TestSuiteExample",
"example.TestSuiteExample2"
Expand All @@ -87,31 +88,14 @@ public void testOnTwoClass2() throws Exception {
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample2"::equals));
}

@Test
public void testOnTwoClass2UsingCtType() throws Exception {

/*
Can match several test classes
*/

final List<CtType> testClasses = Arrays.asList(
InputConfiguration.get().getFactory().Type().get("example.TestSuiteExample"),
InputConfiguration.get().getFactory().Type().get("example.TestSuiteExample2")
);
dspotUnderTest.amplifyAllTests(testClasses);
assertEquals(2, typesToBeAmplified.size());
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample"::equals));
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample2"::equals));
}

@Test
public void testOneClassTwoMethods() throws Throwable {

/*
Can match specific test method in a test class
*/

dspotUnderTest.amplifyTest(
dspotUnderTest.amplifyTestClassTestMethods(
"example.TestSuiteExample",
Arrays.asList("test2", "test3")
);
Expand All @@ -122,29 +106,6 @@ public void testOneClassTwoMethods() throws Throwable {
assertTrue(methodsToBeAmplified.stream().map(CtMethod::getSimpleName).anyMatch("test3"::equals));
}

@Test
public void testOneClassTwoMethodsUsingCtType() throws Throwable {

/*
Can match specific test method in a test class
*/

final CtType<?> testClass = InputConfiguration.get().getFactory().Type().get("example.TestSuiteExample");

dspotUnderTest.amplifyTest(
testClass,
testClass.getMethods()
.stream()
.filter(test -> test.getSimpleName().equals("test2") ||
test.getSimpleName().equals("test3")).collect(Collectors.toList())
);
assertEquals(1, typesToBeAmplified.size());
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample"::equals));
assertEquals(2, methodsToBeAmplified.size());
assertTrue(methodsToBeAmplified.stream().map(CtMethod::getSimpleName).anyMatch("test2"::equals));
assertTrue(methodsToBeAmplified.stream().map(CtMethod::getSimpleName).anyMatch("test3"::equals));
}

@Test
public void testRegexOnWholePackage() throws Throwable {

Expand All @@ -153,7 +114,7 @@ public void testRegexOnWholePackage() throws Throwable {
The test class TestResources is not selected since it does not contain any test method.
*/

dspotUnderTest.amplifyTest("example.*");
dspotUnderTest.amplifyTestClass("example.*");
assertEquals(2, typesToBeAmplified.size());
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample"::equals));
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample2"::equals));
Expand All @@ -166,7 +127,7 @@ public void testUsingRegex() throws Throwable {
Can match test classes using a regex
*/

dspotUnderTest.amplifyTest("example.TestSuiteExample*");
dspotUnderTest.amplifyTestClass("example.TestSuiteExample*");
assertEquals(2, typesToBeAmplified.size());
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample"::equals));
assertTrue(typesToBeAmplified.stream().map(CtType::getQualifiedName).anyMatch("example.TestSuiteExample2"::equals));
Expand Down
4 changes: 2 additions & 2 deletions dspot/src/test/java/eu/stamp_project/dspot/DSpotTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void testUsingAmplifiedTestClassFromTheStart() throws Exception {
InputConfiguration.get(),
new TakeAllSelector()
);
final CtType amplifyTest = dSpot.amplifyTest(testClass);
final CtType amplifyTest = dSpot.amplifyTestClass("fr.inria.preparation.MustBeRenamedFromStart").get(0);
assertTrue("should be empty", TestCompiler.compileAndRun(
amplifyTest,
Utils.getCompiler(),
Expand All @@ -80,7 +80,7 @@ public void testExcludedClassesInPropertyFile() throws Exception {
// the test class fr.inria.filter.passing.PassingTest has 3 methods, but only two are amplified
assertEquals(3, Utils.findClass("fr.inria.filter.passing.PassingTest").getMethods().size());
// the test class fr.inria.filter.failing.FailingTest match the regex, but it is excluded in the properties
final List<CtType> ctTypes = dSpot.amplifyTest("fr.inria.filter.*");
final List<CtType> ctTypes = dSpot.amplifyTestClass("fr.inria.filter.*");
assertEquals(1, ctTypes.size());
// uses the mock to retrieve the number of method to be amplified
assertEquals(2, dSpot.numberOfMethod);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,21 @@ public void test() throws Exception {
new JacocoCoverageSelector()
);

dspot.amplifyTest("fr.inria.amp.TestJavaPoet");
dspot.amplifyTestClass("fr.inria.amp.TestJavaPoet");
try (BufferedReader buffer = new BufferedReader(new FileReader(file))) {
final String jsonAsString = buffer.lines().collect(Collectors.joining(AmplificationHelper.LINE_SEPARATOR));
assertTrue(jsonAsString.startsWith(expectedFirstProjectJSON[0]));
assertTrue(jsonAsString.endsWith(expectedFirstProjectJSON[1]));
}
dspot.amplifyTest("fr.inria.mutation.ClassUnderTestTest");
dspot.amplifyTestClass("fr.inria.mutation.ClassUnderTestTest");
try (BufferedReader buffer = new BufferedReader(new FileReader(file))) {
final String jsonAsString = buffer.lines().collect(Collectors.joining(AmplificationHelper.LINE_SEPARATOR));
assertTrue(jsonAsString.startsWith(expectedFirstProjectJSON[0]));
assertTrue(jsonAsString.contains(expectedFirstProjectJSON[2]));
assertTrue(jsonAsString.endsWith(expectedFirstProjectJSON[3]));
}

dspot.amplifyTest("fr.inria.amp.TestJavaPoet");
dspot.amplifyTestClass("fr.inria.amp.TestJavaPoet");
try (BufferedReader buffer = new BufferedReader(new FileReader(file))) {
final String jsonAsString = buffer.lines().collect(Collectors.joining(AmplificationHelper.LINE_SEPARATOR));
assertTrue(jsonAsString.startsWith(expectedFirstProjectJSON[0]));
Expand Down
Loading

0 comments on commit db7b5ff

Please sign in to comment.