From f19b116c04e746a9e167470a00975495c29f1f33 Mon Sep 17 00:00:00 2001 From: MartinWitt Date: Wed, 5 Jan 2022 17:08:18 +0100 Subject: [PATCH] feat(*): add replacement for assertTrue and equals check with assertEquals (#23) --- .../junit/AssertTrueEqualsCheck.java | 87 +++++++++++++++++++ .../spoon/code_solver/JunitTests.java | 23 ++++- .../projects/junittests/AssertTrueEquals.java | 14 +++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertTrueEqualsCheck.java create mode 100644 code-transformation/src/test/resources/projects/junittests/AssertTrueEquals.java diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertTrueEqualsCheck.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertTrueEqualsCheck.java new file mode 100644 index 000000000..452943374 --- /dev/null +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertTrueEqualsCheck.java @@ -0,0 +1,87 @@ + +package xyz.keksdose.spoon.code_solver.transformations.junit; + +import java.util.List; + +import spoon.reflect.code.BinaryOperatorKind; +import spoon.reflect.code.CtBinaryOperator; +import spoon.reflect.code.CtExpression; +import spoon.reflect.code.CtInvocation; +import spoon.reflect.declaration.CtCompilationUnit; +import spoon.reflect.declaration.CtType; +import spoon.reflect.reference.CtExecutableReference; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.filter.TypeFilter; +import xyz.keksdose.spoon.code_solver.history.Change; +import xyz.keksdose.spoon.code_solver.history.ChangeListener; +import xyz.keksdose.spoon.code_solver.transformations.ImportHelper; +import xyz.keksdose.spoon.code_solver.transformations.TransformationProcessor; + +public class AssertTrueEqualsCheck extends TransformationProcessor> { + + public AssertTrueEqualsCheck(ChangeListener listener) { + super(listener); + } + + @Override + public void process(CtInvocation invocation) { + if (invocation.getExecutable() != null && JunitHelper.isJunit5AssertTrue(invocation.getExecutable())) { + CtInvocation junit5AssertTrue = invocation; + CtExpression expression = invocation.getArguments().iterator().next(); + if (expression instanceof CtInvocation) { + CtInvocation equalsInvocation = (CtInvocation) expression; + if (equalsInvocation.getExecutable().getSimpleName().equals("equals")) { + CtExpression firstArgument = equalsInvocation.getTarget(); + CtExpression secondArgument = equalsInvocation.getArguments().iterator().next(); + CtInvocation junit5AssertEquals = createJunit5AssertEquals(firstArgument, secondArgument); + junit5AssertEquals.setComments(invocation.getComments()); + junit5AssertTrue.replace(junit5AssertEquals); + if (invocation.getArguments().size() == 2) { + // readd the String if it fails argument + junit5AssertEquals.addArgument(invocation.getArguments().get(1)); + } + adjustImports(invocation); + notifyChangeListener(invocation, junit5AssertTrue); + } + } + } + } + + private void adjustImports(CtInvocation element) { + CtType parent = element.getParent(CtType.class); + CtCompilationUnit compilationUnit = element.getPosition().getCompilationUnit(); + + if (parent != null && !hasJunit5AsserTrueLeft(parent)) { + ImportHelper.removeImport("org.junit.jupiter.api.Assertions.assertTrue", true, compilationUnit); + } + ImportHelper.addImport("org.junit.jupiter.api.Assertions.assertEquals", true, compilationUnit); + + } + + private boolean hasJunit5AsserTrueLeft(CtType parent) { + return parent.getElements(new TypeFilter<>(CtInvocation.class)) + .stream() + .filter(v -> v.getExecutable() != null) + .anyMatch(v -> JunitHelper.isJunit5AssertTrue(v.getExecutable())); + } + + private boolean isNullType(CtExpression left) { + return left.getType() != null && left.getType().equals(getFactory().Type().nullType()); + } + + private CtInvocation createJunit5AssertEquals(CtExpression firstArgument, CtExpression secondArgument) { + CtTypeReference typeRef = getFactory().Type().createReference("org.junit.jupiter.api.Assertions"); + CtTypeReference voidType = getFactory().Type().voidPrimitiveType(); + CtTypeReference objectType = getFactory().Type().objectType(); + CtExecutableReference assertEquals = getFactory().Executable() + .createReference(typeRef, voidType, "assertEquals", List.of(objectType, objectType)); + return getFactory().createInvocation(null, assertEquals, List.of(firstArgument, secondArgument)); + } + + private void notifyChangeListener(CtInvocation oldAssert, CtInvocation newAssert) { + CtType parent = newAssert.getParent(CtType.class); + setChanged(parent, new Change(String.format("Replaced %s with %s", oldAssert, newAssert), + "AssertTrue with equals instead of AssertEquals", parent)); + } + +} diff --git a/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/JunitTests.java b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/JunitTests.java index 7e64d1608..3538edcc5 100644 --- a/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/JunitTests.java +++ b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/JunitTests.java @@ -15,6 +15,7 @@ import xyz.keksdose.spoon.code_solver.transformations.junit.AssertNotNullTransformation; import xyz.keksdose.spoon.code_solver.transformations.junit.AssertNullTransformation; +import xyz.keksdose.spoon.code_solver.transformations.junit.AssertTrueEqualsCheck; import xyz.keksdose.spoon.code_solver.transformations.junit.AssertionsTransformation; import xyz.keksdose.spoon.code_solver.transformations.junit.TestAnnotation; @@ -118,7 +119,8 @@ void replaceAssertTrueNullCheck(@TempDir File tempRoot) throws IOException { String resourcePath = "projects/junittests/AssertNotNull.java"; File copy = TestHelper.createCopy(tempRoot, resourcePath, fileName); List transformations = createProcessorSupplier(v -> new TestAnnotation(v), - v -> new AssertionsTransformation(v), v -> new AssertNullTransformation(v)); + v -> new AssertionsTransformation(v), v -> new AssertNullTransformation(v), + v -> new AssertNotNullTransformation(v)); new TransformationHelper.Builder().path(tempRoot.getAbsolutePath()) .className("AssertNotNull") .processors(transformations) @@ -130,4 +132,23 @@ void replaceAssertTrueNullCheck(@TempDir File tempRoot) throws IOException { assertThat(result).doesNotContain("import org.junit.Assert."); assertThat(result).doesNotContain("== null"); } + + @Test + void replaceAssertTrueEqualsCheck(@TempDir File tempRoot) throws IOException { + String fileName = "AssertTrueEquals.java"; + String resourcePath = "projects/junittests/AssertTrueEquals.java"; + File copy = TestHelper.createCopy(tempRoot, resourcePath, fileName); + List transformations = createProcessorSupplier(v -> new TestAnnotation(v), + v -> new AssertionsTransformation(v), v -> new AssertTrueEqualsCheck(v)); + new TransformationHelper.Builder().path(tempRoot.getAbsolutePath()) + .className("AssertTrueEquals") + .processors(transformations) + .apply(); + String result = Files.readString(copy.toPath()); + assertThat(result).contains("@Test"); + assertThat(result).contains("import org.junit.jupiter.api.Test;"); + assertThat(result).doesNotContain("import org.junit.Test;"); + assertThat(result).doesNotContain("import org.junit.Assert."); + assertThat(result).contains("assertEquals"); + } } diff --git a/code-transformation/src/test/resources/projects/junittests/AssertTrueEquals.java b/code-transformation/src/test/resources/projects/junittests/AssertTrueEquals.java new file mode 100644 index 000000000..df6a76ae7 --- /dev/null +++ b/code-transformation/src/test/resources/projects/junittests/AssertTrueEquals.java @@ -0,0 +1,14 @@ +package projects.junittests; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class AssertTrueEquals { + + @Test + public void test() { + assertTrue(Integer.valueOf("3").equals(3)); + assertTrue(Integer.valueOf("3").equals(3), "aaaa"); + } +}