/* * 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.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.internal.* import kotlinx.serialization.test.EnumSerializer import kotlin.test.* class SchemaTest { enum class SampleEnum { OptionA, OptionB, OptionC } @Serializable data class Box(val boxed: T) @Serializable(Data1.Companion::class) data class Data1(val l: List = emptyList(), val s: String) { companion object: KSerializer { override val descriptor = buildClassSerialDescriptor("Data1") { element("l", listSerialDescriptor(), isOptional = true) element("s", serialDescriptor()) } override fun serialize(encoder: Encoder, value: Data1) = error("Should not be called") override fun deserialize(decoder: Decoder): Data1 = error("Should not be called") } } @Serializable data class Data2(val l: List = emptyList(), val s: String) @Serializable data class BoxHolder(val stringBox: Box, val intBox: Box) @Serializable data class DataZoo( @Transient val invisible: String = "", val a: Int, val b: String, val c: List, val ll: List>, val m: Map? ) @Serializable data class DataZooIsomorphic( @Transient val invisible: String = "", val b: Int, val a: String, val cc: List, val lll: List>, val mm: Map? = null ) @Serializable private data class DataWithEnum(val s: String, val enum: SampleEnum, val enumList: List = emptyList()) private fun checkDescriptor(serialDescriptor: SerialDescriptor) { val nested = serialDescriptor.getElementDescriptor(0) assertTrue(nested is ListLikeDescriptor) val elem = nested.getElementDescriptor(0) assertTrue(elem.kind is PrimitiveKind.INT) assertEquals("kotlin.Int", elem.serialName) assertTrue(serialDescriptor.isElementOptional(0)) } @Test fun testManualSchema() { checkDescriptor(Data1.serializer().descriptor) } @Test fun testGeneratedSchema() { checkDescriptor(Data2.serializer().descriptor) } @Test fun testRichSchema() { val d: SerialDescriptor = DataZoo.serializer().descriptor val descs = d.elementDescriptors.toList() assertEquals(5, descs.size) assertEquals(listOf(PrimitiveKind.INT, PrimitiveKind.STRING, StructureKind.LIST), descs.take(3).map { it.kind }) val listListDesc = descs[3] assertFalse(listListDesc.isNullable) assertEquals(listListDesc.kind, StructureKind.LIST) assertEquals(1, listListDesc.elementsCount) assertEquals(PrimitiveKind.BOOLEAN, listListDesc.elementDescriptors.first().elementDescriptors.first().kind) val mapDesc = descs[4] assertTrue(mapDesc.isNullable) assertFalse(d.isElementOptional(4), "Expected value to be marked as optional") assertEquals(2, mapDesc.elementsCount) assertEquals(listOf(PrimitiveKind.STRING, StructureKind.CLASS), mapDesc.kinds()) } @Test fun testEqualDescriptors() { val desc1: SerialDescriptor = DataZoo.serializer().descriptor val desc2: SerialDescriptor = DataZooIsomorphic.serializer().descriptor assertEquals(desc1.elementDescriptors.toList(), desc2.elementDescriptors.toList()) assertEquals(Int.serializer().descriptor.elementDescriptors.toList(), Int.serializer().descriptor.elementDescriptors.toList()) } @Test fun testGenericDescriptors() { val boxes = BoxHolder.serializer().descriptor.elementDescriptors.toList() assertTrue(boxes[0].getElementDescriptor(0).kind is PrimitiveKind.STRING) assertTrue(boxes[1].getElementDescriptor(0).kind is PrimitiveKind.INT) assertNotEquals(boxes[0], boxes[1]) val intBox = Box.serializer(Int.serializer()).descriptor assertEquals(intBox.kind, boxes[1].kind) } @Test fun testEnumDescriptors() { val dataDescriptor = DataWithEnum.serializer().descriptor val enumDesc = dataDescriptor.getElementDescriptor(1) val serialName = "kotlinx.serialization.features.SchemaTest.SampleEnum" val manualSerializer = EnumSerializer(serialName) assertEquals(enumDesc, manualSerializer.descriptor) assertEquals(enumDesc, dataDescriptor.getElementDescriptor(2).getElementDescriptor(0)) } @Test fun testKindNames() { val classDesc = BoxHolder.serializer().descriptor assertEquals("CLASS", classDesc.kind.toString()) val intDesc = classDesc.elementDescriptors.toList()[1].elementDescriptors.toList()[0] assertEquals("INT", intDesc.kind.toString()) } private fun SerialDescriptor.kinds(): List { return List(elementsCount) { getElementDescriptor(it).kind } } }