Skip to content

Commit

Permalink
Merge pull request #587 from AbhigyaKrishna/main
Browse files Browse the repository at this point in the history
Encoding and Decoding case insensitive enums
  • Loading branch information
charleskorn authored Aug 11, 2024
2 parents ad48c20 + d13223f commit 098d578
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package com.charleskorn.kaml

import kotlinx.serialization.ExperimentalSerializationApi

/**
* Configuration options for parsing YAML to objects and serialising objects to YAML.
*
Expand All @@ -35,6 +37,7 @@ package com.charleskorn.kaml
* * [sequenceBlockIndent]: number of spaces to use as indentation for sequences, if [sequenceStyle] set to [SequenceStyle.Block]
* * [allowAnchorsAndAliases]: set to true to allow anchors and aliases when decoding YAML (defaults to `false`)
* * [codePointLimit]: the maximum amount of code points allowed in the input YAML document (defaults to 3 MB)
* * [decodeEnumCaseInsensitive]: set to true to allow case-insensitive decoding of enums (defaults to `false`)
*/
public data class YamlConfiguration(
internal val encodeDefaults: Boolean = true,
Expand All @@ -52,6 +55,8 @@ public data class YamlConfiguration(
internal val allowAnchorsAndAliases: Boolean = false,
internal val yamlNamingStrategy: YamlNamingStrategy? = null,
internal val codePointLimit: Int? = null,
@ExperimentalSerializationApi
internal val decodeEnumCaseInsensitive: Boolean = false,
)

public enum class PolymorphismStyle {
Expand Down
15 changes: 11 additions & 4 deletions src/commonMain/kotlin/com/charleskorn/kaml/YamlScalarInput.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,20 @@ internal class YamlScalarInput(val scalar: YamlScalar, yaml: Yaml, context: Seri
return index
}

val choices = (0..enumDescriptor.elementsCount - 1)
val choices = (0..<enumDescriptor.elementsCount)
.asSequence()
.map { enumDescriptor.getElementName(it) }
.sorted()
.joinToString(", ")

if (configuration.decodeEnumCaseInsensitive) {
val idx = choices.indexOfFirst { it.equals(scalar.content, ignoreCase = true) }

if (idx != -1) {
return idx
}
}

throw YamlScalarFormatException(
"Value ${scalar.contentToString()} is not a valid option, permitted choices are: $choices",
"Value ${scalar.contentToString()} is not a valid option, permitted choices are: ${choices.sorted().joinToString(", ")}",
scalar.path,
scalar.content,
)
Expand Down
27 changes: 27 additions & 0 deletions src/commonTest/kotlin/com/charleskorn/kaml/YamlReadingTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,33 @@ class YamlReadingTest : FlatFunSpec({
}
}
}

context("parsing case insensitive enumeration value") {
val yaml = Yaml(configuration = YamlConfiguration(decodeEnumCaseInsensitive = true))

test("deserializes it to the expected enumeration value") {
val result = yaml.decodeFromString(TestEnum.serializer(), "value1")

result shouldBe TestEnum.Value1
}

test("deserializes explicit names to the expected enumeration value") {
val result = yaml.decodeFromString(TestEnumWithExplicitNames.serializer(), "with SPACE")

result shouldBe TestEnumWithExplicitNames.WithSpace
}

test("throws exception with case sensitive configuration") {
val exception = shouldThrow<YamlScalarFormatException> { Yaml.default.decodeFromString(TestEnum.serializer(), "value1") }

exception.asClue {
it.message shouldBe "Value 'value1' is not a valid option, permitted choices are: Value1, Value2"
it.line shouldBe 1
it.column shouldBe 1
it.path shouldBe YamlPath.root
}
}
}
}

context("parsing null values") {
Expand Down

0 comments on commit 098d578

Please sign in to comment.