[java] IDEA-297284 Convert MigrateAssertToMatcherAssert inspection to UAST

GitOrigin-RevId: a8f748f607798b4fda2c1df761d559bd9df9bf56
This commit is contained in:
Bart van Helvert
2022-07-05 20:57:42 +00:00
committed by intellij-monorepo-bot
parent 7eae8a8696
commit 9e4e9469d4
14 changed files with 615 additions and 457 deletions
@@ -1,6 +1,5 @@
change.class.parameter.incorrect.type.error.hint=Incorrect type
change.class.type.parameter.family.name=Change class type parameter
checkbox.statically.import.matcher.methods=Statically import matcher's methods
convert.to.atomic.family.name=Convert to atomic
convert.to.longadder.family.name=Convert to 'LongAdder'
convert.to.threadlocal.family.name=Convert to 'ThreadLocal'
@@ -9,9 +8,7 @@ inspection.guava.erase.option=Erase @javax.annotations.Nullable from converted f
inspection.guava.method.chains.option=Report method chains
inspection.guava.return.types.option=Report return types
inspection.guava.variables.option=Report variables
inspection.migrate.assert.to.matcher.description=Assert expression <code>#ref</code> can be replaced with ''{0}'' call #loc
migrate.fix.text=<html>Migrate ''{0}'' type to ''{1}''</html>
migrate.guava.to.java.family.name=Migrate Guava type to Java
migrate.method.chain.fix.text=Migrate method chain type to ''{0}''
inspection.guava.name=Guava's functional primitives can be replaced with Java
inspection.assertion.name=JUnit assertion can be 'assertThat()' call
inspection.guava.name=Guava's functional primitives can be replaced with Java
@@ -42,12 +42,6 @@
groupKey="group.names.language.level.specific.issues.and.migration.aids8" enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.refactoring.typeMigration.inspections.GuavaInspection"
bundle="messages.TypeMigrationBundle" key="inspection.guava.name"/>
<localInspection groupPath="Java" language="JAVA" shortName="MigrateAssertToMatcherAssert"
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.intellij.refactoring.typeMigration.inspections.MigrateAssertToMatcherAssertInspection"
bundle="messages.TypeMigrationBundle" key="inspection.assertion.name"/>
<java.error.fix errorCode="lambda.variable.must.be.final" implementationClass="com.intellij.refactoring.typeMigration.intentions.ConvertFieldToAtomicIntention$ConvertNonFinalLocalToAtomicFix"/>
</extensions>
</idea-plugin>
@@ -1,316 +0,0 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.refactoring.typeMigration.inspections;
import com.intellij.codeInsight.intention.impl.AddOnDemandStaticImportAction;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
import com.intellij.refactoring.typeMigration.TypeMigrationBundle;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @author Dmitry Batkovich
*/
public class MigrateAssertToMatcherAssertInspection extends AbstractBaseJavaLocalInspectionTool {
private final static Logger LOG = Logger.getInstance(MigrateAssertToMatcherAssertInspection.class);
private final static Map<String, Pair<@NonNls String, @NonNls String>> ASSERT_METHODS = new HashMap<>();
static {
ASSERT_METHODS.put("assertArrayEquals", Pair.create("$expected$, $actual$", "$actual$, {0}.is($expected$)"));
ASSERT_METHODS.put("assertEquals", Pair.create("$expected$, $actual$", "$actual$, {0}.is($expected$)"));
ASSERT_METHODS.put("assertNotEquals", Pair.create("$expected$, $actual$", "$actual$, {0}.not({0}.is($expected$))"));
ASSERT_METHODS.put("assertSame", Pair.create("$expected$, $actual$", "$actual$, {0}.sameInstance($expected$)"));
ASSERT_METHODS.put("assertNotSame", Pair.create("$expected$, $actual$", "$actual$, {0}.not({0}.sameInstance($expected$))"));
ASSERT_METHODS.put("assertNotNull", Pair.create("$obj$", "$obj$, {0}.notNullValue()"));
ASSERT_METHODS.put("assertNull", Pair.create("$obj$", "$obj$, {0}.nullValue()"));
ASSERT_METHODS.put("assertTrue", Pair.create("$cond$", "$cond$, {0}.is(true)"));
ASSERT_METHODS.put("assertFalse", Pair.create("$cond$", "$cond$, {0}.is(false)"));
}
private static final String CORE_MATCHERS_CLASS_NAME = "org.hamcrest.CoreMatchers";
private static final String MATCHERS_CLASS_NAME = "org.hamcrest.Matchers";
private static final String ORDERING_COMPARISON_NAME = "org.hamcrest.number.OrderingComparison";
public boolean myStaticallyImportMatchers = true;
@Nullable
@Override
public JComponent createOptionsPanel() {
return new SingleCheckboxOptionsPanel(TypeMigrationBundle.message("checkbox.statically.import.matcher.methods"), this,
"myStaticallyImportMatchers");
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
final GlobalSearchScope resolveScope = holder.getFile().getResolveScope();
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(holder.getProject());
final PsiClass coreMatchersClass = javaPsiFacade.findClass(CORE_MATCHERS_CLASS_NAME, resolveScope);
final PsiClass matchersClass = javaPsiFacade.findClass(MATCHERS_CLASS_NAME, resolveScope);
if (coreMatchersClass == null && matchersClass == null) {
return PsiElementVisitor.EMPTY_VISITOR;
}
return new JavaElementVisitor() {
@Override
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final String methodName = methodExpression.getReferenceName();
if (!ASSERT_METHODS.containsKey(methodName)) return;
final PsiClass assertClass;
final PsiMethod assertMethod = expression.resolveMethod();
if (assertMethod == null || (assertClass = assertMethod.getContainingClass()) == null) {
return;
}
if (!"junit.framework.Assert".equals(assertClass.getQualifiedName()) &&
!"org.junit.Assert".equals(assertClass.getQualifiedName())) {
return;
}
if (isBooleanAssert(assertMethod.getName())) {
PsiExpression[] args = expression.getArgumentList().getExpressions();
if (args[args.length - 1] instanceof PsiBinaryExpression &&
javaPsiFacade.findClass(ORDERING_COMPARISON_NAME, expression.getResolveScope()) == null) {
return;
}
}
final PsiElement referenceNameElement = methodExpression.getReferenceNameElement();
if (referenceNameElement != null) {
holder.registerProblem(referenceNameElement,
TypeMigrationBundle.message("inspection.migrate.assert.to.matcher.description", "assertThat()"),
new MigrateAssertToMatcherAssertFix(
matchersClass != null ? MATCHERS_CLASS_NAME : CORE_MATCHERS_CLASS_NAME));
}
}
};
}
public class MigrateAssertToMatcherAssertFix implements LocalQuickFix {
private final String myMatchersClassName;
public MigrateAssertToMatcherAssertFix(String name) {
myMatchersClassName = name;
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return CommonQuickFixBundle.message("fix.replace.with.x", "assertThat()");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
final PsiElement grandParent = element.getParent().getParent();
if (!(grandParent instanceof PsiMethodCallExpression)) {
return;
}
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)grandParent;
final PsiMethod method = methodCall.resolveMethod();
if (method == null) {
return;
}
final String methodName = method.getName();
Pair<String, String> templatePair = null;
if (isBooleanAssert(methodName)) {
final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions();
final PsiExpression conditionExpression = expressions[expressions.length - 1];
final boolean negate = methodName.contains("False");
if (conditionExpression instanceof PsiBinaryExpression) {
templatePair = getSuitableMatcherForBinaryExpressionInsideBooleanAssert((PsiBinaryExpression)conditionExpression, negate);
}
else if (conditionExpression instanceof PsiMethodCallExpression) {
templatePair = getSuitableMatcherForMethodCallInsideBooleanAssert((PsiMethodCallExpression)conditionExpression, negate);
}
}
if (templatePair == null) {
templatePair = ASSERT_METHODS.get(methodName);
}
LOG.assertTrue(templatePair != null);
templatePair = buildFullTemplate(templatePair, method);
final PsiExpression replaced;
try {
replaced = TypeConversionDescriptor.replaceExpression(methodCall, templatePair.getFirst(), MessageFormat.format(templatePair.getSecond(), myMatchersClassName));
}
catch (IncorrectOperationException e) {
LOG.error("Replacer can't match expression:\n" +
methodCall.getText() +
"\nwith replacement template:\n(" +
templatePair.getFirst() +
", " +
templatePair.getSecond() +
")");
throw e;
}
if (myStaticallyImportMatchers) {
for (PsiJavaCodeReferenceElement ref : ContainerUtil.reverse(
new ArrayList<>(PsiTreeUtil.findChildrenOfType(replaced, PsiJavaCodeReferenceElement.class)))) {
if (!ref.isValid()) continue;
final PsiElement resolvedElement = ref.resolve();
if (resolvedElement instanceof PsiClass) {
final String qName = ((PsiClass)resolvedElement).getQualifiedName();
if (qName != null && qName.startsWith("org.hamcrest")) {
final PsiIdentifier identifier = PsiTreeUtil.getChildOfType(ref, PsiIdentifier.class);
if (identifier != null) {
AddOnDemandStaticImportAction.invoke(project, replaced.getContainingFile(), null, identifier);
}
}
}
}
}
}
private Pair<@NonNls String, @NonNls String> buildFullTemplate(Pair<String, String> templatePair, PsiMethod method) {
if (templatePair == null) {
return null;
}
final boolean hasMessage = hasMessage(method);
final String searchTemplate = "'_Assert?." + method.getName() + "(" + (hasMessage ? "$msg$, " : "") + templatePair.getFirst() + ")";
final String replaceTemplate = "org.hamcrest.MatcherAssert.assertThat(" + (hasMessage ? "$msg$, " : "") + templatePair.getSecond() + ")";
return Pair.create(searchTemplate, replaceTemplate);
}
@Nullable
private Pair<@NonNls String, @NonNls String> getSuitableMatcherForBinaryExpressionInsideBooleanAssert(PsiBinaryExpression expression, boolean negate) {
final PsiJavaToken sign = expression.getOperationSign();
IElementType tokenType = sign.getTokenType();
if (negate) {
tokenType = negate(tokenType);
}
final @NonNls String fromTemplate = "$left$ " + sign.getText() + " $right$";
if (JavaTokenType.EQEQ.equals(tokenType) || JavaTokenType.NE.equals(tokenType)) {
boolean isEqEqForPrimitives = true;
for (PsiExpression operand : Arrays.asList(expression.getLOperand(), expression.getROperand())) {
if (!(operand.getType() instanceof PsiPrimitiveType)) {
isEqEqForPrimitives = false;
break;
}
}
@NonNls String rightPartOfAfterTemplate =
isEqEqForPrimitives ? "{0}.is($right$)" : "{0}.sameInstance($right$)";
if (JavaTokenType.NE.equals(tokenType)) {
rightPartOfAfterTemplate = "{0}.not(" + rightPartOfAfterTemplate + ")";
}
return Pair.create(fromTemplate,
"$left$, " + rightPartOfAfterTemplate);
}
@NonNls String replaceTemplate = null;
if (JavaTokenType.GT.equals(tokenType)) {
replaceTemplate = "greaterThan($right$)";
}
else if (JavaTokenType.LT.equals(tokenType)) {
replaceTemplate = "lessThan($right$)";
}
else if (JavaTokenType.GE.equals(tokenType)) {
replaceTemplate = "greaterThanOrEqualTo($right$)";
}
else if (JavaTokenType.LE.equals(tokenType)) {
replaceTemplate = "lessThanOrEqualTo($right$)";
}
if (replaceTemplate == null) {
return null;
}
replaceTemplate = ORDERING_COMPARISON_NAME + "." + replaceTemplate;
return Pair.create(fromTemplate, "$left$, " + replaceTemplate);
}
}
private static boolean isBooleanAssert(String methodName) {
return "assertFalse".equals(methodName) || "assertTrue".equals(methodName);
}
private static IElementType negate(IElementType tokenType) {
if (JavaTokenType.GT.equals(tokenType)) {
return JavaTokenType.LE;
}
else if (JavaTokenType.LT.equals(tokenType)) {
return JavaTokenType.GE;
}
else if (JavaTokenType.GE.equals(tokenType)) {
return JavaTokenType.LT;
}
else if (JavaTokenType.LE.equals(tokenType)) {
return JavaTokenType.GT;
}
return null;
}
@Nullable
private static Pair<String, String> getSuitableMatcherForMethodCallInsideBooleanAssert(PsiMethodCallExpression expression, boolean negate) {
final String methodName = expression.getMethodExpression().getReferenceName();
@NonNls String fromTemplate = null;
@NonNls String toLeftPart = null;
@NonNls String toRightPart = null;
if ("contains".equals(methodName)) {
final PsiMethod method = expression.resolveMethod();
final PsiClass containingClass;
if (method != null &&
(containingClass = method.getContainingClass()) != null) {
if (CommonClassNames.JAVA_LANG_STRING.equals(containingClass.getQualifiedName())) {
fromTemplate = "$str$.contains($sub$)";
toLeftPart = "$str$, ";
toRightPart = "{0}.containsString($sub$)";
} else if (InheritanceUtil.isInheritor(containingClass, CommonClassNames.JAVA_UTIL_COLLECTION)) {
fromTemplate = "$collection$.contains($element$)";
toLeftPart = "$collection$, ";
toRightPart = "{0}.hasItem($element$)";
}
}
}
else if ("equals".equals(methodName)) {
final PsiMethod method = expression.resolveMethod();
if (method != null && isUniqueObjectParameter(method.getParameterList())) {
fromTemplate = "$left$.equals($right$)";
toLeftPart = "$left$, ";
toRightPart = "{0}.is($right$)";
}
}
if (fromTemplate == null) {
return null;
}
if (negate) {
toRightPart = "{0}.not(" + toRightPart + ")";
}
return Pair.create(fromTemplate, toLeftPart + toRightPart);
}
private static boolean isUniqueObjectParameter(PsiParameterList parameters) {
if (parameters.getParametersCount() != 1) {
return false;
}
final PsiParameter parameter = parameters.getParameters()[0];
final PsiClass parameterClass = PsiTypesUtil.getPsiClass(parameter.getType());
return parameterClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(parameterClass.getQualifiedName());
}
private static boolean hasMessage(PsiMethod method) {
final PsiParameter maybeMessage = method.getParameterList().getParameters()[0];
final PsiClass maybeString = PsiTypesUtil.getPsiClass(maybeMessage.getType());
return maybeString != null && CommonClassNames.JAVA_LANG_STRING.equals(maybeString.getQualifiedName());
}
}
@@ -1,46 +0,0 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.inspections;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.project.IntelliJProjectConfiguration;
import com.intellij.refactoring.typeMigration.inspections.MigrateAssertToMatcherAssertInspection;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import com.intellij.util.ArrayUtilRt;
/**
* @author Dmitry Batkovich
*/
public class MigrateAssertToMatcherAssertTest extends JavaCodeInsightFixtureTestCase {
@Override
protected String getTestDataPath() {
return PlatformTestUtil.getCommunityPath() + "/java/typeMigration/testData/inspections/migrateAssertsToAssertThat";
}
@Override
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) {
moduleBuilder.addLibrary("test-env",
ArrayUtilRt.toStringArray(IntelliJProjectConfiguration.getProjectLibraryClassesRootPaths("JUnit4")));
moduleBuilder.addLibrary("test-env",
ArrayUtilRt.toStringArray(IntelliJProjectConfiguration.getProjectLibraryClassesRootPaths("hamcrest")));
}
public void testMigrateAssertToMatcherAssert() {
myFixture.configureByFile(getTestName(false) + ".java");
myFixture.enableInspections(new MigrateAssertToMatcherAssertInspection());
myFixture.checkHighlighting();
for (IntentionAction wrapper : myFixture.getAllQuickFixes()) {
if (wrapper instanceof QuickFixWrapper) {
final LocalQuickFix fix = ((QuickFixWrapper)wrapper).getFix();
if (fix instanceof MigrateAssertToMatcherAssertInspection.MigrateAssertToMatcherAssertFix) {
myFixture.launchAction(wrapper);
}
}
}
myFixture.checkResultByFile(getTestName(false) + "_after.java");
}
}
@@ -1,39 +0,0 @@
import org.junit.Assert;
import java.util.Collection;
public class MigrateAssertToMatcherAssert {
void m() {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 != 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 == 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 > 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 < 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 >= 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 <= 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 != 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 == 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 > 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 < 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 >= 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 <= 3);
}
void m2() {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd".equals("zxc"));
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd" == "zxc");
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd".contains("qwe"));
}
void m3(Collection<String> c, String o) {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(c.contains(o));
Assert.<warning descr="Assert expression 'assertEquals' can be replaced with 'assertThat()' call">assertEquals</warning>(c, o);
Assert.<warning descr="Assert expression 'assertEquals' can be replaced with 'assertThat()' call">assertEquals</warning>("msg", c, o);
Assert.<warning descr="Assert expression 'assertNotNull' can be replaced with 'assertThat()' call">assertNotNull</warning>(c);
Assert.<warning descr="Assert expression 'assertNull' can be replaced with 'assertThat()' call">assertNull</warning>(c);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(c.contains(o));
}
void m(int[] a, int[] b) {
Assert.<warning descr="Assert expression 'assertArrayEquals' can be replaced with 'assertThat()' call">assertArrayEquals</warning>(a, b);
}
}
@@ -1,46 +0,0 @@
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.hamcrest.number.OrderingComparison;
import org.junit.Assert;
import java.util.Collection;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.number.OrderingComparison.*;
public class MigrateAssertToMatcherAssert {
void m() {
assertThat(2, not(is(3)));
assertThat(2, is(3));
assertThat(2, greaterThan(3));
assertThat(2, lessThan(3));
assertThat(2, greaterThanOrEqualTo(3));
assertThat(2, lessThanOrEqualTo(3));
assertThat(2 != 3, is(false));
assertThat(2 == 3, is(false));
assertThat(2, lessThanOrEqualTo(3));
assertThat(2, greaterThanOrEqualTo(3));
assertThat(2, lessThan(3));
assertThat(2, greaterThan(3));
}
void m2() {
assertThat("asd", is("zxc"));
assertThat("asd", sameInstance("zxc"));
assertThat("asd", containsString("qwe"));
}
void m3(Collection<String> c, String o) {
assertThat(c, hasItem(o));
assertThat(o, is(c));
assertThat("msg", o, is(c));
assertThat(c, notNullValue());
assertThat(c, nullValue());
assertThat(c, not(hasItem(o)));
}
void m(int[] a, int[] b) {
assertThat(b, is(a));
}
}
@@ -23,6 +23,11 @@
groupPathKey="jvm.inspections.group.name" groupKey="jvm.inspections.test.frameworks.group.name"
key="jvm.inspection.test.failed.line.display.name"
implementationClass="com.intellij.codeInspection.test.TestFailedLineInspection"/>
<localInspection language="UAST" enabledByDefault="false" level="WARNING" shortName="MigrateAssertToMatcherAssert"
groupBundle="messages.JvmAnalysisBundle" bundle="messages.JvmAnalysisBundle"
groupPathKey="jvm.inspections.group.name" groupKey="jvm.inspections.test.frameworks.group.name"
key="jvm.inspections.migrate.assertion.name"
implementationClass="com.intellij.codeInspection.test.junit.HamcrestAssertionsConverterInspection"/>
<localInspection language="UAST" enabledByDefault="false" level="WARNING" shortName="TestInProductSource"
groupBundle="messages.JvmAnalysisBundle" bundle="messages.JvmAnalysisBundle"
groupPathKey="jvm.inspections.group.name" groupKey="jvm.inspections.test.frameworks.group.name"
@@ -168,6 +168,10 @@ jvm.inspections.junit.assertequals.on.array.problem.descriptor=<code>#ref()</cod
jvm.inspections.junit.assertequals.may.be.assertsame.display.name='assertEquals()' may be 'assertSame()'
jvm.inspections.junit.assertequals.may.be.assertsame.problem.descriptor=<code>#ref()</code> may be 'assertSame()' #loc
jvm.inspections.migrate.assertion.name=JUnit assertion can be 'assertThat()' call
jvm.inspections.migrate.assert.to.matcher.option=Statically import matcher's methods
jvm.inspections.migrate.assert.to.matcher.description=Assert expression <code>#ref</code> can be replaced with ''{0}'' call #loc
jvm.inspection.test.failed.line.display.name=Failed line in test
jvm.inspections.thread.run.display.name=Call to 'Thread.run()'
@@ -0,0 +1,209 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection.test.junit
import com.intellij.analysis.JvmAnalysisBundle
import com.intellij.codeInspection.*
import com.intellij.codeInspection.test.junit.HamcrestCommonClassNames.*
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.CommonClassNames.*
import com.intellij.uast.UastHintedVisitorAdapter
import com.intellij.util.castSafelyTo
import com.siyeh.ig.junit.JUnitCommonClassNames.*
import com.siyeh.ig.psiutils.TypeUtils
import org.jetbrains.uast.*
import org.jetbrains.uast.generate.UastElementFactory
import org.jetbrains.uast.generate.getUastElementFactory
import org.jetbrains.uast.generate.replace
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
import javax.swing.JComponent
class HamcrestAssertionsConverterInspection : AbstractBaseUastLocalInspectionTool() {
@JvmField
var myStaticallyImportMatchers = true
override fun createOptionsPanel(): JComponent = SingleCheckboxOptionsPanel(
JvmAnalysisBundle.message("jvm.inspections.migrate.assert.to.matcher.option"), this, "myStaticallyImportMatchers"
)
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
val matcherFqn =
JavaPsiFacade.getInstance(holder.project).findClass(ORG_HAMCREST_MATCHERS, holder.file.resolveScope)?.qualifiedName
?: JavaPsiFacade.getInstance(holder.project).findClass(ORG_HAMCREST_CORE_MATCHERS, holder.file.resolveScope)?.qualifiedName
?: return PsiElementVisitor.EMPTY_VISITOR
return UastHintedVisitorAdapter.create(
holder.file.language,
HamcrestAssertionsConverterVisitor(holder, matcherFqn),
arrayOf(UCallExpression::class.java),
directOnly = true
)
}
}
private class HamcrestAssertionsConverterVisitor(
private val holder: ProblemsHolder,
private val matcherFqn: String
) : AbstractUastNonRecursiveVisitor() {
private fun isBooleanAssert(methodName: String) = methodName == "assertTrue" || methodName == "assertFalse"
override fun visitCallExpression(node: UCallExpression): Boolean {
val methodName = node.methodName ?: return true
if (!JUNIT_ASSERT_METHODS.contains(methodName)) return true
val method = node.resolveToUElement() ?: return true
val methodClass = method.getContainingUClass() ?: return true
if (methodClass.qualifiedName != ORG_JUNIT_ASSERT && methodClass.qualifiedName != JUNIT_FRAMEWORK_ASSERT) return true
if (isBooleanAssert(methodName)) {
val args = node.valueArguments
val resolveScope = node.sourcePsi?.resolveScope ?: return true
val psiFacade = JavaPsiFacade.getInstance(holder.project)
if (args.last() is UBinaryExpression && psiFacade.findClass(ORG_HAMCREST_NUMBER_ORDERING_COMPARISON, resolveScope) == null) return true
}
val message = JvmAnalysisBundle.message("jvm.inspections.migrate.assert.to.matcher.description", "assertThat()")
holder.registerUProblem(node, message, MigrateToAssertThatQuickFix(matcherFqn))
return true
}
companion object {
private val JUNIT_ASSERT_METHODS = listOf(
"assertArrayEquals",
"assertEquals", "assertNotEquals",
"assertSame", "assertNotSame",
"assertNotNull", "assertNull",
"assertTrue", "assertFalse"
)
}
}
private class MigrateToAssertThatQuickFix(val matcherClassFqn: String) : LocalQuickFix {
override fun getFamilyName(): String = CommonQuickFixBundle.message("fix.replace.with.x", "assertThat()")
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.psiElement ?: return
val call = element.getUastParentOfType<UCallExpression>() ?: return
val factory = call.getUastElementFactory(project) ?: return
val methodName = call.methodName ?: return
val arguments = call.valueArguments.toMutableList()
val method = call.resolveToUElement()?.castSafelyTo<UMethod>() ?: return
val message = if (TypeUtils.typeEquals(JAVA_LANG_STRING, method.uastParameters.first().type)) {
arguments.removeFirst()
} else null
val (left, right) = when (methodName) {
"assertTrue", "assertFalse" -> {
val conditionArgument = arguments.lastOrNull() ?: return
when (conditionArgument) {
is UBinaryExpression -> {
val operator = conditionArgument.operator.normalize(methodName)
val matchExpression = factory.buildMatchExpression(operator, conditionArgument.rightOperand) ?: return
conditionArgument.leftOperand to matchExpression
}
is UQualifiedReferenceExpression -> {
val conditionCall = conditionArgument.selector.castSafelyTo<UCallExpression>() ?: return
val conditionMethodName = conditionCall.methodName ?: return
val matchExpression = if (methodName.contains("False")) {
factory.createMatchExpression(
"not", factory.buildMatchExpression(conditionMethodName, conditionArgument.receiver, conditionCall.valueArguments.first())
)
} else {
factory.buildMatchExpression(conditionMethodName, conditionArgument.receiver, conditionCall.valueArguments.first())
} ?: return
conditionArgument.receiver to matchExpression
}
else -> return
}
}
"assertEquals", "assertArrayEquals" -> {
val matchExpression = factory.createMatchExpression("is", arguments.first()) ?: return
arguments.last() to matchExpression
}
"assertNotEquals" -> {
val matchExpression = factory.createMatchExpression(
"not", factory.createMatchExpression("is", arguments.first())
) ?: return
arguments.last() to matchExpression
}
"assertSame" -> {
val matchExpression = factory.createMatchExpression("sameInstance", arguments.first()) ?: return
arguments.last() to matchExpression
}
"assertNotSame" -> {
val matchExpression = factory.createMatchExpression(
"not", factory.createMatchExpression("sameInstance", arguments.first())
) ?: return
arguments.last() to matchExpression
}
"assertNull" -> {
val matchExpression = factory.createMatchExpression("nullValue") ?: return
arguments.first() to matchExpression
}
"assertNotNull" -> {
val matchExpression = factory.createMatchExpression("notNullValue") ?: return
arguments.first() to matchExpression
}
else -> return
}
val assertThatCall = factory.createAssertThat(listOfNotNull(message, left, right)) ?: return
call.getQualifiedParentOrThis().replace(assertThatCall)
}
private fun UastElementFactory.createAssertThat(params: List<UExpression>): UExpression? {
val matchAssert = createQualifiedReference("org.hamcrest.MatcherAssert", null) ?: return null
return createCallExpression(matchAssert, "assertThat", params, null, UastCallKind.METHOD_CALL)
?.getQualifiedParentOrThis()
}
private fun UastElementFactory.createMatchExpression(name: String, parameter: UExpression? = null): UExpression? {
val paramList = if (parameter == null) emptyList() else listOf(parameter)
val matcher = createQualifiedReference(matcherClassFqn, null) ?: return null
return createCallExpression(matcher, name, paramList, null, UastCallKind.METHOD_CALL)?.getQualifiedParentOrThis()
}
private fun UExpression.isPrimitiveType() = getExpressionType() is PsiPrimitiveType
private fun UastElementFactory.createIdEqualsExpression(param: UExpression) =
if (param.isPrimitiveType()) createMatchExpression("is", param) else createMatchExpression("sameInstance", param)
private fun UastBinaryOperator.inverse(): UastBinaryOperator = when (this) {
UastBinaryOperator.EQUALS -> UastBinaryOperator.NOT_EQUALS
UastBinaryOperator.NOT_EQUALS -> UastBinaryOperator.EQUALS
UastBinaryOperator.IDENTITY_EQUALS -> UastBinaryOperator.IDENTITY_NOT_EQUALS
UastBinaryOperator.IDENTITY_NOT_EQUALS -> UastBinaryOperator.IDENTITY_EQUALS
UastBinaryOperator.GREATER -> UastBinaryOperator.LESS_OR_EQUALS
UastBinaryOperator.LESS -> UastBinaryOperator.GREATER_OR_EQUALS
UastBinaryOperator.GREATER_OR_EQUALS -> UastBinaryOperator.LESS
UastBinaryOperator.LESS_OR_EQUALS -> UastBinaryOperator.GREATER
else -> this
}
fun UastBinaryOperator.normalize(methodName: String): UastBinaryOperator = if (methodName.contains("False")) inverse() else this
private fun UastElementFactory.buildMatchExpression(operator: UastBinaryOperator, param: UExpression): UExpression? = when (operator) {
UastBinaryOperator.EQUALS -> createMatchExpression("is", param)
UastBinaryOperator.NOT_EQUALS -> createMatchExpression("not", createMatchExpression("is", param))
UastBinaryOperator.IDENTITY_EQUALS -> createIdEqualsExpression(param)
UastBinaryOperator.IDENTITY_NOT_EQUALS -> createMatchExpression("not", createIdEqualsExpression(param))
UastBinaryOperator.GREATER -> createMatchExpression("greaterThan", param)
UastBinaryOperator.LESS -> createMatchExpression("lessThan", param)
UastBinaryOperator.GREATER_OR_EQUALS -> createMatchExpression("greaterThanOrEqualTo", param)
UastBinaryOperator.LESS_OR_EQUALS -> createMatchExpression("lessThanOrEqualTo", param)
else -> null
}
private fun UastElementFactory.buildMatchExpression(methodName: String, receiver: UExpression, param: UExpression): UExpression? {
return when (methodName) {
"contains" -> {
if (receiver.getExpressionType()?.isInheritorOf(JAVA_UTIL_COLLECTION) == true) {
return createMatchExpression("hasItem", param)
}
if (TypeUtils.typeEquals(JAVA_LANG_STRING, param.getExpressionType())) {
return createMatchExpression("containsString", param)
}
return createMatchExpression("contains", param)
}
"equals" -> createMatchExpression("is", param)
else -> null
}
}
}
@@ -0,0 +1,8 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection.test.junit;
public class HamcrestCommonClassNames {
public static final String ORG_HAMCREST_NUMBER_ORDERING_COMPARISON = "org.hamcrest.number.OrderingComparison";
public static final String ORG_HAMCREST_CORE_MATCHERS = "org.hamcrest.CoreMatchers";
public static final String ORG_HAMCREST_MATCHERS = "org.hamcrest.Matchers";
}
@@ -0,0 +1,176 @@
package com.intellij.codeInspection.tests.java.test
import com.intellij.codeInspection.tests.ULanguage
import com.intellij.codeInspection.tests.test.HamcrestAssertionsConverterInspectionTestBase
class JavaHamcrestAssertionsConverterInspectionTest : HamcrestAssertionsConverterInspectionTestBase() {
fun `test highlighting`() {
myFixture.testHighlighting(ULanguage.JAVA, """
import org.junit.Assert;
import java.util.Collection;
class Foo {
void m() {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 != 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 == 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 > 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 < 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 >= 3);
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 <= 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 != 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 == 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 > 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 < 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 >= 3);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 <= 3);
}
void m2() {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd".equals("zxc"));
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd" == "zxc");
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd".contains("qwe"));
}
void m3(Collection<String> c, String o) {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(c.contains(o));
Assert.<warning descr="Assert expression 'assertEquals' can be replaced with 'assertThat()' call">assertEquals</warning>(c, o);
Assert.<warning descr="Assert expression 'assertEquals' can be replaced with 'assertThat()' call">assertEquals</warning>("msg", c, o);
Assert.<warning descr="Assert expression 'assertNotNull' can be replaced with 'assertThat()' call">assertNotNull</warning>(c);
Assert.<warning descr="Assert expression 'assertNull' can be replaced with 'assertThat()' call">assertNull</warning>(c);
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(c.contains(o));
}
void m(int[] a, int[] b) {
Assert.<warning descr="Assert expression 'assertArrayEquals' can be replaced with 'assertThat()' call">assertArrayEquals</warning>(a, b);
}
}
""".trimIndent())
}
fun `test quickfix binary expression`() {
myFixture.testAllQuickfixes(ULanguage.JAVA, """
import org.junit.Assert;
class MigrationTest {
void migrate() {
Assert.assertTrue(2 != 3);
Assert.assertTrue(2 == 3);
Assert.assertTrue(2 > 3);
Assert.assertTrue(2 < 3);
Assert.assertTrue(2 >= 3);
Assert.assertTrue(2 <= 3);
Assert.assertFalse(2 != 3);
Assert.assertFalse(2 == 3);
Assert.assertFalse(2 > 3);
Assert.assertFalse(2 < 3);
Assert.assertFalse(2 >= 3);
Assert.assertFalse(2 <= 3);
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
class MigrationTest {
void migrate() {
MatcherAssert.assertThat(2, Matchers.not(Matchers.is(3)));
MatcherAssert.assertThat(2, Matchers.is(3));
MatcherAssert.assertThat(2, Matchers.greaterThan(3));
MatcherAssert.assertThat(2, Matchers.lessThan(3));
MatcherAssert.assertThat(2, Matchers.greaterThanOrEqualTo(3));
MatcherAssert.assertThat(2, Matchers.lessThanOrEqualTo(3));
MatcherAssert.assertThat(2, Matchers.is(3));
MatcherAssert.assertThat(2, Matchers.not(Matchers.is(3)));
MatcherAssert.assertThat(2, Matchers.lessThanOrEqualTo(3));
MatcherAssert.assertThat(2, Matchers.greaterThanOrEqualTo(3));
MatcherAssert.assertThat(2, Matchers.lessThan(3));
MatcherAssert.assertThat(2, Matchers.greaterThan(3));
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
fun `test quickfix string`() {
myFixture.testAllQuickfixes(ULanguage.JAVA, """
import org.junit.Assert;
class Foo {
void migrate() {
Assert.assertTrue("asd".equals("zxc"));
Assert.assertTrue("asd" == "zxc");
Assert.assertTrue("asd".contains("qwe"));
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
class Foo {
void migrate() {
MatcherAssert.assertThat("asd", Matchers.is("zxc"));
MatcherAssert.assertThat("asd", Matchers.sameInstance("zxc"));
MatcherAssert.assertThat("asd", Matchers.containsString("qwe"));
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
fun `test quickfix collection`() {
myFixture.testAllQuickfixes(ULanguage.JAVA, """
import org.junit.Assert;
import java.util.Collection;
class Foo {
void migrate(Collection<String> c, String o) {
Assert.assertTrue(c.contains(o));
Assert.assertEquals(c, o);
Assert.assertEquals("msg", c, o);
Assert.assertNotNull(c);
Assert.assertNull(c);
Assert.assertFalse(c.contains(o));
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import java.util.Collection;
class Foo {
void migrate(Collection<String> c, String o) {
MatcherAssert.assertThat(c, Matchers.hasItem(o));
MatcherAssert.assertThat(o, Matchers.is(c));
MatcherAssert.assertThat("msg", o, Matchers.is(c));
MatcherAssert.assertThat(c, Matchers.notNullValue());
MatcherAssert.assertThat(c, Matchers.nullValue());
MatcherAssert.assertThat(c, Matchers.not(Matchers.hasItem(o)));
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
fun `test quickfix array`() {
myFixture.testAllQuickfixes(ULanguage.JAVA, """
import org.junit.Assert;
class Foo {
void migrate(int[] a, int[] b) {
Assert.assertArrayEquals(a, b);
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
class Foo {
void migrate(int[] a, int[] b) {
MatcherAssert.assertThat(b, Matchers.is(a));
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
}
@@ -0,0 +1,187 @@
package com.intellij.codeInspection.tests.kotlin.test
import com.intellij.codeInspection.tests.ULanguage
import com.intellij.codeInspection.tests.test.HamcrestAssertionsConverterInspectionTestBase
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ContentEntry
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.PsiTestUtil
import com.intellij.util.PathUtil
import java.io.File
class KotlinHamcrestAssertionsConverterInspectionTest : HamcrestAssertionsConverterInspectionTestBase() {
override fun getProjectDescriptor(): LightProjectDescriptor = object : JUnitProjectDescriptor(languageLevel) {
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
super.configureModule(module, model, contentEntry)
val jar = File(PathUtil.getJarPathForClass(JvmStatic::class.java))
PsiTestUtil.addLibrary(model, "kotlin-stdlib", jar.parent, jar.name)
}
}
fun `test highlighting`() {
myFixture.testHighlighting(ULanguage.KOTLIN, """
import org.junit.Assert
class Foo {
fun m() {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 != 3)
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 == 3)
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 > 3)
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 < 3)
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 >= 3)
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(2 <= 3)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 != 3)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 == 3)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 > 3)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 < 3)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 >= 3)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(2 <= 3)
}
fun m2() {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd".equals("zxc"))
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>("asd" == "zxc")
}
fun m3(c: Collection<String>, o: String) {
Assert.<warning descr="Assert expression 'assertTrue' can be replaced with 'assertThat()' call">assertTrue</warning>(c.contains(o))
Assert.<warning descr="Assert expression 'assertEquals' can be replaced with 'assertThat()' call">assertEquals</warning>(c, o)
Assert.<warning descr="Assert expression 'assertEquals' can be replaced with 'assertThat()' call">assertEquals</warning>("msg", c, o)
Assert.<warning descr="Assert expression 'assertNotNull' can be replaced with 'assertThat()' call">assertNotNull</warning>(c)
Assert.<warning descr="Assert expression 'assertNull' can be replaced with 'assertThat()' call">assertNull</warning>(c)
Assert.<warning descr="Assert expression 'assertFalse' can be replaced with 'assertThat()' call">assertFalse</warning>(c.contains(o))
}
fun m(a: IntArray, b: IntArray) {
Assert.<warning descr="Assert expression 'assertArrayEquals' can be replaced with 'assertThat()' call">assertArrayEquals</warning>(a, b)
}
}
""".trimIndent())
}
fun `test quickfix binary expression`() {
myFixture.testAllQuickfixes(ULanguage.KOTLIN, """
import org.junit.Assert
class MigrationTest {
fun migrate() {
Assert.assertTrue(2 != 3)
Assert.assertTrue(2 == 3)
Assert.assertTrue(2 > 3)
Assert.assertTrue(2 < 3)
Assert.assertTrue(2 >= 3)
Assert.assertTrue(2 <= 3)
Assert.assertFalse(2 != 3)
Assert.assertFalse(2 == 3)
Assert.assertFalse(2 > 3)
Assert.assertFalse(2 < 3)
Assert.assertFalse(2 >= 3)
Assert.assertFalse(2 <= 3)
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.junit.Assert
class MigrationTest {
fun migrate() {
MatcherAssert.assertThat(2, Matchers.not(Matchers.`is`(3)))
MatcherAssert.assertThat(2, Matchers.`is`(3))
MatcherAssert.assertThat(2, Matchers.greaterThan(3))
MatcherAssert.assertThat(2, Matchers.lessThan(3))
MatcherAssert.assertThat(2, Matchers.greaterThanOrEqualTo(3))
MatcherAssert.assertThat(2, Matchers.lessThanOrEqualTo(3))
MatcherAssert.assertThat(2, Matchers.`is`(3))
MatcherAssert.assertThat(2, Matchers.not(Matchers.`is`(3)))
MatcherAssert.assertThat(2, Matchers.lessThanOrEqualTo(3))
MatcherAssert.assertThat(2, Matchers.greaterThanOrEqualTo(3))
MatcherAssert.assertThat(2, Matchers.lessThan(3))
MatcherAssert.assertThat(2, Matchers.greaterThan(3))
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
fun `test quickfix string`() {
myFixture.testAllQuickfixes(ULanguage.KOTLIN, """
import org.junit.Assert
class Foo {
fun migrate() {
Assert.assertTrue("asd".equals("zxc"))
Assert.assertTrue("asd" === "zxc")
Assert.assertTrue("asd".contains("zxc"))
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.junit.Assert
class Foo {
fun migrate() {
MatcherAssert.assertThat("asd", Matchers.`is`("zxc"))
MatcherAssert.assertThat("asd", Matchers.sameInstance("zxc"))
MatcherAssert.assertThat("asd", Matchers.containsString("zxc"))
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
fun `test quickfix collection`() {
myFixture.testAllQuickfixes(ULanguage.KOTLIN, """
import org.junit.Assert
class Foo {
fun migrate(c: Collection<String>, o: String) {
Assert.assertTrue(c.contains(o))
Assert.assertEquals(c, o)
Assert.assertEquals("msg", c, o)
Assert.assertNotNull(c)
Assert.assertNull(c)
Assert.assertFalse(c.contains(o))
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.junit.Assert
class Foo {
fun migrate(c: Collection<String>, o: String) {
MatcherAssert.assertThat(c, Matchers.hasItem(o))
MatcherAssert.assertThat(o, Matchers.`is`(c))
MatcherAssert.assertThat("msg", o, Matchers.`is`(c))
MatcherAssert.assertThat(c, Matchers.notNullValue())
MatcherAssert.assertThat(c, Matchers.nullValue())
MatcherAssert.assertThat(c, Matchers.not(Matchers.hasItem(o)))
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
fun `test quickfix array`() {
myFixture.testAllQuickfixes(ULanguage.KOTLIN, """
import org.junit.Assert
class Foo {
fun migrate(a: IntArray, b: IntArray) {
Assert.assertArrayEquals(a, b)
}
}
""".trimIndent(), """
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.junit.Assert
class Foo {
fun migrate(a: IntArray, b: IntArray) {
MatcherAssert.assertThat(b, Matchers.`is`(a))
}
}
""".trimIndent(), "Replace with 'assertThat()'")
}
}
@@ -0,0 +1,25 @@
package com.intellij.codeInspection.tests.test
import com.intellij.codeInspection.test.junit.HamcrestAssertionsConverterInspection
import com.intellij.codeInspection.tests.UastInspectionTestBase
import com.intellij.codeInspection.tests.test.junit.addHamcrestLibrary
import com.intellij.codeInspection.tests.test.junit.addJUnit4Library
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ContentEntry
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.pom.java.LanguageLevel
import com.intellij.testFramework.LightProjectDescriptor
abstract class HamcrestAssertionsConverterInspectionTestBase : UastInspectionTestBase() {
override val inspection = HamcrestAssertionsConverterInspection()
protected open class JUnitProjectDescriptor(languageLevel: LanguageLevel) : ProjectDescriptor(languageLevel) {
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
super.configureModule(module, model, contentEntry)
model.addJUnit4Library()
model.addHamcrestLibrary()
}
}
override fun getProjectDescriptor(): LightProjectDescriptor = JUnitProjectDescriptor(sdkLevel)
}