diff --git a/CHANGELOG.md b/CHANGELOG.md index b1a0937a9b..129f6fdad3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Do not force blank line before function in right hand side of assignment `blank-line-before-declaration` [#2260](https://github.com/pinterest/ktlint/issue/2260) * Ignore override of function in rule `function-naming` [#2271](https://github.com/pinterest/ktlint/issue/2271) * Do not replace function body having a return statement only in case the return statement contains an intermediate exit point 'function-expression-body' [#2269](https://github.com/pinterest/ktlint/issue/2269) +* Ignore function naming in Kotest classes `function-naming` [#2289](https://github.com/pinterest/ktlint/issue/2289) * Prevent wrapping of nested multiline binary expression before operation reference as it results in a compilation error `multiline-expression-wrapping` [#2286](https://github.com/pinterest/ktlint/issue/2286) * Force blank line before object declaration if preceded by another declaration `blank-line-before-declaration` [#2284](https://github.com/pinterest/ktlint/issues/2284) diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRule.kt index fb1623ebbb..b5d4142a0e 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRule.kt @@ -52,19 +52,15 @@ public class FunctionNamingRule : (node.psi as KtImportDirective) .importPath ?.pathStr - ?.takeIf { - it.startsWith(ORG_JUNIT) || it.startsWith(ORG_TESTNG) || it.startsWith(KOTLIN_TEST) - }?.let { - // Assume that each file that imports a Junit Jupiter Api class is a test class - isTestClass = true - } + ?.takeIf { importPathString -> TEST_LIBRARIES_SET.any { importPathString.startsWith(it) } } + ?.let { isTestClass = true } } node .takeIf { node.elementType == FUN } ?.takeUnless { node.isFactoryMethod() || - node.isTestMethod() || + node.isMethodInTestClass() || node.hasValidFunctionName() || node.isAnonymousFunction() || node.isOverrideFunction() || @@ -87,7 +83,7 @@ public class FunctionNamingRule : (this.psi as KtFunction) .let { it.hasDeclaredReturnType() && it.name == it.typeReference?.text } - private fun ASTNode.isTestMethod() = isTestClass && hasValidTestFunctionName() + private fun ASTNode.isMethodInTestClass() = isTestClass && hasValidTestFunctionName() private fun ASTNode.hasValidTestFunctionName() = findChildByType(IDENTIFIER) @@ -159,9 +155,13 @@ public class FunctionNamingRule : private val VALID_FUNCTION_NAME_REGEXP = "[a-z][A-Za-z\\d]*".regExIgnoringDiacriticsAndStrokesOnLetters() private val VALID_TEST_FUNCTION_NAME_REGEXP = "(`.*`)|([a-z][A-Za-z\\d_]*)".regExIgnoringDiacriticsAndStrokesOnLetters() - private const val KOTLIN_TEST = "kotlin.test" - private const val ORG_JUNIT = "org.junit" - private const val ORG_TESTNG = "org.testng" + private val TEST_LIBRARIES_SET = + setOf( + "io.kotest", + "kotlin.test", + "org.junit", + "org.testng", + ) } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRuleTest.kt index 50b6ca761e..4d8563c355 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRuleTest.kt @@ -84,6 +84,7 @@ class FunctionNamingRuleTest { @ParameterizedTest(name = "Junit import: {0}") @ValueSource( strings = [ + "io.kotest.*", "org.junit.jupiter.api.Test", "org.junit.jupiter.api.*", "org.junit.jupiter.*",