Add support for converting JUnit 5 tests to AssertJ

This commit is contained in:
Niels Ulrik Andersen
2022-02-23 18:05:32 +01:00
parent f8b86ac78f
commit 49a3b1aada
10 changed files with 276 additions and 30 deletions
@@ -10,9 +10,15 @@ abstract class AbstractJUnitAssertInspection : AbstractBaseJavaLocalInspectionTo
@NonNls
const val JUNIT4_ASSERT_CLASSNAME = "org.junit.Assert"
@NonNls
const val JUNIT5_ASSERT_CLASSNAME = "org.junit.jupiter.api.Assertions"
@NonNls
const val JUNIT4_ASSUME_CLASSNAME = "org.junit.Assume"
@NonNls
const val JUNIT5_ASSUME_CLASSNAME = "org.junit.jupiter.api.Assumptions"
@NonNls
const val ASSERT_TRUE_METHOD = "assertTrue"
@@ -29,90 +29,120 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(JAVA_LANG_STRING, BOOLEAN),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(BOOLEAN, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(BOOLEAN),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(BOOLEAN),
),
MethodNames.IS_TRUE, hasExpected = false
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(JAVA_LANG_STRING, BOOLEAN),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(BOOLEAN, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(BOOLEAN),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(BOOLEAN),
),
MethodNames.IS_FALSE, hasExpected = false
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(JAVA_LANG_STRING, JAVA_LANG_OBJECT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(JAVA_LANG_OBJECT, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(JAVA_LANG_OBJECT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(JAVA_LANG_OBJECT),
),
MethodNames.IS_NULL, hasExpected = false
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(JAVA_LANG_STRING, JAVA_LANG_OBJECT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(JAVA_LANG_OBJECT, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(JAVA_LANG_OBJECT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(JAVA_LANG_OBJECT),
),
MethodNames.IS_NOT_NULL, hasExpected = false
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(JAVA_LANG_STRING, DOUBLE, DOUBLE, DOUBLE),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(DOUBLE, DOUBLE, DOUBLE, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(DOUBLE, DOUBLE, DOUBLE),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(DOUBLE, DOUBLE, DOUBLE),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(JAVA_LANG_STRING, FLOAT, FLOAT, FLOAT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(FLOAT, FLOAT, FLOAT, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(FLOAT, FLOAT, FLOAT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(FLOAT, FLOAT, FLOAT),
),
MethodNames.IS_CLOSE_TO, hasDelta = true
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2),
),
MethodNames.IS_EQUAL_TO
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(JAVA_LANG_STRING, DOUBLE, DOUBLE, DOUBLE),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(DOUBLE, DOUBLE, DOUBLE, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(DOUBLE, DOUBLE, DOUBLE),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(DOUBLE, DOUBLE, DOUBLE),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(JAVA_LANG_STRING, FLOAT, FLOAT, FLOAT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(FLOAT, FLOAT, FLOAT, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(FLOAT, FLOAT, FLOAT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(FLOAT, FLOAT, FLOAT),
),
MethodNames.IS_NOT_CLOSE_TO, hasDelta = true
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2),
),
MethodNames.IS_NOT_EQUAL_TO
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2),
),
MethodNames.IS_SAME_AS
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2),
),
MethodNames.IS_NOT_SAME_AS
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(JAVA_LANG_STRING, DOUBLE_ARR, DOUBLE_ARR, DOUBLE),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(DOUBLE_ARR, DOUBLE_ARR, DOUBLE, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(DOUBLE_ARR, DOUBLE_ARR, DOUBLE),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(DOUBLE_ARR, DOUBLE_ARR, DOUBLE),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(JAVA_LANG_STRING, FLOAT_ARR, FLOAT_ARR, FLOAT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(FLOAT_ARR, FLOAT_ARR, FLOAT, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(FLOAT_ARR, FLOAT_ARR, FLOAT),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(FLOAT_ARR, FLOAT_ARR, FLOAT),
),
MethodNames.CONTAINS_EXACTLY, hasDelta = true
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2),
staticCall(JUNIT4_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3),
staticCall(JUNIT5_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3),
),
MethodNames.CONTAINS_EXACTLY
)
@@ -122,27 +152,34 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
Mapping(
anyOf(
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_TRUE_METHOD).parameterTypes(JAVA_LANG_STRING, BOOLEAN),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_TRUE_METHOD).parameterTypes(BOOLEAN, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_TRUE_METHOD).parameterTypes(BOOLEAN),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_TRUE_METHOD).parameterTypes(BOOLEAN),
),
MethodNames.IS_TRUE, hasExpected = false
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_FALSE_METHOD).parameterTypes(JAVA_LANG_STRING, BOOLEAN),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_FALSE_METHOD).parameterTypes(BOOLEAN, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_FALSE_METHOD).parameterTypes(BOOLEAN),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_FALSE_METHOD).parameterTypes(BOOLEAN),
),
MethodNames.IS_FALSE, hasExpected = false
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_NOT_NULL_METHOD).parameterCount(1),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_NOT_NULL_METHOD).parameterCount(1),
),
MethodNames.IS_NOT_NULL, hasExpected = false, singleArgument = true
),
Mapping(
anyOf(
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_NO_EXCEPTION).parameterTypes(JAVA_LANG_STRING, JAVA_LANG_THROWABLE),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_NO_EXCEPTION).parameterTypes(JAVA_LANG_THROWABLE, JAVA_LANG_STRING),
staticCall(JUNIT4_ASSUME_CLASSNAME, ASSUME_NO_EXCEPTION).parameterTypes(JAVA_LANG_THROWABLE),
staticCall(JUNIT5_ASSUME_CLASSNAME, ASSUME_NO_EXCEPTION).parameterTypes(JAVA_LANG_THROWABLE),
),
"doesNotThrowAnyException", hasExpected = false
)
@@ -156,35 +193,37 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
when (expression.resolveMethod()?.containingClass?.qualifiedName) {
JUNIT4_ASSERT_CLASSNAME -> visitMethodCallExpressionAssert(holder, expression)
JUNIT4_ASSUME_CLASSNAME -> visitMethodCallExpressionAssume(holder, expression)
JUNIT4_ASSERT_CLASSNAME -> visitMethodCallExpressionAssert(holder, expression, false)
JUNIT5_ASSERT_CLASSNAME -> visitMethodCallExpressionAssert(holder, expression, true)
JUNIT4_ASSUME_CLASSNAME -> visitMethodCallExpressionAssume(holder, expression, false)
JUNIT5_ASSUME_CLASSNAME -> visitMethodCallExpressionAssume(holder, expression, true)
}
}
}
}
private fun visitMethodCallExpressionAssert(holder: ProblemsHolder, expression: PsiMethodCallExpression) {
private fun visitMethodCallExpressionAssert(holder: ProblemsHolder, expression: PsiMethodCallExpression, junit5: Boolean) {
JavaPsiFacade.getInstance(expression.project)
.findClass(AssertJClassNames.ASSERTIONS_CLASSNAME, GlobalSearchScope.allScope(expression.project)) ?: return
val mapping = ASSERT_MAPPINGS.firstOrNull { it.callMatcher.test(expression) } ?: return
if (mapping.hasDelta) {
registerConvertMethod(holder, expression, mapping.replacement, MethodNames.ASSERT_THAT) { desc, method ->
ReplaceJUnitDeltaAssertMethodCallQuickFix(desc, method)
ReplaceJUnitDeltaAssertMethodCallQuickFix(desc, method, junit5)
}
} else {
registerConvertMethod(holder, expression, mapping.replacement, MethodNames.ASSERT_THAT) { desc, method ->
ReplaceJUnitAssertMethodCallQuickFix(desc, method, !mapping.hasExpected)
ReplaceJUnitAssertMethodCallQuickFix(desc, method, !mapping.hasExpected, junit5)
}
}
}
private fun visitMethodCallExpressionAssume(holder: ProblemsHolder, expression: PsiMethodCallExpression) {
private fun visitMethodCallExpressionAssume(holder: ProblemsHolder, expression: PsiMethodCallExpression, junit5: Boolean) {
JavaPsiFacade.getInstance(expression.project)
.findClass(AssertJClassNames.ASSUMPTIONS_CLASSNAME, GlobalSearchScope.allScope(expression.project)) ?: return
val mapping = ASSUME_MAPPINGS.firstOrNull { it.callMatcher.test(expression) } ?: return
if (!mapping.singleArgument || expression.argumentList.expressions.size == 1) {
registerConvertMethod(holder, expression, mapping.replacement, MethodNames.ASSUME_THAT) { desc, method ->
ReplaceJUnitAssumeMethodCallQuickFix(desc, method)
ReplaceJUnitAssumeMethodCallQuickFix(desc, method, junit5)
}
}
}
@@ -7,7 +7,7 @@ import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.*
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME
class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val replacementMethod: String, private val noExpectedExpression: Boolean) :
class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val replacementMethod: String, private val noExpectedExpression: Boolean, private val junit5: Boolean) :
AbstractCommonQuickFix(description) {
companion object {
@@ -23,14 +23,20 @@ class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val repl
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList
val count = args.expressions.size
val actualExpression = args.expressions[count - 1] ?: return
val (expectedExpressions, messageExpression) = if (noExpectedExpression) {
val message = args.expressions.getOrNull(count - 2)
emptyArray<PsiExpression>() to message
val hasMessage = if (noExpectedExpression) count == 1 else count == 2;
val actualExpression: PsiExpression
val expectedExpressions: Array<PsiExpression>
val messageExpression: PsiExpression?
if (junit5) {
actualExpression = args.expressions[if (noExpectedExpression) 0 else 1] ?: return
messageExpression = if (hasMessage) null else args.expressions[count - 1]
expectedExpressions = if (noExpectedExpression) emptyArray() else arrayOf(args.expressions[0])
} else {
val expected = args.expressions[count - 2] ?: return
val message = args.expressions.getOrNull(count - 3)
arrayOf(expected) to message
actualExpression = args.expressions[count - 1] ?: return
messageExpression = if (hasMessage) null else args.expressions[0]
expectedExpressions = if (noExpectedExpression) emptyArray() else arrayOf(args.expressions[count - 2])
}
val swapActualAndExpected = ((expectedExpressions.getOrNull(0)?.calculateConstantValue() == null)
@@ -5,7 +5,7 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.*
class ReplaceJUnitAssumeMethodCallQuickFix(description: String, private val replacementMethod: String) :
class ReplaceJUnitAssumeMethodCallQuickFix(description: String, private val replacementMethod: String, private val junit5: Boolean) :
AbstractCommonQuickFix(description) {
companion object {
@@ -21,8 +21,8 @@ class ReplaceJUnitAssumeMethodCallQuickFix(description: String, private val repl
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList
val count = args.expressions.size
val actualExpression = args.expressions[count - 1] ?: return
val messageExpression = args.expressions.getOrNull(count - 2)
val actualExpression = args.expressions[if (junit5) 0 else count - 1] ?: return
val messageExpression = args.expressions.getOrNull(if (junit5) 1 else count - 2)
val expectedMethodCall = createExpectedMethodCall(element, replacementMethod)
val newMethodCall = createAssumeThat(element, actualExpression)
@@ -6,7 +6,7 @@ import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.*
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME
class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val replacementMethod: String, private val junit5: Boolean) : AbstractCommonQuickFix(description) {
companion object {
private const val CONVERT_DESCRIPTION = "Convert JUnit assertions with delta to assertJ"
@@ -21,10 +21,10 @@ class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList
val count = args.expressions.size
val messageExpression = args.expressions.getOrNull(count - 4)
val expectedExpression = args.expressions[count - 3] ?: return
val actualExpression = args.expressions[count - 2] ?: return
val deltaExpression = args.expressions[count - 1] ?: return
val messageExpression = args.expressions.getOrNull(if (junit5) 3 else count - 4)
val expectedExpression = args.expressions[if (junit5) 0 else count - 3] ?: return
val actualExpression = args.expressions[if (junit5) 1 else count - 2] ?: return
val deltaExpression = args.expressions[if (junit5) 2 else count - 1] ?: return
val offsetMethodCall = createMethodCall(element, "org.assertj.core.data.Offset.offset", deltaExpression)