1 /* 2 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.serialization 6 7 import kotlinx.serialization.descriptors.SerialDescriptor 8 import kotlinx.serialization.encoding.AbstractDecoder 9 import kotlinx.serialization.encoding.CompositeDecoder 10 import kotlinx.serialization.modules.EmptySerializersModule 11 import kotlinx.serialization.modules.SerializersModule 12 import kotlin.test.Test 13 import kotlin.test.assertEquals 14 import kotlin.test.assertFails 15 16 @Suppress("RedundantSetter", "RedundantGetter", "JoinDeclarationAndAssignment") 17 class CustomPropertyAccessorsTest { 18 @Serializable 19 class VarPropertiesClass { 20 var simple: String = "initial1" 21 var simpleInferred = "initial2" 22 23 var getterSetter: String = "initial3" 24 set(value) { 25 field = value 26 } 27 get() = field 28 29 var getterSetterInferred = "initial4" 30 set(value) { 31 field = value 32 } 33 get() { 34 return field 35 } 36 37 var setter: String = "initial5" 38 set(value) { 39 field = value 40 } 41 42 var deferredInit: String 43 44 var getterDeferredInit: String 45 get() { 46 return field 47 } 48 49 50 var noBackingField: String 51 set(value) { 52 println(value) 53 } 54 get() { 55 return "initial8" 56 } 57 58 init { 59 deferredInit = "initial6" 60 getterDeferredInit = "initial7" 61 } 62 63 } 64 65 @Serializable 66 class ValPropertiesClass { 67 val simple: String = "initial1" 68 val simpleInferred = "initial2" 69 70 val getter: String = "initial3" 71 get() { 72 return field 73 } 74 75 val getterInferred = "initial4" 76 get() { 77 return field 78 } 79 80 val deferredInit: String 81 82 val noBackingField: String 83 get() { 84 return "initial6" 85 } 86 87 init { 88 deferredInit = "initial5" 89 } 90 } 91 92 /* 93 94 This class can't be instantiated because it's hard to check val property with deferred init having backing 95 field on constructor resolve stage. So synthetic constructor's signature differs from it's body and it always 96 throw exception during call. 97 In IR back-end this class would not be compiled. 98 @Serializable 99 class BrokenValPropertiesClass { 100 private val getterDeferredInit: String 101 get() { 102 return field 103 } 104 init { 105 getterDeferredInit = "initial6" 106 } 107 } 108 */ 109 110 111 private class CommonStringDecoder(private val elementCount: Int) : AbstractDecoder() { 112 override val serializersModule: SerializersModule = EmptySerializersModule() 113 private var elementIndex = 0 114 decodeStringnull115 override fun decodeString(): String { 116 return "decoded$elementIndex" 117 } 118 decodeElementIndexnull119 override fun decodeElementIndex(descriptor: SerialDescriptor): Int { 120 if (elementIndex == elementCount) return CompositeDecoder.DECODE_DONE 121 return elementIndex++ 122 } 123 decodeSequentiallynull124 override fun decodeSequentially(): Boolean = false 125 } 126 127 128 @Test 129 fun testVarProperties() { 130 val varPropertiesClass = VarPropertiesClass.serializer().deserialize(CommonStringDecoder(7)) 131 132 assertEquals("decoded1", varPropertiesClass.simple) 133 assertEquals("decoded2", varPropertiesClass.simpleInferred) 134 assertEquals("decoded3", varPropertiesClass.getterSetter) 135 assertEquals("decoded4", varPropertiesClass.getterSetterInferred) 136 assertEquals("decoded5", varPropertiesClass.setter) 137 138 // properties with deferred init always has value from init block - deserialize value ignored 139 assertEquals("initial6", varPropertiesClass.deferredInit) 140 assertEquals("initial7", varPropertiesClass.getterDeferredInit) 141 assertEquals("initial8", varPropertiesClass.noBackingField) 142 } 143 144 @Test testValPropertiesnull145 fun testValProperties() { 146 val valPropertiesClass = ValPropertiesClass.serializer().deserialize(CommonStringDecoder(5)) 147 148 assertEquals("decoded1", valPropertiesClass.simple) 149 assertEquals("decoded2", valPropertiesClass.simpleInferred) 150 assertEquals("decoded3", valPropertiesClass.getter) 151 assertEquals("decoded4", valPropertiesClass.getterInferred) 152 153 // properties with deferred init always has value from init block - deserialize value ignored 154 assertEquals("initial5", valPropertiesClass.deferredInit) 155 assertEquals("initial6", valPropertiesClass.noBackingField) 156 } 157 } 158