Implemented JUnitAssertToAssertJInspection. More refactorings. Doc fixes.

This commit is contained in:
Chris Hodges 2019-03-31 15:15:06 +02:00
parent 582e254195
commit 847e46c217
22 changed files with 752 additions and 79 deletions

View File

@ -1,5 +1,6 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="180" />
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>

View File

@ -16,5 +16,10 @@
</set>
</option>
<option name="configurationPath" value="" />
<option name="exclusions">
<set>
<option value="src/test/resources/.*" />
</set>
</option>
</component>
</project>

152
README.md
View File

@ -1,6 +1,6 @@
# Cajon - Concise AssertJ Optimizing Nitpicker
Cajon is an IntelliJ Plugin for shortening and optimizing AssertJ assertions.
Cajon is an IntelliJ IDEA Plugin for shortening and optimizing AssertJ assertions.
## Why?
@ -13,72 +13,130 @@ This makes finding bugs and fixing failed tests more efficient.
For example:
> assertThat(collection.size()).isEqualTo(5);
```
assertThat(collection.size()).isEqualTo(5);
```
If the collection has more or less than 5 elements, the assertion will fail, but will not
tell you about the contents, making it hard to guess what went wrong.
Instead, if you wrote the same assertion the following way:
> assertThat(collection).hasSize(5);
```
assertThat(collection).hasSize(5);
```
Then AssertJ would tell you the contents of the collection on failure.
## Conversion of JUnit assertions to AssertJ
The plugin also supports the conversion of the most common JUnit 4 assertions to AssertJ.
## Implemented
- AssertThatObjectIsNull
> from: assertThat(object).isEqualTo(null);
> to: assertThat(object).isNull();
```
from: assertThat(object).isEqualTo(null);
to: assertThat(object).isNull();
```
- AssertThatObjectIsNotNull
> from: assertThat(object).isNotEqualTo(null);
> to: assertThat(object).isNotNull();
```
from: assertThat(object).isNotEqualTo(null);
to: assertThat(object).isNotNull();
```
- AssertThatBooleanIsTrueOrFalse
> from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE);
> to: assertThat(booleanValue).isTrue()/isFalse();
```
from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE);
to: assertThat(booleanValue).isTrue()/isFalse();
```
- AssertThatStringIsEmpty
> from: assertThat(charSequence/string).isEqualTo("");
> from: assertThat(charSequence/string).hasSize(0);
> to: assertThat(charSequence/string).isEmpty();
```
from: assertThat(charSequence/string).isEqualTo("");
from: assertThat(charSequence/string).hasSize(0);
to: assertThat(charSequence/string).isEmpty();
```
- AssertThatEnumerableIsEmpty
> from: assertThat(enumerable).hasSize(0);
> to: assertThat(charSequence/string).isEmpty();
```
from: assertThat(enumerable).hasSize(0);
to: assertThat(enumerable).isEmpty();
- JUnitAssertToAssertJ
```
assertTrue(condition);
assertTrue(message, condition);
assertFalse(condition);
assertFalse(message, condition);
assertNull(object);
assertNull(message, object);
assertNonNull(object);
assertNonNull(message, object);
assertEquals(expected, actual);
assertEquals(message, expected, actual);
assertEquals(expectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertEquals(message, expectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertNotEquals(unexpected, actual);
assertNotEquals(message, unexpected, actual);
assertNotEquals(unexpectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertNotEquals(message, unexpectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertSame(expected, actual);
assertSame(message, expected, actual);
assertNotSame(unexpected, actual);
assertNotSame(message, unexpected, actual);
assertArrayEquals(expected, actual);
assertArrayEquals(message, expectedArray, actualArray);
assertArrayEquals(expectedDoubleOrFloatArray, actualDoubleOrFloatArray, delta);
assertArrayEquals(message, expectedDoubleOrFloatArray, actualDoubleOrFloatArray, delta);
```
## TODO
- AssertThatArrayHasLiteralSize
> from: assertThat(array.length).isEqualTo(literal); literal > 0
> to: assertThat(array).hasSize(literal);
```
from: assertThat(array.length).isEqualTo(literal); literal > 0
to: assertThat(array).hasSize(literal);
```
- AssertThatArrayHasEqualSize
> from: assertThat(array.length).isEqualTo(anotherArray.length);
> to: assertThat(array).hasSameSizeAs(anotherArray);
> from: assertThat(array.length).isEqualTo(iterable.size());
> to: assertThat(array).hasSameSizeAs(iterable);
```
from: assertThat(array.length).isEqualTo(anotherArray.length);
to: assertThat(array).hasSameSizeAs(anotherArray);
from: assertThat(array.length).isEqualTo(iterable.size());
to: assertThat(array).hasSameSizeAs(iterable);
```
- AssertThatArrayIsEmpty
> from: assertThat(array.length).isEqualTo(0);
> from: assertThat(array.length).isLessThanOrEqualTo(0);
> from: assertThat(array.length).isLessThan(1);
> from: assertThat(array).hasSize(0);
> to: assertThat(array).isEmpty();
```
from: assertThat(array.length).isEqualTo(0);
from: assertThat(array.length).isLessThanOrEqualTo(0);
from: assertThat(array.length).isLessThan(1);
from: assertThat(array).hasSize(0);
to: assertThat(array).isEmpty();
```
- AssertThatArrayIsNotEmpty
> from: assertThat(array.length).isGreaterThan(0);
> to: assertThat(array).isNotEmpty();
- AssertThatIterableHasLiteralSize
> from: assertThat(iterable.size()).isEqualTo(literal); literal > 0
> to: assertThat(iterable).hasSize(literal);
- AssertThatIterableHasEqualSize
> from: assertThat(iterable.size()).isEqualTo(anotherArray.length);
> to: assertThat(iterable).hasSameSizeAs(anotherArray);
> from: assertThat(iterable.size()).isEqualTo(iterable.size());
> to: assertThat(iterable).hasSameSizeAs(iterable);
- AssertThatIterableIsNotEmpty
> from: assertThat(array.length).isGreaterThan(0);
> from: assertThat(array.length).isGreaterThanOrEqualTo(1);
> to: assertThat(array).isNotEmpty();
- AssertThatIterableIsEmpty
> from: assertThat(iterable.size()).isEqualTo(0);
> from: assertThat(iterable.size()).isLessThanOrEqualTo(0);
> from: assertThat(iterable.size()).isLessThan(1);
> from: assertThat(iterable).hasSize(0);
> to: assertThat(iterable).isEmpty();
- JUnit Assertion to AssertJ
```
from: assertThat(array.length).isGreaterThan(0);
to: assertThat(array).isNotEmpty();
```
- AssertThatCollectionHasLiteralSize
```
from: assertThat(collection.size()).isEqualTo(literal); literal > 0
to: assertThat(collection).hasSize(literal);
```
- AssertThatCollectionHasEqualSize
```
from: assertThat(collection.size()).isEqualTo(anotherArray.length);
to: assertThat(collection).hasSameSizeAs(anotherArray);
from: assertThat(collection.size()).isEqualTo(anotherCollection.size());
to: assertThat(collection).hasSameSizeAs(anotherCollection);
```
- AssertThatCollectionIsNotEmpty
```
from: assertThat(collection.size()).isGreaterThan(0);
from: assertThat(collection.size()).isGreaterThanOrEqualTo(1);
to: assertThat(collection).isNotEmpty();
```
- AssertThatCollectionIsEmpty
```
from: assertThat(collection.size()).isEqualTo(0);
from: assertThat(collection.size()).isLessThanOrEqualTo(0);
from: assertThat(collection.size()).isLessThan(1);
from: assertThat(collection).hasSize(0);
to: assertThat(collection).isEmpty();
```
- AssertThatGuavaOptionalContains

View File

@ -17,20 +17,26 @@ import org.jetbrains.annotations.NonNls
open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
companion object {
@NonNls
const val SIMPLIFY_MESSAGE_TEMPLATE = "%s can be simplified to %s"
@NonNls
const val REPLACE_DESCRIPTION_TEMPLATE = "Replace %s with %s"
@NonNls
const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert"
@NonNls
const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert"
@NonNls
const val ABSTRACT_STRING_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractStringAssert"
@NonNls
const val ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractCharSequenceAssert"
@NonNls
const val ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.EnumerableAssert"
@NonNls
const val IS_EQUAL_TO_METHOD = "isEqualTo"
@NonNls
const val IS_NOT_EQUAL_TO_METHOD = "isNotEqualTo"
@NonNls
const val HAS_SIZE_METHOD = "hasSize"
val IS_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_EQUAL_TO_METHOD)
@ -70,8 +76,8 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
replacementMethod: String
) {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = String.format(REPLACE_DESCRIPTION_TEMPLATE, originalMethod, replacementMethod)
val message = String.format(SIMPLIFY_MESSAGE_TEMPLATE, originalMethod, replacementMethod)
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = SIMPLIFY_MESSAGE_TEMPLATE.format(originalMethod, replacementMethod)
holder.registerProblem(
expression,
message,

View File

@ -0,0 +1,44 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool
import com.intellij.psi.PsiMethodCallExpression
import org.jetbrains.annotations.NonNls
open class AbstractJUnitAssertInspection : AbstractBaseJavaLocalInspectionTool() {
companion object {
const val CONVERT_MESSAGE_TEMPLATE = "%s can be converted to AssertJ style"
const val REPLACE_DESCRIPTION_TEMPLATE = "Replace %s with assertThat().%s"
@NonNls
const val JUNIT_ASSERT_CLASSNAME = "org.junit.Assert"
@NonNls
const val ASSERT_TRUE_METHOD = "assertTrue"
@NonNls
const val ASSERT_FALSE_METHOD = "assertFalse"
@NonNls
const val ASSERT_NULL_METHOD = "assertNull"
@NonNls
const val ASSERT_NOT_NULL_METHOD = "assertNotNull"
@NonNls
const val ASSERT_EQUALS_METHOD = "assertEquals"
@NonNls
const val ASSERT_NOT_EQUALS_METHOD = "assertNotEquals"
@NonNls
const val ASSERT_SAME_METHOD = "assertSame"
@NonNls
const val ASSERT_NOT_SAME_METHOD = "assertNotSame"
@NonNls
const val ASSERT_ARRAY_EQUALS_METHOD = "assertArrayEquals"
}
override fun getGroupDisplayName(): String {
return "AssertJ"
}
protected fun getOriginalMethodName(expression: PsiMethodCallExpression) =
expression.resolveMethod()?.name?.plus("()")
}

View File

@ -3,13 +3,11 @@ package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.util.TypeConversionUtil
import org.jetbrains.annotations.NonNls
class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() {
companion object {
@NonNls
private val DISPLAY_NAME = "Asserting true or false"
private const val DISPLAY_NAME = "Asserting true or false"
}
override fun getDisplayName() = DISPLAY_NAME

View File

@ -4,13 +4,11 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import org.jetbrains.annotations.NonNls
class AssertThatEnumerableIsEmptyInspection : AbstractAssertJInspection() {
companion object {
@NonNls
private val DISPLAY_NAME = "Asserting an enumerable is empty"
private const val DISPLAY_NAME = "Asserting an empty enumerable"
}
override fun getDisplayName() = DISPLAY_NAME

View File

@ -5,13 +5,11 @@ import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiType
import org.jetbrains.annotations.NonNls
class AssertThatObjectIsNotNullInspection : AbstractAssertJInspection() {
companion object {
@NonNls
private val DISPLAY_NAME = "Asserting non-null"
private const val DISPLAY_NAME = "Asserting non-null"
}
override fun getDisplayName() = DISPLAY_NAME

View File

@ -5,13 +5,11 @@ import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiType
import org.jetbrains.annotations.NonNls
class AssertThatObjectIsNullInspection : AbstractAssertJInspection() {
companion object {
@NonNls
private val DISPLAY_NAME = "Asserting null"
private const val DISPLAY_NAME = "Asserting null"
}
override fun getDisplayName() = DISPLAY_NAME

View File

@ -4,13 +4,11 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import org.jetbrains.annotations.NonNls
class AssertThatStringIsEmptyInspection : AbstractAssertJInspection() {
companion object {
@NonNls
private val DISPLAY_NAME = "Asserting an empty string"
private const val DISPLAY_NAME = "Asserting an empty string"
}
override fun getDisplayName() = DISPLAY_NAME

View File

@ -0,0 +1,179 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.util.TextRange
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.siyeh.ig.callMatcher.CallMatcher
import com.siyeh.ig.callMatcher.CallMatcher.anyOf
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitAssertMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitDeltaAssertMethodCallQuickFix
class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
companion object {
private const val DISPLAY_NAME = "Convert JUnit assertions to AssertJ"
private val MAPPINGS = listOf(
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes("boolean")
),
"isTrue()", false
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes("boolean")
),
"isFalse()", false
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, CommonClassNames.JAVA_LANG_OBJECT),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)
),
"isNull()", false
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, CommonClassNames.JAVA_LANG_OBJECT),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)
),
"isNotNull()", false
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("float", "float", "float")
),
"isCloseTo()", hasDelta = true
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2)
),
"isEqualTo()"
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("float", "float", "float")
),
"isNotCloseTo()", hasDelta = true
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2)
),
"isNotEqualTo()"
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2)
),
"isSameAs()"
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2)
),
"isNotSameAs()"
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double[]", "double[]", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("double[]", "double[]", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float[]", "float[]", "float"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("float[]", "float[]", "float")
),
"containsExactly()", hasDelta = true
),
Mapping(
anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3)
),
"containsExactly()"
)
)
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
val isJUnitAssertCall = expression.resolveMethod()?.containingClass?.qualifiedName == JUNIT_ASSERT_CLASSNAME
if (!isJUnitAssertCall) {
return // early exit
}
for (mapping in MAPPINGS) {
if (mapping.callMatcher.test(expression)) {
if (mapping.hasDelta) {
registerDeltaReplacementMethod(holder, expression, mapping.replacement)
} else {
registerSimpleReplacementMethod(holder, expression, mapping.hasExpected, mapping.replacement)
}
return
}
}
}
}
}
private fun registerSimpleReplacementMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
hasExpected: Boolean,
replacementMethod: String
) {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
holder.registerProblem(
expression,
message,
ProblemHighlightType.INFORMATION,
null as TextRange?,
ReplaceJUnitAssertMethodCallQuickFix(description, hasExpected, replacementMethod)
)
}
private fun registerDeltaReplacementMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
replacementMethod: String
) {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
holder.registerProblem(
expression,
message,
ProblemHighlightType.INFORMATION,
null as TextRange?,
ReplaceJUnitDeltaAssertMethodCallQuickFix(description, replacementMethod)
)
}
private class Mapping(
val callMatcher: CallMatcher,
val replacement: String,
val hasExpected: Boolean = true,
val hasDelta: Boolean = false
)
}

View File

@ -0,0 +1,32 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethodCallExpression
import org.jetbrains.annotations.NonNls
abstract class AbstractCommonQuickFix(private val description: String) : LocalQuickFix {
override fun getFamilyName() = description
companion object {
@NonNls
const val GUAVA_ASSERTIONS_CLASSNAME = "org.assertj.guava.api.Assertions"
}
protected fun addStaticImport(method: PsiMethod, element: PsiMethodCallExpression, factory: PsiElementFactory, vararg allowedClashes: String) {
val methodName = method.name
val containingClass = method.containingClass ?: return
val importList = (element.containingFile as PsiJavaFile).importList ?: return
val notImportedStatically = importList.importStaticStatements.none {
val targetClass = it.resolveTargetClass() ?: return@none false
((it.referenceName == methodName) && !allowedClashes.contains(targetClass.qualifiedName))
|| (it.isOnDemand && (targetClass == method.containingClass))
}
if (notImportedStatically) {
importList.add(factory.createImportStaticStatement(containingClass, methodName))
}
}
}

View File

@ -0,0 +1,58 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.JavaCodeStyleManager
class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val hasExpected: Boolean, private val replacementMethod: String) :
AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList
val count = args.expressionCount
val actualExpression = args.expressions[count - 1] ?: return
val (expectedExpression, messageExpression) = if (hasExpected) {
val expected = args.expressions[count - 2] ?: return
val message = if (count > 2) args.expressions[0] else null
Pair(expected, message)
} else {
val message = if (count > 1) args.expressions[0] else null
Pair(null, message)
}
val expectedMethodCall = factory.createExpressionFromText(
"a.${if (hasExpected) replacementMethod.replace("()", "(e)") else replacementMethod}", element
) as PsiMethodCallExpression
if (hasExpected) {
expectedMethodCall.argumentList.expressions[0].replace(expectedExpression!!)
}
val newMethodCall = factory.createExpressionFromText(
"org.assertj.core.api.Assertions.assertThat(a)", element
) as PsiMethodCallExpression
newMethodCall.argumentList.expressions[0].replace(actualExpression)
if (messageExpression != null) {
val asExpression = factory.createExpressionFromText("a.as(desc)", element) as PsiMethodCallExpression
asExpression.argumentList.expressions[0].replace(messageExpression)
asExpression.methodExpression.qualifierExpression!!.replace(newMethodCall)
expectedMethodCall.methodExpression.qualifierExpression!!.replace(asExpression)
} else {
expectedMethodCall.methodExpression.qualifierExpression!!.replace(newMethodCall)
}
val assertThatMethod = newMethodCall.resolveMethod() ?: return
addStaticImport(assertThatMethod, element, factory, GUAVA_ASSERTIONS_CLASSNAME)
val codeStyleManager = JavaCodeStyleManager.getInstance(element.project)
val newElement = element.replace(expectedMethodCall)
val shortened = codeStyleManager.shortenClassReferences(newElement)
CodeStyleManager.getInstance(element.project).reformat(shortened)
}
}

View File

@ -0,0 +1,60 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.JavaCodeStyleManager
class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList
val count = args.expressionCount
val actualExpression = args.expressions[count - 2] ?: return
val messageExpression = if (count > 3) args.expressions[0] else null
val expectedExpression = args.expressions[count - 3] ?: return
val deltaExpression = args.expressions[count - 1] ?: return
val offsetMethodCall = factory.createExpressionFromText(
"org.assertj.core.data.Offset.offset(c)", element
) as PsiMethodCallExpression
offsetMethodCall.argumentList.expressions[0].replace(deltaExpression)
val expectedMethodCall = factory.createExpressionFromText(
"a.${replacementMethod.removeSuffix("()")}(e, offs)", element
) as PsiMethodCallExpression
expectedMethodCall.argumentList.expressions[0].replace(expectedExpression)
expectedMethodCall.argumentList.expressions[1].replace(offsetMethodCall)
val newMethodCall = factory.createExpressionFromText(
"org.assertj.core.api.Assertions.assertThat(a)", element
) as PsiMethodCallExpression
newMethodCall.argumentList.expressions[0].replace(actualExpression)
if (messageExpression != null) {
val asExpression = factory.createExpressionFromText("a.as(desc)", element) as PsiMethodCallExpression
asExpression.argumentList.expressions[0].replace(messageExpression)
asExpression.methodExpression.qualifierExpression!!.replace(newMethodCall)
expectedMethodCall.methodExpression.qualifierExpression!!.replace(asExpression)
} else {
expectedMethodCall.methodExpression.qualifierExpression!!.replace(newMethodCall)
}
val assertThatMethod = newMethodCall.resolveMethod() ?: return
addStaticImport(assertThatMethod, element, factory, GUAVA_ASSERTIONS_CLASSNAME)
val offsetMethod = offsetMethodCall.resolveMethod() ?: return
addStaticImport(offsetMethod, element, factory)
val codeStyleManager = JavaCodeStyleManager.getInstance(element.project)
val newElement = element.replace(expectedMethodCall)
val shortened = codeStyleManager.shortenClassReferences(newElement)
CodeStyleManager.getInstance(element.project).reformat(shortened)
}
}

View File

@ -1,14 +1,11 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression
class ReplaceSimpleMethodCallQuickFix(private val description: String, private val replacementMethod: String) :
LocalQuickFix {
override fun getFamilyName() = description
class ReplaceSimpleMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement
@ -16,7 +13,7 @@ class ReplaceSimpleMethodCallQuickFix(private val description: String, private v
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return
val isEmptyExpression =
factory.createExpressionFromText("a.$replacementMethod", null) as PsiMethodCallExpression
factory.createExpressionFromText("a.$replacementMethod", element) as PsiMethodCallExpression
isEmptyExpression.methodExpression.qualifierExpression!!.replace(oldQualifier)
element.replace(isEmptyExpression)
}

View File

@ -30,6 +30,10 @@
<localInspection groupPath="Java" shortName="AssertThatEnumerableIsEmpty" enabledByDefault="true"
level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatEnumerableIsEmptyInspection"/>
<localInspection groupPath="Java" shortName="JUnitAssertToAssertJInspection" enabledByDefault="true"
level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.JUnitAssertToAssertJInspection"/>
</extensions>
<actions>

View File

@ -1,8 +0,0 @@
<html>
<body>
Turns assertThat(booleanExpression).isEqualTo(true/false) or assertThat(booleanExpression).isNotEqualTo(true/false)
into assertThat(booleanExpression).isTrue() or assertThat(booleanExpression).isFalse().
<!-- tooltip end -->
<br>Also works with Boolean.TRUE/FALSE.
</body>
</html>

View File

@ -0,0 +1,10 @@
<html>
<body>
Tries to convert most of the JUnit 4 assertions to AssertJ-Format.
<!-- tooltip end -->
<br>Works for assertTrue(), assertFalse(), assertNull(), assertNotNull(), assertEquals(), assertNotEquals(), assertSame() assertNotSame(), assertArrayEquals().
Copes with variants with message and without, handles special versions for double and float types (including arrays).
<p></p>
Does not support Hamcrest-Matchers. If you need that kind of conversion, you might want to check out the Assertions2AssertJ plugin by Ric Emery.
</body>
</html>

View File

@ -1,10 +1,12 @@
package de.platon42.intellij.playground;
import org.assertj.core.api.ListAssert;
import org.assertj.core.data.Offset;
import java.util.ArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
import static org.junit.Assert.*;
public class Playground {
@ -77,6 +79,106 @@ public class Playground {
assertEquals("message", 1L, 2L);
assertNotEquals(1L, 2L);
assertNotEquals("message", 1L, 2L);
assertEquals(4.0, 4.4, 3.3);
assertThat(3.0).isCloseTo(4.0, Offset.offset(2.3));
assertThat(new int[1]).isEqualTo(new int[2]);
String foo = "foo";
String bar = "bar";
assertTrue(foo == "foo");
assertTrue("oh no!", foo == "foo");
assertFalse(foo == "bar");
assertFalse("boom!", foo == "bar");
assertNull(foo);
assertNull("oh no!", foo);
assertNotNull(foo);
assertNotNull("oh no!", foo);
assertEquals(bar, foo);
assertEquals("equals", bar, foo);
assertNotEquals(bar, foo);
assertNotEquals("equals", bar, foo);
assertSame(bar, foo);
assertSame("same", bar, foo);
assertNotSame(bar, foo);
assertNotSame("same", bar, foo);
assertEquals(1.0, 2.0);
assertEquals(1.0, 2.0, 0.1);
assertEquals("equals", 1.0, 2.0);
assertEquals("equals", 1.0, 2.0, 0.1);
assertEquals(1.0f, 2.0f);
assertEquals(1.0f, 2.0f, 0.1f);
assertEquals("equals", 1.0f, 2.0f);
assertEquals("equals", 1.0f, 2.0f, 0.1f);
assertNotEquals(1.0, 2.0);
assertNotEquals(1.0, 2.0, 0.1);
assertNotEquals("equals", 1.0, 2.0);
assertNotEquals("equals", 1.0, 2.0, 0.1);
assertNotEquals(1.0f, 2.0f);
assertNotEquals(1.0f, 2.0f, 0.1f);
assertNotEquals("equals", 1.0f, 2.0f);
assertNotEquals("equals", 1.0f, 2.0f, 0.1f);
assertArrayEquals(new int[2], new int[1]);
assertArrayEquals("array equals", new int[2], new int[1]);
assertArrayEquals(new double[2], new double[1], 1.0);
assertArrayEquals("array equals", new double[2], new double[1], 1.0);
assertArrayEquals(new float[2], new float[1], 1.0f);
assertArrayEquals("array equals", new float[2], new float[1], 1.0f);
assertThat(foo == "foo").isTrue();
assertThat(foo == "foo").as("oh no!").isTrue();
assertThat(foo == "bar").isFalse();
assertThat(foo == "bar").as("boom!").isFalse();
assertThat(foo).isNull();
assertThat(foo).as("oh no!").isNull();
assertThat(foo).isNotNull();
assertThat(foo).as("oh no!").isNotNull();
assertThat(foo).isEqualTo(bar);
assertThat(foo).as("equals").isEqualTo(bar);
assertThat(foo).isNotEqualTo(bar);
assertThat(foo).as("equals").isNotEqualTo(bar);
assertThat(foo).isSameAs(bar);
assertThat(foo).as("same").isSameAs(bar);
assertThat(foo).isNotSameAs(bar);
assertThat(foo).as("same").isNotSameAs(bar);
assertThat(2.0).isEqualTo(1.0);
assertThat(2.0).isCloseTo(1.0, offset(0.1));
assertThat(2.0).as("equals").isEqualTo(1.0);
assertThat(2.0).as("equals").isCloseTo(1.0, offset(0.1));
assertThat(2.0f).isEqualTo(1.0f);
assertThat(2.0f).isCloseTo(1.0f, offset(0.1f));
assertThat(2.0f).as("equals").isEqualTo(1.0f);
assertThat(2.0f).as("equals").isCloseTo(1.0f, offset(0.1f));
assertThat(2.0).isNotEqualTo(1.0);
assertThat(2.0).isNotCloseTo(1.0, offset(0.1));
assertThat(2.0).as("equals").isNotEqualTo(1.0);
assertThat(2.0).as("equals").isNotCloseTo(1.0, offset(0.1));
assertThat(2.0f).isNotEqualTo(1.0f);
assertThat(2.0f).isNotCloseTo(1.0f, offset(0.1f));
assertThat(2.0f).as("equals").isNotEqualTo(1.0f);
assertThat(2.0f).as("equals").isNotCloseTo(1.0f, offset(0.1f));
assertThat(new int[1]).isEqualTo(new int[2]);
assertThat(new int[1]).as("array equals").isEqualTo(new int[2]);
assertThat(new double[1]).containsExactly(new double[2], offset(1.0));
assertThat(new double[1]).as("array equals").containsExactly(new double[2], offset(1.0));
assertThat(new float[1]).containsExactly(new float[2], offset(1.0f));
assertThat(new float[1]).as("array equals").containsExactly(new float[2], offset(1.0f));
}
}

View File

@ -0,0 +1,25 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
import de.platon42.intellij.jupiter.AddLocalJarToModule
import de.platon42.intellij.jupiter.MyFixture
import de.platon42.intellij.jupiter.TestDataSubPath
import de.platon42.intellij.plugins.cajon.AbstractCajonTest
import org.assertj.core.api.Assertions
import org.junit.Assert
import org.junit.jupiter.api.Test
@AddLocalJarToModule(Assert::class, Assertions::class)
internal class JUnitAssertToAssertJInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/JUnitAssertToAssertJ")
internal fun junit_Assertions_can_be_converted_into_AssertJ(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.enableInspections(JUnitAssertToAssertJInspection::class.java)
myFixture.configureByFile("JUnitAssertToAssertJInspectionBefore.java")
executeQuickFixes(myFixture, Regex("Replace .*"), 38)
myFixture.checkResultByFile("JUnitAssertToAssertJInspectionAfter.java")
}
}
}

View File

@ -0,0 +1,56 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
import static org.junit.Assert.*;
public class JUnitAssertToAssertJInspection {
private void jUnitAssertToAssertJInspection() {
String foo = "foo";
String bar = "bar";
assertThat(foo == "foo").isTrue();
assertThat(foo == "foo").as("oh no!").isTrue();
assertThat(foo == "bar").isFalse();
assertThat(foo == "bar").as("boom!").isFalse();
assertThat(foo).isNull();
assertThat(foo).as("oh no!").isNull();
assertThat(foo).isNotNull();
assertThat(foo).as("oh no!").isNotNull();
assertThat(foo).isEqualTo(bar);
assertThat(foo).as("equals").isEqualTo(bar);
assertThat(foo).isNotEqualTo(bar);
assertThat(foo).as("equals").isNotEqualTo(bar);
assertThat(foo).isSameAs(bar);
assertThat(foo).as("same").isSameAs(bar);
assertThat(foo).isNotSameAs(bar);
assertThat(foo).as("same").isNotSameAs(bar);
assertThat(2.0).isEqualTo(1.0);
assertThat(2.0).isCloseTo(1.0, offset(0.1));
assertThat(2.0).as("equals").isEqualTo(1.0);
assertThat(2.0).as("equals").isCloseTo(1.0, offset(0.1));
assertThat(2.0f).isEqualTo(1.0f);
assertThat(2.0f).isCloseTo(1.0f, offset(0.1f));
assertThat(2.0f).as("equals").isEqualTo(1.0f);
assertThat(2.0f).as("equals").isCloseTo(1.0f, offset(0.1f));
assertThat(2.0).isNotEqualTo(1.0);
assertThat(2.0).isNotCloseTo(1.0, offset(0.1));
assertThat(2.0).as("equals").isNotEqualTo(1.0);
assertThat(2.0).as("equals").isNotCloseTo(1.0, offset(0.1));
assertThat(2.0f).isNotEqualTo(1.0f);
assertThat(2.0f).isNotCloseTo(1.0f, offset(0.1f));
assertThat(2.0f).as("equals").isNotEqualTo(1.0f);
assertThat(2.0f).as("equals").isNotCloseTo(1.0f, offset(0.1f));
assertThat(new int[1]).containsExactly(new int[2]);
assertThat(new int[1]).as("array equals").containsExactly(new int[2]);
assertThat(new double[1]).containsExactly(new double[2], offset(1.0));
assertThat(new double[1]).as("array equals").containsExactly(new double[2], offset(1.0));
assertThat(new float[1]).containsExactly(new float[2], offset(1.0f));
assertThat(new float[1]).as("array equals").containsExactly(new float[2], offset(1.0f));
}
}

View File

@ -0,0 +1,54 @@
import static org.junit.Assert.*;
public class JUnitAssertToAssertJInspection {
private void jUnitAssertToAssertJInspection() {
String foo = "foo";
String bar = "bar";
assertTrue(foo == "foo");
assertTrue("oh no!", foo == "foo");
assertFalse(foo == "bar");
assertFalse("boom!", foo == "bar");
assertNull(foo);
assertNull("oh no!", foo);
assertNotNull(foo);
assertNotNull("oh no!", foo);
assertEquals(bar, foo);
assertEquals("equals", bar, foo);
assertNotEquals(bar, foo);
assertNotEquals("equals", bar, foo);
assertSame(bar, foo);
assertSame("same", bar, foo);
assertNotSame(bar, foo);
assertNotSame("same", bar, foo);
assertEquals(1.0, 2.0);
assertEquals(1.0, 2.0, 0.1);
assertEquals("equals",1.0, 2.0);
assertEquals("equals",1.0, 2.0, 0.1);
assertEquals(1.0f, 2.0f);
assertEquals(1.0f, 2.0f, 0.1f);
assertEquals("equals",1.0f, 2.0f);
assertEquals("equals",1.0f, 2.0f, 0.1f);
assertNotEquals(1.0, 2.0);
assertNotEquals(1.0, 2.0, 0.1);
assertNotEquals("equals",1.0, 2.0);
assertNotEquals("equals",1.0, 2.0, 0.1);
assertNotEquals(1.0f, 2.0f);
assertNotEquals(1.0f, 2.0f, 0.1f);
assertNotEquals("equals",1.0f, 2.0f);
assertNotEquals("equals",1.0f, 2.0f, 0.1f);
assertArrayEquals(new int[2], new int[1]);
assertArrayEquals("array equals", new int[2], new int[1]);
assertArrayEquals(new double[2], new double[1], 1.0);
assertArrayEquals("array equals", new double[2], new double[1], 1.0);
assertArrayEquals(new float[2], new float[1], 1.0f);
assertArrayEquals("array equals", new float[2], new float[1], 1.0f);
}
}