From 5fa61a30042acba0e2f827a07d6d7d43a785c93b Mon Sep 17 00:00:00 2001 From: chrisly42 Date: Sun, 24 Mar 2019 09:15:07 +0100 Subject: [PATCH] Implemented AssertThatStringIsEmpty. --- README.md | 26 ++++++++-- .../inspections/AbstractAssertJInspection.kt | 1 + ...ssertThatBooleanIsTrueOrFalseInspection.kt | 29 ++--------- .../AssertThatObjectIsNotNullInspection.kt | 26 +++------- .../AssertThatObjectIsNullInspection.kt | 26 +++------- .../AssertThatStringIsEmptyInspection.kt | 51 +++++++++++++++++++ .../ReplaceSimpleMethodCallQuickFix.kt | 23 +++++++++ src/main/resources/META-INF/plugin.xml | 2 + .../intellij/playground/Playground.java | 8 +++ .../AssertThatStringIsEmptyInspectionTest.kt | 21 ++++++++ .../StringIsEmpty/StringIsEmptyAfter.java | 11 ++++ .../StringIsEmpty/StringIsEmptyBefore.java | 11 ++++ 12 files changed, 166 insertions(+), 69 deletions(-) create mode 100644 src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspection.kt create mode 100644 src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/ReplaceSimpleMethodCallQuickFix.kt create mode 100644 src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspectionTest.kt create mode 100644 src/test/resources/inspections/StringIsEmpty/StringIsEmptyAfter.java create mode 100644 src/test/resources/inspections/StringIsEmpty/StringIsEmptyBefore.java diff --git a/README.md b/README.md index c20e86a..fd125e3 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,25 @@ Cajon is an IntelliJ Plugin for shortening and optimizing AssertJ assertions. ## Why? -First, code is easier to read, when is concise and reflects the intention clearly. -AssertJ has plenty of different convenience methods that make describing the various intentions. +First, code is easier to read, when it is concise and reflects the intention clearly. +AssertJ has plenty of different convenience methods that describing various intentions precisely. Why write longer, more complex code that can be expressed in brevity? Second, AssertJ is able to output more meaningful descriptions when an assertion fails. -This makes finding bugs and fixing failed tests easier. +This makes finding bugs and fixing failed tests more efficient. + +For example: + +> 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); + +Then AssertJ would tell you the contents of the collection on failure. ## Implemented @@ -22,11 +35,11 @@ This makes finding bugs and fixing failed tests easier. - AssertThatBooleanIsTrueOrFalse > from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE); > to: assertThat(booleanValue).isTrue()/isFalse(); - -## TODO - AssertThatStringIsEmpty > from: assertThat(string).isEqualTo("") > to: assertThat(string).isEmpty(); + +## TODO - AssertThatArrayHasLiteralSize > from: assertThat(array.length).isEqualTo(literal); literal > 0 > to: assertThat(array).hasSize(literal); @@ -62,3 +75,6 @@ This makes finding bugs and fixing failed tests easier. > from: assertThat(iterable.size()).isLessThan(1); > from: assertThat(iterable).hasSize(0); > to: assertThat(iterable).isEmpty(); +- JUnit Assertion to AssertJ + +- AssertThatGuavaOptionalContains \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AbstractAssertJInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AbstractAssertJInspection.kt index 1ecc873..58f6a01 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AbstractAssertJInspection.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AbstractAssertJInspection.kt @@ -9,6 +9,7 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() { companion object { const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert" const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert" + const val ABSTRACT_STRING_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractStringAssert" const val IS_EQUAL_TO = "isEqualTo" const val IS_NOT_EQUAL_TO = "isNotEqualTo" diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatBooleanIsTrueOrFalseInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatBooleanIsTrueOrFalseInspection.kt index 89afeb3..c8bb027 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatBooleanIsTrueOrFalseInspection.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatBooleanIsTrueOrFalseInspection.kt @@ -1,13 +1,11 @@ package de.platon42.intellij.plugins.cajon.inspections -import com.intellij.codeInspection.LocalQuickFix -import com.intellij.codeInspection.ProblemDescriptor import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder -import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange import com.intellij.psi.* import com.intellij.psi.util.TypeConversionUtil +import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix import org.jetbrains.annotations.NonNls class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() { @@ -63,34 +61,17 @@ class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() { } } val expectedResult = result as? Boolean ?: return + val description = + if (flippedBooleanTest) QUICKFIX_DESCRIPTION_NOT_IS_TRUE else QUICKFIX_DESCRIPTION_IS_TRUE + val replacementMethod = if (expectedResult xor flippedBooleanTest) "isTrue()" else "isFalse()" holder.registerProblem( expression, INSPECTION_MESSAGE, ProblemHighlightType.INFORMATION, null as TextRange?, - ReplaceWithIsNullQuickFix( - expectedResult xor flippedBooleanTest, - if (flippedBooleanTest) QUICKFIX_DESCRIPTION_NOT_IS_TRUE else QUICKFIX_DESCRIPTION_IS_TRUE - ) + ReplaceSimpleMethodCallQuickFix(description, replacementMethod) ) } } } - - - private class ReplaceWithIsNullQuickFix(val expectedResult: Boolean, val quickfixName: String) : LocalQuickFix { - override fun getFamilyName() = quickfixName - - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val element = descriptor.startElement - val factory = JavaPsiFacade.getElementFactory(element.project) - val methodCallExpression = element as? PsiMethodCallExpression ?: return - val oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return - val methodName = if (expectedResult) "isTrue()" else "isFalse()" - val isNullExpression = - factory.createExpressionFromText("a.$methodName", null) as PsiMethodCallExpression - isNullExpression.methodExpression.qualifierExpression!!.replace(oldQualifier) - element.replace(isNullExpression) - } - } } \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNotNullInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNotNullInspection.kt index b24905d..3d4b237 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNotNullInspection.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNotNullInspection.kt @@ -1,12 +1,13 @@ package de.platon42.intellij.plugins.cajon.inspections -import com.intellij.codeInspection.LocalQuickFix -import com.intellij.codeInspection.ProblemDescriptor import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder -import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange -import com.intellij.psi.* +import com.intellij.psi.JavaElementVisitor +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiMethodCallExpression +import com.intellij.psi.PsiType +import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix import org.jetbrains.annotations.NonNls class AssertThatObjectIsNotNullInspection : AbstractAssertJInspection() { @@ -38,25 +39,10 @@ class AssertThatObjectIsNotNullInspection : AbstractAssertJInspection() { INSPECTION_MESSAGE, ProblemHighlightType.INFORMATION, null as TextRange?, - ReplaceWithIsNotNullQuickFix() + ReplaceSimpleMethodCallQuickFix(QUICKFIX_DESCRIPTION, "isNotNull()") ) } } } } - - private class ReplaceWithIsNotNullQuickFix : LocalQuickFix { - override fun getFamilyName() = QUICKFIX_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 oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return - val isNotNullExpression = - factory.createExpressionFromText("a.isNotNull()", null) as PsiMethodCallExpression - isNotNullExpression.methodExpression.qualifierExpression!!.replace(oldQualifier) - element.replace(isNotNullExpression) - } - } } \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNullInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNullInspection.kt index 4bce1c0..eb59be7 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNullInspection.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatObjectIsNullInspection.kt @@ -1,12 +1,13 @@ package de.platon42.intellij.plugins.cajon.inspections -import com.intellij.codeInspection.LocalQuickFix -import com.intellij.codeInspection.ProblemDescriptor import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder -import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange -import com.intellij.psi.* +import com.intellij.psi.JavaElementVisitor +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiMethodCallExpression +import com.intellij.psi.PsiType +import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix import org.jetbrains.annotations.NonNls class AssertThatObjectIsNullInspection : AbstractAssertJInspection() { @@ -38,25 +39,10 @@ class AssertThatObjectIsNullInspection : AbstractAssertJInspection() { INSPECTION_MESSAGE, ProblemHighlightType.INFORMATION, null as TextRange?, - ReplaceWithIsNullQuickFix() + ReplaceSimpleMethodCallQuickFix(QUICKFIX_DESCRIPTION, "isNull()") ) } } } } - - private class ReplaceWithIsNullQuickFix : LocalQuickFix { - override fun getFamilyName() = QUICKFIX_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 oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return - val isNullExpression = - factory.createExpressionFromText("a.isNull()", null) as PsiMethodCallExpression - isNullExpression.methodExpression.qualifierExpression!!.replace(oldQualifier) - element.replace(isNullExpression) - } - } } \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspection.kt new file mode 100644 index 0000000..17fda36 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspection.kt @@ -0,0 +1,51 @@ +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.JavaElementVisitor +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiLiteralExpression +import com.intellij.psi.PsiMethodCallExpression +import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix +import org.jetbrains.annotations.NonNls + +class AssertThatStringIsEmptyInspection : AbstractAssertJInspection() { + + companion object { + @NonNls + private val DISPLAY_NAME = "Asserting an empty string" + + @NonNls + private val INSPECTION_MESSAGE = "isEqualTo(\"\") can be simplified to isEmpty()" + + @NonNls + private val QUICKFIX_DESCRIPTION = "Replace isEqualTo(\"\") with isEmpty()" + } + + override fun getDisplayName() = DISPLAY_NAME + + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return object : JavaElementVisitor() { + override fun visitMethodCallExpression(expression: PsiMethodCallExpression) { + super.visitMethodCallExpression(expression) + if (!IS_EQUAL_TO_OBJECT.test(expression)) { + return + } + + val psiExpression = expression.argumentList.expressions[0] as? PsiLiteralExpression ?: return + + if (psiExpression.value == "") { + holder.registerProblem( + expression, + INSPECTION_MESSAGE, + ProblemHighlightType.INFORMATION, + null as TextRange?, + ReplaceSimpleMethodCallQuickFix(QUICKFIX_DESCRIPTION, "isEmpty()") + ) + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/ReplaceSimpleMethodCallQuickFix.kt b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/ReplaceSimpleMethodCallQuickFix.kt new file mode 100644 index 0000000..0d31eac --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/ReplaceSimpleMethodCallQuickFix.kt @@ -0,0 +1,23 @@ +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 + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val element = descriptor.startElement + val factory = JavaPsiFacade.getElementFactory(element.project) + val methodCallExpression = element as? PsiMethodCallExpression ?: return + val oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return + val isEmptyExpression = + factory.createExpressionFromText("a.$replacementMethod", null) as PsiMethodCallExpression + isEmptyExpression.methodExpression.qualifierExpression!!.replace(oldQualifier) + element.replace(isEmptyExpression) + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index cf81350..7c8bb09 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -25,6 +25,8 @@ + diff --git a/src/test/java/de/platon42/intellij/playground/Playground.java b/src/test/java/de/platon42/intellij/playground/Playground.java index a0ada4b..bab2561 100644 --- a/src/test/java/de/platon42/intellij/playground/Playground.java +++ b/src/test/java/de/platon42/intellij/playground/Playground.java @@ -1,5 +1,7 @@ package de.platon42.intellij.playground; +import org.assertj.core.api.AbstractStringAssert; + import java.util.ArrayList; import static org.assertj.core.api.Assertions.assertThat; @@ -48,4 +50,10 @@ public class Playground { assertThat("").isEqualTo(Boolean.TRUE); } + private void stringIsEmpty() { + String foo = "bar"; + AbstractStringAssert abstractStringAssert = assertThat(foo); + abstractStringAssert.isEqualTo(""); + } + } diff --git a/src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspectionTest.kt b/src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspectionTest.kt new file mode 100644 index 0000000..7b8c1af --- /dev/null +++ b/src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringIsEmptyInspectionTest.kt @@ -0,0 +1,21 @@ +package de.platon42.intellij.plugins.cajon.inspections + +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture +import de.platon42.intellij.jupiter.MyFixture +import de.platon42.intellij.jupiter.TestDataSubPath +import de.platon42.intellij.plugins.cajon.AbstractCajonTest +import org.junit.jupiter.api.Test + +internal class AssertThatStringIsEmptyInspectionTest : AbstractCajonTest() { + + @Test + @TestDataSubPath("inspections/StringIsEmpty") + internal fun assertThat_with_isEqualTo_emptyString_can_use_isEmpty(@MyFixture myFixture: JavaCodeInsightTestFixture) { + runTest { + myFixture.enableInspections(AssertThatStringIsEmptyInspection::class.java) + myFixture.configureByFile("StringIsEmptyBefore.java") + executeQuickFixes(myFixture, Regex("Replace is.*"), 1) + myFixture.checkResultByFile("StringIsEmptyAfter.java") + } + } +} \ No newline at end of file diff --git a/src/test/resources/inspections/StringIsEmpty/StringIsEmptyAfter.java b/src/test/resources/inspections/StringIsEmpty/StringIsEmptyAfter.java new file mode 100644 index 0000000..e7031a5 --- /dev/null +++ b/src/test/resources/inspections/StringIsEmpty/StringIsEmptyAfter.java @@ -0,0 +1,11 @@ +import static org.assertj.core.api.Assertions.assertThat; + +public class StringIsEmpty { + + private void stringIsEmpty() { + String string = "string"; + + assertThat(string).isEqualTo("foo"); + assertThat(string).isEmpty(); + } +} diff --git a/src/test/resources/inspections/StringIsEmpty/StringIsEmptyBefore.java b/src/test/resources/inspections/StringIsEmpty/StringIsEmptyBefore.java new file mode 100644 index 0000000..4e32519 --- /dev/null +++ b/src/test/resources/inspections/StringIsEmpty/StringIsEmptyBefore.java @@ -0,0 +1,11 @@ +import static org.assertj.core.api.Assertions.assertThat; + +public class StringIsEmpty { + + private void stringIsEmpty() { + String string = "string"; + + assertThat(string).isEqualTo("foo"); + assertThat(string).isEqualTo(""); + } +}