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

commonTest.kotlinx.serialization.modules.ModuleBuildersTest.kt Maven / Gradle / Ivy

/*
 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

@file:Suppress("UNCHECKED_CAST")

package kotlinx.serialization.modules

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlin.reflect.*
import kotlin.test.*

class ModuleBuildersTest {
    @Serializable
    class A(val i: Int)

    @Serializable
    class B(val b: String)

    @Serializer(forClass = A::class)
    object ASerializer : KSerializer

    @Serializer(forClass = B::class)
    object BSerializer : KSerializer

    private fun SerializersModule.assertModuleHas(aSerializer: Boolean = false, bSerializer: Boolean = false) {
        with(this) {
            assertSame(if (aSerializer) ASerializer else null, getContextual(A::class))
            assertSame(if (bSerializer) BSerializer else null, getContextual(B::class))
        }
    }

    @Test
    fun testSingletonModule() {
        val module = serializersModuleOf(A::class, ASerializer)
        module.assertModuleHas(
            aSerializer = true,
            bSerializer = false
        )
    }

    @Test
    fun testMapModule() {
        val module1 = serializersModuleOf(BSerializer)
        module1.assertModuleHas(
            aSerializer = false,
            bSerializer = true
        )

        SerializersModule {
            contextual(ASerializer)
            contextual(BSerializer)
        }.assertModuleHas(
            aSerializer = true,
            bSerializer = true
        )

        (module1 + serializersModuleOf(A::class, ASerializer)).assertModuleHas(
            aSerializer = true,
            bSerializer = true
        )
    }

    @Test
    fun testCompositeModule() {
        val moduleA = serializersModuleOf(ASerializer)
        val moduleB = serializersModuleOf(BSerializer)

        (moduleA + moduleB).assertModuleHas(
            aSerializer = true,
            bSerializer = true
        )

        var composite = SerializersModule { }
        composite.assertModuleHas(
            aSerializer = false,
            bSerializer = false
        )
        composite += moduleA
        composite.assertModuleHas(
            aSerializer = true,
            bSerializer = false
        )
        composite += moduleB
        composite.assertModuleHas(
            aSerializer = true,
            bSerializer = true
        )
    }

    @Test
    fun testDSL() {
        val module = SerializersModule {
            contextual(A::class, ASerializer)
        }
        module.assertModuleHas(aSerializer = true, bSerializer = false)
    }

    @Test
    fun testPolymorphicDSL() {
        val module1 = SerializersModule {
            polymorphic(PolyBase::class, PolyBase.serializer()) {
                subclass(PolyDerived.serializer())
            }
            polymorphic(Any::class, baseSerializer = null) {
                subclass(PolyBase.serializer())
                subclass(PolyDerived.serializer())
            }
        }

        val module2 = SerializersModule {
            polymorphic(Any::class) {
                subclass(PolyBase::class)
                subclass(PolyDerived.serializer())
            }

            polymorphic(PolyBase::class) {
                subclass(PolyBase.serializer())
                subclass(PolyDerived::class)
            }
        }

        val base = PolyBase(10)
        val derived = PolyDerived("foo")

        listOf(module1, module2).forEachIndexed { index, module ->
            fun  assertPoly(serializer: KSerializer, base: KClass, obj: T) =
                assertEquals(
                    serializer,
                    module.getPolymorphic(base, obj),
                    "No serializer for ${obj::class} with base $base in module ${index + 1}:"
                )

            assertPoly(PolyBase.serializer(), PolyBase::class, base)
            assertPoly(PolyDerived.serializer(), PolyBase::class, derived)
            assertPoly(PolyBase.serializer(), Any::class, base)
            assertPoly(PolyDerived.serializer(), Any::class, derived)
        }

    }

    @Test
    fun testOverwriteSerializer() {
        val moduleA = SerializersModule {
            contextual(A::class, ASerializer)
            assertFailsWith {
                contextual(A::class, object : KSerializer by A.serializer() {})
            }
        }
        moduleA.assertModuleHas(aSerializer = true, bSerializer = false)
    }

    @Test
    fun testOverwriteIsRightBiased() {
        val incorrect = serializersModuleOf(A::class as KClass, BSerializer as KSerializer)
        val correct = serializersModuleOf(ASerializer)
        correct.assertModuleHas(aSerializer = true, bSerializer = false)
        val sum = incorrect overwriteWith correct
        sum.assertModuleHas(aSerializer = true, bSerializer = false)
    }

    @Test
    fun testPlusThrowsExceptionOnDuplication() {
        val incorrect = serializersModuleOf(A::class as KClass, BSerializer as KSerializer)
        val correct = serializersModuleOf(ASerializer)
        correct.assertModuleHas(aSerializer = true, bSerializer = false)
        assertFailsWith {
            incorrect + correct
        }
    }

    @Serializable
    @SerialName("C")
    class C

    @Serializer(forClass = C::class)
    object CSerializer : KSerializer {
        override val descriptor: SerialDescriptor = buildSerialDescriptor("AnotherName", StructureKind.OBJECT)
    }

    @Serializer(forClass = C::class)
    object CSerializer2 : KSerializer {
        override val descriptor: SerialDescriptor = buildSerialDescriptor("C", StructureKind.OBJECT)
    }

    @Test
    fun testOverwriteWithDifferentSerialName() {
        val m1 = SerializersModule {
            polymorphic(Any::class) {
                subclass(C::class, CSerializer)
            }
        }
        val m2 = SerializersModule {
            polymorphic(Any::class) {
                subclass(C::class, C.serializer())
            }
        }
        assertEquals(CSerializer, m1.getPolymorphic(Any::class, serializedClassName = "AnotherName"))
        assertFailsWith { m1 + m2 }
        val result = m1 overwriteWith m2
        assertEquals(C.serializer(), result.getPolymorphic(Any::class, C()))
        assertEquals(C.serializer(), result.getPolymorphic(Any::class, serializedClassName = "C"))
        assertNull(result.getPolymorphic(Any::class, serializedClassName = "AnotherName"))
    }

    @Test
    fun testOverwriteWithSameSerialName() {
        val m1 = SerializersModule {
            polymorphic(Any::class) {
                subclass(C::class, C.serializer())
            }
        }
        val m2 = SerializersModule {
            polymorphic(Any::class) {
                subclass(C::class, CSerializer2)
            }
        }
        assertEquals(C.serializer(), m1.getPolymorphic(Any::class, serializedClassName = "C"))
        assertEquals(CSerializer2, m2.getPolymorphic(Any::class, serializedClassName = "C"))
        assertFailsWith { m1 + m2 }
        val result = m1 overwriteWith m2
        assertEquals(CSerializer2, result.getPolymorphic(Any::class, C()))
        assertEquals(CSerializer2, result.getPolymorphic(Any::class, serializedClassName = "C"))
    }

    @Test
    fun testDoesntThrowOnTheSameSerializer() {
        val m1 = serializersModuleOf(A::class, A.serializer())
        val m2 = serializersModuleOf(A::class, A.serializer())
        val aggregate = m1 + m2
        assertEquals(A.serializer(), aggregate.getContextual(A::class))
    }

    @Test
    fun testDoesntThrowOnTheEqualSerializers() {
        val delegate = object : KSerializer by Unit.serializer() {
            override fun equals(other: Any?): Boolean = (other is KSerializer<*>) && other.descriptor == descriptor
        }

        val delegate2 = object : KSerializer by Unit.serializer() {
            override fun equals(other: Any?): Boolean = (other is KSerializer<*>) && other.descriptor == descriptor
        }

        val m1 = serializersModuleOf(Unit::class, delegate)
        val m2 = serializersModuleOf(Unit::class, delegate2)
        val aggregate = m1 + m2
        assertEquals(delegate2, aggregate.getContextual(Unit::class))
        assertEquals(delegate, aggregate.getContextual(Unit::class))
    }

    @Test
    fun testThrowOnTheSamePolymorphicSerializer() {
        val m1 = SerializersModule { polymorphic(Any::class) { subclass(A.serializer()) } }
        val m2 = SerializersModule { polymorphic(Any::class) { subclass(ASerializer) } }
        assertFailsWith { m1 + m2 }
    }

    @Test
    fun testDoesntThrowOnEqualPolymorphicSerializer() {
        val delegate = object : KSerializer by Unit.serializer() {
            override fun equals(other: Any?): Boolean = (other is KSerializer<*>) && other.descriptor == descriptor
        }

        val delegate2 = object : KSerializer by Unit.serializer() {
            override fun equals(other: Any?): Boolean = (other is KSerializer<*>) && other.descriptor == descriptor
        }

        assertEquals(delegate as Any, delegate2 as Any)
        val m1 = SerializersModule { polymorphic(Any::class) { subclass(delegate) } }
        val m2 = SerializersModule { polymorphic(Any::class) { subclass(delegate2) } }
        val aggregate = m1 + m2
        assertEquals(delegate2, aggregate.getPolymorphic(Any::class, Unit))
        assertEquals(delegate, aggregate.getPolymorphic(Any::class, Unit))
    }

    @Test
    fun testPolymorphicCollision() {
        val m1 = SerializersModule {
            polymorphic(Any::class) {
                defaultDeserializer { _ -> Unit.serializer() }
            }
        }

        val m2 = SerializersModule {
            polymorphic(Any::class) {
                defaultDeserializer { _ -> Unit.serializer() }
            }
        }

        assertFailsWith { m1 + m2 }
    }

    @Test
    fun testNoPolymorphicCollision() {
        val defaultSerializerProvider = { _: String? -> Unit.serializer() }
        val m1 = SerializersModule {
            polymorphic(Any::class) {
                defaultDeserializer(defaultSerializerProvider)
            }
        }

        val m2 = m1 + m1
        assertEquals(Unit.serializer(), m2.getPolymorphic(Any::class, serializedClassName = "foo"))
    }

    @Test
    fun testBothPolymorphicDefaults() {
        val anySerializer = object : KSerializer {
            override val descriptor: SerialDescriptor get() = error("descriptor")
            override fun serialize(encoder: Encoder, value: Any): Unit = error("serialize")
            override fun deserialize(decoder: Decoder): Any = error("deserialize")
        }
        val module = SerializersModule {
            polymorphicDefaultDeserializer(Any::class) { _ -> anySerializer }
            polymorphicDefaultSerializer(Any::class) { _ -> anySerializer }
        }
        assertEquals(anySerializer, module.getPolymorphic(Any::class, 42))
        assertEquals(anySerializer, module.getPolymorphic(Any::class, serializedClassName = "42"))
    }

    @Test
    fun testPolymorphicForStandardSubtypesOfAny() {
        val serializer = object : KSerializer by Int.serializer() {}

        val module = SerializersModule {
            polymorphic(Any::class) {
                subclass(serializer)
            }
        }

        assertSame(serializer, module.getPolymorphic(Any::class, 42))
        assertSame(serializer, module.getPolymorphic(Any::class, serializedClassName =  "kotlin.Int"))
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy