diff --git a/diktat-analysis.yml b/diktat-analysis.yml index 4e4ee6bc7a..af33e6558d 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -8,6 +8,7 @@ disabledChapters: "" testDirs: test kotlinVersion: 1.4.30 + srcDirectories: "main" # Checks that the Class/Enum/Interface name does not match Pascal case - name: CLASS_NAME_INCORRECT enabled: true diff --git a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt index 771e063597..9cc8ac6f61 100644 --- a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt +++ b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt @@ -101,7 +101,11 @@ data class CommonConfiguration(private val configuration: Map?) * List of directory names which will be used to detect test sources */ val testAnchors: List by lazy { - (configuration ?: emptyMap()).getOrDefault("testDirs", "test").split(',') + val testDirs = (configuration ?: emptyMap()).getOrDefault("testDirs", "test").split(',') + if (testDirs.any { !it.toLowerCase().endsWith("test") }) { + log.error("test directory names should end with `test`") + } + testDirs } /** @@ -130,6 +134,17 @@ data class CommonConfiguration(private val configuration: Map?) } } + /** + * Get source directories from configuration + */ + val srcDirectories: List by lazy { + val srcDirs = configuration?.get("srcDirectories")?.split(",")?.map { it.trim() } ?: listOf("main") + if (srcDirs.any { !it.toLowerCase().endsWith("main") }) { + log.error("source directory names should end with `main`") + } + srcDirs + } + /** * False if configuration has been read from config file, true if defaults are used */ diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt index cfb90b317f..835060810d 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt @@ -1,5 +1,6 @@ package org.cqfn.diktat.ruleset.rules.chapter1 +import org.cqfn.diktat.common.config.rules.CommonConfiguration import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.common.config.rules.getCommonConfiguration import org.cqfn.diktat.ruleset.constants.Warnings.INCORRECT_PACKAGE_SEPARATOR @@ -22,6 +23,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.lexer.KtTokens.PACKAGE_KEYWORD import org.slf4j.LoggerFactory + import java.util.concurrent.atomic.AtomicInteger /** @@ -47,7 +49,7 @@ class PackageNaming(configRules: List) : DiktatRule( if (node.elementType == PACKAGE_DIRECTIVE) { val filePath = node.getRootNode().getFilePath() // calculating package name based on the directory where the file is placed - val realPackageName = calculateRealPackageName(filePath) + val realPackageName = calculateRealPackageName(filePath, configuration) // if node isLeaf - this means that there is no package name declared if (node.isLeaf() && !filePath.isKotlinScript()) { @@ -92,7 +94,7 @@ class PackageNaming(configRules: List) : DiktatRule( * * @return list with words that are parts of package name like [org, diktat, name] */ - private fun calculateRealPackageName(fileName: String): List { + private fun calculateRealPackageName(fileName: String, configuration: CommonConfiguration): List { val filePathParts = fileName.splitPathToDirs() return if (!filePathParts.contains(PACKAGE_PATH_ANCHOR)) { @@ -104,8 +106,9 @@ class PackageNaming(configRules: List) : DiktatRule( // 1) getting a path after the base project directory (after "src" directory) // 2) removing src/main/kotlin/java/e.t.c dirs and removing file name // 3) adding company's domain name at the beginning + val allDirs = languageDirNames + configuration.srcDirectories + configuration.testAnchors val fileSubDir = filePathParts.subList(filePathParts.lastIndexOf(PACKAGE_PATH_ANCHOR), filePathParts.size - 1) - .dropWhile { languageDirNames.contains(it) } + .dropWhile { allDirs.contains(it) } // no need to add DOMAIN_NAME to the package name if it is already in path val domainPrefix = if (!fileSubDir.joinToString(PACKAGE_SEPARATOR).startsWith(domainName)) domainName.split(PACKAGE_SEPARATOR) else emptyList() domainPrefix + fileSubDir @@ -259,6 +262,6 @@ class PackageNaming(configRules: List) : DiktatRule( * Directories that are supposed to be first in sources file paths, relative to [PACKAGE_PATH_ANCHOR]. * For kotlin multiplatform projects directories for targets from [kmmTargets] are supported. */ - val languageDirNames = listOf("src", "main", "test", "java", "kotlin") + kmmTargets.flatMap { listOf("${it}Main", "${it}Test") } + val languageDirNames = listOf("src", "java", "kotlin") + kmmTargets.flatMap { listOf("${it}Main", "${it}Test") } } } diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index 4a05681ddb..5c89bffb56 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -8,6 +8,7 @@ disabledChapters: "" testDirs: test kotlinVersion: 1.4.30 + srcDirectories: "main" # Checks that the Class/Enum/Interface name does not match Pascal case - name: CLASS_NAME_INCORRECT enabled: true diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index 14e8dae481..ad1ed749f5 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -6,6 +6,7 @@ testDirs: test disabledChapters: "" kotlinVersion: 1.4 + srcDirectories: "main" # Checks that the Class/Enum/Interface name does not match Pascal case - name: CLASS_NAME_INCORRECT enabled: true diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt index 4e2b3043b1..1f700f71ce 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt @@ -25,6 +25,13 @@ class PackageNamingWarnTest : LintTestBase(::PackageNaming) { private val rulesConfigListEmptyDomainName: List = listOf( RulesConfig("DIKTAT_COMMON", true, mapOf("domainName" to "")) ) + private val rulesConfigSourceDirectories: List = listOf( + RulesConfig("DIKTAT_COMMON", true, mapOf( + "domainName" to "org.cqfn.diktat", + "srcDirectories" to "nativeMain, mobileMain", + "testDirs" to "nativeTest" + )) + ) @Test @Tag(WarningNames.PACKAGE_NAME_MISSING) @@ -148,6 +155,84 @@ class PackageNamingWarnTest : LintTestBase(::PackageNaming) { ) } + @Test + @Tag(WarningNames.PACKAGE_NAME_INCORRECT_SYMBOLS) + fun `test source config`() { + lintMethod( + + """ + package org.cqfn.diktat.domain + + import org.cqfn.diktat.a.b.c + + /** + * testComment + */ + class TestPackageName { } + + """.trimIndent(), + fileName = "~/diktat/diktat-rules/src/nativeMain/kotlin/org/cqfn/diktat/domain/BlaBla.kt", + rulesConfigList = rulesConfigSourceDirectories + ) + + lintMethod( + + """ + package org.cqfn.diktat.domain + + import org.cqfn.diktat.a.b.c + + /** + * testComment + */ + class TestPackageName { } + + """.trimIndent(), + LintError(1, 9, ruleId, "${PACKAGE_NAME_INCORRECT_PATH.warnText()} org.cqfn.diktat.main.kotlin.org.cqfn.diktat.domain", true), + fileName = "~/diktat/diktat-rules/src/main/kotlin/org/cqfn/diktat/domain/BlaBla.kt", + rulesConfigList = rulesConfigSourceDirectories + ) + } + + @Test + @Tag(WarningNames.PACKAGE_NAME_INCORRECT_SYMBOLS) + fun `test directories for test config`() { + lintMethod( + + """ + package org.cqfn.diktat.domain + + import org.cqfn.diktat.a.b.c + + /** + * testComment + */ + class TestPackageName { } + + """.trimIndent(), + fileName = "~/diktat/diktat-rules/src/nativeTest/kotlin/org/cqfn/diktat/domain/BlaBla.kt", + rulesConfigList = rulesConfigSourceDirectories + ) + + lintMethod( + + """ + package org.cqfn.diktat.domain + + import org.cqfn.diktat.a.b.c + + /** + * testComment + */ + class TestPackageName { } + + """.trimIndent(), + LintError(1, 9, ruleId, "${PACKAGE_NAME_INCORRECT_PATH.warnText()} org.cqfn.diktat.test.kotlin.org.cqfn.diktat.domain", true), + fileName = "~/diktat/diktat-rules/src/test/kotlin/org/cqfn/diktat/domain/BlaBla.kt", + rulesConfigList = rulesConfigSourceDirectories + ) + } + @Test @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH) fun `regression - incorrect warning on file under test directory`() {