summaryrefslogtreecommitdiff
path: root/formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonNamesTest.kt
blob: 34044191d55c55784e7d5fa098019de7640990b5 (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
/*
 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

@file:Suppress("ReplaceArrayOfWithLiteral") // https://youtrack.jetbrains.com/issue/KT-22578

package kotlinx.serialization.features

import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.test.*
import kotlin.test.*

class JsonNamesTest : JsonTestBase() {

    @Serializable
    data class WithNames(@JsonNames("foo", "_foo") val data: String)

    @Serializable
    enum class AlternateEnumNames {
        @JsonNames("someValue", "some_value")
        VALUE_A,
        VALUE_B
    }

    @Serializable
    data class WithEnumNames(
        val enumList: List<AlternateEnumNames>,
        val checkCoercion: AlternateEnumNames = AlternateEnumNames.VALUE_B
    )

    @Serializable
    data class CollisionWithAlternate(
        @JsonNames("_foo") val data: String,
        @JsonNames("_foo") val foo: String
    )

    private val inputString1 = """{"foo":"foo"}"""
    private val inputString2 = """{"_foo":"foo"}"""

    private fun parameterizedCoercingTest(test: (json: Json, streaming: JsonTestingMode, msg: String) -> Unit) {
        for (coercing in listOf(true, false)) {
            val json = Json {
                coerceInputValues = coercing
                useAlternativeNames = true
            }
            parametrizedTest { streaming ->
                test(
                    json, streaming,
                    "Failed test with coercing=$coercing and streaming=$streaming"
                )
            }
        }
    }

    @Test
    fun testEnumSupportsAlternativeNames() {
        val input = """{"enumList":["VALUE_A", "someValue", "some_value", "VALUE_B"], "checkCoercion":"someValue"}"""
        val expected = WithEnumNames(
            listOf(
                AlternateEnumNames.VALUE_A,
                AlternateEnumNames.VALUE_A,
                AlternateEnumNames.VALUE_A,
                AlternateEnumNames.VALUE_B
            ), AlternateEnumNames.VALUE_A
        )
        parameterizedCoercingTest { json, streaming, msg ->
            assertEquals(expected, json.decodeFromString(input, streaming), msg)
        }
    }

    @Test
    fun topLevelEnumSupportAlternativeNames() {
        parameterizedCoercingTest { json, streaming, msg ->
            assertEquals(AlternateEnumNames.VALUE_A, json.decodeFromString("\"someValue\"", streaming), msg)
        }
    }

    @Test
    fun testParsesAllAlternativeNames() {
        for (input in listOf(inputString1, inputString2)) {
            parameterizedCoercingTest { json, streaming, _ ->
                val data = json.decodeFromString(WithNames.serializer(), input, jsonTestingMode = streaming)
                assertEquals("foo", data.data, "Failed to parse input '$input' with streaming=$streaming")
            }
        }
    }

    @Test
    fun testThrowsAnErrorOnDuplicateNames() {
        val serializer = CollisionWithAlternate.serializer()
        parameterizedCoercingTest { json, streaming, _ ->
            assertFailsWithMessage<SerializationException>(
                """The suggested name '_foo' for property foo is already one of the names for property data""",
                "Class ${serializer.descriptor.serialName} did not fail with streaming=$streaming"
            ) {
                json.decodeFromString(
                    serializer, inputString2,
                    jsonTestingMode = streaming
                )
            }
        }
    }
}