diff --git a/detekt-api/build.gradle b/detekt-api/build.gradle index 23d4336fb..51d8f88a9 100644 --- a/detekt-api/build.gradle +++ b/detekt-api/build.gradle @@ -1,22 +1,39 @@ buildscript { ext.kotlin_version = '1.0.4' + ext.spek_version = '1.1.18' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M2' } } apply plugin: 'kotlin' +apply plugin: 'org.junit.platform.gradle.plugin' repositories { mavenCentral() + maven { + url "http://dl.bintray.com/jetbrains/spek" + } +} + +junitPlatform { + engines { + include 'spek' + } } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-compiler:$kotlin_version" + compile group: 'org.yaml', name: 'snakeyaml', version: '1.17' + testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testCompile "org.jetbrains.spek:spek-api:$spek_version" + testRuntime 'org.junit.platform:junit-platform-launcher:1.0.0-M2' + testRuntime "org.jetbrains.spek:spek-junit-platform-engine:$spek_version" } diff --git a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Config.kt b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Config.kt index 599141d15..0a5883f88 100644 --- a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Config.kt +++ b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Config.kt @@ -1,6 +1,41 @@ package io.gitlab.arturbosch.detekt.api +import org.yaml.snakeyaml.Yaml +import java.nio.file.Files +import java.nio.file.Path + /** * @author Artur Bosch */ -class Config(val properties: Map) \ No newline at end of file +@Suppress("UNCHECKED_CAST") +class Config private constructor(val properties: Map) { + + fun subConfig(key: String): Config { + val subProperties = properties.getOrElse(key) { mapOf() } + return Config(subProperties as Map) + } + + fun valueOrDefault(key: String, default: () -> T): T { + return properties.getOrElse(key) { default() } as T + } + + internal class InvalidConfigurationError(msg: String = "Provided configuration file is invalid:" + + " Structure must be of type Map!") : RuntimeException(msg) + + companion object { + fun load(path: Path): Config { + require(Files.exists(path) && path.toString().endsWith("yml")) + return Files.newBufferedReader(path).use { + val map = Yaml().loadAll(it).iterator().next() + if (map is Map<*, *>) { + Config(map as Map) + } else { + throw InvalidConfigurationError() + } + } + } + + val EMPTY: Config = Config(mapOf()) + } +} + diff --git a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/KastVisitor.kt b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/KastVisitor.kt index a4a6a4751..abc945d9b 100644 --- a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/KastVisitor.kt +++ b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/KastVisitor.kt @@ -6,5 +6,4 @@ import org.jetbrains.kotlin.psi.KtTreeVisitorVoid * @author artur */ open class KastVisitor : KtTreeVisitorVoid() { - } \ No newline at end of file diff --git a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Rule.kt b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Rule.kt index 2cf00242d..8f4dde433 100644 --- a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Rule.kt +++ b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Rule.kt @@ -20,16 +20,20 @@ abstract class Rule(val id: String, val severity: Severity = Rule.Severity.Minor } open fun visit(root: ASTNode) { + clearFindings() preVisit(root) root.visit(this) postVisit(root) } + internal fun clearFindings() { + _findings = mutableListOf() + } + protected open fun postVisit(root: ASTNode) { } protected open fun preVisit(root: ASTNode) { - _findings = mutableListOf() } protected fun addFindings(vararg finding: Finding) { diff --git a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/RuleSetProvider.kt b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/RuleSetProvider.kt index 7ff67bc40..26ede8ba8 100644 --- a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/RuleSetProvider.kt +++ b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/RuleSetProvider.kt @@ -4,6 +4,5 @@ package io.gitlab.arturbosch.detekt.api * @author Artur Bosch */ interface RuleSetProvider { - - fun instance(): RuleSet + fun instance(config: Config): RuleSet } \ No newline at end of file diff --git a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/TokenRule.kt b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/TokenRule.kt index e3b130492..85f0822ee 100644 --- a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/TokenRule.kt +++ b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/TokenRule.kt @@ -5,13 +5,14 @@ import com.intellij.lang.ASTNode /** * @author Artur Bosch */ -abstract class TokenRule(id: String) : Rule(id) { +abstract class TokenRule(id: String, severity: Severity = Rule.Severity.Minor) : Rule(id, severity) { override fun visit(root: ASTNode) { + clearFindings() preVisit(root) root.visitTokens { procedure(it) } postVisit(root) } abstract fun procedure(node: ASTNode): Unit -} \ No newline at end of file +} diff --git a/detekt-api/src/test/kotlin/io/gitlab/arturbosch/detekt/api/ConfigSpec.kt b/detekt-api/src/test/kotlin/io/gitlab/arturbosch/detekt/api/ConfigSpec.kt new file mode 100644 index 000000000..cabd9b5d2 --- /dev/null +++ b/detekt-api/src/test/kotlin/io/gitlab/arturbosch/detekt/api/ConfigSpec.kt @@ -0,0 +1,57 @@ +package io.gitlab.arturbosch.detekt.api + +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.describe +import org.jetbrains.spek.api.dsl.it +import java.nio.file.Paths +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue +import kotlin.test.fail + +/** + * @author Artur Bosch + */ +class ConfigSpec : Spek({ + + describe("load yaml config") { + val configPath = Paths.get(ConfigSpec::class.java.getResource("/detekt.yml").path) + val config = Config.load(configPath) + + it("should successfully load map of string to any with size two") { + assertTrue { config.properties.size == 2 } + } + + it("should create a sub config") { + try { + val subConfig = config.subConfig("style") + assertTrue { subConfig.valueOrDefault("WildcardImport", { mapOf() }).isNotEmpty() } + assertTrue { subConfig.valueOrDefault("WildcardImport", { mapOf() })["active"].toString() == "true" } + assertTrue { subConfig.valueOrDefault("WildcardImport", { mapOf() })["active"] as Boolean } + assertTrue { subConfig.valueOrDefault("NotFound", { mapOf() }).isEmpty() } + assertTrue { subConfig.valueOrDefault("NotFound", { "" }) == "" } + } catch (ignored: Config.InvalidConfigurationError) { + fail("Creating a sub config should work for test resources config!") + } + } + + it("should create a sub sub config") { + try { + val subConfig = config.subConfig("style") + val subSubConfig = subConfig.subConfig("WildcardImport") + assertTrue { subSubConfig.properties["active"] as Boolean } + assertTrue { subSubConfig.valueOrDefault("active") { false } } + assertTrue { subSubConfig.valueOrDefault("NotFound") { true } } + } catch (ignored: Config.InvalidConfigurationError) { + fail("Creating a sub config should work for test resources config!") + } + } + + it("tests wrong sub config conversion") { + assertFailsWith { + @Suppress("UNUSED_VARIABLE") + val ignored = config.valueOrDefault("style") { "" } + } + } + } + +}) \ No newline at end of file diff --git a/detekt-api/src/test/resources/detekt.yml b/detekt-api/src/test/resources/detekt.yml new file mode 100644 index 000000000..1125f2fe5 --- /dev/null +++ b/detekt-api/src/test/resources/detekt.yml @@ -0,0 +1,21 @@ +code-smell: + LongMethod: + active: true + threshold: 20 + LongParameterList: + active: false + threshold: 5 + LargeClass: + active: false + threshold: 70 + InnerMap: + Inner1: + active: true + Inner2: + active: true + +style: + WildcardImport: + active: true + NoElseInWhenExpression: + active: true \ No newline at end of file diff --git a/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/debug/DebugRuleSetProvider.kt b/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/debug/DebugRuleSetProvider.kt index ad60e7422..08f90d9ad 100644 --- a/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/debug/DebugRuleSetProvider.kt +++ b/detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/debug/DebugRuleSetProvider.kt @@ -1,5 +1,6 @@ package io.gitlab.arturbosch.detekt.cli.debug +import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.RuleSet import io.gitlab.arturbosch.detekt.api.RuleSetProvider @@ -7,7 +8,7 @@ import io.gitlab.arturbosch.detekt.api.RuleSetProvider * @author Artur Bosch */ object DebugRuleSetProvider : RuleSetProvider { - override fun instance(): RuleSet { + override fun instance(config: Config): RuleSet { return RuleSet("debug", listOf( ElementPrinter(), TokenPrinter() diff --git a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/Detekt.kt b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/Detekt.kt index d10c1f06c..067756c02 100644 --- a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/Detekt.kt +++ b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/Detekt.kt @@ -1,5 +1,6 @@ package io.gitlab.arturbosch.detekt.core +import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.Finding import io.gitlab.arturbosch.detekt.api.RuleSetProvider import java.net.URLClassLoader @@ -11,6 +12,7 @@ import java.util.ServiceLoader * @author Artur Bosch */ class Detekt(project: Path, + val config: Config = Config.EMPTY, val ruleSets: List = listOf(), pathFilters: List = listOf(), parallelCompilation: Boolean = false) { @@ -26,7 +28,7 @@ class Detekt(project: Path, val ktFiles = compiler.compile() val providers = loadProviders() val futures = providers.map { - task { it.instance().acceptAll(ktFiles) } + task { it.instance(config).acceptAll(ktFiles) } } return awaitAll(futures).toMap() } diff --git a/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/KT.kt b/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/KT.kt index 8f62e82b8..43b51c0c6 100644 --- a/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/KT.kt +++ b/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/KT.kt @@ -1,5 +1,6 @@ package io.gitlab.arturbosch.detekt.core +import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.RuleSet import io.gitlab.arturbosch.detekt.api.RuleSetProvider import java.nio.file.Path @@ -12,13 +13,13 @@ import java.nio.file.Paths val path: Path = Paths.get(KtTreeCompilerSpec::class.java.getResource("/cases").path) class TestProvider : RuleSetProvider { - override fun instance(): RuleSet { + override fun instance(config: Config): RuleSet { return RuleSet("Test", listOf()) } } class TestProvider2 : RuleSetProvider { - override fun instance(): RuleSet { + override fun instance(config: Config): RuleSet { return RuleSet("Test", listOf()) } } \ No newline at end of file diff --git a/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/CodeSmellProvider.kt b/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/CodeSmellProvider.kt index 8dbd15fb4..6c79c17b9 100644 --- a/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/CodeSmellProvider.kt +++ b/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/CodeSmellProvider.kt @@ -1,5 +1,6 @@ package io.gitlab.arturbosch.detekt.rules.providers +import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.RuleSet import io.gitlab.arturbosch.detekt.api.RuleSetProvider import io.gitlab.arturbosch.detekt.rules.LargeClass @@ -10,7 +11,7 @@ import io.gitlab.arturbosch.detekt.rules.LongParameterList * @author Artur Bosch */ class CodeSmellProvider : RuleSetProvider { - override fun instance(): RuleSet { + override fun instance(config: Config): RuleSet { return RuleSet("code-smell", listOf( LongParameterList(), LongMethod(), diff --git a/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/StyleGuideProvider.kt b/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/StyleGuideProvider.kt index 08affacd1..7a6720801 100644 --- a/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/StyleGuideProvider.kt +++ b/detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/StyleGuideProvider.kt @@ -1,5 +1,6 @@ package io.gitlab.arturbosch.detekt.rules.providers +import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.RuleSet import io.gitlab.arturbosch.detekt.api.RuleSetProvider import io.gitlab.arturbosch.detekt.rules.NoElseInWhenExpression @@ -9,7 +10,7 @@ import io.gitlab.arturbosch.detekt.rules.WildcardImport * @author Artur Bosch */ class StyleGuideProvider : RuleSetProvider { - override fun instance(): RuleSet { + override fun instance(config: Config): RuleSet { return RuleSet("style", listOf( WildcardImport(), NoElseInWhenExpression()