summaryrefslogtreecommitdiff
path: root/runtime/jvmTest/src/kotlinx/serialization/SerializeFlatTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/jvmTest/src/kotlinx/serialization/SerializeFlatTest.kt')
-rw-r--r--runtime/jvmTest/src/kotlinx/serialization/SerializeFlatTest.kt285
1 files changed, 285 insertions, 0 deletions
diff --git a/runtime/jvmTest/src/kotlinx/serialization/SerializeFlatTest.kt b/runtime/jvmTest/src/kotlinx/serialization/SerializeFlatTest.kt
new file mode 100644
index 00000000..7a51bb2b
--- /dev/null
+++ b/runtime/jvmTest/src/kotlinx/serialization/SerializeFlatTest.kt
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.serialization
+
+import org.junit.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<Custom> {
+ override val descriptor = object : SerialDescriptor {
+ override val name = "kotlinx.serialization.Custom"
+ override val kind: SerialKind = StructureKind.CLASS
+ 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 serialize(encoder: Encoder, obj : Custom) {
+ val encoder = encoder.beginStructure(descriptor)
+ encoder.encodeStringElement(descriptor, 0, obj._value1)
+ encoder.encodeIntElement(descriptor, 1, obj._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.READ_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.encode(Data::class.serializer(), Data("s1", 42))
+ out.done()
+
+ val inp = Inp("Data")
+ val data = inp.decode(Data::class.serializer())
+ inp.done()
+ assert(data.value1 == "s1" && data.value2 == 42)
+ }
+
+ @Test
+ fun testDataExplicit() {
+ val out = Out("DataExplicit")
+ out.encode(DataExplicit::class.serializer(), DataExplicit("s1", 42))
+ out.done()
+
+ val inp = Inp("DataExplicit")
+ val data = inp.decode(DataExplicit::class.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.encode(Reg::class.serializer(), reg)
+ out.done()
+
+ val inp = Inp("Reg")
+ val data = inp.decode(Reg::class.serializer())
+ inp.done()
+ assert(data.value1 == "s1" && data.value2 == 42)
+ }
+
+ @Test
+ fun testNames() {
+ val out = Out("Names")
+ out.encode(Names::class.serializer(), Names("s1", 42))
+ out.done()
+
+ val inp = Inp("Names")
+ val data = inp.decode(Names::class.serializer())
+ inp.done()
+ assert(data.custom1 == "s1" && data.custom2 == 42)
+ }
+
+ @Test
+ fun testCustom() {
+ val out = Out("Custom")
+ out.encode(CustomSerializer, Custom("s1", 42))
+ out.done()
+
+ val inp = Inp("Custom")
+ val data = inp.decode(CustomSerializer)
+ inp.done()
+ assert(data._value1 == "s1" && data._value2 == 42)
+ }
+
+ @Test
+ fun testExternalData() {
+ val out = Out("ExternalData")
+ out.encode(ExternalSerializer, ExternalData("s1", 42))
+ out.done()
+
+ val inp = Inp("ExternalData")
+ val data = inp.decode(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.name != "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) : ElementValueEncoder() {
+ var step = 0
+
+ override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeEncoder {
+ checkDesc(name, desc)
+ if (step == 0) step++ else fail("@$step: beginStructure($desc)")
+ return this
+ }
+
+ override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
+ checkDesc(name, desc)
+ when (step) {
+ 1 -> if (index == 0) { step++; return true }
+ 3 -> if (index == 1) { step++; return true }
+ }
+ fail("@$step: encodeElement($desc, $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(desc: SerialDescriptor) {
+ checkDesc(name, desc)
+ if (step == 5) step++ else fail("@$step: endStructure($desc)")
+ }
+
+ fun done() {
+ if (step != 6) fail("@$step: OUT FAIL")
+ }
+ }
+
+ class Inp(private val name: String) : ElementValueDecoder() {
+ var step = 0
+
+ override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
+ checkDesc(name, desc)
+ if (step == 0) step++ else fail("@$step: beginStructure($desc)")
+ return this
+ }
+
+ override fun decodeElementIndex(desc: SerialDescriptor): Int {
+ checkDesc(name, desc)
+ when (step) {
+ 1 -> { step++; return 0 }
+ 3 -> { step++; return 1 }
+ 5 -> { step++; return -1 }
+ }
+ fail("@$step: decodeElementIndex($desc)")
+ }
+
+ 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(desc: SerialDescriptor) {
+ checkDesc(name, desc)
+ if (step == 6) step++ else fail("@$step: endStructure($desc)")
+ }
+
+ fun done() {
+ if (step != 7) fail("@$step: INP FAIL")
+ }
+ }
+}