summaryrefslogtreecommitdiff
path: root/formats/json/jvmTest/src/kotlinx/serialization/JvmMissingFieldsExceptionTest.kt
blob: b932b5aeee56af94c5a05e35195a4c3e9e3c71ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package kotlinx.serialization

import org.junit.Test
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import org.junit.Ignore
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue

class JvmMissingFieldsExceptionTest {
    @Serializable
    data class Generic<out T1, out T2, out T3>(val f1: T1, val f2: T2, val f3: T3)

    @Serializable
    sealed class Parent(val p1: Int, val p2: Int = 2, val p3: Int) {
        @Serializable
        @SerialName("child")
        data class Child(val c1: Int = 1, val c2: Int, val c3: Int = 3) : Parent(c1 + 1, 2, 3)
    }

    @Serializable
    open class ShortPlaneClass(val f1: Int, val f2: Int, val f3: Int = 3, val f4: Int)

    @Serializable
    class WithTransient(val f1: Int, @Transient val f2: Int = 2, val f3: Int, val f4: Int)

    @Serializable
    abstract class SimpleAbstract(val p1: Int, val p2: Int)

    @Serializable
    @SerialName("a")
    data class ChildA(val c1: Int, val c2: Int = 2, val c3: Int) : SimpleAbstract(0, 10)

    @Serializable
    data class PolymorphicWrapper(@Polymorphic val nested: SimpleAbstract)

    @Serializable
    class BigPlaneClass(
            val f0: Int,
            val f5: Int = 5,
            val f6: Int,
            val f7: Int = 7,
            val f8: Int,
            val f9: Int,
            val f10: Int,
            val f11: Int,
            val f12: Int,
            val f13: Int,
            val f14: Int,
            val f15: Int,
            val f16: Int,
            val f17: Int,
            val f18: Int,
            val f19: Int,
            val f20: Int,
            val f21: Int,
            val f22: Int,
            val f23: Int,
            val f24: Int,
            val f25: Int,
            val f26: Int,
            val f27: Int,
            val f28: Int,
            val f29: Int,
            val f30: Int,
            val f31: Int,
            val f32: Int,
            val f33: Int,
            val f34: Int,
            val f35: Int,
    ) : ShortPlaneClass(1, 2, 3, 4)

    @Test
    fun testShortPlaneClass() {
        assertFailsWithMessages(listOf("f2", "f4")) {
            Json.decodeFromString<ShortPlaneClass>("""{"f1":1}""")
        }
    }

    @Test
    fun testBigPlaneClass() {
        val missedFields = MutableList(35) { "f$it" }
        val definedInJsonFields = arrayOf("f1", "f15", "f34")
        val optionalFields = arrayOf("f3", "f5", "f7")
        missedFields.removeAll(definedInJsonFields)
        missedFields.removeAll(optionalFields)
        assertFailsWithMessages(missedFields) {
            Json.decodeFromString<BigPlaneClass>("""{"f1":1, "f15": 15, "f34": 34}""")
        }
    }

    @Test
    fun testAnnotatedPolymorphic() {
        val module = SerializersModule {
            polymorphic(SimpleAbstract::class, null) {
                subclass(ChildA::class)
            }
        }

        assertFailsWithMessages(listOf("p2", "c3")) {
            Json {
                serializersModule = module
                useArrayPolymorphism = false
            }.decodeFromString<PolymorphicWrapper>("""{"nested": {"type": "a", "p1": 1, "c1": 11}}""")
        }
    }


    @Test
    fun testSealed() {
        assertFailsWithMessages(listOf("p3", "c2")) {
            Json { useArrayPolymorphism = false }
                    .decodeFromString<Parent>("""{"type": "child", "p1":1, "c1": 11}""")
        }
    }

    @Test
    fun testTransient() {
        assertFailsWithMessages(listOf("f3", "f4")) {
            Json { useArrayPolymorphism = false }
                    .decodeFromString<WithTransient>("""{"f1":1}""")
        }
    }

    @Test
    fun testGeneric() {
        assertFailsWithMessages(listOf("f2", "f3")) {
            Json.decodeFromString<Generic<Int, Int, Int>>("""{"f1":1}""")
        }
    }


    private inline fun assertFailsWithMessages(messages: List<String>, block: () -> Unit) {
        val exception = assertFailsWith(SerializationException::class, null, block)
        assertEquals("kotlinx.serialization.MissingFieldException", exception::class.qualifiedName)
        val missedMessages = messages.filter { !exception.message!!.contains(it) }
        assertTrue(missedMessages.isEmpty(), "Expected message '${exception.message}' to contain substrings $missedMessages")
    }
}