diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleFixTest.kt index e01dcd605c..b6a24f9204 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleFixTest.kt @@ -1,16 +1,9 @@ package org.cqfn.diktat.ruleset.chapter3.spaces import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.dotQualifiedExpressions -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionBodyFunctions -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionsWrappedAfterOperator -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionsWrappedBeforeOperator -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.parenthesesSurroundedInfixExpressions -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.whitespaceInStringLiterals import org.cqfn.diktat.ruleset.constants.Warnings.WRONG_INDENTATION import org.cqfn.diktat.ruleset.junit.NaturalDisplayName import org.cqfn.diktat.ruleset.rules.chapter3.files.IndentationRule -import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.ALIGNED_PARAMETERS import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT @@ -18,22 +11,19 @@ import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXT import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_OF_PARAMETERS import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END import org.cqfn.diktat.util.FixTestBase -import org.cqfn.diktat.util.assertNotNull import generated.WarningNames -import org.assertj.core.api.SoftAssertions.assertSoftly -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestMethodOrder -import org.junit.jupiter.api.io.TempDir -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.CsvSource -import org.junit.jupiter.params.provider.ValueSource - -import java.nio.file.Path +/** + * Legacy indentation tests. + * + * Consider adding new tests to [IndentationRuleTest] instead. + * + * @see IndentationRuleTest + */ @TestMethodOrder(NaturalDisplayName::class) class IndentationRuleFixTest : FixTestBase("test/paragraph3/indentation", ::IndentationRule, @@ -79,264 +69,4 @@ class IndentationRuleFixTest : FixTestBase("test/paragraph3/indentation", fun `multiline string`() { fixAndCompare("MultilionStringExpected.kt", "MultilionStringTest.kt") } - - /** - * @param actualContent the original file content (may well be modified as - * fixes are applied). - * @param expectedContent the content the file is expected to have after the - * fixes are applied. - */ - private fun lintMultipleMethods( - @Language("kotlin") actualContent: Array, - @Language("kotlin") expectedContent: Array = actualContent, - tempDir: Path, - rulesConfigList: List? = null - ) { - require(actualContent.isNotEmpty()) { - "code fragments is an empty array" - } - - require(actualContent.size == expectedContent.size) { - "The actual and expected code fragments are arrays of different size: ${actualContent.size} != ${expectedContent.size}" - } - - assertSoftly { softly -> - (actualContent.asSequenceWithConcatenation() zip - expectedContent.asSequenceWithConcatenation()).forEach { (actual, expected) -> - val lintResult = fixAndCompareContent( - actual, - expected, - tempDir, - rulesConfigList) - - if (!lintResult.isSuccessful) { - softly.assertThat(lintResult.actualContent) - .describedAs("lint result for ${actual.describe()}") - .isEqualTo(lintResult.expectedContent) - } - } - } - } - - /** - * See [#1330](https://github.com/saveourtool/diktat/issues/1330). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Expression body functions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should remain unchanged if properly indented`(extendedIndentForExpressionBodies: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies) - - lintMultipleMethods( - expressionBodyFunctions[extendedIndentForExpressionBodies].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reformatted if mis-indented`(extendedIndentForExpressionBodies: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies) - - lintMultipleMethods( - actualContent = expressionBodyFunctions[!extendedIndentForExpressionBodies].assertNotNull(), - expectedContent = expressionBodyFunctions[extendedIndentForExpressionBodies].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - } - - /** - * See [#1347](https://github.com/saveourtool/diktat/issues/1347). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Multi-line string literals` { - @ParameterizedTest(name = "extendedIndent = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `no whitespace should be injected (code matches settings)`(extendedIndent: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(*extendedIndent(enabled = extendedIndent)) - - lintMultipleMethods( - whitespaceInStringLiterals[extendedIndent].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - - @ParameterizedTest(name = "extendedIndent = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `no whitespace should be injected (mis-indented code reformatted)`(extendedIndent: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(*extendedIndent(enabled = extendedIndent)) - - lintMultipleMethods( - actualContent = whitespaceInStringLiterals[!extendedIndent].assertNotNull(), - expectedContent = whitespaceInStringLiterals[extendedIndent].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - } - - /** - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Expressions wrapped after operator` { - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentAfterOperators: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - expressionsWrappedAfterOperator[extendedIndentAfterOperators].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reformatted if mis-indented`(extendedIndentAfterOperators: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - actualContent = expressionsWrappedAfterOperator[!extendedIndentAfterOperators].assertNotNull(), - expectedContent = expressionsWrappedAfterOperator[extendedIndentAfterOperators].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - } - - /** - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Expressions wrapped before operator` { - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentAfterOperators: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - expressionsWrappedBeforeOperator[extendedIndentAfterOperators].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reformatted if mis-indented`(extendedIndentAfterOperators: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - actualContent = expressionsWrappedBeforeOperator[!extendedIndentAfterOperators].assertNotNull(), - expectedContent = expressionsWrappedBeforeOperator[extendedIndentAfterOperators].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - } - - /** - * See [#1409](https://github.com/saveourtool/diktat/issues/1409). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Parentheses-surrounded infix expressions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}, $EXTENDED_INDENT_AFTER_OPERATORS = {1}") - @CsvSource(value = ["false,true", "true,false"]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`( - extendedIndentForExpressionBodies: Boolean, - extendedIndentAfterOperators: Boolean, - @TempDir tempDir: Path, - ) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters( - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies, - EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators, - ) - - lintMultipleMethods( - parenthesesSurroundedInfixExpressions[IndentationConfig(customConfig)].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}, $EXTENDED_INDENT_AFTER_OPERATORS = {1}") - @CsvSource(value = ["false,true", "true,false"]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reformatted if mis-indented`( - extendedIndentForExpressionBodies: Boolean, - extendedIndentAfterOperators: Boolean, - @TempDir tempDir: Path, - ) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val actualCodeStyle = defaultConfig.withCustomParameters( - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to !extendedIndentForExpressionBodies, - EXTENDED_INDENT_AFTER_OPERATORS to !extendedIndentAfterOperators, - ) - val desiredCodeStyle = defaultConfig.withCustomParameters( - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies, - EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators, - ) - - lintMultipleMethods( - actualContent = parenthesesSurroundedInfixExpressions[IndentationConfig(actualCodeStyle)].assertNotNull(), - expectedContent = parenthesesSurroundedInfixExpressions[IndentationConfig(desiredCodeStyle)].assertNotNull(), - tempDir = tempDir, - rulesConfigList = desiredCodeStyle.asRulesConfigList()) - } - } - - /** - * See [#1336](https://github.com/saveourtool/diktat/issues/1336). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Dot- and safe-qualified expressions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_BEFORE_DOT = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentBeforeDot: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_BEFORE_DOT to extendedIndentBeforeDot) - - lintMultipleMethods( - dotQualifiedExpressions[extendedIndentBeforeDot].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_BEFORE_DOT = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reformatted if mis-indented`(extendedIndentBeforeDot: Boolean, @TempDir tempDir: Path) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_BEFORE_DOT to extendedIndentBeforeDot) - - lintMultipleMethods( - actualContent = dotQualifiedExpressions[!extendedIndentBeforeDot].assertNotNull(), - expectedContent = dotQualifiedExpressions[extendedIndentBeforeDot].assertNotNull(), - tempDir = tempDir, - rulesConfigList = customConfig.asRulesConfigList()) - } - } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTest.kt new file mode 100644 index 0000000000..7b7f1605d5 --- /dev/null +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTest.kt @@ -0,0 +1,2072 @@ +@file:Suppress("FILE_IS_TOO_LONG") + +package org.cqfn.diktat.ruleset.chapter3.spaces + +import org.cqfn.diktat.ruleset.chapter3.spaces.junit.IndentationTest +import org.cqfn.diktat.ruleset.chapter3.spaces.junit.IndentedSourceCode +import org.cqfn.diktat.ruleset.junit.BooleanOrDefault.FALSE +import org.cqfn.diktat.ruleset.junit.BooleanOrDefault.TRUE +import org.cqfn.diktat.ruleset.junit.NaturalDisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.TestMethodOrder + +/** + * For legacy indentation tests, see [IndentationRuleWarnTest] and + * [IndentationRuleFixTest]. + * + * @see IndentationRuleWarnTest + * @see IndentationRuleFixTest + */ +@Suppress( + "LargeClass", + "MaxLineLength", + "LONG_LINE", +) +@TestMethodOrder(NaturalDisplayName::class) +class IndentationRuleTest { + /** + * See [#1330](https://github.com/saveourtool/diktat/issues/1330). + */ + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `Expression body functions` { + @IndentationTest( + first = IndentedSourceCode( + """ + @Test + fun `checking that suppression with ignore everything works`() { + val code = + ""${'"'} // diktat:WRONG_INDENTATION[expectedIndent = 12] + @Suppress("diktat") + fun foo() { + val a = 1 + } + ""${'"'}.trimIndent() + lintMethod(code) + } + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + @Test + fun `checking that suppression with ignore everything works`() { + val code = + ""${'"'} // diktat:WRONG_INDENTATION[expectedIndent = 8] + @Suppress("diktat") + fun foo() { + val a = 1 + } + ""${'"'}.trimIndent() + lintMethod(code) + } + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 1`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val currentTime: Time + get() = + with(currentDateTime) { // diktat:WRONG_INDENTATION[expectedIndent = 12] + Time(hour = hour, minute = minute, second = second) // diktat:WRONG_INDENTATION[expectedIndent = 16] + } // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + val currentTime: Time + get() = + with(currentDateTime) { // diktat:WRONG_INDENTATION[expectedIndent = 8] + Time(hour = hour, minute = minute, second = second) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 2`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun formatDateByPattern(date: String, pattern: String = "ddMMyy"): String = + DateTimeFormatter.ofPattern(pattern).format(LocalDate.parse(date)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + fun formatDateByPattern(date: String, pattern: String = "ddMMyy"): String = + DateTimeFormatter.ofPattern(pattern).format(LocalDate.parse(date)) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 3`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + private fun createLayoutParams(): WindowManager.LayoutParams = + WindowManager.LayoutParams().apply { /* ... */ } // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + private fun createLayoutParams(): WindowManager.LayoutParams = + WindowManager.LayoutParams().apply { /* ... */ } // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 4`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + private fun createLayoutParams(): WindowManager.LayoutParams = + WindowManager.LayoutParams().apply { // diktat:WRONG_INDENTATION[expectedIndent = 8] + type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL // diktat:WRONG_INDENTATION[expectedIndent = 12] + token = composeView.applicationWindowToken // diktat:WRONG_INDENTATION[expectedIndent = 12] + width = WindowManager.LayoutParams.MATCH_PARENT // diktat:WRONG_INDENTATION[expectedIndent = 12] + height = WindowManager.LayoutParams.MATCH_PARENT // diktat:WRONG_INDENTATION[expectedIndent = 12] + format = PixelFormat.TRANSLUCENT // diktat:WRONG_INDENTATION[expectedIndent = 12] + + // TODO make composable configurable // diktat:WRONG_INDENTATION[expectedIndent = 12] + + // see https://stackoverflow.com/questions/43511326/android-making-activity-full-screen-with-status-bar-on-top-of-it // diktat:WRONG_INDENTATION[expectedIndent = 12] + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // diktat:WRONG_INDENTATION[expectedIndent = 12] + windowInsetsController?.hide(WindowInsets.Type.statusBars()) // diktat:WRONG_INDENTATION[expectedIndent = 16] + } else { // diktat:WRONG_INDENTATION[expectedIndent = 12] + @Suppress("DEPRECATION") // diktat:WRONG_INDENTATION[expectedIndent = 16] + systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or // diktat:WRONG_INDENTATION[expectedIndent = 16] + View.SYSTEM_UI_FLAG_FULLSCREEN or + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) + } // diktat:WRONG_INDENTATION[expectedIndent = 12] + } // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + private fun createLayoutParams(): WindowManager.LayoutParams = + WindowManager.LayoutParams().apply { // diktat:WRONG_INDENTATION[expectedIndent = 4] + type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL // diktat:WRONG_INDENTATION[expectedIndent = 8] + token = composeView.applicationWindowToken // diktat:WRONG_INDENTATION[expectedIndent = 8] + width = WindowManager.LayoutParams.MATCH_PARENT // diktat:WRONG_INDENTATION[expectedIndent = 8] + height = WindowManager.LayoutParams.MATCH_PARENT // diktat:WRONG_INDENTATION[expectedIndent = 8] + format = PixelFormat.TRANSLUCENT // diktat:WRONG_INDENTATION[expectedIndent = 8] + + // TODO make composable configurable // diktat:WRONG_INDENTATION[expectedIndent = 8] + + // see https://stackoverflow.com/questions/43511326/android-making-activity-full-screen-with-status-bar-on-top-of-it // diktat:WRONG_INDENTATION[expectedIndent = 8] + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // diktat:WRONG_INDENTATION[expectedIndent = 8] + windowInsetsController?.hide(WindowInsets.Type.statusBars()) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } else { // diktat:WRONG_INDENTATION[expectedIndent = 8] + @Suppress("DEPRECATION") // diktat:WRONG_INDENTATION[expectedIndent = 12] + systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or // diktat:WRONG_INDENTATION[expectedIndent = 12] + View.SYSTEM_UI_FLAG_FULLSCREEN or + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) + } // diktat:WRONG_INDENTATION[expectedIndent = 8] + } // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 5`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val offsetDelta = + if (shimmerAnimationType != ShimmerAnimationType.FADE) translateAnim.dp // diktat:WRONG_INDENTATION[expectedIndent = 8] + else 2000.dp // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + val offsetDelta = + if (shimmerAnimationType != ShimmerAnimationType.FADE) translateAnim.dp // diktat:WRONG_INDENTATION[expectedIndent = 4] + else 2000.dp // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 6`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + private fun lerp(start: Float, stop: Float, fraction: Float): Float = + (1 - fraction) * start + fraction * stop // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + private fun lerp(start: Float, stop: Float, fraction: Float): Float = + (1 - fraction) * start + fraction * stop // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 7`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun foo() = + println() // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + fun foo() = + println() // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 8`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() = + x + (y + // diktat:WRONG_INDENTATION[expectedIndent = 8] + g(x) + ) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + fun f() = + x + (y + // diktat:WRONG_INDENTATION[expectedIndent = 4] + g(x) + ) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 9`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() = + (1 + // diktat:WRONG_INDENTATION[expectedIndent = 8] + 2) + """, + extendedIndentForExpressionBodies = FALSE), + second = IndentedSourceCode( + """ + fun f() = + (1 + // diktat:WRONG_INDENTATION[expectedIndent = 4] + 2) + """, + extendedIndentForExpressionBodies = TRUE)) + fun `case 10`() = Unit + } + + /** + * See [#1347](https://github.com/saveourtool/diktat/issues/1347). + */ + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `Multi-line string literals` { + @IndentationTest( + first = IndentedSourceCode( + """ + @Test + fun `test method name`() { + @Language("kotlin") + val code = + ""${'"'} + @Suppress("diktat") + fun foo() { + val a = 1 + } + ""${'"'}.trimIndent() + lintMethod(code) + } + """, + extendedIndentOfParameters = FALSE, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = FALSE, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + @Test + fun `test method name`() { + @Language("kotlin") + val code = + ""${'"'} + @Suppress("diktat") + fun foo() { + val a = 1 + } + ""${'"'}.trimIndent() + lintMethod(code) + } + """, + extendedIndentOfParameters = TRUE, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = TRUE, + extendedIndentBeforeDot = TRUE), + includeWarnTests = false + ) + fun `no whitespace should be injected, case 1`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f0() { + @Language("kotlin") + val code = + ""${'"'} + |@Suppress("diktat") + |fun foo() { + | val a = 1 + |} + ""${'"'}.trimMargin() + lintMethod(code) + } + """, + extendedIndentOfParameters = FALSE, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = FALSE, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f0() { + @Language("kotlin") + val code = + ""${'"'} + |@Suppress("diktat") + |fun foo() { + | val a = 1 + |} + ""${'"'}.trimMargin() + lintMethod(code) + } + """, + extendedIndentOfParameters = TRUE, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = TRUE, + extendedIndentBeforeDot = TRUE), + includeWarnTests = false + ) + fun `no whitespace should be injected, case 2`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f1() { + @Language("kotlin") + val code = + ""${'"'} + |@Suppress("diktat") + |fun foo() { + | val a = 1 + |} + ""${'"'}.trimMargin("|") + lintMethod(code) + } + """, + extendedIndentOfParameters = FALSE, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = FALSE, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f1() { + @Language("kotlin") + val code = + ""${'"'} + |@Suppress("diktat") + |fun foo() { + | val a = 1 + |} + ""${'"'}.trimMargin("|") + lintMethod(code) + } + """, + extendedIndentOfParameters = TRUE, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = TRUE, + extendedIndentBeforeDot = TRUE), + includeWarnTests = false + ) + fun `no whitespace should be injected, case 3`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f2() { + @Language("kotlin") + val code = + ""${'"'} + >@Suppress("diktat") + >fun foo() { + > val a = 1 + >} + ""${'"'} . trimMargin ( marginPrefix = ">" ) + lintMethod(code) + } + """, + extendedIndentOfParameters = FALSE, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = FALSE, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f2() { + @Language("kotlin") + val code = + ""${'"'} + >@Suppress("diktat") + >fun foo() { + > val a = 1 + >} + ""${'"'} . trimMargin ( marginPrefix = ">" ) + lintMethod(code) + } + """, + extendedIndentOfParameters = TRUE, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = TRUE, + extendedIndentBeforeDot = TRUE), + includeWarnTests = false + ) + fun `no whitespace should be injected, case 4`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun checkScript() { + lintMethod( + ""${'"'} + |val A = "aa" + ""${'"'}.trimMargin(), + ) + } + """, + extendedIndentOfParameters = FALSE, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = FALSE, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun checkScript() { + lintMethod( + ""${'"'} + |val A = "aa" + ""${'"'}.trimMargin(), + ) + } + """, + extendedIndentOfParameters = TRUE, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = TRUE, + extendedIndentBeforeDot = TRUE), + includeWarnTests = false + ) + fun `no whitespace should be injected, case 5`() = Unit + } + + /** + * Expressions wrapped on an operator or an infix function. + * + * See [#1340](https://github.com/saveourtool/diktat/issues/1340). + */ + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `Expressions wrapped after operator` { + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or + View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 12] + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 12] + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 12] + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 12] + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or + View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 1`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or + View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 8] + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or + View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 4] + View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 4] + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 4] + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 4] + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 2`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val FOO = 1 + + const val BAR = 2 + + const val BAZ = 4 + + fun acceptInteger(arg: Int) = Unit + + fun main() { + acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ or + FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ or // diktat:WRONG_INDENTATION[expectedIndent = 12] + FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + const val FOO = 1 + + const val BAR = 2 + + const val BAZ = 4 + + fun acceptInteger(arg: Int) = Unit + + fun main() { + acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ or + FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ or // diktat:WRONG_INDENTATION[expectedIndent = 8] + FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 3`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val TRUE = true + + const val FALSE = false + + fun acceptBoolean(arg: Boolean) = Unit + + fun f() { + acceptBoolean(TRUE || + FALSE || // diktat:WRONG_INDENTATION[expectedIndent = 12] + TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + const val TRUE = true + + const val FALSE = false + + fun acceptBoolean(arg: Boolean) = Unit + + fun f() { + acceptBoolean(TRUE || + FALSE || // diktat:WRONG_INDENTATION[expectedIndent = 8] + TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 4`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val c = 3 + + 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val c = 3 + + 2 // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 5`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + infix fun Int.combineWith(that: Int) = this + that + + fun f() { + val x = 1 combineWith + 2 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12] + 4 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12] + 5 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12] + 6 // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + infix fun Int.combineWith(that: Int) = this + that + + fun f() { + val x = 1 combineWith + 2 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8] + 4 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8] + 5 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8] + 6 // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 6`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f(i1: Int, i2: Int, i3: Int): Int { + if (i2 > 0 && + i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 12] + return 2 + } + return 0 + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f(i1: Int, i2: Int, i3: Int): Int { + if (i2 > 0 && + i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 8] + return 2 + } + return 0 + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 7`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val value1 = 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3 // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val value1 = 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 4] + 3 // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 8`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val value1a = (1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val value1a = (1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 4] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 9`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val value2 = + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3 // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val value2 = + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3 // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 10`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val value3 = + (1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val value3 = + (1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 11`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value4 = identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value4 = identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 4] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 12`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value5 = identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value5 = identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 13`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value6 = + identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value6 = + identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 14`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + /** + * Line breaks: + * + * 1. before the expression body (`=`), + * 2. before the effective function arguments, and + * 3. on each infix function call ([to]). + */ + val value7 = + identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 16] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + /** + * Line breaks: + * + * 1. before the expression body (`=`), + * 2. before the effective function arguments, and + * 3. on each infix function call ([to]). + */ + val value7 = + identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 15`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value8 = identity(identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value8 = identity(identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 4] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 16`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value9 = identity(identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value9 = identity(identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 17`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value10 = + identity(identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value10 = + identity(identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 8] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 18`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value11 = + identity(identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 16] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value11 = + identity(identity( + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 19`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + // Same as above, but using a custom getter instead of an explicit initializer. + val value12 + get() = + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 16] + 3 // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + // Same as above, but using a custom getter instead of an explicit initializer. + val value12 + get() = + 1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3 // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 20`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + // Same as above, but using a custom getter instead of an explicit initializer. + val value13 + get() = + (1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 16] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + // Same as above, but using a custom getter instead of an explicit initializer. + val value13 + get() = + (1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 21`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value14 + get() = + identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 16] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value14 + get() = + identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 22`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value15 + get() = + identity(identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 16] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value15 + get() = + identity(identity(1 to + 2 to // diktat:WRONG_INDENTATION[expectedIndent = 12] + 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 23`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + g(42 as + Integer) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + g(42 as + Integer) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 24`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + g("" as? + String?) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + g("" as? + String?) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 25`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + // The dot-qualified expression is always single-indented. + "" + .length as + Int // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + // The dot-qualified expression is always single-indented. + "" + .length as + Int // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 26`() = Unit + } + + /** + * Expressions wrapped before an operator or an infix function. + * + * See [#1340](https://github.com/saveourtool/diktat/issues/1340). + */ + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `Expressions wrapped before operator` { + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE + or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 12] + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 12] + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 12] + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 12] + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE + or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 1`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE + or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8] + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE + or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 4] + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 4] + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 4] + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 4] + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 2`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val FOO = 1 + + const val BAR = 2 + + const val BAZ = 4 + + fun acceptInteger(arg: Int) = Unit + + fun main() { + acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ + or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ // diktat:WRONG_INDENTATION[expectedIndent = 12] + or FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + const val FOO = 1 + + const val BAR = 2 + + const val BAZ = 4 + + fun acceptInteger(arg: Int) = Unit + + fun main() { + acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ + or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ // diktat:WRONG_INDENTATION[expectedIndent = 8] + or FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 3`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val TRUE = true + + const val FALSE = false + + fun acceptBoolean(arg: Boolean) = Unit + + fun f() { + acceptBoolean(TRUE + || FALSE // diktat:WRONG_INDENTATION[expectedIndent = 12] + || TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + const val TRUE = true + + const val FALSE = false + + fun acceptBoolean(arg: Boolean) = Unit + + fun f() { + acceptBoolean(TRUE + || FALSE // diktat:WRONG_INDENTATION[expectedIndent = 8] + || TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 4`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val c = (3 + + 2) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val c = (3 + + 2) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 5`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + infix fun Int.combineWith(that: Int) = this + that + + fun f() { + val x = (1 + combineWith 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + combineWith 3 // diktat:WRONG_INDENTATION[expectedIndent = 12] + combineWith 4 // diktat:WRONG_INDENTATION[expectedIndent = 12] + combineWith 5 // diktat:WRONG_INDENTATION[expectedIndent = 12] + combineWith 6) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + infix fun Int.combineWith(that: Int) = this + that + + fun f() { + val x = (1 + combineWith 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + combineWith 3 // diktat:WRONG_INDENTATION[expectedIndent = 8] + combineWith 4 // diktat:WRONG_INDENTATION[expectedIndent = 8] + combineWith 5 // diktat:WRONG_INDENTATION[expectedIndent = 8] + combineWith 6) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 6`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f(i1: Int, i2: Int, i3: Int): Int { + if (i2 > 0 + && i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 12] + return 2 + } + return 0 + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f(i1: Int, i2: Int, i3: Int): Int { + if (i2 > 0 + && i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 8] + return 2 + } + return 0 + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 7`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val value1 = (1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val value1 = (1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 4] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 8`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val value2 = + (1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + val value2 = + (1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 9`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value3 = identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value3 = identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 4] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 10`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value4 = identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value4 = identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 11`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value5 = + identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value5 = + identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 12`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + /** + * Line breaks: + * + * 1. before the expression body (`=`), + * 2. before the effective function arguments, and + * 3. on each infix function call ([to]). + */ + val value6 = + identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + /** + * Line breaks: + * + * 1. before the expression body (`=`), + * 2. before the effective function arguments, and + * 3. on each infix function call ([to]). + */ + val value6 = + identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 13`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value7 = identity(identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value7 = identity(identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 4] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 14`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value8 = identity(identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value8 = identity(identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 15`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value9 = + identity(identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value9 = + identity(identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 16`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value10 = + identity(identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + val value10 = + identity(identity( + 1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 17`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + // Same as above, but using a custom getter instead of an explicit initializer. + val value11 + get() = + (1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + // Same as above, but using a custom getter instead of an explicit initializer. + val value11 + get() = + (1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 18`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value12 + get() = + identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value12 + get() = + identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 19`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value13 + get() = + identity(identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 16] + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun identity(t: T): T = t + + // Same as above, but using a custom getter instead of an explicit initializer. + val value13 + get() = + identity(identity(1 + to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12] + to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentAfterOperators = TRUE)) + fun `case 20`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + g(42 + as Integer) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + g(42 + as Integer) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 21`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + g("" + as? String?) // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + g("" + as? String?) // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 22`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + // The dot-qualified expression is always single-indented. + "" + .length + as Int // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f() { + // The dot-qualified expression is always single-indented. + "" + .length + as Int // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 23`() = Unit + } + + /** + * Parenthesized expressions. + * + * See [#1409](https://github.com/saveourtool/diktat/issues/1409). + */ + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `Parentheses-surrounded infix expressions` { + @IndentationTest( + first = IndentedSourceCode( + """ + fun f1() = ( + 1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 4] + ) + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + fun f1() = ( + 1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + ) + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 1`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f2() = ( + 1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + fun f2() = ( + 1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 2`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f3() = + ( // diktat:WRONG_INDENTATION[expectedIndent = 8] + 1 + 2 + ) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + fun f3() = + ( // diktat:WRONG_INDENTATION[expectedIndent = 4] + 1 + 2 + ) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 3`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f4() = + ( // diktat:WRONG_INDENTATION[expectedIndent = 8] + 1 + 2) + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + fun f4() = + ( // diktat:WRONG_INDENTATION[expectedIndent = 4] + 1 + 2) + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 4`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val v1 = ( + 1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 4] + ) + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + const val v1 = ( + 1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 8] + ) + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 5`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val v2 = ( + 1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + const val v2 = ( + 1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 6`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val v3 = + ( // diktat:WRONG_INDENTATION[expectedIndent = 8] + 1 + 2 + ) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + const val v3 = + ( // diktat:WRONG_INDENTATION[expectedIndent = 4] + 1 + 2 + ) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 7`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + const val v4 = + ( // diktat:WRONG_INDENTATION[expectedIndent = 8] + 1 + 2) + """, + extendedIndentForExpressionBodies = FALSE, + extendedIndentAfterOperators = TRUE), + second = IndentedSourceCode( + """ + const val v4 = + ( // diktat:WRONG_INDENTATION[expectedIndent = 4] + 1 + 2) + """, + extendedIndentForExpressionBodies = TRUE, + extendedIndentAfterOperators = FALSE)) + fun `case 8`() = Unit + } + + /** + * Dot-qualified and safe-access expressions. + * + * See [#1336](https://github.com/saveourtool/diktat/issues/1336). + */ + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `Dot- and safe-qualified expressions` { + @IndentationTest( + first = IndentedSourceCode( + """ + fun LocalDateTime.updateTime( + hour: Int? = null, + minute: Int? = null, + second: Int? = null, + ): LocalDateTime = withHour(hour ?: getHour()) + .withMinute(minute ?: getMinute()) // diktat:WRONG_INDENTATION[expectedIndent = 8] + .withSecond(second ?: getSecond()) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun LocalDateTime.updateTime( + hour: Int? = null, + minute: Int? = null, + second: Int? = null, + ): LocalDateTime = withHour(hour ?: getHour()) + .withMinute(minute ?: getMinute()) // diktat:WRONG_INDENTATION[expectedIndent = 4] + .withSecond(second ?: getSecond()) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 1`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f() { + first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 12] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 12] + } + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f() { + first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + } + """, + extendedIndentBeforeDot = TRUE)) + fun `case 2`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val a = first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + val a = first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 4] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 3`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + val b = first() + ?.second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + ?.third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + val b = first() + ?.second() // diktat:WRONG_INDENTATION[expectedIndent = 4] + ?.third() // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 4`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f1() = first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f1() = first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 4] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 5`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f2() = + first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 12] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f2() = + first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 6`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f3() = g(first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f3() = g(first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 4] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 4] + .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 4] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 7`() = Unit + + @IndentationTest( + first = IndentedSourceCode( + """ + fun f4() = g( + first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 12] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 12] + .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 12] + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f4() = g( + first() + .second() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .third() // diktat:WRONG_INDENTATION[expectedIndent = 8] + .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 8] + """, + extendedIndentBeforeDot = TRUE)) + fun `case 8`() = Unit + } + + @Nested + @TestMethodOrder(NaturalDisplayName::class) + inner class `If expressions` { + /** + * #1351, case 1. + * + * Boolean operator priority (`&&` has higher priority than `||`). + * + * Currently, this is an incorrectly formatted code kept to detect the + * contract breakage. It will be re-formatted once the issue is fixed. + */ + @IndentationTest( + first = IndentedSourceCode( + """ + fun f1() { + if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } || + !valueParameterNode.hasChildOfType(VAL_KEYWORD) && // diktat:WRONG_INDENTATION[expectedIndent = 12] + !valueParameterNode.hasChildOfType(VAR_KEYWORD) // diktat:WRONG_INDENTATION[expectedIndent = 16] + ) { + return + } + } + """, + extendedIndentAfterOperators = FALSE), + second = IndentedSourceCode( + """ + fun f1() { + if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } || + !valueParameterNode.hasChildOfType(VAL_KEYWORD) && // diktat:WRONG_INDENTATION[expectedIndent = 8] + !valueParameterNode.hasChildOfType(VAR_KEYWORD) // diktat:WRONG_INDENTATION[expectedIndent = 16] + ) { + return + } + } + """, + extendedIndentAfterOperators = TRUE)) + fun `case 1`() = Unit + + /** + * #1351, case 2. + * + * IDEA combines the values of `CONTINUATION_INDENT_IN_IF_CONDITIONS` + * and `CONTINUATION_INDENT_FOR_CHAINED_CALLS`, so the resulting indent + * can be anything between 8 (2x) and 16 (4x). + * + * Currently, this is an incorrectly formatted code kept to detect the + * contract breakage. It will be re-formatted once the issue is fixed. + */ + @IndentationTest( + first = IndentedSourceCode( + """ + fun f2() { + val prevComment = if (valueParameterNode.siblings(forward = false) + .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } // diktat:WRONG_INDENTATION[expectedIndent = 12] + .all { it.elementType == WHITE_SPACE } // diktat:WRONG_INDENTATION[expectedIndent = 12] + ) { + 0 + } else { + 1 + } + } + """, + extendedIndentBeforeDot = FALSE), + second = IndentedSourceCode( + """ + fun f2() { + val prevComment = if (valueParameterNode.siblings(forward = false) + .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } // diktat:WRONG_INDENTATION[expectedIndent = 8] + .all { it.elementType == WHITE_SPACE } // diktat:WRONG_INDENTATION[expectedIndent = 8] + ) { + 0 + } else { + 1 + } + } + """, + extendedIndentBeforeDot = TRUE)) + fun `case 2`() = Unit + } +} diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestResources.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestResources.kt deleted file mode 100644 index a63bc2fbd4..0000000000 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestResources.kt +++ /dev/null @@ -1,1785 +0,0 @@ -@file:Suppress("FILE_UNORDERED_IMPORTS")// False positives, see #1494. - -package org.cqfn.diktat.ruleset.chapter3.spaces - -import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS -import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES -import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END -import org.intellij.lang.annotations.Language - -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationConfigFactory as IndentationConfig - -/** - * Test resources shared by [IndentationRuleWarnTest] and - * [IndentationRuleFixTest]. - * - * @see IndentationRuleWarnTest - * @see IndentationRuleFixTest - */ -@Suppress("LargeClass") -internal object IndentationRuleTestResources { - /** - * See [#1330](https://github.com/saveourtool/diktat/issues/1330). - * - * @see expressionBodyFunctionsContinuationIndent - */ - @Language("kotlin") - private val expressionBodyFunctionsSingleIndent = arrayOf( - """ - |@Test - |fun `checking that suppression with ignore everything works`() { - | val code = - | ""${'"'} - | @Suppress("diktat") - | fun foo() { - | val a = 1 - | } - | ""${'"'}.trimIndent() - | lintMethod(code) - |} - """.trimMargin(), - - """ - |val currentTime: Time - | get() = - | with(currentDateTime) { - | Time(hour = hour, minute = minute, second = second) - | } - """.trimMargin(), - - """ - |fun formatDateByPattern(date: String, pattern: String = "ddMMyy"): String = - | DateTimeFormatter.ofPattern(pattern).format(LocalDate.parse(date)) - """.trimMargin(), - - """ - |private fun createLayoutParams(): WindowManager.LayoutParams = - | WindowManager.LayoutParams().apply { /* ... */ } - """.trimMargin(), - - """ - |private fun createLayoutParams(): WindowManager.LayoutParams = - | WindowManager.LayoutParams().apply { - | type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL - | token = composeView.applicationWindowToken - | width = WindowManager.LayoutParams.MATCH_PARENT - | height = WindowManager.LayoutParams.MATCH_PARENT - | format = PixelFormat.TRANSLUCENT - | - | // TODO make composable configurable - | - | // see https://stackoverflow.com/questions/43511326/android-making-activity-full-screen-with-status-bar-on-top-of-it - | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - | windowInsetsController?.hide(WindowInsets.Type.statusBars()) - | } else { - | @Suppress("DEPRECATION") - | systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or - | View.SYSTEM_UI_FLAG_FULLSCREEN or - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) - | } - | } - """.trimMargin(), - - """ - |val offsetDelta = - | if (shimmerAnimationType != ShimmerAnimationType.FADE) translateAnim.dp - | else 2000.dp - """.trimMargin(), - - """ - |private fun lerp(start: Float, stop: Float, fraction: Float): Float = - | (1 - fraction) * start + fraction * stop - """.trimMargin(), - - """ - |fun foo() = - | println() - """.trimMargin(), - - """ - |fun f() = - | x + (y + - | g(x) - | ) - """.trimMargin(), - - """ - |fun f() = - | (1 + - | 2) - """.trimMargin(), - ) - - /** - * See [#1330](https://github.com/saveourtool/diktat/issues/1330). - * - * @see expressionBodyFunctionsSingleIndent - */ - @Language("kotlin") - private val expressionBodyFunctionsContinuationIndent = arrayOf( - """ - |@Test - |fun `checking that suppression with ignore everything works`() { - | val code = - | ""${'"'} - | @Suppress("diktat") - | fun foo() { - | val a = 1 - | } - | ""${'"'}.trimIndent() - | lintMethod(code) - |} - """.trimMargin(), - - """ - |val currentTime: Time - | get() = - | with(currentDateTime) { - | Time(hour = hour, minute = minute, second = second) - | } - """.trimMargin(), - - """ - |fun formatDateByPattern(date: String, pattern: String = "ddMMyy"): String = - | DateTimeFormatter.ofPattern(pattern).format(LocalDate.parse(date)) - """.trimMargin(), - - """ - |private fun createLayoutParams(): WindowManager.LayoutParams = - | WindowManager.LayoutParams().apply { /* ... */ } - """.trimMargin(), - - """ - |private fun createLayoutParams(): WindowManager.LayoutParams = - | WindowManager.LayoutParams().apply { - | type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL - | token = composeView.applicationWindowToken - | width = WindowManager.LayoutParams.MATCH_PARENT - | height = WindowManager.LayoutParams.MATCH_PARENT - | format = PixelFormat.TRANSLUCENT - | - | // TODO make composable configurable - | - | // see https://stackoverflow.com/questions/43511326/android-making-activity-full-screen-with-status-bar-on-top-of-it - | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - | windowInsetsController?.hide(WindowInsets.Type.statusBars()) - | } else { - | @Suppress("DEPRECATION") - | systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or - | View.SYSTEM_UI_FLAG_FULLSCREEN or - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) - | } - | } - """.trimMargin(), - - """ - |val offsetDelta = - | if (shimmerAnimationType != ShimmerAnimationType.FADE) translateAnim.dp - | else 2000.dp - """.trimMargin(), - - """ - |private fun lerp(start: Float, stop: Float, fraction: Float): Float = - | (1 - fraction) * start + fraction * stop - """.trimMargin(), - - """ - |fun foo() = - | println() - """.trimMargin(), - - """ - |fun f() = - | x + (y + - | g(x) - | ) - """.trimMargin(), - - """ - |fun f() = - | (1 + - | 2) - """.trimMargin(), - ) - - /** - * See [#1330](https://github.com/saveourtool/diktat/issues/1330). - */ - val expressionBodyFunctions = mapOf( - false to expressionBodyFunctionsSingleIndent, - true to expressionBodyFunctionsContinuationIndent) - - /** - * See [#1347](https://github.com/saveourtool/diktat/issues/1347). - * - * @see whitespaceInStringLiteralsContinuationIndent - */ - @Language("kotlin") - private val whitespaceInStringLiteralsSingleIndent = arrayOf( - """ - |@Test - |fun `test method name`() { - | @Language("kotlin") - | val code = - | ""${'"'} - | @Suppress("diktat") - | fun foo() { - | val a = 1 - | } - | ""${'"'}.trimIndent() - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun f0() { - | @Language("kotlin") - | val code = - | ""${'"'} - | |@Suppress("diktat") - | |fun foo() { - | | val a = 1 - | |} - | ""${'"'}.trimMargin() - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun f1() { - | @Language("kotlin") - | val code = - | ""${'"'} - | |@Suppress("diktat") - | |fun foo() { - | | val a = 1 - | |} - | ""${'"'}.trimMargin("|") - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun f2() { - | @Language("kotlin") - | val code = - | ""${'"'} - | >@Suppress("diktat") - | >fun foo() { - | > val a = 1 - | >} - | ""${'"'} . trimMargin ( marginPrefix = ">" ) - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun checkScript() { - | lintMethod( - | ""${'"'} - | |val A = "aa" - | ""${'"'}.trimMargin(), - | ) - |} - """.trimMargin(), - ) - - /** - * See [#1347](https://github.com/saveourtool/diktat/issues/1347). - * - * @see whitespaceInStringLiteralsSingleIndent - */ - @Language("kotlin") - private val whitespaceInStringLiteralsContinuationIndent = arrayOf( - """ - |@Test - |fun `test method name`() { - | @Language("kotlin") - | val code = - | ""${'"'} - | @Suppress("diktat") - | fun foo() { - | val a = 1 - | } - | ""${'"'}.trimIndent() - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun f0() { - | @Language("kotlin") - | val code = - | ""${'"'} - | |@Suppress("diktat") - | |fun foo() { - | | val a = 1 - | |} - | ""${'"'}.trimMargin() - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun f1() { - | @Language("kotlin") - | val code = - | ""${'"'} - | |@Suppress("diktat") - | |fun foo() { - | | val a = 1 - | |} - | ""${'"'}.trimMargin("|") - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun f2() { - | @Language("kotlin") - | val code = - | ""${'"'} - | >@Suppress("diktat") - | >fun foo() { - | > val a = 1 - | >} - | ""${'"'} . trimMargin ( marginPrefix = ">" ) - | lintMethod(code) - |} - """.trimMargin(), - - """ - |fun checkScript() { - | lintMethod( - | ""${'"'} - | |val A = "aa" - | ""${'"'}.trimMargin(), - | ) - |} - """.trimMargin(), - ) - - /** - * See [#1347](https://github.com/saveourtool/diktat/issues/1347). - */ - val whitespaceInStringLiterals = mapOf( - false to whitespaceInStringLiteralsSingleIndent, - true to whitespaceInStringLiteralsContinuationIndent) - - /** - * Expressions wrapped on an operator or an infix function, single indent - * (`extendedIndentAfterOperators` is **off**). - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to [expressionsWrappedAfterOperatorContinuationIndent]. - * - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - * - * @see expressionsWrappedAfterOperatorContinuationIndent - */ - @Language("kotlin") - private val expressionsWrappedAfterOperatorSingleIndent = arrayOf( - """ - |fun f() { - | systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or - | View.SYSTEM_UI_FLAG_FULLSCREEN or - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - |} - """.trimMargin(), - - """ - |val systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or - | View.SYSTEM_UI_FLAG_FULLSCREEN or - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - """.trimMargin(), - - """ - |const val FOO = 1 - | - |const val BAR = 2 - | - |const val BAZ = 4 - | - |fun acceptInteger(arg: Int) = Unit - | - |fun main() { - | acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ or - | FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ or - | FOO or BAR or BAZ) - |} - """.trimMargin(), - - """ - |const val TRUE = true - | - |const val FALSE = false - | - |fun acceptBoolean(arg: Boolean) = Unit - | - |fun f() { - | acceptBoolean(TRUE || - | FALSE || - | TRUE) - |} - """.trimMargin(), - - """ - |val c = 3 + - | 2 - """.trimMargin(), - - """ - |infix fun Int.combineWith(that: Int) = this + that - | - |fun f() { - | val x = 1 combineWith - | 2 combineWith - | 3 combineWith - | 4 combineWith - | 5 combineWith - | 6 - |} - """.trimMargin(), - - """ - |fun f(i1: Int, i2: Int, i3: Int): Int { - | if (i2 > 0 && - | i3 < 0) { - | return 2 - | } - | return 0 - |} - """.trimMargin(), - - """ - |val value1 = 1 to - | 2 to - | 3 - """.trimMargin(), - - """ - |val value1a = (1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |val value2 = - | 1 to - | 2 to - | 3 - """.trimMargin(), - - """ - |val value3 = - | (1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value4 = identity(1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value5 = identity( - | 1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value6 = - | identity(1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |/** - | * Line breaks: - | * - | * 1. before the expression body (`=`), - | * 2. before the effective function arguments, and - | * 3. on each infix function call ([to]). - | */ - |val value7 = - | identity( - | 1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value8 = identity(identity(1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value9 = identity(identity( - | 1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value10 = - | identity(identity(1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value11 = - | identity(identity( - | 1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value12 - | get() = - | 1 to - | 2 to - | 3 - """.trimMargin(), - - """ - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value13 - | get() = - | (1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value14 - | get() = - | identity(1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value15 - | get() = - | identity(identity(1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun f() { - | g(42 as - | Integer) - |} - """.trimMargin(), - - """ - |fun f() { - | g("" as? - | String?) - |} - """.trimMargin(), - - """ - |fun f() { - | // The dot-qualified expression is always single-indented. - | "" - | .length as - | Int - |} - """.trimMargin(), - ) - - /** - * Expressions wrapped on an operator or an infix function, continuation - * indent (`extendedIndentAfterOperators` is **on**). - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to [expressionsWrappedAfterOperatorSingleIndent]. - * - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - * - * @see expressionsWrappedAfterOperatorSingleIndent - */ - @Language("kotlin") - private val expressionsWrappedAfterOperatorContinuationIndent = arrayOf( - """ - |fun f() { - | systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or - | View.SYSTEM_UI_FLAG_FULLSCREEN or - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - |} - """.trimMargin(), - - """ - |val systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or - | View.SYSTEM_UI_FLAG_FULLSCREEN or - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - """.trimMargin(), - - """ - |const val FOO = 1 - | - |const val BAR = 2 - | - |const val BAZ = 4 - | - |fun acceptInteger(arg: Int) = Unit - | - |fun main() { - | acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ or - | FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ or - | FOO or BAR or BAZ) - |} - """.trimMargin(), - - """ - |const val TRUE = true - | - |const val FALSE = false - | - |fun acceptBoolean(arg: Boolean) = Unit - | - |fun f() { - | acceptBoolean(TRUE || - | FALSE || - | TRUE) - |} - """.trimMargin(), - - """ - |val c = 3 + - | 2 - """.trimMargin(), - - """ - |infix fun Int.combineWith(that: Int) = this + that - | - |fun f() { - | val x = 1 combineWith - | 2 combineWith - | 3 combineWith - | 4 combineWith - | 5 combineWith - | 6 - |} - """.trimMargin(), - - """ - |fun f(i1: Int, i2: Int, i3: Int): Int { - | if (i2 > 0 && - | i3 < 0) { - | return 2 - | } - | return 0 - |} - """.trimMargin(), - - """ - |val value1 = 1 to - | 2 to - | 3 - """.trimMargin(), - - """ - |val value1a = (1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |val value2 = - | 1 to - | 2 to - | 3 - """.trimMargin(), - - """ - |val value3 = - | (1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value4 = identity(1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value5 = identity( - | 1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value6 = - | identity(1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |/** - | * Line breaks: - | * - | * 1. before the expression body (`=`), - | * 2. before the effective function arguments, and - | * 3. on each infix function call ([to]). - | */ - |val value7 = - | identity( - | 1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value8 = identity(identity(1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value9 = identity(identity( - | 1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value10 = - | identity(identity(1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value11 = - | identity(identity( - | 1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value12 - | get() = - | 1 to - | 2 to - | 3 - """.trimMargin(), - - """ - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value13 - | get() = - | (1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value14 - | get() = - | identity(1 to - | 2 to - | 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value15 - | get() = - | identity(identity(1 to - | 2 to - | 3)) - """.trimMargin(), - - """ - |fun f() { - | g(42 as - | Integer) - |} - """.trimMargin(), - - """ - |fun f() { - | g("" as? - | String?) - |} - """.trimMargin(), - - """ - |fun f() { - | // The dot-qualified expression is always single-indented. - | "" - | .length as - | Int - |} - """.trimMargin(), - ) - - /** - * Expressions wrapped on an operator or an infix function. - * - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - */ - val expressionsWrappedAfterOperator = mapOf( - false to expressionsWrappedAfterOperatorSingleIndent, - true to expressionsWrappedAfterOperatorContinuationIndent) - - /** - * Expressions wrapped before an operator or an infix function, single - * indent (`extendedIndentAfterOperators` is **off**). - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to [expressionsWrappedBeforeOperatorContinuationIndent]. - * - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - * - * @see expressionsWrappedBeforeOperatorContinuationIndent - */ - @Language("kotlin") - private val expressionsWrappedBeforeOperatorSingleIndent = arrayOf( - """ - |fun f() { - | systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE - | or View.SYSTEM_UI_FLAG_FULLSCREEN - | or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) - |} - """.trimMargin(), - - """ - |val systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE - | or View.SYSTEM_UI_FLAG_FULLSCREEN - | or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) - """.trimMargin(), - - """ - |const val FOO = 1 - | - |const val BAR = 2 - | - |const val BAZ = 4 - | - |fun acceptInteger(arg: Int) = Unit - | - |fun main() { - | acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ - | or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ - | or FOO or BAR or BAZ) - |} - """.trimMargin(), - - """ - |const val TRUE = true - | - |const val FALSE = false - | - |fun acceptBoolean(arg: Boolean) = Unit - | - |fun f() { - | acceptBoolean(TRUE - | || FALSE - | || TRUE) - |} - """.trimMargin(), - - """ - |val c = (3 - | + 2) - """.trimMargin(), - - """ - |infix fun Int.combineWith(that: Int) = this + that - | - |fun f() { - | val x = (1 - | combineWith 2 - | combineWith 3 - | combineWith 4 - | combineWith 5 - | combineWith 6) - |} - """.trimMargin(), - - """ - |fun f(i1: Int, i2: Int, i3: Int): Int { - | if (i2 > 0 - | && i3 < 0) { - | return 2 - | } - | return 0 - |} - """.trimMargin(), - - """ - |val value1 = (1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |val value2 = - | (1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value3 = identity(1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value4 = identity( - | 1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value5 = - | identity(1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |/** - | * Line breaks: - | * - | * 1. before the expression body (`=`), - | * 2. before the effective function arguments, and - | * 3. on each infix function call ([to]). - | */ - |val value6 = - | identity( - | 1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value7 = identity(identity(1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value8 = identity(identity( - | 1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value9 = - | identity(identity(1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value10 = - | identity(identity( - | 1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value11 - | get() = - | (1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value12 - | get() = - | identity(1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value13 - | get() = - | identity(identity(1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun f() { - | g(42 - | as Integer) - |} - """.trimMargin(), - - """ - |fun f() { - | g("" - | as? String?) - |} - """.trimMargin(), - - """ - |fun f() { - | // The dot-qualified expression is always single-indented. - | "" - | .length - | as Int - |} - """.trimMargin(), - ) - - /** - * Expressions wrapped before an operator or an infix function, continuation - * indent (`extendedIndentAfterOperators` is **on**). - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to [expressionsWrappedBeforeOperatorSingleIndent]. - * - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - * - * @see expressionsWrappedBeforeOperatorSingleIndent - */ - @Language("kotlin") - private val expressionsWrappedBeforeOperatorContinuationIndent = arrayOf( - """ - |fun f() { - | systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE - | or View.SYSTEM_UI_FLAG_FULLSCREEN - | or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) - |} - """.trimMargin(), - - """ - |val systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE - | or View.SYSTEM_UI_FLAG_FULLSCREEN - | or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) - """.trimMargin(), - - """ - |const val FOO = 1 - | - |const val BAR = 2 - | - |const val BAZ = 4 - | - |fun acceptInteger(arg: Int) = Unit - | - |fun main() { - | acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ - | or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ - | or FOO or BAR or BAZ) - |} - """.trimMargin(), - - """ - |const val TRUE = true - | - |const val FALSE = false - | - |fun acceptBoolean(arg: Boolean) = Unit - | - |fun f() { - | acceptBoolean(TRUE - | || FALSE - | || TRUE) - |} - """.trimMargin(), - - """ - |val c = (3 - | + 2) - """.trimMargin(), - - """ - |infix fun Int.combineWith(that: Int) = this + that - | - |fun f() { - | val x = (1 - | combineWith 2 - | combineWith 3 - | combineWith 4 - | combineWith 5 - | combineWith 6) - |} - """.trimMargin(), - - """ - |fun f(i1: Int, i2: Int, i3: Int): Int { - | if (i2 > 0 - | && i3 < 0) { - | return 2 - | } - | return 0 - |} - """.trimMargin(), - - """ - |val value1 = (1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |val value2 = - | (1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value3 = identity(1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value4 = identity( - | 1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value5 = - | identity(1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |/** - | * Line breaks: - | * - | * 1. before the expression body (`=`), - | * 2. before the effective function arguments, and - | * 3. on each infix function call ([to]). - | */ - |val value6 = - | identity( - | 1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value7 = identity(identity(1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value8 = identity(identity( - | 1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value9 = - | identity(identity(1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |val value10 = - | identity(identity( - | 1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value11 - | get() = - | (1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value12 - | get() = - | identity(1 - | to 2 - | to 3) - """.trimMargin(), - - """ - |fun identity(t: T): T = t - | - |// Same as above, but using a custom getter instead of an explicit initializer. - |val value13 - | get() = - | identity(identity(1 - | to 2 - | to 3)) - """.trimMargin(), - - """ - |fun f() { - | g(42 - | as Integer) - |} - """.trimMargin(), - - """ - |fun f() { - | g("" - | as? String?) - |} - """.trimMargin(), - - """ - |fun f() { - | // The dot-qualified expression is always single-indented. - | "" - | .length - | as Int - |} - """.trimMargin(), - ) - - /** - * Expressions wrapped before an operator or an infix function. - * - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - */ - val expressionsWrappedBeforeOperator = mapOf( - false to expressionsWrappedBeforeOperatorSingleIndent, - true to expressionsWrappedBeforeOperatorContinuationIndent) - - /** - * Parenthesized expressions, `extendedIndentForExpressionBodies` is **off**, - * `extendedIndentAfterOperators` is **on**. - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to - * [parenthesesSurroundedInfixExpressionsContinuationIndent]. - * - * See [#1409](https://github.com/saveourtool/diktat/issues/1409). - * - * @see parenthesesSurroundedInfixExpressionsContinuationIndent - */ - @Language("kotlin") - private val parenthesesSurroundedInfixExpressionsSingleIndent = arrayOf( - """ - |fun f1() = ( - | 1 + 2 - |) - """.trimMargin(), - - """ - |fun f2() = ( - | 1 + 2) - """.trimMargin(), - - """ - |fun f3() = - | ( - | 1 + 2 - | ) - """.trimMargin(), - - """ - |fun f4() = - | ( - | 1 + 2) - """.trimMargin(), - - """ - |const val v1 = ( - | 1 + 2 - |) - """.trimMargin(), - - """ - |const val v2 = ( - | 1 + 2) - """.trimMargin(), - - """ - |const val v3 = - | ( - | 1 + 2 - | ) - """.trimMargin(), - - """ - |const val v4 = - | ( - | 1 + 2) - """.trimMargin(), - ) - - /** - * Parenthesized expressions, `extendedIndentForExpressionBodies` is **on**, - * `extendedIndentAfterOperators` is **off**. - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to - * [parenthesesSurroundedInfixExpressionsSingleIndent]. - * - * See [#1409](https://github.com/saveourtool/diktat/issues/1409). - * - * @see parenthesesSurroundedInfixExpressionsSingleIndent - */ - @Language("kotlin") - private val parenthesesSurroundedInfixExpressionsContinuationIndent = arrayOf( - """ - |fun f1() = ( - | 1 + 2 - |) - """.trimMargin(), - - """ - |fun f2() = ( - | 1 + 2) - """.trimMargin(), - - """ - |fun f3() = - | ( - | 1 + 2 - | ) - """.trimMargin(), - - """ - |fun f4() = - | ( - | 1 + 2) - """.trimMargin(), - - """ - |const val v1 = ( - | 1 + 2 - |) - """.trimMargin(), - - """ - |const val v2 = ( - | 1 + 2) - """.trimMargin(), - - """ - |const val v3 = - | ( - | 1 + 2 - | ) - """.trimMargin(), - - """ - |const val v4 = - | ( - | 1 + 2) - """.trimMargin(), - ) - - /** - * Parenthesized expressions. - * - * See [#1409](https://github.com/saveourtool/diktat/issues/1409). - */ - val parenthesesSurroundedInfixExpressions = mapOf( - IndentationConfig( - NEWLINE_AT_END to false, - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to false, - EXTENDED_INDENT_AFTER_OPERATORS to true, - ) to parenthesesSurroundedInfixExpressionsSingleIndent, - IndentationConfig( - NEWLINE_AT_END to false, - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to true, - EXTENDED_INDENT_AFTER_OPERATORS to false, - ) to parenthesesSurroundedInfixExpressionsContinuationIndent) - - /** - * Dot-qualified and safe-access expressions, single indent - * (`extendedIndentBeforeDot` is **off**). - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to - * [dotQualifiedExpressionsContinuationIndent]. - * - * See [#1336](https://github.com/saveourtool/diktat/issues/1336). - * - * @see dotQualifiedExpressionsContinuationIndent - */ - @Language("kotlin") - val dotQualifiedExpressionsSingleIndent = arrayOf( - """ - |fun LocalDateTime.updateTime( - | hour: Int? = null, - | minute: Int? = null, - | second: Int? = null, - |): LocalDateTime = withHour(hour ?: getHour()) - | .withMinute(minute ?: getMinute()) - | .withSecond(second ?: getSecond()) - """.trimMargin(), - - """ - |fun f() { - | first() - | .second() - | .third() - |} - """.trimMargin(), - - """ - |val a = first() - | .second() - | .third() - """.trimMargin(), - - """ - |val b = first() - | ?.second() - | ?.third() - """.trimMargin(), - - """ - |fun f1() = first() - | .second() - | .third() - """.trimMargin(), - - """ - |fun f2() = - | first() - | .second() - | .third() - """.trimMargin(), - - """ - |fun f3() = g(first() - | .second() - | .third() - | .fourth()) - """.trimMargin(), - - """ - |fun f4() = g( - | first() - | .second() - | .third() - | .fourth()) - """.trimMargin(), - ) - - /** - * Dot-qualified and safe-access expressions, continuation indent - * (`extendedIndentBeforeDot` is **on**). - * - * When adding new code fragments to this list, be sure to also add their - * counterparts (preserving order) to - * [dotQualifiedExpressionsSingleIndent]. - * - * See [#1336](https://github.com/saveourtool/diktat/issues/1336). - * - * @see dotQualifiedExpressionsSingleIndent - */ - @Language("kotlin") - val dotQualifiedExpressionsContinuationIndent = arrayOf( - """ - |fun LocalDateTime.updateTime( - | hour: Int? = null, - | minute: Int? = null, - | second: Int? = null, - |): LocalDateTime = withHour(hour ?: getHour()) - | .withMinute(minute ?: getMinute()) - | .withSecond(second ?: getSecond()) - """.trimMargin(), - - """ - |fun f() { - | first() - | .second() - | .third() - |} - """.trimMargin(), - - """ - |val a = first() - | .second() - | .third() - """.trimMargin(), - - """ - |val b = first() - | ?.second() - | ?.third() - """.trimMargin(), - - """ - |fun f1() = first() - | .second() - | .third() - """.trimMargin(), - - """ - |fun f2() = - | first() - | .second() - | .third() - """.trimMargin(), - - """ - |fun f3() = g(first() - | .second() - | .third() - | .fourth()) - """.trimMargin(), - - """ - |fun f4() = g( - | first() - | .second() - | .third() - | .fourth()) - """.trimMargin(), - ) - - /** - * Dot-qualified and safe-access expressions. - * - * See [#1336](https://github.com/saveourtool/diktat/issues/1336). - */ - val dotQualifiedExpressions = mapOf( - false to dotQualifiedExpressionsSingleIndent, - true to dotQualifiedExpressionsContinuationIndent) - - @Language("kotlin") - @Suppress("COMMENT_WHITE_SPACE") - private val ifExpressionsSingleIndent = arrayOf( - /*- - * #1351, case 1. - * - * Boolean operator priority (`&&` has higher priority than `||`). - * - * Currently, this is an incorrectly formatted code kept to detect the - * contract breakage. It will be re-formatted once the issue is fixed. - */ - """ - |fun f1() { - | if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } || - | !valueParameterNode.hasChildOfType(VAL_KEYWORD) && - | !valueParameterNode.hasChildOfType(VAR_KEYWORD) - | ) { - | return - | } - |} - """.trimMargin(), - - /*- - * #1351, case 2. - * - * IDEA combines the values of `CONTINUATION_INDENT_IN_IF_CONDITIONS` - * and `CONTINUATION_INDENT_FOR_CHAINED_CALLS`, so the resulting indent - * can be anything between 8 (2x) and 16 (4x). - * - * Currently, this is an incorrectly formatted code kept to detect the - * contract breakage. It will be re-formatted once the issue is fixed. - */ - """ - |fun f2() { - | val prevComment = if (valueParameterNode.siblings(forward = false) - | .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } - | .all { it.elementType == WHITE_SPACE } - | ) { - | 0 - | } else { - | 1 - | } - |} - """.trimMargin(), - ) - - @Language("kotlin") - @Suppress("COMMENT_WHITE_SPACE") - private val ifExpressionsContinuationIndent = arrayOf( - /*- - * #1351, case 1. - * - * Boolean operator priority (`&&` has higher priority than `||`). - * - * Currently, this is an incorrectly formatted code kept to detect the - * contract breakage. It will be re-formatted once the issue is fixed. - */ - """ - |fun f1() { - | if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } || - | !valueParameterNode.hasChildOfType(VAL_KEYWORD) && - | !valueParameterNode.hasChildOfType(VAR_KEYWORD) - | ) { - | return - | } - |} - """.trimMargin(), - - /*- - * #1351, case 2. - * - * IDEA combines the values of `CONTINUATION_INDENT_IN_IF_CONDITIONS` - * and `CONTINUATION_INDENT_FOR_CHAINED_CALLS`, so the resulting indent - * can be anything between 8 (2x) and 16 (4x). - * - * Currently, this is an incorrectly formatted code kept to detect the - * contract breakage. It will be re-formatted once the issue is fixed. - */ - """ - |fun f2() { - | val prevComment = if (valueParameterNode.siblings(forward = false) - | .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } - | .all { it.elementType == WHITE_SPACE } - | ) { - | 0 - | } else { - | 1 - | } - |} - """.trimMargin(), - ) - - /** - * `if`-expression examples. - */ - val ifExpressions = mapOf( - false to ifExpressionsSingleIndent, - true to ifExpressionsContinuationIndent) -} diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestSuite.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestSuite.kt index e9919f7b15..bc222da8ee 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestSuite.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestSuite.kt @@ -9,5 +9,7 @@ import org.junit.platform.suite.api.Suite @Suite @SelectClasses( IndentationRuleWarnTest::class, - IndentationRuleFixTest::class) + IndentationRuleFixTest::class, + IndentationRuleTest::class, +) class IndentationRuleTestSuite diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestUtils.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestUtils.kt index 270d0eb099..ceaa333dc1 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestUtils.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleTestUtils.kt @@ -1,3 +1,4 @@ +@file:JvmName("IndentationRuleTestUtils") @file:Suppress("HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE") package org.cqfn.diktat.ruleset.chapter3.spaces @@ -63,19 +64,6 @@ internal fun Map.asRulesConfigList(): List = ) ) -/** - * @return a sequence which returns the elements of this array and, - * additionally, the result of concatenation of all the elements. - */ -internal fun Array.asSequenceWithConcatenation(): Sequence = - sequence { - yieldAll(asSequence()) - - if (size > 1) { - yield(concatenated()) - } - } - /** * @return a brief description of this code fragment. */ @@ -95,36 +83,3 @@ internal fun String.describe(): String { else -> "\"$first\u2026\" ($count line(s))" } } - -/** - * @return the concatenated content of this array (elements separated with - * blank lines). - */ -private fun Array.concatenated(): String = - joinToString(separator = "$NEWLINE$NEWLINE") - -/** - * Creates an `IndentationConfig` from zero or more - * [config entries][configEntries]. Invoke without arguments to create a - * default `IndentationConfig`. - * - * @param configEntries the configuration entries to create this instance from. - * @see [IndentationConfig] - */ -@Suppress("TestFunctionName", "FUNCTION_NAME_INCORRECT_CASE") -internal fun IndentationConfig(vararg configEntries: Pair): IndentationConfig = - IndentationConfigFactory(*configEntries) - -/** - * Allows to simultaneously enable or disable _all_ `extendedIndent*` flags. - * - * @param enabled whether the _continuation indent_ should be enabled or - * disabled. - * @return an array of map entries. - */ -internal fun extendedIndent(enabled: Boolean): Array> = - arrayOf( - EXTENDED_INDENT_OF_PARAMETERS to enabled, - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to enabled, - EXTENDED_INDENT_AFTER_OPERATORS to enabled, - EXTENDED_INDENT_BEFORE_DOT to enabled) diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt index 686b7514aa..79adc34eb8 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt @@ -2,41 +2,30 @@ package org.cqfn.diktat.ruleset.chapter3.spaces import org.cqfn.diktat.common.config.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.dotQualifiedExpressions -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionBodyFunctions -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionsWrappedAfterOperator -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionsWrappedBeforeOperator -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.ifExpressions -import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.parenthesesSurroundedInfixExpressions import org.cqfn.diktat.ruleset.constants.Warnings.WRONG_INDENTATION import org.cqfn.diktat.ruleset.junit.NaturalDisplayName import org.cqfn.diktat.ruleset.rules.chapter3.files.IndentationRule -import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.ALIGNED_PARAMETERS import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_OF_PARAMETERS import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.INDENTATION_SIZE -import org.cqfn.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END import org.cqfn.diktat.util.LintTestBase -import org.cqfn.diktat.util.assertNotNull import com.pinterest.ktlint.core.LintError import generated.WarningNames -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.SoftAssertions.assertSoftly -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestMethodOrder -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.CsvSource -import org.junit.jupiter.params.provider.ValueSource - -import java.util.function.Consumer +/** + * Legacy indentation tests. + * + * Consider adding new tests to [IndentationRuleTest] instead. + * + * @see IndentationRuleTest + */ @Suppress("LargeClass") @TestMethodOrder(NaturalDisplayName::class) class IndentationRuleWarnTest : LintTestBase(::IndentationRule) { @@ -726,275 +715,5 @@ class IndentationRuleWarnTest : LintTestBase(::IndentationRule) { ) } - /** - * @see warnTextRegex - */ private fun warnText(expected: Int, actual: Int) = "${WRONG_INDENTATION.warnText()} expected $expected but was $actual" - - companion object { - /** - * @see warnText - */ - @Language("RegExp") - private val warnTextRegex = "^\\Q${WRONG_INDENTATION.warnText()}\\E expected \\d+ but was \\d+$" - } - - /** - * See [#1330](https://github.com/saveourtool/diktat/issues/1330). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Expression body functions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentForExpressionBodies: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies) - - lintMultipleMethods( - expressionBodyFunctions[extendedIndentForExpressionBodies].assertNotNull(), - lintErrors = emptyArray(), - customConfig.asRulesConfigList() - ) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reported if mis-indented`(extendedIndentForExpressionBodies: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies) - - assertSoftly { softly -> - expressionBodyFunctions[!extendedIndentForExpressionBodies].assertNotNull().forEach { code -> - softly.assertThat(lintResult(code, customConfig.asRulesConfigList())) - .describedAs("lint result for ${code.describe()}") - .isNotEmpty - .hasSizeBetween(1, 20).allSatisfy(Consumer { lintError -> - assertThat(lintError.ruleId).describedAs("ruleId").isEqualTo(ruleId) - assertThat(lintError.canBeAutoCorrected).describedAs("canBeAutoCorrected").isTrue - assertThat(lintError.detail).matches(warnTextRegex) - }) - } - } - } - } - - /** - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Expressions wrapped after operator` { - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - expressionsWrappedAfterOperator[extendedIndentAfterOperators].assertNotNull(), - lintErrors = emptyArray(), - customConfig.asRulesConfigList() - ) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reported if mis-indented`(extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - assertSoftly { softly -> - expressionsWrappedAfterOperator[!extendedIndentAfterOperators].assertNotNull().forEach { code -> - softly.assertThat(lintResult(code, customConfig.asRulesConfigList())) - .describedAs("lint result for ${code.describe()}") - .isNotEmpty - .hasSizeBetween(1, 5).allSatisfy(Consumer { lintError -> - assertThat(lintError.ruleId).describedAs("ruleId").isEqualTo(ruleId) - assertThat(lintError.canBeAutoCorrected).describedAs("canBeAutoCorrected").isTrue - assertThat(lintError.detail).matches(warnTextRegex) - }) - } - } - } - } - - /** - * See [#1340](https://github.com/saveourtool/diktat/issues/1340). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Expressions wrapped before operator` { - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - expressionsWrappedBeforeOperator[extendedIndentAfterOperators].assertNotNull(), - lintErrors = emptyArray(), - customConfig.asRulesConfigList() - ) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reported if mis-indented`(extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - assertSoftly { softly -> - expressionsWrappedBeforeOperator[!extendedIndentAfterOperators].assertNotNull().forEach { code -> - softly.assertThat(lintResult(code, customConfig.asRulesConfigList())) - .describedAs("lint result for ${code.describe()}") - .isNotEmpty - .hasSizeBetween(1, 5).allSatisfy(Consumer { lintError -> - assertThat(lintError.ruleId).describedAs("ruleId").isEqualTo(ruleId) - assertThat(lintError.canBeAutoCorrected).describedAs("canBeAutoCorrected").isTrue - assertThat(lintError.detail).matches(warnTextRegex) - }) - } - } - } - } - - /** - * See [#1409](https://github.com/saveourtool/diktat/issues/1409). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Parentheses-surrounded infix expressions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}, $EXTENDED_INDENT_AFTER_OPERATORS = {1}") - @CsvSource(value = ["false,true", "true,false"]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentForExpressionBodies: Boolean, - extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters( - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies, - EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators, - ) - - lintMultipleMethods( - parenthesesSurroundedInfixExpressions[IndentationConfig(customConfig)].assertNotNull(), - lintErrors = emptyArray(), - customConfig.asRulesConfigList() - ) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_FOR_EXPRESSION_BODIES = {0}, $EXTENDED_INDENT_AFTER_OPERATORS = {1}") - @CsvSource(value = ["false,true", "true,false"]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reported if mis-indented`(extendedIndentForExpressionBodies: Boolean, - extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val actualCodeStyle = defaultConfig.withCustomParameters( - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to !extendedIndentForExpressionBodies, - EXTENDED_INDENT_AFTER_OPERATORS to !extendedIndentAfterOperators, - ) - val desiredCodeStyle = defaultConfig.withCustomParameters( - EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies, - EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators, - ) - - assertSoftly { softly -> - parenthesesSurroundedInfixExpressions[IndentationConfig(actualCodeStyle)].assertNotNull().forEach { code -> - softly.assertThat(lintResult(code, desiredCodeStyle.asRulesConfigList())) - .describedAs("lint result for ${code.describe()}") - .hasSizeBetween(0, 3).allSatisfy(Consumer { lintError -> - assertThat(lintError.ruleId).describedAs("ruleId").isEqualTo(ruleId) - assertThat(lintError.canBeAutoCorrected).describedAs("canBeAutoCorrected").isTrue - assertThat(lintError.detail).matches(warnTextRegex) - }) - } - } - } - } - - /** - * See [#1336](https://github.com/saveourtool/diktat/issues/1336). - */ - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `Dot- and safe-qualified expressions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_BEFORE_DOT = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentBeforeDot: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_BEFORE_DOT to extendedIndentBeforeDot) - - lintMultipleMethods( - dotQualifiedExpressions[extendedIndentBeforeDot].assertNotNull(), - lintErrors = emptyArray(), - customConfig.asRulesConfigList() - ) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_BEFORE_DOT = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reported if mis-indented`(extendedIndentBeforeDot: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_BEFORE_DOT to extendedIndentBeforeDot) - - assertSoftly { softly -> - dotQualifiedExpressions[!extendedIndentBeforeDot].assertNotNull().forEach { code -> - softly.assertThat(lintResult(code, customConfig.asRulesConfigList())) - .describedAs("lint result for ${code.describe()}") - .isNotEmpty - .hasSizeBetween(2, 3).allSatisfy(Consumer { lintError -> - assertThat(lintError.ruleId).describedAs("ruleId").isEqualTo(ruleId) - assertThat(lintError.canBeAutoCorrected).describedAs("canBeAutoCorrected").isTrue - assertThat(lintError.detail).matches(warnTextRegex) - }) - } - } - } - } - - @Nested - @TestMethodOrder(NaturalDisplayName::class) - inner class `If expressions` { - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be properly indented`(extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - lintMultipleMethods( - ifExpressions[extendedIndentAfterOperators].assertNotNull(), - lintErrors = emptyArray(), - customConfig.asRulesConfigList() - ) - } - - @ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}") - @ValueSource(booleans = [false, true]) - @Tag(WarningNames.WRONG_INDENTATION) - fun `should be reported if mis-indented`(extendedIndentAfterOperators: Boolean) { - val defaultConfig = IndentationConfig(NEWLINE_AT_END to false) - val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators) - - assertSoftly { softly -> - ifExpressions[!extendedIndentAfterOperators].assertNotNull().forEach { code -> - softly.assertThat(lintResult(code, customConfig.asRulesConfigList())) - .describedAs("lint result for ${code.describe()}") - .hasSizeBetween(0, 3).allSatisfy(Consumer { lintError -> - assertThat(lintError.ruleId).describedAs("ruleId").isEqualTo(ruleId) - assertThat(lintError.canBeAutoCorrected).describedAs("canBeAutoCorrected").isTrue - assertThat(lintError.detail).matches(warnTextRegex) - }) - } - } - } - } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTest.kt index 356298e86f..a5b1434306 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTest.kt @@ -5,13 +5,14 @@ import org.junit.jupiter.api.Tag import org.junit.jupiter.api.TestTemplate import org.junit.jupiter.api.extension.ExtendWith import kotlin.annotation.AnnotationRetention.RUNTIME -import kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS import kotlin.annotation.AnnotationTarget.FUNCTION -@Target( - ANNOTATION_CLASS, - FUNCTION, -) +/** + * @property includeWarnTests whether unit tests for the "warn" mode should also + * be generated. If `false`, only fix mode tests get generated. The default is + * `true`. + */ +@Target(FUNCTION) @Retention(RUNTIME) @MustBeDocumented @TestTemplate @@ -20,4 +21,5 @@ import kotlin.annotation.AnnotationTarget.FUNCTION annotation class IndentationTest( val first: IndentedSourceCode, val second: IndentedSourceCode, + val includeWarnTests: Boolean = true ) diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTestInvocationContextProvider.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTestInvocationContextProvider.kt index 1172a8f592..38476f2bb9 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTestInvocationContextProvider.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/junit/IndentationTestInvocationContextProvider.kt @@ -17,6 +17,7 @@ import org.junit.jupiter.api.extension.TestTemplateInvocationContext import org.junit.platform.commons.util.AnnotationUtils.findAnnotation import java.util.SortedMap import java.util.stream.Stream +import java.util.stream.Stream.concat import kotlin.reflect.KClass /** @@ -50,15 +51,18 @@ class IndentationTestInvocationContextProvider : RuleInvocationContextProvider): Stream { val testMethod = context.requiredTestMethod val indentationTest = findAnnotation(testMethod, annotationType().java).get() - val testInput0 = indentationTest.first.extractTestInput(supportedTags) + val includeWarnTests = indentationTest.includeWarnTests + + val testInput0 = indentationTest.first.extractTestInput(supportedTags, includeWarnTests) val (code0, expectedErrors0, customConfig0) = testInput0 - val testInput1 = indentationTest.second.extractTestInput(supportedTags) + val testInput1 = indentationTest.second.extractTestInput(supportedTags, includeWarnTests) val (code1, expectedErrors1, customConfig1) = testInput1 assertThat(code0) @@ -72,21 +76,33 @@ class IndentationTestInvocationContextProvider : RuleInvocationContextProvider( - IndentationTestWarnInvocationContext(customConfig0, actualCode = code0), - IndentationTestWarnInvocationContext(customConfig1, actualCode = code1), - IndentationTestWarnInvocationContext(customConfig1, actualCode = code0, expectedErrors0), - IndentationTestWarnInvocationContext(customConfig0, actualCode = code1, expectedErrors1), IndentationTestFixInvocationContext(customConfig0, actualCode = code0), IndentationTestFixInvocationContext(customConfig1, actualCode = code1), IndentationTestFixInvocationContext(customConfig1, actualCode = code0, expectedCode = code1), IndentationTestFixInvocationContext(customConfig0, actualCode = code1, expectedCode = code0), - ).sorted { left, right -> + ).let { fixTests -> + when { + includeWarnTests -> concat(fixTests, Stream.of( + IndentationTestWarnInvocationContext(customConfig0, actualCode = code0), + IndentationTestWarnInvocationContext(customConfig1, actualCode = code1), + IndentationTestWarnInvocationContext(customConfig1, actualCode = code0, expectedErrors0), + IndentationTestWarnInvocationContext(customConfig0, actualCode = code1, expectedErrors1), + )) + + else -> fixTests + } + }.sorted { left, right -> left.getDisplayName(0).compareTo(right.getDisplayName(0)) } } - private fun IndentedSourceCode.extractTestInput(supportedTags: List): IndentationTestInput { - val (code, expectedErrors) = extractExpectedErrors(code, supportedTags) + /** + * @param includeWarnTests whether unit tests for the "warn" mode should also + * be generated. If `false`, only fix mode tests get generated. + */ + private fun IndentedSourceCode.extractTestInput(supportedTags: List, + includeWarnTests: Boolean): IndentationTestInput { + val (code, expectedErrors) = extractExpectedErrors(code, supportedTags, includeWarnTests) return IndentationTestInput(code, expectedErrors, customConfig()) } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/junit/RuleInvocationContextProvider.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/junit/RuleInvocationContextProvider.kt index 95a11cf19b..6e25654b59 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/junit/RuleInvocationContextProvider.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/junit/RuleInvocationContextProvider.kt @@ -76,11 +76,16 @@ interface RuleInvocationContextProvider): ExpectedLintErrors { + fun extractExpectedErrors(@Language("kotlin") code: String, + supportedTags: List, + includeWarnTests: Boolean + ): ExpectedLintErrors { require(supportedTags.isNotEmpty()) { "The list of supported tags is empty" } @@ -115,10 +120,12 @@ interface RuleInvocationContextProvider supportedTags[0] else -> "any of $supportedTags" } - assertThat(expectedErrors) - .describedAs("The code contains no expected-error annotations or an unsupported tag is used (should be $supportedTagsDescription). " + - "Please annotate your code:$NEWLINE$filteredCode") - .isNotEmpty + if (includeWarnTests) { + assertThat(expectedErrors) + .describedAs("The code contains no expected-error annotations or an unsupported tag is used (should be $supportedTagsDescription). " + + "Please annotate your code or set `includeWarnTests` to `false`:$NEWLINE$filteredCode") + .isNotEmpty + } return ExpectedLintErrors(filteredCode, expectedErrors) } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt index e36bb0056d..917ba5f6d3 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt @@ -1,13 +1,10 @@ package org.cqfn.diktat.util import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ruleset.chapter3.spaces.asSequenceWithConcatenation import com.pinterest.ktlint.core.KtLint import com.pinterest.ktlint.core.LintError import com.pinterest.ktlint.core.Rule -import org.assertj.core.api.AbstractSoftAssertions import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.SoftAssertions.assertSoftly import org.intellij.lang.annotations.Language /** @@ -82,64 +79,4 @@ open class LintTestBase(private val ruleSupplier: (rulesConfigList: List, - vararg lintErrors: LintError, - rulesConfigList: List? = null, - fileName: String? = null - ) { - require(fragments.isNotEmpty()) { - "code fragments is an empty array" - } - - assertSoftly { softly -> - fragments.asSequenceWithConcatenation().forEach { fragment -> - softly.lintMethodSoftly( - fragment, - lintErrors = lintErrors, - rulesConfigList, - fileName - ) - } - } - } - - /** - * Similar to [lintMethod], but can be invoked from a scope of - * `AbstractSoftAssertions` in order to accumulate test results from linting - * _multiple_ code fragments. - * - * @param rulesConfigList the list of rules which can optionally override - * the [default value][LintTestBase.rulesConfigList]. - * @see lintMethod - */ - private fun AbstractSoftAssertions.lintMethodSoftly( - @Language("kotlin") code: String, - vararg lintErrors: LintError, - rulesConfigList: List? = null, - fileName: String? = null - ) { - require(code.isNotBlank()) { - "code is blank" - } - - collectAssertionErrors { - lintMethod(code, expectedLintErrors = lintErrors, rulesConfigList, fileName) - } - } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt index d356413160..28d2522f58 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt @@ -15,13 +15,11 @@ import com.pinterest.ktlint.core.RuleSet import com.pinterest.ktlint.core.RuleSetProvider import com.pinterest.ktlint.core.api.FeatureInAlphaState import mu.KotlinLogging -import org.assertj.core.api.AbstractSoftAssertions import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.fail import org.assertj.core.api.SoftAssertions.assertSoftly import org.intellij.lang.annotations.Language import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.opentest4j.MultipleFailuresError import java.io.File import java.nio.file.NoSuchFileException @@ -190,30 +188,6 @@ internal fun ProcessBuilder.prependPath(pathEntry: Path) { internal fun T?.assertNotNull(lazyFailureMessage: () -> String = { "Expecting actual not to be null" }): T = this ?: fail(lazyFailureMessage()) -/** - * When within a scope of an `AbstractSoftAssertions`, collects failures - * thrown by [block], correctly accumulating multiple failures from nested - * soft assertions (if any). - * - * @param block the code block to execute, may throw a [MultipleFailuresError]. - * @see org.assertj.core.api.AssertionErrorCollector.collectAssertionError - */ -internal fun AbstractSoftAssertions.collectAssertionErrors(block: () -> Unit) = - try { - block() - } catch (mfe: MultipleFailuresError) { - mfe.failures.forEach { failure -> - when (failure) { - is AssertionError -> collectAssertionError(failure) - else -> fail(failure.toString(), failure) - } - } - } catch (ae: AssertionError) { - collectAssertionError(ae) - } catch (th: Throwable) { - fail(th.toString(), th) - } - /** * @param ruleSetProviderRef * @param text