Skip to content

Commit

Permalink
[CustomerCenter] Fix help path deserializing when unknown type (#1869)
Browse files Browse the repository at this point in the history
### Description
While testing one thing I noticed we were not handling unknown help path
types. This basically caused the whole screen to not be deserialized,
since we catch deserialization issues at that level, but we can do
better than that and just not deserialize the unknown path type.
  • Loading branch information
tonidero authored Oct 4, 2024
1 parent 9e421bc commit 37b0b83
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ data class CustomerCenterConfigData(
val type: ScreenType,
val title: String,
@Serializable(with = EmptyStringToNullSerializer::class) val subtitle: String? = null,
val paths: List<HelpPath>,
@Serializable(with = HelpPathsSerializer::class) val paths: List<HelpPath>,
) {
@Serializable
enum class ScreenType {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.revenuecat.purchases.customercenter

import com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI
import com.revenuecat.purchases.common.debugLog
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.jsonArray

@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
internal object HelpPathsSerializer : KSerializer<List<CustomerCenterConfigData.HelpPath>> {
override val descriptor: SerialDescriptor = ListSerializer(
CustomerCenterConfigData.HelpPath.serializer(),
).descriptor

override fun deserialize(decoder: Decoder): List<CustomerCenterConfigData.HelpPath> {
val list = mutableListOf<CustomerCenterConfigData.HelpPath>()
val jsonInput = decoder as? JsonDecoder ?: error("Can be deserialized only by JSON")
val jsonArray = jsonInput.decodeJsonElement().jsonArray

jsonArray.forEach { jsonElement ->
try {
list.add(
jsonInput.json.decodeFromJsonElement(CustomerCenterConfigData.HelpPath.serializer(), jsonElement),
)
} catch (e: IllegalArgumentException) {
debugLog("Issue deserializing CustomerCenter HelpPath. Ignoring. Error: $e")
}
}

return list
}

override fun serialize(encoder: Encoder, value: List<CustomerCenterConfigData.HelpPath>) {
ListSerializer(CustomerCenterConfigData.HelpPath.serializer()).serialize(encoder, value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI
import com.revenuecat.purchases.common.Backend
import org.assertj.core.api.Assertions.assertThat
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
Expand Down Expand Up @@ -144,10 +145,33 @@ class CustomerCenterConfigDataTest {
assertThat(support.email).isEqualTo("support@example.com")
}

private fun createSampleConfigData(): CustomerCenterConfigData {
@Test
fun `can parse json with unknown screen types`() {
val json = JSONObject(loadTestJSON())
val screens = json.getJSONObject("customer_center").getJSONObject("screens")
screens.put("random_screen_id", screens.getJSONObject("MANAGEMENT"))
val configData = createSampleConfigData(json.toString())
assertThat(configData.screens).hasSize(2)
}

@Test
fun `can parse json with unknown path types`() {
val json = JSONObject(loadTestJSON())
val managementScreenPaths = json
.getJSONObject("customer_center")
.getJSONObject("screens")
.getJSONObject("MANAGEMENT")
.getJSONArray("paths")
val firstPathClone = JSONObject(managementScreenPaths.getJSONObject(0).toString())
managementScreenPaths.put(firstPathClone.put("type", "UNKNOWN_PATH_TYPE"))
val configData = createSampleConfigData(json.toString())
assertThat(configData.screens[CustomerCenterConfigData.Screen.ScreenType.MANAGEMENT]!!.paths).hasSize(4)
}

private fun createSampleConfigData(json: String = loadTestJSON()): CustomerCenterConfigData {
return Backend.json.decodeFromString(
CustomerCenterRoot.serializer(),
loadTestJSON()
json,
).customerCenter
}

Expand Down

0 comments on commit 37b0b83

Please sign in to comment.