1 /* 2 * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") 6 7 package kotlinx.serialization.features 8 9 import kotlinx.serialization.* 10 import kotlinx.serialization.builtins.serializer 11 import kotlinx.serialization.json.* 12 import kotlinx.serialization.json.internal.BATCH_SIZE 13 import kotlinx.serialization.modules.* 14 import kotlinx.serialization.test.* 15 import org.junit.Test 16 import java.io.ByteArrayInputStream 17 import java.io.ByteArrayOutputStream 18 import kotlin.test.assertEquals 19 import kotlin.test.assertFailsWith 20 21 class JsonJvmStreamsTest { 22 private val strLen = BATCH_SIZE * 2 + 42 23 24 @Test testParsesStringsLongerThanBuffernull25 fun testParsesStringsLongerThanBuffer() { 26 val str = "a".repeat(strLen) 27 val input = """{"data":"$str"}""" 28 assertEquals(input, Json.encodeViaStream(StringData.serializer(), StringData(str))) 29 assertEquals(str, Json.decodeViaStream(StringData.serializer(), input).data) 30 assertEquals(str, Json.decodeViaStream(String.serializer(), "\"$str\"")) 31 } 32 33 @Test testSkipsWhitespacesLongerThanBuffernull34 fun testSkipsWhitespacesLongerThanBuffer() { 35 val str = "a".repeat(strLen) 36 val ws = " ".repeat(strLen) 37 val input = """{"data":$ws"$str"}""" 38 assertEquals("""{"data":"$str"}""", Json.encodeViaStream(StringData.serializer(), StringData(str))) 39 assertEquals(str, Json.decodeViaStream(StringData.serializer(), input).data) 40 } 41 42 @Test testHandlesEscapesLongerThanBuffernull43 fun testHandlesEscapesLongerThanBuffer() { 44 val str = "\\t".repeat(strLen) 45 val expected = "\t".repeat(strLen) 46 val input = """{"data":"$str"}""" 47 assertEquals(input, Json.encodeViaStream(StringData.serializer(), StringData(expected))) 48 assertEquals(expected, Json.decodeViaStream(StringData.serializer(), input).data) 49 } 50 51 @Test testHandlesLongLenientStringsnull52 fun testHandlesLongLenientStrings() { 53 val str = "a".repeat(strLen) 54 val input = """{"data":$str}""" 55 val json = Json { isLenient = true } 56 assertEquals(str, json.decodeViaStream(StringData.serializer(), input).data) 57 assertEquals(str, json.decodeViaStream(String.serializer(), str)) 58 } 59 60 @Test testThrowsCorrectExceptionOnEofnull61 fun testThrowsCorrectExceptionOnEof() { 62 assertFailsWith<SerializationException> { 63 Json.decodeViaStream(StringData.serializer(), """{"data":""") 64 } 65 assertFailsWith<SerializationException> { 66 Json.decodeViaStream(StringData.serializer(), "") 67 } 68 assertFailsWith<SerializationException> { 69 Json.decodeViaStream(String.serializer(), "\"") 70 } 71 } 72 73 @Test testRandomEscapeSequencesnull74 fun testRandomEscapeSequences() { 75 repeat(1000) { 76 val s = generateRandomUnicodeString(strLen) 77 try { 78 val serializer = String.serializer() 79 val b = ByteArrayOutputStream() 80 Json.encodeToStream(serializer, s, b) 81 val restored = Json.decodeFromStream(serializer, ByteArrayInputStream(b.toByteArray())) 82 assertEquals(s, restored) 83 } catch (e: Throwable) { 84 // Not assertion error to preserve cause 85 throw IllegalStateException("Unexpectedly failed test, cause string: $s", e) 86 } 87 } 88 } 89 90 interface Poly 91 92 @Serializable 93 @SerialName("Impl") 94 data class Impl(val str: String) : Poly 95 96 @Test testPolymorphismWhenCrossingBatchSizeNonLeadingKeynull97 fun testPolymorphismWhenCrossingBatchSizeNonLeadingKey() { 98 val json = Json { 99 serializersModule = SerializersModule { 100 polymorphic(Poly::class) { 101 subclass(Impl::class, Impl.serializer()) 102 } 103 } 104 } 105 106 val longString = "a".repeat(BATCH_SIZE - 5) 107 val string = """{"str":"$longString", "type":"Impl"}""" 108 val golden = Impl(longString) 109 110 val deserialized = json.decodeViaStream(serializer<Poly>(), string) 111 assertEquals(golden, deserialized as Impl) 112 } 113 114 @Test testPolymorphismWhenCrossingBatchSizenull115 fun testPolymorphismWhenCrossingBatchSize() { 116 val json = Json { 117 serializersModule = SerializersModule { 118 polymorphic(Poly::class) { 119 subclass(Impl::class, Impl.serializer()) 120 } 121 } 122 } 123 124 val aLotOfWhiteSpaces = " ".repeat(BATCH_SIZE - 5) 125 val string = """{$aLotOfWhiteSpaces"type":"Impl", "str":"value"}""" 126 val golden = Impl("value") 127 128 val deserialized = json.decodeViaStream(serializer<Poly>(), string) 129 assertEquals(golden, deserialized as Impl) 130 } 131 } 132