summaryrefslogtreecommitdiff
path: root/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt')
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt137
1 files changed, 137 insertions, 0 deletions
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt
new file mode 100644
index 00000000..ac24cf04
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/ContextAndPolymorphicTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.features
+
+import kotlinx.serialization.*
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.descriptors.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.*
+import kotlin.test.*
+
+class ContextAndPolymorphicTest {
+
+ @Serializable
+ data class Data(val a: Int, val b: Int = 42)
+
+ @Serializable
+ data class EnhancedData(
+ val data: Data,
+ @Contextual val stringPayload: Payload,
+ @Serializable(with = BinaryPayloadSerializer::class) val binaryPayload: Payload
+ )
+
+ @Serializable
+ @SerialName("Payload")
+ data class Payload(val s: String)
+
+ @Serializable
+ data class PayloadList(val ps: List<@Contextual Payload>)
+
+ @Serializer(forClass = Payload::class)
+ object PayloadSerializer
+
+ object BinaryPayloadSerializer : KSerializer<Payload> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("BinaryPayload", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: Payload) {
+ encoder.encodeString(InternalHexConverter.printHexBinary(value.s.encodeToByteArray()))
+ }
+
+ override fun deserialize(decoder: Decoder): Payload {
+ return Payload(InternalHexConverter.parseHexBinary(decoder.decodeString()).decodeToString())
+ }
+ }
+
+ private val value = EnhancedData(Data(100500), Payload("string"), Payload("binary"))
+ private lateinit var json: Json
+
+ @BeforeTest
+ fun initContext() {
+ val scope = serializersModuleOf(Payload::class, PayloadSerializer)
+ val bPolymorphicModule = SerializersModule { polymorphic(Any::class) { subclass(PayloadSerializer) } }
+ json = Json {
+ useArrayPolymorphism = true
+ encodeDefaults = true
+ serializersModule = scope + bPolymorphicModule
+ }
+ }
+
+ @Test
+ fun testWriteCustom() {
+ val s = json.encodeToString(EnhancedData.serializer(), value)
+ assertEquals("""{"data":{"a":100500,"b":42},"stringPayload":{"s":"string"},"binaryPayload":"62696E617279"}""", s)
+ }
+
+ @Test
+ fun testReadCustom() {
+ val s = json.decodeFromString(
+ EnhancedData.serializer(),
+ """{"data":{"a":100500,"b":42},"stringPayload":{"s":"string"},"binaryPayload":"62696E617279"}""")
+ assertEquals(value, s)
+ }
+
+ @Test
+ fun testWriteCustomList() {
+ val s = json.encodeToString(PayloadList.serializer(), PayloadList(listOf(Payload("1"), Payload("2"))))
+ assertEquals("""{"ps":[{"s":"1"},{"s":"2"}]}""", s)
+ }
+
+ @Test
+ fun testPolymorphicResolve() {
+ val map = mapOf<String, Any>("Payload" to Payload("data"))
+ val serializer = MapSerializer(String.serializer(), PolymorphicSerializer(Any::class))
+ val s = json.encodeToString(serializer, map)
+ assertEquals("""{"Payload":["Payload",{"s":"data"}]}""", s)
+ }
+
+ @Test
+ fun testDifferentRepresentations() {
+ val simpleModule = serializersModuleOf(PayloadSerializer)
+ val binaryModule = serializersModuleOf(BinaryPayloadSerializer)
+
+ val json1 = Json { useArrayPolymorphism = true; serializersModule = simpleModule }
+ val json2 = Json { useArrayPolymorphism = true; serializersModule = binaryModule }
+
+ // in json1, Payload would be serialized with PayloadSerializer,
+ // in json2, Payload would be serialized with BinaryPayloadSerializer
+
+ val list = PayloadList(listOf(Payload("string")))
+ assertEquals("""{"ps":[{"s":"string"}]}""", json1.encodeToString(PayloadList.serializer(), list))
+ assertEquals("""{"ps":["737472696E67"]}""", json2.encodeToString(PayloadList.serializer(), list))
+ }
+
+ private fun SerialDescriptor.inContext(module: SerializersModule): SerialDescriptor = when (kind) {
+ SerialKind.CONTEXTUAL -> requireNotNull(module.getContextualDescriptor(this)) { "Expected $this to be registered in module" }
+ else -> error("Expected this function to be called on CONTEXTUAL descriptor")
+ }
+
+ @Test
+ fun testResolveContextualDescriptor() {
+ val simpleModule = serializersModuleOf(PayloadSerializer)
+ val binaryModule = serializersModuleOf(BinaryPayloadSerializer)
+
+ val contextDesc = EnhancedData.serializer().descriptor.elementDescriptors.toList()[1] // @ContextualSer stringPayload
+ assertEquals(SerialKind.CONTEXTUAL, contextDesc.kind)
+ assertEquals(0, contextDesc.elementsCount)
+
+ val resolvedToDefault = contextDesc.inContext(simpleModule)
+ assertEquals(StructureKind.CLASS, resolvedToDefault.kind)
+ assertEquals("Payload", resolvedToDefault.serialName)
+ assertEquals(1, resolvedToDefault.elementsCount)
+
+ val resolvedToBinary = contextDesc.inContext(binaryModule)
+ assertEquals(PrimitiveKind.STRING, resolvedToBinary.kind)
+ assertEquals("BinaryPayload", resolvedToBinary.serialName)
+ }
+
+ @Test
+ fun testContextualSerializerUsesDefaultIfModuleIsEmpty() {
+ val s = Json { useArrayPolymorphism = true; encodeDefaults = true }.encodeToString(EnhancedData.serializer(), value)
+ assertEquals("""{"data":{"a":100500,"b":42},"stringPayload":{"s":"string"},"binaryPayload":"62696E617279"}""", s)
+ }
+}