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