1 /* <lambda>null2 * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.serialization.json 6 7 import kotlinx.serialization.* 8 import kotlinx.serialization.json.internal.* 9 import kotlinx.serialization.json.okio.decodeFromBufferedSource 10 import kotlinx.serialization.json.okio.encodeToBufferedSink 11 import kotlinx.serialization.modules.EmptySerializersModule 12 import kotlinx.serialization.modules.SerializersModule 13 import kotlinx.serialization.test.* 14 import kotlin.test.assertEquals 15 import okio.* 16 import kotlin.test.assertTrue 17 18 19 enum class JsonTestingMode { 20 STREAMING, 21 TREE, 22 OKIO_STREAMS, 23 JAVA_STREAMS; 24 25 companion object { 26 fun value(i: Int) = values()[i] 27 } 28 } 29 30 abstract class JsonTestBase { <lambda>null31 protected val default = Json { encodeDefaults = true } <lambda>null32 protected val lenient = Json { isLenient = true; ignoreUnknownKeys = true; allowSpecialFloatingPointValues = true } 33 encodeToStringnull34 internal inline fun <reified T : Any> Json.encodeToString(value: T, jsonTestingMode: JsonTestingMode): String { 35 val serializer = serializersModule.serializer<T>() 36 return encodeToString(serializer, value, jsonTestingMode) 37 } 38 encodeToStringnull39 internal fun <T> Json.encodeToString( 40 serializer: SerializationStrategy<T>, 41 value: T, 42 jsonTestingMode: JsonTestingMode 43 ): String = 44 when (jsonTestingMode) { 45 JsonTestingMode.STREAMING -> { 46 encodeToString(serializer, value) 47 } 48 JsonTestingMode.JAVA_STREAMS -> { 49 encodeViaStream(serializer, value) 50 } 51 JsonTestingMode.TREE -> { 52 val tree = writeJson(this, value, serializer) 53 encodeToString(tree) 54 } 55 JsonTestingMode.OKIO_STREAMS -> { 56 val buffer = Buffer() 57 encodeToBufferedSink(serializer, value, buffer) 58 buffer.readUtf8() 59 } 60 } 61 decodeFromStringnull62 internal inline fun <reified T : Any> Json.decodeFromString(source: String, jsonTestingMode: JsonTestingMode): T { 63 val deserializer = serializersModule.serializer<T>() 64 return decodeFromString(deserializer, source, jsonTestingMode) 65 } 66 decodeFromStringnull67 internal fun <T> Json.decodeFromString( 68 deserializer: DeserializationStrategy<T>, 69 source: String, 70 jsonTestingMode: JsonTestingMode 71 ): T = 72 when (jsonTestingMode) { 73 JsonTestingMode.STREAMING -> { 74 decodeFromString(deserializer, source) 75 } 76 JsonTestingMode.JAVA_STREAMS -> { 77 decodeViaStream(deserializer, source) 78 } 79 JsonTestingMode.TREE -> { 80 val tree = decodeStringToJsonTree(this, deserializer, source) 81 readJson(this, tree, deserializer) 82 } 83 JsonTestingMode.OKIO_STREAMS -> { 84 val buffer = Buffer() 85 buffer.writeUtf8(source) 86 decodeFromBufferedSource(deserializer, buffer) 87 } 88 } 89 parametrizedTestnull90 protected open fun parametrizedTest(test: (JsonTestingMode) -> Unit) { 91 processResults(buildList { 92 add(runCatching { test(JsonTestingMode.STREAMING) }) 93 add(runCatching { test(JsonTestingMode.TREE) }) 94 add(runCatching { test(JsonTestingMode.OKIO_STREAMS) }) 95 96 if (isJvm()) { 97 add(runCatching { test(JsonTestingMode.JAVA_STREAMS) }) 98 } 99 }) 100 } 101 102 private inner class SwitchableJson( 103 val json: Json, 104 val jsonTestingMode: JsonTestingMode, 105 override val serializersModule: SerializersModule = EmptySerializersModule() 106 ) : StringFormat { encodeToStringnull107 override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String { 108 return json.encodeToString(serializer, value, jsonTestingMode) 109 } 110 decodeFromStringnull111 override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T { 112 return json.decodeFromString(deserializer, string, jsonTestingMode) 113 } 114 } 115 parametrizedTestnull116 protected fun parametrizedTest(json: Json, test: StringFormat.() -> Unit) { 117 val streamingResult = runCatching { SwitchableJson(json, JsonTestingMode.STREAMING).test() } 118 val treeResult = runCatching { SwitchableJson(json, JsonTestingMode.TREE).test() } 119 val okioResult = runCatching { SwitchableJson(json, JsonTestingMode.OKIO_STREAMS).test() } 120 processResults(listOf(streamingResult, treeResult, okioResult)) 121 } 122 processResultsnull123 protected fun processResults(results: List<Result<*>>) { 124 results.forEachIndexed { i, result -> 125 result.onFailure { 126 println("Failed test for ${JsonTestingMode.value(i)}") 127 throw it 128 } 129 } 130 for (i in results.indices) { 131 for (j in results.indices) { 132 if (i == j) continue 133 assertEquals( 134 results[i].getOrNull()!!, 135 results[j].getOrNull()!!, 136 "Results differ for ${JsonTestingMode.value(i)} and ${JsonTestingMode.value(j)}" 137 ) 138 } 139 } 140 } 141 142 /** 143 * Same as [assertStringFormAndRestored], but tests both json converters (streaming and tree) 144 * via [parametrizedTest] 145 */ assertJsonFormAndRestorednull146 internal fun <T> assertJsonFormAndRestored( 147 serializer: KSerializer<T>, 148 data: T, 149 expected: String, 150 json: Json = default 151 ) { 152 parametrizedTest { jsonTestingMode -> 153 val serialized = json.encodeToString(serializer, data, jsonTestingMode) 154 assertEquals(expected, serialized, "Failed with streaming = $jsonTestingMode") 155 val deserialized: T = json.decodeFromString(serializer, serialized, jsonTestingMode) 156 assertEquals(data, deserialized, "Failed with streaming = $jsonTestingMode") 157 } 158 } 159 /** 160 * Same as [assertStringFormAndRestored], but tests both json converters (streaming and tree) 161 * via [parametrizedTest]. Use custom checker for deserialized value. 162 */ assertJsonFormAndRestoredCustomnull163 internal fun <T> assertJsonFormAndRestoredCustom( 164 serializer: KSerializer<T>, 165 data: T, 166 expected: String, 167 check: (T, T) -> Boolean 168 ) { 169 parametrizedTest { jsonTestingMode -> 170 val serialized = Json.encodeToString(serializer, data, jsonTestingMode) 171 assertEquals(expected, serialized, "Failed with streaming = $jsonTestingMode") 172 val deserialized: T = Json.decodeFromString(serializer, serialized, jsonTestingMode) 173 assertTrue("Failed with streaming = $jsonTestingMode\n\tsource value =$data\n\tdeserialized value=$deserialized") { check(data, deserialized) } 174 } 175 } 176 } 177