jvmTest.kotlinx.serialization.SerializeFlatTest.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-serialization-core-metadata Show documentation
Show all versions of kotlinx-serialization-core-metadata Show documentation
Kotlin multiplatform serialization runtime library
The newest version!
/*
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.serialization
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.modules.*
import org.junit.Test
import kotlin.test.*
// Serializable data class
@Serializable
data class Data(
val value1: String,
val value2: Int
)
// Serializable data class with explicit companion object
@Serializable
data class DataExplicit(
val value1: String,
val value2: Int
) {
companion object
}
// Regular (non-data) class with var properties
@Serializable
class Reg {
var value1: String = ""
var value2: Int = 0
}
// Specify serializable names
@Serializable
data class Names(
@SerialName("value1")
val custom1: String,
@SerialName("value2")
val custom2: Int
)
// Custom serializer
@Serializable(with= CustomSerializer::class)
data class Custom(
val _value1: String,
val _value2: Int
)
@Suppress("NAME_SHADOWING")
object CustomSerializer : KSerializer {
override val descriptor = object : SerialDescriptor {
override val serialName = "kotlinx.serialization.Custom"
override val kind: SerialKind = StructureKind.CLASS
override val elementsCount: Int get() = 2
override fun getElementName(index: Int) = when(index) {
0 -> "value1"
1 -> "value2"
else -> ""
}
override fun getElementIndex(name: String) = when(name) {
"value1" -> 0
"value2" -> 1
else -> -1
}
override fun getElementAnnotations(index: Int): List = emptyList()
override fun getElementDescriptor(index: Int): SerialDescriptor = fail("Should not be called")
override fun isElementOptional(index: Int): Boolean = false
}
override fun serialize(encoder: Encoder, value: Custom) {
val encoder = encoder.beginStructure(descriptor)
encoder.encodeStringElement(descriptor, 0, value._value1)
encoder.encodeIntElement(descriptor, 1, value._value2)
encoder.endStructure(descriptor)
}
override fun deserialize(decoder: Decoder): Custom {
val decoder = decoder.beginStructure(descriptor)
if (decoder.decodeElementIndex(descriptor) != 0) throw java.lang.IllegalStateException()
val value1 = decoder.decodeStringElement(descriptor, 0)
if (decoder.decodeElementIndex(descriptor) != 1) throw java.lang.IllegalStateException()
val value2 = decoder.decodeIntElement(descriptor, 1)
if (decoder.decodeElementIndex(descriptor) != CompositeDecoder.DECODE_DONE) throw java.lang.IllegalStateException()
decoder.endStructure(descriptor)
return Custom(value1, value2)
}
}
// External serializer
// not Serializable !!!
data class ExternalData(
val value1: String,
val value2: Int
)
@Serializer(forClass= ExternalData::class)
object ExternalSerializer
// --------- tests and utils ---------
class SerializeFlatTest() {
@Test
fun testData() {
val out = Out("Data")
out.encodeSerializableValue(serializer(), Data("s1", 42))
out.done()
val inp = Inp("Data")
val data = inp.decodeSerializableValue(serializer())
inp.done()
assert(data.value1 == "s1" && data.value2 == 42)
}
@Test
fun testDataExplicit() {
val out = Out("DataExplicit")
out.encodeSerializableValue(serializer(), DataExplicit("s1", 42))
out.done()
val inp = Inp("DataExplicit")
val data = inp.decodeSerializableValue(serializer())
inp.done()
assert(data.value1 == "s1" && data.value2 == 42)
}
@Test
fun testReg() {
val out = Out("Reg")
val reg = Reg()
reg.value1 = "s1"
reg.value2 = 42
out.encodeSerializableValue(serializer(), reg)
out.done()
val inp = Inp("Reg")
val data = inp.decodeSerializableValue(serializer())
inp.done()
assert(data.value1 == "s1" && data.value2 == 42)
}
@Test
fun testNames() {
val out = Out("Names")
out.encodeSerializableValue(serializer(), Names("s1", 42))
out.done()
val inp = Inp("Names")
val data = inp.decodeSerializableValue(serializer())
inp.done()
assert(data.custom1 == "s1" && data.custom2 == 42)
}
@Test
fun testCustom() {
val out = Out("Custom")
out.encodeSerializableValue(CustomSerializer, Custom("s1", 42))
out.done()
val inp = Inp("Custom")
val data = inp.decodeSerializableValue(CustomSerializer)
inp.done()
assert(data._value1 == "s1" && data._value2 == 42)
}
@Test
fun testExternalData() {
val out = Out("ExternalData")
out.encodeSerializableValue(ExternalSerializer, ExternalData("s1", 42))
out.done()
val inp = Inp("ExternalData")
val data = inp.decodeSerializableValue(ExternalSerializer)
inp.done()
assert(data.value1 == "s1" && data.value2 == 42)
}
companion object {
fun fail(msg: String): Nothing = throw RuntimeException(msg)
fun checkDesc(name: String, desc: SerialDescriptor) {
if (desc.serialName != "kotlinx.serialization." + name) fail("checkDesc name $desc")
if (desc.kind != StructureKind.CLASS) fail("checkDesc kind ${desc.kind}")
if (desc.getElementName(0) != "value1") fail("checkDesc[0] $desc")
if (desc.getElementName(1) != "value2") fail("checkDesc[1] $desc")
}
}
class Out(private val name: String) : AbstractEncoder() {
var step = 0
override val serializersModule: SerializersModule = EmptySerializersModule
override fun beginStructure(
descriptor: SerialDescriptor
): CompositeEncoder {
checkDesc(name, descriptor)
if (step == 0) step++ else fail("@$step: beginStructure($descriptor)")
return this
}
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean {
checkDesc(name, descriptor)
when (step) {
1 -> if (index == 0) {
step++; return true
}
3 -> if (index == 1) {
step++; return true
}
}
fail("@$step: encodeElement($descriptor, $index)")
}
override fun encodeString(value: String) {
when (step) {
2 -> if (value == "s1") {
step++; return
}
}
fail("@$step: encodeString($value)")
}
override fun encodeInt(value: Int) {
when (step) {
4 -> if (value == 42) { step++; return }
}
fail("@$step: decodeInt($value)")
}
override fun endStructure(descriptor: SerialDescriptor) {
checkDesc(name, descriptor)
if (step == 5) step++ else fail("@$step: endStructure($descriptor)")
}
fun done() {
if (step != 6) fail("@$step: OUT FAIL")
}
}
class Inp(private val name: String) : AbstractDecoder() {
var step = 0
override val serializersModule: SerializersModule = EmptySerializersModule
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
checkDesc(name, descriptor)
if (step == 0) step++ else fail("@$step: beginStructure($descriptor)")
return this
}
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
checkDesc(name, descriptor)
when (step) {
1 -> {
step++; return 0
}
3 -> {
step++; return 1
}
5 -> {
step++; return -1
}
}
fail("@$step: decodeElementIndex($descriptor)")
}
override fun decodeString(): String {
when (step) {
2 -> { step++; return "s1" }
}
fail("@$step: decodeString()")
}
override fun decodeInt(): Int {
when (step) {
4 -> { step++; return 42 }
}
fail("@$step: decodeInt()")
}
override fun endStructure(descriptor: SerialDescriptor) {
checkDesc(name, descriptor)
if (step == 6) step++ else fail("@$step: endStructure($descriptor)")
}
fun done() {
if (step != 7) fail("@$step: INP FAIL")
}
}
}