Introduce DefaultValue type (#3928)

* Introduce DefaultValue type

* reuse createDefaultValueIfLiteral in RuleSetProviderCollector.kt

* use DefaultValue.of() explicitly

* default getAsPlainString to toString

* rename ListDefault to StringListDefault

Co-authored-by: Markus Schwarz <post@markus-schwarz.net>
This commit is contained in:
marschwar
2022-01-23 06:45:19 +01:00
committed by GitHub
parent 31520dadf2
commit 8a69676534
14 changed files with 214 additions and 144 deletions

View File

@@ -104,12 +104,12 @@ formatting:
naming:
ClassNaming:
excludes: [ '**/*Spec.kt' ]
excludes: ['**/*Spec.kt']
TopLevelPropertyNaming:
constantPattern: '[a-z][_A-Za-z0-9]*|[A-Z][_A-Z0-9]*'
InvalidPackageDeclaration:
active: true
excludes: [ '**/build-logic/**/*.kt', '**/*.kts' ]
excludes: ['**/build-logic/**/*.kt', '**/*.kts']
NoNameShadowing:
active: true
NonBooleanPropertyPrefixedWithIs:

View File

@@ -3,31 +3,13 @@ package io.gitlab.arturbosch.detekt.generator.collection
data class Configuration(
val name: String,
val description: String,
val defaultValue: String,
val defaultAndroidValue: String?,
val defaultValue: DefaultValue,
val defaultAndroidValue: DefaultValue?,
val deprecated: String?
) {
fun isDeprecated() = deprecated != null
fun isDefaultValueNonEmptyList() = defaultValue.isNonEmptyList()
fun getDefaultValueAsList(): List<String> {
if (defaultValue.isNonEmptyList()) {
return defaultValue.toList()
}
error("default value '$defaultValue' is not a list")
}
private fun String.isNonEmptyList(): Boolean = NON_EMPTY_LIST_REGEX.matchEntire(this) != null
private fun String.toList(): List<String> =
trim()
.removePrefix("[")
.removeSuffix("]")
.split(",")
.map { it.trim().removeSurrounding("'") }
companion object {
private val NON_EMPTY_LIST_REGEX = Regex("""\[.*[\S]+.*]""")
}
fun getDefaultValueAsList(): List<String> = defaultValue.getAsList()
}

View File

@@ -6,6 +6,9 @@ import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.C
import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.ConfigWithFallbackSupport.FALLBACK_DELEGATE_NAME
import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.ConfigWithFallbackSupport.checkUsingInvalidFallbackReference
import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.ConfigWithFallbackSupport.isFallbackConfigDelegate
import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.DefaultValueSupport.getAndroidDefaultValue
import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.DefaultValueSupport.getDefaultValue
import io.gitlab.arturbosch.detekt.generator.collection.ConfigurationCollector.DefaultValueSupport.toDefaultValueIfLiteral
import io.gitlab.arturbosch.detekt.generator.collection.exception.InvalidDocumentationException
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
@@ -24,7 +27,7 @@ import io.gitlab.arturbosch.detekt.api.internal.Configuration as ConfigAnnotatio
class ConfigurationCollector {
private val constantsByName = mutableMapOf<String, String>()
private val constantsByName = mutableMapOf<String, DefaultValue>()
private val properties = mutableListOf<KtProperty>()
fun getConfiguration(): List<Configuration> {
@@ -43,25 +46,22 @@ class ConfigurationCollector {
)
}
private fun resolveConstantOrNull(prop: KtProperty): Pair<String, String>? {
private fun resolveConstantOrNull(prop: KtProperty): Pair<String, DefaultValue>? {
if (prop.isVar) return null
val propertyName = checkNotNull(prop.name)
val constantOrNull = prop.getConstantValueAsStringOrNull()
val constantOrNull = prop.getConstantValue()
return constantOrNull?.let { propertyName to it }
}
private fun KtProperty.getConstantValueAsStringOrNull(): String? {
private fun KtProperty.getConstantValue(): DefaultValue? {
if (hasListDeclaration()) {
return getListDeclaration()
.valueArguments
.map { "'${it.text.withoutQuotes()}'" }
.toString()
return DefaultValue.of(getListDeclaration().valueArguments.map { it.text.withoutQuotes() })
}
return findDescendantOfType<KtConstantExpression>()?.text
?: findDescendantOfType<KtStringTemplateExpression>()?.text?.withoutQuotes()
return findDescendantOfType<KtConstantExpression>()?.toDefaultValueIfLiteral()
?: findDescendantOfType<KtStringTemplateExpression>()?.toDefaultValueIfLiteral()
}
private fun KtProperty.parseConfigurationAnnotation(): Configuration? = when {
@@ -84,59 +84,61 @@ class ConfigurationCollector {
val propertyName: String = checkNotNull(name)
val deprecationMessage = firstAnnotationParameterOrNull(Deprecated::class)
val description: String = firstAnnotationParameter(ConfigAnnotation::class)
val defaultValueAsString = getDefaultValueAsString()
val defaultAndroidValueAsString = getDefaultAndroidValueAsString()
val defaultValue = getDefaultValue(constantsByName)
val defaultAndroidValue = getAndroidDefaultValue(constantsByName)
return Configuration(
name = propertyName,
description = description,
defaultValue = defaultValueAsString,
defaultAndroidValue = defaultAndroidValueAsString,
defaultValue = defaultValue,
defaultAndroidValue = defaultAndroidValue,
deprecated = deprecationMessage,
)
}
private fun KtProperty.getDefaultValueAsString(): String {
val defaultValueArgument = getValueArgument(
name = DEFAULT_VALUE_ARGUMENT_NAME,
actionForPositionalMatch = { arguments ->
when {
isFallbackConfigDelegate() -> arguments[1]
isAndroidVariantConfigDelegate() -> arguments[0]
else -> arguments[0]
private object DefaultValueSupport {
fun KtProperty.getDefaultValue(constantsByName: Map<String, DefaultValue>): DefaultValue {
val defaultValueArgument = getValueArgument(
name = DEFAULT_VALUE_ARGUMENT_NAME,
actionForPositionalMatch = { arguments ->
when {
isFallbackConfigDelegate() -> arguments[1]
isAndroidVariantConfigDelegate() -> arguments[0]
else -> arguments[0]
}
}
}
) ?: invalidDocumentation { "'$name' is not a delegated property" }
return formatDefaultValueExpression(checkNotNull(defaultValueArgument.getArgumentExpression()))
}
private fun KtProperty.getDefaultAndroidValueAsString(): String? {
val defaultValueArgument = getValueArgument(
name = DEFAULT_ANDROID_VALUE_ARGUMENT_NAME,
actionForPositionalMatch = { arguments ->
when {
isAndroidVariantConfigDelegate() -> arguments[1]
else -> null
}
}
)
val defaultValueExpression = defaultValueArgument?.getArgumentExpression() ?: return null
return formatDefaultValueExpression(defaultValueExpression)
}
private fun KtProperty.formatDefaultValueExpression(ktExpression: KtExpression): String {
val listDeclarationForDefault = ktExpression.getListDeclarationOrNull()
if (listDeclarationForDefault != null) {
return listDeclarationForDefault.valueArguments.map {
val value = constantsByName[it.text] ?: it.text
"'${value.withoutQuotes()}'"
}.toString()
) ?: invalidDocumentation { "'$name' is not a delegated property" }
return checkNotNull(defaultValueArgument.getArgumentExpression()).toDefaultValue(constantsByName)
}
val defaultValueOrConstantName = checkNotNull(ktExpression.text.withoutQuotes())
val defaultValue = constantsByName[defaultValueOrConstantName] ?: defaultValueOrConstantName
val needsQuotes = declaredTypeOrNull in TYPES_THAT_NEED_QUOTATION_FOR_DEFAULT
return if (needsQuotes) "'$defaultValue'" else defaultValue
fun KtProperty.getAndroidDefaultValue(constantsByName: Map<String, DefaultValue>): DefaultValue? {
val defaultValueArgument = getValueArgument(
name = DEFAULT_ANDROID_VALUE_ARGUMENT_NAME,
actionForPositionalMatch = { arguments ->
when {
isAndroidVariantConfigDelegate() -> arguments[1]
else -> null
}
}
)
return defaultValueArgument?.getArgumentExpression()?.toDefaultValue(constantsByName)
}
fun KtExpression.toDefaultValue(constantsByName: Map<String, DefaultValue>): DefaultValue {
val listDeclarationForDefault = getListDeclarationOrNull()
if (listDeclarationForDefault != null) {
val listValues = listDeclarationForDefault.valueArguments.map {
(constantsByName[it.text]?.getAsPlainString() ?: it.text.withoutQuotes())
}
return DefaultValue.of(listValues)
}
return toDefaultValueIfLiteral()
?: constantsByName[text.withoutQuotes()]
?: error("$text is neither a literal nor a constant")
}
fun KtExpression.toDefaultValueIfLiteral(): DefaultValue? = createDefaultValueIfLiteral(text)
}
private object ConfigWithFallbackSupport {
@@ -186,14 +188,6 @@ class ConfigurationCollector {
private const val EMPTY_LIST = "emptyList"
private val LIST_CREATORS = setOf(LIST_OF, EMPTY_LIST)
private const val TYPE_STRING = "String"
private const val TYPE_REGEX = "Regex"
private const val TYPE_SPLIT_PATTERN = "SplitPattern"
private val TYPES_THAT_NEED_QUOTATION_FOR_DEFAULT = listOf(TYPE_STRING, TYPE_REGEX, TYPE_SPLIT_PATTERN)
private val KtProperty.declaredTypeOrNull: String?
get() = typeReference?.text
private fun KtElement.getListDeclaration(): KtCallExpression =
checkNotNull(getListDeclarationOrNull())

View File

@@ -0,0 +1,38 @@
package io.gitlab.arturbosch.detekt.generator.collection
sealed interface DefaultValue {
fun isNonEmptyList(): Boolean = false
fun getAsList(): List<String> = error("default value is not a list")
fun getAsPlainString(): String = toString()
fun getQuotedIfNecessary(): String = getAsPlainString()
companion object {
fun of(defaultValue: String): DefaultValue = StringDefault(defaultValue)
fun of(defaultValue: Boolean): DefaultValue = BooleanDefault(defaultValue)
fun of(defaultValue: Int): DefaultValue = IntegerDefault(defaultValue)
fun of(defaultValue: List<String>): DefaultValue = StringListDefault(defaultValue)
}
}
private data class StringDefault(private val defaultValue: String) : DefaultValue {
private val quoted = "'$defaultValue'"
override fun getAsPlainString(): String = defaultValue
override fun getQuotedIfNecessary(): String = quoted
}
private data class BooleanDefault(private val defaultValue: Boolean) : DefaultValue {
override fun getAsPlainString(): String = defaultValue.toString()
}
private data class IntegerDefault(private val defaultValue: Int) : DefaultValue {
override fun getAsPlainString(): String = defaultValue.toString()
}
private data class StringListDefault(private val defaultValue: List<String>) : DefaultValue {
private val quoted: String = defaultValue.map { "'$it'" }.toString()
override fun isNonEmptyList(): Boolean = defaultValue.isNotEmpty()
override fun getAsList(): List<String> = defaultValue.ifEmpty { error("default value is an empty list") }
override fun getAsPlainString(): String = defaultValue.toString()
override fun getQuotedIfNecessary(): String = quoted
}

View File

@@ -0,0 +1,22 @@
package io.gitlab.arturbosch.detekt.generator.collection
import org.jetbrains.kotlin.lexer.KtTokens.FALSE_KEYWORD
import org.jetbrains.kotlin.lexer.KtTokens.TRUE_KEYWORD
fun createDefaultValueIfLiteral(maybeLiteral: String): DefaultValue? = maybeLiteral.toDefaultValueIfLiteral()
private fun String.toDefaultValueIfLiteral(): DefaultValue? {
return when {
isStringLiteral() -> DefaultValue.of(withoutQuotes())
isBooleanLiteral() -> DefaultValue.of(toBoolean())
isIntegerLiteral() -> DefaultValue.of(withoutUnderscores().toInt())
else -> null
}
}
private fun String.withoutUnderscores() = replace("_", "")
private fun String.isStringLiteral() = length > 1 && startsWith(QUOTES) && endsWith(QUOTES)
private fun String.isBooleanLiteral() = this == TRUE_KEYWORD.value || this == FALSE_KEYWORD.value
private fun String.isIntegerLiteral() = withoutUnderscores().toIntOrNull() != null
private const val QUOTES = "\""

View File

@@ -87,6 +87,8 @@ class RuleSetProviderVisitor : DetektVisitor() {
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
if (!containsRuleSetProvider) return
if (property.isOverride() && property.name != null && property.name == PROPERTY_RULE_SET_ID) {
name = (property.initializer as? KtStringTemplateExpression)?.entries?.get(0)?.text
?: throw InvalidDocumentationException(
@@ -95,7 +97,8 @@ class RuleSetProviderVisitor : DetektVisitor() {
)
}
if (property.isAnnotatedWith(ConfigAnnotation::class)) {
val defaultValue = formatDefaultValue(
val defaultValue = toDefaultValue(
name,
checkNotNull(property.delegate?.expression as? KtCallExpression)
.valueArguments
.first()
@@ -133,14 +136,11 @@ class RuleSetProviderVisitor : DetektVisitor() {
}
companion object {
private const val DOUBLE_QUOTE = '"'
private fun formatDefaultValue(defaultValueText: String): String =
if (defaultValueText.startsWith(DOUBLE_QUOTE) && defaultValueText.endsWith(DOUBLE_QUOTE)) {
"'${defaultValueText.removeSurrounding("$DOUBLE_QUOTE")}'"
} else {
defaultValueText
}
private fun toDefaultValue(providerName: String, defaultValueText: String): DefaultValue =
createDefaultValueIfLiteral(defaultValueText)
?: throw InvalidDocumentationException(
"Unsupported default value format '$defaultValueText' " +
"in $providerName. Please use a Boolean, Int or String literal instead."
)
}
}

View File

@@ -68,8 +68,8 @@ object RuleSetPagePrinter : DocumentationPrinter<RuleSetPage> {
h4 { "Configuration options:" }
list {
rule.configuration.forEach {
val defaultValues = formatDefaultValues(it.defaultValue)
val defaultAndroidValues = it.defaultAndroidValue?.let(RuleSetPagePrinter::formatDefaultValues)
val defaultValues = it.defaultValue.getQuotedIfNecessary()
val defaultAndroidValues = it.defaultAndroidValue?.getQuotedIfNecessary()
val defaultString = if (defaultAndroidValues != null) {
"(default: ${code { defaultValues }}) (android default: ${code { defaultAndroidValues }})"
} else {
@@ -94,10 +94,6 @@ object RuleSetPagePrinter : DocumentationPrinter<RuleSetPage> {
}
}
private fun formatDefaultValues(rawString: String) = rawString.lines().joinToString {
it.trim().removePrefix("- ")
}
private fun MarkdownContent.printRuleCodeExamples(rule: Rule) {
if (rule.nonCompliantCodeExample.isNotEmpty()) {
h4 { "Noncompliant Code:" }

View File

@@ -66,7 +66,7 @@ object ConfigPrinter : DocumentationPrinter<List<RuleSetPage>> {
if (configuration.isDefaultValueNonEmptyList()) {
list(configuration.name, configuration.getDefaultValueAsList())
} else {
keyValue { configuration.name to configuration.defaultValue }
keyValue { configuration.name to configuration.defaultValue.getQuotedIfNecessary() }
}
}

View File

@@ -1,5 +1,6 @@
package io.gitlab.arturbosch.detekt.generator.collection
import io.gitlab.arturbosch.detekt.generator.collection.DefaultValue.Companion.of
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatIllegalStateException
import org.junit.jupiter.api.Nested
@@ -8,7 +9,7 @@ import org.junit.jupiter.api.Test
private val defaultConfiguration = Configuration(
name = "name",
description = "description",
defaultValue = "",
defaultValue = of(""),
defaultAndroidValue = null,
deprecated = null
)
@@ -19,7 +20,7 @@ class ConfigurationSpec {
inner class `default value to list conversion` {
@Nested
inner class `empty default value` {
val subject = defaultConfiguration.copy(defaultValue = "")
private val subject = defaultConfiguration.copy(defaultValue = of(""))
@Test
fun `identifies default as not a list`() {
@@ -34,7 +35,7 @@ class ConfigurationSpec {
@Nested
inner class `non list default value` {
val subject = defaultConfiguration.copy(defaultValue = "abc")
private val subject = defaultConfiguration.copy(defaultValue = of("abc"))
@Test
fun `identifies default as not a list`() {
@@ -49,7 +50,7 @@ class ConfigurationSpec {
@Nested
inner class `empty list default value` {
val subject = defaultConfiguration.copy(defaultValue = "[ ]")
private val subject = defaultConfiguration.copy(defaultValue = of(emptyList()))
@Test
fun `identifies default as not a non empty list`() {
@@ -64,7 +65,7 @@ class ConfigurationSpec {
@Nested
inner class `bracket list default value` {
val subject = defaultConfiguration.copy(defaultValue = "[ 'a', 'b' ]")
private val subject = defaultConfiguration.copy(defaultValue = of(listOf("a", "b")))
@Test
fun `identifies default as a non empty list`() {

View File

@@ -1,5 +1,6 @@
package io.gitlab.arturbosch.detekt.generator.collection
import io.gitlab.arturbosch.detekt.generator.collection.DefaultValue.Companion.of
import io.gitlab.arturbosch.detekt.generator.collection.exception.InvalidAliasesDeclaration
import io.gitlab.arturbosch.detekt.generator.collection.exception.InvalidCodeExampleDocumentationException
import io.gitlab.arturbosch.detekt.generator.collection.exception.InvalidDocumentationException
@@ -204,7 +205,7 @@ class RuleCollectorSpec {
val expectedConfiguration = Configuration(
name = "config",
description = "description",
defaultValue = "'[A-Z$]'",
defaultValue = of("[A-Z$]"),
defaultAndroidValue = null,
deprecated = null
)
@@ -219,12 +220,12 @@ class RuleCollectorSpec {
*/
class SomeRandomClass() : Rule {
@Configuration("description")
private val config: Int by config(99)
private val config: Int by config(1_999_000)
}
"""
val items = subject.run(code)
assertThat(items[0].configuration).hasSize(1)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("99")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of(1_999_000))
}
@Test
@@ -239,7 +240,7 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("'abcd'")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of("abcd"))
}
@Test
@@ -254,7 +255,7 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("99")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of(99))
}
@Test
@@ -274,7 +275,8 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("['a', 'b']")
val expected = of(listOf("a", "b"))
assertThat(items[0].configuration[0].defaultValue).isEqualTo(expected)
}
@Test
@@ -311,7 +313,7 @@ class RuleCollectorSpec {
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].description).isEqualTo("This is a multi line description")
assertThat(items[0].configuration[0].defaultValue).isEqualTo("'a'")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of("a"))
}
@Test
@@ -330,7 +332,7 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("99")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of(99))
}
@Test
@@ -349,7 +351,7 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("99")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of(99))
}
@Test
@@ -368,7 +370,7 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("'a'")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of("a"))
}
@Test
@@ -391,7 +393,7 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
val expected = "['a', 'b']"
val expected = of(listOf("a", "b"))
assertThat(items[0].configuration[0].defaultValue).isEqualTo(expected)
assertThat(items[0].configuration[1].defaultValue).isEqualTo(expected)
}
@@ -411,8 +413,9 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("[]")
assertThat(items[0].configuration[1].defaultValue).isEqualTo("[]")
val expected = of(emptyList())
assertThat(items[0].configuration[0].defaultValue).isEqualTo(expected)
assertThat(items[0].configuration[1].defaultValue).isEqualTo(expected)
}
@Test
@@ -434,8 +437,9 @@ class RuleCollectorSpec {
}
"""
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("[]")
assertThat(items[0].configuration[1].defaultValue).isEqualTo("[]")
val expected = of(emptyList())
assertThat(items[0].configuration[0].defaultValue).isEqualTo(expected)
assertThat(items[0].configuration[1].defaultValue).isEqualTo(expected)
}
@Test
@@ -526,8 +530,8 @@ class RuleCollectorSpec {
Configuration(
name = "maxLineLength",
description = "description",
defaultValue = "120",
defaultAndroidValue = "100",
defaultValue = of(120),
defaultAndroidValue = of(100),
deprecated = null
)
)
@@ -550,8 +554,8 @@ class RuleCollectorSpec {
Configuration(
name = "maxLineLength",
description = "description",
defaultValue = "120",
defaultAndroidValue = "100",
defaultValue = of(120),
defaultAndroidValue = of(100),
deprecated = null
)
)
@@ -580,7 +584,7 @@ class RuleCollectorSpec {
val items = subject.run(code)
val fallbackProperties = items[0].configuration.filter { it.name.startsWith("config") }
assertThat(fallbackProperties).hasSize(3)
assertThat(fallbackProperties.map { it.defaultValue }).containsOnly("99")
assertThat(fallbackProperties.map { it.defaultValue }).containsOnly(of(99))
}
@Test
@@ -618,13 +622,13 @@ class RuleCollectorSpec {
@Test
fun `extracts default value with transformer function`() {
val items = subject.run(code)
assertThat(items[0].configuration[0].defaultValue).isEqualTo("'[a-z]+'")
assertThat(items[0].configuration[0].defaultValue).isEqualTo(of("[a-z]+"))
}
@Test
fun `extracts default value with method reference`() {
val items = subject.run(code)
assertThat(items[0].configuration[1].defaultValue).isEqualTo("'false'")
assertThat(items[0].configuration[1].defaultValue).isEqualTo(of(false))
}
}
}

View File

@@ -1,9 +1,11 @@
package io.gitlab.arturbosch.detekt.generator.collection
import io.gitlab.arturbosch.detekt.generator.collection.DefaultValue.Companion.of
import io.gitlab.arturbosch.detekt.generator.collection.exception.InvalidDocumentationException
import io.gitlab.arturbosch.detekt.generator.util.run
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
@@ -287,7 +289,7 @@ class RuleSetProviderCollectorSpec {
}
@Nested
inner class `a correct RuleSetProvider class with full parameters missing` {
inner class `a correct RuleSetProvider class with full parameters and multiple rules` {
val description = "This is a description"
val ruleSetId = "test"
val ruleName = "TestRule"
@@ -365,14 +367,14 @@ class RuleSetProviderCollectorSpec {
}
}
"""
val items = subject.run(code)
private val items = subject.run(code)
@Test
fun `extracts boolean configuration option`() {
val conf = items[0].configuration[0]
assertThat(conf.name).isEqualTo("aBool")
assertThat(conf.description).isEqualTo("bool description")
assertThat(conf.defaultValue).isEqualTo("true")
assertThat(conf.defaultValue).isEqualTo(of(true))
assertThat(conf.deprecated).isNull()
}
@@ -381,7 +383,7 @@ class RuleSetProviderCollectorSpec {
val conf = items[0].configuration[1]
assertThat(conf.name).isEqualTo("anInt")
assertThat(conf.description).isEqualTo("int description")
assertThat(conf.defaultValue).isEqualTo("99")
assertThat(conf.defaultValue).isEqualTo(of(99))
}
@Test
@@ -389,9 +391,39 @@ class RuleSetProviderCollectorSpec {
val conf = items[0].configuration[2]
assertThat(conf.name).isEqualTo("aString")
assertThat(conf.description).isEqualTo("string description")
assertThat(conf.defaultValue).isEqualTo("'a'")
assertThat(conf.defaultValue).isEqualTo(of("a"))
assertThat(conf.deprecated).isEqualTo("use something else")
}
}
@Nested
inner class `a RuleSetProvider with unsupported configuration format` {
val code = """
package foo
/**
* description
*/
class TestProvider: RuleSetProvider {
override val ruleSetId: String = "ruleSetId"
override fun instance(config: Config): RuleSet {
return RuleSet(ruleSetId, listOf(RruleName(config)))
}
companion object {
@Configuration("a description")
val aConfig by ruleSetConfig(listOf("a"))
}
}
"""
@Test
fun `fails`() {
assertThatThrownBy { subject.run(code) }
.isInstanceOf(InvalidDocumentationException::class.java)
.hasMessageContaining("""Unsupported default value format 'listOf("a")'""")
}
}
}
}

View File

@@ -2,6 +2,7 @@ package io.gitlab.arturbosch.detekt.generator.util
import io.gitlab.arturbosch.detekt.generator.collection.Active
import io.gitlab.arturbosch.detekt.generator.collection.Configuration
import io.gitlab.arturbosch.detekt.generator.collection.DefaultValue.Companion.of
import io.gitlab.arturbosch.detekt.generator.collection.Inactive
import io.gitlab.arturbosch.detekt.generator.collection.Rule
import io.gitlab.arturbosch.detekt.generator.collection.RuleSetPage
@@ -19,35 +20,35 @@ internal fun createRuleSetPage(): RuleSetPage {
Configuration(
name = "rulesetconfig1",
description = "description rulesetconfig1",
defaultValue = "true",
defaultValue = of(true),
defaultAndroidValue = null,
deprecated = null
),
Configuration(
name = "rulesetconfig2",
description = "description rulesetconfig2",
defaultValue = "['foo', 'bar']",
defaultValue = of(listOf("foo", "bar")),
defaultAndroidValue = null,
deprecated = null
),
Configuration(
name = "deprecatedSimpleConfig",
description = "description deprecatedSimpleConfig",
defaultValue = "true",
defaultValue = of(true),
defaultAndroidValue = null,
deprecated = "is deprecated"
),
Configuration(
name = "deprecatedListConfig",
description = "description deprecatedListConfig",
defaultValue = "['foo', 'bar']",
defaultValue = of(listOf("foo", "bar")),
defaultAndroidValue = null,
deprecated = "is deprecated"
),
Configuration(
name = "rulesetconfig3",
description = "description rulesetconfig2",
defaultValue = "['first', 'se*cond']",
defaultValue = of(listOf("first", "se*cond")),
defaultAndroidValue = null,
deprecated = null
)
@@ -68,11 +69,11 @@ internal fun createRules(): List<Rule> {
aliases = "alias1, alias2",
parent = "",
configuration = listOf(
Configuration("conf1", "a config option", "foo", null, null),
Configuration("conf2", "deprecated config", "false", null, "use conf1 instead"),
Configuration("conf3", "list config", "['a', 'b']", null, null),
Configuration("conf4", "deprecated list config", "['a', 'b']", null, "use conf3 instead"),
Configuration("conf5", "rule with android variants", "120", "100", null),
Configuration("conf1", "a config option", of("foo"), null, null),
Configuration("conf2", "deprecated config", of(false), null, "use conf1 instead"),
Configuration("conf3", "list config", of(listOf("a", "b")), null, null),
Configuration("conf4", "deprecated list config", of(listOf("a", "b")), null, "use conf3 instead"),
Configuration("conf5", "rule with android variants", of(120), of(100), null),
)
)
val rule2 = Rule(

View File

@@ -12,7 +12,7 @@ a wildcard import
#### Configuration options:
* ``conf1`` (default: ``foo``)
* ``conf1`` (default: ``'foo'``)
a config option

View File

@@ -10,7 +10,7 @@ style:
WildcardImport:
active: true
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
conf1: foo
conf1: 'foo'
conf3:
- 'a'
- 'b'