All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonTest.kotlinx.serialization.SerializersLookupTest.kt Maven / Gradle / Ivy

There is a newer version: 1.7.3
Show newest version
/*
 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package kotlinx.serialization

import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.features.sealed.SealedChild
import kotlinx.serialization.features.sealed.SealedParent
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.*
import kotlinx.serialization.test.*
import kotlin.reflect.*
import kotlin.test.*

@Suppress("RemoveExplicitTypeArguments") // This is exactly what's being tested
class SerializersLookupTest : JsonTestBase() {

    @Test
    fun testPrimitive() {
        val token = typeOf()
        val serial = serializer(token)
        assertSame(Int.serializer() as KSerializer<*>, serial)
        assertSerializedWithType("42", 42)
    }

    @Test
    fun testPlainClass() {
        val b = StringData("some string")
        assertSerializedWithType("""{"data":"some string"}""", b)
    }

    @Test
    fun testListWithT() {
        val source = """[{"intV":42}]"""
        val serial = serializer>()
        assertEquals(listOf(IntData(42)), Json.decodeFromString(serial, source))
    }

    @Test
    fun testPrimitiveList() {
        val myArr = listOf("a", "b", "c")
        assertSerializedWithType("""["a","b","c"]""", myArr)
    }

    @Test
    fun testListAsCollection() {
        val myArr: Collection = listOf("a", "b", "c")
        assertSerializedWithType("""["a","b","c"]""", myArr)
    }


    @Test
    fun testPrimitiveSet() {
        val mySet = setOf("a", "b", "c", "c")
        assertSerializedWithType("""["a","b","c"]""", mySet)
    }

    @Test
    fun testMapWithT() {
        val myMap = mapOf("string" to StringData("foo"), "string2" to StringData("bar"))
        assertSerializedWithType("""{"string":{"data":"foo"},"string2":{"data":"bar"}}""", myMap)
    }

    @Test
    fun testNestedLists() {
        val myList = listOf(listOf(listOf(1, 2, 3)), listOf())
        assertSerializedWithType("[[[1,2,3]],[]]", myList)
    }

    @Test
    fun testListSubtype() {
        val myList = arrayListOf(1, 2, 3)
        assertSerializedWithType>("[1,2,3]", myList)
        assertSerializedWithType>("[1,2,3]", myList)
    }

    @Test
    fun testListProjection() {
        val myList = arrayListOf(1, 2, 3)
        assertSerializedWithType>("[1,2,3]", myList)
        assertSerializedWithType>("[1,2,3]", myList)
        assertSerializedWithType>("[1,2,3]", myList)
    }

    @Test
    fun testNullableTypes() {
        val myList: List = listOf(1, null, 3)
        assertSerializedWithType("[1,null,3]", myList)
        assertSerializedWithType?>("[1,null,3]", myList)
    }

    @Test
    fun testPair() {
        val myPair = "42" to 42
        assertSerializedWithType("""{"first":"42","second":42}""", myPair)
    }

    @Test
    fun testTriple() = noLegacyJs { // because of Box
        val myTriple = Triple("1", 2, Box(42))
        assertSerializedWithType("""{"first":"1","second":2,"third":{"boxed":42}}""", myTriple)
    }

    @Test
    fun testCustomGeneric() = noLegacyJs {
        val intBox = Box(42)
        val intBoxSerializer = serializer>()
        assertEquals(Box.serializer(Int.serializer()).descriptor, intBoxSerializer.descriptor)
        assertSerializedWithType("""{"boxed":42}""", intBox)
        val dataBox = Box(StringData("foo"))
        assertSerializedWithType("""{"boxed":{"data":"foo"}}""", dataBox)
    }

    @Test
    fun testRecursiveGeneric() = noLegacyJs {
        val boxBox = Box(Box(Box(IntData(42))))
        assertSerializedWithType("""{"boxed":{"boxed":{"boxed":{"intV":42}}}}""", boxBox)
    }

    @Test
    fun testMixedGeneric() = noLegacyJs {
        val listOfBoxes = listOf(Box("foo"), Box("bar"))
        assertSerializedWithType("""[{"boxed":"foo"},{"boxed":"bar"}]""", listOfBoxes)
        val boxedList = Box(listOf("foo", "bar"))
        assertSerializedWithType("""{"boxed":["foo","bar"]}""", boxedList)
    }

    @Test
    fun testReferenceArrays() {
        assertSerializedWithType("[1,2,3]", Array(3) { it + 1 }, default)
        assertSerializedWithType("""["1","2","3"]""", Array(3) { (it + 1).toString() }, default)
        assertSerializedWithType("[[0],[1],[2]]", Array>(3) { cnt -> Array(1) { cnt } }, default)
        noLegacyJs {
            assertSerializedWithType("""[{"boxed":"foo"}]""", Array(1) { Box("foo") }, default)
            assertSerializedWithType("""[[{"boxed":"foo"}]]""", Array(1) { Array(1) { Box("foo") } }, default)
        }
    }

    @Test
    fun testPrimitiveArrays() {
        assertSerializedWithType("[1,2,3]", intArrayOf(1, 2, 3), default)
        assertSerializedWithType("[1,2,3]", longArrayOf(1, 2, 3), default)
        assertSerializedWithType("[1,2,3]", byteArrayOf(1, 2, 3), default)
        assertSerializedWithType("[1,2,3]", shortArrayOf(1, 2, 3), default)
        assertSerializedWithType("[true,false]", booleanArrayOf(true, false), default)
        assertSerializedWithType("""["a","b","c"]""", charArrayOf('a', 'b', 'c'), default)
    }

    @Test
    fun testSerializableObject() = noLegacyJs {
        assertSerializedWithType("{}", SampleObject)
    }

    class IntBox(val i: Int)

    class CustomIntSerializer(isNullable: Boolean) : KSerializer {
        override val descriptor: SerialDescriptor

        init {
            val d = PrimitiveSerialDescriptor("CIS", PrimitiveKind.INT)
            descriptor = if (isNullable) d.nullable else d
        }

        override fun serialize(encoder: Encoder, value: IntBox?) {
            if (value == null) encoder.encodeInt(41)
            else encoder.encodeInt(42)
        }

        override fun deserialize(decoder: Decoder): IntBox? {
            TODO()
        }
    }

    @Test
    fun testContextualLookup() {
        val module = SerializersModule { contextual(CustomIntSerializer(false).cast()) }
        val json = Json { serializersModule = module }
        val data = listOf(listOf(IntBox(1)))
        assertEquals("[[42]]", json.encodeToString(data))
    }

    @Test
    fun testContextualLookupNullable() {
        val module = SerializersModule { contextual(CustomIntSerializer(true).cast()) }
        val serializer = module.serializer>>()
        assertEquals("[[41]]", Json.encodeToString(serializer, listOf(listOf(null))))
    }

    @Test
    fun testContextualLookupNonNullable() {
        val module = SerializersModule { contextual(CustomIntSerializer(false).cast()) }
        val serializer = module.serializer>>()
        assertEquals("[[null]]", Json.encodeToString(serializer, listOf(listOf(null))))
    }

    @Test
    fun testCompiledWinsOverContextual() {
        val contextual = object : KSerializer {
            override val descriptor: SerialDescriptor = Int.serializer().descriptor

            override fun serialize(encoder: Encoder, value: Int) {
                fail()
            }

            override fun deserialize(decoder: Decoder): Int {
                fail()
            }
        }
        val json = Json { serializersModule = SerializersModule { contextual(contextual) } }
        assertEquals("[[1]]", json.encodeToString(listOf(listOf(1))))
        assertEquals("42", json.encodeToString(42))
    }

    class NonSerializable

    class NonSerializableBox(val boxed: T)

    @Test
    fun testSealedFromOtherFileLookup() {
        assertNotNull(serializerOrNull(typeOf()))
        assertNotNull(serializerOrNull(typeOf()))
    }

    @Test
    fun testLookupFail() {
        assertNull(serializerOrNull(typeOf()))
        assertNull(serializerOrNull(typeOf>()))
        assertNull(serializerOrNull(typeOf>()))

        assertFailsWithMessage("for class 'NonSerializable'") {
            serializer(typeOf())
        }

        assertFailsWithMessage("for class 'NonSerializableBox'") {
            serializer(typeOf>())
        }

        assertFailsWithMessage("for class 'NonSerializable'") {
            serializer(typeOf>())
        }
    }

    private inline fun  assertSerializedWithType(
        expected: String,
        value: T,
        json: StringFormat = default
    ) {
        val serial = serializer()
        assertEquals(expected, json.encodeToString(serial, value))
        val serial2 = requireNotNull(serializerOrNull(typeOf())) { "Expected serializer to be found" }
        assertEquals(expected, json.encodeToString(serial2, value))
    }

    @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
    inline fun  KSerializer<*>.cast(): KSerializer = this as KSerializer

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy