diff --git a/src/main/java/fr/inria/diversify/dspot/amp/AmplifierChecker.java b/src/main/java/fr/inria/diversify/dspot/amp/AmplifierChecker.java index 811918e5f..ad5b7d6d6 100644 --- a/src/main/java/fr/inria/diversify/dspot/amp/AmplifierChecker.java +++ b/src/main/java/fr/inria/diversify/dspot/amp/AmplifierChecker.java @@ -1,9 +1,6 @@ package fr.inria.diversify.dspot.amp; -import spoon.reflect.code.CtCase; -import spoon.reflect.code.CtInvocation; -import spoon.reflect.code.CtLiteral; -import spoon.reflect.code.CtStatement; +import spoon.reflect.code.*; /** * Created by Benjamin DANGLOT @@ -37,4 +34,8 @@ private static boolean isAssertInstance(Class cl) { Class superCl = cl.getSuperclass(); return superCl != null && isAssertInstance(superCl); } + + public static boolean canBeAdded(CtInvocation invocation) { + return !invocation.toString().startsWith("super(") && invocation.getParent() instanceof CtBlock; + } } diff --git a/src/main/java/fr/inria/diversify/dspot/amp/AmplifierHelper.java b/src/main/java/fr/inria/diversify/dspot/amp/AmplifierHelper.java index b6bd848f5..1e42ee062 100644 --- a/src/main/java/fr/inria/diversify/dspot/amp/AmplifierHelper.java +++ b/src/main/java/fr/inria/diversify/dspot/amp/AmplifierHelper.java @@ -33,7 +33,7 @@ public static Random getRandom() { return random; } - static void reset() { + public static void reset() { cloneNumber = 1; ampTestToParent = new HashMap<>(); } diff --git a/src/main/java/fr/inria/diversify/dspot/amp/TestMethodCallAdder.java b/src/main/java/fr/inria/diversify/dspot/amp/TestMethodCallAdder.java index 8957c826e..57fe818e3 100644 --- a/src/main/java/fr/inria/diversify/dspot/amp/TestMethodCallAdder.java +++ b/src/main/java/fr/inria/diversify/dspot/amp/TestMethodCallAdder.java @@ -1,7 +1,6 @@ package fr.inria.diversify.dspot.amp; import fr.inria.diversify.log.branch.Coverage; -import spoon.reflect.code.CtBlock; import spoon.reflect.code.CtInvocation; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtType; @@ -12,6 +11,7 @@ import java.util.List; + public class TestMethodCallAdder implements Amplifier { public List apply(CtMethod method) { @@ -24,10 +24,11 @@ public List apply(CtMethod method) { int invocation_index = 0; for (CtInvocation invocation : invocations) { try { - if (toAdd(invocation) && !AmplifierChecker.isAssert(invocation)) { + if (AmplifierChecker.canBeAdded(invocation) && !AmplifierChecker.isAssert(invocation)) { methods.add(apply(method, invocation_index)); } } catch (Exception e) { + throw new RuntimeException(e); } invocation_index++; } @@ -38,12 +39,12 @@ public List apply(CtMethod method) { public CtMethod applyRandom(CtMethod method) { if (method.getDeclaringType() != null) { List invocations = Query.getElements(method, new TypeFilter(CtInvocation.class)); - while (!invocations.isEmpty()) { try { int invocation_index = AmplifierHelper.getRandom().nextInt(invocations.size()); return apply(method, invocation_index); - } catch (Exception e) { + } catch (Exception ignored) { + } } } @@ -55,7 +56,7 @@ public void reset(Coverage coverage, CtType testClass) { AmplifierHelper.reset(); } - protected CtMethod apply(CtMethod method, int invocation_index) { + private CtMethod apply(CtMethod method, int invocation_index) { CtMethod cloned_method = AmplifierHelper.cloneMethodTest(method, "_add", 1000); //add the cloned method in the same class as the original method //get the lit_indexth literal of the cloned method @@ -67,8 +68,5 @@ protected CtMethod apply(CtMethod method, int invocation_index) { return cloned_method; } - public boolean toAdd(CtInvocation invocation) { - return !invocation.toString().startsWith("super(") - && invocation.getParent() instanceof CtBlock; - } + } \ No newline at end of file diff --git a/src/test/java/fr/inria/diversify/Utils.java b/src/test/java/fr/inria/diversify/Utils.java index 0f21e5efc..eb8bfc7aa 100644 --- a/src/test/java/fr/inria/diversify/Utils.java +++ b/src/test/java/fr/inria/diversify/Utils.java @@ -7,6 +7,7 @@ import fr.inria.diversify.runner.InputConfiguration; import fr.inria.diversify.runner.InputProgram; import fr.inria.diversify.util.InitUtils; +import spoon.Launcher; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtMethod; @@ -72,4 +73,13 @@ public static CtMethod findMethod(String className, String methodName) throws In .findFirst() .orElse(null); } + + public static Launcher buildSpoon() { + Launcher launcher = new Launcher(); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource("src/test/resources/mutation/ClassUnderTestTest.java"); + launcher.addInputResource("src/test/resources/mutation/ClassUnderTest.java"); + launcher.buildModel(); + return launcher; + } } diff --git a/src/test/java/fr/inria/diversify/dspot/amp/TestMethodCallAdderTest.java b/src/test/java/fr/inria/diversify/dspot/amp/TestMethodCallAdderTest.java new file mode 100644 index 000000000..d99a0518a --- /dev/null +++ b/src/test/java/fr/inria/diversify/dspot/amp/TestMethodCallAdderTest.java @@ -0,0 +1,90 @@ +package fr.inria.diversify.dspot.amp; + +import fr.inria.diversify.Utils; +import org.junit.Test; +import spoon.Launcher; +import spoon.reflect.code.CtStatement; +import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtMethod; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Benjamin DANGLOT + * benjamin.danglot@inria.fr + * on 12/7/16 + */ +public class TestMethodCallAdderTest { + + @Test + public void testMethodCallAddAll() throws Exception { + + /* + Test that we reuse method call in a test for each used method in the test. + 3 method are called in the original test, we produce 3 test methods. + */ + + Launcher launcher = Utils.buildSpoon(); + CtClass testClass = launcher.getFactory().Class().get("mutation.ClassUnderTestTest"); + + TestMethodCallAdder methodCallAdder = new TestMethodCallAdder(); + methodCallAdder.reset(null, null); + + final CtMethod originalMethod = testClass.getMethods().stream().filter(m -> "testAddCall".equals(m.getSimpleName())).findFirst().get(); + List amplifiedMethods = methodCallAdder.apply(originalMethod); + + assertEquals(3, amplifiedMethods.size()); + + for (int i = 0; i < amplifiedMethods.size(); i++) { + CtMethod amplifiedMethod = amplifiedMethods.get(i); + assertEquals(originalMethod.getBody().getStatements().size() + 1, amplifiedMethod.getBody().getStatements().size()); + CtStatement expectedStatement = originalMethod.getBody().getStatements().get(i + 1);//+1 to skip the construction statement. + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(i + 1)); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(i + 2)); + } + } + + @Test + public void testMethodCallAddRandom() throws Exception { + + /* + Test that we duplicate method call in a test for each used method in the test. + Here, we test the applyRandom feature that will build one method randomly by reusing an existing call. + */ + + AmplifierHelper.setSeedRandom(23L); + Launcher launcher = Utils.buildSpoon(); + CtClass testClass = launcher.getFactory().Class().get("mutation.ClassUnderTestTest"); + + TestMethodCallAdder methodCallAdder = new TestMethodCallAdder(); + methodCallAdder.reset(null, null); + + final CtMethod originalMethod = testClass.getMethods().stream().filter(m -> "testAddCall".equals(m.getSimpleName())).findFirst().get(); + CtMethod amplifiedMethod = methodCallAdder.applyRandom(originalMethod); + + assertEquals(originalMethod.getBody().getStatements().size() + 1, amplifiedMethod.getBody().getStatements().size()); + CtStatement expectedStatement = originalMethod.getBody().getStatements().get(2); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(2)); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(3)); + + + amplifiedMethod = methodCallAdder.applyRandom(originalMethod); + assertEquals(originalMethod.getBody().getStatements().size() + 1, amplifiedMethod.getBody().getStatements().size()); + expectedStatement = originalMethod.getBody().getStatements().get(3); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(3)); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(4)); + + amplifiedMethod = methodCallAdder.applyRandom(originalMethod); + assertEquals(originalMethod.getBody().getStatements().size() + 1, amplifiedMethod.getBody().getStatements().size()); + expectedStatement = originalMethod.getBody().getStatements().get(1); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(1)); + assertEquals(expectedStatement, amplifiedMethod.getBody().getStatements().get(2)); + + // stack random amplification + CtMethod stackedAmplifiedMethod = methodCallAdder.applyRandom(amplifiedMethod); + assertEquals(amplifiedMethod.getBody().getStatements().size() + 1, stackedAmplifiedMethod.getBody().getStatements().size()); + assertEquals(originalMethod.getBody().getStatements().size() + 2, stackedAmplifiedMethod.getBody().getStatements().size()); + } +} diff --git a/src/test/java/fr/inria/diversify/dspot/amp/TestMethodCallRemove.java b/src/test/java/fr/inria/diversify/dspot/amp/TestMethodCallRemove.java new file mode 100644 index 000000000..d9b8f7ec2 --- /dev/null +++ b/src/test/java/fr/inria/diversify/dspot/amp/TestMethodCallRemove.java @@ -0,0 +1,70 @@ +package fr.inria.diversify.dspot.amp; + +import fr.inria.diversify.Utils; +import org.junit.Test; +import spoon.Launcher; +import spoon.reflect.code.CtStatement; +import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtMethod; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +/** + * Created by Benjamin DANGLOT + * benjamin.danglot@inria.fr + * on 12/7/16 + */ +public class TestMethodCallRemove { + + @Test + public void testMethodCallRemoveAll() throws Exception { + + /* + Test that we remove method call in a test for each used method in the test. + 3 method are called in the original test, we produce 3 test methods. + */ + + Launcher launcher = Utils.buildSpoon(); + CtClass testClass = launcher.getFactory().Class().get("mutation.ClassUnderTestTest"); + + TestMethodCallRemover methodCallRemove = new TestMethodCallRemover(); + methodCallRemove.reset(null, null); + + final CtMethod originalMethod = testClass.getMethods().stream().filter(m -> "testAddCall".equals(m.getSimpleName())).findFirst().get(); + List amplifiedMethods = methodCallRemove.apply(originalMethod); + + assertEquals(3, amplifiedMethods.size()); + + for (int i = 0; i < amplifiedMethods.size(); i++) { + assertEquals(originalMethod.getBody().getStatements().size() - 1, amplifiedMethods.get(i).getBody().getStatements().size()); + assertNotEquals(amplifiedMethods.get((i+1) % amplifiedMethods.size()).getBody(), amplifiedMethods.get(i).getBody());//checks that all generated methods are different + } + } + + @Test + public void testMethodCallRemoveRnd() throws Exception { + + /* + Test that we remove method call in a test for each used method in the test. + 3 method are called in the original test, we produce 2 test methods randomly among them. + */ + + AmplifierHelper.setSeedRandom(23L); + Launcher launcher = Utils.buildSpoon(); + CtClass testClass = launcher.getFactory().Class().get("mutation.ClassUnderTestTest"); + + TestMethodCallRemover methodCallRemove = new TestMethodCallRemover(); + methodCallRemove.reset(null, null); + + final CtMethod originalMethod = testClass.getMethods().stream().filter(m -> "testAddCall".equals(m.getSimpleName())).findFirst().get(); + CtMethod amplifiedMethod = methodCallRemove.applyRandom(originalMethod); + CtMethod amplifiedMethod2 = methodCallRemove.applyRandom(originalMethod); + + assertEquals(originalMethod.getBody().getStatements().size() - 1, amplifiedMethod.getBody().getStatements().size()); + assertEquals(originalMethod.getBody().getStatements().size() - 1, amplifiedMethod2.getBody().getStatements().size()); + assertNotEquals(amplifiedMethod.getBody().getStatements(), amplifiedMethod2.getBody().getStatements()); + } +} diff --git a/src/test/java/fr/inria/diversify/dspot/amp/TestStatementAdderOnAssert.java b/src/test/java/fr/inria/diversify/dspot/amp/TestStatementAdderOnAssert.java index 1e9f32ed4..4c2236dd0 100644 --- a/src/test/java/fr/inria/diversify/dspot/amp/TestStatementAdderOnAssert.java +++ b/src/test/java/fr/inria/diversify/dspot/amp/TestStatementAdderOnAssert.java @@ -1,11 +1,11 @@ package fr.inria.diversify.dspot.amp; +import fr.inria.diversify.Utils; import org.junit.Test; import spoon.Launcher; import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtLocalVariable; import spoon.reflect.declaration.CtClass; -import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtMethod; import spoon.reflect.visitor.filter.TypeFilter; @@ -34,13 +34,13 @@ public void testStatementAdderOnAssertLiteral() throws Exception { */ AmplifierHelper.setSeedRandom(23L); - Launcher launcher = buildSpoon(); + Launcher launcher = Utils.buildSpoon(); CtClass ctClass = launcher.getFactory().Class().get("mutation.ClassUnderTestTest"); StatementAdderOnAssert amplificator = new StatementAdderOnAssert(); amplificator.reset(null, ctClass); - CtMethod originalMethod = ctClass.getElements(new TypeFilter<>(CtMethod.class)).get(0); + CtMethod originalMethod = ctClass.getElements(new TypeFilter<>(CtMethod.class)).stream().filter(m -> "testLit".equals(m.getSimpleName())).findFirst().get(); List amplifiedMethods = amplificator.apply(originalMethod); amplifiedMethods.forEach(method -> { @@ -76,12 +76,5 @@ public boolean matches(CtLocalVariable ctLocalVariable) { assertTrue(amplifiedMethods.get(8).getBody().getStatement(3) instanceof CtInvocation); } - private Launcher buildSpoon() { - Launcher launcher = new Launcher(); - launcher.getEnvironment().setNoClasspath(true); - launcher.addInputResource("src/test/resources/mutation/ClassUnderTestTest.java"); - launcher.addInputResource("src/test/resources/mutation/ClassUnderTest.java"); - launcher.buildModel(); - return launcher; - } + } diff --git a/src/test/resources/mutation/ClassUnderTest.java b/src/test/resources/mutation/ClassUnderTest.java index 772a539a0..9acb32681 100644 --- a/src/test/resources/mutation/ClassUnderTest.java +++ b/src/test/resources/mutation/ClassUnderTest.java @@ -10,7 +10,7 @@ public int plusOne(int integer) { return integer + 1; } - public int minueOne(int integer) { + public int minusOne(int integer) { return integer - 1; } diff --git a/src/test/resources/mutation/ClassUnderTestTest.java b/src/test/resources/mutation/ClassUnderTestTest.java index d342ddcbf..a7d8b17e6 100644 --- a/src/test/resources/mutation/ClassUnderTestTest.java +++ b/src/test/resources/mutation/ClassUnderTestTest.java @@ -11,6 +11,14 @@ public class ClassUnderTestTest { public void testLit() { ClassUnderTest underTest = new ClassUnderTest(); assertEquals(1, underTest.plusOne(0)); - assertEquals(0, underTest.minueOne(1)); + assertEquals(0, underTest.minusOne(1)); + } + + @Test + public void testAddCall() throws Exception { + ClassUnderTest underTest = new ClassUnderTest(); + underTest.plusOne(0); + underTest.minusOne(1); + underTest.timesTwo(1); } } \ No newline at end of file