Compare commits

..
12 Commits
Author SHA1 Message Date
chrisly42 48349a6528 Prepared for release. 2020-02-25 14:39:30 +01:00
chrisly42 9b25e50183 Improvements for TwistedAssertionInspection to no longer report .class types as constant to bother, nor matches() and doesNotMatch() for regexps. If both sides are constants, they will only show as weak problems. 2020-02-17 20:17:33 +01:00
chrisly42 e8ce8ce2c6 BogusAssertionInspection will no longer warn if the expression contains method calls and now tries to avoid valid hashCode() and equals() tests. 2020-02-17 18:33:11 +01:00
chrisly42 62f59b0fe2 Added new TwistedAssertion inspection that will warn about assertions with the actual expression being a constant indicating swapped use of actual and expected expressions.
Added new BogusAssertion inspection that showing typical copy and paste errors where actual and expected expressions are the same.
2020-02-14 13:36:04 +01:00
chrisly42 58298fabc6 Extended Testing-Framework to work around IntelliJ IDEA introducing an unwanted assertj-core dependency conflicting with our newer one. 2020-02-08 16:33:38 +01:00
chrisly42 77d3608fd3 Minor NPE Bugfix. Fixed use of "experimental API". Upgraded dependencies. 2020-02-04 20:01:05 +01:00
chrisly42 a0909d8c39 Prepared release. 2019-11-19 19:47:40 +01:00
chrisly42 5113cc15ab Added hasSize(), isEmpty() and isNotEmpty() for AssertThatFileExpression when using AssertJ >= 3.14.0. 2019-11-18 21:13:30 +01:00
chrisly42 ae2076a425 Bumped to AssertJ 3.14.0, AssertJ-Guava 3.3.0, Kotlin 1.3.60. IntelliJ-Plugin 0.4.13, Jacoco 0.8.5 2019-11-18 21:10:45 +01:00
chrisly42 42429c0f72 Added AssertThatComparableExpression for funny compareTo() uses. 2019-11-17 21:21:45 +01:00
chrisly42 8133f3850f Added first version of AssertThatPathExpression for a limited number transformations (more stuff is possible, but requires detection and transformation of static Files-methods). 2019-11-17 19:10:41 +01:00
chrisly42 8d03b3734c Fixed a lapsuus in AssertThatFileExpression also transforming listFiles() with a filter argument. 2019-11-17 17:14:28 +01:00
42 changed files with 1667 additions and 76 deletions
+176 -2
View File
@@ -34,6 +34,10 @@ Then AssertJ would tell you the _actual contents_ of the collection on failure.
The plugin also supports the conversion of the most common JUnit 4 assertions to AssertJ.
## Wrong use of AssertJ
Cajon also warns about bogus or incorrect uses of AssertJ.
## Lookup and refactoring of string-based extracting()
AssertJ allows [extracting POJO fields/properties on iterables/arrays](http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#extracted-properties-assertion).
@@ -234,6 +238,35 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the
to: assertThat(objActual).hasSameHashCodeAs(objExpected);
```
- AssertThatComparableExpression
Handles ```compareTo()``` inside an expected expression.
```
from: assertThat(obj1.compareTo(obj2)).isEqualTo(0);
to: assertThat(obj1).isEqualByComparingTo(obj2);
from: assertThat(obj1.compareTo(obj2)).isNotZero();
to: assertThat(obj1).isNotEqualByComparingTo(obj2);
from: assertThat(obj1.compareTo(obj2)).isNotEqualTo(-1);
from: assertThat(obj1.compareTo(obj2)).isGreaterThanOrEqualTo(0);
from: assertThat(obj1.compareTo(obj2)).isGreaterThan(-1);
from: assertThat(obj1.compareTo(obj2)).isNotNegative();
to: assertThat(obj1).isGreaterThanOrEqualTo(obj2);
from: assertThat(obj1.compareTo(obj2)).isOne();
to: assertThat(obj1).isGreaterThan(obj2);
from: assertThat(obj1.compareTo(obj2)).isNotPositive();
to: assertThat(obj1).isLessThanOrEqualTo(obj2);
from: assertThat(obj1.compareTo(obj2)).isLessThan(0);
to: assertThat(obj1).isLessThan(obj2);
```
Several more combinations omitted...
- AssertThatCollectionOrMapExpression
Moves ```Collection``` and ```Map``` operations inside ```assertThat()``` out.
@@ -333,6 +366,47 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the
to: assertThat(file).isNotEmptyDirectory();
```
and additionally with AssertJ 3.14.0 or later
```
from: assertThat(file.length()).isEqualTo(0);
from: assertThat(file.length()).isZero();
to: assertThat(file).isEmpty();
from: assertThat(file.length()).isNotEqualTo(0);
from: assertThat(file.length()).isNotZero();
to: assertThat(file).isNotEmpty();
from: assertThat(file.length()).isEqualTo(len);
to: assertThat(file).hasSize(len);
```
- AssertThatPathExpression
Moves ```Path``` method calls inside ```assertThat()``` out.
Note: Uses hasParentRaw() instead of hasParent() for quickfixes, because it is semantically
equivalent. For most cases though, hasParent() will show identical behavior.
```
from: assertThat(path.isAbsolute()).isTrue();
to: assertThat(path).isAbsolute();
from: assertThat(path.isAbsolute()).isFalse();
to: assertThat(path).isRelative();
from: assertThat(path.getParent()).isEqualTo(pathname);
to: assertThat(path).hasParentRaw(pathname);
from: assertThat(path.getParent()).isNull();
to: assertThat(path).hasNoParentRaw();
from: assertThat(path.startsWith(otherPath)).isTrue();
to: assertThat(path).startsWithRaw(otherPath);
from: assertThat(path.endsWith(otherPath)).isTrue();
to: assertThat(path).endsWithRaw(otherPath);
```
- AssertThatEnumerableIsEmpty
Uses ```isEmpty()``` for ```hasSize(0)``` iterable assertions instead.
@@ -414,6 +488,84 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the
```
...and many, many more combinations (more than 150).
- TwistedAssertion
Examines the actual expression for common mistakes such as mixing expected and actual expression.
For simple cases, a quick fix is offered to swap them. Otherwise, only a warning is issued.
```
from: assertThat(5).isEqualTo(variable);
to: assertThat(variable).isEqualTo(5);
from: assertThat(8.0).isGreaterThan(variable);
to: assertThat(variable).isLessOrEqualTo(8.0);
```
There are, of course, more variations of the theme.
If both sides of an assertion are constant expressions, the problem will only appear as
a weak warning without a quick fix.
Constants used on the actual side of ```.matches()``` and ```doesNotMatch()``` will not be
reported for regular expression testing.
Neither will a ```Class``` type be considered a constant in the classic sense, so
```assertThat(SomeClass.class).isAssignableFrom(SomeOtherClass.class)``` will not be reported.
- BogusAssertion
Sometimes programmers make copy and paste or logical errors writing down assertions
that will never fail due to the same actual and expected assertions.
This inspection will warn about obvious cases such as the following ones.
```
assertThat(object).isEqualTo(object);
assertThat(object).isSameAs(object);
assertThat(object).hasSameClassAs(object);
assertThat(object).hasSameHashCodeAs(object);
assertThat(array).hasSameSizeAs(array);
assertThat(array).contains(array);
assertThat(array).containsAnyOf(array);
assertThat(array).containsExactly(array);
assertThat(array).containsExactlyInAnyOrder(array);
assertThat(array).containsExactlyInAnyOrder(array);
assertThat(array).containsOnly(array);
assertThat(array).containsSequence(array);
assertThat(array).containsSubsequence(array);
assertThat(array).startsWith(array);
assertThat(array).endsWith(array);
assertThat(enumerable).hasSameSizeAs(enumerable);
assertThat(iterable).hasSameElementsAs(iterable);
assertThat(iterable).containsAll(iterable);
assertThat(iterable).containsAnyElementOf(iterable);
assertThat(iterable).containsOnlyElementsOf(iterable);
assertThat(iterable).containsExactlyElementsOf(iterable);
assertThat(iterable).containsSequence(iterable);
assertThat(iterable).containsSubsequence(iterable);
assertThat(charSeq).isEqualToIgnoringCase(charSeq);
assertThat(charSeq).startsWith(charSeq);
assertThat(charSeq).endsWith(charSeq);
assertThat(charSeq).containsSequence(charSeq);
assertThat(charSeq).containsSubsequence(charSeq);
assertThat(map).containsAllEntriesOf(map);
assertThat(map).containsExactlyEntriesOf(map);
assertThat(map).containsExactlyInAnyOrderEntriesOf(map);
assertThat(map).hasSameSizeAs(map);
```
Note that expressions with method calls will not cause a warning as the method call might have side effects
that result in the assertion not being bogus at all.
If the assertions is either ```isEqualTo()``` or ```hasSameHashCodeAs()``` it may be checking custom
```equals()``` or ```hashCode()``` behavior. If the test method name containing the statement has a
name that contains 'equal' or 'hashcode' (case insensitive), the warning will be weakened to information
level.
- ImplicitAssertion
Detects and removes implicit use of ```isNotNull()```, ```isNotEmpty()``` and
@@ -631,8 +783,7 @@ Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for yo
## Planned features
- More Optional fixes such as ```opt1.get() == opt2.get()``` etc.
- More moving out of methods for Path, LocalDate/Time etc.
- Converting ```foo.compareTo(bar) == 0``` to ```isEqualTo()``` (yes, I've *really* seen code like that)
- More moving out of methods for LocalDate/Time etc.
- Extraction with property names to lambda/method reference with Java 8
```
@@ -642,6 +793,29 @@ Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for yo
## Changelog
#### V1.9 (25-Feb-20) Mardi Gras Edition
- TwistedAssertion inspection will no longer warn for ```.matches()``` and ```doesNotMatch()``` for regular expressions.
Apparently, ```assertThat("somestring").matches(regex)``` is a valid test if the regex is what needs to be tested.
If the actual expression is of ```Class``` type, this will no longer be reported.
- If the expected expression in TwistedAssertion is also a constant, the warning will be weakened and
no quick fix will be available.
- BogusAssertion inspection will no longer warn if the expression contains method calls.
Moreover, for assertions of ```isEqualTo()``` and ```hasSameHashCodeAs()```, AND if the containing method name contains 'equal' or 'hashcode',
the warning will be reduced to information level as the assertion may be testing ```equals()``` or ```hashCode()``` for validity.
#### V1.8 (14-Feb-20) Valentine Edition
- Maintenance. Removed experimental API use. Updated dependencies. Fixed testing problems introduced with IntelliJ IDEA 2019.3
- Added new TwistedAssertion inspection that will warn about assertions with the actual expression being a constant indicating
swapped use of actual and expected expressions.
- Added new BogusAssertion inspection that showing typical copy and paste errors where actual and expected expressions are the same.
#### V1.7 (19-Nov-19)
- Fixed a lapsuus in AssertThatFileExpression also transforming ```.listFiles()``` with a filter argument.
- Added first version of AssertThatPathExpression for a limited number transformations (more stuff is possible,
but requires detection and transformation of static ```Files```-methods).
- Added AssertThatComparableExpression for funny ```compareTo()``` uses.
- Added ```hasSize(), isEmpty()``` and ```isNotEmpty()``` for AssertThatFileExpression when using AssertJ >= 3.14.0.
#### V1.6 (30-Sep-19)
- Really fixed AssertThatGuavaOptional inspections to avoid conversions from ```.get()``` to ```.contains()```
for array types. Sigh. Shouldn't be working >12h a day and then do some more stuff at home.
+26 -19
View File
@@ -1,13 +1,13 @@
plugins {
id 'java'
id 'org.jetbrains.intellij' version '0.4.10'
id 'org.jetbrains.kotlin.jvm' version '1.3.50'
id 'org.jetbrains.intellij' version '0.4.16'
id 'org.jetbrains.kotlin.jvm' version '1.3.61'
id 'jacoco'
id 'com.github.kt3k.coveralls' version '2.8.4'
id 'com.github.kt3k.coveralls' version '2.9.0'
}
group 'de.platon42'
version '1.6'
version '1.9'
repositories {
mavenCentral()
@@ -20,10 +20,10 @@ repositories {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile "org.assertj:assertj-core:3.13.2"
testCompile "org.assertj:assertj-guava:3.2.1"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
testCompile "org.assertj:assertj-core:3.15.0"
testCompile "org.assertj:assertj-guava:3.3.0"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
testImplementation "org.jetbrains.kotlin:kotlin-test"
// testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
}
@@ -35,7 +35,7 @@ compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
intellij {
version '2019.2.3'
version '2019.3.3'
// pluginName 'Concise AssertJ Optimizing Nitpicker (Cajon)'
updateSinceUntilBuild false
plugins = ['java']
@@ -43,16 +43,23 @@ intellij {
patchPluginXml {
changeNotes """
<h4>V1.6 (30-Sep-19)</h4>
<h4>V1.9 (25-Feb-20) Mardi Gras Edition</h4>
<ul>
<li>Really fixed AssertThatGuavaOptional inspections to avoid conversions from .get() to .contains()
for array types. Sigh. Shouldn't be working &gt;12h a day and then do some more stuff at home.
<li>Fixed a bug in AssertThatBinaryExpression inspection for assertThat(null != expression) and related
that would not correctly invert the condition on transformation.
<li>Added new AssertThatFileExpression to move out many common methods from inside the
assertThat() expression (exists(), getName(), getParent() and many more).
<li>Added several transformations to AssertThatStringExpression inspection.
Specifically, uses of matches(), compareToIgnoreCase(), indexOf(), and trim().
<li>TwistedAssertion inspection will no longer warn for .matches() and doesNotMatch() for regular expressions.
Apparently, assertThat("somestring").matches(regex) is a valid test if the regex is what needs to be tested.
If the actual expression is of Class type, this will no longer be reported.
<li>If the expected expression in TwistedAssertion is also a constant, the warning will be weakened and
no quick fix will be available.
<li>BogusAssertion inspection will no longer warn if the expression contains method calls.
Moreover, for assertions of isEqualTo() and hasSameHashCodeAs(), AND if the containing method name contains 'equal' or 'hashcode',
the warning will be reduced to information level as the assertion may be testing equals() or hashCode() for validity.
</ul>
<h4>V1.8 (14-Feb-20) Valentine Edition</h4>
<ul>
<li>Maintenance. Removed experimental API use. Updated dependencies. Fixed testing problems introduced with IntelliJ IDEA 2019.3.x
<li>Added new TwistedAssertion inspection that will warn about assertions with the actual expression being a constant indicating
swapped use of actual and expected expressions.
<li>Added new BogusAssertion inspection that showing typical copy and paste errors where actual and expected expressions are the same.
</ul>
<p>Full changelog available at <a href="https://github.com/chrisly42/cajon-plugin#changelog">Github project site</a>.</p>
"""
@@ -66,7 +73,7 @@ test {
}
jacoco {
toolVersion = '0.8.4'
toolVersion = '0.8.5'
}
jacocoTestReport {
@@ -44,10 +44,28 @@ class AssertJClassNames {
@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"
@@ -1,6 +1,5 @@
package de.platon42.intellij.plugins.cajon
import com.intellij.lang.jvm.JvmModifier
import com.intellij.psi.*
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.JavaCodeStyleManager
@@ -33,7 +32,7 @@ fun PsiElement.findOutmostMethodCall(): PsiMethodCallExpression? {
fun PsiElement.findStaticMethodCall(): PsiMethodCallExpression? {
var elem: PsiElement? = this
while (elem != null) {
if ((elem is PsiMethodCallExpression) && (elem.resolveMethod()?.hasModifier(JvmModifier.STATIC) == true)) {
if ((elem is PsiMethodCallExpression) && (elem.resolveMethod()?.hasModifierProperty(PsiModifier.STATIC) == true)) {
return elem
}
elem = elem.firstChild
@@ -44,7 +43,7 @@ fun PsiElement.findStaticMethodCall(): PsiMethodCallExpression? {
fun PsiElement.gatherAssertionCalls(): List<PsiMethodCallExpression> {
val assertThatMethodCall = findStaticMethodCall() ?: return emptyList()
return assertThatMethodCall.collectMethodCallsUpToStatement()
.filterNot { NOT_ACTUAL_ASSERTIONS.test(it) }
.filterNot(NOT_ACTUAL_ASSERTIONS::test)
.toList()
}
@@ -137,9 +137,15 @@ abstract class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool()
val IS_LESS_THAN_OR_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_LESS_THAN_OR_EQUAL_TO)
.parameterTypes("int")!!
val IS_ZERO = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_ZERO)
val IS_ZERO_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_ZERO)
.parameterCount(0)!!
val IS_NOT_ZERO = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_NOT_ZERO)
val IS_NOT_ZERO_INT = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_NOT_ZERO)
.parameterCount(0)!!
val IS_ZERO_LONG = CallMatcher.instanceCall(ABSTRACT_LONG_ASSERT_CLASSNAME, MethodNames.IS_ZERO)
.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")
.parameterCount(0)!!
val IS_NEGATIVE = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, "isNegative")
.parameterCount(0)!!
@@ -42,7 +42,8 @@ abstract class AbstractMoveOutInspection : AbstractAssertJInspection() {
MoveOutMethodCallExpressionQuickFix(
desc, method,
replaceOnlyThisMethod = mapping.expectedMatcher,
replaceFromOriginalMethod = mapping.replaceFromOriginalMethod
replaceFromOriginalMethod = mapping.replaceFromOriginalMethod,
noExpectedExpression = mapping.noExpectedExpression
)
}
}
@@ -57,6 +58,7 @@ abstract class AbstractMoveOutInspection : AbstractAssertJInspection() {
val expectNullNonNull: Boolean? = null,
val expectedMatcher: CallMatcher? = null,
val replaceFromOriginalMethod: Boolean = false,
val noExpectedExpression: Boolean = false,
val additionalCondition: ((PsiExpressionStatement, PsiMethodCallExpression) -> Boolean)? = null
)
}
@@ -0,0 +1,115 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.calculateConstantValue
import de.platon42.intellij.plugins.cajon.firstArg
class AssertThatComparableInspection : AbstractMoveOutInspection() {
companion object {
private const val DISPLAY_NAME = "Asserting a compareTo() expression"
private val ARG_IS_ZERO_CONST: (PsiExpressionStatement, PsiMethodCallExpression) -> Boolean = { _, call -> call.firstArg.calculateConstantValue() == 0 }
private val ARG_IS_PLUS_ONE_CONST: (PsiExpressionStatement, PsiMethodCallExpression) -> Boolean = { _, call -> call.firstArg.calculateConstantValue() == 1 }
private val ARG_IS_MINUS_ONE_CONST: (PsiExpressionStatement, PsiMethodCallExpression) -> Boolean = { _, call -> call.firstArg.calculateConstantValue() == -1 }
private val COMPARABLE_COMPARE_TO =
CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_COMPARABLE, "compareTo").parameterCount(1)
private val MAPPINGS = listOf(
MoveOutMapping(
COMPARABLE_COMPARE_TO,
"isEqualByComparingTo", expectedMatcher = IS_EQUAL_TO_INT, replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
"isEqualByComparingTo", expectedMatcher = IS_ZERO_INT, replaceFromOriginalMethod = true
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
"isNotEqualByComparingTo", expectedMatcher = IS_NOT_EQUAL_TO_INT, replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
"isNotEqualByComparingTo", expectedMatcher = IS_NOT_ZERO_INT, replaceFromOriginalMethod = true
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_GREATER_THAN_OR_EQUAL_TO, expectedMatcher = IS_GREATER_THAN_OR_EQUAL_TO_INT, replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_GREATER_THAN_OR_EQUAL_TO, expectedMatcher = CallMatcher.anyOf(IS_NOT_EQUAL_TO_INT, IS_GREATER_THAN_INT), replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_MINUS_ONE_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_GREATER_THAN_OR_EQUAL_TO, expectedMatcher = IS_NOT_NEGATIVE, replaceFromOriginalMethod = true
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_GREATER_THAN, expectedMatcher = CallMatcher.anyOf(IS_EQUAL_TO_INT, IS_GREATER_THAN_OR_EQUAL_TO_INT), replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_PLUS_ONE_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_GREATER_THAN, expectedMatcher = IS_GREATER_THAN_INT, replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_GREATER_THAN, expectedMatcher = CallMatcher.anyOf(IS_POSITIVE, IS_ONE), replaceFromOriginalMethod = true
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_LESS_THAN_OR_EQUAL_TO, expectedMatcher = IS_LESS_THAN_OR_EQUAL_TO_INT, replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_LESS_THAN_OR_EQUAL_TO, expectedMatcher = CallMatcher.anyOf(IS_NOT_EQUAL_TO_INT, IS_LESS_THAN_INT), replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_PLUS_ONE_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_LESS_THAN_OR_EQUAL_TO, expectedMatcher = IS_NOT_POSITIVE, replaceFromOriginalMethod = true
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_LESS_THAN, expectedMatcher = CallMatcher.anyOf(IS_EQUAL_TO_INT, IS_LESS_THAN_OR_EQUAL_TO_INT), replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_MINUS_ONE_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_LESS_THAN, expectedMatcher = IS_LESS_THAN_INT, replaceFromOriginalMethod = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
COMPARABLE_COMPARE_TO,
MethodNames.IS_LESS_THAN, expectedMatcher = IS_NEGATIVE, replaceFromOriginalMethod = true
)
)
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitExpressionStatement(statement)
createInspectionsForMappings(statement, holder, MAPPINGS)
}
}
}
}
@@ -1,13 +1,9 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiExpressionStatement
import com.intellij.psi.*
import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.AssertJClassNames
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.*
class AssertThatFileExpressionInspection : AbstractMoveOutInspection() {
@@ -15,61 +11,94 @@ class AssertThatFileExpressionInspection : AbstractMoveOutInspection() {
companion object {
private const val DISPLAY_NAME = "Asserting a file specific expression"
private val ARG_IS_ZERO_CONST: (PsiExpressionStatement, PsiMethodCallExpression) -> Boolean = { _, call -> call.firstArg.calculateConstantValue() == 0 }
private val ARG_IS_NOT_ZERO_CONST: (PsiExpressionStatement, PsiMethodCallExpression) -> Boolean = { _, call ->
val constant =
call.firstArg.calculateConstantValue()
(constant != null) && (constant != 0)
}
private val MAPPINGS = listOf(
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "canRead"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "canRead").parameterCount(0),
"canRead", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "canWrite"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "canWrite").parameterCount(0),
"canWrite", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "exists"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "exists").parameterCount(0),
"exists", "doesNotExist", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "isAbsolute"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "isAbsolute").parameterCount(0),
"isAbsolute", "isRelative", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "isDirectory"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "isDirectory").parameterCount(0),
"isDirectory", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "isFile"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "isFile").parameterCount(0),
"isFile", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getName"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getName").parameterCount(0),
"hasName",
expectedMatcher = CallMatcher.anyOf(IS_EQUAL_TO_OBJECT, IS_EQUAL_TO_STRING)
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getParent", "getParentFile"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getParent", "getParentFile").parameterCount(0),
"hasNoParent", expectNullNonNull = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getParent"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getParent").parameterCount(0),
"hasParent",
expectedMatcher = CallMatcher.anyOf(IS_EQUAL_TO_OBJECT, IS_EQUAL_TO_STRING)
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getParentFile"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "getParentFile").parameterCount(0),
"hasParent",
expectedMatcher = IS_EQUAL_TO_OBJECT
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "list", "listFiles"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "list", "listFiles").parameterCount(0),
"isEmptyDirectory",
expectedMatcher = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_OBJECT_ARRAY_ASSERT_CLASSNAME, MethodNames.IS_EMPTY)
.parameterCount(0)!!
.parameterCount(0)
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "list", "listFiles"),
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "list", "listFiles").parameterCount(0),
"isNotEmptyDirectory",
expectedMatcher = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_OBJECT_ARRAY_ASSERT_CLASSNAME, MethodNames.IS_NOT_EMPTY)
.parameterCount(0)!!
.parameterCount(0)
)
)
private val MAPPINGS_SINCE_ASSERTJ_3_14_0 = listOf(
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "length").parameterCount(0),
"isEmpty", expectedMatcher = IS_ZERO_LONG, noExpectedExpression = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "length").parameterCount(0),
"isEmpty", expectedMatcher = IS_EQUAL_TO_LONG, noExpectedExpression = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "length").parameterCount(0),
"isNotEmpty", expectedMatcher = IS_NOT_ZERO_LONG, noExpectedExpression = true
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "length").parameterCount(0),
"isNotEmpty", expectedMatcher = IS_NOT_EQUAL_TO_LONG, noExpectedExpression = true,
additionalCondition = ARG_IS_ZERO_CONST
),
MoveOutMapping(
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, "length").parameterCount(0),
"hasSize", expectedMatcher = IS_EQUAL_TO_LONG,
additionalCondition = ARG_IS_NOT_ZERO_CONST
)
)
}
@@ -81,6 +110,9 @@ class AssertThatFileExpressionInspection : AbstractMoveOutInspection() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitExpressionStatement(statement)
createInspectionsForMappings(statement, holder, MAPPINGS)
if (hasAssertJMethod(statement, AssertJClassNames.ABSTRACT_FILE_ASSERT_CLASSNAME, MethodNames.HAS_SIZE)) {
createInspectionsForMappings(statement, holder, MAPPINGS_SINCE_ASSERTJ_3_14_0)
}
}
}
}
@@ -92,9 +92,7 @@ class AssertThatGuavaOptionalInspection : AbstractAssertJInspection() {
}
private fun checkPreconditions(staticMethodCall: PsiMethodCallExpression): Boolean {
val assertThatGuava = GUAVA_ASSERT_THAT_ANY.test(staticMethodCall)
if (ASSERT_THAT_ANY.test(staticMethodCall) || assertThatGuava) {
if (CallMatcher.anyOf(ASSERT_THAT_ANY, GUAVA_ASSERT_THAT_ANY).test(staticMethodCall)) {
JavaPsiFacade.getInstance(staticMethodCall.project)
.findClass(AssertJClassNames.GUAVA_ASSERTIONS_CLASSNAME, GlobalSearchScope.allScope(staticMethodCall.project)) ?: return false
return true
@@ -34,9 +34,9 @@ class AssertThatObjectExpressionInspection : AbstractMoveOutInspection() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitExpressionStatement(statement)
if (!statement.hasAssertThat()) return
val staticMethodCall = statement.findStaticMethodCall() ?: return
val assertThatArgument = staticMethodCall.firstArg as? PsiMethodCallExpression ?: return
val assertThatArgument = staticMethodCall.getArgOrNull(0) as? PsiMethodCallExpression ?: return
if (OBJECT_HASHCODE.test(assertThatArgument)) {
val expectedCallExpression = statement.findOutmostMethodCall() ?: return
val isEqualTo = staticMethodCall.findFluentCallTo(IS_EQUAL_TO_INT) ?: return
@@ -0,0 +1,51 @@
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.PsiExpressionStatement
import com.siyeh.ig.callMatcher.CallMatcher
class AssertThatPathExpressionInspection : AbstractMoveOutInspection() {
companion object {
private const val DISPLAY_NAME = "Asserting a path specific expression"
private const val JAVA_NIO_PATH = "java.nio.file.Path"
private val MAPPINGS = listOf(
MoveOutMapping(
CallMatcher.instanceCall(JAVA_NIO_PATH, "isAbsolute").parameterCount(0),
"isAbsolute", "isRelative", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(JAVA_NIO_PATH, "startsWith").parameterTypes(JAVA_NIO_PATH),
"startsWithRaw", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(JAVA_NIO_PATH, "endsWith").parameterTypes(JAVA_NIO_PATH),
"endsWithRaw", expectBoolean = true
),
MoveOutMapping(
CallMatcher.instanceCall(JAVA_NIO_PATH, "getParent").parameterCount(0),
"hasParentRaw",
expectedMatcher = IS_EQUAL_TO_OBJECT
),
MoveOutMapping(
CallMatcher.instanceCall(JAVA_NIO_PATH, "getParent").parameterCount(0),
"hasNoParentRaw", expectNullNonNull = true
)
)
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitExpressionStatement(statement)
createInspectionsForMappings(statement, holder, MAPPINGS)
}
}
}
}
@@ -57,10 +57,10 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
} else {
val isTestForEmpty = ((IS_LESS_THAN_OR_EQUAL_TO_INT.test(expression) && (constValue == 0))
|| (IS_LESS_THAN_INT.test(expression) && (constValue == 1))
|| IS_ZERO.test(expression))
|| IS_ZERO_INT.test(expression))
val isTestForNotEmpty = ((IS_GREATER_THAN_INT.test(expression) && (constValue == 0))
|| (IS_GREATER_THAN_OR_EQUAL_TO_INT.test(expression) && (constValue == 1))
|| IS_NOT_ZERO.test(expression))
|| IS_NOT_ZERO_INT.test(expression))
if ((isTestForEmpty && isLastExpression) || isTestForNotEmpty) {
val replacementMethod = isTestForEmpty.map(MethodNames.IS_EMPTY, MethodNames.IS_NOT_EMPTY)
return Match(expression, replacementMethod, noExpectedExpression = true)
@@ -60,7 +60,7 @@ class AssertThatStringExpressionInspection : AbstractMoveOutInspection() {
),
MoveOutMapping(
STRING_COMPARE_TO_IGNORE_CASE,
MethodNames.IS_EQUAL_TO_IC, expectedMatcher = IS_ZERO, replaceFromOriginalMethod = true
MethodNames.IS_EQUAL_TO_IC, expectedMatcher = IS_ZERO_INT, replaceFromOriginalMethod = true
),
MoveOutMapping(
STRING_COMPARE_TO_IGNORE_CASE,
@@ -69,7 +69,7 @@ class AssertThatStringExpressionInspection : AbstractMoveOutInspection() {
),
MoveOutMapping(
STRING_COMPARE_TO_IGNORE_CASE,
MethodNames.IS_NOT_EQUAL_TO_IC, expectedMatcher = IS_NOT_ZERO, replaceFromOriginalMethod = true
MethodNames.IS_NOT_EQUAL_TO_IC, expectedMatcher = IS_NOT_ZERO_INT, replaceFromOriginalMethod = true
),
MoveOutMapping(
@@ -79,7 +79,7 @@ class AssertThatStringExpressionInspection : AbstractMoveOutInspection() {
),
MoveOutMapping(
STRING_INDEX_OF,
MethodNames.STARTS_WITH, expectedMatcher = IS_ZERO, replaceFromOriginalMethod = true
MethodNames.STARTS_WITH, expectedMatcher = IS_ZERO_INT, replaceFromOriginalMethod = true
),
MoveOutMapping(
@@ -89,7 +89,7 @@ class AssertThatStringExpressionInspection : AbstractMoveOutInspection() {
),
MoveOutMapping(
STRING_INDEX_OF,
MethodNames.DOES_NOT_START_WITH, expectedMatcher = IS_NOT_ZERO, replaceFromOriginalMethod = true
MethodNames.DOES_NOT_START_WITH, expectedMatcher = IS_NOT_ZERO_INT, replaceFromOriginalMethod = true
),
MoveOutMapping(
@@ -0,0 +1,176 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import com.siyeh.ig.callMatcher.CallMatcher
import com.siyeh.ig.psiutils.EquivalenceChecker
import de.platon42.intellij.plugins.cajon.*
class BogusAssertionInspection : AbstractAssertJInspection() {
companion object {
private const val DISPLAY_NAME = "Bogus assertion due to same actual and expected expressions"
private const val ACTUAL_IS_EQUAL_TO_EXPECTED_MESSAGE = "Actual expression in assertThat() is the same as expected"
private const val WEAK_ACTUAL_IS_EQUAL_TO_EXPECTED_MESSAGE = "Same actual and expected expression, but may be testing equals() or hashCode()"
private val SAME_OBJECT =
CallMatcher.instanceCall(
AssertJClassNames.ASSERT_INTERFACE,
MethodNames.IS_EQUAL_TO,
MethodNames.IS_SAME_AS,
"hasSameClassAs",
"hasSameHashCodeAs"
).parameterCount(1)
private val ARRAY_METHODS = arrayOf(
"hasSameSizeAs",
MethodNames.CONTAINS,
"containsAnyOf",
"containsExactly",
"containsExactlyInAnyOrder",
"containsOnly",
"containsSequence",
"containsSubsequence",
"startsWith",
"endsWith"
)
private val SAME_BOOLEAN_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_BOOLEAN_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_BYTE_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_BYTE_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_SHORT_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_SHORT_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_INT_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_INT_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_LONG_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_LONG_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_FLOAT_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_FLOAT_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_DOUBLE_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_DOUBLE_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_CHAR_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_CHAR_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val SAME_OBJECT_ARRAY_CONTENTS =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_OBJECT_ARRAY_ASSERT_CLASSNAME, *ARRAY_METHODS).parameterCount(1)
private val HASHCODE_OR_IS_EQUAL_TO =
CallMatcher.instanceCall(
AssertJClassNames.ASSERT_INTERFACE,
MethodNames.IS_EQUAL_TO, "hasSameHashCodeAs"
).parameterCount(1)
private val SAME_ENUMERABLE_CONTENTS =
CallMatcher.instanceCall(
AssertJClassNames.ENUMERABLE_ASSERT_INTERFACE,
MethodNames.HAS_SAME_SIZE_AS
).parameterCount(1)
private val SAME_ITERABLE_CONTENTS =
CallMatcher.instanceCall(
AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME,
"hasSameElementsAs",
MethodNames.CONTAINS_ALL,
"containsAnyElementsOf",
"containsOnlyElementsOf",
"containsExactlyElementsOf",
"containsSequence",
"containsSubsequence"
).parameterCount(1)
private val SAME_MAP_CONTENTS =
CallMatcher.instanceCall(
AssertJClassNames.ABSTRACT_MAP_ASSERT_CLASSNAME,
"containsAllEntriesOf",
"containsExactlyEntriesOf",
"containsExactlyInAnyOrderEntriesOf",
MethodNames.HAS_SAME_SIZE_AS
).parameterCount(1)
private val SAME_CHAR_SEQUENCE_CONTENTS =
CallMatcher.instanceCall(
AssertJClassNames.ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME,
MethodNames.IS_EQUAL_TO,
MethodNames.IS_EQUAL_TO_IC,
MethodNames.STARTS_WITH,
MethodNames.ENDS_WITH,
"containsSequence",
"containsSubsequence"
).parameterCount(1)
private val SAME_ACTUAL_AND_EXPECTED_MATCHERS = CallMatcher.anyOf(
SAME_OBJECT,
SAME_ENUMERABLE_CONTENTS,
SAME_ITERABLE_CONTENTS,
SAME_MAP_CONTENTS,
SAME_CHAR_SEQUENCE_CONTENTS,
SAME_BOOLEAN_ARRAY_CONTENTS,
SAME_BYTE_ARRAY_CONTENTS,
SAME_SHORT_ARRAY_CONTENTS,
SAME_INT_ARRAY_CONTENTS,
SAME_LONG_ARRAY_CONTENTS,
SAME_FLOAT_ARRAY_CONTENTS,
SAME_DOUBLE_ARRAY_CONTENTS,
SAME_CHAR_ARRAY_CONTENTS,
SAME_OBJECT_ARRAY_CONTENTS
)
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitExpressionStatement(statement)
if (!statement.hasAssertThat()) return
val assertThatCall = PsiTreeUtil.findChildrenOfType(statement, PsiMethodCallExpression::class.java).find { ALL_ASSERT_THAT_MATCHERS.test(it) } ?: return
val actualExpression = assertThatCall.firstArg
val allCalls = assertThatCall.collectMethodCallsUpToStatement().toList()
// Note: replace with TrackingEquivalenceChecker() for IDEA >= 2019.1
val equivalenceChecker = EquivalenceChecker.getCanonicalPsiEquivalence()!!
val isSameExpression = allCalls
.filter(SAME_ACTUAL_AND_EXPECTED_MATCHERS::test)
.any { equivalenceChecker.expressionsAreEquivalent(actualExpression, it.firstArg) }
if (isSameExpression) {
if (!hasExpressionWithSideEffects(actualExpression)) {
if (allCalls.any(HASHCODE_OR_IS_EQUAL_TO::test)) {
val method = PsiTreeUtil.getParentOfType(statement, PsiMethod::class.java, true)
val methodName = method?.name
if ((methodName != null)
&& ((methodName.contains("equal", ignoreCase = true) || methodName.contains("hashcode", ignoreCase = true)))
) {
if (isOnTheFly) {
holder.registerProblem(statement, WEAK_ACTUAL_IS_EQUAL_TO_EXPECTED_MESSAGE, ProblemHighlightType.INFORMATION)
}
return
}
}
holder.registerProblem(statement, ACTUAL_IS_EQUAL_TO_EXPECTED_MESSAGE)
}
}
}
private fun hasExpressionWithSideEffects(actualExpression: PsiExpression): Boolean {
var result = false
PsiTreeUtil.processElements(actualExpression) { element ->
val matched = when (element) {
is PsiUnaryExpression -> (element.operationTokenType == JavaTokenType.PLUSPLUS)
|| (element.operationTokenType == JavaTokenType.MINUSMINUS)
is PsiMethodCallExpression -> true
else -> false
}
if (matched) {
result = true
false
} else {
true
}
}
return result
}
}
}
}
@@ -26,7 +26,7 @@ class JoinVarArgsContainsInspection : AbstractAssertJInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitStatement(statement)
super.visitExpressionStatement(statement)
if (!statement.hasAssertThat()) return
val assertThatCall = PsiTreeUtil.findChildrenOfType(statement, PsiMethodCallExpression::class.java).find { ALL_ASSERT_THAT_MATCHERS.test(it) } ?: return
@@ -35,7 +35,7 @@ class JoinVarArgsContainsInspection : AbstractAssertJInspection() {
if (allCalls.find(COMPLEX_CALLS_THAT_MAKES_STUFF_TRICKY::test) != null) return
val onlyAssertionCalls = allCalls
.filterNot { NOT_ACTUAL_ASSERTIONS.test(it) }
.filterNot(NOT_ACTUAL_ASSERTIONS::test)
.toList()
for (methodMatcher in MATCHERS) {
@@ -0,0 +1,108 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil
import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.*
import de.platon42.intellij.plugins.cajon.quickfixes.SwapActualAndExpectedExpressionMethodCallQuickFix
class TwistedAssertionInspection : AbstractAssertJInspection() {
companion object {
private const val DISPLAY_NAME = "Twisted or suspicious actual and expected expressions"
private const val TWISTED_ACTUAL_AND_EXPECTED_MESSAGE = "Twisted actual and expected expressions in assertion"
private const val SWAP_ACTUAL_AND_EXPECTED_DESCRIPTION = "Swap actual and expected expressions in assertion"
private const val SWAP_ACTUAL_AND_EXPECTED_AND_REPLACE_DESCRIPTION_TEMPLATE = "Replace %s() by %s() and swap actual and expected expressions"
private const val ACTUAL_IS_A_CONSTANT_MESSAGE = "Actual expression in assertThat() is a constant"
private val GENERIC_IS_EQUAL_TO = CallMatcher.instanceCall(AssertJClassNames.ASSERT_INTERFACE, MethodNames.IS_EQUAL_TO).parameterCount(1)
private val GENERIC_IS_NOT_EQUAL_TO = CallMatcher.instanceCall(AssertJClassNames.ASSERT_INTERFACE, MethodNames.IS_NOT_EQUAL_TO).parameterCount(1)
private val GENERIC_IS_SAME_AS = CallMatcher.instanceCall(AssertJClassNames.ASSERT_INTERFACE, MethodNames.IS_SAME_AS).parameterCount(1)
private val GENERIC_IS_NOT_SAME_AS = CallMatcher.instanceCall(AssertJClassNames.ASSERT_INTERFACE, MethodNames.IS_NOT_SAME_AS).parameterCount(1)
private val GENERIC_IS_GREATER_THAN = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_GREATER_THAN).parameterCount(1)
private val GENERIC_IS_GREATER_THAN_OR_EQUAL_TO =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_GREATER_THAN_OR_EQUAL_TO).parameterCount(1)
private val GENERIC_IS_LESS_THAN = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_LESS_THAN).parameterCount(1)
private val GENERIC_IS_LESS_THAN_OR_EQUAL_TO =
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_LESS_THAN_OR_EQUAL_TO).parameterCount(1)
private val STRING_IS_EQUAL_TO_IC = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO_IC).parameterCount(1)
private val STRING_REGEX_MATCHING = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME, "matches", "doesNotMatch").parameterCount(1)
private val CALL_MATCHER_TO_REPLACEMENT_MAP = mapOf(
GENERIC_IS_EQUAL_TO to MethodNames.IS_EQUAL_TO,
GENERIC_IS_NOT_EQUAL_TO to MethodNames.IS_NOT_EQUAL_TO,
GENERIC_IS_SAME_AS to MethodNames.IS_SAME_AS,
GENERIC_IS_NOT_SAME_AS to MethodNames.IS_NOT_SAME_AS,
GENERIC_IS_GREATER_THAN to MethodNames.IS_LESS_THAN_OR_EQUAL_TO,
GENERIC_IS_GREATER_THAN_OR_EQUAL_TO to MethodNames.IS_LESS_THAN,
GENERIC_IS_LESS_THAN to MethodNames.IS_GREATER_THAN_OR_EQUAL_TO,
GENERIC_IS_LESS_THAN_OR_EQUAL_TO to MethodNames.IS_GREATER_THAN,
STRING_IS_EQUAL_TO_IC to MethodNames.IS_EQUAL_TO_IC,
CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO_IC).parameterCount(1)
to MethodNames.IS_NOT_EQUAL_TO_IC
)
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
super.visitExpressionStatement(statement)
if (!statement.hasAssertThat()) return
val assertThatCall = PsiTreeUtil.findChildrenOfType(statement, PsiMethodCallExpression::class.java).find { ALL_ASSERT_THAT_MATCHERS.test(it) } ?: return
val actualExpression = assertThatCall.firstArg
actualExpression.calculateConstantValue() ?: return
val allCalls = assertThatCall.collectMethodCallsUpToStatement().toList()
val tooComplex = allCalls.find(USING_COMPARATOR::test) != null
var severity = ProblemHighlightType.GENERIC_ERROR_OR_WARNING
if (actualExpression.type is PsiClassType) {
val psiManager = PsiManager.getInstance(statement.project)
val javaLangClass = PsiType.getJavaLangClass(psiManager, GlobalSearchScope.allScope(statement.project))
if (actualExpression.type!!.isAssignableFrom(javaLangClass)) {
return
}
}
if (!tooComplex) {
val onlyAssertionCalls = allCalls
.filterNot(NOT_ACTUAL_ASSERTIONS::test)
.toList()
if (onlyAssertionCalls.size == 1) {
val expectedMethodCall = onlyAssertionCalls.first()
if (STRING_REGEX_MATCHING.test(expectedMethodCall)) {
return
}
if (expectedMethodCall.getArgOrNull(0)?.calculateConstantValue() == null) {
val matchedMethod = CALL_MATCHER_TO_REPLACEMENT_MAP.asSequence().firstOrNull { it.key.test(expectedMethodCall) }
if (matchedMethod != null) {
val originalMethodName = getOriginalMethodName(expectedMethodCall)
val replacementMethod = matchedMethod.value
val description = if (originalMethodName == replacementMethod) {
SWAP_ACTUAL_AND_EXPECTED_DESCRIPTION
} else {
SWAP_ACTUAL_AND_EXPECTED_AND_REPLACE_DESCRIPTION_TEMPLATE.format(originalMethodName, replacementMethod)
}
holder.registerProblem(
statement,
TWISTED_ACTUAL_AND_EXPECTED_MESSAGE,
SwapActualAndExpectedExpressionMethodCallQuickFix(description, replacementMethod)
)
return
}
} else {
severity = ProblemHighlightType.WEAK_WARNING
}
}
}
holder.registerProblem(statement, ACTUAL_IS_A_CONSTANT_MESSAGE, severity)
}
}
}
}
@@ -46,7 +46,7 @@ class MoveOutMethodCallExpressionQuickFix(
val expectedExpression = createExpectedMethodCall(
it,
replacementMethod,
*if (replaceFromOriginalMethod) arrayOf(assertExpressionArg!!) else it.argumentList.expressions
*if (replaceFromOriginalMethod || noExpectedExpression) listOfNotNull(assertExpressionArg).toTypedArray() else it.argumentList.expressions
)
expectedExpression.replaceQualifierFromMethodCall(it)
it.replace(expectedExpression)
@@ -0,0 +1,34 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import de.platon42.intellij.plugins.cajon.*
class SwapActualAndExpectedExpressionMethodCallQuickFix(
description: String,
private val replacementMethod: String
) : AbstractCommonQuickFix(description) {
companion object {
private const val SPLIT_EXPRESSION_DESCRIPTION = "Swap actual and expected expressions of assertions"
}
override fun getFamilyName(): String {
return SPLIT_EXPRESSION_DESCRIPTION
}
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val assertThatMethodCall = descriptor.startElement.findStaticMethodCall() ?: return
val methodToFix = assertThatMethodCall.collectMethodCallsUpToStatement()
.filterNot(NOT_ACTUAL_ASSERTIONS::test)
.first()
val oldActualExpression = assertThatMethodCall.firstArg.copy()!!
assertThatMethodCall.firstArg.replace(methodToFix.firstArg)
val expectedExpression = createExpectedMethodCall(methodToFix, replacementMethod, oldActualExpression)
expectedExpression.replaceQualifierFromMethodCall(methodToFix)
methodToFix.replace(expectedExpression)
}
}
@@ -1,6 +1,5 @@
package de.platon42.intellij.plugins.cajon.references
import com.intellij.lang.jvm.JvmModifier
import com.intellij.openapi.util.TextRange
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.*
@@ -30,7 +29,7 @@ class ExtractorReferenceContributor : PsiReferenceContributor() {
val matchedGetter = PropertyUtilBase.findPropertyGetter(containingClass, partName, false, true)
val fieldResult = PropertyUtilBase.findPropertyField(containingClass, partName, false)
val textRange = TextRange(startOffset + 1, nextOffset)
val matchedBareMethod = containingClass.allMethods.find { (it.name == partName) && !it.hasModifier(JvmModifier.STATIC) }
val matchedBareMethod = containingClass.allMethods.find { (it.name == partName) && !it.hasModifierProperty(PsiModifier.STATIC) }
val targets = listOfNotNull<PsiElement>(fieldResult, matchedGetter, matchedBareMethod)
if (targets.isNotEmpty()) {
val results = listOf(textRange to targets)
@@ -44,7 +43,7 @@ class ExtractorReferenceContributor : PsiReferenceContributor() {
}
private fun lookupMethod(containingClass: PsiClass, methodName: String): List<Pair<TextRange, List<PsiElement>>>? {
val matchedMethod = containingClass.allMethods.find { (it.name == methodName) && !it.hasModifier(JvmModifier.STATIC) } ?: return null
val matchedMethod = containingClass.allMethods.find { (it.name == methodName) && !it.hasModifierProperty(PsiModifier.STATIC) } ?: return null
val textRange = TextRange(1, methodName.length + 1)
return listOf(textRange to listOf(matchedMethod))
}
+13 -3
View File
@@ -5,10 +5,11 @@
<description><![CDATA[
Cajon is an IntelliJ IDEA Plugin for shortening and optimizing AssertJ assertions.
It adds several inspections and quick fixes to fully use the fluent assertion methods
It adds several <b>inspections and quick fixes</b> to fully use the fluent assertion methods
and thus makes the intention clear and concise, also generating better messages on test failures.
It can also be used to convert JUnit 4 assertions and assumptions to AssertJ.
It supports referencing inside extracting()-methods with strings, adding refactoring safety.
It can also be used to <b>convert JUnit 4 assertions and assumptions to AssertJ</b>.
It supports <b>referencing inside extracting</b>()-methods with strings, adding refactoring safety.
<b>Bogus or twisted assertions</b> are also reported.
<p>
<a href="https://github.com/chrisly42/cajon-plugin/blob/master/README.md">Full documentation here...</a>
]]></description>
@@ -41,12 +42,16 @@
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatBinaryExpressionInspection"/>
<localInspection groupPath="Java" shortName="AssertThatObjectExpression" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatObjectExpressionInspection"/>
<localInspection groupPath="Java" shortName="AssertThatComparable" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatComparableInspection"/>
<localInspection groupPath="Java" shortName="AssertThatStringExpression" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatStringExpressionInspection"/>
<localInspection groupPath="Java" shortName="AssertThatCollectionOrMapExpression" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatCollectionOrMapExpressionInspection"/>
<localInspection groupPath="Java" shortName="AssertThatFileExpression" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatFileExpressionInspection"/>
<localInspection groupPath="Java" shortName="AssertThatPathExpression" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatPathExpressionInspection"/>
<localInspection groupPath="Java" shortName="JoinAssertThatStatements" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.JoinAssertThatStatementsInspection"/>
@@ -63,6 +68,11 @@
<localInspection groupPath="Java" shortName="ImplicitAssertion" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.ImplicitAssertionInspection"/>
<localInspection groupPath="Java" shortName="TwistedAssertion" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.TwistedAssertionInspection"/>
<localInspection groupPath="Java" shortName="BogusAssertion" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.BogusAssertionInspection"/>
<localInspection groupPath="Java" shortName="JUnitAssertToAssertJ" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.JUnitAssertToAssertJInspection"/>
</extensions>
@@ -0,0 +1,5 @@
<html>
<body>
Turns assertThat(obj1.compareTo(obj2)) into assertThat(obj1).someMethod(obj2).
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
Operates on assertions on objects of type Path. Turns assertThat(file.someMethod(arg)).someAssertion() into assertThat(path).someMethod(arg).
<!-- tooltip end -->
<br>someMethod() can be isAbsolute(), getParent(), startsWith() and endsWith().
</body>
</html>
@@ -0,0 +1,6 @@
<html>
<body>
Finds typical copy and paste errors where the assertion will never fail, such as assertThat(foo).isEqualTo(foo), because actual
and expected expressions are the same.
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
Finds assertion method calls that have the expected and actual expressions twisted, such as assertThat(5).isEqualTo(foo).
<!-- tooltip end -->
For some obvious cases, a quickfix to swap the actual and expected expressions is provided.
</body>
</html>
@@ -0,0 +1,24 @@
package de.platon42.intellij.jupiter;
import com.intellij.openapi.roots.DependencyScope;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Repeatable(AddMavenDependencyToModule.List.class)
public @interface AddMavenDependencyToModule {
String value();
boolean includeTransitiveDependencies = false;
DependencyScope scope = DependencyScope.COMPILE;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface List {
AddMavenDependencyToModule[] value();
}
}
@@ -1,10 +1,17 @@
package de.platon42.intellij.jupiter;
import com.intellij.jarRepository.JarRepositoryManager;
import com.intellij.jarRepository.RemoteRepositoryDescription;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.DependencyScope;
import com.intellij.openapi.roots.LibraryOrderEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.ui.OrderRoot;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -13,6 +20,7 @@ import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties;
import org.junit.jupiter.api.extension.*;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
@@ -23,7 +31,11 @@ import java.lang.reflect.Parameter;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class LightCodeInsightExtension implements ParameterResolver, AfterTestExecutionCallback, InvocationInterceptor {
@@ -150,10 +162,12 @@ public class LightCodeInsightExtension implements ParameterResolver, AfterTestEx
@Override
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
super.configureModule(module, model, contentEntry);
AddLocalJarToModule methodOrClassAnnotation = getMethodOrClassAnnotation(AddLocalJarToModule.class);
if (methodOrClassAnnotation != null) {
Stream.of(methodOrClassAnnotation.value()).forEach(it -> addJarContaining(model, it));
AddLocalJarToModule localJars = getMethodOrClassAnnotation(AddLocalJarToModule.class);
if (localJars != null) {
Stream.of(localJars.value()).forEach(it -> addJarContaining(model, it));
}
List<AddMavenDependencyToModule> mavenDependencies = getMethodOrClassAnnotations(AddMavenDependencyToModule.class);
mavenDependencies.forEach(it -> addFromMaven(model, it.value(), it.includeTransitiveDependencies, it.scope));
}
};
}
@@ -175,6 +189,33 @@ public class LightCodeInsightExtension implements ParameterResolver, AfterTestEx
}
}
void addFromMaven(ModifiableRootModel model, String mavenCoordinates,
boolean includeTransitiveDependencies, DependencyScope dependencyScope) {
List<RemoteRepositoryDescription> remoteRepositoryDescriptions = RemoteRepositoryDescription.DEFAULT_REPOSITORIES;
RepositoryLibraryProperties libraryProperties = new RepositoryLibraryProperties(mavenCoordinates, includeTransitiveDependencies);
Collection<OrderRoot> roots =
JarRepositoryManager.loadDependenciesModal(model.getProject(), libraryProperties, false, false, null, remoteRepositoryDescriptions);
LibraryTable.ModifiableModel tableModel = model.getModuleLibraryTable().getModifiableModel();
Library library = tableModel.createLibrary(mavenCoordinates);
Library.ModifiableModel libraryModel = library.getModifiableModel();
if (roots.isEmpty()) {
throw new IllegalStateException(String.format("No roots for '%s'", mavenCoordinates));
}
for (OrderRoot root : roots) {
libraryModel.addRoot(root.getFile(), root.getType());
}
LibraryOrderEntry libraryOrderEntry = model.findLibraryOrderEntry(library);
if (libraryOrderEntry == null) {
throw new IllegalStateException("Unable to find registered library " + mavenCoordinates);
}
libraryOrderEntry.setScope(dependencyScope);
libraryModel.commit();
tableModel.commit();
}
@Override
protected String getTestDataPath() {
TestDataPath testDataPath = getMethodOrClassAnnotation(TestDataPath.class);
@@ -199,5 +240,12 @@ public class LightCodeInsightExtension implements ParameterResolver, AfterTestEx
}
return annotation;
}
private <T extends Annotation> List<T> getMethodOrClassAnnotations(Class<T> clazz) {
return Stream.of(extensionContext.getRequiredTestMethod().getAnnotationsByType(clazz),
extensionContext.getRequiredTestClass().getAnnotationsByType(clazz))
.flatMap(Arrays::stream)
.collect(Collectors.toList());
}
}
}
@@ -3,11 +3,10 @@ package de.platon42.intellij.plugins.cajon
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.pom.java.LanguageLevel
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
import de.platon42.intellij.jupiter.AddLocalJarToModule
import de.platon42.intellij.jupiter.AddMavenDependencyToModule
import de.platon42.intellij.jupiter.LightCodeInsightExtension
import de.platon42.intellij.jupiter.TestDataPath
import de.platon42.intellij.jupiter.TestJdk
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.DisplayNameGeneration
import org.junit.jupiter.api.DisplayNameGenerator
@@ -17,7 +16,8 @@ import java.lang.reflect.Method
@ExtendWith(LightCodeInsightExtension::class)
@TestDataPath("src/test/resources")
@TestJdk(LanguageLevel.JDK_1_8, annotations = true, useInternal = true)
@AddLocalJarToModule(Assertions::class)
//@AddLocalJarToModule(Assertions::class)
@AddMavenDependencyToModule("org.assertj:assertj-core:3.15.0")
@DisplayNameGeneration(AbstractCajonTest.CutOffFixtureDisplayNameGenerator::class)
abstract class AbstractCajonTest {
@@ -38,6 +38,14 @@ abstract class AbstractCajonTest {
return quickfixes
}
protected fun assertHighlightings(myFixture: JavaCodeInsightTestFixture, count: Int, snippet: String) {
val highlights = myFixture.doHighlighting()
.asSequence()
.filter { it.description?.contains(snippet) ?: false }
.toList()
assertThat(highlights).hasSize(count);
}
class CutOffFixtureDisplayNameGenerator : DisplayNameGenerator.ReplaceUnderscores() {
override fun generateDisplayNameForMethod(testClass: Class<*>?, testMethod: Method?): String {
val nameForMethod = super.generateDisplayNameForMethod(testClass, testMethod)
@@ -0,0 +1,24 @@
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 AssertThatComparableInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/Comparable")
internal fun assertThat_with_compareTo_method(@MyFixture myFixture: JavaCodeInsightTestFixture) {
myFixture.enableInspections(AssertThatComparableInspection::class.java)
myFixture.configureByFile("ComparableBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Remove compareTo() of actual expression and use assertThat().isEqualByComparingTo() instead"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove compareTo() of actual expression and use assertThat().isNotEqualByComparingTo() instead"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove compareTo() of actual expression and use assertThat().isGreaterThanOrEqualTo() instead"), 4)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove compareTo() of actual expression and use assertThat().isGreaterThan() instead"), 5)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove compareTo() of actual expression and use assertThat().isLessThanOrEqualTo() instead"), 4)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove compareTo() of actual expression and use assertThat().isLessThan() instead"), 4)
myFixture.checkResultByFile("ComparableAfter.java")
}
}
@@ -30,6 +30,9 @@ internal class AssertThatFileExpressionInspectionTest : AbstractCajonTest() {
executeQuickFixes(myFixture, Regex.fromLiteral("Remove listFiles() of actual expression and use assertThat().isNotEmptyDirectory() instead"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove list() of actual expression and use assertThat().isEmptyDirectory() instead"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove list() of actual expression and use assertThat().isNotEmptyDirectory() instead"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove length() of actual expression and use assertThat().isEmpty() instead"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove length() of actual expression and use assertThat().isNotEmpty() instead"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove length() of actual expression and use assertThat().hasSize() instead"), 1)
myFixture.checkResultByFile("FileExpressionAfter.java")
}
}
@@ -0,0 +1,24 @@
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 AssertThatPathExpressionInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/PathExpression")
internal fun assertThat_with_certain_Path_methods(@MyFixture myFixture: JavaCodeInsightTestFixture) {
myFixture.enableInspections(AssertThatPathExpressionInspection::class.java)
myFixture.configureByFile("PathExpressionBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Remove isAbsolute() of actual expression and use assertThat().isAbsolute() instead"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove isAbsolute() of actual expression and use assertThat().isRelative() instead"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove startsWith() of actual expression and use assertThat().startsWithRaw() instead"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove endsWith() of actual expression and use assertThat().endsWithRaw() instead"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove getParent() of actual expression and use assertThat().hasNoParentRaw() instead"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Remove getParent() of actual expression and use assertThat().hasParentRaw() instead"), 1)
myFixture.checkResultByFile("PathExpressionAfter.java")
}
}
@@ -4,8 +4,6 @@ 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.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.extrakting
import org.junit.jupiter.api.Test
internal class AssertThatSizeInspectionTest : AbstractCajonTest() {
@@ -15,7 +13,7 @@ internal class AssertThatSizeInspectionTest : AbstractCajonTest() {
internal fun assertThat_size_of_array_collection_or_map_can_be_simplified(@MyFixture myFixture: JavaCodeInsightTestFixture) {
myFixture.enableInspections(AssertThatSizeInspection::class.java)
myFixture.configureByFile("SizeBefore.java")
assertThat(myFixture.doHighlighting()).extrakting { it.description }.containsOnlyOnce("Try to operate on the iterable itself rather than its size")
assertHighlightings(myFixture, 1, "Try to operate on the iterable itself rather than its size")
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isEmpty()"), 5)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isZero() with isEmpty()"), 5)
@@ -0,0 +1,19 @@
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 BogusAssertionInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/BogusAssertion")
internal fun reports_bogus_assertions(@MyFixture myFixture: JavaCodeInsightTestFixture) {
myFixture.enableInspections(BogusAssertionInspection::class.java)
myFixture.configureByFile("BogusAssertionBefore.java")
assertHighlightings(myFixture, 14 * 9 + 10 + 12 + 8, "Actual expression in assertThat() is the same as expected")
assertHighlightings(myFixture, 3, "Same actual and expected expression, but may be testing equals() or hashCode()")
}
}
@@ -0,0 +1,23 @@
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 TwistedAssertionInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/TwistedAssertion")
internal fun hint_twisted_actual_and_expected_and_provide_quickfix_where_possible(@MyFixture myFixture: JavaCodeInsightTestFixture) {
myFixture.enableInspections(TwistedAssertionInspection::class.java)
myFixture.configureByFile("TwistedAssertionBefore.java")
assertHighlightings(myFixture, 5, "Actual expression in assertThat() is a constant")
assertHighlightings(myFixture, 10, "Twisted actual and expected expressions")
executeQuickFixes(myFixture, Regex.fromLiteral("Swap actual and expected expressions in assertion"), 6)
executeQuickFixesNoFamilyNameCheck(myFixture, Regex("Replace .* by .* and swap actual and expected expressions"), 4)
myFixture.checkResultByFile("TwistedAssertionAfter.java")
}
}
@@ -0,0 +1,218 @@
import java.io.File;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class BogusAssertions {
private void bogusAssertions() {
boolean[] boolarray = new boolean[10];
byte[] bytearray = new byte[10];
short[] shortarray = new short[10];
int[] intarray = new int[10];
long[] longarray = new long[10];
float[] floatarray = new float[10];
double[] doublearray = new double[10];
char[] chararray = new char[10];
Object[] objarray = new Object[10];
String string = "foo";
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
String bar = "bar";
assertThat(boolarray).isEqualTo(boolarray);
assertThat(boolarray).isSameAs(boolarray);
assertThat(boolarray).hasSameClassAs(boolarray);
assertThat(boolarray).hasSameHashCodeAs(boolarray);
assertThat(boolarray).hasSameSizeAs(boolarray);
assertThat(boolarray).contains(boolarray);
assertThat(boolarray).containsAnyOf(boolarray);
assertThat(boolarray).containsExactly(boolarray);
assertThat(boolarray).containsExactlyInAnyOrder(boolarray);
assertThat(boolarray).containsOnly(boolarray);
assertThat(boolarray).containsSequence(boolarray);
assertThat(boolarray).containsSubsequence(boolarray);
assertThat(boolarray).startsWith(boolarray);
assertThat(boolarray).endsWith(boolarray);
assertThat(bytearray).isEqualTo(bytearray);
assertThat(bytearray).isSameAs(bytearray);
assertThat(bytearray).hasSameClassAs(bytearray);
assertThat(bytearray).hasSameHashCodeAs(bytearray);
assertThat(bytearray).hasSameSizeAs(bytearray);
assertThat(bytearray).contains(bytearray);
assertThat(bytearray).containsAnyOf(bytearray);
assertThat(bytearray).containsExactly(bytearray);
assertThat(bytearray).containsExactlyInAnyOrder(bytearray);
assertThat(bytearray).containsOnly(bytearray);
assertThat(bytearray).containsSequence(bytearray);
assertThat(bytearray).containsSubsequence(bytearray);
assertThat(bytearray).startsWith(bytearray);
assertThat(bytearray).endsWith(bytearray);
assertThat(shortarray).isEqualTo(shortarray);
assertThat(shortarray).isSameAs(shortarray);
assertThat(shortarray).hasSameClassAs(shortarray);
assertThat(shortarray).hasSameHashCodeAs(shortarray);
assertThat(shortarray).hasSameSizeAs(shortarray);
assertThat(shortarray).contains(shortarray);
assertThat(shortarray).containsAnyOf(shortarray);
assertThat(shortarray).containsExactly(shortarray);
assertThat(shortarray).containsExactlyInAnyOrder(shortarray);
assertThat(shortarray).containsOnly(shortarray);
assertThat(shortarray).containsSequence(shortarray);
assertThat(shortarray).containsSubsequence(shortarray);
assertThat(shortarray).startsWith(shortarray);
assertThat(shortarray).endsWith(shortarray);
assertThat(intarray).isEqualTo(intarray);
assertThat(intarray).isSameAs(intarray);
assertThat(intarray).hasSameClassAs(intarray);
assertThat(intarray).hasSameHashCodeAs(intarray);
assertThat(intarray).hasSameSizeAs(intarray);
assertThat(intarray).contains(intarray);
assertThat(intarray).containsAnyOf(intarray);
assertThat(intarray).containsExactly(intarray);
assertThat(intarray).containsExactlyInAnyOrder(intarray);
assertThat(intarray).containsOnly(intarray);
assertThat(intarray).containsSequence(intarray);
assertThat(intarray).containsSubsequence(intarray);
assertThat(intarray).startsWith(intarray);
assertThat(intarray).endsWith(intarray);
assertThat(longarray).isEqualTo(longarray);
assertThat(longarray).isSameAs(longarray);
assertThat(longarray).hasSameClassAs(longarray);
assertThat(longarray).hasSameHashCodeAs(longarray);
assertThat(longarray).hasSameSizeAs(longarray);
assertThat(longarray).contains(longarray);
assertThat(longarray).containsAnyOf(longarray);
assertThat(longarray).containsExactly(longarray);
assertThat(longarray).containsExactlyInAnyOrder(longarray);
assertThat(longarray).containsOnly(longarray);
assertThat(longarray).containsSequence(longarray);
assertThat(longarray).containsSubsequence(longarray);
assertThat(longarray).startsWith(longarray);
assertThat(longarray).endsWith(longarray);
assertThat(floatarray).isEqualTo(floatarray);
assertThat(floatarray).isSameAs(floatarray);
assertThat(floatarray).hasSameClassAs(floatarray);
assertThat(floatarray).hasSameHashCodeAs(floatarray);
assertThat(floatarray).hasSameSizeAs(floatarray);
assertThat(floatarray).contains(floatarray);
assertThat(floatarray).containsAnyOf(floatarray);
assertThat(floatarray).containsExactly(floatarray);
assertThat(floatarray).containsExactlyInAnyOrder(floatarray);
assertThat(floatarray).containsOnly(floatarray);
assertThat(floatarray).containsSequence(floatarray);
assertThat(floatarray).containsSubsequence(floatarray);
assertThat(floatarray).startsWith(floatarray);
assertThat(floatarray).endsWith(floatarray);
assertThat(doublearray).isEqualTo(doublearray);
assertThat(doublearray).isSameAs(doublearray);
assertThat(doublearray).hasSameClassAs(doublearray);
assertThat(doublearray).hasSameHashCodeAs(doublearray);
assertThat(doublearray).hasSameSizeAs(doublearray);
assertThat(doublearray).contains(doublearray);
assertThat(doublearray).containsAnyOf(doublearray);
assertThat(doublearray).containsExactly(doublearray);
assertThat(doublearray).containsExactlyInAnyOrder(doublearray);
assertThat(doublearray).containsOnly(doublearray);
assertThat(doublearray).containsSequence(doublearray);
assertThat(doublearray).containsSubsequence(doublearray);
assertThat(doublearray).startsWith(doublearray);
assertThat(doublearray).endsWith(doublearray);
assertThat(chararray).isEqualTo(chararray);
assertThat(chararray).isSameAs(chararray);
assertThat(chararray).hasSameClassAs(chararray);
assertThat(chararray).hasSameHashCodeAs(chararray);
assertThat(chararray).hasSameSizeAs(chararray);
assertThat(chararray).contains(chararray);
assertThat(chararray).containsAnyOf(chararray);
assertThat(chararray).containsExactly(chararray);
assertThat(chararray).containsExactlyInAnyOrder(chararray);
assertThat(chararray).containsOnly(chararray);
assertThat(chararray).containsSequence(chararray);
assertThat(chararray).containsSubsequence(chararray);
assertThat(chararray).startsWith(chararray);
assertThat(chararray).endsWith(chararray);
assertThat(objarray).isEqualTo(objarray);
assertThat(objarray).isSameAs(objarray);
assertThat(objarray).hasSameClassAs(objarray);
assertThat(objarray).hasSameHashCodeAs(objarray);
assertThat(objarray).hasSameSizeAs(objarray);
assertThat(objarray).contains(objarray);
assertThat(objarray).containsAnyOf(objarray);
assertThat(objarray).containsExactly(objarray);
assertThat(objarray).containsExactlyInAnyOrder(objarray);
assertThat(objarray).containsOnly(objarray);
assertThat(objarray).containsSequence(objarray);
assertThat(objarray).containsSubsequence(objarray);
assertThat(objarray).startsWith(objarray);
assertThat(objarray).endsWith(objarray);
assertThat(string).as("foo").isEqualTo(string);
assertThat(string).as("foo").isSameAs(string);
assertThat(string).as("foo").hasSameClassAs(string);
assertThat(string).as("foo").hasSameHashCodeAs(string);
assertThat(string).as("foo").hasSameSizeAs(string);
assertThat(string).as("foo").isEqualToIgnoringCase(string);
assertThat(string).as("foo").containsSequence(string);
assertThat(string).as("foo").containsSubsequence(string);
assertThat(string).as("foo").startsWith(string);
assertThat(string).as("foo").endsWith(string);
assertThat(list).as("foo").isEqualTo(list);
assertThat(list).as("foo").isSameAs(list);
assertThat(list).as("foo").hasSameClassAs(list);
assertThat(list).as("foo").hasSameHashCodeAs(list);
assertThat(list).as("foo").hasSameSizeAs(list);
assertThat(list).as("foo").containsAll(list);
assertThat(list).as("foo").containsAnyElementsOf(list);
assertThat(list).as("foo").containsOnlyElementsOf(list);
assertThat(list).as("foo").containsExactlyElementsOf(list);
assertThat(list).as("foo").hasSameElementsAs(list);
assertThat(list).as("foo").containsSequence(list);
assertThat(list).as("foo").containsSubsequence(list);
assertThat(map).as("foo").isEqualTo(map);
assertThat(map).as("foo").isSameAs(map);
assertThat(map).as("foo").hasSameClassAs(map);
assertThat(map).as("foo").hasSameHashCodeAs(map);
assertThat(map).as("foo").hasSameSizeAs(map);
assertThat(map).as("foo").containsAllEntriesOf(map);
assertThat(map).as("foo").containsExactlyEntriesOf(map);
assertThat(map).as("foo").containsExactlyInAnyOrderEntriesOf(map);
assertThat(bar).isEqualTo(string);
assertThat(new Random().nextBoolean()).isEqualTo(new Random().nextBoolean());
assertThat(generateString()).isEqualTo(generateString());
int number = 4;
assertThat(number++).isEqualTo(number++);
assertThat(number++).isEqualTo(number++);
org.junit.Assert.assertThat(list, null);
fail("oh no!");
}
private void test_equals() {
assertThat("foo").isEqualTo("foo");
assertThat(new File("foo")).isEqualTo(new File("foo"));
}
private void test_HasHCode() {
assertThat("foo").hasSameHashCodeAs("foo");
}
private String generateString()
{
return "foo";
}
}
@@ -0,0 +1,41 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class CompareTo {
private void comparable() {
String string = "string";
assertThat(string).isEqualByComparingTo("foo");
assertThat(string).isEqualByComparingTo("foo");
assertThat(string).isNotEqualByComparingTo("foo");
assertThat(string).isNotEqualByComparingTo("foo");
assertThat(string).isGreaterThanOrEqualTo("foo");
assertThat(string).isGreaterThanOrEqualTo("foo");
assertThat(string).isGreaterThanOrEqualTo("foo");
assertThat(string).isGreaterThanOrEqualTo("foo");
assertThat(string).isGreaterThan("foo");
assertThat(string).isGreaterThan("foo");
assertThat(string).isGreaterThan("foo");
assertThat(string).isGreaterThan("foo");
assertThat(string).isGreaterThan("foo");
assertThat(string).isLessThanOrEqualTo("foo");
assertThat(string).isLessThanOrEqualTo("foo");
assertThat(string).isLessThanOrEqualTo("foo");
assertThat(string).isLessThanOrEqualTo("foo");
assertThat(string).isLessThan("foo");
assertThat(string).isLessThan("foo");
assertThat(string).isLessThan("foo");
assertThat(string).isLessThan("foo");
assertThat(string.compareTo("foo")).isNotEqualTo(2);
assertThat(string.compareTo("foo")).isEqualTo(2);
org.junit.Assert.assertThat(string, null);
fail("oh no!");
}
}
@@ -0,0 +1,41 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class CompareTo {
private void comparable() {
String string = "string";
assertThat(string.compareTo("foo")).isEqualTo(0);
assertThat(string.compareTo("foo")).isZero();
assertThat(string.compareTo("foo")).isNotEqualTo(0);
assertThat(string.compareTo("foo")).isNotZero();
assertThat(string.compareTo("foo")).isNotEqualTo(-1);
assertThat(string.compareTo("foo")).isGreaterThanOrEqualTo(0);
assertThat(string.compareTo("foo")).isGreaterThan(-1);
assertThat(string.compareTo("foo")).isNotNegative();
assertThat(string.compareTo("foo")).isEqualTo(1);
assertThat(string.compareTo("foo")).isOne();
assertThat(string.compareTo("foo")).isGreaterThan(0);
assertThat(string.compareTo("foo")).isPositive();
assertThat(string.compareTo("foo")).isGreaterThanOrEqualTo(1);
assertThat(string.compareTo("foo")).isNotEqualTo(1);
assertThat(string.compareTo("foo")).isLessThanOrEqualTo(0);
assertThat(string.compareTo("foo")).isLessThan(1);
assertThat(string.compareTo("foo")).isNotPositive();
assertThat(string.compareTo("foo")).isEqualTo(-1);
assertThat(string.compareTo("foo")).isLessThan(0);
assertThat(string.compareTo("foo")).isNegative();
assertThat(string.compareTo("foo")).isLessThanOrEqualTo(-1);
assertThat(string.compareTo("foo")).isNotEqualTo(2);
assertThat(string.compareTo("foo")).isEqualTo(2);
org.junit.Assert.assertThat(string, null);
fail("oh no!");
}
}
@@ -75,11 +75,22 @@ public class FileExpression {
assertThat(file.getParentFile()).isNotEqualTo(null);
assertThat(file.getParentFile()).isNotNull();
assertThat(file).isEmpty();
assertThat(file).isEmpty();
assertThat(file).isNotEmpty();
assertThat(file).isNotEmpty();
assertThat(file).hasSize(2);
assertThat(file.listFiles()).isNull();
assertThat(file.listFiles()).isNullOrEmpty();
assertThat(file).isEmptyDirectory();
assertThat(file).isNotEmptyDirectory();
assertThat(file.listFiles(f -> f.canExecute())).isNull();
assertThat(file.listFiles(f -> f.canExecute())).isNullOrEmpty();
assertThat(file.listFiles(f -> f.canExecute())).isEmpty();
assertThat(file.listFiles(f -> f.canExecute())).isNotEmpty();
assertThat(file.list()).isNull();
assertThat(file.list()).isNullOrEmpty();
assertThat(file).isEmptyDirectory();
@@ -75,11 +75,22 @@ public class FileExpression {
assertThat(file.getParentFile()).isNotEqualTo(null);
assertThat(file.getParentFile()).isNotNull();
assertThat(file.length()).isEqualTo(0);
assertThat(file.length()).isZero();
assertThat(file.length()).isNotEqualTo(0);
assertThat(file.length()).isNotZero();
assertThat(file.length()).isEqualTo(2);
assertThat(file.listFiles()).isNull();
assertThat(file.listFiles()).isNullOrEmpty();
assertThat(file.listFiles()).isEmpty();
assertThat(file.listFiles()).isNotEmpty();
assertThat(file.listFiles(f -> f.canExecute())).isNull();
assertThat(file.listFiles(f -> f.canExecute())).isNullOrEmpty();
assertThat(file.listFiles(f -> f.canExecute())).isEmpty();
assertThat(file.listFiles(f -> f.canExecute())).isNotEmpty();
assertThat(file.list()).isNull();
assertThat(file.list()).isNullOrEmpty();
assertThat(file.list()).isEmpty();
@@ -0,0 +1,126 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class PathExpression {
private void pathExpression() {
Path path = Paths.get("foo");
Path otherPath = Paths.get("bar");
assertThat(path).as("foo").isAbsolute();
assertThat(path).isAbsolute();
assertThat(path).isAbsolute();
assertThat(path).as("foo").isRelative();
assertThat(path).isRelative();
assertThat(path).isRelative();
assertThat(path).hasParentRaw(otherPath);
assertThat(path.getParent()).isNotEqualTo(otherPath);
assertThat(path).hasNoParentRaw();
assertThat(path).hasNoParentRaw();
assertThat(path.getParent()).isNotEqualTo(null);
assertThat(path.getParent()).isNotNull();
assertThat(path).as("foo").startsWithRaw(otherPath);
assertThat(path).startsWithRaw(otherPath);
assertThat(path).startsWithRaw(otherPath);
assertThat(path.startsWith(otherPath)).as("foo").isEqualTo(false);
assertThat(path.startsWith(otherPath)).isNotEqualTo(true);
assertThat(path.startsWith(otherPath)).isFalse();
assertThat(path.startsWith("otherPath")).as("foo").isEqualTo(true);
assertThat(path.startsWith("otherPath")).isNotEqualTo(false);
assertThat(path.startsWith("otherPath")).isTrue();
assertThat(path.startsWith("otherPath")).as("foo").isEqualTo(false);
assertThat(path.startsWith("otherPath")).isNotEqualTo(true);
assertThat(path.startsWith("otherPath")).isFalse();
assertThat(path).as("foo").endsWithRaw(otherPath);
assertThat(path).endsWithRaw(otherPath);
assertThat(path).endsWithRaw(otherPath);
assertThat(path.endsWith(otherPath)).as("foo").isEqualTo(false);
assertThat(path.endsWith(otherPath)).isNotEqualTo(true);
assertThat(path.endsWith(otherPath)).isFalse();
assertThat(path.endsWith("otherPath")).as("foo").isEqualTo(true);
assertThat(path.endsWith("otherPath")).isNotEqualTo(false);
assertThat(path.endsWith("otherPath")).isTrue();
assertThat(path.endsWith("otherPath")).as("foo").isEqualTo(false);
assertThat(path.endsWith("otherPath")).isNotEqualTo(true);
assertThat(path.endsWith("otherPath")).isFalse();
assertThat(Files.isReadable(path)).as("foo").isEqualTo(true);
assertThat(Files.isReadable(path)).isNotEqualTo(false);
assertThat(Files.isReadable(path)).isTrue();
assertThat(Files.isReadable(path)).as("foo").isEqualTo(false);
assertThat(Files.isReadable(path)).isNotEqualTo(true);
assertThat(Files.isReadable(path)).isFalse();
assertThat(Files.isWritable(path)).as("foo").isEqualTo(true);
assertThat(Files.isWritable(path)).isNotEqualTo(false);
assertThat(Files.isWritable(path)).isTrue();
assertThat(Files.isWritable(path)).as("foo").isEqualTo(false);
assertThat(Files.isWritable(path)).isNotEqualTo(true);
assertThat(Files.isWritable(path)).isFalse();
assertThat(Files.isExecutable(path)).as("foo").isEqualTo(true);
assertThat(Files.isExecutable(path)).isNotEqualTo(false);
assertThat(Files.isExecutable(path)).isTrue();
assertThat(Files.isExecutable(path)).as("foo").isEqualTo(false);
assertThat(Files.isExecutable(path)).isNotEqualTo(true);
assertThat(Files.isExecutable(path)).isFalse();
assertThat(Files.isDirectory(path)).as("foo").isEqualTo(true);
assertThat(Files.isDirectory(path)).isNotEqualTo(false);
assertThat(Files.isDirectory(path)).isTrue();
assertThat(Files.isDirectory(path)).as("foo").isEqualTo(false);
assertThat(Files.isDirectory(path)).isNotEqualTo(true);
assertThat(Files.isDirectory(path)).isFalse();
assertThat(Files.isRegularFile(path)).as("foo").isEqualTo(true);
assertThat(Files.isRegularFile(path)).isNotEqualTo(false);
assertThat(Files.isRegularFile(path)).isTrue();
assertThat(Files.isRegularFile(path)).as("foo").isEqualTo(false);
assertThat(Files.isRegularFile(path)).isNotEqualTo(true);
assertThat(Files.isRegularFile(path)).isFalse();
assertThat(Files.isSymbolicLink(path)).as("foo").isEqualTo(true);
assertThat(Files.isSymbolicLink(path)).isNotEqualTo(false);
assertThat(Files.isSymbolicLink(path)).isTrue();
assertThat(Files.isSymbolicLink(path)).as("foo").isEqualTo(false);
assertThat(Files.isSymbolicLink(path)).isNotEqualTo(true);
assertThat(Files.isSymbolicLink(path)).isFalse();
assertThat(Files.exists(path)).as("foo").isEqualTo(true);
assertThat(Files.exists(path)).isNotEqualTo(false);
assertThat(Files.exists(path)).isTrue();
assertThat(Files.exists(path)).as("foo").isEqualTo(false);
assertThat(Files.exists(path)).isNotEqualTo(true);
assertThat(Files.exists(path)).isFalse();
assertThat(Files.notExists(path)).as("foo").isEqualTo(true);
assertThat(Files.notExists(path)).isNotEqualTo(false);
assertThat(Files.notExists(path)).isTrue();
assertThat(Files.notExists(path)).as("foo").isEqualTo(false);
assertThat(Files.notExists(path)).isNotEqualTo(true);
assertThat(Files.notExists(path)).isFalse();
assertThat(Files.list(path)).isEmpty();
assertThat(Files.list(path)).isNotEmpty();
assertThat(Files.readAllBytes(path)).isEqualTo(new byte[1]);
assertThat(Files.readAllLines(path)).containsExactly("foo");
assertThat(Files.lines(path)).containsExactly("foo");
assertThat(path.getName()).endsWith(".foo"); // could be turned into .hasExtension("foo"), but not always.
assertThat(path.getName()).as("foo").isEqualTo("foo").as("bar").isEqualTo("bar");
org.junit.Assert.assertThat(path, null);
fail("oh no!");
}
}
@@ -0,0 +1,126 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class PathExpression {
private void pathExpression() {
Path path = Paths.get("foo");
Path otherPath = Paths.get("bar");
assertThat(path.isAbsolute()).as("foo").isEqualTo(true);
assertThat(path.isAbsolute()).isNotEqualTo(false);
assertThat(path.isAbsolute()).isTrue();
assertThat(path.isAbsolute()).as("foo").isEqualTo(false);
assertThat(path.isAbsolute()).isNotEqualTo(true);
assertThat(path.isAbsolute()).isFalse();
assertThat(path.getParent()).isEqualTo(otherPath);
assertThat(path.getParent()).isNotEqualTo(otherPath);
assertThat(path.getParent()).isEqualTo(null);
assertThat(path.getParent()).isNull();
assertThat(path.getParent()).isNotEqualTo(null);
assertThat(path.getParent()).isNotNull();
assertThat(path.startsWith(otherPath)).as("foo").isEqualTo(true);
assertThat(path.startsWith(otherPath)).isNotEqualTo(false);
assertThat(path.startsWith(otherPath)).isTrue();
assertThat(path.startsWith(otherPath)).as("foo").isEqualTo(false);
assertThat(path.startsWith(otherPath)).isNotEqualTo(true);
assertThat(path.startsWith(otherPath)).isFalse();
assertThat(path.startsWith("otherPath")).as("foo").isEqualTo(true);
assertThat(path.startsWith("otherPath")).isNotEqualTo(false);
assertThat(path.startsWith("otherPath")).isTrue();
assertThat(path.startsWith("otherPath")).as("foo").isEqualTo(false);
assertThat(path.startsWith("otherPath")).isNotEqualTo(true);
assertThat(path.startsWith("otherPath")).isFalse();
assertThat(path.endsWith(otherPath)).as("foo").isEqualTo(true);
assertThat(path.endsWith(otherPath)).isNotEqualTo(false);
assertThat(path.endsWith(otherPath)).isTrue();
assertThat(path.endsWith(otherPath)).as("foo").isEqualTo(false);
assertThat(path.endsWith(otherPath)).isNotEqualTo(true);
assertThat(path.endsWith(otherPath)).isFalse();
assertThat(path.endsWith("otherPath")).as("foo").isEqualTo(true);
assertThat(path.endsWith("otherPath")).isNotEqualTo(false);
assertThat(path.endsWith("otherPath")).isTrue();
assertThat(path.endsWith("otherPath")).as("foo").isEqualTo(false);
assertThat(path.endsWith("otherPath")).isNotEqualTo(true);
assertThat(path.endsWith("otherPath")).isFalse();
assertThat(Files.isReadable(path)).as("foo").isEqualTo(true);
assertThat(Files.isReadable(path)).isNotEqualTo(false);
assertThat(Files.isReadable(path)).isTrue();
assertThat(Files.isReadable(path)).as("foo").isEqualTo(false);
assertThat(Files.isReadable(path)).isNotEqualTo(true);
assertThat(Files.isReadable(path)).isFalse();
assertThat(Files.isWritable(path)).as("foo").isEqualTo(true);
assertThat(Files.isWritable(path)).isNotEqualTo(false);
assertThat(Files.isWritable(path)).isTrue();
assertThat(Files.isWritable(path)).as("foo").isEqualTo(false);
assertThat(Files.isWritable(path)).isNotEqualTo(true);
assertThat(Files.isWritable(path)).isFalse();
assertThat(Files.isExecutable(path)).as("foo").isEqualTo(true);
assertThat(Files.isExecutable(path)).isNotEqualTo(false);
assertThat(Files.isExecutable(path)).isTrue();
assertThat(Files.isExecutable(path)).as("foo").isEqualTo(false);
assertThat(Files.isExecutable(path)).isNotEqualTo(true);
assertThat(Files.isExecutable(path)).isFalse();
assertThat(Files.isDirectory(path)).as("foo").isEqualTo(true);
assertThat(Files.isDirectory(path)).isNotEqualTo(false);
assertThat(Files.isDirectory(path)).isTrue();
assertThat(Files.isDirectory(path)).as("foo").isEqualTo(false);
assertThat(Files.isDirectory(path)).isNotEqualTo(true);
assertThat(Files.isDirectory(path)).isFalse();
assertThat(Files.isRegularFile(path)).as("foo").isEqualTo(true);
assertThat(Files.isRegularFile(path)).isNotEqualTo(false);
assertThat(Files.isRegularFile(path)).isTrue();
assertThat(Files.isRegularFile(path)).as("foo").isEqualTo(false);
assertThat(Files.isRegularFile(path)).isNotEqualTo(true);
assertThat(Files.isRegularFile(path)).isFalse();
assertThat(Files.isSymbolicLink(path)).as("foo").isEqualTo(true);
assertThat(Files.isSymbolicLink(path)).isNotEqualTo(false);
assertThat(Files.isSymbolicLink(path)).isTrue();
assertThat(Files.isSymbolicLink(path)).as("foo").isEqualTo(false);
assertThat(Files.isSymbolicLink(path)).isNotEqualTo(true);
assertThat(Files.isSymbolicLink(path)).isFalse();
assertThat(Files.exists(path)).as("foo").isEqualTo(true);
assertThat(Files.exists(path)).isNotEqualTo(false);
assertThat(Files.exists(path)).isTrue();
assertThat(Files.exists(path)).as("foo").isEqualTo(false);
assertThat(Files.exists(path)).isNotEqualTo(true);
assertThat(Files.exists(path)).isFalse();
assertThat(Files.notExists(path)).as("foo").isEqualTo(true);
assertThat(Files.notExists(path)).isNotEqualTo(false);
assertThat(Files.notExists(path)).isTrue();
assertThat(Files.notExists(path)).as("foo").isEqualTo(false);
assertThat(Files.notExists(path)).isNotEqualTo(true);
assertThat(Files.notExists(path)).isFalse();
assertThat(Files.list(path)).isEmpty();
assertThat(Files.list(path)).isNotEmpty();
assertThat(Files.readAllBytes(path)).isEqualTo(new byte[1]);
assertThat(Files.readAllLines(path)).containsExactly("foo");
assertThat(Files.lines(path)).containsExactly("foo");
assertThat(path.getName()).endsWith(".foo"); // could be turned into .hasExtension("foo"), but not always.
assertThat(path.getName()).as("foo").isEqualTo("foo").as("bar").isEqualTo("bar");
org.junit.Assert.assertThat(path, null);
fail("oh no!");
}
}
@@ -0,0 +1,46 @@
import java.util.*;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class TwistedAssertions {
private static final int SOME_CONST = 10;
private static final String SOME_CONST_STRING = "bar";
private void twistedAssertions() {
List<String> list = new ArrayList<>();
String foo = "foo";
String bar = "bar";
int number = 4;
assertThat(number).as("foo").isEqualTo(5 + 2);
assertThat(number).as("foo").isNotEqualTo(8);
assertThat(number).as("foo").isLessThanOrEqualTo(5 * 2);
assertThat(number + 1).as("foo").isLessThan(4 + (1 - 2));
assertThat(number * 2).as("foo").isGreaterThanOrEqualTo(3);
assertThat(number / 2).as("foo").isGreaterThan(2 + SOME_CONST);
assertThat(foo).as("foo").isEqualTo("foo");
assertThat(foo).as("foo").isSameAs(SOME_CONST_STRING);
assertThat(foo).as("foo").isNotEqualTo("bar");
assertThat(foo).as("foo").isNotSameAs("bar");
assertThat("bar").as("foo").startsWith(foo);
assertThat("foo").as("foo").endsWith(foo);
assertThat(bar).isEqualTo(foo);
assertThat(4).isEqualTo(number).isNotEqualTo(number * 2);
assertThat(4).usingComparator(Comparator.reverseOrder()).isGreaterThanOrEqualTo(number);
assertThat(String.class).isEqualTo(Class.forName("java.lang.String"));
assertThat("XX").matches(Pattern.compile(".."));
assertThat("XX").matches(".."));
assertThat("XX").doesNotMatch(Pattern.compile(".."));
assertThat("XX").doesNotMatch(".."));
assertThat(SOME_CONST).isEqualTo(10);
org.junit.Assert.assertThat(list, null);
fail("oh no!");
}
}
@@ -0,0 +1,46 @@
import java.util.*;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class TwistedAssertions {
private static final int SOME_CONST = 10;
private static final String SOME_CONST_STRING = "bar";
private void twistedAssertions() {
List<String> list = new ArrayList<>();
String foo = "foo";
String bar = "bar";
int number = 4;
assertThat(5 + 2).as("foo").isEqualTo(number);
assertThat(8).as("foo").isNotEqualTo(number);
assertThat(5 * 2).as("foo").isGreaterThan(number);
assertThat(4 + (1 - 2)).as("foo").isGreaterThanOrEqualTo(number + 1);
assertThat(3).as("foo").isLessThan(number * 2);
assertThat(2 + SOME_CONST).as("foo").isLessThanOrEqualTo(number / 2);
assertThat("foo").as("foo").isEqualTo(foo);
assertThat(SOME_CONST_STRING).as("foo").isSameAs(foo);
assertThat("bar").as("foo").isNotEqualTo(foo);
assertThat("bar").as("foo").isNotSameAs(foo);
assertThat("bar").as("foo").startsWith(foo);
assertThat("foo").as("foo").endsWith(foo);
assertThat(bar).isEqualTo(foo);
assertThat(4).isEqualTo(number).isNotEqualTo(number * 2);
assertThat(4).usingComparator(Comparator.reverseOrder()).isGreaterThanOrEqualTo(number);
assertThat(String.class).isEqualTo(Class.forName("java.lang.String"));
assertThat("XX").matches(Pattern.compile(".."));
assertThat("XX").matches(".."));
assertThat("XX").doesNotMatch(Pattern.compile(".."));
assertThat("XX").doesNotMatch(".."));
assertThat(SOME_CONST).isEqualTo(10);
org.junit.Assert.assertThat(list, null);
fail("oh no!");
}
}