Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor config printer to improve testability #4580

Merged
merged 1 commit into from Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -14,35 +14,37 @@ internal fun YamlNode.printRuleSetPage(ruleSetPage: RuleSetPage) {
printRuleSet(ruleSetPage.ruleSet, ruleSetPage.rules)
}

@Suppress("ComplexMethod") // preserving the declarative structure while building the dsl
private fun YamlNode.printRuleSet(ruleSet: RuleSetProvider, rules: List<Rule>) {
internal fun YamlNode.printRuleSet(ruleSet: RuleSetProvider, rules: List<Rule>) {
node(ruleSet.name) {
keyValue { Config.ACTIVE_KEY to "${ruleSet.defaultActivationStatus.active}" }
val ruleSetExclusion = exclusions.singleOrNull { ruleSet.name in it.ruleSets }
if (ruleSetExclusion != null) {
keyValue { Config.EXCLUDES_KEY to ruleSetExclusion.pattern }
}

ruleSet.configuration.forEach { printConfiguration(it) }

rules.forEach { rule ->
node(rule.name) {
keyValue { Config.ACTIVE_KEY to "${rule.defaultActivationStatus.active}" }
if (rule.autoCorrect) {
keyValue { Config.AUTO_CORRECT_KEY to "true" }
}
val ruleExclusion = exclusions.singleOrNull { it.isExcluded(rule) }
if (ruleExclusion != null) {
keyValue { Config.EXCLUDES_KEY to ruleExclusion.pattern }
}
rule.configuration.forEach { printConfiguration(it) }
}
}
ruleSet.configuration.forEach(::printConfiguration)

rules.forEach(::printRule)

emptyLine()
}
}

private fun YamlNode.printConfiguration(configuration: Configuration) {
internal fun YamlNode.printRule(rule: Rule) {
node(rule.name) {
keyValue { Config.ACTIVE_KEY to "${rule.defaultActivationStatus.active}" }
if (rule.autoCorrect) {
keyValue { Config.AUTO_CORRECT_KEY to "true" }
}
val ruleExclusion = exclusions.singleOrNull { it.isExcluded(rule) }
if (ruleExclusion != null) {
keyValue { Config.EXCLUDES_KEY to ruleExclusion.pattern }
}
rule.configuration.forEach(::printConfiguration)
}
}

internal fun YamlNode.printConfiguration(configuration: Configuration) {
if (configuration.isDeprecated()) return

if (configuration.isDefaultValueNonEmptyList()) {
Expand Down
@@ -0,0 +1,205 @@
package io.gitlab.arturbosch.detekt.generator.printer.defaultconfig

import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.generator.collection.Active
import io.gitlab.arturbosch.detekt.generator.collection.Configuration
import io.gitlab.arturbosch.detekt.generator.collection.DefaultValue
import io.gitlab.arturbosch.detekt.generator.collection.Inactive
import io.gitlab.arturbosch.detekt.generator.collection.Rule
import io.gitlab.arturbosch.detekt.generator.collection.RuleSetProvider
import io.gitlab.arturbosch.detekt.generator.out.yaml
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

internal class RuleSetConfigPrinterTest {
private val ruleSetProviderTemplate = RuleSetProvider(
name = "rulesetName",
description = "description",
defaultActivationStatus = Inactive
)
private val ruleTemplate = Rule(
name = "ruleName",
description = "",
nonCompliantCodeExample = "",
compliantCodeExample = "",
defaultActivationStatus = Inactive,
severity = "",
debt = "",
aliases = null,
parent = ""
)

private val configurationTemplate = Configuration(
name = "name",
description = "description",
defaultValue = DefaultValue.of(1),
defaultAndroidValue = null,
deprecated = null,
)

@Nested
inner class PrintRuleSet {

@Test
fun `starts with name on top level`() {
val ruleset = ruleSetProviderTemplate.copy(name = "rule-set-name")
val actual = yaml { printRuleSet(ruleset, emptyList()) }
assertThat(actual).startsWith("rule-set-name:\n")
}

@Test
fun `includes all rules`() {
val rules = listOf(ruleTemplate.copy(name = "RuleA"), ruleTemplate.copy(name = "RuleB"))
val actual = yaml { printRuleSet(ruleSetProviderTemplate, rules) }
assertThat(actual.lines()).contains(" RuleA:", " RuleB:")
}

@Nested
inner class ActivationStatus {

@Test
fun `has active property`() {
val ruleset = ruleSetProviderTemplate.copy(defaultActivationStatus = Active("1.0.0"))
val actual = yaml { printRuleSet(ruleset, emptyList()) }
assertThat(actual.lines()).contains(" active: true")
}

@Test
fun `has active property if inactive`() {
val ruleset = ruleSetProviderTemplate.copy(defaultActivationStatus = Inactive)
val actual = yaml { printRuleSet(ruleset, emptyList()) }
assertThat(actual.lines()).contains(" active: false")
}
}
}

@Nested
inner class PrintRule {

@Test
fun `starts with rule name`() {
val rule = ruleTemplate.copy(name = "RuleA")
val actual = yaml { printRule(rule) }
assertThat(actual).startsWith("RuleA:\n")
}

@Nested
inner class ActivationStatus {

@Test
fun `has active property`() {
val rule = ruleTemplate.copy(defaultActivationStatus = Active("1.0.0"))
val actual = yaml { printRule(rule) }
assertThat(actual.lines()).contains(" active: true")
}

@Test
fun `has active property if inactive`() {
val rule = ruleTemplate.copy(defaultActivationStatus = Inactive)
val actual = yaml { printRule(rule) }
assertThat(actual.lines()).contains(" active: false")
}
}

@Nested
inner class AutoCorrect {

@Test
fun `has auto correct property`() {
val rule = ruleTemplate.copy(autoCorrect = true)
val actual = yaml { printRule(rule) }
assertThat(actual.lines()).contains(" autoCorrect: true")
}

@Test
fun `omits auto correct property if false`() {
val rule = ruleTemplate.copy(autoCorrect = false)
val actual = yaml { printRule(rule) }
assertThat(actual).doesNotContain(Config.AUTO_CORRECT_KEY)
}
}

@Nested
inner class Exclusion {

@Test
fun `rule is excluded`() {
val anExclusion = exclusions[0]
val anExcludedRuleName = anExclusion.rules.first()
val rule = ruleTemplate.copy(name = anExcludedRuleName)
val actual = yaml { printRule(rule) }
assertThat(actual.lines()).contains(" excludes: ${anExclusion.pattern}")
}

@Test
fun `omits excludes property if rule is not excluded in any exclusion`() {
val rule = ruleTemplate.copy(name = "ARuleNameThatIsNotExcluded")
val actual = yaml { printRule(rule) }
assertThat(actual).doesNotContain(Config.EXCLUDES_KEY)
}
}
}

@Nested
inner class PrintConfiguration {

@Test
fun `ignore deprecated`() {
val given = configurationTemplate.copy(deprecated = "use something else")
val actual = yaml { printConfiguration(given) }
assertThat(actual).isEmpty()
}

@Nested
inner class DefaultValues {

@Test
fun `int default value`() {
val given = configurationTemplate.copy(defaultValue = DefaultValue.of(99))
val actual = yaml { printConfiguration(given) }
assertThat(actual).isEqualTo("name: 99")
}

@Test
fun `boolean default value`() {
val given = configurationTemplate.copy(defaultValue = DefaultValue.of(false))
val actual = yaml { printConfiguration(given) }
assertThat(actual).isEqualTo("name: false")
}

@ValueSource(
strings = [
"", " ", "a", "a b", "a\$b"
]
)
@ParameterizedTest
fun `string default value is quoted`(value: String) {
val given = configurationTemplate.copy(defaultValue = DefaultValue.of(value))
val actual = yaml { printConfiguration(given) }
assertThat(actual).isEqualTo("name: '$value'")
}

@Test
fun `empty list default value uses array syntax`() {
val given = configurationTemplate.copy(defaultValue = DefaultValue.of(emptyList()))
val actual = yaml { printConfiguration(given) }
assertThat(actual).isEqualTo("name: []")
}

@Test
fun `string list default value`() {
val given = configurationTemplate.copy(defaultValue = DefaultValue.of(listOf("a", "b", "c")))
val actual = yaml { printConfiguration(given) }
val expected = """name:
| - 'a'
| - 'b'
| - 'c'
""".trimMargin()
assertThat(actual).isEqualTo(expected)
}
}
}
}