diff --git a/README.md b/README.md index c34fbf1..d366b1c 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,21 @@ assertThat(array).hasSameSizeAs(collection); You can toggle the various inspections in the Settings/Editor/Inspections in the AssertJ group. -## Implemented inspections +## Implemented inspections and quickfixes +- JoinAssertThatStatements + ``` + from: assertThat(expected).someCondition(); + assertThat(expected).anotherCondition(); + to: assertThat(expected).someCondition().anotherCondition(); + ``` + Joining will work on actual expressions inside assertThat() that are + - the same variable reference + - textually equal binary expressions + - the same method calls (except for known side-effect methods such as ```Iterator.next()``` -- please notify me about others) + + The comments of the statements will be preserved. When using ```.extracting()``` or similar, the statements will not be merged. + - AssertThatObjectIsNullOrNotNull ``` from: assertThat(object).isEqualTo(null); @@ -320,9 +333,8 @@ Cajon is probably the only plugin that uses JUnit 5 Jupiter for unit testing so The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing and it took me quite a while to make it work with JUnit 5. Feel free to use the code (in package de.platon42.intellij.jupiter) for your projects (with attribution). -## TODO +## Planned features - AssumeThatInsteadOfReturn -- Join consecutive assertThats - Extraction with property names to lambda with Java 8 ``` from: assertThat(object).extracting("propOne", "propNoGetter", "propTwo.innerProp")... @@ -333,10 +345,12 @@ Feel free to use the code (in package de.platon42.intellij.jupiter) for your pro ## Changelog -#### V0.7 (unreleased) +#### V0.7 (28-Apr-19) - Another fix for AssertThatGuavaOptional inspection regarding using the same family name for slightly different quick fix executions (really, Jetbrains, this sucks for no reason). - Extended AssertThatSize inspection to transform ```hasSize()``` into ```hasSameSizeAs()```, if possible. +- Implemented first version of JoinAssertThatStatements inspection that will try to merge ```assertThat()``` statements with the same + actual object together, preserving comments. #### V0.6 (22-Apr-19) - New AssertThatStringExpression inspection that will move ```isEmpty()```, ```equals()```, ```equalsIgnoreCase()```, ```contains()```, diff --git a/build.gradle b/build.gradle index 2823f93..e1bcef4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'org.jetbrains.intellij' version '0.4.8' - id 'org.jetbrains.kotlin.jvm' version '1.3.30' + id 'org.jetbrains.kotlin.jvm' version '1.3.31' } group 'de.platon42' @@ -40,12 +40,14 @@ intellij { patchPluginXml { changeNotes """ -

V0.7 (unreleased)

+

V0.7 (28-Apr-19)

+
  • Implemented first version of JoinAssertThatStatements inspection that will try to merge assertThat() statements with the same + actual object together, preserving comments. +

    V0.6 (22-Apr-19)

    +

    Full changelog available at Github project site.

    """ } diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/CommonMatchers.kt b/src/main/java/de/platon42/intellij/plugins/cajon/CommonMatchers.kt new file mode 100644 index 0000000..bafe3c2 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/cajon/CommonMatchers.kt @@ -0,0 +1,23 @@ +package de.platon42.intellij.plugins.cajon + +import com.intellij.psi.CommonClassNames +import com.siyeh.ig.callMatcher.CallMatcher + +val CORE_ASSERT_THAT_MATCHER = CallMatcher.staticCall(AssertJClassNames.ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)!! +val GUAVA_ASSERT_THAT_MATCHER = CallMatcher.staticCall(AssertJClassNames.GUAVA_ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)!! +val ALL_ASSERT_THAT_MATCHERS = CallMatcher.anyOf(CORE_ASSERT_THAT_MATCHER, GUAVA_ASSERT_THAT_MATCHER)!! +val EXTRACTING_FROM_OBJECT = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_OBJECT_ASSERT_CLASSNAME, "extracting")!! +val EXTRACTING_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "extracting")!! +val FLAT_EXTRACTING_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "flatExtracting")!! +val EXTRACTING_RESULT_OF_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "extractingResultOf")!! + +val EXTRACTING_CALL_MATCHERS = CallMatcher.anyOf( + EXTRACTING_FROM_OBJECT, + EXTRACTING_FROM_ITERABLE, + FLAT_EXTRACTING_FROM_ITERABLE, + EXTRACTING_RESULT_OF_FROM_ITERABLE +)!! + +val KNOWN_METHODS_WITH_SIDE_EFFECTS = CallMatcher.anyOf( + CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_ITERATOR, "next") +)!! \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/Extensions.kt b/src/main/java/de/platon42/intellij/plugins/cajon/Extensions.kt index fcb26a7..c9d5563 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/Extensions.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/Extensions.kt @@ -4,6 +4,7 @@ import com.intellij.psi.* import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.JavaCodeStyleManager import com.intellij.psi.util.PsiTreeUtil +import com.siyeh.ig.callMatcher.CallMatcher val PsiMethodCallExpression.qualifierExpression: PsiExpression get() = this.methodExpression.qualifierExpression!! val PsiMethodCallExpression.firstArg: PsiExpression get() = this.argumentList.expressions[0]!! @@ -21,6 +22,17 @@ fun PsiElement.findOutmostMethodCall(): PsiMethodCallExpression? { return PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) } +fun PsiMethodCallExpression.findFluentCallTo(matcher: CallMatcher): PsiMethodCallExpression? { + var currentMethodCall: PsiMethodCallExpression? = this + while (currentMethodCall != null) { + if (matcher.test(currentMethodCall)) { + return currentMethodCall + } + currentMethodCall = PsiTreeUtil.getParentOfType(currentMethodCall, PsiMethodCallExpression::class.java, true, PsiStatement::class.java) + } + return null +} + fun PsiMethodCallExpression.getArg(n: Int): PsiExpression = this.argumentList.expressions[n] fun Boolean.map(forTrue: T, forFalse: T) = if (this) forTrue else forFalse diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/Helper.kt b/src/main/java/de/platon42/intellij/plugins/cajon/Helper.kt index 66ef68e..6509572 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/Helper.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/Helper.kt @@ -4,9 +4,6 @@ import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiElement import com.intellij.psi.PsiExpression import com.intellij.psi.PsiMethodCallExpression -import com.siyeh.ig.callMatcher.CallMatcher - -val CORE_ASSERT_THAT_MATCHER = CallMatcher.staticCall(AssertJClassNames.ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)!! fun createAssertThat(context: PsiElement, actualExpression: PsiExpression): PsiMethodCallExpression { return createAssertThat(context, AssertJClassNames.ASSERTIONS_CLASSNAME, actualExpression) diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/inspections/JoinAssertThatStatementsInspection.kt b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/JoinAssertThatStatementsInspection.kt new file mode 100644 index 0000000..0948727 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/cajon/inspections/JoinAssertThatStatementsInspection.kt @@ -0,0 +1,87 @@ +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 de.platon42.intellij.plugins.cajon.* +import de.platon42.intellij.plugins.cajon.quickfixes.JoinStatementsQuickFix + +class JoinAssertThatStatementsInspection : AbstractAssertJInspection() { + + companion object { + private const val DISPLAY_NAME = "Joining multiple assertThat() statements with same actual expression" + private const val CAN_BE_JOINED_DESCRIPTION = "Multiple assertThat() statements can be joined together" + } + + override fun getDisplayName() = DISPLAY_NAME + + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return object : JavaElementVisitor() { + override fun visitCodeBlock(block: PsiCodeBlock?) { + super.visitCodeBlock(block) + val statements = block?.statements ?: return + var lastActualExpression: PsiExpression? = null + var sameCount = 0 + var firstStatement: PsiStatement? = null + var lastStatement: PsiStatement? = null + for (statement in statements) { + val assertThatCall = isLegitAssertThatCall(statement) + var reset = true + var actualExpression: PsiExpression? = null + if (assertThatCall != null) { + reset = (lastActualExpression == null) + actualExpression = assertThatCall.firstArg + if (!reset) { + val isSame = when (actualExpression) { + is PsiReferenceExpression -> (actualExpression.qualifierExpression == (lastActualExpression as? PsiReferenceExpression)?.qualifierExpression) + is PsiMethodCallExpression -> (actualExpression.text == (lastActualExpression as? PsiMethodCallExpression)?.text) + && !KNOWN_METHODS_WITH_SIDE_EFFECTS.test(actualExpression) + is PsiPolyadicExpression -> (actualExpression.text == (lastActualExpression as? PsiPolyadicExpression)?.text) + else -> false + } + if (isSame) { + sameCount++ + lastStatement = statement + } else { + reset = true + } + } + } + if (reset) { + if (sameCount > 1) { + registerProblem(firstStatement, lastStatement) + } + firstStatement = statement + lastStatement = null + lastActualExpression = actualExpression + sameCount = 1 + } + } + if (sameCount > 1) { + registerProblem(firstStatement, lastStatement) + } + } + + private fun registerProblem(firstStatement: PsiStatement?, lastStatement: PsiStatement?) { + val problemDescriptor = holder.manager.createProblemDescriptor( + firstStatement!!, + lastStatement!!, + CAN_BE_JOINED_DESCRIPTION, + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + isOnTheFly, + JoinStatementsQuickFix() + ) + holder.registerProblem(problemDescriptor) + } + + private fun isLegitAssertThatCall(statement: PsiStatement?): PsiMethodCallExpression? { + if ((statement is PsiExpressionStatement) && (statement.expression is PsiMethodCallExpression)) { + val assertThatCall = PsiTreeUtil.findChildrenOfType(statement, PsiMethodCallExpression::class.java).find { ALL_ASSERT_THAT_MATCHERS.test(it) } + return assertThatCall?.takeIf { it.findFluentCallTo(EXTRACTING_CALL_MATCHERS) == null } + } + return null + } + } + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/JoinStatementsQuickFix.kt b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/JoinStatementsQuickFix.kt new file mode 100644 index 0000000..ed94fcc --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/JoinStatementsQuickFix.kt @@ -0,0 +1,54 @@ +package de.platon42.intellij.plugins.cajon.quickfixes + +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.openapi.project.Project +import com.intellij.psi.* +import com.intellij.psi.codeStyle.CodeStyleManager +import com.intellij.psi.util.PsiTreeUtil +import de.platon42.intellij.plugins.cajon.ALL_ASSERT_THAT_MATCHERS + +class JoinStatementsQuickFix : AbstractCommonQuickFix(JOIN_STATEMENTS_MESSAGE) { + companion object { + private const val JOIN_STATEMENTS_MESSAGE = "Join assertThat() statements" + } + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val firstStatement = descriptor.startElement as PsiExpressionStatement + val lastStatement = descriptor.endElement as PsiExpressionStatement + do { + val commentsToKeep = ArrayList() + val stuffToDelete = ArrayList() + var previousStatement = lastStatement.prevSibling ?: throw IllegalStateException("Internal error") + while (previousStatement !is PsiExpressionStatement) { + if (previousStatement is PsiComment) { + commentsToKeep.add(previousStatement.copy() as PsiComment) + } + stuffToDelete.add(previousStatement) + previousStatement = previousStatement.prevSibling ?: throw IllegalStateException("Internal error") + } + stuffToDelete.forEach { if (it.isValid) it.delete() } + + val statementComments = PsiTreeUtil.getChildrenOfAnyType(previousStatement, PsiComment::class.java) + commentsToKeep.addAll(statementComments) + + val assertThatCallOfCursorStatement = + PsiTreeUtil.findChildrenOfType(lastStatement, PsiMethodCallExpression::class.java).find { ALL_ASSERT_THAT_MATCHERS.test(it) } + ?: throw IllegalStateException("Internal error") + + val lastElementBeforeConcat = assertThatCallOfCursorStatement.parent + commentsToKeep.forEach { + lastElementBeforeConcat.addAfter(it, lastElementBeforeConcat.firstChild) + val newLineNode = + PsiParserFacade.SERVICE.getInstance(project).createWhiteSpaceFromText("\n\t") + + lastElementBeforeConcat.addAfter(newLineNode, lastElementBeforeConcat.firstChild) + } + + val newLeaf = previousStatement.firstChild + assertThatCallOfCursorStatement.replace(newLeaf) + previousStatement.delete() + } while (previousStatement !== firstStatement) + val codeBlock = PsiTreeUtil.getParentOfType(lastStatement, PsiCodeBlock::class.java) ?: return + CodeStyleManager.getInstance(project).reformat(codeBlock) + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveInstanceOfExpressionQuickFix.kt b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveInstanceOfExpressionQuickFix.kt index b5874d2..6692b10 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveInstanceOfExpressionQuickFix.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveInstanceOfExpressionQuickFix.kt @@ -5,7 +5,7 @@ import com.intellij.openapi.project.Project import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiInstanceOfExpression import com.intellij.psi.PsiMethodCallExpression -import com.intellij.psi.PsiParenthesizedExpression +import com.intellij.psi.util.PsiUtil import de.platon42.intellij.plugins.cajon.createExpectedMethodCall import de.platon42.intellij.plugins.cajon.findOutmostMethodCall import de.platon42.intellij.plugins.cajon.firstArg @@ -21,11 +21,7 @@ class RemoveInstanceOfExpressionQuickFix(description: String, private val replac val factory = JavaPsiFacade.getElementFactory(project) val classObjectAccess = factory.createExpressionFromText("${expectedClass.type.canonicalText}.class", null) - var operand = assertExpression.operand - while (operand is PsiParenthesizedExpression) { - operand = operand.expression ?: return - } - + val operand = PsiUtil.deparenthesizeExpression(assertExpression.operand) ?: return assertExpression.replace(operand) val oldExpectedExpression = element.findOutmostMethodCall() ?: return diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveUnaryExpressionQuickFix.kt b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveUnaryExpressionQuickFix.kt index fc453ee..e29e248 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveUnaryExpressionQuickFix.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/quickfixes/RemoveUnaryExpressionQuickFix.kt @@ -3,8 +3,8 @@ package de.platon42.intellij.plugins.cajon.quickfixes import com.intellij.codeInspection.ProblemDescriptor import com.intellij.openapi.project.Project import com.intellij.psi.PsiMethodCallExpression -import com.intellij.psi.PsiParenthesizedExpression import com.intellij.psi.PsiUnaryExpression +import com.intellij.psi.util.PsiUtil import de.platon42.intellij.plugins.cajon.createExpectedMethodCall import de.platon42.intellij.plugins.cajon.findOutmostMethodCall import de.platon42.intellij.plugins.cajon.firstArg @@ -16,10 +16,7 @@ class RemoveUnaryExpressionQuickFix(description: String, private val replacement val element = descriptor.startElement val methodCallExpression = element as? PsiMethodCallExpression ?: return val assertExpression = methodCallExpression.firstArg as? PsiUnaryExpression ?: return - var operand = assertExpression.operand ?: return - while (operand is PsiParenthesizedExpression) { - operand = operand.expression ?: return - } + val operand = PsiUtil.skipParenthesizedExprDown(assertExpression.operand) ?: return assertExpression.replace(operand) val oldExpectedExpression = element.findOutmostMethodCall() ?: return diff --git a/src/main/java/de/platon42/intellij/plugins/cajon/references/ExtractorReferenceContributor.kt b/src/main/java/de/platon42/intellij/plugins/cajon/references/ExtractorReferenceContributor.kt index 97d7684..5f41ed4 100644 --- a/src/main/java/de/platon42/intellij/plugins/cajon/references/ExtractorReferenceContributor.kt +++ b/src/main/java/de/platon42/intellij/plugins/cajon/references/ExtractorReferenceContributor.kt @@ -10,19 +10,11 @@ import com.intellij.psi.util.PsiTypesUtil import com.intellij.util.ArrayUtil import com.intellij.util.ProcessingContext import com.siyeh.ig.callMatcher.CallMatcher -import de.platon42.intellij.plugins.cajon.AssertJClassNames -import de.platon42.intellij.plugins.cajon.CORE_ASSERT_THAT_MATCHER -import de.platon42.intellij.plugins.cajon.firstArg +import de.platon42.intellij.plugins.cajon.* class ExtractorReferenceContributor : PsiReferenceContributor() { companion object { - - private val EXTRACTING_FROM_OBJECT = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_OBJECT_ASSERT_CLASSNAME, "extracting") - private val EXTRACTING_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "extracting") - private val FLAT_EXTRACTING_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "flatExtracting") - private val EXTRACTING_RESULT_OF_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "extractingResultOf") - private val BY_NAME = CallMatcher.staticCall(AssertJClassNames.EXTRACTORS_CLASSNAME, "byName") private val RESULT_OF = CallMatcher.staticCall(AssertJClassNames.EXTRACTORS_CLASSNAME, "resultOf") .parameterTypes(CommonClassNames.JAVA_LANG_STRING)!! diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index c40a17a..416cbcd 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -43,6 +43,9 @@ + + list = new ArrayList<>(); + assertThat(list).as("foo").hasSize(2); + assertThat(list).as("bar").contains("barbar"); // comment to keep + assertThat(list).as("etc").contains("etcetc"); + + // moar! + assertThat(list).doesNotContain("foobar"); + + assertThat("narf").isNotEqualTo("puit"); + assertThat(list).as("bar").contains("barbar"); + assertThat(list).as("foo").hasSize(2); + assertThat(list).as("evil").extracting(String::length).contains(2); + + assertThat(list).as("bar").contains("barbar"); + assertThat("narf").isNotEqualTo("puit"); + assertThat(list).as("foo").hasSize(2); + if (true) { + assertThat(list).doesNotContain("narf"); + assertThat(list).as("bar").contains("barbar"); + } + assertThat(list.get(0)).isNotEmpty(); + assertThat(list.get(0)).hasSize(3); + assertThat(list.get(0)).isEqualTo("bar"); + + assertThat(list.get(0) + "foo").isEqualTo("bar"); + assertThat(list.get(0) + "foo").doesNotStartWith("foo"); + + Iterator iterator = list.iterator(); + assertThat(iterator.next()).isEqualTo("foo"); + assertThat(iterator.next()).isEqualTo("bar"); + } + private void sizeOfArray() { assertThat(new String[1].length).isLessThanOrEqualTo(1); assertThat(new String[1]).hasSameSizeAs(new Object()); diff --git a/src/test/java/de/platon42/intellij/plugins/cajon/inspections/JoinAssertThatStatementsInspectionTest.kt b/src/test/java/de/platon42/intellij/plugins/cajon/inspections/JoinAssertThatStatementsInspectionTest.kt new file mode 100644 index 0000000..c760ff2 --- /dev/null +++ b/src/test/java/de/platon42/intellij/plugins/cajon/inspections/JoinAssertThatStatementsInspectionTest.kt @@ -0,0 +1,21 @@ +package de.platon42.intellij.plugins.cajon.inspections + +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture +import de.platon42.intellij.jupiter.MyFixture +import de.platon42.intellij.jupiter.TestDataSubPath +import de.platon42.intellij.plugins.cajon.AbstractCajonTest +import org.junit.jupiter.api.Test + +internal class JoinAssertThatStatementsInspectionTest : AbstractCajonTest() { + + @Test + @TestDataSubPath("inspections/JoinStatements") + internal fun assertThat_size_of_array_or_collection_can_be_simplified(@MyFixture myFixture: JavaCodeInsightTestFixture) { + runTest { + myFixture.enableInspections(JoinAssertThatStatementsInspection::class.java) + myFixture.configureByFile("JoinStatementsBefore.java") + executeQuickFixes(myFixture, Regex.fromLiteral("Join assertThat() statements"), 6) + myFixture.checkResultByFile("JoinStatementsAfter.java") + } + } +} \ No newline at end of file diff --git a/src/test/resources/inspections/JoinStatements/JoinStatementsAfter.java b/src/test/resources/inspections/JoinStatements/JoinStatementsAfter.java new file mode 100644 index 0000000..3b18060 --- /dev/null +++ b/src/test/resources/inspections/JoinStatements/JoinStatementsAfter.java @@ -0,0 +1,40 @@ +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JoinStatements { + + private void joinStatements() { + List list = new ArrayList<>(); + // the future is always born in pain + /* tricky */ + assertThat(list).as("foo").hasSize(2) + /* do another */ + /* do one */.as("bar").contains("barbar") + // comment to keep + .doesNotContain("barbara") // another comment to keep + .doesNotContain("wrzlbrmpft") + /* and a multi line comment + after the statement */ + // across two lines + .as("etc")/* what a nasty comment */.contains("etcetc") + // moar! + .doesNotContain("foobar"); + + assertThat("narf").isNotEqualTo("puit").as("bar").contains("barbar").as("foo").hasSize(2); + assertThat(list).as("evil").extracting(String::length).contains(2); + + assertThat(list).as("bar").contains("barbar"); + assertThat("narf").isNotEqualTo("puit").as("foo").hasSize(2); + if (true) { + assertThat(list).doesNotContain("narf").as("bar").contains("barbar"); + } + assertThat(list.get(0)).isNotEmpty().hasSize(3).isEqualTo("bar"); + + assertThat(list.get(0) + "foo").isEqualTo("bar").doesNotStartWith("foo"); + + Iterator iterator = list.iterator(); + assertThat(iterator.next()).isEqualTo("foo"); + assertThat(iterator.next()).isEqualTo("bar"); + } +} diff --git a/src/test/resources/inspections/JoinStatements/JoinStatementsBefore.java b/src/test/resources/inspections/JoinStatements/JoinStatementsBefore.java new file mode 100644 index 0000000..7e924d1 --- /dev/null +++ b/src/test/resources/inspections/JoinStatements/JoinStatementsBefore.java @@ -0,0 +1,44 @@ +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JoinStatements { + + private void joinStatements() { + List list = new ArrayList<>(); + // the future is always born in pain + /* tricky */assertThat(list).as("foo").hasSize(2); /* do one */ /* do another */ + assertThat(list).as("bar").contains("barbar"); // comment to keep + assertThat(list).doesNotContain("barbara") // another comment to keep + .doesNotContain("wrzlbrmpft") // across two lines + ; /* and a multi line comment + after the statement */ + assertThat(list).as("etc")/* what a nasty comment */.contains("etcetc"); + + // moar! + assertThat(list).doesNotContain("foobar"); + + assertThat("narf").isNotEqualTo("puit"); + assertThat(list).as("bar").contains("barbar"); + assertThat(list).as("foo").hasSize(2); + assertThat(list).as("evil").extracting(String::length).contains(2); + + assertThat(list).as("bar").contains("barbar"); + assertThat("narf").isNotEqualTo("puit"); + assertThat(list).as("foo").hasSize(2); + if (true) { + assertThat(list).doesNotContain("narf"); + assertThat(list).as("bar").contains("barbar"); + } + assertThat(list.get(0)).isNotEmpty(); + assertThat(list.get(0)).hasSize(3); + assertThat(list.get(0)).isEqualTo("bar"); + + assertThat(list.get(0) + "foo").isEqualTo("bar"); + assertThat(list.get(0) + "foo").doesNotStartWith("foo"); + + Iterator iterator = list.iterator(); + assertThat(iterator.next()).isEqualTo("foo"); + assertThat(iterator.next()).isEqualTo("bar"); + } +}