1 /* <lambda>null2 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.serialization.json 6 7 import kotlinx.serialization.* 8 import kotlinx.serialization.test.assertFailsWithSerial 9 import kotlin.test.* 10 11 class JsonCoerceInputValuesTest : JsonTestBase() { 12 @Serializable 13 data class WithBoolean(val b: Boolean = false) 14 15 @Serializable 16 data class WithEnum(val e: SampleEnum = SampleEnum.OptionC) 17 18 @Serializable 19 data class MultipleValues( 20 val data: StringData, 21 val data2: IntData = IntData(0), 22 val i: Int = 42, 23 val e: SampleEnum = SampleEnum.OptionA, 24 val foo: String 25 ) 26 27 @Serializable 28 data class NullableEnumHolder( 29 val enum: SampleEnum? 30 ) 31 32 @Serializable 33 class Uncoercable( 34 val s: String 35 ) 36 37 @Serializable 38 class UncoercableEnum( 39 val e: SampleEnum 40 ) 41 42 val json = Json { 43 coerceInputValues = true 44 isLenient = true 45 } 46 47 private fun <T> doTest(inputs: List<String>, expected: T, serializer: KSerializer<T>) { 48 for (input in inputs) { 49 parametrizedTest(json) { 50 assertEquals(expected, decodeFromString(serializer, input), "Failed on input: $input") 51 } 52 } 53 } 54 55 @Test 56 fun testUseDefaultOnNonNullableBoolean() = doTest( 57 listOf( 58 """{"b":false}""", 59 """{"b":null}""", 60 """{}""", 61 ), 62 WithBoolean(), 63 WithBoolean.serializer() 64 ) 65 66 @Test 67 fun testUseDefaultOnUnknownEnum() { 68 doTest( 69 listOf( 70 """{"e":unknown_value}""", 71 """{"e":"unknown_value"}""", 72 """{"e":null}""", 73 """{}""", 74 ), 75 WithEnum(), 76 WithEnum.serializer() 77 ) 78 assertFailsWithSerial("JsonDecodingException") { 79 json.decodeFromString(WithEnum.serializer(), """{"e":{"x":"definitely not a valid enum value"}}""") 80 } 81 assertFailsWithSerial("JsonDecodingException") { // test user still sees exception on missing quotes 82 Json(json) { isLenient = false }.decodeFromString(WithEnum.serializer(), """{"e":unknown_value}""") 83 } 84 } 85 86 @Test 87 fun testUseDefaultInMultipleCases() { 88 val testData = mapOf( 89 """{"data":{"data":"foo"},"data2":null,"i":null,"e":null,"foo":"bar"}""" to MultipleValues( 90 StringData("foo"), 91 foo = "bar" 92 ), 93 """{"data":{"data":"foo"},"data2":{"intV":42},"i":null,"e":null,"foo":"bar"}""" to MultipleValues( 94 StringData( 95 "foo" 96 ), IntData(42), foo = "bar" 97 ), 98 """{"data":{"data":"foo"},"data2":{"intV":42},"i":0,"e":"NoOption","foo":"bar"}""" to MultipleValues( 99 StringData("foo"), 100 IntData(42), 101 i = 0, 102 foo = "bar" 103 ), 104 """{"data":{"data":"foo"},"data2":{"intV":42},"i":0,"e":"OptionC","foo":"bar"}""" to MultipleValues( 105 StringData("foo"), 106 IntData(42), 107 i = 0, 108 e = SampleEnum.OptionC, 109 foo = "bar" 110 ), 111 ) 112 for ((input, expected) in testData) { 113 assertEquals(expected, json.decodeFromString(MultipleValues.serializer(), input), "Failed on input: $input") 114 } 115 } 116 117 @Test 118 fun testNullSupportForEnums() = parametrizedTest(json) { 119 var decoded = decodeFromString<NullableEnumHolder>("""{"enum": null}""") 120 assertNull(decoded.enum) 121 122 decoded = decodeFromString<NullableEnumHolder>("""{"enum": OptionA}""") 123 assertEquals(SampleEnum.OptionA, decoded.enum) 124 } 125 126 @Test 127 fun propertiesWithoutDefaultValuesDoNotChangeErrorMsg() { 128 val json2 = Json(json) { coerceInputValues = false } 129 parametrizedTest { mode -> 130 val e1 = assertFailsWith<SerializationException>() { json.decodeFromString<Uncoercable>("""{"s":null}""", mode) } 131 val e2 = assertFailsWith<SerializationException>() { json2.decodeFromString<Uncoercable>("""{"s":null}""", mode) } 132 assertEquals(e2.message, e1.message) 133 } 134 } 135 136 @Test 137 fun propertiesWithoutDefaultValuesDoNotChangeErrorMsgEnum() { 138 val json2 = Json(json) { coerceInputValues = false } 139 parametrizedTest { mode -> 140 val e1 = assertFailsWith<SerializationException> { json.decodeFromString<UncoercableEnum>("""{"e":"UNEXPECTED"}""", mode) } 141 val e2 = assertFailsWith<SerializationException> { json2.decodeFromString<UncoercableEnum>("""{"e":"UNEXPECTED"}""", mode) } 142 assertEquals(e2.message, e1.message) 143 } 144 } 145 } 146