Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The changelog for `Superwall`. Also see the [releases](https://github.com/superw
## Unreleased

- Fix prices not showing when product/offers are fetched from cache
- Fix a JSON null in placement parameters or user attributes reaching audience filters as the text `"null"`, so a filter checking whether a field is null never matched.

## 2.8.2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.boolean
Expand Down Expand Up @@ -246,6 +247,11 @@ internal fun Any.toPassableValue(): PassableValue =

private fun JsonElement.toPassableValue(): PassableValue =
when (this) {
// Checked before JsonPrimitive, which JsonNull is a kind of. Without this a
// JSON null falls past every primitive branch and comes out as the string
// "null", so an audience filter comparing the field to null never matches.
is JsonNull -> PassableValue.NullValue

is JsonObject ->
PassableValue.MapValue(
this.mapValues { (_, value) -> value.toPassableValue() }.toMap(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ class JsonElementToPassableValueTest {
assertEquals(false, (passableFalseValue as PassableValue.BoolValue).value)
}

@Test
fun `test JsonNull conversion to PassableValue`() {
// JsonNull is a JsonPrimitive, so without an explicit branch it falls past
// every primitive check and comes out as the string "null". An audience
// filter asking `field == null` would then never match.
assertTrue(JsonNull.toPassableValue() is PassableValue.NullValue)
}

@Test
fun `test JsonObject conversion to PassableValue`() {
val jsonObject =
Expand Down Expand Up @@ -94,8 +102,7 @@ class JsonElementToPassableValueTest {
assertTrue(resultMap["boolean"] is PassableValue.BoolValue)
assertEquals(true, (resultMap["boolean"] as PassableValue.BoolValue).value)

assertTrue(resultMap["null"] is PassableValue.StringValue)
assertEquals("null", (resultMap["null"] as PassableValue.StringValue).value)
assertTrue(resultMap["null"] is PassableValue.NullValue)
}

@Test
Expand Down Expand Up @@ -128,8 +135,7 @@ class JsonElementToPassableValueTest {
assertTrue(resultList[3] is PassableValue.BoolValue)
assertEquals(true, (resultList[3] as PassableValue.BoolValue).value)

assertTrue(resultList[4] is PassableValue.StringValue)
assertEquals("null", (resultList[4] as PassableValue.StringValue).value)
assertTrue(resultList[4] is PassableValue.NullValue)
}

@Test
Expand Down