diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..7a7ad4c70 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +insert_final_newline = true +trim_trailing_whitespace = true + +[src/test*/java/**.java] +indent_size = 4 +ij_continuation_indent_size = 2 diff --git a/build.gradle.kts b/build.gradle.kts index bce1547cf..55200b105 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,6 +19,7 @@ recipeDependencies { parserClasspath("com.github.tomakehurst:wiremock-jre8:2.35.0") parserClasspath("org.mockito:mockito-all:1.10.19") parserClasspath("org.mockito:mockito-core:3.+") + parserClasspath("org.mockito:mockito-core:5.+") parserClasspath("org.jmockit:jmockit:1.49") parserClasspath("org.jmockit:jmockit:1.22") // last version with NonStrictExpectations parserClasspath("org.mockito:mockito-junit-jupiter:3.+") @@ -26,6 +27,7 @@ recipeDependencies { parserClasspath("org.powermock:powermock-core:1.7.+") parserClasspath("com.squareup.okhttp3:mockwebserver:4.10.0") parserClasspath("org.springframework:spring-test:6.1.12") + parserClasspath("com.github.database-rider:rider-junit5:1.44.0") } val rewriteVersion = rewriteRecipe.rewriteVersion.get() @@ -48,12 +50,13 @@ dependencies { testImplementation("org.openrewrite:rewrite-java-17") testImplementation("org.openrewrite:rewrite-groovy") + testImplementation("org.openrewrite:rewrite-test") testImplementation("org.openrewrite:rewrite-kotlin:$rewriteVersion") testImplementation("org.openrewrite.gradle.tooling:model:$rewriteVersion") annotationProcessor("org.openrewrite:rewrite-templating:${rewriteVersion}") implementation("org.openrewrite:rewrite-templating:${rewriteVersion}") - compileOnly("com.google.errorprone:error_prone_core:2.19.1:with-dependencies") { + compileOnly("com.google.errorprone:error_prone_core:2.+:with-dependencies") { exclude("com.google.auto.service", "auto-service-annotations") } @@ -66,10 +69,9 @@ dependencies { testRuntimeOnly("net.datafaker:datafaker:latest.release") { exclude(group = "org.yaml", module = "snakeyaml") } + testRuntimeOnly("org.easymock:easymock:latest.release") + testRuntimeOnly("org.testng:testng:latest.release") testRuntimeOnly("org.mockito.kotlin:mockito-kotlin:latest.release") testRuntimeOnly("org.testcontainers:testcontainers:latest.release") testRuntimeOnly("org.testcontainers:nginx:latest.release") - -// testImplementation("org.hamcrest:hamcrest:latest.release") -// testImplementation("org.assertj:assertj-core:latest.release") } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cb4e5525f..2f2f53604 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionSha256Sum=1541fa36599e12857140465f3c91a97409b4512501c26f9631fb113e392c5bd1 +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 diff --git a/src/main/java/org/openrewrite/java/testing/assertj/AdoptAssertJDurationAssertions.java b/src/main/java/org/openrewrite/java/testing/assertj/AdoptAssertJDurationAssertions.java index ef26a84bd..b84ca6133 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/AdoptAssertJDurationAssertions.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/AdoptAssertJDurationAssertions.java @@ -32,17 +32,48 @@ import java.util.*; -public class AdoptAssertJDurationAssertions extends Recipe { - - static final String DURATION_ASSERT_HAS_LONG = "org.assertj.core.api.AbstractDurationAssert has*(long)"; +import static org.openrewrite.Preconditions.or; - static final String INTEGER_ASSERT_IS_EQUAL_TO = "org.assertj.core.api.AbstractIntegerAssert isEqualTo(..)"; - static final String INTEGER_ASSERT_IS_GREATER_THAN = "org.assertj.core.api.AbstractIntegerAssert isGreaterThan(..)"; - static final String INTEGER_ASSERT_IS_LESS_THAN = "org.assertj.core.api.AbstractIntegerAssert isLessThan(..)"; +public class AdoptAssertJDurationAssertions extends Recipe { - static final String LONG_ASSERT_IS_LESS_THAN = "org.assertj.core.api.AbstractLongAssert isLessThan(..)"; - static final String LONG_ASSERT_IS_GREATER_THAN = "org.assertj.core.api.AbstractLongAssert isGreaterThan(..)"; - static final String LONG_ASSERT_IS_EQUAL_TO = "org.assertj.core.api.AbstractLongAssert isEqualTo(..)"; + private static final String DURATION_ASSERT_HAS_LONG = "org.assertj.core.api.AbstractDurationAssert has*(long)"; + private static final String INTEGER_ASSERT_IS_EQUAL_TO = "org.assertj.core.api.AbstractIntegerAssert isEqualTo(..)"; + private static final String INTEGER_ASSERT_IS_GREATER_THAN = "org.assertj.core.api.AbstractIntegerAssert isGreaterThan(..)"; + private static final String INTEGER_ASSERT_IS_LESS_THAN = "org.assertj.core.api.AbstractIntegerAssert isLessThan(..)"; + private static final String LONG_ASSERT_IS_LESS_THAN = "org.assertj.core.api.AbstractLongAssert isLessThan(..)"; + private static final String LONG_ASSERT_IS_GREATER_THAN = "org.assertj.core.api.AbstractLongAssert isGreaterThan(..)"; + private static final String LONG_ASSERT_IS_EQUAL_TO = "org.assertj.core.api.AbstractLongAssert isEqualTo(..)"; + + private static final MethodMatcher ASSERT_THAT_MATCHER = new MethodMatcher("org.assertj.core.api.Assertions assertThat(..)"); + private static final MethodMatcher GET_NANO_MATCHER = new MethodMatcher("java.time.Duration getNano()"); + private static final MethodMatcher GET_SECONDS_MATCHER = new MethodMatcher("java.time.Duration getSeconds()"); + private static final MethodMatcher AS_MATCHER = new MethodMatcher("org.assertj.core.api.AbstractObjectAssert as(..)"); + private static final MethodMatcher TIME_UNIT_MATCHERS = new MethodMatcher(DURATION_ASSERT_HAS_LONG, true); + + private static final List IS_MATCHERS = Arrays.asList( + new MethodMatcher(INTEGER_ASSERT_IS_EQUAL_TO, true), + new MethodMatcher(INTEGER_ASSERT_IS_GREATER_THAN, true), + new MethodMatcher(INTEGER_ASSERT_IS_LESS_THAN, true), + + new MethodMatcher(LONG_ASSERT_IS_EQUAL_TO, true), + new MethodMatcher(LONG_ASSERT_IS_GREATER_THAN, true), + new MethodMatcher(LONG_ASSERT_IS_LESS_THAN, true) + ); + + private static final Map METHOD_MAP = new HashMap() {{ + put("getSeconds", "hasSeconds"); + put("getNano", "hasNanos"); + + put("hasNanos", "hasMillis"); + put("hasMillis", "hasSeconds"); + put("hasSeconds", "hasMinutes"); + put("hasMinutes", "hasHours"); + put("hasHours", "hasDays"); + + put("isGreaterThan", "isPositive"); + put("isLessThan", "isNegative"); + put("isEqualTo", "isZero"); + }}; @Override public String getDisplayName() { @@ -56,190 +87,156 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(Preconditions.or( + return Preconditions.check( + or( new UsesMethod<>(DURATION_ASSERT_HAS_LONG, true), - new UsesMethod<>(INTEGER_ASSERT_IS_EQUAL_TO, true), new UsesMethod<>(INTEGER_ASSERT_IS_GREATER_THAN, true), new UsesMethod<>(INTEGER_ASSERT_IS_LESS_THAN, true), - new UsesMethod<>(LONG_ASSERT_IS_EQUAL_TO, true), new UsesMethod<>(LONG_ASSERT_IS_GREATER_THAN, true), new UsesMethod<>(LONG_ASSERT_IS_LESS_THAN, true) - ), new AdoptAssertJDurationAssertionsVisitor() - ); - } - - @SuppressWarnings("DataFlowIssue") - private static class AdoptAssertJDurationAssertionsVisitor extends JavaIsoVisitor { - private static final MethodMatcher ASSERT_THAT_MATCHER = new MethodMatcher("org.assertj.core.api.Assertions assertThat(..)"); - private static final MethodMatcher GET_NANO_MATCHER = new MethodMatcher("java.time.Duration getNano()"); - private static final MethodMatcher GET_SECONDS_MATCHER = new MethodMatcher("java.time.Duration getSeconds()"); - private static final MethodMatcher AS_MATCHER = new MethodMatcher("org.assertj.core.api.AbstractObjectAssert as(..)"); - private static final MethodMatcher TIME_UNIT_MATCHERS = new MethodMatcher(DURATION_ASSERT_HAS_LONG, true); - private static final List IS_MATCHERS = Arrays.asList( - new MethodMatcher(INTEGER_ASSERT_IS_EQUAL_TO, true), - new MethodMatcher(INTEGER_ASSERT_IS_GREATER_THAN, true), - new MethodMatcher(INTEGER_ASSERT_IS_LESS_THAN, true), - - new MethodMatcher(LONG_ASSERT_IS_EQUAL_TO, true), - new MethodMatcher(LONG_ASSERT_IS_GREATER_THAN, true), - new MethodMatcher(LONG_ASSERT_IS_LESS_THAN, true) - ); - private static final Map METHOD_MAP = new HashMap() {{ - put("getSeconds", "hasSeconds"); - put("getNano", "hasNanos"); - - put("hasNanos", "hasMillis"); - put("hasMillis", "hasSeconds"); - put("hasSeconds", "hasMinutes"); - put("hasMinutes", "hasHours"); - put("hasHours", "hasDays"); - - put("isGreaterThan", "isPositive"); - put("isLessThan", "isNegative"); - put("isEqualTo", "isZero"); - }}; - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - if (TIME_UNIT_MATCHERS.matches(mi)) { - return simplifyTimeUnits(mi, ctx); - } else if (IS_MATCHERS.stream().anyMatch(matcher -> matcher.matches(mi))) { - return simplifyMultipleAssertions(mi, ctx); - } - return mi; - } - - private J.MethodInvocation simplifyMultipleAssertions(J.MethodInvocation m, ExecutionContext ctx) { - Expression isEqualToArg = m.getArguments().get(0); - Expression select = m.getSelect(); - List templateParameters = new ArrayList<>(); - templateParameters.add(null); - Expression asDescription = null; - - if (AS_MATCHER.matches(select)) { - asDescription = ((J.MethodInvocation) select).getArguments().get(0); - select = ((J.MethodInvocation) select).getSelect(); - templateParameters.add(asDescription); - } - - if (!ASSERT_THAT_MATCHER.matches(select)) { - return m; - } - - Expression assertThatArgumentExpr = ((J.MethodInvocation) select).getArguments().get(0); - if (!(assertThatArgumentExpr instanceof J.MethodInvocation)) { - return m; - } - J.MethodInvocation assertThatArg = (J.MethodInvocation) assertThatArgumentExpr; - - if (isZero(isEqualToArg) && checkIfRelatedToDuration(assertThatArg)) { - String formatted_template = formatTemplate("assertThat(#{any()}).%s();", m.getSimpleName(), asDescription); - templateParameters.set(0, assertThatArg); - return applyTemplate(ctx, m, formatted_template, templateParameters.toArray()); - } - - if (GET_NANO_MATCHER.matches(assertThatArg) || GET_SECONDS_MATCHER.matches(assertThatArg)) { - Expression assertThatArgSelect = assertThatArg.getSelect(); - String methodName = assertThatArg.getSimpleName(); - String formatted_template = formatTemplate("assertThat(#{any()}).%s(#{any()});", methodName, asDescription); - templateParameters.set(0, assertThatArgSelect); - templateParameters.add(isEqualToArg); - - return applyTemplate(ctx, m, formatted_template, templateParameters.toArray()); - } - - return m; - } - - private boolean isZero(Expression isEqualToArg) { - if (isEqualToArg instanceof J.Literal) { - J.Literal literal = (J.Literal) isEqualToArg; - return literal.getValue() instanceof Number && ((Number) literal.getValue()).longValue() == 0; - } - return false; - } - - private J.MethodInvocation simplifyTimeUnits(J.MethodInvocation m, ExecutionContext ctx) { - Expression arg = m.getArguments().get(0); - Long argValue = SimplifyDurationCreationUnits.getConstantIntegralValue(arg); - if (argValue == null) { - return m; - } - - List unitInfo = getUnitInfo(m.getSimpleName(), Math.toIntExact(argValue)); - String methodName = (String) unitInfo.get(0); - int methodArg = (int) unitInfo.get(1); - if (!(m.getSimpleName().equals(methodName))) { - // update method invocation with new name and arg - String template = String.format("#{any()}.%s(%d)", methodName, methodArg); - return applyTemplate(ctx, m, template, m.getSelect()); - } - - return m; - } - - private static List getUnitInfo(String name, int argValue) { - final int timeLength; - if (name.equals("hasSeconds") || name.equals("hasMinutes")) { - timeLength = 60; - } else if (name.equals("hasNanos") || name.equals("hasMillis")) { - timeLength = 1000; - } else if (name.equals("hasHours")) { - timeLength = 24; - } else { - return Arrays.asList(name, argValue); - } - - if (argValue % timeLength == 0) { - String newName = METHOD_MAP.get(name); - return getUnitInfo(newName, argValue / timeLength); - } else { - // returning name, newArg - return Arrays.asList(name, argValue); - } - } - - private J.MethodInvocation applyTemplate(ExecutionContext ctx, J.MethodInvocation m, String template, Object... parameters) { - J.MethodInvocation invocation = JavaTemplate.builder(template) - .contextSensitive() - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) - .build() - .apply(getCursor(), m.getCoordinates().replace(), parameters); - - // retain whitespace formatting - if (invocation.getPadding().getSelect() != null && m.getPadding().getSelect() != null) { - return invocation.getPadding() - .withSelect( - invocation.getPadding().getSelect() - .withAfter(m.getPadding().getSelect().getAfter()) - ); - } - return invocation; - } - - private boolean checkIfRelatedToDuration(J.MethodInvocation argument) { - // assertThat(.).isEqual(0) - if (argument.getSelect() != null) { - if (argument.getSelect() instanceof J.MethodInvocation) { - J.MethodInvocation selectMethod = (J.MethodInvocation) argument.getSelect(); - return TypeUtils.isOfType(selectMethod.getType(), JavaType.buildType("java.time.Duration")); + ), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (TIME_UNIT_MATCHERS.matches(mi)) { + return simplifyTimeUnits(mi, ctx); + } else if (IS_MATCHERS.stream().anyMatch(matcher -> matcher.matches(mi))) { + return simplifyMultipleAssertions(mi, ctx); + } + return mi; + } + + private J.MethodInvocation simplifyMultipleAssertions(J.MethodInvocation m, ExecutionContext ctx) { + Expression isEqualToArg = m.getArguments().get(0); + Expression select = m.getSelect(); + List templateParameters = new ArrayList<>(); + templateParameters.add(null); + Expression asDescription = null; + + if (AS_MATCHER.matches(select)) { + asDescription = ((J.MethodInvocation) select).getArguments().get(0); + select = ((J.MethodInvocation) select).getSelect(); + templateParameters.add(asDescription); + } + + if (!ASSERT_THAT_MATCHER.matches(select)) { + return m; + } + + Expression assertThatArgumentExpr = ((J.MethodInvocation) select).getArguments().get(0); + if (!(assertThatArgumentExpr instanceof J.MethodInvocation)) { + return m; + } + J.MethodInvocation assertThatArg = (J.MethodInvocation) assertThatArgumentExpr; + + if (isZero(isEqualToArg) && checkIfRelatedToDuration(assertThatArg)) { + String formatted_template = formatTemplate("assertThat(#{any()}).%s();", m.getSimpleName(), asDescription); + templateParameters.set(0, assertThatArg); + return applyTemplate(ctx, m, formatted_template, templateParameters.toArray()); + } + + if (GET_NANO_MATCHER.matches(assertThatArg) || GET_SECONDS_MATCHER.matches(assertThatArg)) { + Expression assertThatArgSelect = assertThatArg.getSelect(); + String methodName = assertThatArg.getSimpleName(); + String formatted_template = formatTemplate("assertThat(#{any()}).%s(#{any()});", methodName, asDescription); + templateParameters.set(0, assertThatArgSelect); + templateParameters.add(isEqualToArg); + + return applyTemplate(ctx, m, formatted_template, templateParameters.toArray()); + } + + return m; + } + + private boolean isZero(Expression isEqualToArg) { + if (isEqualToArg instanceof J.Literal) { + J.Literal literal = (J.Literal) isEqualToArg; + return literal.getValue() instanceof Number && ((Number) literal.getValue()).longValue() == 0; + } + return false; + } + + private J.MethodInvocation simplifyTimeUnits(J.MethodInvocation m, ExecutionContext ctx) { + Expression arg = m.getArguments().get(0); + Long argValue = SimplifyDurationCreationUnits.getConstantIntegralValue(arg); + if (argValue == null) { + return m; + } + + List unitInfo = getUnitInfo(m.getSimpleName(), Math.toIntExact(argValue)); + String methodName = (String) unitInfo.get(0); + int methodArg = (int) unitInfo.get(1); + if (!(m.getSimpleName().equals(methodName))) { + // update method invocation with new name and arg + String template = String.format("#{any()}.%s(%d)", methodName, methodArg); + return applyTemplate(ctx, m, template, m.getSelect()); + } + + return m; + } + + private List getUnitInfo(String name, int argValue) { + final int timeLength; + if (name.equals("hasSeconds") || name.equals("hasMinutes")) { + timeLength = 60; + } else if (name.equals("hasNanos") || name.equals("hasMillis")) { + timeLength = 1000; + } else if (name.equals("hasHours")) { + timeLength = 24; + } else { + return Arrays.asList(name, argValue); + } + + if (argValue % timeLength == 0) { + String newName = METHOD_MAP.get(name); + return getUnitInfo(newName, argValue / timeLength); + } else { + // returning name, newArg + return Arrays.asList(name, argValue); + } + } + + private J.MethodInvocation applyTemplate(ExecutionContext ctx, J.MethodInvocation m, String template, Object... parameters) { + J.MethodInvocation invocation = JavaTemplate.builder(template) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), m.getCoordinates().replace(), parameters); + + // retain whitespace formatting + if (invocation.getPadding().getSelect() != null && m.getPadding().getSelect() != null) { + return invocation.getPadding() + .withSelect( + invocation.getPadding().getSelect() + .withAfter(m.getPadding().getSelect().getAfter()) + ); + } + return invocation; + } + + private boolean checkIfRelatedToDuration(J.MethodInvocation argument) { + if (argument.getSelect() != null) { + if (argument.getSelect() instanceof J.MethodInvocation) { + J.MethodInvocation selectMethod = (J.MethodInvocation) argument.getSelect(); + return TypeUtils.isOfType(selectMethod.getType(), JavaType.buildType("java.time.Duration")); + } + } + return false; + } + + @SuppressWarnings("ConstantValue") + private String formatTemplate(String template, String methodName, Object asDescriptionArg) { + String replacementMethod = METHOD_MAP.get(methodName); + if (asDescriptionArg == null) { + return String.format(template, replacementMethod); + } + StringBuilder newTemplate = new StringBuilder(template); + newTemplate.insert(newTemplate.indexOf(").") + 1, ".as(#{any()})"); + return String.format(newTemplate.toString(), replacementMethod); + } } - } - return false; - } - - @SuppressWarnings("ConstantValue") - private String formatTemplate(String template, String methodName, Object asDescriptionArg) { - String replacementMethod = METHOD_MAP.get(methodName); - if (asDescriptionArg == null) { - return String.format(template, replacementMethod); - } - StringBuilder newTemplate = new StringBuilder(template); - newTemplate.insert(newTemplate.indexOf(").") + 1, ".as(#{any()})"); - return String.format(newTemplate.toString(), replacementMethod); - } + ); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertArrayEqualsToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertArrayEqualsToAssertThat.java index ecdde2479..2c636e98f 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertArrayEqualsToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertArrayEqualsToAssertThat.java @@ -23,7 +23,7 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -32,11 +32,14 @@ import java.util.List; public class JUnitAssertArrayEqualsToAssertThat extends Recipe { - private static final String JUNIT_QUALIFIED_ASSERTIONS_CLASS_NAME = "org.junit.jupiter.api.Assertions"; + + private static final String JUNIT = "org.junit.jupiter.api.Assertions"; + private static final String ASSERTJ = "org.assertj.core.api.Assertions"; + private static final MethodMatcher ASSERT_ARRAY_EQUALS_MATCHER = new MethodMatcher(JUNIT + " assertArrayEquals(..)", true); @Override public String getDisplayName() { - return "JUnit `assertArrayEquals` To AssertJ"; + return "JUnit `assertArrayEquals` to assertJ"; } @Override @@ -46,93 +49,72 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>(JUNIT_QUALIFIED_ASSERTIONS_CLASS_NAME, false), new AssertArrayEqualsToAssertThatVisitor()); - } - - public static class AssertArrayEqualsToAssertThatVisitor extends JavaIsoVisitor { - private static final MethodMatcher JUNIT_ASSERT_EQUALS = new MethodMatcher(JUNIT_QUALIFIED_ASSERTIONS_CLASS_NAME + " assertArrayEquals(..)"); - - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_EQUALS.matches(method)) { - return method; - } - - List args = method.getArguments(); - Expression expected = args.get(0); - Expression actual = args.get(1); - - // Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - maybeRemoveImport(JUNIT_QUALIFIED_ASSERTIONS_CLASS_NAME); - - if (args.size() == 2) { - return JavaTemplate.builder("assertThat(#{anyArray()}).containsExactly(#{anyArray()});") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply(getCursor(), method.getCoordinates().replace(), actual, expected); - } else if (args.size() == 3 && !isFloatingPointType(args.get(2))) { - Expression message = args.get(2); - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{anyArray()}).as(#{any(String)}).containsExactly(#{anyArray()});") : - JavaTemplate.builder("assertThat(#{anyArray()}).as(#{any(java.util.function.Supplier)}).containsExactly(#{anyArray()});"); - return template - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply(getCursor(), method.getCoordinates().replace(), actual, message, expected); - } else if (args.size() == 3) { - maybeAddImport("org.assertj.core.api.Assertions", "within", false); - // assert is using floating points with a delta and no message. - return JavaTemplate.builder("assertThat(#{anyArray()}).containsExactly(#{anyArray()}, within(#{any()}));") - .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") - .javaParser(assertionsParser(ctx)) + return Preconditions.check(new UsesMethod<>(ASSERT_ARRAY_EQUALS_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation md = super.visitMethodInvocation(method, ctx); + if (!ASSERT_ARRAY_EQUALS_MATCHER.matches(md)) { + return md; + } + + maybeAddImport(ASSERTJ, "assertThat", false); + maybeRemoveImport(JUNIT); + + List args = md.getArguments(); + Expression expected = args.get(0); + Expression actual = args.get(1); + if (args.size() == 2) { + return JavaTemplate.builder("assertThat(#{anyArray()}).containsExactly(#{anyArray()});") + .staticImports(ASSERTJ + ".assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), md.getCoordinates().replace(), actual, expected); + } + if (args.size() == 3 && isFloatingPointType(args.get(2))) { + maybeAddImport(ASSERTJ, "within", false); + // assert is using floating points with a delta and no message. + return JavaTemplate.builder("assertThat(#{anyArray()}).containsExactly(#{anyArray()}, within(#{any()}));") + .staticImports(ASSERTJ + ".assertThat", ASSERTJ + ".within") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), md.getCoordinates().replace(), actual, expected, args.get(2)); + } + if (args.size() == 3) { + Expression message = args.get(2); + return JavaTemplate.builder("assertThat(#{anyArray()}).as(#{any()}).containsExactly(#{anyArray()});") + .staticImports(ASSERTJ + ".assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), md.getCoordinates().replace(), actual, message, expected); + } + + maybeAddImport(ASSERTJ, "within", false); + + // The assertEquals is using a floating point with a delta argument and a message. + Expression message = args.get(3); + return JavaTemplate.builder("assertThat(#{anyArray()}).as(#{any()}).containsExactly(#{anyArray()}, within(#{}));") + .staticImports(ASSERTJ + ".assertThat", ASSERTJ + ".within") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply(getCursor(), method.getCoordinates().replace(), actual, expected, args.get(2)); + .apply(getCursor(), md.getCoordinates().replace(), actual, message, expected, args.get(2)); } - // The assertEquals is using a floating point with a delta argument and a message. - Expression message = args.get(3); - maybeAddImport("org.assertj.core.api.Assertions", "within", false); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{anyArray()}).as(#{any(String)}).containsExactly(#{anyArray()}, within(#{any()}));") : - JavaTemplate.builder("assertThat(#{anyArray()}).as(#{any(java.util.function.Supplier)}).containsExactly(#{anyArray()}, within(#{}));"); - return template - .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") - .javaParser(assertionsParser(ctx)) - .build() - .apply(getCursor(), method.getCoordinates().replace(), actual, message, expected, args.get(2)); - } - - /** - * Returns true if the expression's type is either a primitive float/double or their object forms Float/Double - * - * @param expression The expression parsed from the original AST. - * @return true if the type is a floating point number. - */ - private static boolean isFloatingPointType(Expression expression) { - - JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); - if (fullyQualified != null) { - String typeName = fullyQualified.getFullyQualifiedName(); - return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + /** + * Returns true if the expression's type is either a primitive float/double or their object forms Float/Double + * + * @param expression The expression parsed from the original AST. + * @return true if the type is a floating point number. + */ + private boolean isFloatingPointType(Expression expression) { + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); + if (fullyQualified != null) { + String typeName = fullyQualified.getFullyQualifiedName(); + return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + } + + JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); + return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; } - - JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); - return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertEqualsToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertEqualsToAssertThat.java index 276c3870d..cbfad48c2 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertEqualsToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertEqualsToAssertThat.java @@ -23,7 +23,7 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -33,6 +33,10 @@ public class JUnitAssertEqualsToAssertThat extends Recipe { + private static final String JUNIT = "org.junit.jupiter.api.Assertions"; + private static final String ASSERTJ = "org.assertj.core.api.Assertions"; + private static final MethodMatcher ASSERT_EQUALS_MATCHER = new MethodMatcher(JUNIT + " assertEquals(..)", true); + @Override public String getDisplayName() { return "JUnit `assertEquals` to AssertJ"; @@ -45,105 +49,67 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertEqualsToAssertThatVisitor()); - } - - public static class AssertEqualsToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_EQUALS = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertEquals(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_EQUALS.matches(method)) { - return method; - } - - List args = method.getArguments(); - Expression expected = args.get(0); - Expression actual = args.get(1); - - //always add the import (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - // Remove import for "org.junit.jupiter.api.Assertions" if no longer used. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - - if (args.size() == 2) { - return JavaTemplate.builder("assertThat(#{any()}).isEqualTo(#{any()});") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply(getCursor(), method.getCoordinates().replace(), actual, expected); - } else if (args.size() == 3 && !isFloatingPointType(args.get(2))) { - Expression message = args.get(2); - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isEqualTo(#{any()});") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isEqualTo(#{any()});"); - return template - .staticImports("org.assertj.core.api.Assertions.assertThat") + return Preconditions.check(new UsesMethod<>(ASSERT_EQUALS_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_EQUALS_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport(ASSERTJ, "assertThat", false); + maybeRemoveImport(JUNIT); + + List args = mi.getArguments(); + Expression expected = args.get(0); + Expression actual = args.get(1); + if (args.size() == 2) { + return JavaTemplate.builder("assertThat(#{any()}).isEqualTo(#{any()});") + .staticImports(ASSERTJ + ".assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, expected); + } + if (args.size() == 3 && !isFloatingPointType(args.get(2))) { + Expression message = args.get(2); + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isEqualTo(#{any()});") + .staticImports(ASSERTJ + ".assertThat") + .imports("java.util.function.Supplier") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, message, expected); + } + if (args.size() == 3) { + maybeAddImport(ASSERTJ, "within", false); + return JavaTemplate.builder("assertThat(#{any()}).isCloseTo(#{any()}, within(#{any()}));") + .staticImports(ASSERTJ + ".assertThat", ASSERTJ + ".within") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, expected, args.get(2)); + } + + maybeAddImport(ASSERTJ, "within", false); + + // The assertEquals is using a floating point with a delta argument and a message. + Expression message = args.get(3); + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isCloseTo(#{any()}, within(#{any()}));") + .staticImports(ASSERTJ + ".assertThat", ASSERTJ + ".within") .imports("java.util.function.Supplier") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message, - expected - ); - } else if (args.size() == 3) { - //always add the import (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "within", false); - return JavaTemplate.builder("assertThat(#{any()}).isCloseTo(#{any()}, within(#{any()}));") - .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") - .javaParser(assertionsParser(ctx)) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply(getCursor(), method.getCoordinates().replace(), actual, expected, args.get(2)); - + .apply(getCursor(), mi.getCoordinates().replace(), actual, message, expected, args.get(2)); } - // The assertEquals is using a floating point with a delta argument and a message. - Expression message = args.get(3); - - //always add the import (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "within", false); - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isCloseTo(#{any()}, within(#{any()}));") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isCloseTo(#{any()}, within(#{any()}));"); - return template - .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") - .imports("java.util.function.Supplier") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message, - expected, - args.get(2) - ); - } + private boolean isFloatingPointType(Expression expression) { + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); + if (fullyQualified != null) { + String typeName = fullyQualified.getFullyQualifiedName(); + return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + } - private static boolean isFloatingPointType(Expression expression) { - - JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); - if (fullyQualified != null) { - String typeName = fullyQualified.getFullyQualifiedName(); - return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); + return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; } - - JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); - return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertFalseToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertFalseToAssertThat.java index 149e5b3df..84d1462a1 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertFalseToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertFalseToAssertThat.java @@ -23,15 +23,16 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.TypeUtils; import java.util.List; public class JUnitAssertFalseToAssertThat extends Recipe { + private static final MethodMatcher ASSERT_FALSE_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertFalse(boolean, ..)", true); + @Override public String getDisplayName() { return "JUnit `assertFalse` to AssertJ"; @@ -44,66 +45,34 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertFalseToAssertThatVisitor()); - } - - public static class AssertFalseToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_FALSE = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertFalse(boolean, ..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_FALSE.matches(method)) { - return method; - } + return Preconditions.check(new UsesMethod<>(ASSERT_FALSE_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_FALSE_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + + List args = mi.getArguments(); + Expression actual = args.get(0); + if (args.size() == 1) { + return JavaTemplate.builder("assertThat(#{any(boolean)}).isFalse();") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual); + } - List args = method.getArguments(); - Expression actual = args.get(0); - - if (args.size() == 1) { - method = JavaTemplate.builder("assertThat(#{any(boolean)}).isFalse();") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual - ); - } else { Expression message = args.get(1); - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any(boolean)}).as(#{any(String)}).isFalse();") : - JavaTemplate.builder("assertThat(#{any(boolean)}).as(#{any(java.util.function.Supplier)}).isFalse();"); - - method = template + return JavaTemplate.builder("assertThat(#{any(boolean)}).as(#{any()}).isFalse();") .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message - ); + .apply(getCursor(), mi.getCoordinates().replace(), actual, message); } - - //Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - // Remove import for "org.junit.jupiter.api.Assertions" if no longer used. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - - return method; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertInstanceOfToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertInstanceOfToAssertThat.java new file mode 100644 index 000000000..f5921f80c --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertInstanceOfToAssertThat.java @@ -0,0 +1,76 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.assertj; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; + +public class JUnitAssertInstanceOfToAssertThat extends Recipe { + + private static final MethodMatcher ASSERT_INSTANCE_OF_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertInstanceOf(..)", true); + + @Override + public String getDisplayName() { + return "JUnit `assertInstanceOf` to AssertJ"; + } + + @Override + public String getDescription() { + return "Convert JUnit-style `assertInstanceOf()` to AssertJ's `assertThat().isInstanceOf()`."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesMethod<>(ASSERT_INSTANCE_OF_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_INSTANCE_OF_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + + Expression expected = mi.getArguments().get(0); + Expression actual = mi.getArguments().get(1); + if (mi.getArguments().size() == 2) { + return JavaTemplate.builder("assertThat(#{any()}).isInstanceOf(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), method.getCoordinates().replace(), actual, expected); + } + + Expression messageOrSupplier = mi.getArguments().get(2); + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isInstanceOf(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), method.getCoordinates().replace(), actual, messageOrSupplier, expected); + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotEqualsToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotEqualsToAssertThat.java index d78506810..f8dfce9e7 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotEqualsToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotEqualsToAssertThat.java @@ -23,7 +23,7 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -33,6 +33,10 @@ public class JUnitAssertNotEqualsToAssertThat extends Recipe { + private static final String JUNIT = "org.junit.jupiter.api.Assertions"; + private static final String ASSERTJ = "org.assertj.core.api.Assertions"; + private static final MethodMatcher ASSERT_NOT_EQUALS_MATCHER = new MethodMatcher(JUNIT + " assertNotEquals(..)", true); + @Override public String getDisplayName() { return "JUnit `assertNotEquals` to AssertJ"; @@ -45,117 +49,64 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertNotEqualsToAssertThatVisitor()); - } - - public static class AssertNotEqualsToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_EQUALS = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertNotEquals(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_EQUALS.matches(method)) { - return method; - } - - List args = method.getArguments(); - - Expression expected = args.get(0); - Expression actual = args.get(1); - - if (args.size() == 2) { - method = JavaTemplate.builder("assertThat(#{any()}).isNotEqualTo(#{any()});") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - expected - ); - } else if (args.size() == 3 && !isFloatingPointType(args.get(2))) { - Expression message = args.get(2); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isNotEqualTo(#{any()});") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isNotEqualTo(#{any()});"); - + return Preconditions.check(new UsesMethod<>(ASSERT_NOT_EQUALS_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_NOT_EQUALS_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport(ASSERTJ, "assertThat", false); + maybeRemoveImport(JUNIT); + + List args = mi.getArguments(); + Expression expected = args.get(0); + Expression actual = args.get(1); + if (args.size() == 2) { + return JavaTemplate.builder("assertThat(#{any()}).isNotEqualTo(#{any()});") + .staticImports(ASSERTJ + ".assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, expected); + } + if (args.size() == 3 && isFloatingPointType(args.get(2))) { + maybeAddImport(ASSERTJ, "within", false); + return JavaTemplate.builder("assertThat(#{any()}).isNotCloseTo(#{any()}, within(#{any()}));") + .staticImports(ASSERTJ + ".assertThat", ASSERTJ + ".within") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, expected, args.get(2)); + } + if (args.size() == 3) { + Expression message = args.get(2); + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isNotEqualTo(#{any()});") + .staticImports(ASSERTJ + ".assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, message, expected); + } + + maybeAddImport(ASSERTJ, "within", false); - method = template - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message, - expected - ); - } else if (args.size() == 3) { - method = JavaTemplate.builder("assertThat(#{any()}).isNotCloseTo(#{any()}, within(#{any()}));") - .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - expected, - args.get(2) - ); - maybeAddImport("org.assertj.core.api.Assertions", "within", false); - } else { Expression message = args.get(3); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isNotCloseTo(#{any()}, within(#{any()}));") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isNotCloseTo(#{any()}, within(#{any()}));"); - - method = template - .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") - .javaParser(assertionsParser(ctx)) + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isNotCloseTo(#{any()}, within(#{any()}));") + .staticImports(ASSERTJ + ".assertThat", ASSERTJ + ".within") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message, - expected, - args.get(2) - ); - - maybeAddImport("org.assertj.core.api.Assertions", "within", false); + .apply(getCursor(), method.getCoordinates().replace(), actual, message, expected, args.get(2)); } - //Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - // Remove import for "org.junit.jupiter.api.Assertions" if no longer used. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); + private boolean isFloatingPointType(Expression expression) { + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); + if (fullyQualified != null) { + String typeName = fullyQualified.getFullyQualifiedName(); + return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + } - return method; - } - - private static boolean isFloatingPointType(Expression expression) { - JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); - if (fullyQualified != null) { - String typeName = fullyQualified.getFullyQualifiedName(); - return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); + return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; } - - JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); - return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotNullToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotNullToAssertThat.java index dea4c6ffe..f6d4696ad 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotNullToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNotNullToAssertThat.java @@ -23,15 +23,16 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.TypeUtils; import java.util.List; public class JUnitAssertNotNullToAssertThat extends Recipe { + private static final MethodMatcher ASSERT_NOT_NULL_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertNotNull(..)", true); + @Override public String getDisplayName() { return "JUnit `assertNotNull` to AssertJ"; @@ -44,68 +45,35 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertNotNullToAssertThatVisitor()); - } - - public static class AssertNotNullToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_NOT_NULL_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertNotNull(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_NOT_NULL_MATCHER.matches(method)) { - return method; - } - - List args = method.getArguments(); - Expression actual = args.get(0); + return Preconditions.check(new UsesMethod<>(ASSERT_NOT_NULL_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_NOT_NULL_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + + List args = mi.getArguments(); + Expression actual = args.get(0); + if (args.size() == 1) { + return JavaTemplate.builder("assertThat(#{any()}).isNotNull();") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual); + + } - if (args.size() == 1) { - method = JavaTemplate.builder("assertThat(#{any()}).isNotNull();") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual - ); - - } else { Expression message = args.get(1); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isNotNull();") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isNotNull();"); - - method = template + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isNotNull();") .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message - ); + .apply(getCursor(), mi.getCoordinates().replace(), actual, message); } - - //Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - //And if there are no longer references to the JUnit assertions class, we can remove the import. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - - return method; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNullToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNullToAssertThat.java index c2c916f20..7dc9586e8 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNullToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertNullToAssertThat.java @@ -23,15 +23,16 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.TypeUtils; import java.util.List; public class JUnitAssertNullToAssertThat extends Recipe { + private static final MethodMatcher ASSERT_NULL_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertNull(..)", true); + @Override public String getDisplayName() { return "JUnit `assertNull` to AssertJ"; @@ -44,67 +45,34 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertNullToAssertThatVisitor()); - } - - public static class AssertNullToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_NULL_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertNull(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_NULL_MATCHER.matches(method)) { - return method; - } + return Preconditions.check(new UsesMethod<>(ASSERT_NULL_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_NULL_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + + List args = mi.getArguments(); + Expression actual = args.get(0); + if (args.size() == 1) { + return JavaTemplate.builder("assertThat(#{any()}).isNull();") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual); + } - List args = method.getArguments(); - Expression actual = args.get(0); - - if (args.size() == 1) { - method = JavaTemplate.builder("assertThat(#{any()}).isNull();") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual - ); - } else { Expression message = args.get(1); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isNull();") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isNull();"); - - method = template + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isNull();") .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message - ); + .apply(getCursor(), mi.getCoordinates().replace(), actual, message); } - - // Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - // Remove import for "org.junit.jupiter.api.Assertions" if no longer used. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - - return method; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertSameToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertSameToAssertThat.java index 1241d70e0..88a3a584e 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertSameToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertSameToAssertThat.java @@ -23,15 +23,16 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.TypeUtils; import java.util.List; public class JUnitAssertSameToAssertThat extends Recipe { + private static final MethodMatcher ASSERT_SAME_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertSame(..)", true); + @Override public String getDisplayName() { return "JUnit `assertSame` to AssertJ"; @@ -44,70 +45,35 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertSameToAssertThatVisitor()); - } - - public static class AssertSameToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_SAME_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertSame(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_SAME_MATCHER.matches(method)) { - return method; - } + return Preconditions.check(new UsesMethod<>(ASSERT_SAME_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_SAME_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + + List args = mi.getArguments(); + Expression expected = args.get(0); + Expression actual = args.get(1); + if (args.size() == 2) { + return JavaTemplate.builder("assertThat(#{any()}).isSameAs(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual, expected); + } - List args = method.getArguments(); - Expression expected = args.get(0); - Expression actual = args.get(1); - - if (args.size() == 2) { - method = JavaTemplate.builder("assertThat(#{any()}).isSameAs(#{any()});") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - expected - ); - } else { Expression message = args.get(2); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isSameAs(#{any()});") : - JavaTemplate.builder("assertThat(#{any()}).as(#{any(java.util.function.Supplier)}).isSameAs(#{any()});"); - - method = template + return JavaTemplate.builder("assertThat(#{any()}).as(#{any()}).isSameAs(#{any()});") .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message, - expected - ); + .apply(getCursor(), mi.getCoordinates().replace(), actual, message, expected); } - - // Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - // Remove import for "org.junit.jupiter.api.Assertions" if no longer used. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - - return method; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionType.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionType.java index 10eb1b5f2..0960100d0 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionType.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionType.java @@ -30,6 +30,9 @@ public class JUnitAssertThrowsToAssertExceptionType extends Recipe { + private static final MethodMatcher ASSERT_THROWS_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertThrows(..)"); + private static final JavaType THROWING_CALLABLE_TYPE = JavaType.buildType("org.assertj.core.api.ThrowableAssert.ThrowingCallable"); + @Override public String getDisplayName() { return "JUnit AssertThrows to AssertJ exceptionType"; @@ -42,47 +45,38 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesMethod<>("org.junit.jupiter.api.Assertions assertThrows(..)"), new AssertExceptionTypeVisitor()); - } - - private static class AssertExceptionTypeVisitor extends JavaIsoVisitor { - private static final MethodMatcher ASSERT_THROWS_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertThrows(..)"); - private static final JavaType THROWING_CALLABLE_TYPE = JavaType.buildType("org.assertj.core.api.ThrowableAssert.ThrowingCallable"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - if (ASSERT_THROWS_MATCHER.matches(mi) - && mi.getArguments().size() == 2 - && getCursor().getParentTreeCursor().getValue() instanceof J.Block) { - J executable = mi.getArguments().get(1); - if (executable instanceof J.Lambda) { - executable = ((J.Lambda) executable).withType(THROWING_CALLABLE_TYPE); - } else if (executable instanceof J.MemberReference) { - executable = ((J.MemberReference) executable).withType(THROWING_CALLABLE_TYPE); - } else { - executable = null; - } + return Preconditions.check(new UsesMethod<>(ASSERT_THROWS_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (ASSERT_THROWS_MATCHER.matches(mi) && + mi.getArguments().size() == 2 && + getCursor().getParentTreeCursor().getValue() instanceof J.Block) { + J executable = mi.getArguments().get(1); + if (executable instanceof J.Lambda) { + executable = ((J.Lambda) executable).withType(THROWING_CALLABLE_TYPE); + } else if (executable instanceof J.MemberReference) { + executable = ((J.MemberReference) executable).withType(THROWING_CALLABLE_TYPE); + } else { + executable = null; + } - if (executable != null) { - mi = JavaTemplate - .builder("assertThatExceptionOfType(#{any(java.lang.Class)}).isThrownBy(#{any(org.assertj.core.api.ThrowableAssert.ThrowingCallable)})") - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) - .staticImports("org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType") - .build() - .apply( - getCursor(), - mi.getCoordinates().replace(), - mi.getArguments().get(0), executable - ); - maybeAddImport("org.assertj.core.api.AssertionsForClassTypes", "assertThatExceptionOfType", false); - maybeRemoveImport("org.junit.jupiter.api.Assertions.assertThrows"); - maybeRemoveImport("org.junit.jupiter.api.Assertions"); + if (executable != null) { + mi = JavaTemplate + .builder("assertThatExceptionOfType(#{any(java.lang.Class)}).isThrownBy(#{any(org.assertj.core.api.ThrowableAssert.ThrowingCallable)})") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .staticImports("org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), mi.getArguments().get(0), executable); + maybeAddImport("org.assertj.core.api.AssertionsForClassTypes", "assertThatExceptionOfType", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions.assertThrows"); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); - doAfterVisit(new LambdaBlockToExpression().getVisitor()); + doAfterVisit(new LambdaBlockToExpression().getVisitor()); + } } + return mi; } - return mi; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertTrueToAssertThat.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertTrueToAssertThat.java index b478716dc..8541a4f2c 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertTrueToAssertThat.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitAssertTrueToAssertThat.java @@ -23,14 +23,16 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.TypeUtils; import java.util.List; public class JUnitAssertTrueToAssertThat extends Recipe { + + private static final MethodMatcher ASSERT_TRUE_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertTrue(boolean, ..)"); + @Override public String getDisplayName() { return "JUnit `assertTrue` to AssertJ"; @@ -43,67 +45,34 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new AssertTrueToAssertThatVisitor()); - } - - public static class AssertTrueToAssertThatVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_ASSERT_TRUE = new MethodMatcher("org.junit.jupiter.api.Assertions" + " assertTrue(boolean, ..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!JUNIT_ASSERT_TRUE.matches(method)) { - return method; - } + return Preconditions.check(new UsesMethod<>(ASSERT_TRUE_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!ASSERT_TRUE_MATCHER.matches(mi)) { + return mi; + } + + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + + List args = mi.getArguments(); + Expression actual = args.get(0); + if (args.size() == 1) { + return JavaTemplate.builder("assertThat(#{any(boolean)}).isTrue();") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), actual); + } - List args = method.getArguments(); - Expression actual = args.get(0); - - if (args.size() == 1) { - method = JavaTemplate.builder("assertThat(#{any(boolean)}).isTrue();") - .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual - ); - } else { Expression message = args.get(1); - - JavaTemplate.Builder template = TypeUtils.isString(message.getType()) ? - JavaTemplate.builder("assertThat(#{any(boolean)}).as(#{any(String)}).isTrue();") : - JavaTemplate.builder("assertThat(#{any(boolean)}).as(#{any(java.util.function.Supplier)}).isTrue();"); - - method = template + return JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isTrue();") .staticImports("org.assertj.core.api.Assertions.assertThat") - .javaParser(assertionsParser(ctx)) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - actual, - message - ); + .apply(getCursor(), mi.getCoordinates().replace(), actual, message); } - - //Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); - - // Remove import for "org.junit.jupiter.api.Assertions" if no longer used. - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - - return method; - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/JUnitFailToAssertJFail.java b/src/main/java/org/openrewrite/java/testing/assertj/JUnitFailToAssertJFail.java index b93ee3c9e..aef7ddfde 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/JUnitFailToAssertJFail.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/JUnitFailToAssertJFail.java @@ -20,14 +20,20 @@ import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; import org.openrewrite.java.*; -import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.TypeUtils; +import java.util.Collections; import java.util.List; public class JUnitFailToAssertJFail extends Recipe { + + private static final String JUNIT = "org.junit.jupiter.api.Assertions"; + private static final String ASSERTJ = "org.assertj.core.api.Assertions"; + private static final MethodMatcher FAIL_MATCHER = new MethodMatcher(JUNIT + " fail(..)"); + @Override public String getDisplayName() { return "JUnit fail to AssertJ"; @@ -40,118 +46,70 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", false), new JUnitFailToAssertJFailVisitor()); - } - - public static class JUnitFailToAssertJFailVisitor extends JavaIsoVisitor { - private JavaParser.Builder assertionsParser; - - private JavaParser.Builder assertionsParser(ExecutionContext ctx) { - if (assertionsParser == null) { - assertionsParser = JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "assertj-core-3.24"); - } - return assertionsParser; - } - - private static final MethodMatcher JUNIT_FAIL_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions" + " fail(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = method; - - if (!JUNIT_FAIL_MATCHER.matches(m)) { - return m; - } - - List args = m.getArguments(); + return Preconditions.check(new UsesMethod<>(FAIL_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = method; + if (!FAIL_MATCHER.matches(mi)) { + return mi; + } - if (args.size() == 1) { - // fail(), fail(String), fail(Supplier), fail(Throwable) - if (args.get(0) instanceof J.Empty) { - m = JavaTemplate.builder("org.assertj.core.api.Assertions.fail(\"\");") - .javaParser(assertionsParser(ctx)) - .build() - .apply(getCursor(), m.getCoordinates().replace()); - } else if (args.get(0) instanceof J.Literal || - TypeUtils.isAssignableTo("java.lang.String", args.get(0).getType())) { - m = JavaTemplate.builder("org.assertj.core.api.Assertions.fail(#{any()});") - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - m.getCoordinates().replace(), - args.get(0) - ); + List args = mi.getArguments(); + if (args.size() == 1) { + // fail(), fail(String), fail(Supplier), fail(Throwable) + if (args.get(0) instanceof J.Empty) { + mi = JavaTemplate.builder(ASSERTJ + ".fail(\"\");") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace()); + } else if (args.get(0) instanceof J.Literal || + TypeUtils.isAssignableTo("java.lang.String", args.get(0).getType())) { + mi = JavaTemplate.builder(ASSERTJ + ".fail(#{any()});") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), args.get(0)); + } else { + mi = JavaTemplate.builder(ASSERTJ + ".fail(\"\", #{any()});") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), args.get(0)); + } } else { - m = JavaTemplate.builder("org.assertj.core.api.Assertions.fail(\"\", #{any()});") - .javaParser(assertionsParser(ctx)) + // fail(String, Throwable) + String anyArgs = String.join(",", Collections.nCopies(args.size(), "#{any()}")); + mi = JavaTemplate.builder(ASSERTJ + ".fail(" + anyArgs + ");") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) .build() - .apply( - getCursor(), - m.getCoordinates().replace(), - args.get(0) - ); + .apply(getCursor(), mi.getCoordinates().replace(), args.toArray()); } - } else { - // fail(String, Throwable) - StringBuilder templateBuilder = new StringBuilder("org.assertj.core.api.Assertions.fail("); - for (int i = 0; i < args.size(); i++) { - templateBuilder.append("#{any()}"); - if (i < args.size() - 1) { - templateBuilder.append(", "); - } - } - templateBuilder.append(");"); - m = JavaTemplate.builder(templateBuilder.toString()) - .javaParser(assertionsParser(ctx)) - .build() - .apply( - getCursor(), - m.getCoordinates().replace(), - args.toArray() - ); + doAfterVisit(new RemoveUnusedImports().getVisitor()); + doAfterVisit(new UnqualifiedMethodInvocations()); + return mi; } - doAfterVisit(new RemoveUnusedImports().getVisitor()); - doAfterVisit(new UnqualifiedMethodInvocations()); - return m; - } + class UnqualifiedMethodInvocations extends JavaIsoVisitor { + private final MethodMatcher INTERNAL_FAIL_MATCHER = new MethodMatcher(ASSERTJ + " fail(..)"); - private static class UnqualifiedMethodInvocations extends JavaIsoVisitor { - private static final MethodMatcher ASSERTJ_FAIL_MATCHER = new MethodMatcher("org.assertj.core.api.Assertions" + " fail(..)"); + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!INTERNAL_FAIL_MATCHER.matches(mi)) { + return mi; + } - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (!ASSERTJ_FAIL_MATCHER.matches(method)) { - return method; - } + maybeAddImport(ASSERTJ, "fail", false); + maybeRemoveImport(JUNIT + ".fail"); - StringBuilder templateBuilder = new StringBuilder("fail("); - List arguments = method.getArguments(); - for (int i = 0; i < arguments.size(); i++) { - templateBuilder.append("#{any()}"); - if (i < arguments.size() - 1) { - templateBuilder.append(", "); - } + List arguments = mi.getArguments(); + String anyArgs = String.join(",", Collections.nCopies(arguments.size(), "#{any()}")); + return JavaTemplate.builder("fail(" + anyArgs + ");") + .staticImports(ASSERTJ + ".fail") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), arguments.toArray()); } - templateBuilder.append(");"); - - method = JavaTemplate.builder(templateBuilder.toString()) - .staticImports("org.assertj.core.api.Assertions" + ".fail") - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) - .build() - .apply( - getCursor(), - method.getCoordinates().replace(), - arguments.toArray() - ); - //Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) - maybeAddImport("org.assertj.core.api.Assertions", "fail", false); - maybeRemoveImport("org.junit.jupiter.api.Assertions.fail"); - return super.visitMethodInvocation(method, ctx); } - } + }); } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/SimplifyAssertJAssertion.java b/src/main/java/org/openrewrite/java/testing/assertj/SimplifyAssertJAssertion.java index 1d3685955..de1d6be55 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/SimplifyAssertJAssertion.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/SimplifyAssertJAssertion.java @@ -33,6 +33,8 @@ @NoArgsConstructor public class SimplifyAssertJAssertion extends Recipe { + private static final MethodMatcher ASSERT_THAT_MATCHER = new MethodMatcher("org.assertj.core.api.Assertions assertThat(..)"); + @Option(displayName = "AssertJ assertion", description = "The assertion method that should be replaced.", example = "hasSize", @@ -67,38 +69,34 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return new ShorthenChainedAssertJAssertionsVisitor(); - } - - private class ShorthenChainedAssertJAssertionsVisitor extends JavaIsoVisitor { - private final MethodMatcher ASSERT_THAT_MATCHER = new MethodMatcher("org.assertj.core.api.Assertions assertThat(..)"); - private final MethodMatcher ASSERT_TO_REPLACE = new MethodMatcher("org.assertj.core.api.* " + assertToReplace + "(..)"); + final MethodMatcher assertToReplace = new MethodMatcher("org.assertj.core.api.* " + this.assertToReplace + "(..)"); + return new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocation, ExecutionContext ctx) { - J.MethodInvocation mi = super.visitMethodInvocation(methodInvocation, ctx); + // Match the end of the chain first, then the select to avoid matching the wrong method chain + if (!assertToReplace.matches(mi) || !ASSERT_THAT_MATCHER.matches(mi.getSelect())) { + return mi; + } - // Match the end of the chain first, then the select to avoid matching the wrong method chain - if (!ASSERT_TO_REPLACE.matches(mi) || !ASSERT_THAT_MATCHER.matches(mi.getSelect())) { - return mi; - } + // Compare argument with passed in literal + if (!(mi.getArguments().get(0) instanceof J.Literal) || + !literalArgument.equals(((J.Literal) mi.getArguments().get(0)).getValueSource())) { // Implies "null" is `null` + return mi; + } - // Compare argument with passed in literal - if (!(mi.getArguments().get(0) instanceof J.Literal) || - !literalArgument.equals(((J.Literal) mi.getArguments().get(0)).getValueSource())) { // Implies "null" is `null` - return mi; - } + // Check argument type of assertThat + if (!TypeUtils.isAssignableTo(requiredType, ((J.MethodInvocation) mi.getSelect()).getArguments().get(0).getType())) { + return mi; + } - // Check argument type of assertThat - if (!TypeUtils.isAssignableTo(requiredType, ((J.MethodInvocation) mi.getSelect()).getArguments().get(0).getType())) { - return mi; + // Assume zero argument replacement method + return JavaTemplate.builder("#{any()}." + dedicatedAssertion + "()") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), mi.getSelect()); } - - // Assume zero argument replacement method - return JavaTemplate.builder("#{any()}." + dedicatedAssertion + "()") - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "assertj-core-3.24")) - .build() - .apply(getCursor(), mi.getCoordinates().replace(), mi.getSelect()); - } + }; } } diff --git a/src/main/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertion.java b/src/main/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertion.java index bfbf9fc43..e6d37912e 100644 --- a/src/main/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertion.java +++ b/src/main/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertion.java @@ -30,14 +30,12 @@ import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.TypeUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; @AllArgsConstructor @NoArgsConstructor public class SimplifyChainedAssertJAssertion extends Recipe { + @Option(displayName = "AssertJ chained assertion", description = "The chained AssertJ assertion to move to dedicated assertion.", example = "equals", @@ -84,98 +82,89 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return new SimplifyChainedAssertJAssertionsVisitor(); - } - - private class SimplifyChainedAssertJAssertionsVisitor extends JavaIsoVisitor { - private final MethodMatcher ASSERT_THAT_MATCHER = new MethodMatcher("org.assertj.core.api.Assertions assertThat(..)"); - private final MethodMatcher CHAINED_ASSERT_MATCHER = new MethodMatcher("java..* " + chainedAssertion + "(..)"); - private final MethodMatcher ASSERT_TO_REPLACE = new MethodMatcher("org.assertj.core.api.* " + assertToReplace + "(..)"); - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocation, ExecutionContext ctx) { - J.MethodInvocation mi = super.visitMethodInvocation(methodInvocation, ctx); - - // assert has correct assertion - if (!ASSERT_TO_REPLACE.matches(mi)) { - return mi; - } - - // assertThat has method call - J.MethodInvocation assertThat = (J.MethodInvocation) mi.getSelect(); - if (!ASSERT_THAT_MATCHER.matches(assertThat) || !(assertThat.getArguments().get(0) instanceof J.MethodInvocation)) { - return mi; - } - - J.MethodInvocation assertThatArg = (J.MethodInvocation) assertThat.getArguments().get(0); - if (!CHAINED_ASSERT_MATCHER.matches(assertThatArg)) { - return mi; + MethodMatcher assertThatMatcher = new MethodMatcher("org.assertj.core.api.Assertions assertThat(..)"); + MethodMatcher chainedAssertMatcher = new MethodMatcher("java..* " + chainedAssertion + "(..)"); + MethodMatcher assertToReplace = new MethodMatcher("org.assertj.core.api.* " + this.assertToReplace + "(..)"); + + return new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocation, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(methodInvocation, ctx); + + // assert has correct assertion + if (!assertToReplace.matches(mi) || mi.getArguments().size() != 1) { + return mi; + } + + // assertThat has method call + J.MethodInvocation assertThat = (J.MethodInvocation) mi.getSelect(); + if (!assertThatMatcher.matches(assertThat) || !(assertThat.getArguments().get(0) instanceof J.MethodInvocation)) { + return mi; + } + + J.MethodInvocation assertThatArg = (J.MethodInvocation) assertThat.getArguments().get(0); + if (!chainedAssertMatcher.matches(assertThatArg)) { + return mi; + } + + // Extract the actual argument for the new assertThat call + Expression actual = assertThatArg.getSelect() != null ? assertThatArg.getSelect() : assertThatArg; + if (!TypeUtils.isAssignableTo(requiredType, actual.getType())) { + return mi; + } + List arguments = new ArrayList<>(); + arguments.add(actual); + + String template = getStringTemplateAndAppendArguments(assertThatArg, mi, arguments); + return JavaTemplate.builder(String.format(template, dedicatedAssertion)) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-5.9", "assertj-core-3.24")) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), arguments.toArray()); } - // Extract the actual argument for the new assertThat call - Expression actual = assertThatArg.getSelect() != null ? assertThatArg.getSelect() : assertThatArg; - if (!TypeUtils.isAssignableTo(requiredType, actual.getType())) { - return mi; + private String getStringTemplateAndAppendArguments(J.MethodInvocation assertThatArg, J.MethodInvocation methodToReplace, List arguments) { + Expression assertThatArgument = assertThatArg.getArguments().get(0); + Expression methodToReplaceArgument = methodToReplace.getArguments().get(0); + boolean assertThatArgumentIsEmpty = assertThatArgument instanceof J.Empty; + boolean methodToReplaceArgumentIsEmpty = methodToReplaceArgument instanceof J.Empty; + + // If both arguments are empty, then the select is already added to the arguments list, and we use a minimal template + if (assertThatArgumentIsEmpty && methodToReplaceArgumentIsEmpty) { + return "assertThat(#{any()}).%s()"; + } + + // If both arguments are not empty, then we add both to the arguments to the arguments list, and return a template with two arguments + if (!assertThatArgumentIsEmpty && !methodToReplaceArgumentIsEmpty) { + // This should only happen for map assertions using a key and value + arguments.add(assertThatArgument); + arguments.add(methodToReplaceArgument); + return "assertThat(#{any()}).%s(#{any()}, #{any()})"; + } + + // If either argument is empty, we choose which one to add to the arguments list, and optionally extract the select + arguments.add(extractEitherArgument(assertThatArgumentIsEmpty, assertThatArgument, methodToReplaceArgument)); + + // Special case for Path.of() assertions + if ("java.nio.file.Path".equals(requiredType) && dedicatedAssertion.contains("Raw") && + TypeUtils.isAssignableTo("java.lang.String", assertThatArgument.getType())) { + maybeAddImport("java.nio.file.Path"); + return "assertThat(#{any()}).%s(Path.of(#{any()}))"; + } + + return "assertThat(#{any()}).%s(#{any()})"; } - List arguments = new ArrayList<>(); - arguments.add(actual); - - String template = getStringTemplateAndAppendArguments(assertThatArg, mi, arguments); - return applyTemplate(String.format(template, dedicatedAssertion), arguments, mi, ctx); - } - - private J.MethodInvocation applyTemplate(String formattedTemplate, List arguments, J.MethodInvocation mi, ExecutionContext ctx) { - return JavaTemplate.builder(formattedTemplate) - .contextSensitive() - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-5.9", "assertj-core-3.24")) - .build() - .apply(getCursor(), mi.getCoordinates().replace(), arguments.toArray()); - } - - private String getStringTemplateAndAppendArguments(J.MethodInvocation assertThatArg, J.MethodInvocation methodToReplace, List arguments) { - Expression assertThatArgument = assertThatArg.getArguments().get(0); - Expression methodToReplaceArgument = methodToReplace.getArguments().get(0); - boolean assertThatArgumentIsEmpty = assertThatArgument instanceof J.Empty; - boolean methodToReplaceArgumentIsEmpty = methodToReplaceArgument instanceof J.Empty; - - // If both arguments are empty, then the select is already added to the arguments list, and we use a minimal template - if (assertThatArgumentIsEmpty && methodToReplaceArgumentIsEmpty) { - return "assertThat(#{any()}).%s()"; - } - - // If both arguments are not empty, then we add both to the arguments to the arguments list, and return a template with two arguments - if (!assertThatArgumentIsEmpty && !methodToReplaceArgumentIsEmpty) { - // This should only happen for map assertions using a key and value - arguments.add(assertThatArgument); - arguments.add(methodToReplaceArgument); - return "assertThat(#{any()}).%s(#{any()}, #{any()})"; - } - - // If either argument is empty, we choose which one to add to the arguments list, and optionally extract the select - arguments.add(extractEitherArgument(assertThatArgumentIsEmpty, assertThatArgument, methodToReplaceArgument)); - - // Special case for Path.of() assertions - if ("java.nio.file.Path".equals(requiredType) && dedicatedAssertion.contains("Raw") - && TypeUtils.isAssignableTo("java.lang.String", assertThatArgument.getType())) { - maybeAddImport("java.nio.file.Path"); - return "assertThat(#{any()}).%s(Path.of(#{any()}))"; - } - - return "assertThat(#{any()}).%s(#{any()})"; - } - } - private static Expression extractEitherArgument(boolean assertThatArgumentIsEmpty, Expression assertThatArgument, Expression methodToReplaceArgument) { - if (assertThatArgumentIsEmpty) { - return methodToReplaceArgument; - } - // Only on the assertThat argument do we possibly replace the argument with the select; such as list.size() -> list - if (assertThatArgument instanceof J.MethodInvocation) { - Expression select = ((J.MethodInvocation) assertThatArgument).getSelect(); - if (select != null) { - return select; + private Expression extractEitherArgument(boolean assertThatArgumentIsEmpty, Expression assertThatArgument, Expression methodToReplaceArgument) { + if (assertThatArgumentIsEmpty) { + return methodToReplaceArgument; + } + // Only on the assertThat argument do we possibly replace the argument with the select; such as list.size() -> list + if (chainedAssertMatcher.matches(assertThatArgument)) { + return Objects.requireNonNull(((J.MethodInvocation) assertThatArgument).getSelect()); + } + return assertThatArgument; } - } - return assertThatArgument; + }; } } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/AssertEqualsBooleanToAssertBoolean.java b/src/main/java/org/openrewrite/java/testing/cleanup/AssertEqualsBooleanToAssertBoolean.java index 0ebbd75db..ca911cd05 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/AssertEqualsBooleanToAssertBoolean.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/AssertEqualsBooleanToAssertBoolean.java @@ -60,8 +60,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu if (ASSERT_EQUALS.matches(mi) && isBooleanLiteral(mi) && JavaType.Primitive.Boolean.equals(mi.getArguments().get(1).getType())) { StringBuilder sb = new StringBuilder(); - String assertMethod = Boolean.parseBoolean(((J.Literal) mi.getArguments().get(0)).getValueSource()) - ? "assertTrue" : "assertFalse"; + String assertMethod = Boolean.parseBoolean(((J.Literal) mi.getArguments().get(0)).getValueSource()) ? + "assertTrue" : "assertFalse"; Expression assertion = mi.getArguments().get(1); if (mi.getSelect() == null) { maybeRemoveImport("org.junit.jupiter.api.Assertions"); diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/AssertFalseEqualsToAssertNotEquals.java b/src/main/java/org/openrewrite/java/testing/cleanup/AssertFalseEqualsToAssertNotEquals.java index 005e94ed1..bea963e03 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/AssertFalseEqualsToAssertNotEquals.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/AssertFalseEqualsToAssertNotEquals.java @@ -100,8 +100,8 @@ private boolean isEquals(Expression expr) { J.MethodInvocation methodInvocation = (J.MethodInvocation) expr; - return "equals".equals(methodInvocation.getName().getSimpleName()) - && methodInvocation.getArguments().size() == 1; + return "equals".equals(methodInvocation.getName().getSimpleName()) && + methodInvocation.getArguments().size() == 1; } }); } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/AssertNotEqualsBooleanToAssertBoolean.java b/src/main/java/org/openrewrite/java/testing/cleanup/AssertNotEqualsBooleanToAssertBoolean.java index 33dc0d81a..65d156ede 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/AssertNotEqualsBooleanToAssertBoolean.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/AssertNotEqualsBooleanToAssertBoolean.java @@ -59,8 +59,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); if (ASSERT_NOT_EQUALS.matches(mi) && isBooleanLiteral(mi)) { StringBuilder sb = new StringBuilder(); - String assertMethod = Boolean.parseBoolean(((J.Literal) mi.getArguments().get(0)).getValueSource()) - ? "assertFalse" : "assertTrue"; + String assertMethod = Boolean.parseBoolean(((J.Literal) mi.getArguments().get(0)).getValueSource()) ? + "assertFalse" : "assertTrue"; Expression assertion = mi.getArguments().get(1); if (mi.getSelect() == null) { maybeRemoveImport("org.junit.jupiter.api.Assertions"); diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueComparisonToAssertEquals.java b/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueComparisonToAssertEquals.java index c975d7d0a..fbcdaa352 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueComparisonToAssertEquals.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueComparisonToAssertEquals.java @@ -115,10 +115,10 @@ private boolean isEqualBinary(J.MethodInvocation method) { // Prevent breaking identity comparison. // Objects that are compared with == should not be compared with `.equals()` instead. // Out of the primitives == is not allowed when both are of type String - return binary.getLeft().getType() instanceof JavaType.Primitive - && binary.getRight().getType() instanceof JavaType.Primitive - && !(binary.getLeft().getType() == JavaType.Primitive.String - && binary.getRight().getType() == JavaType.Primitive.String); + return binary.getLeft().getType() instanceof JavaType.Primitive && + binary.getRight().getType() instanceof JavaType.Primitive && + !(binary.getLeft().getType() == JavaType.Primitive.String && + binary.getRight().getType() == JavaType.Primitive.String); } }); } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueEqualsToAssertEquals.java b/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueEqualsToAssertEquals.java index 35af67a58..e8a8ab646 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueEqualsToAssertEquals.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/AssertTrueEqualsToAssertEquals.java @@ -102,8 +102,8 @@ private boolean isEquals(Expression expr) { J.MethodInvocation methodInvocation = (J.MethodInvocation) expr; - return "equals".equals(methodInvocation.getName().getSimpleName()) - && methodInvocation.getArguments().size() == 1; + return "equals".equals(methodInvocation.getName().getSimpleName()) && + methodInvocation.getArguments().size() == 1; } }); } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrder.java b/src/main/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrder.java index 6ff67c3bf..2a56bcca0 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrder.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrder.java @@ -37,8 +37,21 @@ public class AssertionsArgumentOrder extends Recipe { new MethodMatcher("org.junit.jupiter.api.Assertions assertEquals(..)"), new MethodMatcher("org.junit.jupiter.api.Assertions assertNotEquals(..)"), new MethodMatcher("org.junit.jupiter.api.Assertions assertSame(..)"), - new MethodMatcher("org.junit.jupiter.api.Assertions assertNotSame(..)"), - new MethodMatcher("org.junit.jupiter.api.Assertions assertArrayEquals(..)") + new MethodMatcher("org.junit.jupiter.api.Assertions assertNotSame(..)") + }; + + private static final MethodMatcher[] junitAssertMatchers = new MethodMatcher[]{ + new MethodMatcher("org.junit.Assert assertEquals(..)"), + new MethodMatcher("org.junit.Assert assertEquals(..)"), + new MethodMatcher("org.junit.Assert assertArrayEquals(..)"), + new MethodMatcher("org.junit.Assert assertSame(..)"), + new MethodMatcher("org.junit.Assert assertNotSame(..)"), + new MethodMatcher("org.junit.Assert assert*Null(String, Object)") + }; + + private static final MethodMatcher[] junitAssertWithMessageMatchers = new MethodMatcher[]{ + new MethodMatcher("org.junit.Assert assertEquals(String, ..)"), + new MethodMatcher("org.junit.Assert assertArrayEquals(String, ..)") }; private static final MethodMatcher jupiterAssertIterableEqualsMatcher = new MethodMatcher("org.junit.jupiter.api.Assertions assertIterableEquals(..)"); @@ -56,6 +69,8 @@ public class AssertionsArgumentOrder extends Recipe { static { List matchers = new ArrayList<>(Arrays.asList(jupiterAssertionMatchers)); + matchers.addAll(Arrays.asList(junitAssertMatchers)); + matchers.addAll(Arrays.asList(junitAssertWithMessageMatchers)); matchers.add(jupiterAssertIterableEqualsMatcher); matchers.add(jupiterAssertNullMatcher); matchers.addAll(Arrays.asList(testNgMatcher)); @@ -97,7 +112,10 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu final Expression expected; final Expression actual; - if (isJupiterAssertion(mi)) { + if (isJunitAssertEqualsWithMessage(mi)) { + expected = mi.getArguments().get(1); + actual = mi.getArguments().get(2); + } else if (isJunitAssertion(mi) || isJupiterAssertion(mi)) { expected = mi.getArguments().get(0); actual = mi.getArguments().get(1); } else if (isTestNgAssertion(mi)) { @@ -174,5 +192,23 @@ private boolean isTestNgAssertion(J.MethodInvocation mi) { } return false; } + + private boolean isJunitAssertion(J.MethodInvocation mi) { + for (MethodMatcher assertionMethodMatcher : junitAssertMatchers) { + if (assertionMethodMatcher.matches(mi)) { + return true; + } + } + return false; + } + + private boolean isJunitAssertEqualsWithMessage(J.MethodInvocation mi) { + for (MethodMatcher actExpMatcher : junitAssertWithMessageMatchers) { + if (actExpMatcher.matches(mi)) { + return true; + } + } + return false; + } } } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/RemoveEmptyTests.java b/src/main/java/org/openrewrite/java/testing/cleanup/RemoveEmptyTests.java index cbc914457..d2701d963 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/RemoveEmptyTests.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/RemoveEmptyTests.java @@ -15,6 +15,7 @@ */ package org.openrewrite.java.testing.cleanup; +import org.jspecify.annotations.Nullable; import org.openrewrite.ExecutionContext; import org.openrewrite.Preconditions; import org.openrewrite.Recipe; @@ -53,8 +54,9 @@ public Set getTags() { @Override public TreeVisitor getVisitor() { return Preconditions.check(new FindEmptyMethods(false), new JavaVisitor() { + @Override - public J visitMethodDeclaration(MethodDeclaration method, ExecutionContext ctx) { + public @Nullable J visitMethodDeclaration(MethodDeclaration method, ExecutionContext ctx) { if (hasTestAnnotation(method) && isEmptyMethod(method)) { //noinspection ConstantConditions return null; diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefix.java b/src/main/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefix.java index 30142e99f..240bd0250 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefix.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefix.java @@ -21,7 +21,9 @@ import org.openrewrite.TreeVisitor; import org.openrewrite.internal.NameCaseConvention; import org.openrewrite.java.AnnotationMatcher; +import org.openrewrite.java.ChangeMethodName; import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.search.UsesType; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.J.MethodDeclaration; @@ -84,26 +86,26 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, // Quickly reject invalid methods String simpleName = method.getSimpleName(); int nameLength = simpleName.length(); - if (nameLength < 5 - || !simpleName.startsWith("test") - || !(simpleName.charAt(4) == '_' || Character.isUpperCase(simpleName.charAt(4))) - || TypeUtils.isOverride(method.getMethodType()) - || !hasJUnit5MethodAnnotation(method)) { + if (nameLength < 5 || + !simpleName.startsWith("test") || + !(simpleName.charAt(4) == '_' || Character.isUpperCase(simpleName.charAt(4))) || + TypeUtils.isOverride(method.getMethodType()) || + !hasJUnit5MethodAnnotation(method)) { return m; } // Reject invalid start character - boolean snakecase = simpleName.charAt(4) == '_' - && 5 < nameLength - && Character.isAlphabetic(simpleName.charAt(5)); + boolean snakecase = simpleName.charAt(4) == '_' && + 5 < nameLength && + Character.isAlphabetic(simpleName.charAt(5)); if (!snakecase && !Character.isAlphabetic(simpleName.charAt(4))) { return m; } // Avoid reserved keywords - String newMethodName = snakecase - ? NameCaseConvention.format(NameCaseConvention.LOWER_UNDERSCORE, simpleName.substring(5)) - : NameCaseConvention.format(NameCaseConvention.LOWER_CAMEL, simpleName.substring(4)); + String newMethodName = snakecase ? + NameCaseConvention.format(NameCaseConvention.LOWER_UNDERSCORE, simpleName.substring(5)) : + NameCaseConvention.format(NameCaseConvention.LOWER_CAMEL, simpleName.substring(4)); if (RESERVED_KEYWORDS.contains(newMethodName)) { return m; } @@ -138,9 +140,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Atomi } // Rename method and return - type = type.withName(newMethodName); - return m.withName(m.getName().withSimpleName(newMethodName).withType(type)) - .withMethodType(type); + doAfterVisit(new ChangeMethodName(MethodMatcher.methodPattern(m), newMethodName, false, false).getVisitor()); + return m; } private boolean methodExists(JavaType.Method method, String newName) { @@ -149,11 +150,11 @@ private boolean methodExists(JavaType.Method method, String newName) { private static boolean hasJUnit5MethodAnnotation(MethodDeclaration method) { for (J.Annotation a : method.getLeadingAnnotations()) { - if (TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.Test") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestTemplate") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.RepeatedTest") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.params.ParameterizedTest") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestFactory")) { + if (TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.Test") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestTemplate") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.RepeatedTest") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.params.ParameterizedTest") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestFactory")) { return true; } } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/SimplifyTestThrows.java b/src/main/java/org/openrewrite/java/testing/cleanup/SimplifyTestThrows.java index a33911d34..57cd7cfab 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/SimplifyTestThrows.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/SimplifyTestThrows.java @@ -63,9 +63,9 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx); // reject invalid methods - if (TypeUtils.isOverride(m.getMethodType()) - || !hasJUnit5MethodAnnotation(method) - || throwsNothingOrException(method)) { + if (TypeUtils.isOverride(m.getMethodType()) || + !hasJUnit5MethodAnnotation(method) || + throwsNothingOrException(method)) { return m; } @@ -101,11 +101,11 @@ private boolean throwsNothingOrException(J.MethodDeclaration method) { private boolean hasJUnit5MethodAnnotation(J.MethodDeclaration method) { for (J.Annotation a : method.getLeadingAnnotations()) { - if (TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.Test") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestTemplate") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.RepeatedTest") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.params.ParameterizedTest") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestFactory")) { + if (TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.Test") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestTemplate") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.RepeatedTest") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.params.ParameterizedTest") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestFactory")) { return true; } } diff --git a/src/main/java/org/openrewrite/java/testing/cleanup/TestsShouldNotBePublic.java b/src/main/java/org/openrewrite/java/testing/cleanup/TestsShouldNotBePublic.java index 0a6b4ebb3..dff7b613b 100644 --- a/src/main/java/org/openrewrite/java/testing/cleanup/TestsShouldNotBePublic.java +++ b/src/main/java/org/openrewrite/java/testing/cleanup/TestsShouldNotBePublic.java @@ -97,10 +97,10 @@ private static final class TestsNotPublicVisitor extends JavaIsoVisitor mod.getType() == J.Modifier.Type.Public) - && c.getModifiers().stream().noneMatch(mod -> mod.getType() == J.Modifier.Type.Abstract) - && !acc.extendedClasses.contains(String.valueOf(c.getType()))) { + if (c.getKind() != J.ClassDeclaration.Kind.Type.Interface && + c.getModifiers().stream().anyMatch(mod -> mod.getType() == J.Modifier.Type.Public) && + c.getModifiers().stream().noneMatch(mod -> mod.getType() == J.Modifier.Type.Abstract) && + !acc.extendedClasses.contains(String.valueOf(c.getType()))) { boolean hasTestMethods = c.getBody().getStatements().stream() .filter(org.openrewrite.java.tree.J.MethodDeclaration.class::isInstance) .map(J.MethodDeclaration.class::cast) @@ -168,14 +168,14 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex private boolean hasJUnit5MethodAnnotation(J.MethodDeclaration method) { for (J.Annotation a : method.getLeadingAnnotations()) { - if (TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.Test") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.RepeatedTest") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.params.ParameterizedTest") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestFactory") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.AfterEach") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.BeforeEach") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.AfterAll") - || TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.BeforeAll")) { + if (TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.Test") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.RepeatedTest") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.params.ParameterizedTest") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.TestFactory") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.AfterEach") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.BeforeEach") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.AfterAll") || + TypeUtils.isOfClassType(a.getType(), "org.junit.jupiter.api.BeforeAll")) { return true; } } diff --git a/src/main/java/org/openrewrite/java/testing/dbrider/ExecutionListenerToDbRiderAnnotation.java b/src/main/java/org/openrewrite/java/testing/dbrider/ExecutionListenerToDbRiderAnnotation.java new file mode 100644 index 000000000..93c1ac817 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/dbrider/ExecutionListenerToDbRiderAnnotation.java @@ -0,0 +1,265 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.dbrider; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.AnnotationMatcher; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Space; + +import java.util.Comparator; +import java.util.List; + +public class ExecutionListenerToDbRiderAnnotation extends Recipe { + + private static final AnnotationMatcher EXECUTION_LISTENER_ANNOTATION_MATCHER = new AnnotationMatcher("@org.springframework.test.context.TestExecutionListeners"); + private static final AnnotationMatcher DBRIDER_ANNOTATION_MATCHER = new AnnotationMatcher("@com.github.database.rider.junit5.api.DBRider"); + private static final String DBRIDER_TEST_EXECUTION_LISTENER = "com.github.database.rider.spring.DBRiderTestExecutionListener"; + + @Override + public String getDisplayName() { + return "Migrate the `DBRiderTestExecutionListener` to the `@DBRider` annotation"; + } + + @Override + public String getDescription() { + return "Migrate the `DBRiderTestExecutionListener` to the `@DBRider` annotation. " + + "This recipe is useful when migrating from JUnit 4 `dbrider-spring` to JUnit 5 `dbrider-junit5`."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesType<>(DBRIDER_TEST_EXECUTION_LISTENER, true), new JavaIsoVisitor() { + + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDeclaration, ExecutionContext ctx) { + J.ClassDeclaration cd = super.visitClassDeclaration(classDeclaration, ctx); + DbRiderExecutionListenerContext context = DbRiderExecutionListenerContext.ofClass(cd); + if (!context.shouldMigrate()) { + return cd; + } + if (context.shouldAddDbRiderAnnotation()) { + cd = JavaTemplate.builder("@DBRider") + .imports("com.github.database.rider.junit5.api.DBRider") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "rider-junit5-1.44")) + .build() + .apply(getCursor(), cd.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + maybeAddImport("com.github.database.rider.junit5.api.DBRider"); + } + Space prefix = cd.getLeadingAnnotations().get(cd.getLeadingAnnotations().size() - 1).getPrefix(); + return cd.withLeadingAnnotations(ListUtils.map(cd.getLeadingAnnotations(), annotation -> { + if (annotation != null && EXECUTION_LISTENER_ANNOTATION_MATCHER.matches(annotation)) { + J.Annotation executionListenerAnnotation = context.getExecutionListenerAnnotation(); + maybeRemoveImport(DBRIDER_TEST_EXECUTION_LISTENER); + maybeRemoveImport("org.springframework.test.context.TestExecutionListeners.MergeMode"); + maybeRemoveImport("org.springframework.test.context.TestExecutionListeners"); + if (executionListenerAnnotation != null) { + return executionListenerAnnotation + .withArguments(firstItemPrefixWorkaround(executionListenerAnnotation.getArguments())) + .withPrefix(prefix); + } + return null; + } + return annotation; + })); + } + }); + } + + private static class DbRiderExecutionListenerContext { + private J.@Nullable Annotation testExecutionListenerAnnotation; + private boolean dbriderFound = false; + private J.@Nullable NewArray listeners; + private J.@Nullable FieldAccess listener; + private @Nullable Expression inheritListeners; + private @Nullable Expression mergeMode; + + static DbRiderExecutionListenerContext ofClass(J.ClassDeclaration clazz) { + DbRiderExecutionListenerContext context = new DbRiderExecutionListenerContext(); + clazz.getLeadingAnnotations().forEach(annotation -> { + if (EXECUTION_LISTENER_ANNOTATION_MATCHER.matches(annotation)) { + context.testExecutionListenersFound(annotation); + } else if (DBRIDER_ANNOTATION_MATCHER.matches(annotation)) { + context.dbriderFound = true; + } + }); + return context; + } + + private void testExecutionListenersFound(final J.Annotation annotation) { + testExecutionListenerAnnotation = annotation; + if (annotation.getArguments() != null) { + annotation.getArguments().forEach(arg -> { + if (arg instanceof J.Assignment) { + J.Assignment assignment = (J.Assignment) arg; + switch (((J.Identifier) assignment.getVariable()).getSimpleName()) { + case "value": + case "listeners": + if (assignment.getAssignment() instanceof J.NewArray) { + listeners = (J.NewArray) assignment.getAssignment(); + } + break; + case "inheritListeners": + inheritListeners = assignment.getAssignment(); + break; + case "mergeMode": + mergeMode = assignment.getAssignment(); + break; + } + } else if (arg instanceof J.NewArray) { + listeners = (J.NewArray) arg; + } else if (arg instanceof J.FieldAccess) { + listener = (J.FieldAccess) arg; + } + }); + } + } + + public boolean shouldMigrate() { + return isTestExecutionListenerForDbRider() && !dbriderFound; + } + + public boolean shouldAddDbRiderAnnotation() { + if (dbriderFound) { + return false; + } + + return isTestExecutionListenerForDbRider(); + } + + public J.@Nullable Annotation getExecutionListenerAnnotation() { + if (isTestExecutionListenerForDbRider()) { + if (canTestExecutionListenerBeRemoved()) { + return null; + } + if (testExecutionListenerAnnotation != null && testExecutionListenerAnnotation.getArguments() != null) { + return testExecutionListenerAnnotation.withArguments(ListUtils.map(testExecutionListenerAnnotation.getArguments(), arg -> { + if (arg instanceof J.Assignment) { + J.Assignment assignment = (J.Assignment) arg; + Expression newValue = assignment.getAssignment(); + switch (((J.Identifier) assignment.getVariable()).getSimpleName()) { + case "value": + case "listeners": + if (assignment.getAssignment() instanceof J.NewArray) { + newValue = getMigratedListeners(); + } + break; + case "inheritListeners": + newValue = getMigratedInheritListeners(); + break; + case "mergeMode": + newValue = getMigratedMergeMode(); + break; + } + if (newValue == null) { + return null; + } + return assignment.withAssignment(newValue); + } else if (arg instanceof J.NewArray) { + return getMigratedListeners(); + } + if (arg instanceof J.FieldAccess && isTypeReference(arg, DBRIDER_TEST_EXECUTION_LISTENER)) { + return null; + } + return arg; + })); + } + } + + return testExecutionListenerAnnotation; + } + + // We can only remove an execution listener annotation if: + // - InheritListeners was null or true + // - MergeMode was TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS + // By default, the TestExecutionListeners.MergeMode is REPLACE_DEFAULTS so if we remove the annotation, other defaults would kick in. + private boolean canTestExecutionListenerBeRemoved() { + if (listener == null && listeners != null && listeners.getInitializer() != null && + listeners.getInitializer().stream().allMatch(listener -> isTypeReference(listener, DBRIDER_TEST_EXECUTION_LISTENER))) { + return (getMigratedInheritListeners() == null && getMigratedMergeMode() != null); + } + return false; + } + + private @Nullable Expression getMigratedMergeMode() { + if (mergeMode != null && mergeMode instanceof J.FieldAccess && "REPLACE_DEFAULTS".equals(((J.FieldAccess) mergeMode).getName().getSimpleName())) { + return null; + } + return mergeMode; + } + + private @Nullable Expression getMigratedInheritListeners() { + if (inheritListeners != null && (inheritListeners instanceof J.Literal && Boolean.TRUE.equals(((J.Literal) inheritListeners).getValue()))) { + return null; + } + return inheritListeners; + } + + // Remove the DBRiderTestExecutionListener from the listeners array + // If the listeners array is empty after removing the DBRiderTestExecutionListener, return null so that the array itself can be removed + private J.@Nullable NewArray getMigratedListeners() { + if (listeners != null && listeners.getInitializer() != null) { + List newListeners = ListUtils.map(listeners.getInitializer(), listener -> { + if (listener instanceof J.FieldAccess && isTypeReference(listener, DBRIDER_TEST_EXECUTION_LISTENER)) { + return null; + } + return listener; + }); + if (newListeners.isEmpty()) { + return null; + } + return listeners.withInitializer(firstItemPrefixWorkaround(newListeners)); + } + return listeners; + } + + private boolean isTestExecutionListenerForDbRider() { + if (listener != null) { + return isTypeReference(listener, DBRIDER_TEST_EXECUTION_LISTENER); + } + if (listeners != null && listeners.getInitializer() != null) { + return listeners.getInitializer().stream().anyMatch(listener -> isTypeReference(listener, DBRIDER_TEST_EXECUTION_LISTENER)); + } + return false; + } + + private static boolean isTypeReference(Expression expression, String type) { + return expression.getType() instanceof JavaType.Parameterized && + ((JavaType.Parameterized) expression.getType()).getFullyQualifiedName().equals("java.lang.Class") && + ((JavaType.Parameterized) expression.getType()).getTypeParameters().size() == 1 && + ((JavaType.Parameterized) expression.getType()).getTypeParameters().get(0) instanceof JavaType.Class && + ((JavaType.Class) ((JavaType.Parameterized) expression.getType()).getTypeParameters().get(0)).getFullyQualifiedName().equals(type); + } + } + + private static @Nullable List firstItemPrefixWorkaround(@Nullable List list) { + if (list == null || list.isEmpty()) { + return list; + } + return ListUtils.mapFirst(list, t -> t.withPrefix(t.getPrefix().withWhitespace(t.getPrefix().getLastWhitespace().replaceAll(" $", "")))); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/dbrider/package-info.java b/src/main/java/org/openrewrite/java/testing/dbrider/package-info.java new file mode 100644 index 000000000..8a8f30054 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/dbrider/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.java.testing.dbrider; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/src/main/java/org/openrewrite/java/testing/easymock/EasyMockVerifyToMockitoVerify.java b/src/main/java/org/openrewrite/java/testing/easymock/EasyMockVerifyToMockitoVerify.java new file mode 100644 index 000000000..c820c4039 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/easymock/EasyMockVerifyToMockitoVerify.java @@ -0,0 +1,135 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.easymock; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaCoordinates; +import org.openrewrite.java.tree.Statement; + +import java.util.ArrayList; +import java.util.List; + +import static java.lang.String.join; +import static java.util.Collections.nCopies; + +public class EasyMockVerifyToMockitoVerify extends Recipe { + + private static final MethodMatcher VERIFY_MATCHER = new MethodMatcher("org.easymock.EasyMock verify(..)", true); + private static final MethodMatcher EASY_MATCHER = new MethodMatcher("org.easymock.EasyMock expect(..)"); + + @Override + public String getDisplayName() { + return "Replace EasyMock `verify` calls with Mockito `verify` calls"; + } + + @Override + public String getDescription() { + return "Replace `EasyMock.verify(dependency)` with individual `Mockito.verify(dependency).method()` calls based on expected methods."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesMethod<>(VERIFY_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { + J.MethodDeclaration md = super.visitMethodDeclaration(method, ctx); + if (md.getBody() == null) { + return md; + } + + maybeAddImport("org.mockito.Mockito", "verify"); + maybeRemoveImport("org.easymock.EasyMock.verify"); + + int idx = 0; + for (Statement statement : md.getBody().getStatements()) { + if (statement instanceof J.MethodInvocation) { + J.MethodInvocation m = (J.MethodInvocation) statement; + if (VERIFY_MATCHER.matches(m) && m.getArguments().size() == 1 && m.getArguments().get(0) instanceof J.Identifier) { + J.Identifier dependency = (J.Identifier) m.getArguments().get(0); + List statementsAboveVerify = md.getBody().getStatements().subList(0, idx); + List expectedCalls = getExpectedCalls(dependency, statementsAboveVerify); + + for (int i = 0, expectedCallsSize = expectedCalls.size(); i < expectedCallsSize; i++) { + J.MethodInvocation expectedMethod = expectedCalls.get(i); + List parameters = expectedMethod.getArguments(); + if (parameters.size() == 1 && parameters.get(0) instanceof J.Empty) { + parameters.clear(); + } + String anyArgs = join(",", nCopies(parameters.size(), "#{any()}")); + parameters.add(0, dependency); + Statement currStatement = md.getBody().getStatements().get(idx); + JavaCoordinates coordinates = i == 0 ? currStatement.getCoordinates().replace() : currStatement.getCoordinates().after(); + md = JavaTemplate.builder("verify(#{any()})." + expectedMethod.getSimpleName() + "(" + anyArgs + ")") + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-core-5")) + .staticImports("org.mockito.Mockito.verify") + .build() + .apply(updateCursor(md), coordinates, parameters.toArray()); + if (i != 0) { + idx++; + } + } + } + } + idx++; + } + + return md; + } + + private List getExpectedCalls(J.Identifier dependency, List statementsAboveVerify) { + List expectedCalls = new ArrayList<>(); + for (Statement statement : statementsAboveVerify) { + if (statement instanceof J.MethodInvocation) { + J.MethodInvocation mi = (J.MethodInvocation) statement; + if (isExpectInvocation(mi, dependency)) { + expectedCalls.add((J.MethodInvocation) mi.getArguments().get(0)); + } else if (isExpectAndReturnInvocation(mi, dependency)) { + expectedCalls.add((J.MethodInvocation) ((J.MethodInvocation) mi.getSelect()).getArguments().get(0)); + } + } + } + return expectedCalls; + } + + // match: expect(.someMethod()); + private boolean isExpectInvocation(J.MethodInvocation mi, J.Identifier dependency) { + return EASY_MATCHER.matches(mi) && + mi.getArguments().size() == 1 && + mi.getArguments().get(0) instanceof J.MethodInvocation && + ((J.MethodInvocation) mi.getArguments().get(0)).getSelect() instanceof J.Identifier && + dependency.getSimpleName().equals(((J.Identifier) ((J.MethodInvocation) mi.getArguments().get(0)).getSelect()).getSimpleName()); + } + + // match: expect(.someMethod()).andReturn(); + private boolean isExpectAndReturnInvocation(J.MethodInvocation m, J.Identifier dependency) { + return EASY_MATCHER.matches(m.getSelect()) && + m.getSelect() instanceof J.MethodInvocation && + isExpectInvocation((J.MethodInvocation) m.getSelect(), dependency); + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/easymock/RemoveExtendsEasyMockSupport.java b/src/main/java/org/openrewrite/java/testing/easymock/RemoveExtendsEasyMockSupport.java new file mode 100644 index 000000000..6f76d4290 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/easymock/RemoveExtendsEasyMockSupport.java @@ -0,0 +1,56 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.easymock; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.TypeUtils; + +public class RemoveExtendsEasyMockSupport extends Recipe { + + private static final String EASYMOCK = "org.easymock.EasyMockSupport"; + + @Override + public String getDisplayName() { + return "Migrate Test classes that extend `org.easymock.EasyMockSupport` to use Mockito"; + } + + @Override + public String getDescription() { + return "Modify test classes by removing extends EasyMockSupport and replacing EasyMock methods with Mockito equivalents."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesType<>(EASYMOCK, false), new JavaIsoVisitor() { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx); + + if (cd.getExtends() != null && TypeUtils.isAssignableTo(EASYMOCK, cd.getExtends().getType())) { + maybeRemoveImport(EASYMOCK); + cd = cd.withExtends(null); + } + return cd; + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/easymock/package-info.java b/src/main/java/org/openrewrite/java/testing/easymock/package-info.java new file mode 100644 index 000000000..a8a0f7300 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/easymock/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package org.openrewrite.java.testing.easymock; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/openrewrite/java/testing/hamcrest/HamcrestInstanceOfToJUnit5.java b/src/main/java/org/openrewrite/java/testing/hamcrest/HamcrestInstanceOfToJUnit5.java new file mode 100644 index 000000000..0fbcdb35f --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/hamcrest/HamcrestInstanceOfToJUnit5.java @@ -0,0 +1,116 @@ +/* + * Copyright 2023 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; + +import java.util.ArrayList; +import java.util.List; + +public class HamcrestInstanceOfToJUnit5 extends Recipe { + @Override + public String getDisplayName() { + return "Migrate from Hamcrest `instanceOf` matcher to JUnit 5"; + } + + @Override + public String getDescription() { + return "Migrate from Hamcrest `instanceOf` and `isA` matcher to JUnit5 `assertInstanceOf` assertion."; + } + + private static final MethodMatcher INSTANCE_OF_MATCHER = new MethodMatcher("org.hamcrest.Matchers instanceOf(..)"); + private static final MethodMatcher IS_A_MATCHER = new MethodMatcher("org.hamcrest.Matchers isA(..)"); + private static final MethodMatcher ASSERT_THAT_MATCHER = new MethodMatcher("org.hamcrest.MatcherAssert assertThat(.., org.hamcrest.Matcher)"); + + @Override + public TreeVisitor getVisitor() { + TreeVisitor preconditions = Preconditions.and( + new UsesMethod<>(ASSERT_THAT_MATCHER), + Preconditions.or( + new UsesMethod<>(INSTANCE_OF_MATCHER), + new UsesMethod<>(IS_A_MATCHER))); + return Preconditions.check(preconditions, new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) { + if (ASSERT_THAT_MATCHER.matches(mi)) { + Expression reason; + Expression examinedObject; + Expression hamcrestMatcher; + + if (mi.getArguments().size() == 2) { + reason = null; + examinedObject = mi.getArguments().get(0); + hamcrestMatcher = mi.getArguments().get(1); + } else if (mi.getArguments().size() == 3) { + reason = mi.getArguments().get(0); + examinedObject = mi.getArguments().get(1); + hamcrestMatcher = mi.getArguments().get(2); + } else { + return mi; + } + + J.MethodInvocation matcherInvocation = (J.MethodInvocation) hamcrestMatcher; + while ("not".equals(matcherInvocation.getSimpleName())) { + maybeRemoveImport("org.hamcrest.Matchers.not"); + maybeRemoveImport("org.hamcrest.CoreMatchers.not"); + matcherInvocation = (J.MethodInvocation) new RemoveNotMatcherVisitor().visit(matcherInvocation, ctx); + } + + if (INSTANCE_OF_MATCHER.matches(matcherInvocation) || IS_A_MATCHER.matches(matcherInvocation)) { + boolean logicalContext = RemoveNotMatcherVisitor.getLogicalContext(matcherInvocation, ctx); + + String templateString = (logicalContext ? + "assertInstanceOf(#{any(java.lang.Class)}, #{any(java.lang.Object)}" : + "assertFalse(#{any(java.lang.Class)}.isAssignableFrom(#{any(java.lang.Object)}.getClass())") + + (reason == null ? ")" : ", #{any(java.lang.String)})"); + + JavaTemplate template = JavaTemplate.builder(templateString) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-5.9")) + .staticImports("org.junit.jupiter.api.Assertions." + (logicalContext ? "assertInstanceOf" : "assertFalse")) + .build(); + + maybeRemoveImport("org.hamcrest.MatcherAssert.assertThat"); + maybeRemoveImport("org.hamcrest.Matchers.instanceOf"); + maybeRemoveImport("org.hamcrest.CoreMatchers.instanceOf"); + maybeRemoveImport("org.hamcrest.Matchers.isA"); + maybeRemoveImport("org.hamcrest.CoreMatchers.isA"); + maybeAddImport("org.junit.jupiter.api.Assertions", logicalContext ? "assertInstanceOf" : "assertFalse"); + + List arguments = new ArrayList<>(); + arguments.add(matcherInvocation.getArguments().get(0)); + arguments.add(examinedObject); + if (reason != null) { + arguments.add(reason); + } + + return template.apply(getCursor(), mi.getCoordinates().replace(), arguments.toArray()); + } + } + return super.visitMethodInvocation(mi, ctx); + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/hamcrest/HamcrestMatcherToJUnit5.java b/src/main/java/org/openrewrite/java/testing/hamcrest/HamcrestMatcherToJUnit5.java new file mode 100644 index 000000000..fe3a9a4dc --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/hamcrest/HamcrestMatcherToJUnit5.java @@ -0,0 +1,191 @@ +/* + * Copyright 2023 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +public class HamcrestMatcherToJUnit5 extends Recipe { + + private static final MethodMatcher MATCHER_ASSERT_MATCHER = new MethodMatcher("org.hamcrest.MatcherAssert assertThat(.., org.hamcrest.Matcher)"); + + @Override + public String getDisplayName() { + return "Migrate from Hamcrest `Matcher` to JUnit 5"; + } + + @Override + public String getDescription() { + return "Migrate from Hamcrest `Matcher` to JUnit 5 assertions."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + new UsesMethod<>(MATCHER_ASSERT_MATCHER), + new MigrationFromHamcrestVisitor()); + } + + enum Replacement { + EQUALTO("equalTo", "assertEquals", "assertNotEquals", "#{any(java.lang.Object)}, #{any(java.lang.Object)}", "examinedObjThenMatcherArgs"), + EMPTYARRAY("emptyArray", "assertEquals", "assertNotEquals", "0, #{anyArray(java.lang.Object)}.length", "examinedObjOnly"), + HASENTRY("hasEntry", "assertEquals", "assertNotEquals", "#{any(java.lang.Object)}, #{any(java.util.Map)}.get(#{any(java.lang.Object)})", "matcher1ExaminedObjMatcher0"), + HASSIZE("hasSize", "assertEquals", "assertNotEquals", "#{any(java.util.Collection)}.size(), #{any(double)}", "examinedObjThenMatcherArgs"), + HASTOSTRING("hasToString", "assertEquals", "assertNotEquals", "#{any(java.lang.Object)}.toString(), #{any(java.lang.String)}", "examinedObjThenMatcherArgs"), + CLOSETO("closeTo", "assertTrue", "assertFalse", "Math.abs(#{any(double)} - #{any(double)}) < #{any(double)}", "examinedObjThenMatcherArgs"), + CONTAINSSTRING("containsString", "assertTrue", "assertFalse", "#{any(java.lang.String)}.contains(#{any(java.lang.String)}", "examinedObjThenMatcherArgs"), + EMPTY("empty", "assertTrue", "assertFalse", "#{any(java.util.Collection)}.isEmpty()", "examinedObjOnly"), + ENDSWITH("endsWith", "assertTrue", "assertFalse", "#{any(java.lang.String)}.endsWith(#{any(java.lang.String)})", "examinedObjThenMatcherArgs"), + EQUALTOIGNORINGCASE("equalToIgnoringCase", "assertTrue", "assertFalse", "#{any(java.lang.String)}.equalsIgnoreCase(#{any(java.lang.String)})", "examinedObjThenMatcherArgs"), + GREATERTHAN("greaterThan", "assertTrue", "assertFalse", "#{any(double)} > #{any(double)}", "examinedObjThenMatcherArgs"), + GREATERTHANOREQUALTO("greaterThanOrEqualTo", "assertTrue", "assertFalse", "#{any(double)} >= #{any(double)}", "examinedObjThenMatcherArgs"), + HASKEY("hasKey", "assertTrue", "assertFalse", "#{any(java.util.Map)}.containsKey(#{any(java.lang.Object)})", "examinedObjThenMatcherArgs"), + HASVALUE("hasValue", "assertTrue", "assertFalse", "#{any(java.util.Map)}.containsValue(#{any(java.lang.Object)})", "examinedObjThenMatcherArgs"), + LESSTHAN("lessThan", "assertTrue", "assertFalse", "#{any(double)} < #{any(double)}", "examinedObjThenMatcherArgs"), + LESSTHANOREQUALTO("lessThanOrEqualTo", "assertTrue", "assertFalse", "#{any(double)} <= #{any(double)}", "examinedObjThenMatcherArgs"), + STARTSWITH("startsWith", "assertTrue", "assertFalse", "#{any(java.lang.String)}.startsWith(#{any(java.lang.String)})", "examinedObjThenMatcherArgs"), + TYPECOMPATIBLEWITH("typeCompatibleWith", "assertTrue", "assertFalse", "#{any(java.lang.Class)}.isAssignableFrom(#{any(java.lang.Class)})", "matcherArgsThenExaminedObj"), + NOTNULLVALUE("notNullValue", "assertNotNull", "assertNull", "#{any(java.lang.Object)}", "examinedObjOnly"), + NULLVALUE("nullValue", "assertNull", "assertNotNull", "#{any(java.lang.Object)}", "examinedObjOnly"), + SAMEINSTANCE("sameInstance", "assertSame", "assertNotSame", "#{any(java.lang.Object)}, #{any(java.lang.Object)}", "examinedObjThenMatcherArgs"), + THEINSTANCE("theInstance", "assertSame", "assertNotSame", "#{any(java.lang.Object)}, #{any(java.lang.Object)}", "examinedObjThenMatcherArgs"), + EMPTYITERABLE("emptyIterable", "assertFalse", "assertTrue", "#{any(java.lang.Iterable)}.iterator().hasNext()", "examinedObjOnly"); + + final String hamcrest, junitPositive, junitNegative, template; + final String argumentsMethod; + + private static final Map>> methods = new HashMap<>(); + + static { + methods.put("examinedObjThenMatcherArgs", (ex, matcher) -> { + List arguments = matcher.getArguments(); + arguments.add(0, ex); + return arguments; + }); + methods.put("matcherArgsThenExaminedObj", (ex, matcher) -> { + List arguments = matcher.getArguments(); + arguments.add(ex); + return arguments; + }); + methods.put("examinedObjOnly", (ex, matcher) -> { + List arguments = new ArrayList<>(); + arguments.add(ex); + return arguments; + }); + methods.put("matcher1ExaminedObjMatcher0", (ex, matcher) -> { + List arguments = new ArrayList<>(); + arguments.add(matcher.getArguments().get(1)); + arguments.add(ex); + arguments.add(matcher.getArguments().get(0)); + return arguments; + }); + } + + Replacement(String hamcrest, String junitPositive, String junitNegative, String template, String argumentsMethod) { + this.hamcrest = hamcrest; + this.junitPositive = junitPositive; + this.junitNegative = junitNegative; + this.template = template; + this.argumentsMethod = argumentsMethod; + } + } + + private static class MigrationFromHamcrestVisitor extends JavaIsoVisitor { + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + + if (MATCHER_ASSERT_MATCHER.matches(mi)) { + Expression reason; + Expression examinedObject; + Expression hamcrestMatcher; + + if (mi.getArguments().size() == 2) { + reason = null; + examinedObject = mi.getArguments().get(0); + hamcrestMatcher = mi.getArguments().get(1); + } else if (mi.getArguments().size() == 3) { + reason = mi.getArguments().get(0); + examinedObject = mi.getArguments().get(1); + hamcrestMatcher = mi.getArguments().get(2); + } else { + return mi; + } + + if (hamcrestMatcher instanceof J.MethodInvocation) { + J.MethodInvocation matcherInvocation = (J.MethodInvocation) hamcrestMatcher; + maybeRemoveImport("org.hamcrest.MatcherAssert.assertThat"); + + while ("not".equals(matcherInvocation.getSimpleName())) { + maybeRemoveImport("org.hamcrest.Matchers.not"); + maybeRemoveImport("org.hamcrest.CoreMatchers.not"); + matcherInvocation = (J.MethodInvocation) new RemoveNotMatcherVisitor().visit(matcherInvocation, ctx); + } + + //we do not handle nested matchers + if (!(matcherInvocation.getArguments().get(0) instanceof J.Empty)) { + if ((matcherInvocation.getArguments().get(0).getType()).toString().startsWith("org.hamcrest")) { + return mi; + } + } + + boolean logicalContext = RemoveNotMatcherVisitor.getLogicalContext(matcherInvocation, ctx); + + Replacement replacement; + try { + replacement = Replacement.valueOf(matcherInvocation.getSimpleName().toUpperCase()); + } catch (IllegalArgumentException e) { + return mi; + } + String assertion = logicalContext ? replacement.junitPositive : replacement.junitNegative; + String templateString = assertion + "(" + replacement.template + (reason == null ? ")" : ", #{any(java.lang.String)})"); + JavaTemplate template = JavaTemplate.builder(templateString) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-5.9")) + .staticImports("org.junit.jupiter.api.Assertions." + assertion) + .build(); + + maybeRemoveImport("org.hamcrest.Matchers." + replacement.hamcrest); + maybeRemoveImport("org.hamcrest.CoreMatchers." + replacement.hamcrest); + maybeAddImport("org.junit.jupiter.api.Assertions", assertion); + + List arguments = Replacement.methods.get(replacement.argumentsMethod).apply(examinedObject, matcherInvocation); + if (reason != null) { + arguments.add(reason); + } + + return template.apply(getCursor(), method.getCoordinates().replace(), arguments.toArray()); + } + } + return mi; + } + } +} diff --git a/src/main/java/org/openrewrite/java/testing/hamcrest/RemoveNotMatcherVisitor.java b/src/main/java/org/openrewrite/java/testing/hamcrest/RemoveNotMatcherVisitor.java new file mode 100644 index 000000000..cd0413de5 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/hamcrest/RemoveNotMatcherVisitor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.J; + +import java.security.InvalidParameterException; +import java.util.Objects; + +class RemoveNotMatcherVisitor extends JavaIsoVisitor { + static final MethodMatcher NOT_MATCHER = new MethodMatcher("org.hamcrest.Matchers not(..)"); + + public static boolean getLogicalContext(J.MethodInvocation mi, ExecutionContext ctx) throws InvalidParameterException { + Object msg = ctx.getMessage(mi.toString()); + if (msg == null) { + return true; + } else if (msg instanceof Boolean) { + return (Boolean) msg; + } else { + throw new InvalidParameterException(); + } + } + + @Override + @SuppressWarnings("ConstantConditions") + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) { + if (NOT_MATCHER.matches(mi)) { + boolean logicalContext; + if (ctx.pollMessage(mi.toString()) != null) { + logicalContext = ctx.getMessage(mi.toString()); + } else { + logicalContext = true; + } + + maybeRemoveImport("org.hamcrest.Matchers.not"); + + J.MethodInvocation result; + if (Objects.requireNonNull(mi.getArguments().get(0).getType()).toString().startsWith("org.hamcrest")) { + result = mi.getArguments().get(0).withPrefix(mi.getPrefix()); + } else { + JavaTemplate template = JavaTemplate.builder("equalTo(#{any(java.lang.Object)})") + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "hamcrest-2.2")) + .staticImports("org.hamcrest.Matchers.equalTo") + .build(); + maybeAddImport("org.hamcrest.Matchers", "equalTo"); + result = template.apply(getCursor(), mi.getCoordinates().replace(), mi.getArguments().get(0)); + } + + ctx.putMessage(result.toString(), !logicalContext); + + return result; + } else { + if (ctx.pollMessage(mi.toString()) == null) { + ctx.putMessage(mi.toString(), true); + } + } + return super.visitMethodInvocation(mi, ctx); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/ArgumentMatchersRewriter.java b/src/main/java/org/openrewrite/java/testing/jmockit/ArgumentMatchersRewriter.java index 8b24ee034..66521b1fc 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/ArgumentMatchersRewriter.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/ArgumentMatchersRewriter.java @@ -99,17 +99,23 @@ private J.MethodInvocation rewriteMethodInvocation(J.MethodInvocation invocation if (invocation.getSelect() instanceof J.MethodInvocation) { invocation = invocation.withSelect(rewriteMethodInvocation((J.MethodInvocation) invocation.getSelect())); } + // in mockito, argument matchers must be used for all arguments or none - boolean hasArgumentMatcher = false; List arguments = invocation.getArguments(); - for (Expression methodArgument : arguments) { - if (isJmockitArgumentMatcher(methodArgument)) { - hasArgumentMatcher = true; - break; + // replace this.matcher with matcher, otherwise it's ignored + arguments.replaceAll(arg -> { + if (arg instanceof J.FieldAccess) { + J.FieldAccess fieldAccess = (J.FieldAccess) arg; + if (fieldAccess.getTarget() instanceof J.Identifier && + "this".equals(((J.Identifier) fieldAccess.getTarget()).getSimpleName())) { + return fieldAccess.getName(); + } } - } + return arg; + }); + // if there are no argument matchers, return the invocation as-is - if (!hasArgumentMatcher) { + if (arguments.stream().noneMatch(ArgumentMatchersRewriter::isJmockitArgumentMatcher)) { return invocation; } // replace each argument with the appropriate argument matcher @@ -145,9 +151,9 @@ private Expression rewriteMethodArgument(Expression methodArgument) { // ((int) any) to anyInt(), ((long) any) to anyLong(), etc argumentMatcher = PRIMITIVE_TO_MOCKITO_ARGUMENT_MATCHER.get(type); template = argumentMatcher + "()"; - } else if (type instanceof JavaType.FullyQualified) { - // (() any) to any(.class) - return rewriteFullyQualifiedToArgumentMatcher(methodArgument, (JavaType.FullyQualified) type); + } else if (type instanceof JavaType.FullyQualified || type instanceof JavaType.Array) { + // (() any) to any(.class), type can also be simple array + return rewriteAnyWithClassParameterToArgumentMatcher(methodArgument, type); } if (template == null || argumentMatcher == null) { // unhandled type, return argument unchanged @@ -157,17 +163,16 @@ private Expression rewriteMethodArgument(Expression methodArgument) { } private Expression applyArgumentTemplate(Expression methodArgument, String argumentMatcher, String template, - List templateParams) { + List templateParams) { visitor.maybeAddImport("org.mockito.Mockito", argumentMatcher); return JavaTemplate.builder(template) - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-core-3.12")) + .javaParser(JMockitUtils.getJavaParser(ctx)) .staticImports("org.mockito.Mockito." + argumentMatcher) .build() .apply( new Cursor(visitor.getCursor(), methodArgument), methodArgument.getCoordinates().replace(), - templateParams.toArray() - ); + templateParams.toArray()); } private Expression applyClassArgumentTemplate(Expression methodArgument, JavaType.FullyQualified type) { @@ -179,45 +184,72 @@ private Expression applyClassArgumentTemplate(Expression methodArgument, JavaTyp .apply( new Cursor(visitor.getCursor(), methodArgument), methodArgument.getCoordinates().replace(), - type.getClassName() - )) + type.getClassName())) .withType(type); } - private Expression rewriteFullyQualifiedToArgumentMatcher(Expression methodArgument, JavaType.FullyQualified type) { + private Expression rewriteAnyWithClassParameterToArgumentMatcher(Expression methodArgument, JavaType type) { String template; List templateParams = new ArrayList<>(); - String argumentMatcher = FQN_TO_MOCKITO_ARGUMENT_MATCHER.get(type.getFullyQualifiedName()); - if (argumentMatcher != null) { - // mockito has convenience argument matchers - template = argumentMatcher + "()"; - return applyArgumentTemplate(methodArgument, argumentMatcher, template, templateParams); + + if (type instanceof JavaType.FullyQualified) { + JavaType.FullyQualified fq = (JavaType.FullyQualified) type; + String argumentMatcher = FQN_TO_MOCKITO_ARGUMENT_MATCHER.get(fq.getFullyQualifiedName()); + if (argumentMatcher != null) { + // mockito has convenience argument matchers + template = argumentMatcher + "()"; + return applyArgumentTemplate(methodArgument, argumentMatcher, template, templateParams); + } } // mockito uses any(Class) for all other types - argumentMatcher = "any"; + String argumentMatcher = "any"; template = argumentMatcher + "(#{any(java.lang.Class)})"; - templateParams.add(applyClassArgumentTemplate(methodArgument, type)); + + if (type instanceof JavaType.FullyQualified) { + templateParams.add(applyClassArgumentTemplate(methodArgument, (JavaType.FullyQualified) type)); + } else if (type instanceof JavaType.Array) { + templateParams.add(applyArrayClassArgumentTemplate(methodArgument, ((JavaType.Array) type).getElemType())); + } J.MethodInvocation invocationArgument = (J.MethodInvocation) applyArgumentTemplate(methodArgument, argumentMatcher, template, templateParams); // update the Class type parameter and method return type Expression classArgument = (Expression) templateParams.get(0); - if (classArgument.getType() == null - || invocationArgument.getMethodType() == null - || invocationArgument.getMethodType().getParameterTypes().size() != 1 - || !(invocationArgument.getMethodType().getParameterTypes().get(0) instanceof JavaType.Parameterized)) { + if (classArgument.getType() == null || + invocationArgument.getMethodType() == null || + invocationArgument.getMethodType().getParameterTypes().size() != 1 || + !(invocationArgument.getMethodType().getParameterTypes().get(0) instanceof JavaType.Parameterized)) { return invocationArgument; } - JavaType.Parameterized newParameterType = - ((JavaType.Parameterized) invocationArgument.getMethodType().getParameterTypes().get(0)) - .withTypeParameters(Collections.singletonList(classArgument.getType())); + JavaType.Parameterized newParameterType = ((JavaType.Parameterized) invocationArgument.getMethodType() + .getParameterTypes().get(0)) + .withTypeParameters(Collections.singletonList(classArgument.getType())); JavaType.Method newMethodType = invocationArgument.getMethodType() .withReturnType(classArgument.getType()) .withParameterTypes(Collections.singletonList(newParameterType)); return invocationArgument.withMethodType(newMethodType); } + private Expression applyArrayClassArgumentTemplate(Expression methodArgument, JavaType elementType) { + String newArrayElementClassName; + if (elementType instanceof JavaType.FullyQualified) { + newArrayElementClassName = ((JavaType.FullyQualified) elementType).getClassName(); + } else if (elementType instanceof JavaType.Primitive) { + newArrayElementClassName = ((JavaType.Primitive) elementType).getKeyword(); + } else { + newArrayElementClassName = elementType.getClass().getName(); + } + + return JavaTemplate.builder("#{}[].class") + .javaParser(JavaParser.fromJavaVersion()) + .build() + .apply( + new Cursor(visitor.getCursor(), methodArgument), + methodArgument.getCoordinates().replace(), + newArrayElementClassName); + } + private static boolean isJmockitArgumentMatcher(Expression expression) { if (expression instanceof J.TypeCast) { expression = ((J.TypeCast) expression).getExpression(); diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockito.java b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockito.java index 0bc1fe9dd..355b6d106 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockito.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockito.java @@ -22,7 +22,6 @@ import org.openrewrite.TreeVisitor; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.search.FindAnnotations; import org.openrewrite.java.search.UsesType; @@ -32,6 +31,8 @@ import java.util.ArrayList; import java.util.List; +import static org.openrewrite.java.testing.jmockit.JMockitUtils.getJavaParser; + @EqualsAndHashCode(callSuper = false) public class JMockitAnnotatedArgumentToMockito extends Recipe { @Override @@ -82,7 +83,7 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl // Add mocked parameters as statements to the method declaration if (!mockedParameter.isEmpty()) { JavaTemplate addStatementsTemplate = JavaTemplate.builder("#{} #{} = Mockito.mock(#{}.class);\n") - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-core-3.12")) + .javaParser(getJavaParser(ctx)) .imports("org.mockito.Mockito") .contextSensitive() .build(); diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockRewriter.java b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockRewriter.java index 4dc1df56f..676bac373 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockRewriter.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockRewriter.java @@ -29,20 +29,24 @@ import java.util.ArrayList; import java.util.List; -import static org.openrewrite.java.testing.jmockit.JMockitBlockType.NonStrictExpectations; -import static org.openrewrite.java.testing.jmockit.JMockitBlockType.Verifications; +import static org.openrewrite.java.testing.jmockit.JMockitBlockType.*; +import static org.openrewrite.java.testing.jmockit.JMockitUtils.MOCKITO_ALL_IMPORT; +import static org.openrewrite.java.testing.jmockit.JMockitUtils.getJavaParser; class JMockitBlockRewriter { private static final String WHEN_TEMPLATE_PREFIX = "when(#{any()})."; private static final String VERIFY_TEMPLATE_PREFIX = "verify(#{any()}"; + private static final String VERIFY_NO_INTERACTIONS_TEMPLATE_PREFIX = "verifyNoMoreInteractions("; + private static final String VERIFY_IN_ORDER_TEMPLATE_PREFIX_1 = "InOrder inOrder"; + private static final String VERIFY_IN_ORDER_TEMPLATE_PREFIX_2 = " = inOrder("; private static final String LENIENT_TEMPLATE_PREFIX = "lenient()."; - private static final String RETURN_TEMPLATE_PREFIX = "thenReturn("; private static final String THROW_TEMPLATE_PREFIX = "thenThrow("; private static final String LITERAL_TEMPLATE_FIELD = "#{}"; private static final String ANY_TEMPLATE_FIELD = "#{any()}"; private static final String MOCKITO_IMPORT_FQN_PREFX = "org.mockito.Mockito"; + private static final String IN_ORDER_IMPORT_FQN = "org.mockito.InOrder"; private static String getObjectTemplateField(String fqn) { return "#{any(" + fqn + ")}"; @@ -52,6 +56,7 @@ private static String getObjectTemplateField(String fqn) { private final ExecutionContext ctx; private final J.NewClass newExpectations; private final JMockitBlockType blockType; + private final int verificationsInOrderIdx; // index of the Expectations block in the method body private final int bodyStatementIndex; private J.Block methodBody; @@ -68,13 +73,14 @@ boolean isRewriteFailed() { private int numStatementsAdded = 0; JMockitBlockRewriter(JavaVisitor visitor, ExecutionContext ctx, J.Block methodBody, - J.NewClass newExpectations, int bodyStatementIndex, JMockitBlockType blockType) { + J.NewClass newExpectations, int bodyStatementIndex, JMockitBlockType blockType, int verificationsInOrderIdx) { this.visitor = visitor; this.ctx = ctx; this.methodBody = methodBody; this.newExpectations = newExpectations; this.bodyStatementIndex = bodyStatementIndex; this.blockType = blockType; + this.verificationsInOrderIdx = verificationsInOrderIdx; this.nextStatementCoordinates = newExpectations.getCoordinates().replace(); } @@ -95,17 +101,27 @@ J.Block rewriteMethodBody() { // iterate over the statements and build a list of grouped method invocations and related statements eg times List> methodInvocationsToRewrite = new ArrayList<>(); + List uniqueMocks = new ArrayList<>(); int methodInvocationIdx = -1; for (Statement jmockitBlockStatement : jmockitBlock.getStatements()) { if (jmockitBlockStatement instanceof J.MethodInvocation) { - // ensure it's not a returns statement, we add that later to related statements J.MethodInvocation invocation = (J.MethodInvocation) jmockitBlockStatement; - if (invocation.getSelect() != null && !invocation.getName().getSimpleName().equals("returns")) { - methodInvocationIdx++; - methodInvocationsToRewrite.add(new ArrayList<>()); + Expression select = invocation.getSelect(); + if (select instanceof J.Identifier) { + J.Identifier mockObj = (J.Identifier) select; + // ensure it's not a returns statement, we add that later to related statements + if (!invocation.getName().getSimpleName().equals("returns")) { + methodInvocationIdx++; + methodInvocationsToRewrite.add(new ArrayList<>()); + } + if ((isFullVerifications() || isVerificationsInOrder()) && + uniqueMocks.stream().noneMatch(mock -> mock.getSimpleName().equals(mockObj.getSimpleName()))) { + uniqueMocks.add(mockObj); + } } } + // add the statements corresponding to the method invocation if (methodInvocationIdx != -1) { methodInvocationsToRewrite.get(methodInvocationIdx).add(jmockitBlockStatement); } @@ -116,11 +132,28 @@ J.Block rewriteMethodBody() { removeBlock(); } + List mocks = new ArrayList<>(uniqueMocks); + if (isVerificationsInOrder()) { + rewriteInOrderVerify(mocks); + } + // now rewrite methodInvocationsToRewrite.forEach(this::rewriteMethodInvocation); + + if (isFullVerifications()) { + rewriteFullVerify(mocks); + } return methodBody; } + private boolean isFullVerifications() { + return this.blockType == FullVerifications; + } + + private boolean isVerificationsInOrder() { + return this.blockType == VerificationsInOrder; + } + private void rewriteMethodInvocation(List statementsToRewrite) { final MockInvocationResults mockInvocationResults = buildMockInvocationResults(statementsToRewrite); if (mockInvocationResults == null) { @@ -136,7 +169,7 @@ private void rewriteMethodInvocation(List statementsToRewrite) { rewriteResult(invocation, mockInvocationResults.getResults(), hasTimes); } - if (!hasResults && !hasTimes && (this.blockType == JMockitBlockType.Expectations || this.blockType == Verifications)) { + if (!hasResults && !hasTimes && (this.blockType == JMockitBlockType.Expectations || this.blockType.isVerifications())) { rewriteVerify(invocation, null, ""); return; } @@ -171,7 +204,7 @@ private void rewriteResult(J.MethodInvocation invocation, List resul List templateParams = new ArrayList<>(); templateParams.add(invocation); templateParams.addAll(results); - this.rewriteFailed = !rewriteTemplate(template, templateParams, nextStatementCoordinates); + rewriteTemplate(template, templateParams, nextStatementCoordinates); if (this.rewriteFailed) { return; } @@ -199,19 +232,19 @@ private void rewriteVerify(J.MethodInvocation invocation, @Nullable Expression t templateParams.add(invocation.getName().getSimpleName()); String verifyTemplate = getVerifyTemplate(invocation.getArguments(), verificationMode, templateParams); JavaCoordinates verifyCoordinates; - if (this.blockType == Verifications) { + if (this.blockType.isVerifications()) { // for Verifications, replace the Verifications block verifyCoordinates = nextStatementCoordinates; } else { - // for Expectations put the verify at the end of the method + // for Expectations put verify at the end of the method verifyCoordinates = methodBody.getCoordinates().lastStatement(); } - this.rewriteFailed = !rewriteTemplate(verifyTemplate, templateParams, verifyCoordinates); + rewriteTemplate(verifyTemplate, templateParams, verifyCoordinates); if (this.rewriteFailed) { return; } - if (this.blockType == Verifications) { + if (this.blockType.isVerifications()) { setNextStatementCoordinates(++numStatementsAdded); // for Expectations, verify statements added to end of method } @@ -223,6 +256,39 @@ private void rewriteVerify(J.MethodInvocation invocation, @Nullable Expression t } } + private void rewriteFullVerify(List mocks) { + if (rewriteMultipleMocks(mocks, VERIFY_NO_INTERACTIONS_TEMPLATE_PREFIX)) { // verifyNoMoreInteractions(mock1, mock2 ... + visitor.maybeAddImport(MOCKITO_IMPORT_FQN_PREFX, "verifyNoMoreInteractions", false); + } + } + + private void rewriteInOrderVerify(List mocks) { + StringBuilder sb = new StringBuilder(VERIFY_IN_ORDER_TEMPLATE_PREFIX_1); // InOrder inOrder + if (verificationsInOrderIdx > 0) { + sb.append(verificationsInOrderIdx); // InOrder inOrder1 + } + sb.append(VERIFY_IN_ORDER_TEMPLATE_PREFIX_2); // InOrder inOrder1 = inOrder( + if (rewriteMultipleMocks(mocks, sb.toString())) { // InOrder inOrder = inOrder(mock1, mock2 ..) + visitor.maybeAddImport(MOCKITO_IMPORT_FQN_PREFX, "inOrder", false); + visitor.maybeAddImport(IN_ORDER_IMPORT_FQN); + } + } + + private boolean rewriteMultipleMocks(List mocks, String template) { + if (mocks.isEmpty()) { + return false; + } + StringBuilder sb = new StringBuilder(template); + mocks.forEach(mock -> sb.append(ANY_TEMPLATE_FIELD).append(", ")); + sb.delete(sb.length() - 2, sb.length()); + sb.append(");"); + rewriteTemplate(sb.toString(), mocks, nextStatementCoordinates); + if (!this.rewriteFailed) { + setNextStatementCoordinates(++numStatementsAdded); + } + return !this.rewriteFailed; + } + private void setNextStatementCoordinates(int numStatementsAdded) { if (numStatementsAdded <= 0 && bodyStatementIndex == 0) { nextStatementCoordinates = methodBody.getCoordinates().firstStatement(); @@ -240,19 +306,16 @@ private void setNextStatementCoordinates(int numStatementsAdded) { this.nextStatementCoordinates = this.methodBody.getStatements().get(lastStatementIdx).getCoordinates().after(); } - private boolean rewriteTemplate(String template, List templateParams, JavaCoordinates + private void rewriteTemplate(String template, List templateParams, JavaCoordinates rewriteCoords) { int numStatementsBefore = methodBody.getStatements().size(); methodBody = JavaTemplate.builder(template) - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-core-3.12")) - .staticImports("org.mockito.Mockito.*") + .javaParser(getJavaParser(ctx)) + .staticImports(MOCKITO_ALL_IMPORT) + .imports(IN_ORDER_IMPORT_FQN) .build() - .apply( - new Cursor(visitor.getCursor(), methodBody), - rewriteCoords, - templateParams.toArray() - ); - return methodBody.getStatements().size() > numStatementsBefore; + .apply(new Cursor(visitor.getCursor(), methodBody), rewriteCoords, templateParams.toArray()); + this.rewriteFailed = methodBody.getStatements().size() <= numStatementsBefore; } private @Nullable String getWhenTemplate(List results, boolean lenient) { @@ -291,7 +354,8 @@ private boolean rewriteTemplate(String template, List templateParams, Ja return templateBuilder.toString(); } - private static void appendToTemplate(StringBuilder templateBuilder, boolean buildingResults, String templatePrefix, + private static void appendToTemplate(StringBuilder templateBuilder, boolean buildingResults, String + templatePrefix, String templateField) { if (!buildingResults) { templateBuilder.append(templatePrefix); @@ -301,8 +365,17 @@ private static void appendToTemplate(StringBuilder templateBuilder, boolean buil templateBuilder.append(templateField); } - private static String getVerifyTemplate(List arguments, String verificationMode, List templateParams) { - StringBuilder templateBuilder = new StringBuilder(VERIFY_TEMPLATE_PREFIX); // eg verify(object + private String getVerifyTemplate(List arguments, String + verificationMode, List templateParams) { + StringBuilder templateBuilder = new StringBuilder(); + if (isVerificationsInOrder()) { + templateBuilder.append("inOrder"); + if (this.verificationsInOrderIdx > 0) { + templateBuilder.append(this.verificationsInOrderIdx); + } + templateBuilder.append("."); + } + templateBuilder.append(VERIFY_TEMPLATE_PREFIX); // eg verify(object if (!verificationMode.isEmpty()) { templateBuilder.append(", ").append(verificationMode).append("(#{any(int)})"); // eg verify(object, times(2) } @@ -333,7 +406,8 @@ private static String getVerifyTemplate(List arguments, String verif return templateBuilder.toString(); } - private static @Nullable MockInvocationResults buildMockInvocationResults(List expectationStatements) { + private static @Nullable MockInvocationResults buildMockInvocationResults + (List expectationStatements) { final MockInvocationResults resultWrapper = new MockInvocationResults(); for (int i = 1; i < expectationStatements.size(); i++) { Statement expectationStatement = expectationStatements.get(i); diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockToMockito.java b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockToMockito.java index 04db84952..89deb552b 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockToMockito.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockToMockito.java @@ -26,31 +26,34 @@ import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.Statement; +import java.util.Arrays; import java.util.List; import java.util.Optional; -import static org.openrewrite.java.testing.jmockit.JMockitBlockType.*; +import static org.openrewrite.java.testing.jmockit.JMockitBlockType.getSupportedTypesStr; +import static org.openrewrite.java.testing.jmockit.JMockitBlockType.values; @Value @EqualsAndHashCode(callSuper = false) public class JMockitBlockToMockito extends Recipe { + private static final String SUPPORTED_TYPES = getSupportedTypesStr(); + @Override public String getDisplayName() { - return "Rewrite JMockit Expectations, Verifications and NonStrictExpectations"; + return "Rewrite JMockit " + SUPPORTED_TYPES; } @Override public String getDescription() { - return "Rewrites JMockit `Expectations, Verifications and NonStrictExpectations` blocks to Mockito statements."; + return "Rewrites JMockit `" + SUPPORTED_TYPES + "` blocks to Mockito statements."; } @Override public TreeVisitor getVisitor() { - return Preconditions.check(Preconditions.or( - new UsesType<>(Expectations.getFqn(), false), - new UsesType<>(Verifications.getFqn(), false), - new UsesType<>(NonStrictExpectations.getFqn(), false)), new RewriteJMockitBlockVisitor()); + @SuppressWarnings("rawtypes") + UsesType[] usesTypes = Arrays.stream(values()).map(blockType -> new UsesType<>(blockType.getFqn(), false)).toArray(UsesType[]::new); + return Preconditions.check(Preconditions.or(usesTypes), new RewriteJMockitBlockVisitor()); } private static class RewriteJMockitBlockVisitor extends JavaIsoVisitor { @@ -66,19 +69,25 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl J.Block methodBody = ssr.rewriteMethodBody(); List statements = methodBody.getStatements(); + int verificationsInOrderIdx = 0; int bodyStatementIndex = 0; - // iterate over each statement in the method body, find Expectations blocks and rewrite them + // iterate over each statement in the method body, find JMockit blocks and rewrite them while (bodyStatementIndex < statements.size()) { Statement s = statements.get(bodyStatementIndex); - Optional blockType = JMockitUtils.getJMockitBlock(s); - if (blockType.isPresent()) { + Optional blockTypeOpt = JMockitUtils.getJMockitBlock(s); + if (blockTypeOpt.isPresent()) { + JMockitBlockType blockType = blockTypeOpt.get(); JMockitBlockRewriter blockRewriter = new JMockitBlockRewriter(this, ctx, methodBody, - ((J.NewClass) s), bodyStatementIndex, blockType.get()); + ((J.NewClass) s), bodyStatementIndex, blockType, verificationsInOrderIdx); methodBody = blockRewriter.rewriteMethodBody(); statements = methodBody.getStatements(); - // if the expectations rewrite failed, skip the next statement + // if the block rewrite failed, skip the next statement if (blockRewriter.isRewriteFailed()) { bodyStatementIndex++; + } else { + if (blockType == JMockitBlockType.VerificationsInOrder) { + verificationsInOrderIdx++; + } } } else { bodyStatementIndex++; diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockType.java b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockType.java index b36c9240f..2fac37d70 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockType.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockType.java @@ -17,16 +17,26 @@ import lombok.Getter; +import java.util.Arrays; + @Getter enum JMockitBlockType { Expectations, + NonStrictExpectations, Verifications, - NonStrictExpectations; + VerificationsInOrder, + FullVerifications; + + private final String fqn = "mockit." + this.name(); - private final String fqn; + boolean isVerifications() { + return this == Verifications || this == FullVerifications || this == VerificationsInOrder; + } - JMockitBlockType() { - this.fqn = "mockit." + this.name(); + static String getSupportedTypesStr() { + StringBuilder sb = new StringBuilder(); + Arrays.stream(values()).forEach(value -> sb.append(value).append(", ")); + return sb.substring(0, sb.length() - 2); } } diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockito.java b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockito.java new file mode 100644 index 000000000..d41bb66d9 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockito.java @@ -0,0 +1,530 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.jmockit; + +import org.openrewrite.*; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.*; +import org.openrewrite.marker.SearchResult; +import org.openrewrite.staticanalysis.LambdaBlockToExpression; +import org.openrewrite.staticanalysis.VariableReferences; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static org.openrewrite.java.testing.jmockit.JMockitUtils.MOCKITO_ALL_IMPORT; +import static org.openrewrite.java.testing.jmockit.JMockitUtils.getJavaParser; +import static org.openrewrite.java.testing.mockito.MockitoUtils.maybeAddMethodWithAnnotation; +import static org.openrewrite.java.tree.Flag.Private; +import static org.openrewrite.java.tree.Flag.Static; + +public class JMockitMockUpToMockito extends Recipe { + + private static final String JMOCKIT_MOCKUP_IMPORT = "mockit.MockUp"; + private static final String JMOCKIT_MOCK_IMPORT = "mockit.Mock"; + private static final String MOCKITO_MATCHER_IMPORT = "org.mockito.ArgumentMatchers.*"; + private static final String MOCKITO_DELEGATEANSWER_IMPORT = "org.mockito.AdditionalAnswers.delegatesTo"; + private static final String MOCKITO_STATIC_PREFIX = "mockStatic"; + private static final String MOCKITO_STATIC_IMPORT = "org.mockito.MockedStatic"; + private static final String MOCKITO_MOCK_PREFIX = "mock"; + private static final String MOCKITO_CONSTRUCTION_PREFIX = "mockCons"; + private static final String MOCKITO_CONSTRUCTION_IMPORT = "org.mockito.MockedConstruction"; + + @Override + public String getDisplayName() { + return "Rewrite JMockit MockUp to Mockito statements"; + } + + @Override + public String getDescription() { + return "Rewrites JMockit `MockUp` blocks to Mockito statements. This recipe will not rewrite private methods in MockUp."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesType<>(JMOCKIT_MOCKUP_IMPORT, false), new JMockitMockUpToMockitoVisitor()); + } + + private static class JMockitMockUpToMockitoVisitor extends JavaIsoVisitor { + private final Map tearDownMocks = new HashMap<>(); + + /** + * Handle at class level because need to handle the case where when there is a MockUp in a setup method, and we + * need to close the migrated mockCons in the teardown, yet the teardown method comes before the setup method + */ + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + // Handle @Before/@BeforeEach mockUp + Set mds = TreeVisitor.collect( + new JavaIsoVisitor() { + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration md, ExecutionContext ctx) { + if (isSetUpMethod(md)) { + return SearchResult.found(md); + } + return super.visitMethodDeclaration(md, ctx); + } + }, + classDecl, + new HashSet<>() + ) + .stream() + .filter(J.MethodDeclaration.class::isInstance) + .map(J.MethodDeclaration.class::cast) + .collect(Collectors.toSet()); + if (mds.isEmpty()) { + return super.visitClassDeclaration(classDecl, ctx); + } + + AtomicReference cdRef = new AtomicReference<>(classDecl); + mds.forEach(md -> md.getBody() + .getStatements() + .stream() + .filter(this::isMockUpStatement) + .map(J.NewClass.class::cast) + .forEach(newClass -> { + String className = ((J.ParameterizedType) newClass.getClazz()).getTypeParameters().get(0).toString(); + + Map mockedMethods = getMockUpMethods(newClass); + + // Add mockStatic field + if (mockedMethods.values().stream().anyMatch(m -> m.getFlags().contains(Static))) { + cdRef.set(JavaTemplate.builder("private MockedStatic #{};") + .contextSensitive() + .javaParser(getJavaParser(ctx)) + .imports(MOCKITO_STATIC_IMPORT) + .staticImports(MOCKITO_ALL_IMPORT) + .build() + .apply( + new Cursor(getCursor().getParentOrThrow(), cdRef.get()), + cdRef.get().getBody().getCoordinates().firstStatement(), + MOCKITO_STATIC_PREFIX + className + )); + J.VariableDeclarations mockField = (J.VariableDeclarations) cdRef.get().getBody().getStatements().get(0); + J.Identifier mockFieldId = mockField.getVariables().get(0).getName(); + tearDownMocks.put(MOCKITO_STATIC_PREFIX + className, mockFieldId); + } + // Add mockConstruction field + if (mockedMethods.values().stream().anyMatch(m -> !m.getFlags().contains(Static))) { + cdRef.set(JavaTemplate.builder("private MockedConstruction #{};") + .contextSensitive() + .javaParser(getJavaParser(ctx)) + .imports(MOCKITO_CONSTRUCTION_IMPORT) + .staticImports(MOCKITO_ALL_IMPORT) + .build() + .apply( + updateCursor(cdRef.get()), + cdRef.get().getBody().getCoordinates().firstStatement(), + MOCKITO_CONSTRUCTION_PREFIX + className + )); + J.VariableDeclarations mockField = (J.VariableDeclarations) cdRef.get().getBody().getStatements().get(0); + J.Identifier mockFieldId = mockField.getVariables().get(0).getName(); + tearDownMocks.put(MOCKITO_CONSTRUCTION_PREFIX + className, mockFieldId); + } + })); + + J.ClassDeclaration cd = maybeAddMethodWithAnnotation(this, cdRef.get(), ctx, true, "tearDown", + "@org.junit.After", + "@After", + "junit-4.13", + "org.junit.After", + ""); + + return super.visitClassDeclaration(cd, ctx); + } + + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl, ExecutionContext ctx) { + J.MethodDeclaration md = methodDecl; + if (md.getBody() == null) { + return md; + } + if (isTearDownMethod(md)) { + for (J.Identifier id : tearDownMocks.values()) { + String type = TypeUtils.asFullyQualified(id.getFieldType().getType()).getFullyQualifiedName(); + md = JavaTemplate.builder("#{any(" + type + ")}.closeOnDemand();") + .contextSensitive() + .javaParser(getJavaParser(ctx)) + .imports(MOCKITO_STATIC_IMPORT, MOCKITO_CONSTRUCTION_IMPORT) + .staticImports(MOCKITO_ALL_IMPORT) + .build() + .apply( + updateCursor(md), + md.getBody().getCoordinates().lastStatement(), + id + ); + } + return md; + } + + boolean isBeforeTest = isSetUpMethod(md); + List varDeclarationInTry = new ArrayList<>(); + List mockStaticMethodInTry = new ArrayList<>(); + List mockConstructionMethodInTry = new ArrayList<>(); + List encloseStatements = new ArrayList<>(); + List residualStatements = new ArrayList<>(); + for (Statement statement : md.getBody().getStatements()) { + if (!isMockUpStatement(statement)) { + encloseStatements.add(statement); + continue; + } + + J.NewClass newClass = (J.NewClass) statement; + + // Only discard @Mock method declarations + residualStatements.addAll(newClass + .getBody() + .getStatements() + .stream() + .filter(s -> { + if (s instanceof J.MethodDeclaration) { + return ((J.MethodDeclaration) s).getLeadingAnnotations().stream() + .noneMatch(o -> TypeUtils.isOfClassType(o.getType(), JMOCKIT_MOCK_IMPORT)); + } + return true; + }) + .collect(toList()) + ); + + JavaType mockType = ((J.ParameterizedType) newClass.getClazz()).getTypeParameters().get(0).getType(); + String className = ((J.ParameterizedType) newClass.getClazz()).getTypeParameters().get(0).toString(); + + Map mockedMethods = getMockUpMethods(newClass); + + // Add MockStatic + Map mockedPublicStaticMethods = mockedMethods + .entrySet() + .stream() + .filter(m -> m.getValue().getFlags().contains(Static)) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + if (!mockedPublicStaticMethods.isEmpty()) { + if (isBeforeTest) { + String tpl = getMockStaticDeclarationInBefore(className) + + getMockStaticMethods((JavaType.Class) mockType, className, mockedPublicStaticMethods); + + md = JavaTemplate.builder(tpl) + .contextSensitive() + .javaParser(getJavaParser(ctx)) + .imports(MOCKITO_STATIC_IMPORT) + .staticImports(MOCKITO_ALL_IMPORT) + .build() + .apply( + updateCursor(md), + statement.getCoordinates().after(), + tearDownMocks.get(MOCKITO_STATIC_PREFIX + className) + ); + } else { + varDeclarationInTry.add(getMockStaticDeclarationInTry(className)); + mockStaticMethodInTry.add(getMockStaticMethods((JavaType.Class) mockType, className, mockedPublicStaticMethods)); + } + + maybeAddImport(MOCKITO_STATIC_IMPORT); + } + + // Add MockConstruction + Map mockedPublicMethods = mockedMethods + .entrySet() + .stream() + .filter(m -> !m.getValue().getFlags().contains(Static)) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + if (!mockedPublicMethods.isEmpty()) { + if (isBeforeTest) { + String tpl = getMockConstructionMethods(className, mockedPublicMethods) + + getMockConstructionDeclarationInBefore(className); + + md = JavaTemplate.builder(tpl) + .contextSensitive() + .javaParser(getJavaParser(ctx)) + .imports(MOCKITO_STATIC_IMPORT) + .staticImports(MOCKITO_ALL_IMPORT, MOCKITO_DELEGATEANSWER_IMPORT) + .build() + .apply( + updateCursor(md), + statement.getCoordinates().after(), + tearDownMocks.get(MOCKITO_CONSTRUCTION_PREFIX + className) + ); + } else { + varDeclarationInTry.add(getMockConstructionDeclarationInTry(className)); + mockConstructionMethodInTry.add(getMockConstructionMethods(className, mockedPublicMethods)); + } + + maybeAddImport(MOCKITO_CONSTRUCTION_IMPORT); + maybeAddImport("org.mockito.Answers", "CALLS_REAL_METHODS", false); + maybeAddImport("org.mockito.AdditionalAnswers", "delegatesTo", false); + } + + List statements = md.getBody().getStatements(); + statements.remove(statement); + md = md.withBody(md.getBody().withStatements(statements)); + } + + if (!varDeclarationInTry.isEmpty()) { + String tpl = String.join("", mockConstructionMethodInTry) + + "try (" + + String.join(";", varDeclarationInTry) + + ") {" + + String.join(";", mockStaticMethodInTry) + + "}"; + + J.MethodDeclaration residualMd = md.withBody(md.getBody().withStatements(residualStatements)); + residualMd = JavaTemplate.builder(tpl) + .contextSensitive() + .javaParser(getJavaParser(ctx)) + .imports(MOCKITO_STATIC_IMPORT, MOCKITO_CONSTRUCTION_IMPORT) + .staticImports(MOCKITO_ALL_IMPORT, MOCKITO_MATCHER_IMPORT, MOCKITO_MATCHER_IMPORT, MOCKITO_DELEGATEANSWER_IMPORT) + .build() + .apply(updateCursor(residualMd), residualMd.getBody().getCoordinates().lastStatement()); + + List mdStatements = residualMd.getBody().getStatements(); + J.Try try_ = (J.Try) mdStatements.get(mdStatements.size() - 1); + + List tryStatements = try_.getBody().getStatements(); + tryStatements.addAll(encloseStatements); + try_ = try_.withBody(try_.getBody().withStatements(tryStatements)); + + mdStatements.set(mdStatements.size() - 1, try_); + md = md.withBody(residualMd.getBody().withStatements(mdStatements)); + } + + maybeAddImport(MOCKITO_ALL_IMPORT.replace(".*", ""), "*", false); + maybeRemoveImport(JMOCKIT_MOCK_IMPORT); + maybeRemoveImport(JMOCKIT_MOCKUP_IMPORT); + + doAfterVisit(new LambdaBlockToExpression().getVisitor()); + return maybeAutoFormat(methodDecl, md, ctx); + } + + private String getMatcher(JavaType s) { + maybeAddImport(MOCKITO_MATCHER_IMPORT.replace(".*", ""), "*", false); + if (s instanceof JavaType.Primitive) { + switch (s.toString()) { + case "int": + return "anyInt()"; + case "long": + return "anyLong()"; + case "double": + return "anyDouble()"; + case "float": + return "anyFloat()"; + case "short": + return "anyShort()"; + case "byte": + return "anyByte()"; + case "char": + return "anyChar()"; + case "boolean": + return "anyBoolean()"; + } + } else if (s instanceof JavaType.Array) { + String elem = TypeUtils.asArray(s).getElemType().toString(); + return "nullable(" + elem + "[].class)"; + } + return "nullable(" + TypeUtils.asFullyQualified(s).getClassName() + ".class)"; + } + + private String getAnswerBody(J.MethodDeclaration md) { + Set usedVariables = new HashSet<>(); + new JavaIsoVisitor>() { + @Override + public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, Set ctx) { + Cursor scope = getCursor().dropParentUntil((is) -> is instanceof J.ClassDeclaration || is instanceof J.Block || is instanceof J.MethodDeclaration || is instanceof J.ForLoop || is instanceof J.ForEachLoop || is instanceof J.ForLoop.Control || is instanceof J.ForEachLoop.Control || is instanceof J.Case || is instanceof J.Try || is instanceof J.Try.Resource || is instanceof J.Try.Catch || is instanceof J.MultiCatch || is instanceof J.Lambda || is instanceof JavaSourceFile); + if (!VariableReferences.findRhsReferences(scope.getValue(), variable.getName()).isEmpty()) { + ctx.add(variable.getSimpleName()); + } + return super.visitVariable(variable, ctx); + } + }.visit(md, usedVariables); + + StringBuilder sb = new StringBuilder(); + List parameters = md.getParameters(); + for (int i = 0; i < parameters.size(); i++) { + if (!(parameters.get(i) instanceof J.VariableDeclarations)) { + continue; + } + J.VariableDeclarations vd = (J.VariableDeclarations) parameters.get(i); + String className; + if (vd.getType() instanceof JavaType.Primitive) { + className = vd.getType().toString(); + } else { + className = vd.getTypeAsFullyQualified().getClassName(); + } + String varName = vd.getVariables().get(0).getName().getSimpleName(); + if (usedVariables.contains(varName)) { + sb.append(className).append(" ").append(varName) + .append(" = invocation.getArgument(").append(i).append(");"); + } + } + + boolean hasReturn = false; + for (Statement s : md.getBody().getStatements()) { + hasReturn |= s instanceof J.Return; + sb.append(s.print(getCursor())).append(";"); + } + // Avoid syntax error + if (!hasReturn) { + sb.append("return null;"); + } + return sb.toString(); + } + + private String getCallRealMethod(JavaType.Method m) { + return "(" + + m.getParameterTypes() + .stream() + .map(this::getMatcher) + .collect(Collectors.joining(", ")) + + ")).thenCallRealMethod();"; + } + + private String getMockStaticDeclarationInBefore(String className) { + return "#{any(" + MOCKITO_STATIC_IMPORT + ")}" + + " = mockStatic(" + className + ".class);"; + } + + private String getMockStaticDeclarationInTry(String className) { + return "MockedStatic " + MOCKITO_STATIC_PREFIX + className + + " = mockStatic(" + className + ".class)"; + } + + private String getMockStaticMethods(JavaType.Class clazz, String className, Map mockedMethods) { + StringBuilder tpl = new StringBuilder(); + + // To generate predictable method order + List keys = mockedMethods.keySet().stream() + .sorted(Comparator.comparing(o -> o.print(getCursor()))) + .collect(toList()); + for (J.MethodDeclaration m : keys) { + tpl.append("mockStatic").append(className) + .append(".when(() -> ").append(className).append(".").append(m.getSimpleName()).append("(") + .append(m.getParameters() + .stream() + .filter(J.VariableDeclarations.class::isInstance) + .map(J.VariableDeclarations.class::cast) + .map(J.VariableDeclarations::getType) + .map(this::getMatcher) + .collect(Collectors.joining(", ")) + ) + .append(")).thenAnswer(invocation -> {") + .append(getAnswerBody(m)) + .append("});"); + } + + // Call real method for non private, static methods + clazz.getMethods() + .stream() + .filter(m -> !m.isConstructor()) + .filter(m -> !m.getFlags().contains(Private)) + .filter(m -> m.getFlags().contains(Static)) + .filter(m -> !mockedMethods.containsValue(m)) + .forEach(m -> tpl.append("mockStatic").append(className).append(".when(() -> ") + .append(className).append(".").append(m.getName()) + .append(getCallRealMethod(m)) + .append(");") + ); + + return tpl.toString(); + } + + private String getMockConstructionDeclarationInBefore(String className) { + return "#{any(" + MOCKITO_CONSTRUCTION_IMPORT + ")}" + + " = mockConstructionWithAnswer(" + className + ".class, delegatesTo(" + MOCKITO_MOCK_PREFIX + className + "));"; + } + + private String getMockConstructionDeclarationInTry(String className) { + return "MockedConstruction " + MOCKITO_CONSTRUCTION_PREFIX + className + + " = mockConstructionWithAnswer(" + className + ".class, delegatesTo(" + MOCKITO_MOCK_PREFIX + className + "))"; + } + + private String getMockConstructionMethods(String className, Map mockedMethods) { + StringBuilder tpl = new StringBuilder() + .append(className) + .append(" ") + .append(MOCKITO_MOCK_PREFIX).append(className) + .append(" = mock(").append(className).append(".class, CALLS_REAL_METHODS);"); + + mockedMethods + .keySet() + .stream() + .sorted(Comparator.comparing(o -> o.print(getCursor()))) + .forEach(m -> tpl.append("doAnswer(invocation -> {") + .append(getAnswerBody(m)) + .append("}).when(").append(MOCKITO_MOCK_PREFIX).append(className).append(").").append(m.getSimpleName()).append("(") + .append(m.getParameters() + .stream() + .filter(J.VariableDeclarations.class::isInstance) + .map(J.VariableDeclarations.class::cast) + .map(J.VariableDeclarations::getType) + .map(this::getMatcher) + .collect(Collectors.joining(", ")) + ) + .append(");")); + + return tpl.toString(); + } + + private boolean isMockUpStatement(Tree tree) { + return tree instanceof J.NewClass && + ((J.NewClass) tree).getClazz() != null && + TypeUtils.isOfClassType(((J.NewClass) tree).getClazz().getType(), JMOCKIT_MOCKUP_IMPORT); + } + + private boolean isSetUpMethod(J.MethodDeclaration md) { + return md + .getLeadingAnnotations() + .stream() + .anyMatch(o -> TypeUtils.isOfClassType(o.getType(), "org.junit.Before")); + } + + private boolean isTearDownMethod(J.MethodDeclaration md) { + return md + .getLeadingAnnotations() + .stream() + .anyMatch(o -> TypeUtils.isOfClassType(o.getType(), "org.junit.After")); + } + + private Map getMockUpMethods(J.NewClass newClass) { + JavaType mockType = ((J.ParameterizedType) newClass.getClazz()).getTypeParameters().get(0).getType(); + return newClass.getBody() + .getStatements() + .stream() + .filter(J.MethodDeclaration.class::isInstance) + .map(J.MethodDeclaration.class::cast) + .filter(s -> s.getLeadingAnnotations().stream() + .anyMatch(o -> TypeUtils.isOfClassType(o.getType(), JMOCKIT_MOCK_IMPORT))) + .map(method -> { + Optional found = TypeUtils.findDeclaredMethod( + TypeUtils.asFullyQualified(mockType), + method.getSimpleName(), + method.getMethodType().getParameterTypes() + ); + if (found.isPresent()) { + JavaType.Method m = found.get(); + if (!m.getFlags().contains(Private)) { + return new AbstractMap.SimpleEntry<>(method, found.get()); + } + } + return null; + }) + .filter(Objects::nonNull) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + } +} diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitUtils.java b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitUtils.java index a8e2a7453..226e78c14 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/JMockitUtils.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/JMockitUtils.java @@ -15,34 +15,43 @@ */ package org.openrewrite.java.testing.jmockit; +import org.openrewrite.ExecutionContext; +import org.openrewrite.java.JavaParser; import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.Statement; import org.openrewrite.java.tree.TypeUtils; +import java.util.Arrays; import java.util.Optional; import static java.util.Optional.empty; class JMockitUtils { + static final String MOCKITO_ALL_IMPORT = "org.mockito.Mockito.*"; + + public static JavaParser.Builder getJavaParser(ExecutionContext ctx) { + return JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-core-3.12"); + } + static Optional getJMockitBlock(Statement s) { if (!(s instanceof J.NewClass)) { return empty(); } + J.NewClass nc = (J.NewClass) s; - if (!(nc.getClazz() instanceof J.Identifier)) { + if (nc.getBody() == null || nc.getClazz() == null) { return empty(); } - J.Identifier clazz = (J.Identifier) nc.getClazz(); - // JMockit block should be composed of a block within another block - if (nc.getBody() == null || - (nc.getBody().getStatements().size() != 1 && - !TypeUtils.isAssignableTo("mockit.Expectations", clazz.getType()) && - !TypeUtils.isAssignableTo("mockit.Verifications", clazz.getType()))) { + JavaType type = nc.getClazz().getType(); + if (type == null) { return empty(); } - return Optional.of(JMockitBlockType.valueOf(clazz.getSimpleName())); + return Arrays.stream(JMockitBlockType.values()) + .filter(supportedType -> TypeUtils.isOfClassType(type, supportedType.getFqn())) + .findFirst(); } } diff --git a/src/main/java/org/openrewrite/java/testing/jmockit/SetupStatementsRewriter.java b/src/main/java/org/openrewrite/java/testing/jmockit/SetupStatementsRewriter.java index 344e064c1..473f82be4 100644 --- a/src/main/java/org/openrewrite/java/testing/jmockit/SetupStatementsRewriter.java +++ b/src/main/java/org/openrewrite/java/testing/jmockit/SetupStatementsRewriter.java @@ -139,8 +139,8 @@ private static boolean isNotMockIdentifier(J.Identifier identifier, Set if (spies.contains(identifier.getSimpleName())) { return false; } - if (identifier.getType() instanceof JavaType.Method - && TypeUtils.isAssignableTo("mockit.Invocations", + if (identifier.getType() instanceof JavaType.Method && + TypeUtils.isAssignableTo("mockit.Invocations", ((JavaType.Method) identifier.getType()).getDeclaringType())) { return false; } @@ -149,9 +149,9 @@ private static boolean isNotMockIdentifier(J.Identifier identifier, Set return true; } for (JavaType.FullyQualified annotationType : fieldType.getAnnotations()) { - if (TypeUtils.isAssignableTo("mockit.Mocked", annotationType) - || TypeUtils.isAssignableTo("mockit.Injectable", annotationType) - || TypeUtils.isAssignableTo("mockit.Tested", annotationType)) { + if (TypeUtils.isAssignableTo("mockit.Mocked", annotationType) || + TypeUtils.isAssignableTo("mockit.Injectable", annotationType) || + TypeUtils.isAssignableTo("mockit.Tested", annotationType)) { return false; } } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/AddMissingNested.java b/src/main/java/org/openrewrite/java/testing/junit5/AddMissingNested.java index 844d832e4..e39cccb19 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/AddMissingNested.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/AddMissingNested.java @@ -17,7 +17,6 @@ import lombok.EqualsAndHashCode; import lombok.Value; -import org.jspecify.annotations.NonNull; import org.openrewrite.ExecutionContext; import org.openrewrite.Preconditions; import org.openrewrite.Recipe; @@ -74,7 +73,7 @@ public TreeVisitor getVisitor() { @Override public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx); - cd = cd.withBody((J.Block) new AddNestedAnnotationVisitor().visitNonNull(cd.getBody(), ctx, getCursor())); + cd = cd.withBody((J.Block) new AddNestedAnnotationVisitor().visitNonNull(cd.getBody(), ctx, updateCursor(cd))); maybeAddImport(NESTED); return cd; } @@ -88,22 +87,18 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex boolean alreadyNested = classDecl.getLeadingAnnotations().stream() .anyMatch(a -> TypeUtils.isOfClassType(a.getType(), NESTED)); if (!alreadyNested && hasTestMethods(cd)) { - cd = getNestedJavaTemplate(ctx).apply(updateCursor(cd), - cd.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + cd = JavaTemplate.builder("@Nested") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "junit-jupiter-api-5.9")) + .imports(NESTED) + .build() + .apply(getCursor(), cd.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); cd.getModifiers().removeIf(modifier -> modifier.getType().equals(J.Modifier.Type.Static)); + return maybeAutoFormat(classDecl, cd, ctx); } return cd; } - @NonNull - private JavaTemplate getNestedJavaTemplate(ExecutionContext ctx) { - return JavaTemplate.builder("@Nested") - .javaParser(JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "junit-jupiter-api-5.9")) - .imports(NESTED) - .build(); - } - private static boolean hasTestMethods(final J.ClassDeclaration cd) { return TEST_ANNOTATIONS.stream().anyMatch(ann -> !FindAnnotations.find(cd, "@" + ann).isEmpty()); } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatement.java b/src/main/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatement.java index de757861d..add5ab8e7 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatement.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatement.java @@ -56,8 +56,11 @@ public TreeVisitor getVisitor() { @Override public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl, ExecutionContext ctx) { J.MethodDeclaration m = super.visitMethodDeclaration(methodDecl, ctx); - - m = m.withBody(m.getBody().withStatements(ListUtils.flatMap(m.getBody().getStatements(), methodStatement -> { + if (m.getBody() == null) { + return m; + } + doAfterVisit(new LambdaBlockToExpression().getVisitor()); + return m.withBody(m.getBody().withStatements(ListUtils.flatMap(m.getBody().getStatements(), methodStatement -> { J statementToCheck = methodStatement; final J.VariableDeclarations assertThrowsWithVarDec; final J.VariableDeclarations.NamedVariable assertThrowsVar; @@ -132,11 +135,7 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl J.VariableDeclarations.NamedVariable newAssertThrowsVar = assertThrowsVar.withInitializer(newAssertThrows); return assertThrowsWithVarDec.withVariables(singletonList(newAssertThrowsVar)); }); - }))); - - doAfterVisit(new LambdaBlockToExpression().getVisitor()); - return m; } }); } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/AssertTrueInstanceofToAssertInstanceOf.java b/src/main/java/org/openrewrite/java/testing/junit5/AssertTrueInstanceofToAssertInstanceOf.java index 30bc12d38..a80e9b5dd 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/AssertTrueInstanceofToAssertInstanceOf.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/AssertTrueInstanceofToAssertInstanceOf.java @@ -99,9 +99,9 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu .staticImports("org.junit.jupiter.api.Assertions.assertInstanceOf") .build(); - J.MethodInvocation methodd = reason != null - ? template.apply(getCursor(), mi.getCoordinates().replace(), clazz.toString(), expression, reason) - : template.apply(getCursor(), mi.getCoordinates().replace(), clazz.toString(), expression); + J.MethodInvocation methodd = reason != null ? + template.apply(getCursor(), mi.getCoordinates().replace(), clazz.toString(), expression, reason) : + template.apply(getCursor(), mi.getCoordinates().replace(), clazz.toString(), expression); maybeAddImport("org.junit.jupiter.api.Assertions", "assertInstanceOf"); return methodd; } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/EnclosedToNested.java b/src/main/java/org/openrewrite/java/testing/junit5/EnclosedToNested.java index d4d54c8f4..ac3ee5573 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/EnclosedToNested.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/EnclosedToNested.java @@ -21,24 +21,18 @@ import org.openrewrite.Preconditions; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; +import org.openrewrite.java.AnnotationMatcher; import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.JavaParser; -import org.openrewrite.java.JavaTemplate; -import org.openrewrite.java.search.FindAnnotations; +import org.openrewrite.java.RemoveAnnotationVisitor; import org.openrewrite.java.search.UsesType; import org.openrewrite.java.tree.J; -import java.util.Comparator; -import java.util.Set; - @Value @EqualsAndHashCode(callSuper = false) public class EnclosedToNested extends Recipe { private static final String ENCLOSED = "org.junit.experimental.runners.Enclosed"; private static final String RUN_WITH = "org.junit.runner.RunWith"; - private static final String NESTED = "org.junit.jupiter.api.Nested"; - private static final String TEST_JUNIT4 = "org.junit.Test"; - private static final String TEST_JUNIT_JUPITER = "org.junit.jupiter.api.Test"; + private static final String RUN_WITH_ENCLOSED = String.format("@%s(%s.class)", RUN_WITH, ENCLOSED); @Override public String getDisplayName() { @@ -47,54 +41,19 @@ public String getDisplayName() { @Override public String getDescription() { - return "Removes the `Enclosed` specification from a class, and adds `Nested` to its inner classes."; + return "Removes the `Enclosed` specification from a class, with `Nested` added to its inner classes by `AddMissingNested`."; } @Override public TreeVisitor getVisitor() { return Preconditions.check(new UsesType<>(ENCLOSED, false), new JavaIsoVisitor() { - @SuppressWarnings("ConstantConditions") @Override public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx); - final Set runWithEnclosedAnnotationSet = FindAnnotations.find(cd.withBody(null), - String.format("@%s(%s.class)", RUN_WITH, ENCLOSED)); - for (J.Annotation runWithEnclosed : runWithEnclosedAnnotationSet) { - cd.getLeadingAnnotations().remove(runWithEnclosed); - cd = cd.withBody((J.Block) new AddNestedAnnotationVisitor().visit(cd.getBody(), ctx, getCursor())); - - maybeRemoveImport(ENCLOSED); - maybeRemoveImport(RUN_WITH); - maybeAddImport(NESTED); - } - return cd; + maybeRemoveImport(ENCLOSED); + maybeRemoveImport(RUN_WITH); + return (J.ClassDeclaration) new RemoveAnnotationVisitor(new AnnotationMatcher(RUN_WITH_ENCLOSED)).visitNonNull(cd, ctx); } }); } - - public static class AddNestedAnnotationVisitor extends JavaIsoVisitor { - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { - J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx); - if (hasTestMethods(cd)) { - cd = getNestedJavaTemplate(ctx).apply(updateCursor(cd), cd.getCoordinates().addAnnotation(Comparator.comparing( - J.Annotation::getSimpleName))); - cd.getModifiers().removeIf(modifier -> modifier.getType().equals(J.Modifier.Type.Static)); - } - return cd; - } - - private JavaTemplate getNestedJavaTemplate(ExecutionContext ctx) { - return JavaTemplate.builder("@Nested") - .javaParser(JavaParser.fromJavaVersion() - .classpathFromResources(ctx, "junit-jupiter-api-5.9")) - .imports(NESTED) - .build(); - } - - private boolean hasTestMethods(final J.ClassDeclaration cd) { - return !FindAnnotations.find(cd, "@" + TEST_JUNIT4).isEmpty() - || !FindAnnotations.find(cd, "@" + TEST_JUNIT_JUPITER).isEmpty(); - } - } } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/ExpectedExceptionToAssertThrows.java b/src/main/java/org/openrewrite/java/testing/junit5/ExpectedExceptionToAssertThrows.java index 1253442bf..78a5d3fe5 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/ExpectedExceptionToAssertThrows.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/ExpectedExceptionToAssertThrows.java @@ -154,8 +154,8 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl } } - String exceptionDeclParam = ((isExpectArgAMatcher || isExpectMessageArgAMatcher || isExpectedCauseArgAMatcher) - || expectMessageMethodInvocation != null) ? + String exceptionDeclParam = ((isExpectArgAMatcher || isExpectMessageArgAMatcher || isExpectedCauseArgAMatcher) || + expectMessageMethodInvocation != null) ? "Throwable exception = " : ""; Object expectedExceptionParam = (expectMethodInvocation == null || isExpectArgAMatcher) ? @@ -182,7 +182,9 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl m = m.withBody(m.getBody().withPrefix(thrown.get(0).getPrefix())).withThrows(Collections.emptyList()); } - maybeAddImport("org.junit.jupiter.api.Assertions", "assertThrows"); + // Unconditionally add the import for assertThrows, got a report where the above template adds the method successfully + // but with missing type attribution for assertThrows so the import was missing + maybeAddImport("org.junit.jupiter.api.Assertions", "assertThrows", false); if (expectMessageMethodInvocation != null && !isExpectMessageArgAMatcher && m.getBody() != null) { m = JavaTemplate.builder("assertTrue(exception.getMessage().contains(#{any(java.lang.String)}));") diff --git a/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java b/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java index 8fbe83308..8d2b1280e 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java @@ -194,9 +194,9 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu } break; case "withType": - if (m.getSelect() == null - || !TypeUtils.isOfClassType(m.getSelect().getType(), "org.gradle.api.tasks.TaskContainer") - || !(m.getArguments().get(0) instanceof J.Identifier && "Test".equals(((J.Identifier) m.getArguments().get(0)).getSimpleName()))) { + if (m.getSelect() == null || + !TypeUtils.isOfClassType(m.getSelect().getType(), "org.gradle.api.tasks.TaskContainer") || + !(m.getArguments().get(0) instanceof J.Identifier && "Test".equals(((J.Identifier) m.getArguments().get(0)).getSimpleName()))) { return m; } break; @@ -208,10 +208,10 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu return m; } J.MethodInvocation select = (J.MethodInvocation) m.getSelect(); - if(!"withType".equals(select.getSimpleName()) - || select.getArguments().size() != 1 - || !(select.getArguments().get(0) instanceof J.Identifier) - || !"Test".equals(((J.Identifier) select.getArguments().get(0)).getSimpleName())) { + if(!"withType".equals(select.getSimpleName()) || + select.getArguments().size() != 1 || + !(select.getArguments().get(0) instanceof J.Identifier) || + !"Test".equals(((J.Identifier) select.getArguments().get(0)).getSimpleName())) { return m; } break; diff --git a/src/main/java/org/openrewrite/java/testing/junit5/JUnitParamsRunnerToParameterized.java b/src/main/java/org/openrewrite/java/testing/junit5/JUnitParamsRunnerToParameterized.java index 5c0e2e3ac..616ee48c0 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/JUnitParamsRunnerToParameterized.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/JUnitParamsRunnerToParameterized.java @@ -148,10 +148,10 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct private @Nullable String getAnnotationArgumentForInitMethod(J.Annotation anno, String... variableNames) { String value = null; - if (anno.getArguments() != null && anno.getArguments().size() == 1 - && anno.getArguments().get(0) instanceof J.Assignment - && ((J.Assignment) anno.getArguments().get(0)).getVariable() instanceof J.Identifier - && ((J.Assignment) anno.getArguments().get(0)).getAssignment() instanceof J.Literal) { + if (anno.getArguments() != null && anno.getArguments().size() == 1 && + anno.getArguments().get(0) instanceof J.Assignment && + ((J.Assignment) anno.getArguments().get(0)).getVariable() instanceof J.Identifier && + ((J.Assignment) anno.getArguments().get(0)).getAssignment() instanceof J.Literal) { J.Assignment annoArg = (J.Assignment) anno.getArguments().get(0); J.Literal assignment = (J.Literal) annoArg.getAssignment(); String identifier = ((J.Identifier) annoArg.getVariable()).getSimpleName(); diff --git a/src/main/java/org/openrewrite/java/testing/junit5/LifecycleNonPrivate.java b/src/main/java/org/openrewrite/java/testing/junit5/LifecycleNonPrivate.java index 273362d04..57a3a47d0 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/LifecycleNonPrivate.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/LifecycleNonPrivate.java @@ -67,8 +67,8 @@ private static class LifecycleNonPrivateVisitor extends JavaIsoVisitor lifeCycleAnnotationMatchers.stream() + if (J.Modifier.hasModifier(md.getModifiers(), Type.Private) && + md.getLeadingAnnotations().stream().anyMatch(ann -> lifeCycleAnnotationMatchers.stream() .anyMatch(matcher -> matcher.matches(ann)))) { return maybeAutoFormat(md, md.withModifiers(ListUtils.map(md.getModifiers(), diff --git a/src/main/java/org/openrewrite/java/testing/junit5/MigrateJUnitTestCase.java b/src/main/java/org/openrewrite/java/testing/junit5/MigrateJUnitTestCase.java index 0e07eed51..1bb528abd 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/MigrateJUnitTestCase.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/MigrateJUnitTestCase.java @@ -83,10 +83,10 @@ public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionCon @SuppressWarnings("ConstantConditions") @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + public J.@Nullable MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - if ((mi.getSelect() != null && TypeUtils.isOfClassType(mi.getSelect().getType(), "junit.framework.TestCase")) - || (mi.getMethodType() != null && TypeUtils.isOfClassType(mi.getMethodType().getDeclaringType(), "junit.framework.TestCase"))) { + if ((mi.getSelect() != null && TypeUtils.isOfClassType(mi.getSelect().getType(), "junit.framework.TestCase")) || + (mi.getMethodType() != null && TypeUtils.isOfClassType(mi.getMethodType().getDeclaringType(), "junit.framework.TestCase"))) { String name = mi.getSimpleName(); // setUp and tearDown will be invoked via Before and After annotations if ("setUp".equals(name) || "tearDown".equals(name)) { diff --git a/src/main/java/org/openrewrite/java/testing/junit5/MockitoJUnitToMockitoExtension.java b/src/main/java/org/openrewrite/java/testing/junit5/MockitoJUnitToMockitoExtension.java index e82911cb0..194d0e056 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/MockitoJUnitToMockitoExtension.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/MockitoJUnitToMockitoExtension.java @@ -74,6 +74,7 @@ public TreeVisitor getVisitor() { public static class MockitoRuleToMockitoExtensionVisitor extends JavaIsoVisitor { private static final String MOCKITO_RULE_INVOCATION_KEY = "mockitoRuleInvocation"; private static final String MOCKITO_TEST_RULE_INVOCATION_KEY = "mockitoTestRuleInvocation"; + private static final String STRICTNESS_KEY = "strictness"; private static final String EXTEND_WITH_MOCKITO_EXTENSION = "@org.junit.jupiter.api.extension.ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class)"; private static final String RUN_WITH_MOCKITO_JUNIT_RUNNER = "@org.junit.runner.RunWith(org.mockito.runners.MockitoJUnitRunner.class)"; @@ -100,6 +101,7 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex if (classDecl.getBody().getStatements().size() != cd.getBody().getStatements().size() && (FindAnnotations.find(classDecl.withBody(null), RUN_WITH_MOCKITO_JUNIT_RUNNER).isEmpty() && FindAnnotations.find(classDecl.withBody(null), EXTEND_WITH_MOCKITO_EXTENSION).isEmpty())) { + String strictness = getCursor().pollMessage(STRICTNESS_KEY); cd = JavaTemplate.builder("@ExtendWith(MockitoExtension.class)") .javaParser(JavaParser.fromJavaVersion() @@ -110,6 +112,22 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex maybeAddImport("org.junit.jupiter.api.extension.ExtendWith"); maybeAddImport("org.mockito.junit.jupiter.MockitoExtension"); + + if (strictness == null) { + // As we are in a Rule, and rules where always warn by default, + // we cannot use junit5 Strictness.STRICT_STUBS during migration + strictness = "Strictness.WARN"; + } + if (!strictness.contains("STRICT_STUBS")) { + cd = JavaTemplate.builder("@MockitoSettings(strictness = " + strictness + ")") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "junit-jupiter-api-5.9", "mockito-junit-jupiter-3.12")) + .imports("org.mockito.junit.jupiter.MockitoSettings", "org.mockito.quality.Strictness") + .build() + .apply(updateCursor(cd), cd.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + maybeAddImport("org.mockito.junit.jupiter.MockitoSettings", false); + maybeAddImport("org.mockito.quality.Strictness", false); + } } } @@ -119,10 +137,27 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex @Override public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { if (method.getMethodType() != null) { + String key = null; if (TypeUtils.isOfClassType(method.getMethodType().getDeclaringType(), "org.mockito.junit.MockitoRule")) { - getCursor().putMessageOnFirstEnclosing(J.MethodDeclaration.class, MOCKITO_RULE_INVOCATION_KEY, method); + key = MOCKITO_RULE_INVOCATION_KEY; } else if (TypeUtils.isOfClassType(method.getMethodType().getDeclaringType(), "org.mockito.junit.MockitoTestRule")) { - getCursor().putMessageOnFirstEnclosing(J.MethodDeclaration.class, MOCKITO_TEST_RULE_INVOCATION_KEY, method); + key = MOCKITO_TEST_RULE_INVOCATION_KEY; + } + if (key != null) { + getCursor().putMessageOnFirstEnclosing(J.MethodDeclaration.class, key, method); + String strictness = null; + switch (method.getSimpleName()) { + case "strictness": + strictness = method.getArguments().get(0).toString(); + break; + case "silent": + strictness = "Strictness.LENIENT"; + break; + } + if (strictness != null) { + strictness = strictness.startsWith("Strictness.") ? strictness : "Strictness." + strictness; + getCursor().putMessageOnFirstEnclosing(J.ClassDeclaration.class, STRICTNESS_KEY, strictness); + } } } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/ParameterizedRunnerToParameterized.java b/src/main/java/org/openrewrite/java/testing/junit5/ParameterizedRunnerToParameterized.java index 269390a54..64c919aac 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/ParameterizedRunnerToParameterized.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/ParameterizedRunnerToParameterized.java @@ -280,8 +280,8 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex cd = cd.withBody(cd.getBody().withStatements(ListUtils.map(cd.getBody().getStatements(), statement -> { if (statement instanceof J.VariableDeclarations) { J.VariableDeclarations varDecls = (J.VariableDeclarations) statement; - if (varDecls.getVariables().stream().anyMatch(it -> fieldNames.contains(it.getSimpleName())) - && (varDecls.hasModifier(J.Modifier.Type.Final))) { + if (varDecls.getVariables().stream().anyMatch(it -> fieldNames.contains(it.getSimpleName())) && + (varDecls.hasModifier(J.Modifier.Type.Final))) { varDecls = varDecls.withModifiers(ListUtils.map(varDecls.getModifiers(), mod -> mod.getType() == J.Modifier.Type.Final ? null : mod)); statement = maybeAutoFormat(statement, varDecls, ctx, new Cursor(getCursor(), finalBody)); } diff --git a/src/main/java/org/openrewrite/java/testing/junit5/TempDirNonFinal.java b/src/main/java/org/openrewrite/java/testing/junit5/TempDirNonFinal.java index 6ba7eb1e1..d843cf349 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/TempDirNonFinal.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/TempDirNonFinal.java @@ -50,8 +50,8 @@ private static class TempDirVisitor extends JavaIsoVisitor { @Override public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { J.VariableDeclarations varDecls = super.visitVariableDeclarations(multiVariable, ctx); - if (varDecls.getLeadingAnnotations().stream().anyMatch(TEMPDIR_ANNOTATION_MATCHER::matches) - && varDecls.hasModifier(Type.Final) && isField(getCursor())) { + if (varDecls.getLeadingAnnotations().stream().anyMatch(TEMPDIR_ANNOTATION_MATCHER::matches) && + varDecls.hasModifier(Type.Final) && isField(getCursor())) { return maybeAutoFormat(varDecls, varDecls.withModifiers(ListUtils .map(varDecls.getModifiers(), modifier -> modifier.getType() == Type.Final ? null : modifier)), ctx, getCursor().getParentOrThrow()); diff --git a/src/main/java/org/openrewrite/java/testing/junit5/TemporaryFolderToTempDir.java b/src/main/java/org/openrewrite/java/testing/junit5/TemporaryFolderToTempDir.java index d67f5b5a9..d6b3bf130 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/TemporaryFolderToTempDir.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/TemporaryFolderToTempDir.java @@ -49,7 +49,7 @@ public TreeVisitor getVisitor() { final AnnotationMatcher classRule = new AnnotationMatcher("@org.junit.ClassRule"); final AnnotationMatcher rule = new AnnotationMatcher("@org.junit.Rule"); - + private JavaParser.@Nullable Builder javaParser; private JavaParser.Builder javaParser(ExecutionContext ctx) { @@ -103,16 +103,16 @@ public J visitVariableDeclarations(J.VariableDeclarations multiVariable, Executi } private boolean isRuleAnnotatedTemporaryFolder(J.VariableDeclarations vd) { - return TypeUtils.isOfClassType(vd.getTypeAsFullyQualified(), "org.junit.rules.TemporaryFolder") - && vd.getLeadingAnnotations().stream().anyMatch(anno -> classRule.matches(anno) || rule.matches(anno)); + return TypeUtils.isOfClassType(vd.getTypeAsFullyQualified(), "org.junit.rules.TemporaryFolder") && + vd.getLeadingAnnotations().stream().anyMatch(anno -> classRule.matches(anno) || rule.matches(anno)); } @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + public @Nullable J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); updateCursor(mi); - if (mi.getSelect() != null && mi.getMethodType() != null - && TypeUtils.isOfClassType(mi.getMethodType().getDeclaringType(), "org.junit.rules.TemporaryFolder")) { + if (mi.getSelect() != null && mi.getMethodType() != null && + TypeUtils.isOfClassType(mi.getMethodType().getDeclaringType(), "org.junit.rules.TemporaryFolder")) { switch (mi.getSimpleName()) { case "newFile": return convertToNewFile(mi, ctx); @@ -157,7 +157,7 @@ private J convertToNewFile(J.MethodInvocation mi, ExecutionContext ctx) { private static class AddNewFolderMethod extends JavaIsoVisitor { private final J.MethodInvocation methodInvocation; - + private JavaParser.@Nullable Builder javaParser; private JavaParser.Builder javaParser(ExecutionContext ctx) { @@ -236,7 +236,7 @@ private static class TranslateNewFolderMethodInvocation extends JavaVisitor javaParser; private JavaParser.Builder javaParser(ExecutionContext ctx) { diff --git a/src/main/java/org/openrewrite/java/testing/junit5/TestRuleToTestInfo.java b/src/main/java/org/openrewrite/java/testing/junit5/TestRuleToTestInfo.java index 53e3c4fb0..5d97b74dc 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/TestRuleToTestInfo.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/TestRuleToTestInfo.java @@ -101,7 +101,7 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m } @Override - public J.NewClass visitNewClass(J.NewClass newClass, ExecutionContext ctx) { + public J.@Nullable NewClass visitNewClass(J.NewClass newClass, ExecutionContext ctx) { J.NewClass nc = super.visitNewClass(newClass, ctx); if (TypeUtils.isOfClassType(nc.getType(), "org.junit.rules.TestName")) { //noinspection ConstantConditions diff --git a/src/main/java/org/openrewrite/java/testing/junit5/UpdateTestAnnotation.java b/src/main/java/org/openrewrite/java/testing/junit5/UpdateTestAnnotation.java index dbe906653..ddae37181 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/UpdateTestAnnotation.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/UpdateTestAnnotation.java @@ -135,8 +135,8 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex assert lambda != null; - if (cta.expectedException instanceof J.FieldAccess - && TypeUtils.isAssignableTo("org.junit.Test$None", ((J.FieldAccess) cta.expectedException).getTarget().getType())) { + if (cta.expectedException instanceof J.FieldAccess && + TypeUtils.isAssignableTo("org.junit.Test$None", ((J.FieldAccess) cta.expectedException).getTarget().getType())) { m = JavaTemplate.builder("assertDoesNotThrow(#{any(org.junit.jupiter.api.function.Executable)});") .javaParser(javaParser(ctx)) .staticImports("org.junit.jupiter.api.Assertions.assertDoesNotThrow") @@ -150,7 +150,9 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex .build() .apply(updateCursor(m), m.getCoordinates().replaceBody(), cta.expectedException, lambda); m = m.withThrows(Collections.emptyList()); - maybeAddImport("org.junit.jupiter.api.Assertions", "assertThrows"); + // Unconditionally add the import for assertThrows, got a report where the above template adds the method successfully + // but with missing type attribution for assertThrows so the import was missing + maybeAddImport("org.junit.jupiter.api.Assertions", "assertThrows", false); } } if (cta.timeout != null) { diff --git a/src/main/java/org/openrewrite/java/testing/junit5/UseAssertSame.java b/src/main/java/org/openrewrite/java/testing/junit5/UseAssertSame.java new file mode 100644 index 000000000..1dc6f250f --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/junit5/UseAssertSame.java @@ -0,0 +1,106 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.junit5; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; + +import java.util.ArrayList; +import java.util.List; + +public class UseAssertSame extends Recipe { + @Override + public String getDisplayName() { + return "Use JUnit5's `assertSame` or `assertNotSame` instead of `assertTrue(... == ...)`"; + } + + @Override + public String getDescription() { + return "Prefers the usage of `assertSame` or `assertNotSame` methods instead of using of vanilla `assertTrue` " + + "or `assertFalse` with a boolean comparison."; + } + + private static final MethodMatcher ASSERT_TRUE_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertTrue(..)"); + private static final MethodMatcher ASSERT_FALSE_MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertFalse(..)"); + + @Override + public TreeVisitor getVisitor() { + JavaIsoVisitor visitor = new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocation, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(methodInvocation, ctx); + if (!ASSERT_TRUE_MATCHER.matches(mi) && !ASSERT_FALSE_MATCHER.matches(mi)) { + return mi; + } else if (mi.getMethodType() == null) { + return mi; + } + + Expression firstArgument = mi.getArguments().get(0); + if (!(firstArgument instanceof J.Binary)) { + return mi; + } + J.Binary binary = (J.Binary) firstArgument; + if (binary.getOperator() != J.Binary.Type.Equal && binary.getOperator() != J.Binary.Type.NotEqual) { + return mi; + } + List newArguments = new ArrayList<>(); + newArguments.add(binary.getLeft()); + newArguments.add(binary.getRight()); + newArguments.addAll(mi.getArguments().subList(1, mi.getArguments().size())); + + String newMethodName = binary.getOperator() == J.Binary.Type.Equal == ASSERT_TRUE_MATCHER.matches(mi) ? + "assertSame" : "assertNotSame"; + + maybeRemoveImport("org.junit.jupiter.api.Assertions"); + maybeAddImport("org.junit.jupiter.api.Assertions", newMethodName); + + JavaType.Method newType = assertSameMethodType(mi, newMethodName); + return mi.withName(mi.getName().withSimpleName(newMethodName).withType(newType)) + .withMethodType(newType) + .withArguments(newArguments); + } + + private JavaType.Method assertSameMethodType(J.MethodInvocation mi, String newMethodName) { + JavaType.Method assertTrue = mi.getMethodType(); + assert assertTrue != null; + int parameterCount = assertTrue.getParameterTypes().size(); + JavaType.FullyQualified assertions = assertTrue.getDeclaringType(); + for (JavaType.Method method : assertions.getMethods()) { + if (method.getName().equals("assertSame") && method.getParameterNames().size() == parameterCount + 1 && + assertTrue.getParameterTypes().get(parameterCount - 1).equals(method.getParameterTypes().get(parameterCount))) { + return method; + } + } + // fallback when type attribution was stubbed + return assertTrue.withName(newMethodName); + } + }; + return Preconditions.check( + Preconditions.or( + new UsesMethod<>(ASSERT_TRUE_MATCHER), + new UsesMethod<>(ASSERT_FALSE_MATCHER)), + visitor); + } + +} diff --git a/src/main/java/org/openrewrite/java/testing/junit5/UseTestMethodOrder.java b/src/main/java/org/openrewrite/java/testing/junit5/UseTestMethodOrder.java index 5fa7ef266..4525701a8 100644 --- a/src/main/java/org/openrewrite/java/testing/junit5/UseTestMethodOrder.java +++ b/src/main/java/org/openrewrite/java/testing/junit5/UseTestMethodOrder.java @@ -45,7 +45,7 @@ public String getDescription() { public TreeVisitor getVisitor() { return Preconditions.check(new UsesType<>("org.junit.FixMethodOrder", false), new JavaIsoVisitor() { - + private JavaParser.@Nullable Builder javaParser; private JavaParser.Builder javaParser(ExecutionContext ctx) { diff --git a/src/main/java/org/openrewrite/java/testing/mockito/CleanupMockitoImports.java b/src/main/java/org/openrewrite/java/testing/mockito/CleanupMockitoImports.java index 2a120e833..08ada5309 100644 --- a/src/main/java/org/openrewrite/java/testing/mockito/CleanupMockitoImports.java +++ b/src/main/java/org/openrewrite/java/testing/mockito/CleanupMockitoImports.java @@ -153,9 +153,9 @@ private static class QualifiedMockitoMethodTypeVisitor extends JavaIsoVisitor

  • qualifiedMethods) { J.MethodInvocation mi = super.visitMethodInvocation(method, qualifiedMethods); - if (MOCKITO_METHOD_NAMES.contains(mi.getSimpleName()) - && mi.getSelect() != null - && TypeUtils.isAssignableTo("org.mockito.Mockito", mi.getSelect().getType())) { + if (MOCKITO_METHOD_NAMES.contains(mi.getSimpleName()) && + mi.getSelect() != null && + TypeUtils.isAssignableTo("org.mockito.Mockito", mi.getSelect().getType())) { qualifiedMethods.add(mi.getSimpleName()); } return mi; diff --git a/src/main/java/org/openrewrite/java/testing/mockito/MockitoUtils.java b/src/main/java/org/openrewrite/java/testing/mockito/MockitoUtils.java new file mode 100644 index 000000000..ad143e008 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/mockito/MockitoUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.Cursor; +import org.openrewrite.ExecutionContext; +import org.openrewrite.java.AnnotationMatcher; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.JavaVisitor; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.Statement; + +import java.util.List; +import java.util.stream.Collectors; + +public class MockitoUtils { + public static J.ClassDeclaration maybeAddMethodWithAnnotation( + JavaVisitor visitor, + J.ClassDeclaration classDecl, + ExecutionContext ctx, + boolean isPublic, + String methodName, + String methodAnnotationSignature, + String methodAnnotationToAdd, + String additionalClasspathResource, + String importToAdd, + String methodAnnotationParameters + ) { + if (hasMethodWithAnnotation(classDecl, new AnnotationMatcher(methodAnnotationSignature))) { + return classDecl; + } + + J.MethodDeclaration firstTestMethod = getFirstTestMethod( + classDecl.getBody().getStatements().stream().filter(J.MethodDeclaration.class::isInstance) + .map(J.MethodDeclaration.class::cast).collect(Collectors.toList())); + + visitor.maybeAddImport(importToAdd); + String tplStr = methodAnnotationToAdd + methodAnnotationParameters + + (isPublic ? " public" : "") + " void " + methodName + "() {}"; + return JavaTemplate.builder(tplStr) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, additionalClasspathResource)) + .imports(importToAdd) + .build() + .apply( + new Cursor(visitor.getCursor().getParentOrThrow(), classDecl), + (firstTestMethod != null) ? + firstTestMethod.getCoordinates().before() : + classDecl.getBody().getCoordinates().lastStatement() + ); + } + + private static boolean hasMethodWithAnnotation(J.ClassDeclaration classDecl, AnnotationMatcher annotationMatcher) { + for (Statement statement : classDecl.getBody().getStatements()) { + if (statement instanceof J.MethodDeclaration) { + J.MethodDeclaration methodDeclaration = (J.MethodDeclaration) statement; + List allAnnotations = methodDeclaration.getAllAnnotations(); + for (J.Annotation annotation : allAnnotations) { + if (annotationMatcher.matches(annotation)) { + return true; + } + } + } + } + return false; + } + + private static J.@Nullable MethodDeclaration getFirstTestMethod(List methods) { + for (J.MethodDeclaration methodDeclaration : methods) { + for (J.Annotation annotation : methodDeclaration.getLeadingAnnotations()) { + if ("Test".equals(annotation.getSimpleName())) { + return methodDeclaration; + } + } + } + return null; + } +} diff --git a/src/main/java/org/openrewrite/java/testing/mockito/MockitoWhenOnStaticToMockStatic.java b/src/main/java/org/openrewrite/java/testing/mockito/MockitoWhenOnStaticToMockStatic.java new file mode 100644 index 000000000..52c9c9200 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/mockito/MockitoWhenOnStaticToMockStatic.java @@ -0,0 +1,136 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.VariableNameUtils; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Flag; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.Statement; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class MockitoWhenOnStaticToMockStatic extends Recipe { + + private static final MethodMatcher MOCKITO_WHEN = new MethodMatcher("org.mockito.Mockito when(..)"); + + @Override + public String getDisplayName() { + return "Replace `Mockito.when` on static (non mock) with try-with-resource with MockedStatic"; + } + + @Override + public String getDescription() { + return "Replace `Mockito.when` on static (non mock) with try-with-resource with MockedStatic as Mockito4 no longer allows this."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesMethod<>(MOCKITO_WHEN), new JavaIsoVisitor() { + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { + J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx); + if (m.getBody() == null) { + return m; + } + + List newStatements = maybeWrapStatementsInTryWithResourcesMockedStatic(m, m.getBody().getStatements()); + return maybeAutoFormat(m, m.withBody(m.getBody().withStatements(newStatements)), ctx); + } + + private List maybeWrapStatementsInTryWithResourcesMockedStatic(J.MethodDeclaration m, List remainingStatements) { + AtomicBoolean restInTry = new AtomicBoolean(false); + return ListUtils.flatMap(remainingStatements, (index, statement) -> { + if (restInTry.get()) { + // Rest of the statements have ended up in the try block + return Collections.emptyList(); + } + + if (statement instanceof J.MethodInvocation && + MOCKITO_WHEN.matches(((J.MethodInvocation) statement).getSelect())) { + J.MethodInvocation when = (J.MethodInvocation) ((J.MethodInvocation) statement).getSelect(); + if (when != null && when.getArguments().get(0) instanceof J.MethodInvocation) { + J.MethodInvocation whenArg = (J.MethodInvocation) when.getArguments().get(0); + if (whenArg.getMethodType() != null && whenArg.getMethodType().hasFlags(Flag.Static)) { + if (whenArg.getSelect() instanceof J.Identifier) { + J.Identifier clazz = (J.Identifier) whenArg.getSelect(); + if (clazz.getType() != null) { + return tryWithMockedStatic(m, remainingStatements, index, statement, clazz.getSimpleName(), whenArg, restInTry); + } + } else if (whenArg.getSelect() instanceof J.FieldAccess) { + J.FieldAccess fieldAccess = (J.FieldAccess) whenArg.getSelect(); + if (fieldAccess.getTarget() instanceof J.Identifier) { + J.Identifier clazz = (J.Identifier) fieldAccess.getTarget(); + if (clazz.getType() != null) { + return tryWithMockedStatic(m, remainingStatements, index, statement, clazz.getSimpleName(), whenArg, restInTry); + } + } + } + } + } + } + return statement; + }); + } + + private J.Try tryWithMockedStatic( + J.MethodDeclaration m, + List remainingStatements, + Integer index, + Statement statement, + String simpleName, + J.MethodInvocation whenArg, + AtomicBoolean restInTry) { + String mockName = VariableNameUtils.generateVariableName("mock" + simpleName, updateCursor(m), VariableNameUtils.GenerationStrategy.INCREMENT_NUMBER); + maybeAddImport("org.mockito.MockedStatic", false); + maybeAddImport("org.mockito.Mockito", "mockStatic"); + String template = String.format( + "try(MockedStatic<%1$s> %2$s = mockStatic(%1$s.class)) {\n" + + " %2$s.when(#{any()}).thenReturn(#{any()});\n" + + "}", simpleName, mockName); + J.Try try_ = (J.Try) ((J.MethodDeclaration) JavaTemplate.builder(template) + .contextSensitive() + .imports("org.mockito.MockedStatic") + .staticImports("org.mockito.Mockito.mockStatic") + .build() + .apply(getCursor(), m.getCoordinates().replaceBody(), + whenArg, ((J.MethodInvocation) statement).getArguments().get(0))) + .getBody().getStatements().get(0); + + restInTry.set(true); + + List precedingStatements = remainingStatements.subList(0, index); + return try_.withBody(try_.getBody().withStatements(ListUtils.concatAll( + try_.getBody().getStatements(), + maybeWrapStatementsInTryWithResourcesMockedStatic( + m.withBody(m.getBody().withStatements(ListUtils.concat(precedingStatements, try_))), + remainingStatements.subList(index + 1, remainingStatements.size()) + )))) + .withPrefix(statement.getPrefix()); + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java b/src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java new file mode 100644 index 000000000..923f0e055 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java @@ -0,0 +1,72 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.openrewrite.*; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.AnnotationMatcher; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.service.AnnotationService; +import org.openrewrite.java.tree.J; + +import java.util.Iterator; + +public class NoInitializationForInjectMock extends Recipe { + + private static final AnnotationMatcher INJECT_MOCKS = new AnnotationMatcher("@org.mockito.InjectMocks"); + + @Override + public String getDisplayName() { + return "Remove initialization when using `@InjectMocks`"; + } + + @Override + public String getDescription() { + return "Removes unnecessary initialization for fields annotated with `@InjectMocks` in Mockito tests."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesType<>("org.mockito.*", false), new JavaIsoVisitor() { + @Override + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations variableDeclarations, ExecutionContext ctx) { + J.VariableDeclarations vd = super.visitVariableDeclarations(variableDeclarations, ctx); + + if (isField(getCursor()) && new AnnotationService().matches(getCursor(), INJECT_MOCKS)) { + return vd.withVariables(ListUtils.map(vd.getVariables(), it -> it.withInitializer(null))); + } + + return vd; + } + + // copied from org.openrewrite.java.search.FindFieldsOfType.isField(Cursor), should probably become part of the API + private boolean isField(Cursor cursor) { + Iterator path = cursor.getPath(); + while (path.hasNext()) { + Object o = path.next(); + if (o instanceof J.MethodDeclaration) { + return false; + } + if (o instanceof J.ClassDeclaration) { + return true; + } + } + return true; + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockito.java b/src/main/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockito.java index c1f7d2133..dbc259a8e 100644 --- a/src/main/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockito.java +++ b/src/main/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockito.java @@ -26,6 +26,8 @@ import java.util.*; import java.util.stream.Collectors; +import static org.openrewrite.java.testing.mockito.MockitoUtils.maybeAddMethodWithAnnotation; + public class PowerMockitoMockStaticToMockito extends Recipe { @Override @@ -168,7 +170,7 @@ public J visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx } @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + public @Nullable J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); Map mockStaticInvocationsByClassName = getCursor().getNearestMessage(MOCK_STATIC_INVOCATIONS); @@ -190,7 +192,9 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) if (MOCKED_STATIC_MATCHER.matches(mi)) { determineTestGroups(); - if (!getCursor().getPath(o -> o instanceof J.Assignment || o instanceof J.Try.Resource).hasNext()) { + if (!getCursor().getPath(o -> o instanceof J.VariableDeclarations || + o instanceof J.Assignment || + o instanceof J.Try.Resource).hasNext()) { //noinspection DataFlowIssue return null; } @@ -211,32 +215,6 @@ private static boolean isFieldAlreadyDefined(J.Block classBody, String fieldName return false; } - private static J.@Nullable MethodDeclaration getFirstTestMethod(List methods) { - for (J.MethodDeclaration methodDeclaration : methods) { - for (J.Annotation annotation : methodDeclaration.getLeadingAnnotations()) { - if ("Test".equals(annotation.getSimpleName())) { - return methodDeclaration; - } - } - } - return null; - } - - private static boolean hasMethodWithAnnotation(J.ClassDeclaration classDecl, AnnotationMatcher annotationMatcher) { - for (Statement statement : classDecl.getBody().getStatements()) { - if (statement instanceof J.MethodDeclaration) { - J.MethodDeclaration methodDeclaration = (J.MethodDeclaration) statement; - List allAnnotations = methodDeclaration.getAllAnnotations(); - for (J.Annotation annotation : allAnnotations) { - if (annotationMatcher.matches(annotation)) { - return true; - } - } - } - } - return false; - } - private static boolean isStaticMockAlreadyClosed(J.Identifier staticMock, J.Block methodBody) { for (Statement statement : methodBody.getStatements()) { if (statement instanceof J.MethodInvocation) { @@ -463,7 +441,7 @@ private J.ClassDeclaration addFieldDeclarationForMockedTypes(J.ClassDeclaration private J.ClassDeclaration maybeAddSetUpMethodBody(J.ClassDeclaration classDecl, ExecutionContext ctx) { String testGroupsAsString = getTestGroupsAsString(); - return maybeAddMethodWithAnnotation(classDecl, ctx, "setUpStaticMocks", + return maybeAddMethodWithAnnotation(this, classDecl, ctx, false, "setUpStaticMocks", setUpMethodAnnotationSignature, setUpMethodAnnotation, additionalClasspathResource, setUpImportToAdd, testGroupsAsString); } @@ -481,38 +459,12 @@ private String getTestGroupsAsString() { private J.ClassDeclaration maybeAddTearDownMethodBody(J.ClassDeclaration classDecl, ExecutionContext ctx) { String testGroupsAsString = (getTestGroupsAsString().isEmpty()) ? tearDownMethodAnnotationParameters : getTestGroupsAsString(); - return maybeAddMethodWithAnnotation(classDecl, ctx, "tearDownStaticMocks", + return maybeAddMethodWithAnnotation(this, classDecl, ctx, false, "tearDownStaticMocks", tearDownMethodAnnotationSignature, tearDownMethodAnnotation, additionalClasspathResource, tearDownImportToAdd, testGroupsAsString); } - private J.ClassDeclaration maybeAddMethodWithAnnotation(J.ClassDeclaration classDecl, ExecutionContext ctx, - String methodName, String methodAnnotationSignature, - String methodAnnotationToAdd, - String additionalClasspathResource, String importToAdd, - String methodAnnotationParameters) { - if (hasMethodWithAnnotation(classDecl, new AnnotationMatcher(methodAnnotationSignature))) { - return classDecl; - } - - J.MethodDeclaration firstTestMethod = getFirstTestMethod( - classDecl.getBody().getStatements().stream().filter(J.MethodDeclaration.class::isInstance) - .map(J.MethodDeclaration.class::cast).collect(Collectors.toList())); - - maybeAddImport(importToAdd); - return JavaTemplate.builder(methodAnnotationToAdd + methodAnnotationParameters + " void " + methodName + "() {}") - .contextSensitive() - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, additionalClasspathResource)) - .imports(importToAdd) - .build() - .apply( - new Cursor(getCursor().getParentOrThrow(), classDecl), - (firstTestMethod != null) ? - firstTestMethod.getCoordinates().before() : - classDecl.getBody().getCoordinates().lastStatement() - ); - } private J.MethodInvocation modifyWhenMethodInvocation(J.MethodInvocation whenMethod) { List methodArguments = whenMethod.getArguments(); diff --git a/src/main/java/org/openrewrite/java/testing/mockito/RetainStrictnessWarn.java b/src/main/java/org/openrewrite/java/testing/mockito/RetainStrictnessWarn.java deleted file mode 100644 index 9a5ef294b..000000000 --- a/src/main/java/org/openrewrite/java/testing/mockito/RetainStrictnessWarn.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - *

    - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * https://www.apache.org/licenses/LICENSE-2.0 - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.java.testing.mockito; - -import org.jspecify.annotations.Nullable; -import org.openrewrite.*; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.JavaParser; -import org.openrewrite.java.JavaTemplate; -import org.openrewrite.java.RemoveAnnotation; -import org.openrewrite.java.dependencies.DependencyInsight; -import org.openrewrite.java.search.FindAnnotations; -import org.openrewrite.java.search.UsesType; -import org.openrewrite.java.tree.J; - -import java.util.Comparator; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -public class RetainStrictnessWarn extends ScanningRecipe { - - private static final String EXTEND_WITH_FQ = "org.junit.jupiter.api.extension.ExtendWith"; - private static final String MOCKITO_EXTENSION_FQ = "org.mockito.junit.jupiter.MockitoExtension"; - private static final String MOCKITO_SETTINGS_FQ = "org.mockito.junit.jupiter.MockitoSettings"; - private static final String MOCKITO_STRICTNESS_FQ = "org.mockito.quality.Strictness"; - - private static final String EXTEND_WITH_MOCKITO_EXTENSION = "@" + EXTEND_WITH_FQ + "(" + MOCKITO_EXTENSION_FQ + ".class)"; - - @Override - public String getDisplayName() { - return "Retain Mockito strictness `WARN` when switching to JUnit 5"; - } - - @Override - public String getDescription() { - return "Migrating from JUnit 4 to 5 [changes the default strictness](https://stackoverflow.com/a/53234137/53444) of the mocks from `WARN` to `STRICT_STUBS`. " + - "To prevent tests from failing we restore the original behavior by adding `@MockitoSettings(strictness = Strictness.WARN)`."; - } - - @Override - public AtomicBoolean getInitialValue(ExecutionContext ctx) { - return new AtomicBoolean(false); - } - - @Override - public TreeVisitor getScanner(AtomicBoolean usingOlderMockito) { - TreeVisitor div = new DependencyInsight("org.mockito", "mockito-*", "[1.1,2.17)").getVisitor(); - return new TreeVisitor() { - @Override - public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { - if (!usingOlderMockito.get() && div.visit(tree, ctx) != tree) { - usingOlderMockito.set(true); - } - return tree; - } - }; - } - - @Override - public TreeVisitor getVisitor(AtomicBoolean usingOlderMockito) { - return Preconditions.check(usingOlderMockito.get(), - Preconditions.check( - Preconditions.and( - new UsesType<>(MOCKITO_EXTENSION_FQ, true), - Preconditions.not(new UsesType<>(MOCKITO_SETTINGS_FQ, false)) - ), new JavaIsoVisitor() { - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { - Set annotations = FindAnnotations.find(classDecl, EXTEND_WITH_MOCKITO_EXTENSION); - if (!annotations.isEmpty()) { - maybeAddImport(MOCKITO_SETTINGS_FQ); - maybeAddImport(MOCKITO_STRICTNESS_FQ); - classDecl = JavaTemplate.builder("@MockitoSettings(strictness = Strictness.WARN)") - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-junit-jupiter", "mockito-core")) - .imports(MOCKITO_SETTINGS_FQ, MOCKITO_STRICTNESS_FQ) - .build() - .apply(getCursor(), classDecl.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); - doAfterVisit(new RemoveAnnotation(EXTEND_WITH_MOCKITO_EXTENSION).getVisitor()); - maybeRemoveImport(EXTEND_WITH_FQ); - maybeRemoveImport(MOCKITO_EXTENSION_FQ); - } - return super.visitClassDeclaration(classDecl, ctx); - } - }) - ); - } -} diff --git a/src/main/java/org/openrewrite/java/testing/mockito/SimplifyMockitoVerifyWhenGiven.java b/src/main/java/org/openrewrite/java/testing/mockito/SimplifyMockitoVerifyWhenGiven.java new file mode 100644 index 000000000..e837aa9be --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/mockito/SimplifyMockitoVerifyWhenGiven.java @@ -0,0 +1,92 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.MethodCall; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class SimplifyMockitoVerifyWhenGiven extends Recipe { + + private static final MethodMatcher WHEN_MATCHER = new MethodMatcher("org.mockito.Mockito when(..)"); + private static final MethodMatcher GIVEN_MATCHER = new MethodMatcher("org.mockito.BDDMockito given(..)"); + private static final MethodMatcher VERIFY_MATCHER = new MethodMatcher("org.mockito.Mockito verify(..)"); + private static final MethodMatcher STUBBER_MATCHER = new MethodMatcher("org.mockito.stubbing.Stubber when(..)"); + private static final MethodMatcher EQ_MATCHER = new MethodMatcher("org.mockito.ArgumentMatchers eq(..)"); + private static final MethodMatcher MOCKITO_EQ_MATCHER = new MethodMatcher("org.mockito.Mockito eq(..)"); + + @Override + public String getDisplayName() { + return "Call to Mockito method \"verify\", \"when\" or \"given\" should be simplified"; + } + + @Override + public String getDescription() { + return "Fixes Sonar issue `java:S6068`: Call to Mockito method \"verify\", \"when\" or \"given\" should be simplified."; + } + + @Override + public Set getTags() { + return Collections.singleton("RSPEC-6068"); + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(Preconditions.or(new UsesMethod<>(EQ_MATCHER), new UsesMethod<>(MOCKITO_EQ_MATCHER)), + new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocation, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(methodInvocation, ctx); + + if ((WHEN_MATCHER.matches(mi) || GIVEN_MATCHER.matches(mi)) && mi.getArguments().get(0) instanceof J.MethodInvocation) { + List updatedArguments = new ArrayList<>(mi.getArguments()); + updatedArguments.set(0, checkAndUpdateEq((J.MethodInvocation) mi.getArguments().get(0))); + mi = mi.withArguments(updatedArguments); + } else if (VERIFY_MATCHER.matches(mi.getSelect()) || + STUBBER_MATCHER.matches(mi.getSelect())) { + mi = checkAndUpdateEq(mi); + } + + maybeRemoveImport("org.mockito.ArgumentMatchers.eq"); + maybeRemoveImport("org.mockito.Mockito.eq"); + return mi; + } + + private J.MethodInvocation checkAndUpdateEq(J.MethodInvocation methodInvocation) { + if (methodInvocation.getArguments().stream().allMatch(arg -> EQ_MATCHER.matches(arg) || + MOCKITO_EQ_MATCHER.matches(arg))) { + return methodInvocation.withArguments(ListUtils.map(methodInvocation.getArguments(), invocation -> + ((MethodCall) invocation).getArguments().get(0).withPrefix(invocation.getPrefix()))); + } + return methodInvocation; + } + }); + } + +} diff --git a/src/main/java/org/openrewrite/java/testing/mockito/VerifyZeroToNoMoreInteractions.java b/src/main/java/org/openrewrite/java/testing/mockito/VerifyZeroToNoMoreInteractions.java new file mode 100644 index 000000000..2315e88ba --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/mockito/VerifyZeroToNoMoreInteractions.java @@ -0,0 +1,84 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.java.ChangeMethodName; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.dependencies.DependencyInsight; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.J; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class VerifyZeroToNoMoreInteractions extends ScanningRecipe { + + private static final String VERIFY_ZERO_INTERACTIONS = "org.mockito.Mockito verifyZeroInteractions(..)"; + private static final MethodMatcher ASSERT_INSTANCE_OF_MATCHER = new MethodMatcher(VERIFY_ZERO_INTERACTIONS, true); + + @Override + public String getDisplayName() { + return "Replace `verifyZeroInteractions() to `verifyNoMoreInteractions()"; + } + + @Override + public String getDescription() { + return "Replaces `verifyZeroInteractions()` with `verifyNoMoreInteractions()` in Mockito tests when migration when using a Mockito version < 3.x."; + } + + @Override + public AtomicBoolean getInitialValue(final ExecutionContext ctx) { + return new AtomicBoolean(false); + } + + @Override + public TreeVisitor getScanner(AtomicBoolean usingOlderMockito) { + TreeVisitor div = new DependencyInsight("org.mockito", "mockito-*", "[1.0,3.0)", null).getVisitor(); + return new TreeVisitor() { + @Override + public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + if (!usingOlderMockito.get() && div.visit(tree, ctx) != tree) { + usingOlderMockito.set(true); + } + return tree; + } + }; + } + + @Override + public TreeVisitor getVisitor(AtomicBoolean usingOlderMockito) { + return Preconditions.check(usingOlderMockito.get(), + Preconditions.check(new UsesMethod<>(ASSERT_INSTANCE_OF_MATCHER), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation md = super.visitMethodInvocation(method, ctx); + + if (!ASSERT_INSTANCE_OF_MATCHER.matches(md)) { + return md; + } + + maybeAddImport("org.mockito.Mockito", "verifyNoMoreInteractions"); + maybeRemoveImport("org.mockito.Mockito.verifyZeroInteractions"); + + ChangeMethodName changeMethodName = new ChangeMethodName(VERIFY_ZERO_INTERACTIONS, "verifyNoMoreInteractions", false, false); + return (J.MethodInvocation) changeMethodName.getVisitor().visitNonNull(md, ctx); + } + }) + ); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/testng/TestNgAssertEqualsToAssertThat.java b/src/main/java/org/openrewrite/java/testing/testng/TestNgAssertEqualsToAssertThat.java new file mode 100644 index 000000000..08ab531ed --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/testng/TestNgAssertEqualsToAssertThat.java @@ -0,0 +1,136 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.testng; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; + +import java.util.List; + +public class TestNgAssertEqualsToAssertThat extends Recipe { + + @Override + public String getDisplayName() { + return "TestNG `assertEquals` to AssertJ"; + } + + @Override + public String getDescription() { + return "Convert TestNG-style `assertEquals()` to AssertJ's `assertThat().isEqualTo()`."; + } + + private static final MethodMatcher TESTNG_ASSERT_METHOD = new MethodMatcher("org.testng.Assert assertEquals(..)"); + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesMethod<>(TESTNG_ASSERT_METHOD), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + if (!TESTNG_ASSERT_METHOD.matches(method)) { + return method; + } + + List args = method.getArguments(); + Expression expected = args.get(1); + Expression actual = args.get(0); + + //always add the import (even if not referenced) + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + + // Remove import for "org.testng.Assert" if no longer used. + maybeRemoveImport("org.testng.Assert"); + + if (args.size() == 2) { + return JavaTemplate.builder("assertThat(#{any()}).isEqualTo(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), method.getCoordinates().replace(), actual, expected); + } else if (args.size() == 3 && !isFloatingPointType(args.get(2))) { + Expression message = args.get(2); + return JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isEqualTo(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .imports("java.util.function.Supplier") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply( + getCursor(), + method.getCoordinates().replace(), + actual, + message, + expected + ); + } else if (args.size() == 3) { + //always add the import (even if not referenced) + maybeAddImport("org.assertj.core.api.Assertions", "within", false); + return JavaTemplate.builder("assertThat(#{any()}).isCloseTo(#{any()}, within(#{any()}));") + .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply(getCursor(), method.getCoordinates().replace(), actual, expected, args.get(2)); + + } + + // The assertEquals is using a floating point with a delta argument and a message. + Expression message = args.get(3); + + //always add the import (even if not referenced) + maybeAddImport("org.assertj.core.api.Assertions", "within", false); + return JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isCloseTo(#{any()}, within(#{any()}));") + .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") + .imports("java.util.function.Supplier") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply( + getCursor(), + method.getCoordinates().replace(), + actual, + message, + expected, + args.get(2) + ); + } + + private boolean isFloatingPointType(Expression expression) { + + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); + if (fullyQualified != null) { + String typeName = fullyQualified.getFullyQualifiedName(); + return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + } + + JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); + return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; + } + }); + } + +} diff --git a/src/main/java/org/openrewrite/java/testing/testng/TestNgAssertNotEqualsToAssertThat.java b/src/main/java/org/openrewrite/java/testing/testng/TestNgAssertNotEqualsToAssertThat.java new file mode 100644 index 000000000..bbe8e218b --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/testng/TestNgAssertNotEqualsToAssertThat.java @@ -0,0 +1,143 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.testng; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; + +import java.util.List; + +public class TestNgAssertNotEqualsToAssertThat extends Recipe { + + @Override + public String getDisplayName() { + return "TestNG `assertNotEquals` to AssertJ"; + } + + @Override + public String getDescription() { + return "Convert TestNG-style `assertNotEquals()` to AssertJ's `assertThat().isNotEqualTo()`."; + } + + private static final MethodMatcher TESTNG_ASSERT_METHOD = new MethodMatcher("org.testng.Assert assertNotEquals(..)"); + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesMethod<>(TESTNG_ASSERT_METHOD), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + if (!TESTNG_ASSERT_METHOD.matches(method)) { + return method; + } + + List args = method.getArguments(); + + Expression expected = args.get(1); + Expression actual = args.get(0); + + if (args.size() == 2) { + method = JavaTemplate.builder("assertThat(#{any()}).isNotEqualTo(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply( + getCursor(), + method.getCoordinates().replace(), + actual, + expected + ); + } else if (args.size() == 3 && !isFloatingPointType(args.get(2))) { + Expression message = args.get(2); + method = JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isNotEqualTo(#{any()});") + .staticImports("org.assertj.core.api.Assertions.assertThat") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply( + getCursor(), + method.getCoordinates().replace(), + actual, + message, + expected + ); + } else if (args.size() == 3) { + method = JavaTemplate.builder("assertThat(#{any()}).isNotCloseTo(#{any()}, within(#{any()}));") + .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply( + getCursor(), + method.getCoordinates().replace(), + actual, + expected, + args.get(2) + ); + maybeAddImport("org.assertj.core.api.Assertions", "within", false); + } else { + Expression message = args.get(3); + method = JavaTemplate.builder("assertThat(#{any()}).as(#{any(String)}).isNotCloseTo(#{any()}, within(#{any()}));") + .staticImports("org.assertj.core.api.Assertions.assertThat", "org.assertj.core.api.Assertions.within") + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "assertj-core-3.24")) + .build() + .apply( + getCursor(), + method.getCoordinates().replace(), + actual, + message, + expected, + args.get(2) + ); + + maybeAddImport("org.assertj.core.api.Assertions", "within", false); + } + + //Make sure there is a static import for "org.assertj.core.api.Assertions.assertThat" (even if not referenced) + maybeAddImport("org.assertj.core.api.Assertions", "assertThat", false); + + // Remove import for "org.testng.Assert" if no longer used. + maybeRemoveImport("org.testng.Assert"); + + return method; + } + + private boolean isFloatingPointType(Expression expression) { + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(expression.getType()); + if (fullyQualified != null) { + String typeName = fullyQualified.getFullyQualifiedName(); + return "java.lang.Double".equals(typeName) || "java.lang.Float".equals(typeName); + } + + JavaType.Primitive parameterType = TypeUtils.asPrimitive(expression.getType()); + return parameterType == JavaType.Primitive.Double || parameterType == JavaType.Primitive.Float; + } + }); + } + +} diff --git a/src/main/resources/META-INF/rewrite/assertj.yml b/src/main/resources/META-INF/rewrite/assertj.yml index 1ae70b513..44b426617 100644 --- a/src/main/resources/META-INF/rewrite/assertj.yml +++ b/src/main/resources/META-INF/rewrite/assertj.yml @@ -24,6 +24,7 @@ tags: recipeList: - org.openrewrite.java.testing.hamcrest.MigrateHamcrestToAssertJ - org.openrewrite.java.testing.assertj.JUnitToAssertj + - org.openrewrite.java.testing.testng.TestNgToAssertj - org.openrewrite.java.testing.assertj.StaticImports - org.openrewrite.java.testing.assertj.SimplifyChainedAssertJAssertions - org.openrewrite.java.testing.assertj.SimplifyAssertJAssertions @@ -61,6 +62,9 @@ recipeList: - org.openrewrite.java.ChangeMethodTargetToStatic: methodPattern: "org.assertj.core.api.AssertionsForInterfaceTypes assertThat(..)" fullyQualifiedTargetTypeName: "org.assertj.core.api.Assertions" + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: "org.assertj.core.api.Fail fail(..)" + fullyQualifiedTargetTypeName: "org.assertj.core.api.Assertions" - org.openrewrite.java.UseStaticImport: methodPattern: "org.assertj.core.api.Assertions *(..)" @@ -446,13 +450,16 @@ recipeList: type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.testing.assertj.JUnitToAssertj displayName: Migrate JUnit asserts to AssertJ -description: AssertJ provides a rich set of assertions, truly helpful error messages, improves test code readability. Converts assertions from `org.junit.jupiter.api.Assertions` to `org.assertj.core.api.Assertions`. +description: >- + AssertJ provides a rich set of assertions, truly helpful error messages, improves test code readability. + Converts assertions from `org.junit.jupiter.api.Assertions` to `org.assertj.core.api.Assertions`. + Will convert JUnit 4 to JUnit Jupiter if necessary to match and modify assertions. tags: - testing - assertj recipeList: # First improve the assertions for JUnit, to fix inverted expected/actual values - - org.openrewrite.java.testing.junit5.CleanupAssertions + - org.openrewrite.java.testing.junit5.JUnit5BestPractices - org.openrewrite.java.testing.assertj.JUnitAssertArrayEqualsToAssertThat - org.openrewrite.java.testing.assertj.JUnitAssertEqualsToAssertThat - org.openrewrite.java.testing.assertj.JUnitAssertFalseToAssertThat @@ -463,6 +470,7 @@ recipeList: - org.openrewrite.java.testing.assertj.JUnitAssertTrueToAssertThat - org.openrewrite.java.testing.assertj.JUnitFailToAssertJFail - org.openrewrite.java.testing.assertj.JUnitAssertThrowsToAssertExceptionType + - org.openrewrite.java.testing.assertj.JUnitAssertInstanceOfToAssertThat - org.openrewrite.java.dependencies.AddDependency: groupId: org.assertj artifactId: assertj-core diff --git a/src/main/resources/META-INF/rewrite/classpath/mockito-core-5.14.2.jar b/src/main/resources/META-INF/rewrite/classpath/mockito-core-5.14.2.jar new file mode 100644 index 000000000..f40502548 Binary files /dev/null and b/src/main/resources/META-INF/rewrite/classpath/mockito-core-5.14.2.jar differ diff --git a/src/main/resources/META-INF/rewrite/classpath/rider-junit5-1.44.0.jar b/src/main/resources/META-INF/rewrite/classpath/rider-junit5-1.44.0.jar new file mode 100644 index 000000000..8c4bbfc62 Binary files /dev/null and b/src/main/resources/META-INF/rewrite/classpath/rider-junit5-1.44.0.jar differ diff --git a/src/main/resources/META-INF/rewrite/dbrider.yml b/src/main/resources/META-INF/rewrite/dbrider.yml new file mode 100644 index 000000000..a6ecc2980 --- /dev/null +++ b/src/main/resources/META-INF/rewrite/dbrider.yml @@ -0,0 +1,32 @@ +# +# Copyright 2024 the original author or authors. +#

    +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +#

    +# https://www.apache.org/licenses/LICENSE-2.0 +#

    +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.dbrider.MigrateDbRiderSpringToDbRiderJUnit5 +displayName: Migrate rider-spring (JUnit4) to rider-junit5 (JUnit5) +description: This recipe will migrate the necessary dependencies and annotations from DbRider with JUnit4 to JUnit5 in a Spring application. +tags: + - testing + - dbrider + - spring +recipeList: + - org.openrewrite.java.testing.dbrider.ExecutionListenerToDbRiderAnnotation + - org.openrewrite.java.dependencies.ChangeDependency: + oldGroupId: com.github.database-rider + oldArtifactId: rider-spring + newArtifactId: rider-junit5 + newVersion: 1.x +--- \ No newline at end of file diff --git a/src/main/resources/META-INF/rewrite/easymock.yml b/src/main/resources/META-INF/rewrite/easymock.yml new file mode 100644 index 000000000..b6f49601f --- /dev/null +++ b/src/main/resources/META-INF/rewrite/easymock.yml @@ -0,0 +1,156 @@ +# +# Copyright 2024 the original author or authors. +#

    +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +#

    +# https://www.apache.org/licenses/LICENSE-2.0 +#

    +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.easymock.EasyMockToMockito +displayName: Migrate from EasyMock to Mockito +description: This recipe will apply changes commonly needed when migrating from EasyMock to Mockito. +tags: + - testing + - easymock +recipeList: + - org.openrewrite.java.dependencies.AddDependency: + groupId: org.mockito + artifactId: mockito-core + version: 5.x + onlyIfUsing: org.easymock.* + - org.openrewrite.java.dependencies.RemoveDependency: + groupId: org.easymock + artifactId: easymock + - org.openrewrite.java.testing.easymock.EasyMockVerifyToMockitoVerify + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IExpectationSetters times(..) + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IExpectationSetters once() + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IExpectationSetters atLeastOnce() + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IExpectationSetters anyTimes() + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IMocksControl replay(..) + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.EasyMock replay(..) + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IMocksControl verify(..) + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IMocksControl verifyRecording(..) + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.IMocksControl verifyUnexpectedCalls(..) + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.EasyMockSupport replayAll() + - org.openrewrite.java.RemoveMethodInvocations: + methodPattern: org.easymock.EasyMockSupport verifyAll() + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.IExpectationSetters andReturn(..) + newMethodName: thenReturn + ignoreDefinition: true + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.IExpectationSetters andThrow(java.lang.Throwable) + newMethodName: thenThrow + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.IExpectationSetters andAnswer(..) + newMethodName: thenAnswer + ignoreDefinition: true + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.IExpectationSetters andStubReturn(..) + newMethodName: thenReturn + ignoreDefinition: true + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.IExpectationSetters andStubThrow(java.lang.Throwable) + newMethodName: thenThrow + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.IExpectationSetters andStubAnswer(..) + newMethodName: thenAnswer + ignoreDefinition: true + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.IMocksControl mock(..) + fullyQualifiedTargetTypeName: org.mockito.Mockito + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.IMocksControl createMock(..) + fullyQualifiedTargetTypeName: org.mockito.Mockito + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: org.easymock.IArgumentMatcher + newFullyQualifiedTypeName: org.mockito.ArgumentMatcher + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock anyObject(..) + newMethodName: any + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock capture(..) + newMethodName: argThat + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock reportMatcher(..) + newMethodName: argThat + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock expect(..) + newMethodName: when + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock createNiceMock(..) + newMethodName: mock + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock createStrictMock(..) + newMethodName: mock + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock createMock(..) + newMethodName: mock + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock niceMock(..) + newMethodName: mock + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.easymock.EasyMock strictMock(..) + newMethodName: mock + - org.openrewrite.java.ReorderMethodArguments: + methodPattern: org.easymock.EasyMock mock(String, Class) + newParameterNames: + - classToMock + - name + oldParameterNames: + - name + - classToMock + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock lt(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock leq(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock gt(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock geq(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock and(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock or(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.easymock.EasyMock not(..) + fullyQualifiedTargetTypeName: org.mockito.AdditionalMatchers + - org.openrewrite.java.testing.easymock.RemoveExtendsEasyMockSupport + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: org.easymock.EasyMock + newFullyQualifiedTypeName: org.mockito.Mockito + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: org.easymock.EasyMockRunner + newFullyQualifiedTypeName: org.mockito.junit.MockitoJUnitRunner + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: org.easymock.Mock + newFullyQualifiedTypeName: org.mockito.Mock + - org.openrewrite.java.ChangeType: + oldFullyQualifiedTypeName: org.easymock.TestSubject + newFullyQualifiedTypeName: org.mockito.InjectMocks + - org.openrewrite.java.testing.mockito.MockitoBestPractices diff --git a/src/main/resources/META-INF/rewrite/hamcrest.yml b/src/main/resources/META-INF/rewrite/hamcrest.yml index 2271ea278..e08946662 100644 --- a/src/main/resources/META-INF/rewrite/hamcrest.yml +++ b/src/main/resources/META-INF/rewrite/hamcrest.yml @@ -31,9 +31,9 @@ recipeList: acceptTransitive: true --- type: specs.openrewrite.org/v1beta/recipe -name: org.openrewrite.java.testing.hamcrest.MigrateHamcrestToAssertJ -displayName: Migrate to AssertJ assertions -description: Migrate Hamcrest `assertThat(..)` to AssertJ `Assertions`. +name: org.openrewrite.java.testing.hamcrest.ConsistentHamcrestMatcherImports +displayName: Use consistent Hamcrest matcher imports +description: Use consistent imports for Hamcrest matchers, and remove wrapping `is(Matcher)` calls ahead of further changes. tags: - testing - hamcrest @@ -49,6 +49,51 @@ recipeList: # Then remove wrapping `is(Matcher)` calls such that further recipes will match - org.openrewrite.java.testing.hamcrest.RemoveIsMatcher +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.hamcrest.MigrateHamcrestToJUnit5 +displayName: Migrate Hamcrest assertions to JUnit Jupiter +description: Migrate Hamcrest `assertThat(..)` to JUnit Jupiter `Assertions`. +tags: + - testing + - hamcrest + - assertj +recipeList: + # First change `is(..)` to `Matchers.is(..)` for consistent matching + - org.openrewrite.java.testing.hamcrest.ConsistentHamcrestMatcherImports + # Then replace `assertThat(String, boolean)` with `assertTrue(boolean, String)` + - org.openrewrite.java.ReorderMethodArguments: + methodPattern: org.hamcrest.MatcherAssert assertThat(java.lang.String, boolean) + oldParameterNames: [reason, assertion] + newParameterNames: [assertion, reason] + - org.openrewrite.java.ChangeMethodName: + methodPattern: org.hamcrest.MatcherAssert assertThat(boolean, String) + newMethodName: assertTrue + - org.openrewrite.java.ChangeMethodTargetToStatic: + methodPattern: org.hamcrest.MatcherAssert assertTrue(boolean, String) + fullyQualifiedTargetTypeName: org.junit.jupiter.api.Assertions + - org.openrewrite.java.testing.hamcrest.HamcrestInstanceOfToJUnit5 + - org.openrewrite.java.testing.hamcrest.HamcrestMatcherToJUnit5 +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.hamcrest.MigrateHamcrestToAssertJ +displayName: Migrate Hamcrest assertions to AssertJ +description: Migrate Hamcrest `assertThat(..)` to AssertJ `Assertions`. +tags: + - testing + - hamcrest + - assertj +recipeList: + # Add dependency if not already present + - org.openrewrite.java.dependencies.AddDependency: + groupId: org.assertj + artifactId: assertj-core + version: 3.x + onlyIfUsing: org.hamcrest.* + acceptTransitive: true + + # First change `is(..)` to `Matchers.is(..)` for consistent matching + - org.openrewrite.java.testing.hamcrest.ConsistentHamcrestMatcherImports # Then remove calls to `MatcherAssert.assertThat(String, is(Matcher))` - org.openrewrite.java.testing.hamcrest.HamcrestIsMatcherToAssertJ @@ -319,10 +364,3 @@ recipeList: notMatcher: empty assertion: isNotEmpty - # Add dependency if not already present - - org.openrewrite.java.dependencies.AddDependency: - groupId: org.assertj - artifactId: assertj-core - version: 3.x - onlyIfUsing: org.assertj.core.api.Assertions - acceptTransitive: true diff --git a/src/main/resources/META-INF/rewrite/jmockit.yml b/src/main/resources/META-INF/rewrite/jmockit.yml index a15136715..d1ee335d7 100644 --- a/src/main/resources/META-INF/rewrite/jmockit.yml +++ b/src/main/resources/META-INF/rewrite/jmockit.yml @@ -23,6 +23,7 @@ tags: - jmockit recipeList: - org.openrewrite.java.testing.jmockit.JMockitBlockToMockito + - org.openrewrite.java.testing.jmockit.JMockitMockUpToMockito - org.openrewrite.java.testing.jmockit.JMockitAnnotatedArgumentToMockito - org.openrewrite.java.ChangeType: oldFullyQualifiedTypeName: mockit.Mocked diff --git a/src/main/resources/META-INF/rewrite/junit5.yml b/src/main/resources/META-INF/rewrite/junit5.yml index a8a38c9cf..481a4d71d 100755 --- a/src/main/resources/META-INF/rewrite/junit5.yml +++ b/src/main/resources/META-INF/rewrite/junit5.yml @@ -106,7 +106,7 @@ recipeList: # Workaround for https://github.com/testcontainers/testcontainers-java/issues/970: - org.openrewrite.maven.RemoveExclusion: groupId: org.testcontainers - artifactId: testcontainers + artifactId: '*' exclusionGroupId: junit exclusionArtifactId: junit # Similar for https://github.com/openrewrite/rewrite-testing-frameworks/issues/477 @@ -129,7 +129,6 @@ recipeList: onlyIfUsing: org.junit.jupiter.params.ParameterizedTest acceptTransitive: true scope: test - - org.openrewrite.java.testing.mockito.Mockito1to4Migration - org.openrewrite.maven.UpgradePluginVersion: groupId: org.apache.maven.plugins artifactId: maven-surefire-plugin @@ -142,6 +141,7 @@ recipeList: - org.openrewrite.java.ChangeType: oldFullyQualifiedTypeName: org.jbehave.core.junit.JUnitStories newFullyQualifiedTypeName: org.jbehave.core.junit.JupiterStories + - org.openrewrite.java.testing.dbrider.MigrateDbRiderSpringToDbRiderJUnit5 --- type: specs.openrewrite.org/v1beta/recipe diff --git a/src/main/resources/META-INF/rewrite/mockito.yml b/src/main/resources/META-INF/rewrite/mockito.yml index fd6028729..7386b8936 100644 --- a/src/main/resources/META-INF/rewrite/mockito.yml +++ b/src/main/resources/META-INF/rewrite/mockito.yml @@ -25,11 +25,23 @@ recipeList: - org.openrewrite.java.testing.mockito.Mockito1to5Migration - org.openrewrite.java.RemoveAnnotation: annotationPattern: "@org.mockito.junit.jupiter.MockitoSettings(strictness=org.mockito.quality.Strictness.WARN)" + - org.openrewrite.java.testing.mockito.SimplifyMockitoVerifyWhenGiven --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.testing.mockito.Mockito1to5Migration displayName: Mockito 5.x upgrade description: Upgrade Mockito from 1.x to 5.x. +tags: + - testing + - mockito +recipeList: + - org.openrewrite.java.testing.mockito.Mockito1to4Migration + - org.openrewrite.java.testing.mockito.Mockito4to5Only +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.mockito.Mockito4to5Only +displayName: Mockito 4 to 5.x upgrade only +description: Upgrade Mockito from 4.x to 5.x. Does not include 1.x to 4.x migration. tags: - testing - mockito @@ -48,7 +60,6 @@ recipeList: artifactId: byte-buddy* newVersion: 1.15.x - org.openrewrite.maven.RemoveDuplicateDependencies - --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.testing.mockito.Mockito1to4Migration @@ -59,6 +70,7 @@ tags: - mockito recipeList: - org.openrewrite.java.testing.mockito.Mockito1to3Migration + - org.openrewrite.java.testing.mockito.MockitoWhenOnStaticToMockStatic - org.openrewrite.java.dependencies.UpgradeDependencyVersion: groupId: org.mockito artifactId: "*" @@ -130,6 +142,7 @@ recipeList: oldParameterNames: - mode - verification + - org.openrewrite.java.testing.mockito.VerifyZeroToNoMoreInteractions - org.openrewrite.java.ChangeMethodName: methodPattern: org.mockito.Mockito verifyZeroInteractions(..) newMethodName: verifyNoInteractions @@ -148,11 +161,11 @@ recipeList: - org.openrewrite.java.ChangeType: oldFullyQualifiedTypeName: org.mockito.runners.MockitoJUnitRunner newFullyQualifiedTypeName: org.mockito.junit.MockitoJUnitRunner + - org.openrewrite.java.testing.mockito.NoInitializationForInjectMock - org.openrewrite.java.testing.mockito.CleanupMockitoImports - org.openrewrite.java.testing.mockito.MockUtilsToStatic - org.openrewrite.java.testing.junit5.MockitoJUnitToMockitoExtension - org.openrewrite.java.testing.mockito.ReplacePowerMockito - - org.openrewrite.java.testing.mockito.RetainStrictnessWarn - org.openrewrite.java.dependencies.AddDependency: groupId: org.mockito artifactId: mockito-junit-jupiter diff --git a/src/main/resources/META-INF/rewrite/testng.yml b/src/main/resources/META-INF/rewrite/testng.yml new file mode 100644 index 000000000..8bab3e86a --- /dev/null +++ b/src/main/resources/META-INF/rewrite/testng.yml @@ -0,0 +1,34 @@ +# +# Copyright 2024 the original author or authors. +#

    +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +#

    +# https://www.apache.org/licenses/LICENSE-2.0 +#

    +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.testng.TestNgToAssertj +displayName: Migrate TestNG assertions to AssertJ +description: Convert assertions from `org.testng.Assert` to `org.assertj.core.api.Assertions`. +tags: + - assertj + - testing + - testng +recipeList: + - org.openrewrite.java.dependencies.AddDependency: + groupId: org.assertj + artifactId: assertj-core + version: 3.x + onlyIfUsing: org.testng.* + acceptTransitive: true + - tech.picnic.errorprone.refasterrules.TestNGToAssertJRulesRecipes + - org.openrewrite.java.testing.testng.TestNgAssertEqualsToAssertThat + - org.openrewrite.java.testing.testng.TestNgAssertNotEqualsToAssertThat diff --git a/src/test/java/org/openrewrite/java/testing/.editorconfig b/src/test/java/org/openrewrite/java/testing/.editorconfig deleted file mode 100644 index a4824935e..000000000 --- a/src/test/java/org/openrewrite/java/testing/.editorconfig +++ /dev/null @@ -1,5 +0,0 @@ -root = true - -[*.java] -indent_size = 4 -ij_continuation_indent_size = 2 diff --git a/src/test/java/org/openrewrite/java/testing/assertj/AssertJBestPracticesTest.java b/src/test/java/org/openrewrite/java/testing/assertj/AssertJBestPracticesTest.java index f96060d54..a23205627 100644 --- a/src/test/java/org/openrewrite/java/testing/assertj/AssertJBestPracticesTest.java +++ b/src/test/java/org/openrewrite/java/testing/assertj/AssertJBestPracticesTest.java @@ -319,4 +319,5 @@ void test(%2$s x, %2$s y, Object value) { template.formatted(imprt, argumentsType, dedicatedAssertion))); } } + } diff --git a/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertInstanceOfToAssertThatTest.java b/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertInstanceOfToAssertThatTest.java new file mode 100644 index 000000000..10579e3c2 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertInstanceOfToAssertThatTest.java @@ -0,0 +1,232 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.assertj; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class JUnitAssertInstanceOfToAssertThatTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9")) + .recipe(new JUnitAssertInstanceOfToAssertThat()); + } + + @Test + @DocumentExample + void convertsIsInstanceOf() { + rewriteRun( + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + class Test { + void test() { + assertInstanceOf(Integer.class, 4); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void test() { + assertThat(4).isInstanceOf(Integer.class); + } + } + """ + ) + ); + } + + @Test + void convertsIsInstanceOfWithMessage() { + rewriteRun( + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + class Test { + void test() { + assertInstanceOf(Integer.class, 4, "error message"); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void test() { + assertThat(4).as("error message").isInstanceOf(Integer.class); + } + } + """ + ) + ); + } + + @Test + void convertsIsInstanceOfWithMessageLambda() { + rewriteRun( + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + class Test { + void test() { + assertInstanceOf(Integer.class, 4, () -> "error message"); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void test() { + assertThat(4).as(() -> "error message").isInstanceOf(Integer.class); + } + } + """ + ) + ); + } + + @Test + void convertsIsInstanceOfWithMessageMethodReference() { + rewriteRun( + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + class Test { + void test() { + assertInstanceOf(Integer.class, 4, this::getErrorMessage); + } + + String getErrorMessage() { + return "error message"; + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void test() { + assertThat(4).as(this::getErrorMessage).isInstanceOf(Integer.class); + } + + String getErrorMessage() { + return "error message"; + } + } + """ + ) + ); + } + + @Test + void canBeRerun() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "assertj-core-3-*")), + // language=java + java( + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void test() { + assertThat(4).isInstanceOf(Integer.class); + } + } + """ + ) + ); + } + + @Test + void doesNotConvertAnyOtherMethods() { + rewriteRun( + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + import static org.junit.jupiter.api.Assertions.assertTrue; + + class Test { + void test() { + assertInstanceOf(Integer.class, 4); + assertTrue(1 == 1, "Message"); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + import static org.junit.jupiter.api.Assertions.assertTrue; + + class Test { + void test() { + assertThat(4).isInstanceOf(Integer.class); + assertTrue(1 == 1, "Message"); + } + } + """ + ) + ); + } + + @Test + void doesConvertNestedMethodInvocations() { + rewriteRun( + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + import static org.junit.jupiter.api.Assertions.assertAll; + + class Test { + void test() { + assertAll(() -> assertInstanceOf(Integer.class, 4)); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + import static org.junit.jupiter.api.Assertions.assertAll; + + class Test { + void test() { + assertAll(() -> assertThat(4).isInstanceOf(Integer.class)); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionTypeTest.java b/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionTypeTest.java index 1b5e7fd24..85b9f6a01 100644 --- a/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionTypeTest.java +++ b/src/test/java/org/openrewrite/java/testing/assertj/JUnitAssertThrowsToAssertExceptionTypeTest.java @@ -44,12 +44,10 @@ void toAssertExceptionOfType() { java( """ import static org.junit.jupiter.api.Assertions.assertThrows; - + public class SimpleExpectedExceptionTest { public void throwsExceptionWithSpecificType() { - assertThrows(NullPointerException.class, () -> { - foo(); - }); + assertThrows(NullPointerException.class, () -> foo()); } void foo() { throw new NullPointerException(); @@ -58,11 +56,10 @@ void foo() { """, """ import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; - + public class SimpleExpectedExceptionTest { public void throwsExceptionWithSpecificType() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> - foo()); + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> foo()); } void foo() { throw new NullPointerException(); diff --git a/src/test/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertionTest.java b/src/test/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertionTest.java index 785822116..b88b7d315 100644 --- a/src/test/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertionTest.java +++ b/src/test/java/org/openrewrite/java/testing/assertj/SimplifyChainedAssertJAssertionTest.java @@ -42,7 +42,7 @@ void stringIsEmpty() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat("hello world".isEmpty()).isTrue(); @@ -51,7 +51,7 @@ void testMethod() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat("hello world").isEmpty(); @@ -71,7 +71,7 @@ void stringIsEmptyDescribedAs() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod(String actual) { assertThat(actual.isEmpty()).as("Reason").isTrue(); @@ -80,7 +80,7 @@ void testMethod(String actual) { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod(String actual) { assertThat(actual).as("Reason").isEmpty(); @@ -102,12 +102,12 @@ void chainedRecipes() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString().isEmpty()).isTrue(); } - + String getString() { return "hello world"; } @@ -115,12 +115,12 @@ String getString() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString()).isEmpty(); } - + String getString() { return "hello world"; } @@ -141,14 +141,14 @@ void chainedRecipesOfDifferingTypes() { java( """ import java.nio.file.Path; - + import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void string(String actual) { assertThat(actual.startsWith("prefix")).isTrue(); } - + void path(Path actual) { assertThat(actual.startsWith("prefix")).isTrue(); } @@ -156,14 +156,14 @@ void path(Path actual) { """, """ import java.nio.file.Path; - + import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void string(String actual) { assertThat(actual).startsWith("prefix"); } - + void path(Path actual) { assertThat(actual).startsWithRaw(Path.of("prefix")); } @@ -181,13 +181,13 @@ void assertThatArgHasArgument() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { String expected = "hello world"; assertThat(getString().equalsIgnoreCase(expected)).isTrue(); } - + String getString() { return "hello world"; } @@ -195,13 +195,13 @@ String getString() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { String expected = "hello world"; assertThat(getString()).isEqualToIgnoringCase(expected); } - + String getString() { return "hello world"; } @@ -219,13 +219,13 @@ void replacementHasArgument() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { int length = 5; assertThat(getString().length()).isEqualTo(length); } - + String getString() { return "hello world"; } @@ -233,13 +233,13 @@ String getString() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { int length = 5; assertThat(getString()).hasSize(length); } - + String getString() { return "hello world"; } @@ -258,12 +258,12 @@ void normalCase() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString().trim()).isEmpty(); } - + String getString() { return "hello world"; } @@ -271,12 +271,12 @@ String getString() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString()).isBlank(); } - + String getString() { return "hello world"; } @@ -297,7 +297,7 @@ void stringContains() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat("hello world".contains("lo wo")).isTrue(); @@ -307,7 +307,7 @@ void testMethod() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat("hello world").contains("lo wo"); @@ -319,6 +319,48 @@ void testMethod() { ); } + @Test + void stringContainsObjectMethod() { + rewriteRun( + spec -> spec.recipes( + new SimplifyChainedAssertJAssertion("contains", "isTrue", "contains", "java.lang.String")), + //language=java + java( + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Pojo { + public String getString() { + return "lo wo"; + } + } + + class MyTest { + void testMethod() { + var pojo = new Pojo(); + assertThat("hello world".contains(pojo.getString())).isTrue(); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Pojo { + public String getString() { + return "lo wo"; + } + } + + class MyTest { + void testMethod() { + var pojo = new Pojo(); + assertThat("hello world").contains(pojo.getString()); + } + } + """ + ) + ); + } @Test void mapMethodDealsWithTwoArguments() { @@ -329,16 +371,16 @@ void mapMethodDealsWithTwoArguments() { """ import java.util.Collections; import java.util.Map; - + import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { String key = "key"; String value = "value"; assertThat(getMap().get(key)).isEqualTo(value); } - + Map getMap() { return Collections.emptyMap(); } @@ -347,16 +389,16 @@ Map getMap() { """ import java.util.Collections; import java.util.Map; - + import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { String key = "key"; String value = "value"; assertThat(getMap()).containsEntry(key, value); } - + Map getMap() { return Collections.emptyMap(); } @@ -366,6 +408,28 @@ Map getMap() { ); } + @Test + void keySetContainsWithMultipleArguments() { + rewriteRun( + spec -> spec.recipe(new SimplifyChainedAssertJAssertion("keySet", "contains", "containsKey", "java.util.Map")), + //language=java + java( + """ + import java.util.Map; + + import static org.assertj.core.api.Assertions.assertThat; + + class MyTest { + void testMethod(Map map) { + // we don't yet support `containsKeys` + assertThat(map.keySet()).contains("a", "b", "c"); + } + } + """ + ) + ); + } + @Test void isNotEmptyTest() { rewriteRun( @@ -374,12 +438,12 @@ void isNotEmptyTest() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString().isEmpty()).isFalse(); } - + String getString() { return "hello world"; } @@ -387,12 +451,12 @@ String getString() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString()).isNotEmpty(); } - + String getString() { return "hello world"; } @@ -410,12 +474,12 @@ void doesNoRunOnWrongCombination() { java( """ import static org.assertj.core.api.Assertions.assertThat; - + class MyTest { void testMethod() { assertThat(getString().isBlank()).isFalse(); } - + String getString() { return "hello world"; } @@ -442,7 +506,7 @@ void simplifyPresenceAssertion() { """ import static org.assertj.core.api.Assertions.assertThat; import java.util.Optional; - + class Test { void simpleTest(Optional o) { assertThat(o.isPresent()).isTrue(); @@ -455,7 +519,7 @@ void simpleTest(Optional o) { """ import static org.assertj.core.api.Assertions.assertThat; import java.util.Optional; - + class Test { void simpleTest(Optional o) { assertThat(o).isPresent(); @@ -481,7 +545,7 @@ void simplifiyEqualityAssertion() { """ import static org.assertj.core.api.Assertions.assertThat; import java.util.Optional; - + class Test { void simpleTest(Optional o) { assertThat(o.get()).isEqualTo("foo"); @@ -492,7 +556,7 @@ void simpleTest(Optional o) { """ import static org.assertj.core.api.Assertions.assertThat; import java.util.Optional; - + class Test { void simpleTest(Optional o) { assertThat(o).contains("foo"); diff --git a/src/test/java/org/openrewrite/java/testing/assertj/StaticImportsTest.java b/src/test/java/org/openrewrite/java/testing/assertj/StaticImportsTest.java index b23b8e13a..3b6808446 100644 --- a/src/test/java/org/openrewrite/java/testing/assertj/StaticImportsTest.java +++ b/src/test/java/org/openrewrite/java/testing/assertj/StaticImportsTest.java @@ -51,6 +51,7 @@ void useAssertionsStaticImport() { import org.assertj.core.api.AssertionsForInterfaceTypes; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + import static org.assertj.core.api.Fail.fail; public class Test { List exampleList; @@ -59,6 +60,7 @@ void method() { AssertionsForClassTypes.assertThat(true).isTrue(); assertThat(true).isTrue(); assertThat(exampleList).hasSize(0); + fail("This is a failure"); } } """, @@ -66,6 +68,7 @@ void method() { import java.util.List; import static org.assertj.core.api.Assertions.assertThat; + import static org.assertj.core.api.Assertions.fail; public class Test { List exampleList; @@ -74,6 +77,7 @@ void method() { assertThat(true).isTrue(); assertThat(true).isTrue(); assertThat(exampleList).hasSize(0); + fail("This is a failure"); } } """ diff --git a/src/test/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrderTest.java b/src/test/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrderTest.java index 80e79f1d6..962faa04e 100644 --- a/src/test/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrderTest.java +++ b/src/test/java/org/openrewrite/java/testing/cleanup/AssertionsArgumentOrderTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Issue; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -29,7 +30,7 @@ class AssertionsArgumentOrderTest implements RewriteTest { public void defaults(RecipeSpec spec) { spec.recipe(new AssertionsArgumentOrder()) .parser(JavaParser.fromJavaVersion() - .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "testng-7.7")); + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "testng-7.7", "junit-4.13")); } @DocumentExample @@ -40,7 +41,7 @@ void junitAssertEqualsHavingPrimitiveArg() { java( """ import static org.junit.jupiter.api.Assertions.assertEquals; - + class MyTest { void someMethod() { assertEquals(result(), "result"); @@ -54,7 +55,7 @@ String result() { """, """ import static org.junit.jupiter.api.Assertions.assertEquals; - + class MyTest { void someMethod() { assertEquals("result", result()); @@ -71,14 +72,98 @@ String result() { } @Test - void junitAssertNullAndAssertNotNull() { + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/636") + void junit4AssertEqualsHavingStringArg() { + rewriteRun( + //language=java + java( + """ + import static org.junit.Assert.assertEquals; + + class MyTest { + void someMethod() { + assertEquals(result(), "result"); + assertEquals("result", result()); + assertEquals("message", result(), "result"); + assertEquals("message", "result", result()); + } + String result() { + return "result"; + } + } + """, + """ + import static org.junit.Assert.assertEquals; + + class MyTest { + void someMethod() { + assertEquals("result", result()); + assertEquals("result", result()); + assertEquals("message", "result", result()); + assertEquals("message", "result", result()); + } + String result() { + return "result"; + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/636") + void junit4AssertEqualsHavingPrimitiveArg() { + rewriteRun( + //language=java + java( + """ + import static org.junit.Assert.assertEquals; + + class MyTest { + void someMethod() { + assertEquals(0L, 1L); + assertEquals(1L, 0L); + assertEquals(longResult(), 0L); + assertEquals(0L, longResult()); + assertEquals("message", 0L, longResult()); + assertEquals("message", longResult(), 0L); + } + long longResult() { + return 0L; + } + } + """, + """ + import static org.junit.Assert.assertEquals; + + class MyTest { + void someMethod() { + assertEquals(0L, 1L); + assertEquals(1L, 0L); + assertEquals(0L, longResult()); + assertEquals(0L, longResult()); + assertEquals("message", 0L, longResult()); + assertEquals("message", 0L, longResult()); + } + long longResult() { + return 0L; + } + } + """ + ) + ); + } + + @Test + void jupiterAssertNullAndAssertNotNull() { rewriteRun( //language=java java( """ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; - + class MyTest { void someMethod() { assertNull(result(), "message"); @@ -94,7 +179,7 @@ String result() { """ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; - + class MyTest { void someMethod() { assertNull(result(), "message"); @@ -111,6 +196,48 @@ String result() { ); } + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/636") + void junitAssertNullAndAssertNotNull() { + rewriteRun( + //language=java + java( + """ + import static org.junit.Assert.assertNotNull; + import static org.junit.Assert.assertNull; + + class MyTest { + void someMethod() { + assertNull(result(), "message"); + assertNull("message", result()); + assertNotNull(result(), "message"); + assertNotNull("message", result()); + } + String result() { + return "result"; + } + } + """, + """ + import static org.junit.Assert.assertNotNull; + import static org.junit.Assert.assertNull; + + class MyTest { + void someMethod() { + assertNull("message", result()); + assertNull("message", result()); + assertNotNull("message", result()); + assertNotNull("message", result()); + } + String result() { + return "result"; + } + } + """ + ) + ); + } + @Test void jupiterAssertSameNotSame() { rewriteRun( @@ -119,7 +246,7 @@ void jupiterAssertSameNotSame() { """ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertNotSame; - + class MyTest { private static final Integer LIMIT = 0; private static String MESSAGE = ""; @@ -127,7 +254,7 @@ void someMethod() { assertSame(getCount(), LIMIT); assertSame(getCount(), MyTest.LIMIT); assertSame(LIMIT, getCount()); - + assertNotSame(getMsg(), MESSAGE); } String getMsg() { @@ -141,7 +268,61 @@ Integer getCount() { """ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertNotSame; - + + class MyTest { + private static final Integer LIMIT = 0; + private static String MESSAGE = ""; + void someMethod() { + assertSame(LIMIT, getCount()); + assertSame(MyTest.LIMIT, getCount()); + assertSame(LIMIT, getCount()); + + assertNotSame(getMsg(), MESSAGE); + } + String getMsg() { + return ""; + } + Integer getCount() { + return 1; + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/636") + void junit4AssertSameNotSame() { + rewriteRun( + //language=java + java( + """ + import static org.junit.Assert.assertSame; + import static org.junit.Assert.assertNotSame; + + class MyTest { + private static final Integer LIMIT = 0; + private static String MESSAGE = ""; + void someMethod() { + assertSame(getCount(), LIMIT); + assertSame(getCount(), MyTest.LIMIT); + assertSame(LIMIT, getCount()); + + assertNotSame(getMsg(), MESSAGE); + } + String getMsg() { + return ""; + } + Integer getCount() { + return 1; + } + } + """, + """ + import static org.junit.Assert.assertSame; + import static org.junit.Assert.assertNotSame; + class MyTest { private static final Integer LIMIT = 0; private static String MESSAGE = ""; @@ -149,7 +330,7 @@ void someMethod() { assertSame(LIMIT, getCount()); assertSame(MyTest.LIMIT, getCount()); assertSame(LIMIT, getCount()); - + assertNotSame(getMsg(), MESSAGE); } String getMsg() { @@ -171,7 +352,7 @@ void jupiterAssertArrayEquals() { java( """ import static org.junit.jupiter.api.Assertions.assertArrayEquals; - + class MyTest { void someMethod() { assertArrayEquals(result(), new String[]{""}); @@ -184,7 +365,7 @@ String[] result() { """, """ import static org.junit.jupiter.api.Assertions.assertArrayEquals; - + class MyTest { void someMethod() { assertArrayEquals(new String[]{""}, result()); @@ -199,6 +380,46 @@ String[] result() { ); } + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/636") + void junitAssertArrayEquals() { + rewriteRun( + //language=java + java( + """ + import static org.junit.Assert.assertArrayEquals; + + class MyTest { + void someMethod() { + assertArrayEquals(result(), new String[]{""}); + assertArrayEquals(new String[]{""}, result()); + assertArrayEquals("message", new String[]{""}, result()); + assertArrayEquals("message", result(), new String[]{""}); + } + String[] result() { + return null; + } + } + """, + """ + import static org.junit.Assert.assertArrayEquals; + + class MyTest { + void someMethod() { + assertArrayEquals(new String[]{""}, result()); + assertArrayEquals(new String[]{""}, result()); + assertArrayEquals("message", new String[]{""}, result()); + assertArrayEquals("message", new String[]{""}, result()); + } + String[] result() { + return null; + } + } + """ + ) + ); + } + @Test void junitIterableEquals() { rewriteRun( @@ -208,9 +429,9 @@ void junitIterableEquals() { import java.util.ArrayList; import java.util.Collections; import java.util.List; - + import static org.junit.jupiter.api.Assertions.assertIterableEquals; - + class MyTest { static final Iterable COSNT_LIST = new ArrayList<>(); void someTest() { @@ -227,9 +448,9 @@ List doubleList() { import java.util.ArrayList; import java.util.Collections; import java.util.List; - + import static org.junit.jupiter.api.Assertions.assertIterableEquals; - + class MyTest { static final Iterable COSNT_LIST = new ArrayList<>(); void someTest() { @@ -253,7 +474,7 @@ void ngAssertions() { java( """ import static org.testng.Assert.assertEquals; - + class MyTest { void someTest() { assertEquals("abc", someString()); @@ -266,7 +487,7 @@ String someString() { """, """ import static org.testng.Assert.assertEquals; - + class MyTest { void someTest() { assertEquals(someString(), "abc"); diff --git a/src/test/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefixTest.java b/src/test/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefixTest.java index aa7e8e238..944b49fad 100644 --- a/src/test/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefixTest.java +++ b/src/test/java/org/openrewrite/java/testing/cleanup/RemoveTestPrefixTest.java @@ -377,4 +377,40 @@ void of() { ) ); } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/258") + @Test + void removeTestPrefixWhenCalled() { + rewriteRun( + // language=java + java( + """ + import org.junit.jupiter.api.Test; + + public class FooTest { + @Test + void bar() { + testFoo(); + } + + @Test + void testFoo() {} + } + """, + """ + import org.junit.jupiter.api.Test; + + public class FooTest { + @Test + void bar() { + foo(); + } + + @Test + void foo() {} + } + """ + ) + ); + } } diff --git a/src/test/java/org/openrewrite/java/testing/dbrider/ExecutionListenerToDbRiderAnnotationUnitTest.java b/src/test/java/org/openrewrite/java/testing/dbrider/ExecutionListenerToDbRiderAnnotationUnitTest.java new file mode 100644 index 000000000..b1820b6fc --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/dbrider/ExecutionListenerToDbRiderAnnotationUnitTest.java @@ -0,0 +1,233 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.dbrider; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class ExecutionListenerToDbRiderAnnotationUnitTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "spring-test-6.1", "rider-spring-1.18", "rider-junit5-1.44")) + .recipe(new ExecutionListenerToDbRiderAnnotation()); + } + + @Test + @DocumentExample + void replaceAnnotationIfOnlyDbRiderListenerMergedWithDefaults() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS, listeners = {DBRiderTestExecutionListener.class}) + public class Sample {} + """, + """ + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + public class Sample {} + """ + ) + ); + } + + @Test + void addAnnotationIfOnlyDbRiderListenerReplacedDefaults() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.REPLACE_DEFAULTS, listeners = {DBRiderTestExecutionListener.class}) + public class Sample {} + """, + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + @TestExecutionListeners + public class Sample {} + """ + ) + ); + } + + @Test + void addAnnotationIfOnlyDbRiderListenerAndNoMergeModeSpecified() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners(listeners = {DBRiderTestExecutionListener.class}) + public class Sample {} + """, + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + @TestExecutionListeners + public class Sample {} + """ + ) + ); + } + + @Test + void addAnnotationIfOnlyDbRiderListenerThroughValue() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners(DBRiderTestExecutionListener.class) + public class Sample {} + """, + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + @TestExecutionListeners + public class Sample {} + """ + ) + ); + } + + @Test + void addAnnotationIfOnlyDbRiderListenerThroughValueArray() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners({DBRiderTestExecutionListener.class}) + public class Sample {} + """, + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + @TestExecutionListeners + public class Sample {} + """ + ) + ); + } + + @Test + void keepAnnotationIfOnlyDbRiderListenerSetAndNonDefaultSetting() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners(value = {DBRiderTestExecutionListener.class}, inheritListeners = false) + public class Sample {} + """, + """ + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + @TestExecutionListeners(inheritListeners = false) + public class Sample {} + """ + ) + ); + } + + @Test + void removeListenerFromOtherListeners() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.context.TestExecutionListeners; + import org.springframework.test.context.support.DirtiesContextTestExecutionListener; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.REPLACE_DEFAULTS, listeners = {DBRiderTestExecutionListener.class, DirtiesContextTestExecutionListener.class}) + public class Sample {} + """, + """ + import org.springframework.test.context.TestExecutionListeners; + import org.springframework.test.context.support.DirtiesContextTestExecutionListener; + import com.github.database.rider.junit5.api.DBRider; + + @DBRider + @TestExecutionListeners(listeners = {DirtiesContextTestExecutionListener.class}) + public class Sample {} + """ + ) + ); + } + + @Test + void doNotTouchIfNoListenerPresent() { + rewriteRun( + //language=java + java( + """ + @Deprecated + public class Sample {} + """ + ) + ); + } + + @Test + void doNotTouchIfDbRiderAlreadyPresent() { + rewriteRun( + //language=java + java( + """ + import com.github.database.rider.junit5.api.DBRider; + import org.springframework.test.context.TestExecutionListeners; + import com.github.database.rider.spring.DBRiderTestExecutionListener; + + @DBRider + @TestExecutionListeners(listeners = {DBRiderTestExecutionListener.class}, inheritListeners = false) + public class Sample {} + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/easymock/EasyMockToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/easymock/EasyMockToMockitoTest.java new file mode 100644 index 000000000..2892bd236 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/easymock/EasyMockToMockitoTest.java @@ -0,0 +1,235 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.easymock; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class EasyMockToMockitoTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion().classpath("junit", "easymock")) + .recipeFromResources("org.openrewrite.java.testing.easymock.EasyMockToMockito"); + } + + @Test + @DocumentExample + void replaceEasyMockByMockito() { + //language=java + rewriteRun( + java( + """ + import org.easymock.EasyMockRunner; + import org.easymock.Mock; + import org.easymock.EasyMock; + import org.easymock.TestSubject; + import org.junit.Before; + import org.junit.Test; + import org.junit.runner.RunWith; + + import static org.junit.Assert.assertEquals; + import static org.easymock.EasyMock.createNiceMock; + import static org.easymock.EasyMock.expect; + import static org.easymock.EasyMock.replay; + import static org.easymock.EasyMock.verify; + + @RunWith(EasyMockRunner.class) + public class ExampleTest { + + private Service service; + private Dependency dependency; + + @Mock + private Dependency dependency2; + + @TestSubject + Service service2 = new Service(); + + @Before + public void setUp() { + dependency = createNiceMock(Dependency.class); + service = new Service(dependency); + } + + @Test + public void testServiceMethod() { + expect(dependency.performAction()).andReturn("Mocked Result"); + EasyMock.replay(dependency); + replay(dependency); + assertEquals("Mocked Result", service.useDependency()); + verify(dependency); + } + + class Service { + private Dependency dependency; + + Service() {} + + Service(Dependency dependency) { + this.dependency = dependency; + } + + String useDependency() { + return dependency.performAction(); + } + } + + interface Dependency { + String performAction(); + } + } + """, + """ + import org.junit.Before; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.mockito.InjectMocks; + import org.mockito.Mock; + import org.mockito.junit.MockitoJUnitRunner; + + import static org.junit.Assert.assertEquals; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + + @RunWith(MockitoJUnitRunner.class) + public class ExampleTest { + + private Service service; + private Dependency dependency; + + @Mock + private Dependency dependency2; + + @InjectMocks + Service service2; + + @Before + public void setUp() { + dependency = mock(Dependency.class); + service = new Service(dependency); + } + + @Test + public void testServiceMethod() { + when(dependency.performAction()).thenReturn("Mocked Result"); + assertEquals("Mocked Result", service.useDependency()); + verify(dependency).performAction(); + } + + class Service { + private Dependency dependency; + + Service() {} + + Service(Dependency dependency) { + this.dependency = dependency; + } + + String useDependency() { + return dependency.performAction(); + } + } + + interface Dependency { + String performAction(); + } + } + """ + ) + ); + } + + @Test + void matchers() { + // From: https://www.baeldung.com/easymock-argument-matchers + //language=java + rewriteRun( + java( + """ + import java.util.ArrayList; + import java.util.List; + + class User { + private long id; + private String firstName; + private String lastName; + private double age; + private String email; + } + + // The second `Object ignore` argument disables the removal-matcher-optimization code like: + // expect(service.addUser(eq(new User()))) to expect(service.addUser(new User())); + class UserService { + boolean addUser(User user, Object ignore) { return true; } + List findByEmail(String email, Object ignore) { return new ArrayList<>(); } + List findByAge(double age, Object ignore) { return new ArrayList<>(); } + } + """ + ), + java( + """ + import org.junit.Test; + import static org.easymock.EasyMock.*; + + public class ExampleTest { + @Test + public void testServiceMethod() { + User user = new User(); + UserService service = createNiceMock(UserService.class); + + expect(service.addUser(eq(new User()), anyObject())); + expect(service.addUser(isNull(), anyObject())); + expect(service.addUser(same(user), anyObject())); + expect(service.findByEmail(anyString(), anyObject())); + expect(service.findByAge(lt(100.0), anyObject())); + expect(service.findByAge(and(gt(10.0),leq(100.0)), anyObject())); + expect(service.findByEmail(not(endsWith(".com")), anyObject())); + } + } + """, + """ + import org.junit.Test; + import static org.mockito.Mockito.*; + import static org.mockito.AdditionalMatchers.*; + + public class ExampleTest { + @Test + public void testServiceMethod() { + User user = new User(); + UserService service = mock(UserService.class); + + when(service.addUser(eq(new User()), any())); + when(service.addUser(isNull(), any())); + when(service.addUser(same(user), any())); + when(service.findByEmail(anyString(), any())); + when(service.findByAge(lt(100.0), any())); + when(service.findByAge(and(gt(10.0),leq(100.0)), any())); + when(service.findByEmail(not(endsWith(".com")), any())); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/easymock/EasyMockVerifyToMockitoVerifyTest.java b/src/test/java/org/openrewrite/java/testing/easymock/EasyMockVerifyToMockitoVerifyTest.java new file mode 100644 index 000000000..33d48a3d0 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/easymock/EasyMockVerifyToMockitoVerifyTest.java @@ -0,0 +1,322 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.easymock; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class EasyMockVerifyToMockitoVerifyTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion().classpath("easymock")) + .recipe(new EasyMockVerifyToMockitoVerify()); + } + + @Test + @DocumentExample + void replaceEasyMockVerifyByMockitoVerify() { + //language=java + rewriteRun( + java( + """ + import static org.easymock.EasyMock.*; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action("", 2)).andReturn("result"); + + Dependency dependency2 = createNiceMock(Dependency.class); + expect(dependency2.action("", 2)).andReturn("result"); + expect(dependency2.action2()); + + Dependency dependency3 = createNiceMock(Dependency.class); + expect(dependency3.action("A", 1)).andReturn("result"); + expect(dependency3.action2()).andReturn("result"); + expect(dependency3.action3(3.3)).andReturn("result"); + + verify(dependency); + verify(dependency2); + verify(dependency3); + } + + interface Dependency { + String action(String s, int i); + String action2(); + String action3(double d); + } + } + """, + """ + import static org.easymock.EasyMock.expect; + import static org.easymock.EasyMock.createNiceMock; + import static org.mockito.Mockito.verify; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action("", 2)).andReturn("result"); + + Dependency dependency2 = createNiceMock(Dependency.class); + expect(dependency2.action("", 2)).andReturn("result"); + expect(dependency2.action2()); + + Dependency dependency3 = createNiceMock(Dependency.class); + expect(dependency3.action("A", 1)).andReturn("result"); + expect(dependency3.action2()).andReturn("result"); + expect(dependency3.action3(3.3)).andReturn("result"); + + verify(dependency).action("", 2); + verify(dependency2).action("", 2); + verify(dependency2).action2(); + verify(dependency3).action("A", 1); + verify(dependency3).action2(); + verify(dependency3).action3(3.3); + } + + interface Dependency { + String action(String s, int i); + String action2(); + String action3(double d); + } + } + """) + ); + } + + @Test + void simpleReplacement() { + //language=java + rewriteRun( + java( + """ + import static org.easymock.EasyMock.*; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action()).andReturn("result"); + verify(dependency); + } + + interface Dependency { + String action(); + } + } + """, + """ + import static org.easymock.EasyMock.expect; + import static org.easymock.EasyMock.createNiceMock; + import static org.mockito.Mockito.verify; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action()).andReturn("result"); + verify(dependency).action(); + } + + interface Dependency { + String action(); + } + } + """) + ); + } + + @Test + void simpleReplacementWithArguments() { + //language=java + rewriteRun( + java( + """ + import static org.easymock.EasyMock.*; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action("", 2)).andReturn("result"); + verify(dependency); + } + + interface Dependency { + String action(String s, int i); + } + } + """, + """ + import static org.easymock.EasyMock.expect; + import static org.easymock.EasyMock.createNiceMock; + import static org.mockito.Mockito.verify; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action("", 2)).andReturn("result"); + verify(dependency).action("", 2); + } + + interface Dependency { + String action(String s, int i); + } + } + """) + ); + } + + @Test + void replacementWithMultipleMethods() { + //language=java + rewriteRun( + java( + """ + import static org.easymock.EasyMock.*; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action("", 2)).andReturn("result"); + expect(dependency.action2()).andReturn("result"); + verify(dependency); + } + + interface Dependency { + String action(String s, int i); + String action2(); + } + } + """, + """ + import static org.easymock.EasyMock.expect; + import static org.easymock.EasyMock.createNiceMock; + import static org.mockito.Mockito.verify; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action("", 2)).andReturn("result"); + expect(dependency.action2()).andReturn("result"); + verify(dependency).action("", 2); + verify(dependency).action2(); + } + + interface Dependency { + String action(String s, int i); + String action2(); + } + } + """) + ); + } + + @Test + void verifyWithoutExpect() { + //language=java + rewriteRun( + java( + """ + import static org.easymock.EasyMock.*; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + verify(dependency); + } + + interface Dependency {} + } + """, + """ + import static org.easymock.EasyMock.createNiceMock; + import static org.easymock.EasyMock.verify; + + public class ExampleTest { + public void testServiceMethod() { + Dependency dependency = createNiceMock(Dependency.class); + verify(dependency); + } + + interface Dependency {} + } + """) + ); + } + + @Test + void verifyAndDependenciesAllOverThePlace() { + //language=java + rewriteRun( + java( + """ + import static org.easymock.EasyMock.*; + + public class ExampleTest { + public void testServiceMethod() { + verify(null); + + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action()).andReturn("result"); + + Dependency dependency3 = createNiceMock(Dependency.class); + verify(dependency3); + + Dependency dependency2 = createNiceMock(Dependency.class); + expect(dependency2.action()).andReturn("result"); + + verify(dependency2); + verify(dependency); + } + + interface Dependency { + String action(); + } + } + """, + """ + import static org.easymock.EasyMock.*; + import static org.mockito.Mockito.verify; + + public class ExampleTest { + public void testServiceMethod() { + verify(null); + + Dependency dependency = createNiceMock(Dependency.class); + expect(dependency.action()).andReturn("result"); + + Dependency dependency3 = createNiceMock(Dependency.class); + verify(dependency3); + + Dependency dependency2 = createNiceMock(Dependency.class); + expect(dependency2.action()).andReturn("result"); + + verify(dependency2).action(); + verify(dependency).action(); + } + + interface Dependency { + String action(); + } + } + """) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/easymock/RemoveExtendsEasyMockSupportTest.java b/src/test/java/org/openrewrite/java/testing/easymock/RemoveExtendsEasyMockSupportTest.java new file mode 100644 index 000000000..33f49a20e --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/easymock/RemoveExtendsEasyMockSupportTest.java @@ -0,0 +1,107 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.easymock; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class RemoveExtendsEasyMockSupportTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion().classpath("easymock")) + .recipe(new RemoveExtendsEasyMockSupport()); + } + + @Test + @DocumentExample + void shouldRemoveEasyMockSupportParentClass() { + rewriteRun( + //language=java + java( + """ + import org.easymock.EasyMockSupport; + + public class Test extends EasyMockSupport { + } + """, + """ + public class Test { + } + """ + ) + ); + } + + @Test + void shouldRemoveForInnerClassesEasyMockSupportParentClass() { + rewriteRun( + //language=java + java( + """ + import org.easymock.EasyMockSupport; + + public class Test { + class InnerTest extends EasyMockSupport { + class InnerInnerTest extends EasyMockSupport {} + } + } + """, + """ + public class Test { + class InnerTest { + class InnerInnerTest {} + } + } + """ + ) + ); + } + + @Test + void shouldLeaveClassesWithoutEasyMockSupportAlone() { + rewriteRun( + //language=java + java( + """ + public class Test { + } + """ + ) + ); + } + + @Test + void shouldLeaveClassesWithDifferentExtendsAlone() { + rewriteRun( + //language=java + java( + """ + import javax.management.monitor.Monitor; + + public class Test extends Monitor { + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/hamcrest/HamcrestInstanceOfToJUnit5Test.java b/src/test/java/org/openrewrite/java/testing/hamcrest/HamcrestInstanceOfToJUnit5Test.java new file mode 100644 index 000000000..a63ec98cd --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/hamcrest/HamcrestInstanceOfToJUnit5Test.java @@ -0,0 +1,128 @@ +/* + * Copyright 2023 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class HamcrestInstanceOfToJUnit5Test implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "hamcrest-2.2")) + .recipe(new HamcrestInstanceOfToJUnit5()); + } + + @DocumentExample + @Test + void instanceOf() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import java.util.List; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.instanceOf; + import static org.hamcrest.Matchers.isA; + import static org.hamcrest.Matchers.not; + + class ATest { + private static final List list = List.of(); + @Test + void testInstance() { + assertThat(list, instanceOf(Iterable.class)); + assertThat(list, not(instanceOf(Integer.class))); + assertThat(list, isA(Iterable.class)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + import java.util.List; + + import static org.junit.jupiter.api.Assertions.assertFalse; + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + class ATest { + private static final List list = List.of(); + @Test + void testInstance() { + assertInstanceOf(Iterable.class, list); + assertFalse(Integer.class.isAssignableFrom(list.getClass())); + assertInstanceOf(Iterable.class, list); + } + } + """ + ) + ); + } + + @Test + void assertionsWithReason() { + //language=java + rewriteRun( + java( + """ + import java.util.List; + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.instanceOf; + import static org.hamcrest.Matchers.isA; + import static org.hamcrest.Matchers.not; + + class ATest { + private static final List list = List.of(); + + @Test + void testInstance() { + assertThat("Examined object is not instance of Iterable", list, instanceOf(Iterable.class)); + assertThat("Examined object is not instance of Iterable", list, isA(Iterable.class)); + assertThat("Examined object must not be instance of Integer", list, not(instanceOf(Integer.class))); + } + } + """, + """ + import java.util.List; + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertFalse; + import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + class ATest { + private static final List list = List.of(); + + @Test + void testInstance() { + assertInstanceOf(Iterable.class, list, "Examined object is not instance of Iterable"); + assertInstanceOf(Iterable.class, list, "Examined object is not instance of Iterable"); + assertFalse(Integer.class.isAssignableFrom(list.getClass()), "Examined object must not be instance of Integer"); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/hamcrest/HamcrestMatcherToJUnit5Test.java b/src/test/java/org/openrewrite/java/testing/hamcrest/HamcrestMatcherToJUnit5Test.java new file mode 100644 index 000000000..42cd23ec9 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/hamcrest/HamcrestMatcherToJUnit5Test.java @@ -0,0 +1,937 @@ +/* + * Copyright 2023 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class HamcrestMatcherToJUnit5Test implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "hamcrest-2.2")) + .recipe(new HamcrestMatcherToJUnit5()); + } + + @Test + void equalToObject() { + //language=java + rewriteRun( + java( + """ + class Biscuit { + String name; + Biscuit(String name) { + this.name = name; + } + } + """ + ), + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + + class BiscuitTest { + @Test + void testEquals() { + Biscuit theBiscuit = new Biscuit("Ginger"); + Biscuit myBiscuit = new Biscuit("Ginger"); + assertThat(theBiscuit, equalTo(myBiscuit)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertEquals; + + class BiscuitTest { + @Test + void testEquals() { + Biscuit theBiscuit = new Biscuit("Ginger"); + Biscuit myBiscuit = new Biscuit("Ginger"); + assertEquals(theBiscuit, myBiscuit); + } + } + """ + ) + ); + } + + @DocumentExample + @Test + void equalToString() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, equalTo(str2)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertEquals; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertEquals(str1, str2); + } + } + """ + ) + ); + } + + @Test + void notEqualToString() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + import static org.hamcrest.Matchers.not; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, not(equalTo(str2))); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertNotEquals; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertNotEquals(str1, str2); + } + } + """ + ) + ); + } + + @Test + void greaterThan() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.greaterThan; + + class ATest { + @Test + void testEquals() { + int intt = 7; + assertThat(10, greaterThan(intt)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testEquals() { + int intt = 7; + assertTrue(10 > intt); + } + } + """ + ) + ); + } + + @Test + void greaterThanOrEqualTo() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.greaterThanOrEqualTo; + + class ATest { + @Test + void testGreaterThanOrEqualTo() { + int intt = 7; + assertThat(10, greaterThanOrEqualTo(intt)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testGreaterThanOrEqualTo() { + int intt = 7; + assertTrue(10 >= intt); + } + } + """ + ) + ); + } + + @Test + void closeTo() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.closeTo; + + class ATest { + @Test + void testCloseTo() { + double dbl = 179.1; + assertThat(dbl, closeTo(178.2, 1.0)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testCloseTo() { + double dbl = 179.1; + assertTrue(Math.abs(dbl - 178.2) < 1.0); + } + } + """ + ) + ); + } + + @Test + void collections() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import java.util.ArrayList; + import java.util.Collection; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.empty; + import static org.hamcrest.Matchers.hasSize; + + class ATest { + private static final Collection collection = new ArrayList<>(); + @Test + void testEmpty() { + assertThat(collection, empty()); + assertThat(collection, hasSize(0)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + import java.util.ArrayList; + import java.util.Collection; + + import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + private static final Collection collection = new ArrayList<>(); + @Test + void testEmpty() { + assertTrue(collection.isEmpty()); + assertEquals(collection.size(), 0); + } + } + """ + ) + ); + } + + @Test + void arraysAndIterables() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import java.util.Arrays; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.emptyArray; + import static org.hamcrest.Matchers.emptyIterable; + + class ATest { + private static final Integer[] ints = new Integer[]{}; + @Test + void testEmpty() { + assertThat(ints, emptyArray()); + Iterable iterable = Arrays.stream(ints).toList(); + assertThat(iterable, emptyIterable()); + } + } + """, + """ + import org.junit.jupiter.api.Test; + import java.util.Arrays; + + import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.assertFalse; + + class ATest { + private static final Integer[] ints = new Integer[]{}; + @Test + void testEmpty() { + assertEquals(0, ints.length); + Iterable iterable = Arrays.stream(ints).toList(); + assertFalse(iterable.iterator().hasNext()); + } + } + """ + ) + ); + } + + @Test + void lessThan() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.lessThan; + + class ATest { + @Test + void testLessThan() { + int intt = 7; + assertThat(5, lessThan(intt)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testLessThan() { + int intt = 7; + assertTrue(5 < intt); + } + } + """ + ) + ); + } + + @Test + void lessThanOrEqualTo() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.lessThanOrEqualTo; + + class ATest { + @Test + void testLessThanOrEqualTo() { + int intt = 7; + assertThat(5, lessThanOrEqualTo(intt)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testLessThanOrEqualTo() { + int intt = 7; + assertTrue(5 <= intt); + } + } + """ + ) + ); + } + + @Test + void nullValue() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.nullValue; + import static org.hamcrest.Matchers.notNullValue; + + class ATest { + @Test + void testNullValue() { + Integer integer = null; + String str = "hello world"; + assertThat(integer, nullValue()); + assertThat(str, notNullValue()); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertNotNull; + import static org.junit.jupiter.api.Assertions.assertNull; + + class ATest { + @Test + void testNullValue() { + Integer integer = null; + String str = "hello world"; + assertNull(integer); + assertNotNull(str); + } + } + """ + ) + ); + } + + @Test + void sameInstance() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.not; + import static org.hamcrest.Matchers.sameInstance; + import static org.hamcrest.Matchers.theInstance; + + class ATest { + private final String string = "Hello world."; + @Test + void testSameInstance() { + String localString = string; + String differentString = "Hello void."; + assertThat(string, sameInstance(localString)); + assertThat(string, not(theInstance(differentString))); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertNotSame; + import static org.junit.jupiter.api.Assertions.assertSame; + + class ATest { + private final String string = "Hello world."; + @Test + void testSameInstance() { + String localString = string; + String differentString = "Hello void."; + assertSame(string, localString); + assertNotSame(string, differentString); + } + } + """ + ) + ); + } + + @Test + void hasEntry() { + //language=java + rewriteRun( + java( + """ + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.hasEntry; + + class ATest { + @Test + void testHasEntry() { + Map map = new HashMap<>(); + assertThat(map, hasEntry("hello", "world")); + } + } + """, + """ + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertEquals; + + class ATest { + @Test + void testHasEntry() { + Map map = new HashMap<>(); + assertEquals("world", map.get("hello")); + } + } + """ + ) + ); + } + + @Test + void hasKey() { + //language=java + rewriteRun( + java( + """ + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.hasKey; + + class ATest { + @Test + void testHasKey() { + Map map = new HashMap<>(); + assertThat(map, hasKey("hello")); + } + } + """, + """ + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testHasKey() { + Map map = new HashMap<>(); + assertTrue(map.containsKey("hello")); + } + } + """ + ) + ); + } + + @Test + void hasValue() { + //language=java + rewriteRun( + java( + """ + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.hasValue; + + class ATest { + @Test + void testHasValue() { + Map map = new HashMap<>(); + assertThat(map, hasValue("world")); + } + } + """, + """ + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testHasValue() { + Map map = new HashMap<>(); + assertTrue(map.containsValue("world")); + } + } + """ + ) + ); + } + + @Test + void typeCompatibleWith() { + //language=java + rewriteRun( + java( + """ + import java.util.List; + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.typeCompatibleWith; + + class ATest { + @Test + void testTypeCompatibleWith() { + assertThat(List.class, typeCompatibleWith(Iterable.class)); + } + } + """, + """ + import java.util.List; + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testTypeCompatibleWith() { + assertTrue(Iterable.class.isAssignableFrom(List.class)); + } + } + """ + ) + ); + } + + @Test + void containsString() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.containsString; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String substring = "llo wor"; + assertThat(string, containsString(substring)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String substring = "llo wor"; + assertTrue(string.contains(substring)); + } + } + """ + ) + ); + } + + @Test + void endsWith() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.endsWith; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String suffix = "world"; + assertThat(string, endsWith(suffix)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String suffix = "world"; + assertTrue(string.endsWith(suffix)); + } + } + """ + ) + ); + } + + @Test + void equalToIgnoringCase() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalToIgnoringCase; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string1 = "hELLo WoRLD"; + String string2 = "HeLlO WOrLd"; + assertThat(string1, equalToIgnoringCase(string2)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string1 = "hELLo WoRLD"; + String string2 = "HeLlO WOrLd"; + assertTrue(string1.equalsIgnoreCase(string2)); + } + } + """ + ) + ); + } + + @Test + void hasToString() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.hasToString; + + class ATest { + @Test + void testTypeCompatibleWith() { + StringBuilder sb = new StringBuilder(); + sb.append("hello"); + assertThat(sb, hasToString("hello")); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertEquals; + + class ATest { + @Test + void testTypeCompatibleWith() { + StringBuilder sb = new StringBuilder(); + sb.append("hello"); + assertEquals(sb.toString(), "hello"); + } + } + """ + ) + ); + } + + @Test + void startsWith() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.startsWith; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String prefix = "hello"; + assertThat(string, startsWith(prefix)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String prefix = "hello"; + assertTrue(string.startsWith(prefix)); + } + } + """ + ) + ); + } + + @Test + void assertionsWithReason() { + //language=java + rewriteRun( + java( + """ + import java.util.List; + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.startsWith; + + class ATest { + private static final List list = List.of(); + + @Test + void testAssertionsWithReason() { + String string = "hello world"; + String prefix = "hello"; + assertThat("String does not start with given prefix.", string, startsWith(prefix)); + } + } + """, + """ + import java.util.List; + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + private static final List list = List.of(); + + @Test + void testAssertionsWithReason() { + String string = "hello world"; + String prefix = "hello"; + assertTrue(string.startsWith(prefix), "String does not start with given prefix."); + } + } + """ + ) + ); + } + + @Test + void shouldNotRewriteCaseTest() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.containsString; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String substring = "llo wor"; + assertThat(string, containsString(substring)); + assertThat("String does not contain the substring", string.contains(substring)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testTypeCompatibleWith() { + String string = "hello world"; + String substring = "llo wor"; + assertTrue(string.contains(substring)); + assertThat("String does not contain the substring", string.contains(substring)); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToAssertJTest.java b/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToAssertJTest.java index b0229562f..b1ea8767a 100644 --- a/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToAssertJTest.java +++ b/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToAssertJTest.java @@ -68,7 +68,7 @@ class Biscuit { Biscuit(String name) { this.name = name; } - + int getChocolateChipCount() { return 10; } @@ -120,40 +120,40 @@ void allOfStringMatchersAndConvert() { rewriteRun( //language=java java( - """ - import org.junit.jupiter.api.Test; - - import static org.hamcrest.MatcherAssert.assertThat; - import static org.hamcrest.Matchers.allOf; - import static org.hamcrest.Matchers.equalTo; - import static org.hamcrest.Matchers.hasLength; - - class ATest { - @Test - void test() { - String str1 = "Hello world!"; - String str2 = "Hello world!"; - assertThat(str1, allOf(equalTo(str2), hasLength(12))); - } - } - """, """ - import org.junit.jupiter.api.Test; - - import static org.assertj.core.api.Assertions.assertThat; - - class ATest { - @Test - void test() { - String str1 = "Hello world!"; - String str2 = "Hello world!"; - assertThat(str1) - .satisfies( - arg -> assertThat(arg).isEqualTo(str2), - arg -> assertThat(arg).hasSize(12) - ); - } - } - """)); + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.allOf; + import static org.hamcrest.Matchers.equalTo; + import static org.hamcrest.Matchers.hasLength; + + class ATest { + @Test + void test() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, allOf(equalTo(str2), hasLength(12))); + } + } + """, """ + import org.junit.jupiter.api.Test; + + import static org.assertj.core.api.Assertions.assertThat; + + class ATest { + @Test + void test() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1) + .satisfies( + arg -> assertThat(arg).isEqualTo(str2), + arg -> assertThat(arg).hasSize(12) + ); + } + } + """)); } @Test @@ -162,40 +162,40 @@ void convertAnyOfMatchersAfterSatisfiesAnyOfConversion() { rewriteRun( //language=java java( - """ - import org.junit.jupiter.api.Test; - - import static org.hamcrest.MatcherAssert.assertThat; - import static org.hamcrest.Matchers.anyOf; - import static org.hamcrest.Matchers.equalTo; - import static org.hamcrest.Matchers.hasLength; - - class ATest { - @Test - void test() { - String str1 = "Hello world!"; - String str2 = "Hello world!"; - assertThat(str1, anyOf(equalTo(str2), hasLength(12))); - } - } - """, """ - import org.junit.jupiter.api.Test; - - import static org.assertj.core.api.Assertions.assertThat; - - class ATest { - @Test - void test() { - String str1 = "Hello world!"; - String str2 = "Hello world!"; - assertThat(str1) - .satisfiesAnyOf( - arg -> assertThat(arg).isEqualTo(str2), - arg -> assertThat(arg).hasSize(12) - ); - } - } - """)); + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.anyOf; + import static org.hamcrest.Matchers.equalTo; + import static org.hamcrest.Matchers.hasLength; + + class ATest { + @Test + void test() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, anyOf(equalTo(str2), hasLength(12))); + } + } + """, """ + import org.junit.jupiter.api.Test; + + import static org.assertj.core.api.Assertions.assertThat; + + class ATest { + @Test + void test() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1) + .satisfiesAnyOf( + arg -> assertThat(arg).isEqualTo(str2), + arg -> assertThat(arg).hasSize(12) + ); + } + } + """)); } private static Stream arrayReplacements() { @@ -218,9 +218,9 @@ void arrayReplacements(String actual, String hamcrestMatcher, String matcherArgs //language=java String template = """ import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test() { @@ -276,9 +276,9 @@ void stringReplacements(String actual, String hamcrestMatcher, String matcherArg //language=java String template = """ import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test() { @@ -315,9 +315,9 @@ void objectReplacements(String actual, String hamcrestMatcher, String matcherArg //language=java String template = """ import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test() { @@ -331,14 +331,14 @@ void test() { String after = template.formatted(importsAfter, "assertThat(%s).%s(%s);".formatted(actual, assertJAssertion, matcherArgs)); rewriteRun( java( - """ - class Biscuit { - String name; - Biscuit(String name) { - this.name = name; - } - } - """), + """ + class Biscuit { + String name; + Biscuit(String name) { + this.name = name; + } + } + """), java(before, after)); } @@ -362,9 +362,9 @@ void numberReplacements(String actual, String hamcrestMatcher, String matcherArg //language=java String template = """ import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test() { @@ -404,9 +404,9 @@ void listReplacements(String actual, String hamcrestMatcher, String matcherArgs, String template = """ import java.util.List; import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test(String item) { @@ -441,9 +441,9 @@ void mapReplacements(String actual, String hamcrestMatcher, String matcherArgs, String template = """ import java.util.Map; import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test(String key, String value) { @@ -490,9 +490,9 @@ void notReplacements(String actual, String hamcrestMatcher, String matcherArgs, //language=java String template = """ import org.junit.jupiter.api.Test; - + %s - + class ATest { @Test void test() { @@ -512,10 +512,10 @@ class Dependencies { @Language("java") private static final String JAVA_BEFORE = """ import org.junit.jupiter.api.Test; - + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; - + class ATest { @Test void test() { @@ -527,9 +527,9 @@ void test() { @Language("java") private static final String JAVA_AFTER = """ import org.junit.jupiter.api.Test; - + import static org.assertj.core.api.Assertions.assertThat; - + class ATest { @Test void test() { @@ -541,90 +541,91 @@ void test() { @Test void assertjMavenDependencyAddedWithTestScope() { rewriteRun( - spec -> spec.expectedCyclesThatMakeChanges(2), mavenProject("project", srcTestJava(java(JAVA_BEFORE, JAVA_AFTER)), //language=xml pomXml(""" - - 4.0.0 - com.example - demo - 0.0.1-SNAPSHOT - - - org.hamcrest - hamcrest - 2.2 - test - - - - """, - sourceSpecs -> sourceSpecs.after(after -> """ - - 4.0.0 - com.example - demo - 0.0.1-SNAPSHOT - - - org.assertj - assertj-core - %s - test - - - org.hamcrest - hamcrest - 2.2 - test - - - - """.formatted(Pattern.compile("(3\\.2.*)").matcher(requireNonNull(after)).results().findFirst().orElseThrow().group(1)))) - ) - ); + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + org.hamcrest + hamcrest + 2.2 + test + + + + """, + sourceSpecs -> sourceSpecs.after(after -> """ + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + org.assertj + assertj-core + %s + test + + + org.hamcrest + hamcrest + 2.2 + test + + + + """.formatted(Pattern.compile("(3\\.2.*)").matcher(requireNonNull(after)).results().findFirst().orElseThrow().group(1)))) + ) + ); } @Test void assertjGradleDependencyAddedWithTestScope() { rewriteRun( - spec -> spec.beforeRecipe(withToolingApi()).expectedCyclesThatMakeChanges(2), + spec -> spec.beforeRecipe(withToolingApi()), mavenProject("project", srcTestJava(java(JAVA_BEFORE, JAVA_AFTER)), - buildGradle(""" - plugins { - id "java-library" - } - - repositories { - mavenCentral() - } - - dependencies { - testImplementation "org.hamcrest:hamcrest:2.2" - } - """, - sourceSpecs -> sourceSpecs.after(after -> """ - plugins { - id "java-library" - } - - repositories { - mavenCentral() - } - - dependencies { - testImplementation "org.assertj:%s" - testImplementation "org.hamcrest:hamcrest:2.2" - } + //language=groovy + buildGradle( """ - .formatted(Pattern.compile("(assertj-core:[^\"]*)").matcher(requireNonNull(after)).results().findFirst().orElseThrow().group(1)) + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + + dependencies { + testImplementation "org.hamcrest:hamcrest:2.2" + } + """, + sourceSpecs -> sourceSpecs.after(after -> """ + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + + dependencies { + testImplementation "org.assertj:%s" + testImplementation "org.hamcrest:hamcrest:2.2" + } + """ + .formatted(Pattern.compile("(assertj-core:[^\"]*)").matcher(requireNonNull(after)).results().findFirst().orElseThrow().group(1)) + ) ) ) - ) - ); + ); } } @@ -685,14 +686,14 @@ void isMatcherFromCore() { """ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; - + import org.junit.jupiter.api.Test; - + class DebugTest { class Foo { int i = 8; } - + @Test void ba() { assertThat(System.out, is(System.out)); @@ -702,14 +703,14 @@ void ba() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + import org.junit.jupiter.api.Test; - + class DebugTest { class Foo { int i = 8; } - + @Test void ba() { assertThat(System.out).isEqualTo(System.out); @@ -732,9 +733,9 @@ void isEqualMatcherFromCore() { import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNot.not; import static org.hamcrest.core.IsSame.sameInstance; - + import org.junit.jupiter.api.Test; - + class DebugTest { @Test void ba() { @@ -746,9 +747,9 @@ void ba() { """, """ import static org.assertj.core.api.Assertions.assertThat; - + import org.junit.jupiter.api.Test; - + class DebugTest { @Test void ba() { @@ -803,7 +804,7 @@ void bar(List list) { } ) @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/526") - void greaterThanOrEqualToDate(String type){ + void greaterThanOrEqualToDate(String type) { rewriteRun( java( """ diff --git a/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToJUnitTest.java b/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToJUnitTest.java new file mode 100644 index 000000000..c4a9a49ad --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/hamcrest/MigrateHamcrestToJUnitTest.java @@ -0,0 +1,149 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class MigrateHamcrestToJUnitTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "hamcrest-2.2")) + .recipeFromResource("/META-INF/rewrite/hamcrest.yml", "org.openrewrite.java.testing.hamcrest.MigrateHamcrestToJUnit5"); + } + + @DocumentExample + @Test + void equalToString() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + import static org.hamcrest.Matchers.is; + import static org.hamcrest.Matchers.not; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, is(equalTo(str2))); + assertThat(str1, is(not(equalTo(str2 + "!")))); + } + } + """, + """ + import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.assertNotEquals; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertEquals(str1, str2); + assertNotEquals(str1, str2 + "!"); + } + } + """ + ) + ); + } + + @Test + void assertWithLogicOp() { + rewriteRun( + //language=java + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + + class ATest { + @Test + void testEquals() { + int a = 7; + int b = 29; + assertThat("Not equal", a == b); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testEquals() { + int a = 7; + int b = 29; + assertTrue(a == b, "Not equal"); + } + } + """ + ) + ); + } + + @Test + void assertWithMethodCall() { + rewriteRun( + //language=java + java( + """ + import org.junit.jupiter.api.Test; + + import static org.hamcrest.MatcherAssert.assertThat; + + class ATest { + @Test + void testContains() { + String string = "Hello world"; + assertThat("Does not contain", string.contains("llo wor")); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class ATest { + @Test + void testContains() { + String string = "Hello world"; + assertTrue(string.contains("llo wor"), "Does not contain"); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/hamcrest/RemoveNotMatcherTest.java b/src/test/java/org/openrewrite/java/testing/hamcrest/RemoveNotMatcherTest.java new file mode 100644 index 000000000..418c81a78 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/hamcrest/RemoveNotMatcherTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2023 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.hamcrest; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.test.RewriteTest.toRecipe; + +class RemoveNotMatcherTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "hamcrest-2.2")) + .recipe(toRecipe(RemoveNotMatcherVisitor::new)); + } + + @DocumentExample + void nestedNotMatcher() { + rewriteRun( + //language=java + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + import static org.hamcrest.Matchers.not; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, not(equalTo(str2))); + } + } + """, + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, equalTo(str2)); + } + } + """ + ) + ); + } + + @Test + void notMatcher() { + rewriteRun( + //language=java + java( + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.not; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, not(str2)); + } + } + """, + """ + import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; + import static org.hamcrest.Matchers.equalTo; + + class ATest { + @Test + void testEquals() { + String str1 = "Hello world!"; + String str2 = "Hello world!"; + assertThat(str1, equalTo(str2)); + } + } + """ + ) + ); + } + +} diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockitoTest.java index aba68599f..2cb93ff8f 100644 --- a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockitoTest.java +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitAnnotatedArgumentToMockitoTest.java @@ -17,27 +17,17 @@ import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.setDefaultParserSettings; class JMockitAnnotatedArgumentToMockitoTest implements RewriteTest { + @Override public void defaults(RecipeSpec spec) { - spec - .parser(JavaParser.fromJavaVersion() - .logCompilationWarningsAndErrors(true) - .classpathFromResources(new InMemoryExecutionContext(), - "junit-jupiter-api-5.9", - "jmockit-1.49" - )) - .recipeFromResource( - "/META-INF/rewrite/jmockit.yml", - "org.openrewrite.java.testing.jmockit.JMockitToMockito" - ); + setDefaultParserSettings(spec); } @DocumentExample diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitDelegateToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitDelegateToMockitoTest.java index e4ad77bbd..dca71281e 100644 --- a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitDelegateToMockitoTest.java +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitDelegateToMockitoTest.java @@ -30,6 +30,7 @@ * with the template being printed out. These tests were written to try to replicate this issue, however I was unable to. * They may help anyone who wants to add Delegate migration. */ +@SuppressWarnings("ResultOfMethodCallIgnored") @Disabled @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/522") class JMockitDelegateToMockitoTest implements RewriteTest { @@ -51,12 +52,12 @@ void whenNoArgsVoidMethod() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.wait(); @@ -75,14 +76,14 @@ public void wait() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { doAnswer(invocation -> { System.out.println("foo"); @@ -107,12 +108,12 @@ void whenHasArgsVoidMethod() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.wait(anyLong); @@ -132,15 +133,15 @@ void wait(long timeoutMs) { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { doAnswer(invocation -> { System.out.println("foo"); @@ -166,14 +167,14 @@ void whenNoArgsNonVoidMethod() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.toString(); @@ -193,15 +194,15 @@ String toString() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { when(myObject.toString()).thenAnswer(invocation -> { String a = "foo"; @@ -226,14 +227,14 @@ void whenMultipleStatementsWithAnnotation() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.hashCode(); @@ -257,15 +258,15 @@ String toString() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { when(myObject.hashCode()).thenReturn(100); when(myObject.toString()).thenAnswer(invocation -> { @@ -288,7 +289,7 @@ void whenClassArgumentMatcher() { java( """ import java.util.List; - + class MyObject { public String getSomeField(List input) { return "X"; @@ -303,18 +304,18 @@ public String getSomeOtherField(Object input) { """ import java.util.ArrayList; import java.util.List; - + import mockit.Delegate; import mockit.Mocked; import mockit.Expectations; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField((List) any); @@ -333,21 +334,21 @@ String getSomeOtherField(List input) { """ import java.util.ArrayList; import java.util.List; - + import mockit.Delegate; - + import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.when; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField(anyList())).thenAnswer(invocation -> { List input = invocation.getArgument(0); diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitExpectationsToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitExpectationsToMockitoTest.java index 7ebd6531a..29e107663 100644 --- a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitExpectationsToMockitoTest.java +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitExpectationsToMockitoTest.java @@ -24,6 +24,7 @@ import static org.openrewrite.java.Assertions.java; import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.setDefaultParserSettings; +@SuppressWarnings({"SpellCheckingInspection", "ResultOfMethodCallIgnored", "EmptyClassInitializer"}) class JMockitExpectationsToMockitoTest implements RewriteTest { @Override @@ -42,14 +43,14 @@ void whenTimesAndResult() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.toString(); @@ -65,15 +66,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { when(myObject.toString()).thenReturn("foo"); assertEquals("foo", myObject.toString()); @@ -97,12 +98,12 @@ void whenNoResultNoTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.wait(anyLong, anyInt); @@ -115,14 +116,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject).wait(anyLong(), anyInt()); @@ -143,12 +144,12 @@ void whenNoResultNoTimesNoArgs() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.wait(); @@ -161,14 +162,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject).wait(); @@ -189,14 +190,14 @@ void whenHasResultNoTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.toString(); @@ -213,12 +214,12 @@ void test() { import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { when(myObject.toString()).thenReturn("foo"); assertEquals("foo", myObject.toString()); @@ -248,14 +249,14 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField(); @@ -269,15 +270,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField()).thenReturn(null); assertNull(myObject.getSomeField()); @@ -307,14 +308,14 @@ public int getSomeField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField(); @@ -333,15 +334,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField()).thenReturn(10); assertEquals(10, myObject.getSomeField()); @@ -373,14 +374,14 @@ public String getSomeField(String s) { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField(anyString); @@ -394,16 +395,16 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField(anyString())).thenReturn("foo"); assertEquals("foo", myObject.getSomeField("bar")); @@ -433,16 +434,16 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + String expected = "expected"; - + void test() { new Expectations() {{ myObject.getSomeField(); @@ -456,17 +457,17 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + String expected = "expected"; - + void test() { when(myObject.getSomeField()).thenReturn(expected); assertEquals(expected, myObject.getSomeField()); @@ -496,14 +497,14 @@ public Object getSomeField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertNotNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField(); @@ -517,15 +518,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField()).thenReturn(new Object()); assertNotNull(myObject.getSomeField()); @@ -555,12 +556,12 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() throws RuntimeException { new Expectations() {{ myObject.getSomeField(); @@ -574,14 +575,14 @@ void test() throws RuntimeException { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() throws RuntimeException { when(myObject.getSomeField()).thenThrow(new RuntimeException()); myObject.getSomeField(); @@ -611,14 +612,14 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() throws RuntimeException { new Expectations() {{ myObject.getSomeField(); @@ -633,15 +634,15 @@ void test() throws RuntimeException { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() throws RuntimeException { when(myObject.getSomeField()).thenReturn("foo", "bar"); assertEquals("foo", myObject.getSomeField()); @@ -660,7 +661,7 @@ void whenClassArgumentMatcher() { java( """ import java.util.List; - + class MyObject { public String getSomeField(List input) { return "X"; @@ -668,6 +669,9 @@ public String getSomeField(List input) { public String getSomeOtherField(Object input) { return "Y"; } + public String getSomeArrayField(Object input) { + return "Z"; + } } """ ), @@ -675,52 +679,57 @@ public String getSomeOtherField(Object input) { """ import java.util.ArrayList; import java.util.List; - + import mockit.Expectations; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField((List) any); result = null; myObject.getSomeOtherField((Object) any); result = null; + myObject.getSomeArrayField((byte[]) any); + result = null; }}; assertNull(myObject.getSomeField(new ArrayList<>())); assertNull(myObject.getSomeOtherField(new Object())); + assertNull(myObject.getSomeArrayField(new byte[0])); } } """, """ import java.util.ArrayList; import java.util.List; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField(anyList())).thenReturn(null); when(myObject.getSomeOtherField(any(Object.class))).thenReturn(null); + when(myObject.getSomeArrayField(any(byte[].class))).thenReturn(null); assertNull(myObject.getSomeField(new ArrayList<>())); assertNull(myObject.getSomeOtherField(new Object())); + assertNull(myObject.getSomeArrayField(new byte[0])); } } """ @@ -735,7 +744,7 @@ void whenNoArguments() { java( """ import java.util.List; - + class MyObject { public String getSomeField() { return "X"; @@ -747,19 +756,19 @@ public String getSomeField() { """ import java.util.ArrayList; import java.util.List; - + import mockit.Expectations; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeField(); @@ -772,19 +781,19 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeField()).thenReturn(null); assertNull(myObject.getSomeField()); @@ -802,7 +811,7 @@ void whenMixedArgumentMatcher() { java( """ import java.util.List; - + class MyObject { public String getSomeField(String s, String s2, String s3, long l1) { return "X"; @@ -814,19 +823,19 @@ public String getSomeField(String s, String s2, String s3, long l1) { """ import java.util.ArrayList; import java.util.List; - + import mockit.Expectations; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { String bazz = "bazz"; new Expectations() {{ @@ -840,19 +849,19 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { String bazz = "bazz"; when(myObject.getSomeField(eq("foo"), anyString(), eq(bazz), eq(10L))).thenReturn(null); @@ -871,7 +880,7 @@ void whenSetupStatements() { java( """ class MyObject { - + public String getSomeField(String s) { return "X"; } @@ -887,26 +896,26 @@ public String getString() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { String a = "a"; String s = "s"; - + new Expectations() {{ myObject.getSomeField(anyString); result = s; - + myObject.getString(); result = a; }}; - + assertEquals("s", myObject.getSomeField("foo")); assertEquals("a", myObject.getString()); } @@ -916,22 +925,22 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { String a = "a"; String s = "s"; when(myObject.getSomeField(anyString())).thenReturn(s); when(myObject.getString()).thenReturn(a); - + assertEquals("s", myObject.getSomeField("foo")); assertEquals("a", myObject.getString()); } @@ -960,14 +969,14 @@ public String getSomeField(String s) { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { String a = "a"; new Expectations() {{ @@ -976,7 +985,7 @@ void test() { String b = "b"; result = s; }}; - + assertEquals("s", myObject.getSomeField("foo")); } } @@ -985,22 +994,22 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { String a = "a"; String s = "s"; String b = "b"; when(myObject.getSomeField(anyString())).thenReturn(s); - + assertEquals("s", myObject.getSomeField("foo")); } } @@ -1019,12 +1028,12 @@ void whenTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.wait(anyLong, anyInt); @@ -1040,14 +1049,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); myObject.wait(10L, 10); @@ -1070,7 +1079,7 @@ void whenMinTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked @@ -1089,9 +1098,9 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock @@ -1117,7 +1126,7 @@ void whenMaxTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked @@ -1136,9 +1145,9 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock @@ -1164,7 +1173,7 @@ void whenMinTimesMaxTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked @@ -1184,9 +1193,9 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock @@ -1222,14 +1231,14 @@ public String getSomeField() { import mockit.Tested; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; - + @ExtendWith(JMockitExtension.class) class MyTest { @Tested MyObject myObject; - + void test() { new Expectations(myObject) {{ myObject.getSomeField(); @@ -1243,15 +1252,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @InjectMocks MyObject myObject; - + void test() { when(myObject.getSomeField()).thenReturn("foo"); assertEquals("foo", myObject.getSomeField()); @@ -1288,18 +1297,18 @@ public void doSomething() {} import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + @Mocked MyObject myOtherObject; - + void test() { new Expectations() {{ myObject.hashCode(); @@ -1321,19 +1330,19 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + @Mock MyObject myOtherObject; - + void test() { when(myObject.hashCode()).thenReturn(10); when(myOtherObject.getSomeObjectField()).thenReturn(null); @@ -1369,15 +1378,15 @@ public String getSomeStringField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ myObject.getSomeStringField(); @@ -1396,16 +1405,16 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getSomeStringField()).thenReturn("a"); assertEquals("a", myObject.getSomeStringField()); @@ -1440,18 +1449,18 @@ public String getY() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() { - { + { myObject.getX(); result = "x1"; } @@ -1469,16 +1478,16 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { when(myObject.getX()).thenReturn("x1"); when(myObject.getY()).thenReturn("y1"); @@ -1492,7 +1501,7 @@ void test() { } @Test - void whenMultipleExpectationsNoResults() { + void whenMultipleExpectationsNoResults() { //language=java rewriteRun( java( @@ -1501,15 +1510,15 @@ void whenMultipleExpectationsNoResults() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Expectations() {{ myObject.wait(anyLong); @@ -1526,17 +1535,17 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(1L); myObject.wait(); @@ -1549,6 +1558,57 @@ void test() { ); } + @Test + void whenWithRedundantThisModifier() { + //language=java + rewriteRun( + java( + """ + import mockit.Expectations; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.assertNull; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + new Expectations() {{ + myObject.wait(this.anyLong, anyInt); + }}; + myObject.wait(); + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.assertNull; + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + myObject.wait(); + verify(myObject).wait(anyLong(), anyInt()); + } + } + """ + ) + ); + } + @Disabled // comment migration not supported yet @Test void whenComments() { @@ -1569,15 +1629,15 @@ public String getSomeStringField() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { new Expectations() {{ // comments for this line below @@ -1597,16 +1657,16 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { // comments for this line below when(myObject.getSomeStringField()).thenReturn("a"); @@ -1619,4 +1679,46 @@ void test() { ) ); } + + @Test + void whenEmptyBlock() { + //language=java + rewriteRun( + java( + """ + import mockit.Expectations; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + new Expectations() {{ + }}; + myObject.wait(1L); + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + myObject.wait(1L); + } + } + """ + ) + ); + } } diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitFullVerificationsToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitFullVerificationsToMockitoTest.java new file mode 100644 index 000000000..5eae411e5 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitFullVerificationsToMockitoTest.java @@ -0,0 +1,248 @@ +/* + * Copyright 2023 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.jmockit; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.setDefaultParserSettings; + +/** + * Not doing comprehensive testing as it is covered in JMockitVerificationsToMockitoTest and shares same code path + */ +@SuppressWarnings("SpellCheckingInspection") +class JMockitFullVerificationsToMockitoTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + setDefaultParserSettings(spec); + } + + @DocumentExample + @Test + void whenMultipleMocks() { + //language=java + rewriteRun( + java( + """ + import mockit.FullVerifications; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + @Mocked + String str; + + void test() { + myObject.wait(10L, 10); + myObject.wait(10L, 10); + str.notify(); + new FullVerifications() {{ + myObject.wait(anyLong, anyInt); + times = 2; + str.notify(); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + @Mock + String str; + + void test() { + myObject.wait(10L, 10); + myObject.wait(10L, 10); + str.notify(); + verify(myObject, times(2)).wait(anyLong(), anyInt()); + verify(str).notify(); + verifyNoMoreInteractions(myObject, str); + } + } + """ + ) + ); + } + + @Test + void whenTimes() { + //language=java + rewriteRun( + java( + """ + import mockit.FullVerifications; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + myObject.wait(10L, 10); + myObject.wait(10L, 10); + new FullVerifications() {{ + myObject.wait(anyLong, anyInt); + times = 2; + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + myObject.wait(10L, 10); + myObject.wait(10L, 10); + verify(myObject, times(2)).wait(anyLong(), anyInt()); + verifyNoMoreInteractions(myObject); + } + } + """ + ) + ); + } + + @DocumentExample + @Test + void whenOtherStatements() { + //language=java + rewriteRun( + java( + """ + import mockit.FullVerifications; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + myObject.wait(10L, 10); + new FullVerifications() {{ + myObject.wait(anyLong, anyInt); + }}; + System.out.println("bla"); + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + myObject.wait(10L, 10); + verify(myObject).wait(anyLong(), anyInt()); + verifyNoMoreInteractions(myObject); + System.out.println("bla"); + } + } + """ + ) + ); + } + + @Test + void whenMultipleInvocationsSameMock() { + //language=java + rewriteRun( + java( + """ + import mockit.FullVerifications; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + myObject.wait(10L, 10); + myObject.wait(); + new FullVerifications() {{ + myObject.wait(anyLong, anyInt); + myObject.wait(); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + myObject.wait(10L, 10); + myObject.wait(); + verify(myObject).wait(anyLong(), anyInt()); + verify(myObject).wait(); + verifyNoMoreInteractions(myObject); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java new file mode 100644 index 000000000..49c9ed48b --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java @@ -0,0 +1,653 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.jmockit; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.SourceSpec; +import org.openrewrite.test.TypeValidation; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.*; + +class JMockitMockUpToMockitoTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + setParserSettings(spec, JMOCKIT_DEPENDENCY, JUNIT_4_DEPENDENCY); + } + + @DocumentExample + @Test + void mockUpStaticMethodTest() { + //language=java + rewriteRun( + java( + """ + import mockit.Mock; + import mockit.MockUp; + import static org.junit.Assert.assertEquals; + import org.junit.Test; + + public class MockUpTest { + @Test + public void test() { + new MockUp() { + + @Mock + public int staticMethod() { + return 1024; + } + + @Mock + public int staticMethod(int v) { + return 128; + } + }; + assertEquals(1024, MyClazz.staticMethod()); + assertEquals(128, MyClazz.staticMethod(0)); + } + + public static class MyClazz { + public static int staticMethod() { + return 0; + } + + public static int staticMethod(int v) { + return 1; + } + } + } + """, """ + import static org.junit.Assert.assertEquals; + import static org.mockito.ArgumentMatchers.*; + import static org.mockito.Mockito.*; + + import org.junit.Test; + import org.mockito.MockedStatic; + + public class MockUpTest { + @Test + public void test() { + try (MockedStatic mockStaticMyClazz = mockStatic(MyClazz.class)) { + mockStaticMyClazz.when(() -> MyClazz.staticMethod()).thenAnswer(invocation -> 1024); + mockStaticMyClazz.when(() -> MyClazz.staticMethod(anyInt())).thenAnswer(invocation -> 128); + assertEquals(1024, MyClazz.staticMethod()); + assertEquals(128, MyClazz.staticMethod(0)); + } + } + + public static class MyClazz { + public static int staticMethod() { + return 0; + } + + public static int staticMethod(int v) { + return 1; + } + } + } + """)); + } + + @Test + void mockUpMultipleTest() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + package com.openrewrite; + public static class Foo { + public String getMsg() { + return "foo"; + } + + public String getMsg(String echo) { + return "foo" + echo; + } + } + """, + SourceSpec::skip + ), + java( + """ + package com.openrewrite; + public static class Bar { + public String getMsg() { + return "bar"; + } + + public String getMsg(String echo) { + return "bar" + echo; + } + } + """, + SourceSpec::skip + ), + java( + """ + import com.openrewrite.Foo; + import com.openrewrite.Bar; + import org.junit.Test; + import mockit.Mock; + import mockit.MockUp; + import static org.junit.Assert.assertEquals; + + public class MockUpTest { + @Test + public void test() { + new MockUp() { + @Mock + public String getMsg() { + return "FOO"; + } + @Mock + public String getMsg(String echo) { + return "FOO" + echo; + } + }; + new MockUp() { + @Mock + public String getMsg() { + return "BAR"; + } + @Mock + public String getMsg(String echo) { + return "BAR" + echo; + } + }; + assertEquals("FOO", new Foo().getMsg()); + assertEquals("FOOecho", new Foo().getMsg("echo")); + assertEquals("BAR", new Bar().getMsg()); + assertEquals("BARecho", new Bar().getMsg("echo")); + } + } + """, """ + import com.openrewrite.Foo; + import com.openrewrite.Bar; + import org.junit.Test; + import org.mockito.MockedConstruction; + import static org.junit.Assert.assertEquals; + import static org.mockito.AdditionalAnswers.delegatesTo; + import static org.mockito.Answers.CALLS_REAL_METHODS; + import static org.mockito.ArgumentMatchers.*; + import static org.mockito.Mockito.*; + + public class MockUpTest { + @Test + public void test() { + Foo mockFoo = mock(Foo.class, CALLS_REAL_METHODS); + doAnswer(invocation -> "FOO").when(mockFoo).getMsg(); + doAnswer(invocation -> { + String echo = invocation.getArgument(0); + return "FOO" + echo; + }).when(mockFoo).getMsg(nullable(String.class)); + Bar mockBar = mock(Bar.class, CALLS_REAL_METHODS); + doAnswer(invocation -> "BAR").when(mockBar).getMsg(); + doAnswer(invocation -> { + String echo = invocation.getArgument(0); + return "BAR" + echo; + }).when(mockBar).getMsg(nullable(String.class)); + try (MockedConstruction mockConsFoo = mockConstructionWithAnswer(Foo.class, delegatesTo(mockFoo));MockedConstruction mockConsBar = mockConstructionWithAnswer(Bar.class, delegatesTo(mockBar))) { + assertEquals("FOO", new Foo().getMsg()); + assertEquals("FOOecho", new Foo().getMsg("echo")); + assertEquals("BAR", new Bar().getMsg()); + assertEquals("BARecho", new Bar().getMsg("echo")); + } + } + } + """) + ); + } + + @Test + void mockUpInnerStatementTest() { + //language=java + rewriteRun( + java( + """ + import mockit.Mock; + import mockit.MockUp; + + import org.junit.Test; + import static org.junit.Assert.assertEquals; + + public class MockUpTest { + @Test + public void test() { + new MockUp() { + final String msg = "newMsg"; + + @Mock + public String getMsg() { + return msg; + } + }; + + // Should ignore the newClass statement + new Runnable() { + @Override + public void run() { + System.out.println("run"); + } + }; + assertEquals("newMsg", new MyClazz().getMsg()); + } + + public static class MyClazz { + public String getMsg() { + return "msg"; + } + } + } + """, """ + import org.junit.Test; + import org.mockito.MockedConstruction; + + import static org.junit.Assert.assertEquals; + import static org.mockito.AdditionalAnswers.delegatesTo; + import static org.mockito.Answers.CALLS_REAL_METHODS; + import static org.mockito.Mockito.*; + + public class MockUpTest { + @Test + public void test() { + final String msg = "newMsg"; + MyClazz mockMyClazz = mock(MyClazz.class, CALLS_REAL_METHODS); + doAnswer(invocation -> msg).when(mockMyClazz).getMsg(); + try (MockedConstruction mockConsMyClazz = mockConstructionWithAnswer(MyClazz.class, delegatesTo(mockMyClazz))) { + + // Should ignore the newClass statement + new Runnable() { + @Override + public void run() { + System.out.println("run"); + } + }; + assertEquals("newMsg", new MyClazz().getMsg()); + } + } + + public static class MyClazz { + public String getMsg() { + return "msg"; + } + } + } + """)); + } + + @Test + void mockUpVoidTest() { + //language=java + rewriteRun( + java( + """ + import mockit.Mock; + import mockit.MockUp; + import static org.junit.Assert.assertEquals; + import org.junit.Test; + + public class MockUpTest { + @Test + public void test() { + new MockUp() { + @Mock + public void changeMsg() { + MockUpClass.Save.msg = "mockMsg"; + } + + @Mock + public void changeText(String text) { + MockUpClass.Save.text = "mockText"; + } + }; + + assertEquals("mockMsg", new MockUpClass().getMsg()); + assertEquals("mockText", new MockUpClass().getText()); + } + + public static class MockUpClass { + public static class Save { + public static String msg = "msg"; + public static String text = "text"; + } + + public final String getMsg() { + changeMsg(); + return Save.msg; + } + + public void changeMsg() { + Save.msg = "newMsg"; + } + + public String getText() { + changeText("newText"); + return Save.text; + } + + public static void changeText(String text) { + Save.text = text; + } + } + } + """, + """ + import static org.junit.Assert.assertEquals; + import static org.mockito.AdditionalAnswers.delegatesTo; + import static org.mockito.Answers.CALLS_REAL_METHODS; + import static org.mockito.ArgumentMatchers.*; + import static org.mockito.Mockito.*; + + import org.junit.Test; + import org.mockito.MockedConstruction; + import org.mockito.MockedStatic; + + public class MockUpTest { + @Test + public void test() { + MockUpClass mockMockUpClass = mock(MockUpClass.class, CALLS_REAL_METHODS); + doAnswer(invocation -> { + MockUpClass.Save.msg = "mockMsg"; + return null; + }).when(mockMockUpClass).changeMsg(); + try (MockedStatic mockStaticMockUpClass = mockStatic(MockUpClass.class);MockedConstruction mockConsMockUpClass = mockConstructionWithAnswer(MockUpClass.class, delegatesTo(mockMockUpClass))) { + mockStaticMockUpClass.when(() -> MockUpClass.changeText(nullable(String.class))).thenAnswer(invocation -> { + String text = invocation.getArgument(0); + MockUpClass.Save.text = "mockText"; + return null; + }); + + assertEquals("mockMsg", new MockUpClass().getMsg()); + assertEquals("mockText", new MockUpClass().getText()); + } + } + + public static class MockUpClass { + public static class Save { + public static String msg = "msg"; + public static String text = "text"; + } + + public final String getMsg() { + changeMsg(); + return Save.msg; + } + + public void changeMsg() { + Save.msg = "newMsg"; + } + + public String getText() { + changeText("newText"); + return Save.text; + } + + public static void changeText(String text) { + Save.text = text; + } + } + } + """)); + } + + @Test + void mockUpAtSetUpWithoutTearDownTest() { + rewriteRun( + //language=java + java( + """ + import org.junit.Before; + import org.junit.Test; + import mockit.Mock; + import mockit.MockUp; + import static org.junit.Assert.assertEquals; + + public class MockUpTest { + @Before + public void setUp() { + new MockUp() { + @Mock + public String getMsg() { + return "mockMsg"; + } + }; + } + + @Test + public void test() { + assertEquals("mockMsg", new MyClazz().getMsg()); + } + + public static class MyClazz { + public String getMsg() { + return "msg"; + } + } + } + """, + """ + import org.junit.After; + import org.junit.Before; + import org.junit.Test; + import org.mockito.MockedConstruction; + import static org.junit.Assert.assertEquals; + import static org.mockito.AdditionalAnswers.delegatesTo; + import static org.mockito.Answers.CALLS_REAL_METHODS; + import static org.mockito.Mockito.*; + + public class MockUpTest { + private MockedConstruction mockConsMyClazz; + + @Before + public void setUp() { + MyClazz mockMyClazz = mock(MyClazz.class, CALLS_REAL_METHODS); + doAnswer(invocation -> "mockMsg").when(mockMyClazz).getMsg(); + mockConsMyClazz = mockConstructionWithAnswer(MyClazz.class, delegatesTo(mockMyClazz)); + } + + @After + public void tearDown() { + mockConsMyClazz.closeOnDemand(); + } + + @Test + public void test() { + assertEquals("mockMsg", new MyClazz().getMsg()); + } + + public static class MyClazz { + public String getMsg() { + return "msg"; + } + } + } + """ + ) + ); + } + + @Test + void mockUpAtSetUpWithTearDownTest() { + rewriteRun( + //language=java + java( + """ + import org.junit.Before; + import org.junit.After; + import org.junit.Test; + import mockit.Mock; + import mockit.MockUp; + import static org.junit.Assert.assertEquals; + + public class MockUpTest { + @Before + public void setUp() { + new MockUp() { + @Mock + public String getMsg() { + return "mockMsg"; + } + + @Mock + public String getStaticMsg() { + return "mockStaticMsg"; + } + }; + } + + @After + public void tearDown() { + } + + @Test + public void test() { + assertEquals("mockMsg", new MyClazz().getMsg()); + assertEquals("mockStaticMsg", MyClazz.getStaticMsg()); + } + + public static class MyClazz { + public String getMsg() { + return "msg"; + } + + public static String getStaticMsg() { + return "staticMsg"; + } + } + } + """, + """ + import org.junit.Before; + import org.junit.After; + import org.junit.Test; + import org.mockito.MockedConstruction; + import org.mockito.MockedStatic; + import static org.junit.Assert.assertEquals; + import static org.mockito.AdditionalAnswers.delegatesTo; + import static org.mockito.Answers.CALLS_REAL_METHODS; + import static org.mockito.Mockito.*; + + public class MockUpTest { + private MockedConstruction mockConsMyClazz; + private MockedStatic mockStaticMyClazz; + + @Before + public void setUp() { + MyClazz mockMyClazz = mock(MyClazz.class, CALLS_REAL_METHODS); + doAnswer(invocation -> "mockMsg").when(mockMyClazz).getMsg(); + mockConsMyClazz = mockConstructionWithAnswer(MyClazz.class, delegatesTo(mockMyClazz)); + mockStaticMyClazz = mockStatic(MyClazz.class); + mockStaticMyClazz.when(() -> MyClazz.getStaticMsg()).thenAnswer(invocation -> "mockStaticMsg"); + } + + @After + public void tearDown() { + mockConsMyClazz.closeOnDemand(); + mockStaticMyClazz.closeOnDemand(); + } + + @Test + public void test() { + assertEquals("mockMsg", new MyClazz().getMsg()); + assertEquals("mockStaticMsg", MyClazz.getStaticMsg()); + } + + public static class MyClazz { + public String getMsg() { + return "msg"; + } + + public static String getStaticMsg() { + return "staticMsg"; + } + } + } + """ + ) + ); + } + + @Test + void mockUpWithParamsTest() { + rewriteRun( + //language=java + java( + """ + import mockit.Mock; + import mockit.MockUp; + import org.junit.Test; + + import static org.junit.Assert.assertEquals; + + public class MockUpTest { + @Test + public void init() { + new MockUp() { + @Mock + public String getMsg(String foo, String bar, String unused) { + return foo + bar; + } + }; + assertEquals("foobar", new MyClazz().getMsg("foo", "bar", "unused")); + } + + public static class MyClazz { + public String getMsg(String foo, String bar, String unused) { + return "msg"; + } + } + } + """, + """ + import org.junit.Test; + import org.mockito.MockedConstruction; + + import static org.junit.Assert.assertEquals; + import static org.mockito.AdditionalAnswers.delegatesTo; + import static org.mockito.Answers.CALLS_REAL_METHODS; + import static org.mockito.ArgumentMatchers.*; + import static org.mockito.Mockito.*; + + public class MockUpTest { + @Test + public void init() { + MyClazz mockMyClazz = mock(MyClazz.class, CALLS_REAL_METHODS); + doAnswer(invocation -> { + String foo = invocation.getArgument(0); + String bar = invocation.getArgument(1); + return foo + bar; + }).when(mockMyClazz).getMsg(nullable(String.class), nullable(String.class), nullable(String.class)); + try (MockedConstruction mockConsMyClazz = mockConstructionWithAnswer(MyClazz.class, delegatesTo(mockMyClazz))) { + assertEquals("foobar", new MyClazz().getMsg("foo", "bar", "unused")); + } + } + + public static class MyClazz { + public String getMsg(String foo, String bar, String unused) { + return "msg"; + } + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitNonStrictExpectationsToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitNonStrictExpectationsToMockitoTest.java index bc186bb48..463746a26 100644 --- a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitNonStrictExpectationsToMockitoTest.java +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitNonStrictExpectationsToMockitoTest.java @@ -21,12 +21,9 @@ import org.openrewrite.test.RewriteTest; import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.MOCKITO_CORE_DEPENDENCY; -import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.setParserSettings; +import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.*; class JMockitNonStrictExpectationsToMockitoTest implements RewriteTest { - - private static final String JUNIT_4_DEPENDENCY = "junit-4.13.2"; private static final String LEGACY_JMOCKIT_DEPENDENCY = "jmockit-1.22"; @Override @@ -53,14 +50,14 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -74,16 +71,16 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeField()).thenReturn(null); assertNull(myObject.getSomeField()); @@ -113,14 +110,14 @@ public int getSomeField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -139,16 +136,16 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeField()).thenReturn(10); assertEquals(10, myObject.getSomeField()); @@ -180,14 +177,14 @@ public String getSomeField(String s) { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField(anyString); @@ -201,15 +198,15 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeField(anyString())).thenReturn("foo"); assertEquals("foo", myObject.getSomeField("bar")); @@ -239,16 +236,16 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + String expected = "expected"; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -262,18 +259,18 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + String expected = "expected"; - + void test() { lenient().when(myObject.getSomeField()).thenReturn(expected); assertEquals(expected, myObject.getSomeField()); @@ -303,14 +300,14 @@ public Object getSomeField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertNotNull; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -324,16 +321,16 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeField()).thenReturn(new Object()); assertNotNull(myObject.getSomeField()); @@ -363,12 +360,12 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() throws RuntimeException { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -382,15 +379,15 @@ void test() throws RuntimeException { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() throws RuntimeException { lenient().when(myObject.getSomeField()).thenThrow(new RuntimeException()); myObject.getSomeField(); @@ -420,14 +417,14 @@ public String getSomeField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() throws RuntimeException { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -442,16 +439,16 @@ void test() throws RuntimeException { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() throws RuntimeException { lenient().when(myObject.getSomeField()).thenReturn("foo", "bar"); assertEquals("foo", myObject.getSomeField()); @@ -470,7 +467,7 @@ void whenClassArgumentMatcher() { java( """ import java.util.List; - + class MyObject { public String getSomeField(List input) { return "X"; @@ -485,19 +482,19 @@ public String getSomeOtherField(Object input) { """ import java.util.ArrayList; import java.util.List; - + import mockit.NonStrictExpectations; import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField((List) any); @@ -513,19 +510,19 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertNull; import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeField(anyList())).thenReturn(null); lenient().when(myObject.getSomeOtherField(any(Object.class))).thenReturn(null); @@ -545,7 +542,7 @@ void whenNoArguments() { java( """ import java.util.List; - + class MyObject { public String getSomeField() { return "X"; @@ -557,19 +554,19 @@ public String getSomeField() { """ import java.util.ArrayList; import java.util.List; - + import mockit.NonStrictExpectations; import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeField(); @@ -582,20 +579,20 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeField()).thenReturn(null); assertNull(myObject.getSomeField()); @@ -614,7 +611,7 @@ void whenMixedArgumentMatcher() { java( """ import java.util.List; - + class MyObject { public String getSomeField(String s, String s2, String s3, long l1) { return "X"; @@ -626,19 +623,19 @@ public String getSomeField(String s, String s2, String s3, long l1) { """ import java.util.ArrayList; import java.util.List; - + import mockit.NonStrictExpectations; import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { String bazz = "bazz"; new NonStrictExpectations() {{ @@ -652,19 +649,19 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertNull; import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { String bazz = "bazz"; lenient().when(myObject.getSomeField(eq("foo"), anyString(), eq(bazz), eq(10L))).thenReturn(null); @@ -683,7 +680,7 @@ void whenSetupStatements() { java( """ class MyObject { - + public String getSomeField(String s) { return "X"; } @@ -699,26 +696,26 @@ public String getString() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { String a = "a"; String s = "s"; - + new NonStrictExpectations() {{ myObject.getSomeField(anyString); result = s; - + myObject.getString(); result = a; }}; - + assertEquals("s", myObject.getSomeField("foo")); assertEquals("a", myObject.getString()); } @@ -728,21 +725,21 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { String a = "a"; String s = "s"; lenient().when(myObject.getSomeField(anyString())).thenReturn(s); lenient().when(myObject.getString()).thenReturn(a); - + assertEquals("s", myObject.getSomeField("foo")); assertEquals("a", myObject.getString()); } @@ -771,14 +768,14 @@ public String getSomeField(String s) { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { String a = "a"; new NonStrictExpectations() {{ @@ -787,7 +784,7 @@ void test() { String b = "b"; result = s; }}; - + assertEquals("s", myObject.getSomeField("foo")); } } @@ -796,21 +793,21 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { String a = "a"; String s = "s"; String b = "b"; lenient().when(myObject.getSomeField(anyString())).thenReturn(s); - + assertEquals("s", myObject.getSomeField("foo")); } } @@ -838,14 +835,14 @@ public String getSomeField() { import mockit.Tested; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; - + @RunWith(JMockit.class) class MyTest { @Tested MyObject myObject; - + void test() { new NonStrictExpectations(myObject) {{ myObject.getSomeField(); @@ -859,16 +856,16 @@ void test() { import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @InjectMocks MyObject myObject; - + void test() { lenient().when(myObject.getSomeField()).thenReturn("foo"); assertEquals("foo", myObject.getSomeField()); @@ -905,18 +902,18 @@ public void doSomething() {} import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked Object myObject; - + @Mocked MyObject myOtherObject; - + void test() { new NonStrictExpectations() {{ myObject.hashCode(); @@ -938,19 +935,19 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock Object myObject; - + @Mock MyObject myOtherObject; - + void test() { lenient().when(myObject.hashCode()).thenReturn(10); lenient().when(myOtherObject.getSomeObjectField()).thenReturn(null); @@ -985,15 +982,15 @@ public String getSomeStringField() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked MyObject myObject; - + void test() { new NonStrictExpectations() {{ myObject.getSomeStringField(); @@ -1012,17 +1009,17 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock MyObject myObject; - + void test() { lenient().when(myObject.getSomeStringField()).thenReturn("a"); assertEquals("a", myObject.getSomeStringField()); @@ -1045,15 +1042,15 @@ void whenNoResultsNoTimes() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; - + @RunWith(JMockit.class) class MyTest { @Mocked Object myObject; - + void test() { new NonStrictExpectations() {{ myObject.wait(anyLong); @@ -1066,15 +1063,15 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(1L); } @@ -1094,12 +1091,12 @@ void whenTimes() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + @RunWith(JMockit.class) class MyTest { @Mocked Object myObject; - + void test() { new NonStrictExpectations() {{ myObject.wait(anyLong, anyInt); @@ -1115,14 +1112,14 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); myObject.wait(10L, 10); @@ -1145,12 +1142,12 @@ void whenTimesAndResult() { import mockit.Mocked; import mockit.integration.junit4.JMockit; import org.junit.runner.RunWith; - + @RunWith(JMockit.class) class MyTest { @Mocked Object myObject; - + void test() { new NonStrictExpectations() {{ myObject.toString(); @@ -1166,14 +1163,14 @@ void test() { import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; - + import static org.mockito.Mockito.*; - + @RunWith(MockitoJUnitRunner.class) class MyTest { @Mock Object myObject; - + void test() { when(myObject.toString()).thenReturn("foo"); myObject.toString(); diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitTestUtils.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitTestUtils.java index 0b21832ab..9c2ac5f31 100644 --- a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitTestUtils.java +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitTestUtils.java @@ -19,15 +19,18 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; +@SuppressWarnings("SpellCheckingInspection") public class JMockitTestUtils { static final String MOCKITO_CORE_DEPENDENCY = "mockito-core-3.12"; static final String JUNIT_5_JUPITER_DEPENDENCY = "junit-jupiter-api-5.9"; + static final String JUNIT_4_DEPENDENCY = "junit-4.13.2"; static final String JMOCKIT_DEPENDENCY = "jmockit-1.49"; static final String MOCKITO_JUPITER_DEPENDENCY = "mockito-junit-jupiter-3.12"; static void setDefaultParserSettings(RecipeSpec spec) { - setParserSettings(spec, JUNIT_5_JUPITER_DEPENDENCY, + setParserSettings(spec, + JUNIT_5_JUPITER_DEPENDENCY, JMOCKIT_DEPENDENCY, MOCKITO_CORE_DEPENDENCY, MOCKITO_JUPITER_DEPENDENCY); diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsInOrderToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsInOrderToMockitoTest.java new file mode 100644 index 000000000..02809435e --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsInOrderToMockitoTest.java @@ -0,0 +1,293 @@ +/* + * Copyright 2023 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.jmockit; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.TypeValidation; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.setDefaultParserSettings; + +/** + * Not doing full testing of VerificationsInOrder as it is covered in JMockitVerificationsToMockitoTest + */ +class JMockitVerificationsInOrderToMockitoTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + setDefaultParserSettings(spec); + } + + @DocumentExample + @Test + void whenMultipleMocks() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + import mockit.VerificationsInOrder; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object obj; + + @Mocked + String str; + + void test() { + obj.wait(10L, 10); + str.notify(); + new VerificationsInOrder() {{ + obj.wait(anyLong, anyInt); + str.notify(); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.InOrder; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object obj; + + @Mock + String str; + + void test() { + obj.wait(10L, 10); + str.notify(); + InOrder inOrder = inOrder(obj, str); + inOrder.verify(obj).wait(anyLong(), anyInt()); + inOrder.verify(str).notify(); + } + } + """ + ) + ); + } + + @Test + void whenTimes() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + import mockit.VerificationsInOrder; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object obj; + + void test() { + obj.wait(10L, 10); + obj.wait(10L, 10); + obj.wait(); + new VerificationsInOrder() {{ + obj.wait(anyLong, anyInt); + times = 2; + obj.wait(); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.InOrder; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object obj; + + void test() { + obj.wait(10L, 10); + obj.wait(10L, 10); + obj.wait(); + InOrder inOrder = inOrder(obj); + inOrder.verify(obj, times(2)).wait(anyLong(), anyInt()); + inOrder.verify(obj).wait(); + } + } + """ + ) + ); + } + + @Test + void whenThreeBlocks() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + import mockit.VerificationsInOrder; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object obj; + + void test() { + obj.wait(10L, 10); + obj.wait(); + new VerificationsInOrder() {{ + obj.wait(anyLong, anyInt); + obj.wait(); + }}; + + obj.wait(); + new VerificationsInOrder() {{ + obj.wait(); + }}; + + obj.wait(10L, 10); + new VerificationsInOrder() {{ + obj.wait(anyLong, anyInt); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.InOrder; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object obj; + + void test() { + obj.wait(10L, 10); + obj.wait(); + InOrder inOrder = inOrder(obj); + inOrder.verify(obj).wait(anyLong(), anyInt()); + inOrder.verify(obj).wait(); + + obj.wait(); + + InOrder inOrder1 = inOrder(obj); + + inOrder1.verify(obj).wait(); + + obj.wait(10L, 10); + + InOrder inOrder2 = inOrder(obj); + + inOrder2.verify(obj).wait(anyLong(), anyInt()); + } + } + """ + ) + ); + } + + @Test + void whenTwoBlocks() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + import mockit.VerificationsInOrder; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object obj; + + void test() { + obj.wait(10L, 10); + obj.wait(); + new VerificationsInOrder() {{ + obj.wait(anyLong, anyInt); + obj.wait(); + }}; + + obj.wait(); + obj.notify(); + new VerificationsInOrder() {{ + obj.wait(); + obj.notify(); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.InOrder; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object obj; + + void test() { + obj.wait(10L, 10); + obj.wait(); + InOrder inOrder = inOrder(obj); + inOrder.verify(obj).wait(anyLong(), anyInt()); + inOrder.verify(obj).wait(); + + obj.wait(); + obj.notify(); + InOrder inOrder1 = inOrder(obj); + inOrder1.verify(obj).wait(); + inOrder1.verify(obj).notify(); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsToMockitoTest.java index 58f30cdd5..47125c88f 100644 --- a/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsToMockitoTest.java +++ b/src/test/java/org/openrewrite/java/testing/jmockit/JMockitVerificationsToMockitoTest.java @@ -24,7 +24,9 @@ import static org.openrewrite.java.Assertions.java; import static org.openrewrite.java.testing.jmockit.JMockitTestUtils.setDefaultParserSettings; +@SuppressWarnings({"SpellCheckingInspection", "ResultOfMethodCallIgnored"}) class JMockitVerificationsToMockitoTest implements RewriteTest { + @Override public void defaults(RecipeSpec spec) { setDefaultParserSettings(spec); @@ -41,12 +43,12 @@ void whenNoTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); new Verifications() {{ @@ -59,14 +61,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject).wait(anyLong(), anyInt()); @@ -88,12 +90,12 @@ void whenNoTimesNoArgs() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); new Verifications() {{ @@ -106,14 +108,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject).wait(); @@ -133,17 +135,17 @@ void whenTimesNoArgs() { """ import java.util.ArrayList; import java.util.List; - + import mockit.Verifications; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(); myObject.wait(); @@ -157,18 +159,18 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(); myObject.wait(); @@ -188,7 +190,7 @@ void whenClassArgumentMatcher() { java( """ import java.util.List; - + class MyObject { public String getSomeField(List input) { return "X"; @@ -203,17 +205,17 @@ public String getSomeOtherField(Object input) { """ import java.util.ArrayList; import java.util.List; - + import mockit.Mocked; import mockit.Verifications; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked MyObject myObject; - + void test() { myObject.getSomeField(new ArrayList<>()); myObject.getSomeOtherField(new Object()); @@ -227,18 +229,18 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import static org.mockito.Mockito.*; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock MyObject myObject; - + void test() { myObject.getSomeField(new ArrayList<>()); myObject.getSomeOtherField(new Object()); @@ -260,17 +262,17 @@ void whenMixedArgumentMatcher() { """ import java.util.ArrayList; import java.util.List; - + import mockit.Verifications; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); new Verifications() {{ @@ -282,18 +284,18 @@ void test() { """ import java.util.ArrayList; import java.util.List; - + import static org.mockito.Mockito.*; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject).wait(anyLong(), eq(10)); @@ -314,12 +316,12 @@ void whenSetupStatements() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { String a = "a"; String s = "s"; @@ -336,15 +338,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { String a = "a"; String s = "s"; @@ -369,12 +371,12 @@ void whenSetupStatements2() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { String a = "a"; myObject.wait(1L); @@ -388,15 +390,15 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { String a = "a"; myObject.wait(1L); @@ -418,12 +420,12 @@ void whenTimes() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); myObject.wait(10L, 10); @@ -439,14 +441,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); myObject.wait(10L, 10); @@ -464,17 +466,17 @@ void whenMinTimes() { //language=java rewriteRun( java( - """ + """ import mockit.Verifications; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); new Verifications() {{ @@ -484,18 +486,18 @@ void test() { } } """, - """ + """ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject, atLeast(2)).wait(anyLong(), anyInt()); @@ -511,17 +513,17 @@ void whenMaxTimes() { //language=java rewriteRun( java( - """ + """ import mockit.Verifications; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); new Verifications() {{ @@ -531,18 +533,18 @@ void test() { } } """, - """ + """ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject, atMost(5)).wait(anyLong(), anyInt()); @@ -558,17 +560,17 @@ void whenMinTimesMaxTimes() { //language=java rewriteRun( java( - """ + """ import mockit.Verifications; import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(10L, 10); new Verifications() {{ @@ -579,18 +581,18 @@ void test() { } } """, - """ + """ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(10L, 10); verify(myObject, atLeast(1)).wait(anyLong(), anyInt()); @@ -612,15 +614,15 @@ void whenMultipleStatements() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + @Mocked Object myOtherObject; - + void test() { myObject.hashCode(); myOtherObject.wait(); @@ -639,17 +641,17 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + @Mock Object myOtherObject; - + void test() { myObject.hashCode(); myOtherObject.wait(); @@ -676,18 +678,16 @@ void whenMultipleVerificationsAndMultipleStatements() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { myObject.wait(); new Verifications() {{ - myObject.wait(); - myObject.wait(anyLong, anyInt); }}; myObject.wait(1L); @@ -703,14 +703,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { myObject.wait(); verify(myObject).wait(); @@ -735,12 +735,12 @@ void whenMultipleBlockInSingleVerification() { import mockit.Mocked; import mockit.integration.junit5.JMockitExtension; import org.junit.jupiter.api.extension.ExtendWith; - + @ExtendWith(JMockitExtension.class) class MyTest { @Mocked Object myObject; - + void test() { new Verifications() { { @@ -759,14 +759,14 @@ void test() { import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import static org.mockito.Mockito.*; - + @ExtendWith(MockitoExtension.class) class MyTest { @Mock Object myObject; - + void test() { verify(myObject).wait(); verify(myObject).wait(anyLong(), anyInt()); @@ -777,4 +777,170 @@ void test() { ) ); } + + @Test + void whenUnsupportedType() { + //language=java + rewriteRun( + java( + """ + import mockit.Delegate; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + myObject.wait(1L); + new Delegate() {{ + myObject.wait(); + }}; + } + } + """, + """ + import mockit.Delegate; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + myObject.wait(1L); + new Delegate() {{ + myObject.wait(); + }}; + } + } + """ + ) + ); + } + + @Test + void whenWithRedundantThisModifier() { + //language=java + rewriteRun( + java( + """ + import mockit.Verifications; + import mockit.Mocked; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + Object myObject; + + void test() { + new Verifications() {{ + myObject.wait(this.anyLong, this.anyInt); + myObject.wait(anyLong, this.anyInt); + }}; + } + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.*; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + Object myObject; + + void test() { + verify(myObject).wait(anyLong(), anyInt()); + verify(myObject).wait(anyLong(), anyInt()); + } + } + """ + ) + ); + } + + @Test + void whenArrayArgumentMatcher() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().methodInvocations(false).build()), + java( + """ + import java.util.List; + + class MyObject { + public String getSomeObject(Object input) { + return "Z"; + } + } + """ + ), + java( + """ + import java.util.ArrayList; + import java.util.List; + + import mockit.Mocked; + import mockit.Verifications; + import mockit.integration.junit5.JMockitExtension; + import org.junit.jupiter.api.extension.ExtendWith; + + @ExtendWith(JMockitExtension.class) + class MyTest { + @Mocked + MyObject myObject; + + void test() { + myObject.getSomeObject(new byte[0]); + myObject.getSomeObject(new int[0]); + myObject.getSomeObject(new Exception[0]); + new Verifications() {{ + myObject.getSomeObject((byte[]) any); + myObject.getSomeObject((int[]) any); + myObject.getSomeObject((Exception[]) any); + }}; + } + } + """, + """ + import java.util.ArrayList; + import java.util.List; + + import static org.mockito.Mockito.any; + import static org.mockito.Mockito.verify; + + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @Mock + MyObject myObject; + + void test() { + myObject.getSomeObject(new byte[0]); + myObject.getSomeObject(new int[0]); + myObject.getSomeObject(new Exception[0]); + verify(myObject).getSomeObject(any(byte[].class)); + verify(myObject).getSomeObject(any(int[].class)); + verify(myObject).getSomeObject(any(Exception[].class)); + } + } + """ + ) + ); + } } diff --git a/src/test/java/org/openrewrite/java/testing/junit5/AddMissingNestedTest.java b/src/test/java/org/openrewrite/java/testing/junit5/AddMissingNestedTest.java index c8b063887..9aa37dbc8 100644 --- a/src/test/java/org/openrewrite/java/testing/junit5/AddMissingNestedTest.java +++ b/src/test/java/org/openrewrite/java/testing/junit5/AddMissingNestedTest.java @@ -43,23 +43,25 @@ void oneInnerClass() { java( """ import org.junit.jupiter.api.Test; - + public class RootTest { public class InnerTest { @Test - public void test() {} + public void test() { + } } } """, """ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; - + public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } } """ @@ -74,20 +76,23 @@ void multipleInnerClasses() { java( """ import org.junit.jupiter.api.Test; - + public class RootTest { public class InnerTest { @Test - public void test() {} + public void test() { + } } - + public class Inner2Test { @Test - public void test() {} - + public void test() { + } + public class InnermostTest { @Test - public void test() {} + public void test() { + } } } } @@ -100,18 +105,21 @@ public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } @Nested public class Inner2Test { @Test - public void test() {} + public void test() { + } @Nested public class InnermostTest { @Test - public void test() {} + public void test() { + } } } } @@ -131,11 +139,13 @@ void doesNotAnnotationNonTestInnerClass() { public class RootTest { public class InnerTest { @Test - public void test() {} + public void test() { + } } - + public static class Foo { - public void bar() {} + public void bar() { + } } } """, @@ -147,11 +157,13 @@ public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } - + public static class Foo { - public void bar() {} + public void bar() { + } } } """ @@ -170,7 +182,8 @@ void removesStatic() { public class RootTest { public static class InnerTest { @Test - public void test() {} + public void test() { + } } } """, @@ -182,7 +195,8 @@ public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } } """ diff --git a/src/test/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatementTest.java b/src/test/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatementTest.java index ad8cb779c..f91702b27 100644 --- a/src/test/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatementTest.java +++ b/src/test/java/org/openrewrite/java/testing/junit5/AssertThrowsOnLastStatementTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Issue; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -252,4 +253,31 @@ void foo() { ) ); } + + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/618") + void bodyNull() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.*; + + class MyTest { + + @Test + void test() { + assertThrows(IllegalStateException.class, () -> System.out.println("foo")); + } + + interface InnerInterface { + String createParser(String input); + } + } + """ + ) + ); + } } diff --git a/src/test/java/org/openrewrite/java/testing/junit5/EnclosedToNestedTest.java b/src/test/java/org/openrewrite/java/testing/junit5/EnclosedToNestedTest.java index 7b70ccf0c..1d5cc7f96 100644 --- a/src/test/java/org/openrewrite/java/testing/junit5/EnclosedToNestedTest.java +++ b/src/test/java/org/openrewrite/java/testing/junit5/EnclosedToNestedTest.java @@ -31,7 +31,7 @@ public void defaults(RecipeSpec spec) { spec .parser(JavaParser.fromJavaVersion() .classpathFromResources(new InMemoryExecutionContext(), "junit-4.13")) - .recipe(new EnclosedToNested()); + .recipeFromResources("org.openrewrite.java.testing.junit5.JUnit4to5Migration"); } @DocumentExample @@ -49,21 +49,21 @@ void oneInnerClass() { public class RootTest { public static class InnerTest { @Test - public void test() {} + public void test() { + } } } """, """ - import org.junit.Test; import org.junit.jupiter.api.Nested; + import org.junit.jupiter.api.Test; - \s - \s public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } } """ @@ -85,42 +85,46 @@ void multipleInnerClasses() { public class RootTest { public static class InnerTest { @Test - public void test() {} + public void test() { + } } - + public static class Inner2Test { @Test - public void test() {} + public void test() { + } public static class InnermostTest { @Test - public void test() {} + public void test() { + } } } } """, """ - import org.junit.Test; import org.junit.jupiter.api.Nested; + import org.junit.jupiter.api.Test; - \s - \s public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } @Nested public class Inner2Test { @Test - public void test() {} + public void test() { + } @Nested public class InnermostTest { @Test - public void test() {} + public void test() { + } } } } @@ -143,21 +147,25 @@ void recognizesTestAnnotationWithArguments() { public class RootTest { public static class InnerTest { @Test(timeout = 10) - public void test() {} + public void test() { + } } } """, """ - import org.junit.Test; import org.junit.jupiter.api.Nested; + import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.Timeout; - + import java.util.concurrent.TimeUnit; public class RootTest { @Nested public class InnerTest { - @Test(timeout = 10) - public void test() {} + @Test + @Timeout(value = 10, unit = TimeUnit.MILLISECONDS) + public void test() { + } } } """ @@ -179,29 +187,31 @@ void doesNotAnnotateNonTestInnerClasses() { public class RootTest { public static class InnerTest { @Test - public void test() {} + public void test() { + } } - + public static class Foo { - public void bar() {} + public void bar() { + } } } """, """ - import org.junit.Test; import org.junit.jupiter.api.Nested; - - + import org.junit.jupiter.api.Test; public class RootTest { @Nested public class InnerTest { @Test - public void test() {} + public void test() { + } } - + public static class Foo { - public void bar() {} + public void bar() { + } } } """ diff --git a/src/test/java/org/openrewrite/java/testing/junit5/JUnit5BestPracticesTest.java b/src/test/java/org/openrewrite/java/testing/junit5/JUnit5BestPracticesTest.java index 3d1dccc53..412e39e39 100644 --- a/src/test/java/org/openrewrite/java/testing/junit5/JUnit5BestPracticesTest.java +++ b/src/test/java/org/openrewrite/java/testing/junit5/JUnit5BestPracticesTest.java @@ -189,7 +189,7 @@ void somethingElse() { ) ); } - + @Test void changeThrowingRunnableToExecutable() { //language=java diff --git a/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java b/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java index 17478e64c..71752bbb3 100644 --- a/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java +++ b/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java @@ -55,7 +55,7 @@ void classReference() { java( """ import org.junit.Test; - + public class Sample { void method() { Class c = Test.class; @@ -64,7 +64,7 @@ void method() { """, """ import org.junit.jupiter.api.Test; - + public class Sample { void method() { Class c = Test.class; @@ -85,10 +85,10 @@ void assertThatReceiver() { """ import org.junit.Assert; import org.junit.Test; - + import static java.util.Arrays.asList; import static org.hamcrest.Matchers.containsInAnyOrder; - + public class SampleTest { @SuppressWarnings("ALL") @Test @@ -100,11 +100,11 @@ public void filterShouldRemoveUnusedConfig() { """, """ import org.junit.jupiter.api.Test; - + import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; - + public class SampleTest { @SuppressWarnings("ALL") @Test @@ -178,6 +178,30 @@ void dontExcludeJunit4DependencyfromTestcontainers() { rewriteRun(pomXml(before, before)); } + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/429") + void dontExcludeJunit4DependencyfromTestcontainersJupiter() { + //language=xml + String before = """ + + 4.0.0 + com.example.jackson + test-plugins + 1.0.0 + + + org.testcontainers + junit-jupiter + 1.18.3 + test + + + + """; + // Output identical, but we want to make sure we don't exclude junit4 from testcontainers + rewriteRun(pomXml(before, before)); + } + @Test @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/477") void dontExcludeJunit4DependencyfromSpringBootTestcontainers() { @@ -231,7 +255,7 @@ void assertEqualsWithArrayArgumentToAssertArrayEquals() { java( """ import org.junit.Assert; - + class MyTest { void test() { Assert.assertEquals(new Object[1], new Object[1]); @@ -240,7 +264,7 @@ void test() { """, """ import org.junit.jupiter.api.Assertions; - + class MyTest { void test() { Assertions.assertArrayEquals(new Object[1], new Object[1]); @@ -261,16 +285,16 @@ void migrateInheritedTestBeforeAfterAnnotations() { import org.junit.After; import org.junit.Before; import org.junit.Test; - + public class AbstractTest { @Before public void before() { } - + @After public void after() { } - + @Test public void test() { } @@ -280,16 +304,16 @@ public void test() { import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - + public class AbstractTest { @BeforeEach public void before() { } - + @AfterEach public void after() { } - + @Test public void test() { } @@ -301,10 +325,10 @@ public void test() { public class A extends AbstractTest { public void before() { } - + public void after() { } - + public void test() { } } @@ -313,16 +337,16 @@ public void test() { import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - + public class A extends AbstractTest { @BeforeEach public void before() { } - + @AfterEach public void after() { } - + @Test public void test() { } diff --git a/src/test/java/org/openrewrite/java/testing/junit5/UseAssertSameTest.java b/src/test/java/org/openrewrite/java/testing/junit5/UseAssertSameTest.java new file mode 100644 index 000000000..d68d05f27 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/junit5/UseAssertSameTest.java @@ -0,0 +1,192 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.junit5; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class UseAssertSameTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9")) + .recipe(new UseAssertSame()); + } + + @DocumentExample + @Test + void assertSameForSimpleBooleanComparison() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = number; + assertTrue(number == otherNumber); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertSame; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = number; + assertSame(number, otherNumber); + } + } + """ + ) + ); + } + + @Test + void usingStringMessage() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = number; + assertTrue(number == otherNumber, "Something is not right"); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertSame; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = number; + assertSame(number, otherNumber, "Something is not right"); + } + } + """ + ) + ); + } + + @Test + void assertFalse() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertFalse; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = "thirty-seven"; + assertFalse(number == otherNumber); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertNotSame; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = "thirty-seven"; + assertNotSame(number, otherNumber); + } + } + """ + ) + ); + } + + @Test + void notEqual() { + //language=java + rewriteRun( + java( + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertTrue; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = "thirty-seven"; + assertTrue(number != otherNumber); + } + } + """, + """ + import org.junit.jupiter.api.Test; + + import static org.junit.jupiter.api.Assertions.assertNotSame; + + class MyTest { + + @Test + public void test() { + String number = "thirty-six"; + String otherNumber = "thirty-seven"; + assertNotSame(number, otherNumber); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/mockito/MockitoJUnitToMockitoExtensionTest.java b/src/test/java/org/openrewrite/java/testing/mockito/MockitoJUnitToMockitoExtensionTest.java index 0b8d71722..03f3017f2 100644 --- a/src/test/java/org/openrewrite/java/testing/mockito/MockitoJUnitToMockitoExtensionTest.java +++ b/src/test/java/org/openrewrite/java/testing/mockito/MockitoJUnitToMockitoExtensionTest.java @@ -48,12 +48,12 @@ void leavesOtherRulesAlone() { import org.mockito.Mock; import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoJUnit; - + class MyTest { - + @Rule TemporaryFolder tempDir = new TemporaryFolder(); - + @Rule MockitoRule mockitoRule = MockitoJUnit.rule(); } @@ -64,10 +64,13 @@ class MyTest { import org.junit.rules.TemporaryFolder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.WARN) class MyTest { - + @Rule TemporaryFolder tempDir = new TemporaryFolder(); } @@ -89,10 +92,10 @@ void leavesOtherAnnotationsAlone() { import org.mockito.Mock; import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoJUnit; - + @FixMethodOrder(MethodSorters.NAME_ASCENDING) class MyTest { - + @Rule MockitoRule mockitoRule = MockitoJUnit.rule(); } @@ -103,9 +106,12 @@ class MyTest { import org.junit.runners.MethodSorters; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + @ExtendWith(MockitoExtension.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) + @MockitoSettings(strictness = Strictness.WARN) class MyTest { } """ @@ -121,21 +127,21 @@ void refactorMockitoRule() { java( """ import java.util.List; - + import org.junit.Rule; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.mockito.quality.Strictness; - + class MyTest { - + @Rule MockitoRule mockitoRule = MockitoJUnit.rule(); - + @Mock private List list; - + public void exampleTest() { mockitoRule.strictness(Strictness.LENIENT); list.add(100); @@ -144,17 +150,20 @@ public void exampleTest() { """, """ import java.util.List; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.LENIENT) class MyTest { - + @Mock private List list; - + public void exampleTest() { list.add(100); } @@ -172,21 +181,21 @@ void refactorMockitoTestRule() { java( """ import java.util.List; - + import org.junit.Rule; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoTestRule; import org.mockito.quality.Strictness; - + class MyTest { - + @Rule MockitoTestRule mockitoTestRule = MockitoJUnit.rule(); - + @Mock private List list; - + public void exampleTest() { mockitoTestRule.strictness(Strictness.LENIENT); list.add(100); @@ -195,17 +204,20 @@ public void exampleTest() { """, """ import java.util.List; - + import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.LENIENT) class MyTest { - + @Mock private List list; - + public void exampleTest() { list.add(100); } @@ -229,22 +241,22 @@ void onlyRefactorMockitoRule() { import org.mockito.junit.MockitoTestRule; import org.mockito.junit.VerificationCollector; import org.mockito.quality.Strictness; - + import java.util.List; - + import static org.mockito.Mockito.verify; - + class MyTest { - + @Rule VerificationCollector verificationCollectorRule = MockitoJUnit.collector(); - + @Rule MockitoTestRule mockitoTestRule = MockitoJUnit.rule(); - + @Mock private List list; - + @Test public void exampleTest() { verify(list).add(100); @@ -260,20 +272,23 @@ public void exampleTest() { import org.mockito.junit.MockitoJUnit; import org.mockito.junit.VerificationCollector; import org.mockito.junit.jupiter.MockitoExtension; - + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + import java.util.List; - + import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.WARN) class MyTest { - + @Rule VerificationCollector verificationCollectorRule = MockitoJUnit.collector(); - + @Mock private List list; - + @Test public void exampleTest() { verify(list).add(100); @@ -293,20 +308,20 @@ void unchangedMockitoCollectorRule() { java( """ import java.util.List; - + import org.junit.Rule; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.VerificationCollector; - + class MyTest { - + @Rule VerificationCollector verificationCollectorRule = MockitoJUnit.collector(); - + @Mock private List list; - + public void exampleTest() { list.add(100); verificationCollectorRule.collectAndReport(); @@ -325,25 +340,25 @@ void unchangedMockitoCollectorDeclaredInMethod() { java( """ import java.util.List; - + import org.mockito.Mock; import org.mockito.exceptions.base.MockitoAssertionError; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.VerificationCollector; - + import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; - + class MyTest { - + public void unsupported() { VerificationCollector collector = MockitoJUnit.collector().assertLazily(); - + List mockList = mock(List.class); verify(mockList).add("one"); verify(mockList).clear(); - + try { collector.collectAndReport(); } catch (MockitoAssertionError error) { @@ -374,20 +389,20 @@ void leaveMockitoJUnitRunnerAlone() { import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoTestRule; import org.mockito.runners.MockitoJUnitRunner; - + import java.util.List; - + import static org.mockito.Mockito.verify; - + @RunWith(MockitoJUnitRunner.class) class MyTest { - + @Rule MockitoTestRule mockitoTestRule = MockitoJUnit.rule(); - + @Mock private List list; - + @Test public void exampleTest() { verify(list).add(100); @@ -399,17 +414,17 @@ public void exampleTest() { import org.junit.Test; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; - + import java.util.List; - + import static org.mockito.Mockito.verify; - + @RunWith(MockitoJUnitRunner.class) class MyTest { - + @Mock private List list; - + @Test public void exampleTest() { verify(list).add(100); @@ -434,20 +449,20 @@ void leaveExtendWithAlone() { import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoTestRule; - + import java.util.List; - + import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { - + @Rule MockitoTestRule mockitoTestRule = MockitoJUnit.rule(); - + @Mock private List list; - + @Test public void exampleTest() { verify(list).add(100); @@ -459,17 +474,17 @@ public void exampleTest() { import org.junit.Test; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - + import java.util.List; - + import static org.mockito.Mockito.verify; - + @ExtendWith(MockitoExtension.class) class MyTest { - + @Mock private List list; - + @Test public void exampleTest() { verify(list).add(100); @@ -479,4 +494,315 @@ public void exampleTest() { ) ); } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/623") + @Test + void silentRuleAddMockitoSettings() { + //language=java + rewriteRun( + java( + """ + import org.junit.Rule; + import org.junit.Test; + import org.mockito.Mock; + import org.mockito.junit.MockitoJUnit; + import org.mockito.junit.MockitoRule; + + import java.util.List; + + import static org.mockito.Mockito.when; + + public class MyTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule().silent(); + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """, + """ + import org.junit.Test; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.LENIENT) + public class MyTest { + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/623") + @Test + void warnStrictnessRuleAddMockitoSettings() { + //language=java + rewriteRun( + java( + """ + import org.junit.Rule; + import org.junit.Test; + import org.mockito.Mock; + import org.mockito.junit.MockitoJUnit; + import org.mockito.junit.MockitoRule; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + public class MyTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.WARN); + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """, + """ + import org.junit.Test; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.WARN) + public class MyTest { + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/623") + @Test + void warnStrictnessRuleAddMockitoSettingsWithStaticImport() { + //language=java + rewriteRun( + java( + """ + import org.junit.Rule; + import org.junit.Test; + import org.mockito.Mock; + import org.mockito.junit.MockitoJUnit; + import org.mockito.junit.MockitoRule; + + import java.util.List; + + import static org.mockito.Mockito.when; + import static org.mockito.quality.Strictness.WARN; + + public class MyTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule().strictness(WARN); + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """, + """ + import org.junit.Test; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.WARN) + public class MyTest { + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/623") + @Test + void lenientStrictnessRuleAddMockitoSettings() { + //language=java + rewriteRun( + java( + """ + import org.junit.Rule; + import org.junit.Test; + import org.mockito.Mock; + import org.mockito.junit.MockitoJUnit; + import org.mockito.junit.MockitoRule; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + public class MyTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT); + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """, + """ + import org.junit.Test; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + import org.mockito.junit.jupiter.MockitoSettings; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.LENIENT) + public class MyTest { + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/623") + @Test + void strictRuleDoNotAddMockitoSettings() { + //language=java + rewriteRun( + java( + """ + import org.junit.Rule; + import org.junit.Test; + import org.mockito.Mock; + import org.mockito.junit.MockitoJUnit; + import org.mockito.junit.MockitoRule; + import org.mockito.quality.Strictness; + + import java.util.List; + + import static org.mockito.Mockito.when; + + public class MyTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """, + """ + import org.junit.Test; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + + import java.util.List; + + import static org.mockito.Mockito.when; + + @ExtendWith(MockitoExtension.class) + public class MyTest { + + @Mock + private List mockList; + + @Test + public void testing() { + when(mockList.add("one")).thenReturn(true); // this won't get called + System.out.println("Hello world!"); + } + } + """ + ) + ); + } } diff --git a/src/test/java/org/openrewrite/java/testing/mockito/MockitoWhenOnStaticToMockStaticTest.java b/src/test/java/org/openrewrite/java/testing/mockito/MockitoWhenOnStaticToMockStaticTest.java new file mode 100644 index 000000000..a7eb4b724 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/mockito/MockitoWhenOnStaticToMockStaticTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.SourceSpec; +import org.openrewrite.test.TypeValidation; + +import static org.openrewrite.java.Assertions.java; + +class MockitoWhenOnStaticToMockStaticTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new MockitoWhenOnStaticToMockStatic()) + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), + "junit-4.13", + "mockito-core-3.12", + "mockito-junit-jupiter-3.12" + )); + } + + @DocumentExample + @Test + void shouldRefactorMockito_When() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + package com.foo; + public class A { + public static Integer getNumber() { + return 42; + } + } + """, + SourceSpec::skip + ), + java( + """ + import com.foo.A; + + import static org.junit.Assert.assertEquals; + import static org.mockito.Mockito.*; + + class Test { + void test() { + when(A.getNumber()).thenReturn(-1); + assertEquals(A.getNumber(), -1); + } + } + """, + """ + import com.foo.A; + import org.mockito.MockedStatic; + + import static org.junit.Assert.assertEquals; + import static org.mockito.Mockito.*; + + class Test { + void test() { + try (MockedStatic mockA = mockStatic(A.class)) { + mockA.when(A.getNumber()).thenReturn(-1); + assertEquals(A.getNumber(), -1); + } + } + } + """ + ) + ); + } + + @Test + void shouldHandleMultipleStaticMocks() { + //language=java + rewriteRun( + spec -> spec.afterTypeValidationOptions(TypeValidation.builder().identifiers(false).build()), + java( + """ + package com.foo; + public class A { + public static Integer getNumber() { + return 42; + } + } + """, + SourceSpec::skip + ), + java( + """ + import com.foo.A; + + import static org.junit.Assert.assertEquals; + import static org.mockito.Mockito.*; + + class Test { + void test() { + when(A.getNumber()).thenReturn(-1); + assertEquals(A.getNumber(), -1); + + when(A.getNumber()).thenReturn(-2); + assertEquals(A.getNumber(), -2); + } + } + """, + """ + import com.foo.A; + import org.mockito.MockedStatic; + + import static org.junit.Assert.assertEquals; + import static org.mockito.Mockito.*; + + class Test { + void test() { + try (MockedStatic mockA = mockStatic(A.class)) { + mockA.when(A.getNumber()).thenReturn(-1); + assertEquals(A.getNumber(), -1); + + try (MockedStatic mockA1 = mockStatic(A.class)) { + mockA1.when(A.getNumber()).thenReturn(-2); + assertEquals(A.getNumber(), -2); + } + } + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java b/src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java new file mode 100644 index 000000000..3ac327f2b --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class NoInitializationForInjectMockTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "mockito-core-3.12")) + .recipe(new NoInitializationForInjectMock()); + } + + @Test + @DocumentExample + void removeInitializationOfInjectMocks() { + //language=java + rewriteRun( + java( + """ + class MyObject { + private String someField; + + public MyObject(String someField) { + this.someField = someField; + } + } + """ + ), + java( + """ + import org.mockito.InjectMocks; + + class MyTest { + @InjectMocks + MyObject myObject = new MyObject("someField"); + } + """, + """ + import org.mockito.InjectMocks; + + class MyTest { + @InjectMocks + MyObject myObject; + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockitoTest.java b/src/test/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockitoTest.java index a9fa9a0cb..3a3225ad4 100644 --- a/src/test/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockitoTest.java +++ b/src/test/java/org/openrewrite/java/testing/mockito/PowerMockitoMockStaticToMockitoTest.java @@ -22,6 +22,7 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.TypeValidation; import static org.openrewrite.groovy.Assertions.groovy; import static org.openrewrite.java.Assertions.java; @@ -41,7 +42,8 @@ public void defaults(RecipeSpec spec) { "powermock-core-1.6", "testng-7.7" )) - .recipe(new PowerMockitoMockStaticToMockito()); + .recipe(new PowerMockitoMockStaticToMockito()) + .typeValidationOptions(TypeValidation.builder().cursorAcyclic(false).build()); } @DocumentExample @@ -681,6 +683,25 @@ public void testStaticMethod() { ); } + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/611") + void existingMockitoMockStaticShouldNotBeTouched() { + //language=java + rewriteRun( + java( + """ + import static org.mockito.Mockito.mockStatic; + + import org.mockito.MockedStatic; + + class TestClass { + MockedStatic mocked = mockStatic(String.class); + } + """ + ) + ); + } + @Test @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/358") void doesNotExplodeOnTopLevelMethodDeclaration() { diff --git a/src/test/java/org/openrewrite/java/testing/mockito/ReplacePowerMockitoIntegrationTest.java b/src/test/java/org/openrewrite/java/testing/mockito/ReplacePowerMockitoIntegrationTest.java index 746f91e97..73162b8c0 100644 --- a/src/test/java/org/openrewrite/java/testing/mockito/ReplacePowerMockitoIntegrationTest.java +++ b/src/test/java/org/openrewrite/java/testing/mockito/ReplacePowerMockitoIntegrationTest.java @@ -39,8 +39,9 @@ public void defaults(RecipeSpec spec) { "powermock-api-mockito-1.6", "powermock-api-support-1.6", "testng-7.7")) - // TODO Resolve the missing types in the replacement templates rather than ignore the errors here .typeValidationOptions(TypeValidation.builder() + .cursorAcyclic(false) + // TODO Resolve the missing types in the replacement templates rather than ignore the errors here .identifiers(false) .methodInvocations(false) .build()) diff --git a/src/test/java/org/openrewrite/java/testing/mockito/RetainStrictnessWarnTest.java b/src/test/java/org/openrewrite/java/testing/mockito/RetainStrictnessWarnTest.java deleted file mode 100644 index 1f9fbae59..000000000 --- a/src/test/java/org/openrewrite/java/testing/mockito/RetainStrictnessWarnTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - *

    - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * https://www.apache.org/licenses/LICENSE-2.0 - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.java.testing.mockito; - -import org.intellij.lang.annotations.Language; -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.maven.Assertions.pomXml; - -class RetainStrictnessWarnTest implements RewriteTest { - - @Language("xml") - private static final String POM_XML_WITH_OLDER_MOCKITO = """ - - 4.0.0 - bla.bla - bla-bla - 1.0.0 - - - org.mockito - mockito-all - 1.1 - test - - - - """; - - @Language("java") - private static final String JAVA_BEFORE = """ - import org.junit.jupiter.api.extension.ExtendWith; - import org.mockito.junit.jupiter.MockitoExtension; - - @ExtendWith(MockitoExtension.class) - class MyTest { - } - """; - - @Language("java") - private static final String JAVA_AFTER = """ - import org.mockito.junit.jupiter.MockitoSettings; - import org.mockito.quality.Strictness; - - @MockitoSettings(strictness = Strictness.WARN) - class MyTest { - } - """; - - @Override - public void defaults(RecipeSpec spec) { - spec - .parser(JavaParser.fromJavaVersion() - .classpathFromResources(new InMemoryExecutionContext(), - "mockito-core", "mockito-junit-jupiter", "junit-jupiter-api")) - .recipe(new RetainStrictnessWarn()); - } - - @Test - @DocumentExample - void shouldAddMockitoSettingsWithLenientStubbing() { - //language=java - rewriteRun( - pomXml(POM_XML_WITH_OLDER_MOCKITO), - java(JAVA_BEFORE, JAVA_AFTER) - ); - } - - @Test - void shouldLeaveExisting() { - //language=java - rewriteRun( - pomXml(POM_XML_WITH_OLDER_MOCKITO), - java( - """ - import org.mockito.junit.jupiter.MockitoSettings; - import org.mockito.quality.Strictness; - - @MockitoSettings(strictness = Strictness.STRICT_STUBS) - class MyTest { - } - """ - ) - ); - } - - @Test - void shouldRunBeforeMockitoCore2_17() { - rewriteRun( - pomXml(POM_XML_WITH_OLDER_MOCKITO), - java(JAVA_BEFORE, JAVA_AFTER) - ); - } - - @Test - void shouldNotRunOnNewerMockito() { - rewriteRun( - //language=xml - pomXml( - """ - - 4.0.0 - bla.bla - bla-bla - 1.0.0 - - - org.mockito - mockito-core - 2.17.0 - test - - - - """ - ), - java(JAVA_BEFORE) - ); - } -} diff --git a/src/test/java/org/openrewrite/java/testing/mockito/SimplifyMockitoVerifyWhenGivenTest.java b/src/test/java/org/openrewrite/java/testing/mockito/SimplifyMockitoVerifyWhenGivenTest.java new file mode 100644 index 000000000..baa688cdf --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/mockito/SimplifyMockitoVerifyWhenGivenTest.java @@ -0,0 +1,303 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Issue; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class SimplifyMockitoVerifyWhenGivenTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new SimplifyMockitoVerifyWhenGiven()) + .parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "mockito-core")); + } + + @DocumentExample + @Test + void shouldRemoveUnneccesaryEqFromVerify() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.mock; + import static org.mockito.ArgumentMatchers.eq; + + class Test { + void test() { + var mockString = mock(String.class); + verify(mockString).replace(eq("foo"), eq("bar")); + } + } + """, """ + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.mock; + + class Test { + void test() { + var mockString = mock(String.class); + verify(mockString).replace("foo", "bar"); + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/634") + void shouldRemoveUnneccesaryEqFromVerify_withMockitoStarImport() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.eq; + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.verify; + + class Test { + void test() { + var mockString = mock(String.class); + verify(mockString).replace(eq("foo"), eq("bar")); + } + } + """, """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.verify; + + class Test { + void test() { + var mockString = mock(String.class); + verify(mockString).replace("foo", "bar"); + } + } + """ + ) + ); + } + + @Test + void shouldRemoveUnneccesaryEqFromWhen() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + import static org.mockito.ArgumentMatchers.eq; + + class Test { + void test() { + var mockString = mock(String.class); + when(mockString.replace(eq("foo"), eq("bar"))).thenReturn("bar"); + } + } + """, """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + + class Test { + void test() { + var mockString = mock(String.class); + when(mockString.replace("foo", "bar")).thenReturn("bar"); + } + } + """ + ) + ); + } + + @Test + void shouldNotRemoveEqWhenMatchersAreMixed() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + import static org.mockito.ArgumentMatchers.eq; + import static org.mockito.ArgumentMatchers.anyString; + + class Test { + void test() { + var mockString = mock(String.class); + when(mockString.replace(eq("foo"), anyString())).thenReturn("bar"); + } + } + """ + ) + ); + } + + @Test + void shouldRemoveUnneccesaryEqFromStubber() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.doThrow; + import static org.mockito.ArgumentMatchers.eq; + + class Test { + void test() { + doThrow(new RuntimeException()).when("foo").substring(eq(1)); + } + } + """, """ + import static org.mockito.Mockito.doThrow; + + class Test { + void test() { + doThrow(new RuntimeException()).when("foo").substring(1); + } + } + """ + ) + ); + } + + @Test + void shouldRemoveUnneccesaryEqFromBDDGiven() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.BDDMockito.given; + import static org.mockito.ArgumentMatchers.eq; + + class Test { + void test() { + given("foo".substring(eq(1))); + } + } + """, """ + import static org.mockito.BDDMockito.given; + + class Test { + void test() { + given("foo".substring(1)); + } + } + """ + ) + ); + } + + @Test + void shouldNotRemoveEqImportWhenStillNeeded() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + import static org.mockito.ArgumentMatchers.eq; + import static org.mockito.ArgumentMatchers.anyString; + + class Test { + void testRemoveEq() { + var mockString = mock(String.class); + when(mockString.replace(eq("foo"), eq("bar"))).thenReturn("bar"); + } + + void testKeepEq() { + var mockString = mock(String.class); + when(mockString.replace(eq("foo"), anyString())).thenReturn("bar"); + } + } + """, """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + import static org.mockito.ArgumentMatchers.eq; + import static org.mockito.ArgumentMatchers.anyString; + + class Test { + void testRemoveEq() { + var mockString = mock(String.class); + when(mockString.replace("foo", "bar")).thenReturn("bar"); + } + + void testKeepEq() { + var mockString = mock(String.class); + when(mockString.replace(eq("foo"), anyString())).thenReturn("bar"); + } + } + """ + ) + ); + } + + @Test + void shouldFixSonarExamples() { + rewriteRun( + //language=Java + java( + """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.doThrow; + import static org.mockito.BDDMockito.given; + import static org.mockito.ArgumentMatchers.eq; + + class Test { + void test(Object v1, Object v2, Object v3, Object v4, Object v5, Foo foo) { + given(foo.bar(eq(v1), eq(v2), eq(v3))).willReturn(null); + when(foo.baz(eq(v4), eq(v5))).thenReturn("foo"); + doThrow(new RuntimeException()).when(foo).quux(eq(42)); + verify(foo).bar(eq(v1), eq(v2), eq(v3)); + } + } + + class Foo { + Object bar(Object v1, Object v2, Object v3) { return null; } + String baz(Object v4, Object v5) { return ""; } + void quux(int x) {} + } + """, """ + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.doThrow; + import static org.mockito.BDDMockito.given; + + class Test { + void test(Object v1, Object v2, Object v3, Object v4, Object v5, Foo foo) { + given(foo.bar(v1, v2, v3)).willReturn(null); + when(foo.baz(v4, v5)).thenReturn("foo"); + doThrow(new RuntimeException()).when(foo).quux(42); + verify(foo).bar(v1, v2, v3); + } + } + + class Foo { + Object bar(Object v1, Object v2, Object v3) { return null; } + String baz(Object v4, Object v5) { return ""; } + void quux(int x) {} + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/mockito/VerifyZeroToNoMoreInteractionsTest.java b/src/test/java/org/openrewrite/java/testing/mockito/VerifyZeroToNoMoreInteractionsTest.java new file mode 100644 index 000000000..6b342323f --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/mockito/VerifyZeroToNoMoreInteractionsTest.java @@ -0,0 +1,214 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.mockito; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.maven.Assertions.pomXml; + +class VerifyZeroToNoMoreInteractionsTest implements RewriteTest { + + @Language("xml") + private static final String POM_XML_WITH_MOCKITO_2 = """ + + 4.0.0 + bla.bla + bla-bla + 1.0.0 + + + org.mockito + mockito-core + 2.17.0 + test + + + + """; + + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "mockito-core-3", "mockito-junit-jupiter-3")) + .recipe(new VerifyZeroToNoMoreInteractions()); + } + + @Test + @DocumentExample + void shouldReplaceToNoMoreInteractions() { + //language=java + rewriteRun( + pomXml(POM_XML_WITH_MOCKITO_2), + java( + """ + import static org.mockito.Mockito.verifyZeroInteractions; + + class MyTest { + void test() { + verifyZeroInteractions(System.out); + } + } + """, + """ + import static org.mockito.Mockito.verifyNoMoreInteractions; + + class MyTest { + void test() { + verifyNoMoreInteractions(System.out); + } + } + """ + ) + ); + } + + @Test + void shouldNotReplaceToNoMoreInteractionsForImportOnly() { + //language=java + rewriteRun( + pomXml(POM_XML_WITH_MOCKITO_2), + java( + """ + import static org.mockito.Mockito.verifyZeroInteractions; + + class MyTest {} + """ + ) + ); + } + + @Test + void doesNotConvertAnyOtherMethods() { + rewriteRun( + pomXml(POM_XML_WITH_MOCKITO_2), + // language=java + java( + """ + import org.mockito.junit.jupiter.MockitoExtension; + import org.mockito.Mock; + import static org.mockito.Mockito.verifyZeroInteractions; + import static org.mockito.Mockito.verify; + + class MyTest { + @Mock + Object myObject; + + void test() { + verifyZeroInteractions(System.out); + verify(myObject); + } + } + """, + """ + import org.mockito.junit.jupiter.MockitoExtension; + import org.mockito.Mock; + import static org.mockito.Mockito.verifyNoMoreInteractions; + import static org.mockito.Mockito.verify; + + class MyTest { + @Mock + Object myObject; + + void test() { + verifyNoMoreInteractions(System.out); + verify(myObject); + } + } + """ + ) + ); + } + + @Test + void doesConvertNestedMethodInvocations() { + rewriteRun( + pomXml(POM_XML_WITH_MOCKITO_2), + // language=java + java( + """ + import java.util.function.Consumer; + + import static org.mockito.Mockito.verifyZeroInteractions; + + class MyTest { + void test() { + Runnable f = () -> verifyZeroInteractions(System.out); + f.run(); + } + } + """, + """ + import java.util.function.Consumer; + + import static org.mockito.Mockito.verifyNoMoreInteractions; + + class MyTest { + void test() { + Runnable f = () -> verifyNoMoreInteractions(System.out); + f.run(); + } + } + """ + ) + ); + } + + @Test + void shouldNotRunOnNewerMockito3OrHigher() { + rewriteRun( + //language=xml + pomXml( + """ + + 4.0.0 + bla.bla + bla-bla + 1.0.0 + + + org.mockito + mockito-core + 3.0.0 + test + + + + """), + //language=java + java( + """ + import org.mockito.junit.jupiter.MockitoExtension; + + import static org.mockito.Mockito.verifyZeroInteractions; + + class MyTest { + void test() { + verifyZeroInteractions(System.out); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/testng/TestNgToAssertJTest.java b/src/test/java/org/openrewrite/java/testing/testng/TestNgToAssertJTest.java new file mode 100644 index 000000000..8e4f23762 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/testng/TestNgToAssertJTest.java @@ -0,0 +1,177 @@ +/* + * Copyright 2024 the original author or authors. + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * https://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.testng; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class TestNgToAssertJTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion().classpath("testng")) + .recipeFromResources("org.openrewrite.java.testing.assertj.Assertj"); + } + + /** + * Verify that we can throw new Exception from the JavaTemplate in the generated recipe. + */ + @DocumentExample + @Test + void failWithMessage() { + rewriteRun( + //language=java + java( + """ + import static org.testng.Assert.fail; + + class Test { + void test() { + fail("foo"); + fail("foo", new IllegalStateException()); + fail(); + } + } + """, + """ + import static org.assertj.core.api.Assertions.fail; + + class Test { + void test() { + fail("foo"); + fail("foo", new IllegalStateException()); + fail(); + } + } + """ + ) + ); + } + + /** + * Verify some assertions as implemented through Refaster rules converted to Recipes. No need to test all variants. + */ + @Test + void assertTrueFalse() { + rewriteRun( + //language=java + java( + """ + import static org.testng.Assert.assertFalse; + import static org.testng.Assert.assertTrue; + + class Test { + void test() { + assertTrue(true); + assertTrue(true, "foo"); + assertFalse(false); + assertFalse(false, "foo"); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void test() { + assertThat(true).isTrue(); + assertThat(true).withFailMessage("foo").isTrue(); + assertThat(false).isFalse(); + assertThat(false).withFailMessage("foo").isFalse(); + } + } + """ + ) + ); + } + + @Test + void assertNullAndNotNull() { + rewriteRun( + //language=java + java( + """ + import static org.testng.Assert.assertNotNull; + import static org.testng.Assert.assertNull; + + class Test { + void aaa(Object obj) { + assertNull(obj); + assertNull(obj, "foo"); + } + void bbb(Object obj) { + assertNotNull(obj); + assertNotNull(obj, "foo"); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void aaa(Object obj) { + assertThat(obj).isNull(); + assertThat(obj).withFailMessage("foo").isNull(); + } + void bbb(Object obj) { + assertThat(obj).isNotNull(); + assertThat(obj).withFailMessage("foo").isNotNull(); + } + } + """ + ) + ); + } + + @Test + void assertEqualsAndNotEquals() { + rewriteRun( + //language=java + java( + """ + import static org.testng.Assert.assertEquals; + import static org.testng.Assert.assertNotEquals; + + class Test { + void aaa(Object obj) { + assertEquals(1, 1); + assertEquals(1, 1, "foo"); + assertNotEquals(1, 2); + assertNotEquals(1, 2, "foo"); + } + } + """, + """ + import static org.assertj.core.api.Assertions.assertThat; + + class Test { + void aaa(Object obj) { + assertThat(1).isEqualTo(1); + assertThat(1).as("foo").isEqualTo(1); + assertThat(1).isNotEqualTo(2); + assertThat(1).as("foo").isNotEqualTo(2); + } + } + """ + ) + ); + } +} diff --git a/src/test/resources/META-INF/rewrite/classpath/rider-spring-1.18.0.jar b/src/test/resources/META-INF/rewrite/classpath/rider-spring-1.18.0.jar new file mode 100644 index 000000000..6809b154b Binary files /dev/null and b/src/test/resources/META-INF/rewrite/classpath/rider-spring-1.18.0.jar differ diff --git a/suppressions.xml b/suppressions.xml index fbf9371b9..cc839fdf3 100644 --- a/suppressions.xml +++ b/suppressions.xml @@ -1,3 +1,11 @@ + + + ^pkg:javascript/DOMPurify@.*$ + CVE-2024-45801 +