diff --git a/.gitignore b/.gitignore index cbd819f58..1d7877301 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,4 @@ gradle-app.setting # JDT-specific (Eclipse Java Development Tools) .classpath +.vscode/settings.json diff --git a/code-transformation/build.gradle b/code-transformation/build.gradle index c5dcbbf78..2269cd478 100644 --- a/code-transformation/build.gradle +++ b/code-transformation/build.gradle @@ -31,6 +31,8 @@ dependencies { implementation 'com.google.flogger:flogger:0.7.4' implementation 'com.google.flogger:flogger-system-backend:0.7.4' implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.3.0-alpha12' + testImplementation "com.google.truth:truth:1.1.3" + } application { diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/TransformationEngine.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/TransformationEngine.java index b2e9475a3..ca00a99f6 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/TransformationEngine.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/TransformationEngine.java @@ -33,11 +33,8 @@ public class TransformationEngine { private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); - private TransformationEngine() { - } - - public static Changelog applyToGivenPath(String path) { + public Changelog applyToGivenPath(String path) { LOGGER.atInfo().log("Applying transformations to %s", path); Launcher launcher = new Launcher(); Environment environment = setEnvironmentOptions(launcher); @@ -56,14 +53,14 @@ public static Changelog applyToGivenPath(String path) { return listener.getChangelog(); } - private static void addProcessors(ProcessingManager pm, ChangeListener listener) { + protected void addProcessors(ProcessingManager pm, ChangeListener listener) { pm.addProcessor(new AssertThatTransformation(listener)); pm.addProcessor(new TestAnnotation(listener)); pm.addProcessor(new ExpectedExceptionRemoval(listener)); pm.addProcessor(new AssertionsTransformation(listener)); } - public static Changelog applyToGivenPath(String path, String typeName) { + public Changelog applyToGivenPath(String path, String typeName) { LOGGER.atInfo().log("Applying transformations to %s", path); Launcher launcher = new Launcher(); Environment environment = setEnvironmentOptions(launcher); diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/github/CommitBuilder.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/github/CommitBuilder.java index e05dd9790..ee77524bb 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/github/CommitBuilder.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/github/CommitBuilder.java @@ -28,8 +28,11 @@ public static void refactorRepo(String path, String sourceFiles, String file, git.checkout().setName(config.getGitDefaultBranchName()).call(); git.checkout().setForced(true).setCreateBranch(true).setName(config.getGitBranchPrefix() + file).call(); Changelog changelog = transformation.apply(sourceFiles, file); - git.commit().setAll(true).setAuthor(config.getGitAuthor(), config.getGitEmail()).setMessage( - "refactor(" + file + "): \n " + getRelevantChangeLog(file, changelog)).call(); + git.commit() + .setAll(true) + .setAuthor(config.getGitAuthor(), config.getGitEmail()) + .setMessage("refactor(" + file + "): \n " + getRelevantChangeLog(file, changelog)) + .call(); git.close(); } catch (IOException | GitAPIException e) { diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/spoon/ImportCleaner.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/spoon/ImportCleaner.java index e39d88036..2593e067f 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/spoon/ImportCleaner.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/spoon/ImportCleaner.java @@ -156,8 +156,10 @@ public class Context { if (pckg != null) { this.packageQName = pckg.getReference().getQualifiedName(); } - this.typeRefQNames = cu.getDeclaredTypeReferences().stream().map(CtTypeReference::getQualifiedName).collect( - Collectors.toSet()); + this.typeRefQNames = cu.getDeclaredTypeReferences() + .stream() + .map(CtTypeReference::getQualifiedName) + .collect(Collectors.toSet()); computedImports = new HashMap<>(); } @@ -229,8 +231,10 @@ else if (ref instanceof CtTypeReference) { } private boolean isReferencePresentInImports(CtReference ref) { - return compilationUnit.getImports().stream().anyMatch(ctImport -> ctImport.getReference() != null - && isEqualAfterSkippingRole(ctImport.getReference(), ref, CtRole.TYPE_ARGUMENT)); + return compilationUnit.getImports() + .stream() + .anyMatch(ctImport -> ctImport.getReference() != null + && isEqualAfterSkippingRole(ctImport.getReference(), ref, CtRole.TYPE_ARGUMENT)); } /** diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/ImportHelper.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/ImportHelper.java index a326c057d..b481b8cdb 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/ImportHelper.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/ImportHelper.java @@ -1,10 +1,12 @@ package xyz.keksdose.spoon.code_solver.transformations; +import java.util.ArrayList; import java.util.List; import spoon.experimental.CtUnresolvedImport; import spoon.reflect.declaration.CtCompilationUnit; import spoon.reflect.declaration.CtImport; +import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.CtAbstractImportVisitor; public class ImportHelper { @@ -25,6 +27,22 @@ public static void addImport(String importString, boolean isStatic, CtCompilatio public static void removeImport(String importString, boolean isStatic, CtCompilationUnit unit) { List imports = unit.getImports(); + List removalableImports = new ArrayList<>(); + for (CtImport ctImport : imports) { + if (ctImport.getReference() instanceof CtTypeReference) { + CtTypeReference typeReference = (CtTypeReference) ctImport.getReference(); + if (typeReference.getQualifiedName().equals(importString)) { + removalableImports.add(ctImport); + } + } + } + removalableImports.forEach(imports::remove); + removalableImports.forEach(CtImport::delete); + imports.clear(); + unit.setImports(imports); + ImportVisitor visitor = new ImportVisitor(importString); + imports.forEach(i -> i.accept(visitor)); + imports.remove(visitor.getResult()); imports.remove(createImport(importString, isStatic, unit)); } @@ -51,7 +69,7 @@ public ImportVisitor(String importString) { } private String importString; - private CtUnresolvedImport result; + private CtImport result; // all junit imports are unresolved imports @Override @@ -61,7 +79,7 @@ public void visitUnresolvedImport(CtUnresolvedImport unresolvedImport) { } } - public CtUnresolvedImport getResult() { + public CtImport getResult() { return result; } } diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertionsTransformation.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertionsTransformation.java index ce64a2da7..1f5fd92d2 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertionsTransformation.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/AssertionsTransformation.java @@ -24,40 +24,46 @@ public AssertionsTransformation(ChangeListener listener) { @Override public void process(CtMethod method) { if (JunitHelper.isJunit5TestMethod(method)) { - var junit4Asserts = method.getElements(new TypeFilter<>(CtInvocation.class)).stream().filter( - v -> v.getTarget() != null).filter(v -> v.getTarget().getType() != null).filter( - v -> CtTypeAccess.class.isInstance(v.getTarget())).filter( - v -> ((CtTypeAccess) v.getTarget()).getAccessedType() != null).filter( - v -> ((CtTypeAccess) v.getTarget()).getAccessedType().getQualifiedName().equals( - "org.junit.Assert")).toList(); + var junit4Asserts = method.getElements(new TypeFilter<>(CtInvocation.class)) + .stream() + .filter(v -> v.getTarget() != null) + .filter(v -> v.getTarget().getType() != null) + .filter(v -> CtTypeAccess.class.isInstance(v.getTarget())) + .filter(v -> ((CtTypeAccess) v.getTarget()).getAccessedType() != null) + .filter(v -> ((CtTypeAccess) v.getTarget()).getAccessedType() + .getQualifiedName() + .equals("org.junit.Assert")) + .toList(); if (!junit4Asserts.isEmpty()) { - junit4Asserts.forEach(v -> v.getExecutable().setDeclaringType( - getFactory().Type().createReference("org.junit.jupiter.api.Assertions"))); - CtTypeAccess access = getFactory().createTypeAccess( - getFactory().Type().createReference("org.junit.jupiter.api.Assertions")); + junit4Asserts.forEach(v -> v.getExecutable() + .setDeclaringType(getFactory().Type().createReference("org.junit.jupiter.api.Assertions"))); + CtTypeAccess access = getFactory() + .createTypeAccess(getFactory().Type().createReference("org.junit.jupiter.api.Assertions")); for (CtInvocation junit4Assert : junit4Asserts) { junit4Assert.setTarget(null); } List imports = new ArrayList<>(); List newImports = new ArrayList<>(); - method.getPosition().getCompilationUnit().getImports().forEach( - v -> v.accept(new CtAbstractImportVisitor() { + method.getPosition() + .getCompilationUnit() + .getImports() + .forEach(v -> v.accept(new CtAbstractImportVisitor() { - @Override - public void visitUnresolvedImport(CtUnresolvedImport ctUnresolvedImport) { - if (ctUnresolvedImport.getUnresolvedReference().startsWith("org.junit.Assert.")) { - imports.add(ctUnresolvedImport); - newImports.add(getFactory().createUnresolvedImport( - ctUnresolvedImport.getUnresolvedReference().replace("org.junit.Assert.", - "org.junit.jupiter.api.Assertions."), - true)); + @Override + public void visitUnresolvedImport(CtUnresolvedImport ctUnresolvedImport) { + if (ctUnresolvedImport.getUnresolvedReference().startsWith("org.junit.Assert.")) { + imports.add(ctUnresolvedImport); + newImports.add(getFactory().createUnresolvedImport( + ctUnresolvedImport.getUnresolvedReference() + .replace("org.junit.Assert.", "org.junit.jupiter.api.Assertions."), + true)); + } } - } - })); + })); imports.forEach(CtElement::delete); - newImports.stream().filter( - v -> !method.getPosition().getCompilationUnit().getImports().contains(v)).forEach( - method.getPosition().getCompilationUnit().getImports()::add); + newImports.stream() + .filter(v -> !method.getPosition().getCompilationUnit().getImports().contains(v)) + .forEach(method.getPosition().getCompilationUnit().getImports()::add); setChanged(method.getDeclaringType(), new Change( diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/ExpectedExceptionRemoval.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/ExpectedExceptionRemoval.java index 0c964cfe9..93130fed7 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/ExpectedExceptionRemoval.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/ExpectedExceptionRemoval.java @@ -51,18 +51,23 @@ public void process(CtMethod method) { } private void removeExpectedValue(Optional> testAnnotation) { - testAnnotation.get().setValues( - testAnnotation.get().getValues().entrySet().stream().filter(v -> !v.getKey().equals("expected")).collect( - Collectors.toMap(Entry::getKey, Entry::getValue))); + testAnnotation.get() + .setValues(testAnnotation.get() + .getValues() + .entrySet() + .stream() + .filter(v -> !v.getKey().equals("expected")) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue))); } private CtInvocation createAssertThrows(CtExpression exceptionClass, CtStatement body) { CtTypeReference typeRef = getFactory().Type().createReference("org.junit.jupiter.api.Assertions"); CtTypeReference clazzRef = getFactory().Type().createReference("java.lang.Class"); - CtTypeReference executableJunit = getFactory().Type().createReference( - "org.junit.jupiter.api.function.Executable"); - CtExecutableReference assertThrows = getFactory().Executable().createReference(typeRef, - getFactory().Type().voidType(), "assertThrows", List.of(clazzRef, executableJunit)); + CtTypeReference executableJunit = getFactory().Type() + .createReference("org.junit.jupiter.api.function.Executable"); + CtExecutableReference assertThrows = getFactory().Executable() + .createReference(typeRef, getFactory().Type().voidType(), "assertThrows", + List.of(clazzRef, executableJunit)); CtLambda lambda = getFactory().createLambda(); lambda.setType((CtTypeReference) getFactory().Type().voidType()); lambda.setBody(body); diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/TestAnnotation.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/TestAnnotation.java index efa2a70a7..9b5e60912 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/TestAnnotation.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/junit/TestAnnotation.java @@ -24,8 +24,10 @@ public void process(CtAnnotation annotation) { CtElement element = annotation.getAnnotatedElement(); refactorTimeoutAnnotation(annotation, element); adjustImports(annotation, element); + annotation.setType(getFactory().createReference("org.junit.jupiter.api.Test")); annotation.setAnnotationType(getFactory().createReference("org.junit.jupiter.api.Test")); CtType type = annotation.getParent(CtType.class); + type.getReferencedTypes(); setChanged(type, new Change( String.format("Replaced junit 4 test annotation with junit 5 test annotation in %s", diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/qodana/CollectionEmptyCheck.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/qodana/CollectionEmptyCheck.java index fbd803743..d51b9db53 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/qodana/CollectionEmptyCheck.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/qodana/CollectionEmptyCheck.java @@ -31,15 +31,17 @@ public boolean isApplicable(CtBinaryOperator element) { private boolean leftHandIsSizeCheck(CtBinaryOperator element) { CtExpression leftHand = element.getLeftHandOperand(); List> innvocation = leftHand.getElements(new TypeFilter<>(CtInvocation.class)); - innvocation.stream().filter( - outer -> innvocation.stream().anyMatch(inner -> outer.hasParent(inner))).toList().forEach( - innvocation::remove); + innvocation.stream() + .filter(outer -> innvocation.stream().anyMatch(inner -> outer.hasParent(inner))) + .toList() + .forEach(innvocation::remove); if (innvocation.isEmpty()) { return false; } CtInvocation invocation = innvocation.get(innvocation.size() - 1); - if (invocation.getTarget() != null && invocation.getTarget().getType().isSubtypeOf( - getFactory().Type().createReference(Collection.class))) { + if (invocation.getTarget() != null && invocation.getTarget() + .getType() + .isSubtypeOf(getFactory().Type().createReference(Collection.class))) { if (invocation.getExecutable().getSimpleName().equals("size")) { if (invocation.getArguments().isEmpty()) { return true; @@ -57,9 +59,9 @@ public void process(CtBinaryOperator element) { ref.setDeclaringType(getFactory().createCtTypeReference(Collection.class)); setChanged(element.getParent(CtType.class), new Change("EmptyCollectionCheck", "EmptyCollectionCheck", element.getParent(CtType.class))); - CtInvocation innvocation = getFactory().Code().createInvocation( - element.getElements(new TypeFilter<>(CtInvocation.class)).get(0).getTarget(), ref, - new ArrayList>()); + CtInvocation innvocation = getFactory().Code() + .createInvocation(element.getElements(new TypeFilter<>(CtInvocation.class)).get(0).getTarget(), ref, + new ArrayList>()); element.replace(innvocation); } } diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/MissingOverride.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/MissingOverride.java index 7d8464ec0..8f50767e6 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/MissingOverride.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/MissingOverride.java @@ -21,10 +21,12 @@ public MissingOverride(ChangeListener listener) { public void process(CtMethod element) { if (element.getTopDefinitions().size() == 1) { if (element.getAnnotations().stream().noneMatch(v -> v.getName().equals("Override"))) { - if (element.getTopDefinitions().stream().filter(v -> v.getBody() != null).anyMatch( - v -> !v.getBody().getStatements().isEmpty() || !v.isAbstract())) { - CtAnnotation overrideAnnotation = getFactory().createAnnotation( - getFactory().Type().createReference(Override.class)); + if (element.getTopDefinitions() + .stream() + .filter(v -> v.getBody() != null) + .anyMatch(v -> !v.getBody().getStatements().isEmpty() || !v.isAbstract())) { + CtAnnotation overrideAnnotation = getFactory() + .createAnnotation(getFactory().Type().createReference(Override.class)); overrideAnnotation.setComments(element.getComments()); overrideAnnotation.setDocComment(element.getDocComment()); element.setComments(List.of()); diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/RedundantInterface.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/RedundantInterface.java index 51bd83dab..530cc494f 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/RedundantInterface.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/transformations/self/RedundantInterface.java @@ -21,9 +21,9 @@ public void process(CtType element) { return; } Set> superClass = element.getSuperInterfaces(); - superClass.stream().filter( - intrface -> superClass.stream().filter(inner -> inner.isSubtypeOf(intrface)).count() > 1).forEach( - intrface -> { + superClass.stream() + .filter(intrface -> superClass.stream().filter(inner -> inner.isSubtypeOf(intrface)).count() > 1) + .forEach(intrface -> { element.removeSuperInterface(intrface); setChanged(element, new Change( diff --git a/code-transformation/src/main/resources/formatter-settings.xml b/code-transformation/src/main/resources/formatter-settings.xml index 1f0d038f1..4a8faf6a7 100644 --- a/code-transformation/src/main/resources/formatter-settings.xml +++ b/code-transformation/src/main/resources/formatter-settings.xml @@ -161,7 +161,7 @@ - + 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 new file mode 100644 index 000000000..a49a7b939 --- /dev/null +++ b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/JunitTests.java @@ -0,0 +1,31 @@ + +package xyz.keksdose.spoon.code_solver; + +import static com.google.common.truth.Truth.assertThat; +import static xyz.keksdose.spoon.code_solver.TestHelper.createProcessorSupplier; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import xyz.keksdose.spoon.code_solver.transformations.junit.TestAnnotation; + +class JunitTests { + + @Test + void replaceJunit4WithJunit5TestAnnotation(@TempDir File tempRoot) throws IOException { + String fileName = "TestAnnotation.java"; + String resourcePath = "projects/junittests/TestAnnotation.java"; + File copy = TestHelper.createCopy(tempRoot, resourcePath, fileName); + List transformations = createProcessorSupplier(v -> new TestAnnotation(v)); + new TransformationHelper.Builder().path(tempRoot.getAbsolutePath()) + .className("TestAnnotation") + .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;"); + } +} diff --git a/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TestHelper.java b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TestHelper.java new file mode 100644 index 000000000..896c0efb6 --- /dev/null +++ b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TestHelper.java @@ -0,0 +1,40 @@ + +package xyz.keksdose.spoon.code_solver; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import com.google.common.io.Files; +import xyz.keksdose.spoon.code_solver.history.ChangeListener; +import xyz.keksdose.spoon.code_solver.transformations.TransformationProcessor; + +public class TestHelper { + + public static void copyFile(File source, File target) throws IOException { + Files.copy(source, target); + } + + public static File getResouces(Path path) { + return Path.of("src/test/resources/").resolve(path).toFile(); + } + + public static File createCopy(File root, String resourcePath, String filename) throws IOException { + File copy = new File(root, "filename"); + File source = TestHelper.getResouces(Path.of(resourcePath)); + TestHelper.copyFile(source, copy); + return copy; + } + + @SafeVarargs + public static List createProcessorSupplier(TransformationCreator... processors) { + List transformations = new ArrayList<>(); + for (TransformationCreator processor : processors) { + transformations.add(v -> processor.apply(v)); + } + return transformations; + } +} diff --git a/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TransformationCreator.java b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TransformationCreator.java new file mode 100644 index 000000000..8c3b643a0 --- /dev/null +++ b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TransformationCreator.java @@ -0,0 +1,10 @@ + +package xyz.keksdose.spoon.code_solver; + +import java.util.function.Function; +import xyz.keksdose.spoon.code_solver.history.ChangeListener; +import xyz.keksdose.spoon.code_solver.transformations.TransformationProcessor; + +public interface TransformationCreator extends Function> { + +} diff --git a/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TransformationHelper.java b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TransformationHelper.java new file mode 100644 index 000000000..dfb5d1be4 --- /dev/null +++ b/code-transformation/src/test/java/xyz/keksdose/spoon/code_solver/TransformationHelper.java @@ -0,0 +1,54 @@ + +package xyz.keksdose.spoon.code_solver; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import spoon.processing.ProcessingManager; +import xyz.keksdose.spoon.code_solver.history.ChangeListener; +import xyz.keksdose.spoon.code_solver.transformations.TransformationProcessor; + +public class TransformationHelper { + + static class Builder { + private String path; + private String className; + private Iterable processors; + + public Builder path(String path) { + this.path = path; + return this; + } + + public Builder className(String className) { + this.className = className; + return this; + } + + public Builder processors(Iterable processors) { + this.processors = processors; + return this; + } + + public void apply() { + new TestTransformationEngine().applyWithGivenProcessors(path, className, processors); + } + } + + private static class TestTransformationEngine extends TransformationEngine { + + private List currentProcessors = new ArrayList<>(); + + public void applyWithGivenProcessors(String path, String className, + Iterable processors) { + currentProcessors.clear(); + processors.forEach(currentProcessors::add); + applyToGivenPath(path, className); + } + + @Override + protected void addProcessors(ProcessingManager pm, ChangeListener listener) { + currentProcessors.stream().map(v -> v.apply(listener)).forEach(pm::addProcessor); + } + } +} diff --git a/code-transformation/src/test/resources/projects/junittests/TestAnnotation.java b/code-transformation/src/test/resources/projects/junittests/TestAnnotation.java new file mode 100644 index 000000000..50e0e18ef --- /dev/null +++ b/code-transformation/src/test/resources/projects/junittests/TestAnnotation.java @@ -0,0 +1,13 @@ +package projects.junittests; + +import java.util.ArrayList; +import static org.junit.Assertions.assertSame; +import org.junit.Test; + +public class TestAnnotation { + + @Test + public void testAnnotation() { + assertSame(new ArrayList<>(), 1); + } +}