From 1ba1363dd270bf1029d3698066be95116f770737 Mon Sep 17 00:00:00 2001 From: chrisly42 Date: Mon, 15 Aug 2022 22:44:45 +0200 Subject: [PATCH] Added AssertThatIsZeroOneInspection. --- README.md | 19 ++++- build.gradle | 1 + .../plugins/cajon/AssertJClassNames.kt | 32 ++++++++ .../intellij/plugins/cajon/MethodNames.kt | 50 ++++++++++++ .../inspections/AbstractAssertJInspection.kt | 15 ++-- .../AssertThatComparableInspection.kt | 8 +- .../AssertThatIsZeroOneInspection.kt | 81 +++++++++++++++++++ .../AssertThatStringExpressionInspection.kt | 4 +- src/main/resources/META-INF/plugin.xml | 2 + .../AssertThatIsZeroOne.html | 8 ++ .../AssertThatIsZeroOneInspectionTest.kt | 21 +++++ .../inspections/IsZeroOne/IsZeroOneAfter.java | 67 +++++++++++++++ .../IsZeroOne/IsZeroOneBefore.java | 67 +++++++++++++++ 13 files changed, 363 insertions(+), 12 deletions(-) create mode 100644 src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspection.kt create mode 100644 src/main/resources/inspectionDescriptions/AssertThatIsZeroOne.html create mode 100644 src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspectionTest.kt create mode 100644 src/test/resources/inspections/IsZeroOne/IsZeroOneAfter.java create mode 100644 src/test/resources/inspections/IsZeroOne/IsZeroOneBefore.java diff --git a/README.md b/README.md index fad2f65..084ca48 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the - AssertThatInstanceOf Moves ```instanceof``` expressions out of ```assertThat()```. - + ``` from: assertThat(object instanceof classname).isEqualTo(true); from: assertThat(object instanceof classname).isTrue(); @@ -171,6 +171,23 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the to: assertThat(object).isNotInstanceOf(classname.class); ``` +- AssertThatIsZeroOne + + Uses ```isZero()```, ```isNotZero()``` and ```isOne()``` instead. + Works with shorts, integers, longs, floats and doubles, and tries to evaluate + constant expressions, too. + + ``` + from: assertThat(numeric).isEqualTo(0); + to: assertThat(numeric).isZero(); + + from: assertThat(numeric).isNotEqualTo(0); + to: assertThat(numeric).isNotZero(); + + from: assertThat(numeric).isEqualTo(1); + to: assertThat(numeric).isOne(); + ``` + - AssertThatStringIsEmpty Uses ```isEmpty()``` for empty string assertions. diff --git a/build.gradle b/build.gradle index dd7faac..79cfdfa 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,7 @@ patchPluginXml {
  • Maintenance. Updated various dependencies (Kotlin 1.70.0) and AssertJ 3.23.1 and AssertJ-Guava 3.5.0.
  • Tried to fix unreproducable issue#9.
  • Added workaround for upcoming API change in IntelliJ breaking older releases. +
  • Added AssertThatIsZeroOne inspection demanded by issue#5.

    Full changelog available at Github project site.

    """) diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/AssertJClassNames.kt b/src/main/java/de/platon42/intellij/plugins/cajon/AssertJClassNames.kt index 6605812..349e9e0 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/AssertJClassNames.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/AssertJClassNames.kt @@ -12,68 +12,100 @@ class AssertJClassNames { @NonNls const val DESCRIPTABLE_INTERFACE = "org.assertj.core.api.Descriptable" + @NonNls const val EXTENSION_POINTS_INTERFACE = "org.assertj.core.api.ExtensionPoints" + @NonNls const val ENUMERABLE_ASSERT_INTERFACE = "org.assertj.core.api.EnumerableAssert" + @NonNls const val OBJECT_ENUMERABLE_ASSERT_INTERFACE = "org.assertj.core.api.ObjectEnumerableAssert" @NonNls const val ASSERT_INTERFACE = "org.assertj.core.api.Assert" + @NonNls const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert" + @NonNls const val ABSTRACT_OBJECT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractObjectAssert" + @NonNls const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert" + + @NonNls + const val ABSTRACT_SHORT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractShortAssert" + @NonNls const val ABSTRACT_INTEGER_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIntegerAssert" + @NonNls const val ABSTRACT_LONG_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractLongAssert" + @NonNls const val ABSTRACT_FLOAT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractFloatAssert" + @NonNls const val ABSTRACT_DOUBLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractDoubleAssert" + @NonNls const val ABSTRACT_COMPARABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractComparableAssert" + @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_MAP_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractMapAssert" + @NonNls const val ABSTRACT_BOOLEAN_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanArrayAssert" + @NonNls const val ABSTRACT_BYTE_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractByteArrayAssert" + @NonNls const val ABSTRACT_SHORT_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractShortArrayAssert" + @NonNls const val ABSTRACT_INT_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIntArrayAssert" + @NonNls const val ABSTRACT_LONG_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractLongArrayAssert" + @NonNls const val ABSTRACT_FLOAT_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractFloatArrayAssert" + @NonNls const val ABSTRACT_DOUBLE_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractDoubleArrayAssert" + @NonNls const val ABSTRACT_CHAR_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractCharArrayAssert" + @NonNls const val ABSTRACT_OBJECT_ARRAY_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractObjectArrayAssert" + @NonNls const val ABSTRACT_ITERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIterableAssert" + @NonNls const val ABSTRACT_FILE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractFileAssert" + @NonNls const val ABSTRACT_OPTIONAL_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractOptionalAssert" + @NonNls const val EXTRACTORS_CLASSNAME = "org.assertj.core.extractor.Extractors" @NonNls const val GUAVA_OPTIONAL_CLASSNAME = "com.google.common.base.Optional" + @NonNls const val GUAVA_ASSERTIONS_CLASSNAME = "org.assertj.guava.api.Assertions" + @NonNls const val GUAVA_OPTIONAL_ASSERTIONS_CLASSNAME = "org.assertj.guava.api.OptionalAssert" } diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/MethodNames.kt b/src/main/java/de/platon42/intellij/plugins/cajon/MethodNames.kt index 98dcbe3..308f30e 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/MethodNames.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/MethodNames.kt @@ -17,19 +17,25 @@ class MethodNames { @NonNls const val AS = "as" + @NonNls const val DESCRIBED_AS = "describedAs" + @NonNls const val IN_HEXADECIMAL = "inHexadecimal" + @NonNls const val IN_BINARY = "inBinary" @NonNls const val IS_EQUAL_TO = "isEqualTo" + @NonNls const val IS_NOT_EQUAL_TO = "isNotEqualTo" + @NonNls const val IS_SAME_AS = "isSameAs" + @NonNls const val IS_NOT_SAME_AS = "isNotSameAs" @@ -38,89 +44,133 @@ class MethodNames { @NonNls const val IS_GREATER_THAN = "isGreaterThan" + @NonNls const val IS_GREATER_THAN_OR_EQUAL_TO = "isGreaterThanOrEqualTo" + @NonNls const val IS_LESS_THAN = "isLessThan" + @NonNls const val IS_LESS_THAN_OR_EQUAL_TO = "isLessThanOrEqualTo" + @NonNls const val IS_ZERO = "isZero" + @NonNls const val IS_NOT_ZERO = "isNotZero" + + @NonNls + const val IS_ONE = "isOne" + @NonNls const val IS_TRUE = "isTrue" + @NonNls const val IS_FALSE = "isFalse" + @NonNls const val IS_NULL = "isNull" // terminal, returns void + @NonNls const val IS_NOT_NULL = "isNotNull" + @NonNls const val IS_CLOSE_TO = "isCloseTo" + @NonNls const val IS_NOT_CLOSE_TO = "isNotCloseTo" + @NonNls const val IS_INSTANCE_OF = "isInstanceOf" + @NonNls const val IS_NOT_INSTANCE_OF = "isNotInstanceOf" @NonNls const val IS_NULL_OR_EMPTY = "isNullOrEmpty" // terminal, returns void + @NonNls const val IS_EMPTY = "isEmpty" // terminal, returns void + @NonNls const val IS_NOT_EMPTY = "isNotEmpty" + @NonNls const val HAS_SIZE = "hasSize" + @NonNls const val HAS_SIZE_LESS_THAN = "hasSizeLessThan" + @NonNls const val HAS_SIZE_LESS_THAN_OR_EQUAL_TO = "hasSizeLessThanOrEqualTo" + @NonNls const val HAS_SIZE_GREATER_THAN = "hasSizeGreaterThan" + @NonNls const val HAS_SIZE_GREATER_THAN_OR_EQUAL_TO = "hasSizeGreaterThanOrEqualTo" + @NonNls const val HAS_SAME_SIZE_AS = "hasSameSizeAs" + @NonNls const val CONTAINS = "contains" + @NonNls const val CONTAINS_ONLY_ONCE = "containsOnlyOnce" + @NonNls const val DOES_NOT_CONTAIN = "doesNotContain" + @NonNls const val CONTAINS_EXACTLY = "containsExactly" + @NonNls const val CONTAINS_ALL = "containsAll" + @NonNls const val CONTAINS_KEY = "containsKey" + @NonNls const val DOES_NOT_CONTAIN_KEY = "doesNotContainKey" + @NonNls const val CONTAINS_VALUE = "containsValue" + @NonNls const val DOES_NOT_CONTAIN_VALUE = "doesNotContainValue" + @NonNls const val CONTAINS_ENTRY = "containsEntry" + @NonNls const val DOES_NOT_CONTAIN_ENTRY = "doesNotContainEntry" + @NonNls const val IS_EQUAL_TO_IC = "isEqualToIgnoringCase" + @NonNls const val IS_NOT_EQUAL_TO_IC = "isNotEqualToIgnoringCase" + @NonNls const val STARTS_WITH = "startsWith" + @NonNls const val ENDS_WITH = "endsWith" + @NonNls const val DOES_NOT_START_WITH = "doesNotStartWith" + @NonNls const val DOES_NOT_END_WITH = "doesNotEndWith" + @NonNls const val CONTAINS_SAME = "containsSame" + @NonNls const val IS_PRESENT = "isPresent" + @NonNls const val IS_NOT_PRESENT = "isNotPresent" 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 84404ab..a780187 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 @@ -15,6 +15,7 @@ import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_D import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_FLOAT_ASSERT_CLASSNAME import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_INTEGER_ASSERT_CLASSNAME import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_LONG_ASSERT_CLASSNAME +import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_SHORT_ASSERT_CLASSNAME import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_STRING_ASSERT_CLASSNAME import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ASSERTIONS_CLASSNAME import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ASSERT_INTERFACE @@ -88,6 +89,8 @@ abstract class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() .parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! val IS_EQUAL_TO_STRING = CallMatcher.instanceCall(ABSTRACT_STRING_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO) .parameterTypes(CommonClassNames.JAVA_LANG_STRING)!! + val IS_EQUAL_TO_SHORT = CallMatcher.instanceCall(ABSTRACT_SHORT_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO) + .parameterTypes("short")!! val IS_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO) .parameterTypes("int")!! val IS_EQUAL_TO_LONG = CallMatcher.instanceCall(ABSTRACT_LONG_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO) @@ -103,6 +106,8 @@ abstract class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() .parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! val IS_NOT_EQUAL_TO_BOOLEAN = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO) .parameterTypes("boolean")!! + val IS_NOT_EQUAL_TO_SHORT = CallMatcher.instanceCall(ABSTRACT_SHORT_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO) + .parameterTypes("short")!! val IS_NOT_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO) .parameterTypes("int")!! val IS_NOT_EQUAL_TO_LONG = CallMatcher.instanceCall(ABSTRACT_LONG_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO) @@ -155,15 +160,15 @@ abstract class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() .parameterCount(0)!! val IS_NOT_ZERO_LONG = CallMatcher.instanceCall(ABSTRACT_LONG_ASSERT_CLASSNAME, MethodNames.IS_NOT_ZERO) .parameterCount(0)!! - val IS_ONE = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isOne") + val IS_ONE_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isOne") .parameterCount(0)!! - val IS_NEGATIVE = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNegative") + val IS_NEGATIVE_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNegative") .parameterCount(0)!! - val IS_NOT_NEGATIVE = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNotNegative") + val IS_NOT_NEGATIVE_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNotNegative") .parameterCount(0)!! - val IS_POSITIVE = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isPositive") + val IS_POSITIVE_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isPositive") .parameterCount(0)!! - val IS_NOT_POSITIVE = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNotPositive") + val IS_NOT_POSITIVE_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNotPositive") .parameterCount(0)!! val IS_TRUE = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, MethodNames.IS_TRUE) diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatComparableInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatComparableInspection.kt index 6b6d117..80ad7b9 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatComparableInspection.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatComparableInspection.kt @@ -52,7 +52,7 @@ class AssertThatComparableInspection : AbstractMoveOutInspection() { ), MoveOutMapping( COMPARABLE_COMPARE_TO, - MethodNames.IS_GREATER_THAN_OR_EQUAL_TO, expectedMatcher = IS_NOT_NEGATIVE, replaceFromOriginalMethod = true + MethodNames.IS_GREATER_THAN_OR_EQUAL_TO, expectedMatcher = IS_NOT_NEGATIVE_INT, replaceFromOriginalMethod = true ), MoveOutMapping( @@ -67,7 +67,7 @@ class AssertThatComparableInspection : AbstractMoveOutInspection() { ), MoveOutMapping( COMPARABLE_COMPARE_TO, - MethodNames.IS_GREATER_THAN, expectedMatcher = CallMatcher.anyOf(IS_POSITIVE, IS_ONE), replaceFromOriginalMethod = true + MethodNames.IS_GREATER_THAN, expectedMatcher = CallMatcher.anyOf(IS_POSITIVE_INT, IS_ONE_INT), replaceFromOriginalMethod = true ), MoveOutMapping( @@ -82,7 +82,7 @@ class AssertThatComparableInspection : AbstractMoveOutInspection() { ), MoveOutMapping( COMPARABLE_COMPARE_TO, - MethodNames.IS_LESS_THAN_OR_EQUAL_TO, expectedMatcher = IS_NOT_POSITIVE, replaceFromOriginalMethod = true + MethodNames.IS_LESS_THAN_OR_EQUAL_TO, expectedMatcher = IS_NOT_POSITIVE_INT, replaceFromOriginalMethod = true ), MoveOutMapping( @@ -97,7 +97,7 @@ class AssertThatComparableInspection : AbstractMoveOutInspection() { ), MoveOutMapping( COMPARABLE_COMPARE_TO, - MethodNames.IS_LESS_THAN, expectedMatcher = IS_NEGATIVE, replaceFromOriginalMethod = true + MethodNames.IS_LESS_THAN, expectedMatcher = IS_NEGATIVE_INT, replaceFromOriginalMethod = true ) ) } diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspection.kt new file mode 100644 index 0000000..749392b --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspection.kt @@ -0,0 +1,81 @@ +package de.platon42.intellij.plugins.cajon.inspections + +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.psi.JavaElementVisitor +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiMethodCallExpression +import com.intellij.psi.util.TypeConversionUtil +import com.siyeh.ig.callMatcher.CallMatcher +import de.platon42.intellij.plugins.cajon.* + +class AssertThatIsZeroOneInspection : AbstractAssertJInspection() { + + companion object { + private const val DISPLAY_NAME = "Asserting a zero or one value" + } + + 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 (!expression.hasAssertThat()) return + val isEqualTo = CallMatcher.anyOf(IS_EQUAL_TO_OBJECT, IS_EQUAL_TO_SHORT, IS_EQUAL_TO_INT, IS_EQUAL_TO_LONG, IS_EQUAL_TO_FLOAT, IS_EQUAL_TO_DOUBLE).test(expression) + val isNotEqualTo = + CallMatcher.anyOf(IS_NOT_EQUAL_TO_OBJECT, IS_NOT_EQUAL_TO_SHORT, IS_NOT_EQUAL_TO_INT, IS_NOT_EQUAL_TO_LONG, IS_NOT_EQUAL_TO_FLOAT, IS_NOT_EQUAL_TO_DOUBLE) + .test(expression) + + if (!(isEqualTo || isNotEqualTo)) return + + val expectedExpression = expression.firstArg + if (!TypeConversionUtil.isNumericType(expectedExpression.type)) return + + val expectedResult = expression.calculateConstantParameterValue(0) ?: return + var isZero = false + var isOne = false + when (expectedResult) { + is Short -> { + isZero = (expectedResult == 0.toShort()) + isOne = (expectedResult == 1.toShort()) + } + + is Int -> { + isZero = (expectedResult == 0) + isOne = (expectedResult == 1) + } + + is Long -> { + isZero = (expectedResult == 0L) + isOne = (expectedResult == 1L) + } + + is Float -> { + isZero = (expectedResult == 0.0f) + isOne = (expectedResult == 1.0f) + } + + is Double -> { + isZero = (expectedResult == 0.0) + isOne = (expectedResult == 1.0) + } + } + if (isZero || isOne) { + val numericBaseClass = listOf( + AssertJClassNames.ABSTRACT_SHORT_ASSERT_CLASSNAME, + AssertJClassNames.ABSTRACT_INTEGER_ASSERT_CLASSNAME, + AssertJClassNames.ABSTRACT_LONG_ASSERT_CLASSNAME, + AssertJClassNames.ABSTRACT_FLOAT_ASSERT_CLASSNAME, + AssertJClassNames.ABSTRACT_DOUBLE_ASSERT_CLASSNAME + ).any { checkAssertedType(expression, it) } + if (!numericBaseClass) return + } + if (isZero) { + registerSimplifyMethod(holder, expression, isEqualTo.map(MethodNames.IS_ZERO, MethodNames.IS_NOT_ZERO)) + } else if (isOne && isEqualTo) { + registerSimplifyMethod(holder, expression, MethodNames.IS_ONE) + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringExpressionInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringExpressionInspection.kt index 9a22b32..e548731 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringExpressionInspection.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatStringExpressionInspection.kt @@ -94,7 +94,7 @@ class AssertThatStringExpressionInspection : AbstractMoveOutInspection() { MoveOutMapping( STRING_INDEX_OF, - MethodNames.CONTAINS, expectedMatcher = IS_NOT_NEGATIVE, replaceFromOriginalMethod = true + MethodNames.CONTAINS, expectedMatcher = IS_NOT_NEGATIVE_INT, replaceFromOriginalMethod = true ), MoveOutMapping( STRING_INDEX_OF, @@ -119,7 +119,7 @@ class AssertThatStringExpressionInspection : AbstractMoveOutInspection() { ), MoveOutMapping( STRING_INDEX_OF, - MethodNames.DOES_NOT_CONTAIN, expectedMatcher = IS_NEGATIVE, replaceFromOriginalMethod = true + MethodNames.DOES_NOT_CONTAIN, expectedMatcher = IS_NEGATIVE_INT, replaceFromOriginalMethod = true ), MoveOutMapping( STRING_INDEX_OF, diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 25e1227..d60f10c 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -28,6 +28,8 @@ implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatBooleanConditionInspection"/> + + +Turns assertThat(numeric).isEqualTo(0/1) into assertThat(numeric).isZero()/isOne() +or assertThat(numeric).isNotEqualTo(0) into assertThat(numeric).isNotZero(). + +
    Also works with constant expressions. + + \ No newline at end of file diff --git a/src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspectionTest.kt b/src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspectionTest.kt new file mode 100644 index 0000000..a2e2c37 --- /dev/null +++ b/src/test/java/de/platon42/intellij/plugins/cajon/inspections/AssertThatIsZeroOneInspectionTest.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 AssertThatIsZeroOneInspectionTest : AbstractCajonTest() { + + @Test + @TestDataSubPath("inspections/IsZeroOne") + internal fun assertThat_with_isEqualTo_zero_or_one_can_use_isZero_or_isOne_plus_isNotZero(@MyFixture myFixture: JavaCodeInsightTestFixture) { + myFixture.enableInspections(AssertThatIsZeroOneInspection::class.java) + myFixture.configureByFile("IsZeroOneBefore.java") + executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isZero()"), 10) + executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isOne()"), 10) + executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isNotZero()"), 10) + myFixture.checkResultByFile("IsZeroOneAfter.java") + } +} \ No newline at end of file diff --git a/src/test/resources/inspections/IsZeroOne/IsZeroOneAfter.java b/src/test/resources/inspections/IsZeroOne/IsZeroOneAfter.java new file mode 100644 index 0000000..6ac3eb7 --- /dev/null +++ b/src/test/resources/inspections/IsZeroOne/IsZeroOneAfter.java @@ -0,0 +1,67 @@ +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +public class IsZeroOne { + + private void isZeroOne() { + short shortValue = 0; + int intValue = 0; + long longValue = 0L; + float floatValue = 0.0f; + double doubleValue = 0.0; + + assertThat(shortValue).as("foo").isZero(); + assertThat(shortValue).isZero(); + assertThat(shortValue).as("foo").isOne(); + assertThat(shortValue).isOne(); + + assertThat(shortValue).as("foo").isNotZero(); + assertThat(shortValue).isNotZero(); + assertThat(shortValue).as("foo").isNotEqualTo(1); + assertThat(shortValue).isNotEqualTo(0 + 1); + + assertThat(intValue).as("foo").isZero(); + assertThat(intValue).isZero(); + assertThat(intValue).as("foo").isOne(); + assertThat(intValue).isOne(); + + assertThat(intValue).as("foo").isNotZero(); + assertThat(intValue).isNotZero(); + assertThat(intValue).as("foo").isNotEqualTo(1); + assertThat(intValue).isNotEqualTo(0 + 1); + + assertThat(longValue).as("foo").isZero(); + assertThat(longValue).isZero(); + assertThat(longValue).as("foo").isOne(); + assertThat(longValue).isOne(); + + assertThat(longValue).as("foo").isNotZero(); + assertThat(longValue).isNotZero(); + assertThat(longValue).as("foo").isNotEqualTo(1L); + assertThat(longValue).isNotEqualTo(0L + 1L); + + assertThat(floatValue).as("foo").isZero(); + assertThat(floatValue).isZero(); + assertThat(floatValue).as("foo").isOne(); + assertThat(floatValue).isOne(); + + assertThat(floatValue).as("foo").isNotZero(); + assertThat(floatValue).isNotZero(); + assertThat(floatValue).as("foo").isNotEqualTo(1.0f); + assertThat(floatValue).isNotEqualTo(0.0f + 1.0f); + + assertThat(doubleValue).as("foo").isZero(); + assertThat(doubleValue).isZero(); + assertThat(doubleValue).as("foo").isOne(); + assertThat(doubleValue).isOne(); + + assertThat(doubleValue).as("foo").isNotZero(); + assertThat(doubleValue).isNotZero(); + assertThat(doubleValue).as("foo").isNotEqualTo(1.0); + assertThat(doubleValue).isNotEqualTo(0.0 + 1.0); + + assertThat(intValue).as("foo").isEqualTo(2); + + fail("oh no!"); + } +} diff --git a/src/test/resources/inspections/IsZeroOne/IsZeroOneBefore.java b/src/test/resources/inspections/IsZeroOne/IsZeroOneBefore.java new file mode 100644 index 0000000..000e215 --- /dev/null +++ b/src/test/resources/inspections/IsZeroOne/IsZeroOneBefore.java @@ -0,0 +1,67 @@ +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +public class IsZeroOne { + + private void isZeroOne() { + short shortValue = 0; + int intValue = 0; + long longValue = 0L; + float floatValue = 0.0f; + double doubleValue = 0.0; + + assertThat(shortValue).as("foo").isEqualTo(0); + assertThat(shortValue).isEqualTo(1 - 1); + assertThat(shortValue).as("foo").isEqualTo(1); + assertThat(shortValue).isEqualTo(0 + 1); + + assertThat(shortValue).as("foo").isNotEqualTo(0); + assertThat(shortValue).isNotEqualTo(1 - 1); + assertThat(shortValue).as("foo").isNotEqualTo(1); + assertThat(shortValue).isNotEqualTo(0 + 1); + + assertThat(intValue).as("foo").isEqualTo(0); + assertThat(intValue).isEqualTo(1 - 1); + assertThat(intValue).as("foo").isEqualTo(1); + assertThat(intValue).isEqualTo(0 + 1); + + assertThat(intValue).as("foo").isNotEqualTo(0); + assertThat(intValue).isNotEqualTo(1 - 1); + assertThat(intValue).as("foo").isNotEqualTo(1); + assertThat(intValue).isNotEqualTo(0 + 1); + + assertThat(longValue).as("foo").isEqualTo(0L); + assertThat(longValue).isEqualTo(1L - 1L); + assertThat(longValue).as("foo").isEqualTo(1L); + assertThat(longValue).isEqualTo(0L + 1L); + + assertThat(longValue).as("foo").isNotEqualTo(0L); + assertThat(longValue).isNotEqualTo(1L - 1L); + assertThat(longValue).as("foo").isNotEqualTo(1L); + assertThat(longValue).isNotEqualTo(0L + 1L); + + assertThat(floatValue).as("foo").isEqualTo(0.0f); + assertThat(floatValue).isEqualTo(1.0f - 1.0f); + assertThat(floatValue).as("foo").isEqualTo(1.0f); + assertThat(floatValue).isEqualTo(0.0f + 1.0f); + + assertThat(floatValue).as("foo").isNotEqualTo(0.0f); + assertThat(floatValue).isNotEqualTo(1.0f - 1.0f); + assertThat(floatValue).as("foo").isNotEqualTo(1.0f); + assertThat(floatValue).isNotEqualTo(0.0f + 1.0f); + + assertThat(doubleValue).as("foo").isEqualTo(0.0); + assertThat(doubleValue).isEqualTo(1.0 - 1.0); + assertThat(doubleValue).as("foo").isEqualTo(1.0); + assertThat(doubleValue).isEqualTo(0.0 + 1.0); + + assertThat(doubleValue).as("foo").isNotEqualTo(0.0); + assertThat(doubleValue).isNotEqualTo(1.0 - 1.0); + assertThat(doubleValue).as("foo").isNotEqualTo(1.0); + assertThat(doubleValue).isNotEqualTo(0.0 + 1.0); + + assertThat(intValue).as("foo").isEqualTo(2); + + fail("oh no!"); + } +}