Repository: orchestr7/ktoml (kotlin)

Issue:
Add proper, readable error for incorrect arrays
Now if we will use invalid type where array is expected, ktoml will simply raise:
```
tags is not a valid list index
java.lang.IllegalArgumentException: tags is not a valid list index
```

Pull request:
Fixes #65

Patch:
diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlMainDecoder.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlMainDecoder.kt
index 31f42859..1804fac3 100644
--- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlMainDecoder.kt
+++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlMainDecoder.kt
@@ -102,6 +102,7 @@ public class TomlMainDecoder(
         }
 
         val currentNode = rootNode.getNeighbourNodes().elementAt(elementIndex)
+        checkDescriptorHasAllowedType(descriptor)
         val currentProperty = descriptor.getElementIndex(currentNode.name)
         checkNullability(currentNode, currentProperty, descriptor)
 
@@ -125,6 +126,24 @@ public class TomlMainDecoder(
         return currentProperty
     }
 
+    private fun checkDescriptorHasAllowedType(descriptor: SerialDescriptor) {
+        // LIST and MAP use their own decoders. If we decode with descriptor of these types in
+        // TomlMainDecoder, original toml is invalid, i.e. toml:
+        // a = "abc" # string value
+        // But deserializing type is List/Map
+        when (descriptor.kind) {
+            StructureKind.LIST -> throw IllegalTypeException(
+                "Expected type ARRAY for key \"${rootNode.name}\"",
+                rootNode.lineNo,
+            )
+            StructureKind.MAP -> throw IllegalTypeException(
+                "Expected type MAP for key \"${rootNode.name}\"",
+                rootNode.lineNo,
+            )
+            else -> {}
+        }
+    }
+
     private fun iterateUntilWillFindAnyKnownName(descriptor: SerialDescriptor): Int {
         while (true) {
             if (isDecodingDone()) {


Test patch:
diff --git a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/ArrayDecoderTest.kt b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/ArrayDecoderTest.kt
index 41eeb6b6..ac222278 100644
--- a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/ArrayDecoderTest.kt
+++ b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/ArrayDecoderTest.kt
@@ -185,4 +185,19 @@ class SimpleArrayDecoderTest {
         val testSingleWithInternalQuote = "a = ['yes, \"indeed\"', 'hmm, \"hmm\"']"
         assertEquals(SimpleStringArray(listOf("yes, \"indeed\"", "hmm, \"hmm\"")), Toml.decodeFromString(testSingleWithInternalQuote))
     }
+
+    @Test
+    fun shouldThrowIllegalTypeExceptionOnWrongArrayType() {
+        @Serializable
+        data class ArrayWrapper(
+            val a: List<Int>,
+        )
+        val toml = """
+            a = "abc"
+        """.trimIndent()
+
+        assertFailsWith<IllegalTypeException> {
+            Toml.decodeFromString<ArrayWrapper>(toml)
+        }
+    }
 }
diff --git a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/MapDecoderTest.kt b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/MapDecoderTest.kt
index 78188829..49f2e7fb 100644
--- a/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/MapDecoderTest.kt
+++ b/ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/decoders/MapDecoderTest.kt
@@ -1,6 +1,7 @@
 package com.akuleshov7.ktoml.decoders
 
 import com.akuleshov7.ktoml.Toml
+import com.akuleshov7.ktoml.exceptions.IllegalTypeException
 import com.akuleshov7.ktoml.exceptions.MissingRequiredPropertyException
 import com.akuleshov7.ktoml.exceptions.TomlDecodingException
 import kotlinx.serialization.SerialName
@@ -256,4 +257,19 @@ class MapDecoderTest {
             Toml.decodeFromString<Wrapper>(toml),
         )
     }
+
+    @Test
+    fun shouldThrowIllegalTypeExceptionOnWrongMapType() {
+        @Serializable
+        data class MapWrapper(
+            val a: Map<Int, Int>,
+        )
+        val toml = """
+            a = "abc"
+        """.trimIndent()
+
+        assertFailsWith<IllegalTypeException> {
+            Toml.decodeFromString<MapWrapper>(toml)
+        }
+    }
 }