mirror of
https://github.com/jlengrand/detekt.git
synced 2026-03-10 08:11:23 +00:00
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:
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 = "\""
|
||||
@@ -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."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:" }
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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`() {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")'""")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -12,7 +12,7 @@ a wildcard import
|
||||
|
||||
#### Configuration options:
|
||||
|
||||
* ``conf1`` (default: ``foo``)
|
||||
* ``conf1`` (default: ``'foo'``)
|
||||
|
||||
a config option
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ style:
|
||||
WildcardImport:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
conf1: foo
|
||||
conf1: 'foo'
|
||||
conf3:
|
||||
- 'a'
|
||||
- 'b'
|
||||
|
||||
Reference in New Issue
Block a user