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

Adding the support for Char #176

Merged
merged 4 commits into from
Jan 5, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.akuleshov7.ktoml.decoders

import com.akuleshov7.ktoml.exceptions.IllegalTypeException
import com.akuleshov7.ktoml.tree.nodes.TomlKeyValue
import com.akuleshov7.ktoml.tree.nodes.pairs.values.TomlBasicString
import com.akuleshov7.ktoml.tree.nodes.pairs.values.TomlDouble
import com.akuleshov7.ktoml.tree.nodes.pairs.values.TomlLiteralString
import com.akuleshov7.ktoml.tree.nodes.pairs.values.TomlLong
import com.akuleshov7.ktoml.utils.FloatingPointLimitsEnum
import com.akuleshov7.ktoml.utils.FloatingPointLimitsEnum.*
Expand Down Expand Up @@ -32,7 +34,35 @@ public abstract class TomlAbstractDecoder : AbstractDecoder() {
override fun decodeShort(): Short = decodePrimitiveType()
override fun decodeInt(): Int = decodePrimitiveType()
override fun decodeFloat(): Float = decodePrimitiveType()
override fun decodeChar(): Char = invalidType("Char", "String")
override fun decodeChar(): Char {
val keyValue = decodeKeyValue()
return when (val value = keyValue.value) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will give users a possibility to decode Char from integer or from a literal

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

char1 = 156
char2 = '5'

TOML standard does not support Char, but we will have it out of the box

// converting to Char from a parsed Long number and checking bounds for the Char (MIN-MAX range)
is TomlLong -> validateAndConvertInteger(value.content as Long, keyValue.lineNo, CHAR) { Char(it.toInt()) }
// converting to Char from a parsed Literal String (with single quotes: '')
is TomlLiteralString ->
try {
(value.content as String).single()
} catch (ex: NoSuchElementException) {
throw IllegalTypeException("Empty value is not allowed for type [Char], " +
"please check the value: [${value.content}] or use [String] type for deserialization of " +
"[${keyValue.key}] instead", keyValue.lineNo)
} catch (ex: IllegalArgumentException) {
throw IllegalTypeException("[Char] type should be used for decoding of single character, but " +
"received multiple characters instead: [${value.content}]. " +
"If you really want to decode multiple chars, use [String] instead.", keyValue.lineNo)
}
// to avoid confusion, we prohibit basic strings with double quotes for decoding to a Char type
is TomlBasicString -> throw IllegalTypeException("Double quotes were used in the input for deserialization " +
"of [Char]. Use [String] type or single quotes ('') instead for: [${value.content}]", keyValue.lineNo)
// all other toml tree types are not supported
else -> throw IllegalTypeException(
"Cannot decode the key [${keyValue.key.last()}] with the value [${keyValue.value.content}]" +
" and with the provided type [Char]. Please check the type in your Serializable class or it's nullability",
keyValue.lineNo
)
}
}

// Valid Toml types that should be properly decoded
override fun decodeBoolean(): Boolean = decodePrimitiveType()
Expand Down Expand Up @@ -78,7 +108,7 @@ public abstract class TomlAbstractDecoder : AbstractDecoder() {
} catch (e: ClassCastException) {
throw IllegalTypeException(
"Cannot decode the key [${keyValue.key.last()}] with the value [${keyValue.value.content}]" +
" with the provided type [${T::class}]. Please check the type in your Serializable class or it's nullability",
" and with the provided type [${T::class}]. Please check the type in your Serializable class or it's nullability",
keyValue.lineNo
)
}
Expand Down Expand Up @@ -118,10 +148,10 @@ public abstract class TomlAbstractDecoder : AbstractDecoder() {
*/
private inline fun <reified T> decodeInteger(content: Long, lineNo: Int): T =
when (T::class) {
Byte::class -> validateAndConvertInteger(content, lineNo, BYTE) { num: Long -> num.toByte() as T }
Short::class -> validateAndConvertInteger(content, lineNo, SHORT) { num: Long -> num.toShort() as T }
Int::class -> validateAndConvertInteger(content, lineNo, INT) { num: Long -> num.toInt() as T }
Long::class -> validateAndConvertInteger(content, lineNo, LONG) { num: Long -> num as T }
Byte::class -> validateAndConvertInteger(content, lineNo, BYTE) { it.toByte() as T }
Short::class -> validateAndConvertInteger(content, lineNo, SHORT) { it.toShort() as T }
Int::class -> validateAndConvertInteger(content, lineNo, INT) { it.toInt() as T }
Long::class -> validateAndConvertInteger(content, lineNo, LONG) { it as T }
Double::class, Float::class -> throw IllegalTypeException(
"Expected floating-point number, but received integer literal: <$content>. " +
"Deserialized floating-point number should have a dot: <$content.0>",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public class TomlMainDecoder(
private fun getCurrentNode() = rootNode.getNeighbourNodes().elementAt(elementIndex - 1)

/**
* Trying to decode the value (ite
* Trying to decode the value using elementIndex
* |--- child1, child2, ... , childN
* ------------elementIndex------->
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ private fun String.validateSymbols(lineNo: Int) {
throw ParseException(
"Not able to parse the key: [$this] as it contains invalid symbols." +
" In case you would like to use special symbols - use quotes as" +
" it is required by TOML standard: \"My key ~ with special % symbols\"",
" it is required by TOML standard: \"My key with special (%, ±) symbols\" = \"value\"",
lineNo
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package com.akuleshov7.ktoml.utils
*/
public enum class IntegerLimitsEnum(public val min: Long, public val max: Long) {
BYTE(Byte.MIN_VALUE.toLong(), Byte.MAX_VALUE.toLong()),
CHAR(Char.MIN_VALUE.code.toLong(), Char.MAX_VALUE.code.toLong()),
INT(Int.MIN_VALUE.toLong(), Int.MAX_VALUE.toLong()),
LONG(Long.MIN_VALUE, Long.MAX_VALUE),
SHORT(Short.MIN_VALUE.toLong(), Short.MAX_VALUE.toLong()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,10 @@ class SimpleArrayDecoderTest {
@Test
fun testSimpleArrayDecoderInNestedTable() {
var test = """
|[table]
|name = "my name"
|configurationList = ["a", "b", "c"]
""".trimMargin()
[table]
name = "my name"
configurationList = ["a", "b", "c"]
"""

assertEquals(
ArrayInInlineTable(
Expand All @@ -369,10 +369,10 @@ class SimpleArrayDecoderTest {

test =
"""
|[table]
|configurationList = ["a", "b", "c"]
|name = "my name"
""".trimMargin()
[table]
configurationList = ["a", "b", "c"]
name = "my name"
"""

assertEquals(
ArrayInInlineTable(
Expand All @@ -381,11 +381,11 @@ class SimpleArrayDecoderTest {
)

val testTable = """
|configurationList1 = ["a", "b", "c"]
|configurationList2 = ["a", "b", "c"]
|[table]
|name = "my name"
""".trimMargin()
configurationList1 = ["a", "b", "c"]
configurationList2 = ["a", "b", "c"]
[table]
name = "my name"
"""

assertEquals(
TestArrays(
Expand All @@ -396,13 +396,13 @@ class SimpleArrayDecoderTest {
)

val testTableAndVariables = """
|name1 = "simple"
|configurationList1 = ["a", "b", "c"]
|name2 = "simple"
|configurationList2 = ["a", "b", "c"]
|[table]
|name = "my name"
""".trimMargin()
name1 = "simple"
configurationList1 = ["a", "b", "c"]
name2 = "simple"
configurationList2 = ["a", "b", "c"]
[table]
name = "my name"
"""


assertEquals(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
package com.akuleshov7.ktoml.decoders

import com.akuleshov7.ktoml.Toml
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith

@Serializable
data class TomlArrayOfTables(val a: List<Long>)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.akuleshov7.ktoml.decoders

import com.akuleshov7.ktoml.Toml
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals


class CharDecoderTest {
@Serializable
data class MyClass(
val a: Char,
val b: Char,
val c: Char,
)

@Test
fun charBasicTest() {
val test =
"""
a = 123
b = '4'
c = 'D'
"""

// FixMe #177: actually this logic is invalid, because Literal Strings should not be making a conversion of str
val decoded = Toml.decodeFromString<MyClass>(test)
assertEquals(decoded, MyClass('{', '4', 'D'))
}

@Test
@Ignore
fun charUnicodeSymbolsTest() {
val test =
"""
a = '\u0048'
b = '\u0FCA'
c = '\u0002'
"""

val decoded = Toml.decodeFromString<MyClass>(test)
assertEquals(decoded, MyClass('{', '\n', '\t'))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class CustomSerializerTest {
""".trimIndent()
)
)
UInt.MAX_VALUE
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,16 @@ class DottedKeysDecoderTest {
),
Toml().decodeFromString(
"""
|table2.b.d = 2
|[table1]
|a.c = 1
|[table1.table2]
|b.b.a = 1
|[table2]
|b.f = 2
|table2."foo bar".d = 2
|[table3]
""".trimMargin()
table2.b.d = 2
[table1]
a.c = 1
[table1.table2]
b.b.a = 1
[table2]
b.f = 2
table2."foo bar".d = 2
[table3]
"""
)
)
}
Expand All @@ -130,11 +130,11 @@ class DottedKeysDecoderTest {
SimpleNestedExample(table2 = Table4(b = B(f = 2, d = 2), e = 5)),
Toml(TomlInputConfig(true)).decodeFromString(
"""
|table2.b.d = 2
|[table2]
|e = 5
|b.f = 2
""".trimMargin()
table2.b.d = 2
[table2]
e = 5
b.f = 2
"""
)
)
}
Expand All @@ -145,13 +145,13 @@ class DottedKeysDecoderTest {
SimpleNestedExample(table2 = Table4(b = B(f = 7, d = 2), e = 6)),
Toml(TomlInputConfig(true)).decodeFromString(
"""
|[table2]
|table2."foo bar".d = 2
|e = 6
|[table2.b]
|d = 2
|f = 7
""".trimMargin()
[table2]
table2."foo bar".d = 2
e = 6
[table2.b]
d = 2
f = 7
"""
)
)
}
Expand Down Expand Up @@ -208,14 +208,14 @@ class DottedKeysDecoderTest {
),
Toml.decodeFromString(
"""
|[a."b.c..".d."e.f"]
| val = 1
| [a]
| [a."b.c.."]
| val = 2
| [a."b.c..".inner]
| val = 3
""".trimMargin()
[a."b.c..".d."e.f"]
val = 1
[a]
[a."b.c.."]
val = 2
[a."b.c..".inner]
val = 3
"""
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,11 @@ class GeneralDecoderTest {
@Test
fun testChildTableBeforeParent() {
val test = """
|[a.b]
| c = 5
| [a]
| a = true
""".trimMargin()
[a.b]
c = 5
[a]
a = true
"""
TomlInputConfig(true)

assertEquals(ChildTableBeforeParent(A(B(5), true)), Toml.decodeFromString(test))
Expand Down Expand Up @@ -377,20 +377,20 @@ class GeneralDecoderTest {
@Test
fun severalTablesOnTheSameLevel() {
val test = """
|[table]
|[table.in1]
| a = 1
| [table.in1.in1]
| a = 1
| [table.in1.in2]
| a = 1
|[table.in2]
| a = 1
| [table.in2.in1]
| a = 1
| [table.in2.in2]
| a = 1
""".trimMargin()
[table]
[table.in1]
a = 1
[table.in1.in1]
a = 1
[table.in1.in2]
a = 1
[table.in2]
a = 1
[table.in2.in1]
a = 1
[table.in2.in2]
a = 1
"""

assertEquals(
MyTest(
Expand Down
Loading