summaryrefslogtreecommitdiff
path: root/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic
diff options
context:
space:
mode:
authorSergey Shanshin <sergey.shanshin@jetbrains.com>2022-06-30 15:43:42 +0300
committerGitHub <noreply@github.com>2022-06-30 15:43:42 +0300
commit5e8ccad1f70a9457e0ffe6ae6b10a0bd0eaaa618 (patch)
treee522ba5e8da0cb4701f4a259d9f2ba5b43b42bf2 /formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic
parent605a35faa87534e24482aa00a52a2a71bebd51a3 (diff)
downloadkotlinx.serialization-5e8ccad1f70a9457e0ffe6ae6b10a0bd0eaaa618.tar.gz
Add Okio integration (#1901)
* Add okio integration as separate module json-okio * Extract separate module json-tests that tests both Java streams and okio * Rewrite Java stream writer so that it uses much faster in-place UTF8 encoder instead of java.io.Writer * Add benchmarks for streams and okio * Disable targets for tests that are not supported by okio (they can't be run on LinuxX64-86 hosts anyway)
Diffstat (limited to 'formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic')
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt103
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt25
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt46
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt94
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt67
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt33
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt26
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt44
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt51
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt96
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt63
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt65
12 files changed, 713 insertions, 0 deletions
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt
new file mode 100644
index 00000000..d58e26b6
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonContentPolymorphicSerializerTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonContentPolymorphicSerializerTest : JsonTestBase() {
+ val json = Json
+
+ @Serializable
+ sealed class Choices {
+ @Serializable
+ data class HasA(val a: String) : Choices()
+
+ @Serializable
+ data class HasB(val b: Int) : Choices()
+
+ @Serializable
+ data class HasC(val c: Boolean) : Choices()
+ }
+
+ object ChoicesParametricSerializer : JsonContentPolymorphicSerializer<Choices>(Choices::class) {
+ override fun selectDeserializer(element: JsonElement): KSerializer<out Choices> {
+ val obj = element.jsonObject
+ return when {
+ "a" in obj -> Choices.HasA.serializer()
+ "b" in obj -> Choices.HasB.serializer()
+ "c" in obj -> Choices.HasC.serializer()
+ else -> throw SerializationException("Unknown choice")
+ }
+ }
+ }
+
+ @Serializable
+ data class WithChoices(@Serializable(ChoicesParametricSerializer::class) val response: Choices)
+
+ private val testDataInput = listOf(
+ """{"response":{"a":"string"}}""",
+ """{"response":{"b":42}}""",
+ """{"response":{"c":true}}"""
+ )
+
+ private val testDataOutput = listOf(
+ WithChoices(Choices.HasA("string")),
+ WithChoices(Choices.HasB(42)),
+ WithChoices(Choices.HasC(true))
+ )
+
+ @Test
+ fun testParsesParametrically() = parametrizedTest { streaming ->
+ for (i in testDataInput.indices) {
+ assertEquals(
+ testDataOutput[i],
+ json.decodeFromString(WithChoices.serializer(), testDataInput[i], streaming),
+ "failed test on ${testDataInput[i]}, jsonTestingMode = $streaming"
+ )
+ }
+ }
+
+ @Test
+ fun testSerializesParametrically() = parametrizedTest { streaming ->
+ for (i in testDataOutput.indices) {
+ assertEquals(
+ testDataInput[i],
+ json.encodeToString(WithChoices.serializer(), testDataOutput[i], streaming),
+ "failed test on ${testDataOutput[i]}, jsonTestingMode = $streaming"
+ )
+ }
+ }
+
+ interface Payment {
+ val amount: String
+ }
+
+ @Serializable
+ data class SuccessfulPayment(override val amount: String, val date: String) : Payment
+
+ @Serializable
+ data class RefundedPayment(override val amount: String, val date: String, val reason: String) : Payment
+
+ object PaymentSerializer : JsonContentPolymorphicSerializer<Payment>(Payment::class) {
+ override fun selectDeserializer(element: JsonElement) = when {
+ "reason" in element.jsonObject -> RefundedPayment.serializer()
+ else -> SuccessfulPayment.serializer()
+ }
+ }
+
+ @Test
+ fun testDocumentationSample() = parametrizedTest { streaming ->
+ assertEquals(
+ SuccessfulPayment("1.0", "03.02.2020"),
+ json.decodeFromString(PaymentSerializer, """{"amount":"1.0","date":"03.02.2020"}""", streaming)
+ )
+ assertEquals(
+ RefundedPayment("2.0", "03.02.2020", "complaint"),
+ json.decodeFromString(PaymentSerializer, """{"amount":"2.0","date":"03.02.2020","reason":"complaint"}""", streaming)
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt
new file mode 100644
index 00000000..f0229046
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonDeserializePolymorphicTwiceTest.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonDeserializePolymorphicTwiceTest {
+
+ @Serializable
+ sealed class Foo {
+ @Serializable
+ data class Bar(val a: Int) : Foo()
+ }
+
+ @Test
+ fun testDeserializeTwice() { // #812
+ val json = Json.encodeToJsonElement(Foo.serializer(), Foo.Bar(1))
+ assertEquals(Foo.Bar(1), Json.decodeFromJsonElement(Foo.serializer(), json))
+ assertEquals(Foo.Bar(1), Json.decodeFromJsonElement(Foo.serializer(), json))
+ }
+} \ No newline at end of file
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt
new file mode 100644
index 00000000..5722e8df
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonListPolymorphismTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.Polymorphic
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.JsonTestBase
+import kotlin.test.Test
+import kotlin.test.assertFails
+
+class JsonListPolymorphismTest : JsonTestBase() {
+
+ @Serializable
+ internal data class ListWrapper(val list: List<@Polymorphic InnerBase>)
+
+ @Test
+ fun testPolymorphicValues() = assertJsonFormAndRestored(
+ ListWrapper.serializer(),
+ ListWrapper(listOf(InnerImpl(1), InnerImpl2(2))),
+ """{"list":[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":2}]}""",
+ polymorphicRelaxedJson)
+
+ @Serializable
+ internal data class ListNullableWrapper(val list: List<@Polymorphic InnerBase?>)
+
+ @Test
+ fun testPolymorphicNullableValues() = assertJsonFormAndRestored(
+ ListNullableWrapper.serializer(),
+ ListNullableWrapper(listOf(InnerImpl(1), null)),
+ """{"list":[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},""" +
+ "null]}",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testPolymorphicNullableValuesWithNonNullSerializerFails() =
+ parametrizedTest { jsonTestingMode ->
+ val wrapper = ListNullableWrapper(listOf(InnerImpl(1), null))
+ val serialized = polymorphicRelaxedJson.encodeToString(ListNullableWrapper.serializer(), wrapper, jsonTestingMode)
+ assertFails { polymorphicRelaxedJson.decodeFromString(ListWrapper.serializer(), serialized, jsonTestingMode) }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt
new file mode 100644
index 00000000..b2adaa71
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonMapPolymorphismTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonMapPolymorphismTest : JsonTestBase() {
+
+ @Serializable
+ internal data class MapWrapper(val map: Map<String, @Polymorphic InnerBase>)
+
+ @Test
+ fun testPolymorphicValues() = assertJsonFormAndRestored(
+ MapWrapper.serializer(),
+ MapWrapper(mapOf("k1" to InnerImpl(1), "k2" to InnerImpl2(2))),
+ """{"map":{"k1":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},"k2":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":2}}}""".trimMargin(),
+ polymorphicJson
+ )
+
+ @Serializable
+ internal data class MapNullableWrapper(val map: Map<String, @Polymorphic InnerBase?>)
+
+ @Serializable
+ internal data class MapKeys(val map: Map<@Polymorphic InnerBase, String>)
+
+ @Test
+ fun testPolymorphicNullableValues() = assertJsonFormAndRestored(
+ MapNullableWrapper.serializer(),
+ MapNullableWrapper(mapOf("k1" to InnerImpl(1), "k2" to null)),
+ """{"map":{"k1":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},"k2":null}}""",
+ polymorphicJson
+ )
+
+ @Test
+ fun testPolymorphicKeys() {
+ val json = Json {
+ allowStructuredMapKeys = true
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+ }
+ assertJsonFormAndRestored(
+ MapKeys.serializer(),
+ MapKeys(mapOf(InnerImpl(1) to "k2", InnerImpl2(2) to "k2")),
+ """{"map":[{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null},"k2",{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":2},"k2"]}""",
+ json
+ )
+ }
+
+ @Test
+ fun testPolymorphicKeysInArray() {
+ val json = Json {
+ allowStructuredMapKeys = true
+ useArrayPolymorphism = true
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+ }
+ assertJsonFormAndRestored(
+ MapKeys.serializer(),
+ MapKeys(mapOf(InnerImpl(1) to "k2", InnerImpl2(2) to "k2")),
+ """{"map":[["kotlinx.serialization.json.polymorphic.InnerImpl",{"field":1,"str":"default","nullable":null}],"k2",["kotlinx.serialization.json.polymorphic.InnerImpl2",{"field":2}],"k2"]}""",
+ json
+ )
+ }
+
+ @Serializable
+ abstract class Base
+
+ @Serializable
+ data class Derived(val myMap: Map<StringData, String>) : Base()
+
+ @Test
+ fun testIssue480() {
+ val json = Json {
+ allowStructuredMapKeys = true
+ serializersModule = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived.serializer())
+ }
+ }
+ }
+
+ assertJsonFormAndRestored(
+ Base.serializer(),
+ Derived(mapOf(StringData("hi") to "hello")),
+ """{"type":"kotlinx.serialization.json.polymorphic.JsonMapPolymorphismTest.Derived","myMap":[{"data":"hi"},"hello"]}""",
+ json
+ )
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt
new file mode 100644
index 00000000..0caa99dd
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNestedPolymorphismTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonNestedPolymorphismTest : JsonTestBase() {
+
+ private val polymorphicJson = Json {
+ isLenient = true
+ encodeDefaults = true
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(InnerImpl.serializer())
+ subclass(InnerImpl2.serializer())
+ subclass(OuterImpl.serializer())
+
+ }
+
+ polymorphic(InnerBase::class) {
+ subclass(InnerImpl.serializer())
+ subclass(InnerImpl2.serializer())
+ }
+ }
+ }
+
+ @Serializable
+ internal data class NestedGenericsList(val list: List<List<@Polymorphic Any>>)
+
+ @Test
+ fun testAnyList() = assertJsonFormAndRestored(
+ NestedGenericsList.serializer(),
+ NestedGenericsList(listOf(listOf(InnerImpl(1)), listOf(InnerImpl(2)))),
+ """{"list":[[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":1,"str":"default","nullable":null}],[""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":2,"str":"default","nullable":null}]]}""",
+ polymorphicJson)
+
+ @Serializable
+ internal data class NestedGenericsMap(val list: Map<String, Map<String, @Polymorphic Any>>)
+
+ @Test
+ fun testAnyMap() = assertJsonFormAndRestored(
+ NestedGenericsMap.serializer(),
+ NestedGenericsMap(mapOf("k1" to mapOf("k1" to InnerImpl(1)))),
+ """{"list":{"k1":{"k1":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":1,"str":"default","nullable":null}}}}""",
+ polymorphicJson)
+
+ @Serializable
+ internal data class AnyWrapper(@Polymorphic val any: Any)
+
+ @Test
+ fun testAny() = assertJsonFormAndRestored(
+ AnyWrapper.serializer(),
+ AnyWrapper(OuterImpl(InnerImpl2(1), InnerImpl(2))),
+ """{"any":""" +
+ """{"type":"kotlinx.serialization.json.polymorphic.OuterImpl",""" +
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":1},""" +
+ """"base2":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":2,"str":"default","nullable":null}}}""",
+ polymorphicJson)
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt
new file mode 100644
index 00000000..ba8d0dfe
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonNullablePolymorphicTest.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonNullablePolymorphicTest : JsonTestBase() {
+ @Serializable
+ data class NullableHolder(@Polymorphic val a: Any?)
+
+ @Serializable
+ @SerialName("Box")
+ data class Box(val i: Int)
+
+ @Test
+ fun testPolymorphicNulls() {
+ val json = Json {
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(Box::class)
+ }
+ }
+ }
+
+ assertJsonFormAndRestored(serializer(), NullableHolder(Box(42)), """{"a":{"type":"Box","i":42}}""", json)
+ assertJsonFormAndRestored(serializer(), NullableHolder(null), """{"a":null}""", json)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt
new file mode 100644
index 00000000..b11e9dad
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicClassDescriptorTest.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.json.*
+import kotlin.test.*
+
+class JsonPolymorphicClassDescriptorTest : JsonTestBase() {
+
+ private val json = Json {
+ classDiscriminator = "class"
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+ }
+
+ @Test
+ fun testPolymorphicProperties() = assertJsonFormAndRestored(
+ InnerBox.serializer(),
+ InnerBox(InnerImpl(42, "foo")),
+ """{"base":{"class":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}}""",
+ json
+ )
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt
new file mode 100644
index 00000000..e47f5790
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphicObjectTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonPolymorphicObjectTest : JsonTestBase() {
+
+ @Serializable
+ data class Holder(@Polymorphic val a: Any)
+
+ @Serializable
+ @SerialName("MyObject")
+ object MyObject {
+ @Suppress("unused")
+ val unused = 42
+ }
+
+ val json = Json {
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ subclass(MyObject::class, MyObject.serializer()) // JS bug workaround
+ }
+ }
+ }
+
+ @Test
+ fun testRegularPolymorphism() {
+ assertJsonFormAndRestored(Holder.serializer(), Holder(MyObject), """{"a":{"type":"MyObject"}}""", json)
+ }
+
+ @Test
+ fun testArrayPolymorphism() {
+ val json = Json(from = json) {
+ useArrayPolymorphism = true
+ }
+ assertJsonFormAndRestored(Holder.serializer(), Holder(MyObject), """{"a":["MyObject",{}]}""", json)
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt
new file mode 100644
index 00000000..b7d4f122
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPolymorphismExceptionTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.json.internal.*
+import kotlinx.serialization.modules.*
+import kotlinx.serialization.test.assertFailsWithSerial
+import kotlin.test.*
+
+class JsonPolymorphismExceptionTest : JsonTestBase() {
+
+ @Serializable
+ abstract class Base
+
+ @Serializable
+ @SerialName("derived")
+ class Derived(val nested: Nested = Nested()) : Base()
+
+ @Serializable
+ class Nested
+
+ @Test
+ fun testDecodingException() = parametrizedTest { jsonTestingMode ->
+ val serialModule = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived::class)
+ }
+ }
+
+ assertFailsWithSerial("JsonDecodingException") {
+ Json { serializersModule = serialModule }.decodeFromString(Base.serializer(), """{"type":"derived","nested":null}""", jsonTestingMode)
+ }
+ }
+
+ @Test
+ fun testMissingDiscriminator() = parametrizedTest { jsonTestingMode ->
+ val serialModule = SerializersModule {
+ polymorphic(Base::class) {
+ subclass(Derived::class)
+ }
+ }
+
+ assertFailsWithSerial("JsonDecodingException") {
+ Json { serializersModule = serialModule }.decodeFromString(Base.serializer(), """{"nested":{}}""", jsonTestingMode)
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt
new file mode 100644
index 00000000..7a825395
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonProhibitedPolymorphicKindsTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.test.*
+
+class JsonProhibitedPolymorphicKindsTest : JsonTestBase() {
+
+ @Serializable
+ sealed class Base {
+ @Serializable
+ class Impl(val data: Int) : Base()
+ }
+
+ @Serializable
+ enum class MyEnum
+
+ @Test
+ fun testSealedSubclass() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(true) {
+ subclass(Base::class)
+ }
+ }
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(Base::class)
+ }
+ }
+ }
+
+ @Test
+ fun testPrimitive() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(Int::class)
+ }
+ }
+
+ // Doesn't fail
+ Json(true) {
+ subclass(Int::class)
+ }
+ }
+
+ @Test
+ fun testEnum() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(MyEnum::class)
+ }
+ }
+
+ Json(true) {
+ subclass(MyEnum::class)
+ }
+ }
+
+ @Test
+ fun testStructures() {
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(serializer<Map<Int, Int>>())
+ }
+ }
+
+ assertFailsWith<IllegalArgumentException> {
+ Json(false) {
+ subclass(serializer<List<Int>>())
+ }
+ }
+
+ Json(true) {
+ subclass(serializer<List<Int>>())
+ }
+
+
+ Json(true) {
+ subclass(serializer<Map<Int, Int>>())
+ }
+ }
+
+ private fun Json(useArrayPolymorphism: Boolean, builderAction: PolymorphicModuleBuilder<Any>.() -> Unit) = Json {
+ this.useArrayPolymorphism = useArrayPolymorphism
+ serializersModule = SerializersModule {
+ polymorphic(Any::class) {
+ builderAction()
+ }
+ }
+ }
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt
new file mode 100644
index 00000000..e2e10e24
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/JsonPropertyPolymorphicTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.PolymorphicSerializer
+import kotlinx.serialization.json.JsonTestBase
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class JsonPropertyPolymorphicTest : JsonTestBase() {
+
+ @Test
+ fun testPolymorphicProperties() = assertJsonFormAndRestored(
+ InnerBox.serializer(),
+ InnerBox(InnerImpl(42, "foo")),
+ """{"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}}""",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testFlatPolymorphic() = parametrizedTest { jsonTestingMode ->
+ val base: InnerBase = InnerImpl(42, "foo")
+ val string = polymorphicRelaxedJson.encodeToString(PolymorphicSerializer(InnerBase::class), base, jsonTestingMode)
+ assertEquals("""{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}""", string)
+ assertEquals(base, polymorphicRelaxedJson.decodeFromString(PolymorphicSerializer(InnerBase::class), string, jsonTestingMode))
+ }
+
+ @Test
+ fun testNestedPolymorphicProperties() = assertJsonFormAndRestored(
+ OuterBox.serializer(),
+ OuterBox(OuterImpl(InnerImpl(42), InnerImpl2(42)), InnerImpl2(239)),
+ """{"outerBase":{""" +
+ """"type":"kotlinx.serialization.json.polymorphic.OuterImpl",""" +
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":42,"str":"default","nullable":null},""" +
+ """"base2":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":42}},""" +
+ """"innerBase":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":239}}""",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testPolymorphicNullableProperties() = assertJsonFormAndRestored(
+ InnerNullableBox.serializer(),
+ InnerNullableBox(InnerImpl(42, "foo")),
+ """{"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl",""" +
+ """"field":42,"str":"foo","nullable":null}}""",
+ polymorphicRelaxedJson)
+
+ @Test
+ fun testPolymorphicNullablePropertiesWithNull() =
+ assertJsonFormAndRestored(InnerNullableBox.serializer(), InnerNullableBox(null), """{"base":null}""", polymorphicJson)
+
+ @Test
+ fun testNestedPolymorphicNullableProperties() = assertJsonFormAndRestored(
+ OuterNullableBox.serializer(),
+ OuterNullableBox(OuterNullableImpl(InnerImpl(42), null), InnerImpl2(239)),
+ """{"outerBase":{""" +
+ """"type":"kotlinx.serialization.json.polymorphic.OuterNullableImpl",""" +
+ """"base":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl","field":42,"str":"default","nullable":null},"base2":null},""" +
+ """"innerBase":{"type":"kotlinx.serialization.json.polymorphic.InnerImpl2","field":239}}""",
+ polymorphicRelaxedJson)
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt
new file mode 100644
index 00000000..e46de17a
--- /dev/null
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/polymorphic/PolymorphicClasses.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.serialization.json.polymorphic
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.modules.*
+import kotlin.native.concurrent.*
+
+@Serializable
+internal open class InnerBase
+
+internal interface OuterBase
+
+@Serializable
+internal data class InnerImpl(val field: Int, val str: String = "default", val nullable: Int? = null) : InnerBase()
+
+@Serializable
+internal data class InnerImpl2(val field: Int) : InnerBase()
+
+@Serializable
+internal data class InnerBox(@Polymorphic val base: InnerBase)
+
+@Serializable
+internal data class InnerNullableBox(@Polymorphic val base: InnerBase?)
+
+@Serializable
+internal data class OuterImpl(@Polymorphic val base: InnerBase, @Polymorphic val base2: InnerBase) : OuterBase
+
+@Serializable
+internal data class OuterNullableImpl(@Polymorphic val base: InnerBase?, @Polymorphic val base2: InnerBase?) : OuterBase
+
+@Serializable
+internal data class OuterBox(@Polymorphic val outerBase: OuterBase, @Polymorphic val innerBase: InnerBase)
+
+@Serializable
+internal data class OuterNullableBox(@Polymorphic val outerBase: OuterBase?, @Polymorphic val innerBase: InnerBase?)
+
+@SharedImmutable
+internal val polymorphicTestModule = SerializersModule {
+ polymorphic(InnerBase::class) {
+ subclass(InnerImpl.serializer())
+ subclass(InnerImpl2.serializer())
+ }
+
+ polymorphic(OuterBase::class) {
+ subclass(OuterImpl.serializer())
+ subclass(OuterNullableImpl.serializer())
+ }
+}
+
+@SharedImmutable
+internal val polymorphicJson = Json {
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+}
+
+@SharedImmutable
+internal val polymorphicRelaxedJson = Json {
+ isLenient = true
+ serializersModule = polymorphicTestModule
+ encodeDefaults = true
+}