From e5584558b7d3b97f4e9b8066d5a1cdefbd48e22a Mon Sep 17 00:00:00 2001 From: Bart Arys Date: Mon, 14 Jun 2021 22:04:31 +0200 Subject: [PATCH] Make serialization of Snowflake consistent (#316) Snowflakes are decoded as Longs but encoded as Strings. Mixing these types is allowed in JSON (and is done by Discord quite frequently) but does lead to other encoding types failing. This commit changes snowflakes to be encoded and decoded as long values exclusively, and should fix the issue. --- common/src/main/kotlin/entity/Snowflake.kt | 4 +- gateway/src/test/kotlin/json/CommandTest.kt | 6 +-- gateway/src/test/kotlin/json/SnowflakeTest.kt | 50 +++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 gateway/src/test/kotlin/json/SnowflakeTest.kt diff --git a/common/src/main/kotlin/entity/Snowflake.kt b/common/src/main/kotlin/entity/Snowflake.kt index 187d6e20308..3593540b095 100644 --- a/common/src/main/kotlin/entity/Snowflake.kt +++ b/common/src/main/kotlin/entity/Snowflake.kt @@ -71,7 +71,7 @@ class Snowflake(val value: Long) : Comparable { override fun deserialize(decoder: Decoder): Snowflake = Snowflake(decoder.decodeLong()) override fun serialize(encoder: Encoder, value: Snowflake) { - encoder.encodeString(value.value.toString()) + encoder.encodeLong(value.value) } } } @@ -79,4 +79,4 @@ class Snowflake(val value: Long) : Comparable { private class SnowflakeMark(val epochMilliseconds: Long) : TimeMark() { override fun elapsedNow(): Duration = Instant.fromEpochMilliseconds(epochMilliseconds) - Clock.System.now() -} \ No newline at end of file +} diff --git a/gateway/src/test/kotlin/json/CommandTest.kt b/gateway/src/test/kotlin/json/CommandTest.kt index 45562e2233b..5a9c38702b0 100644 --- a/gateway/src/test/kotlin/json/CommandTest.kt +++ b/gateway/src/test/kotlin/json/CommandTest.kt @@ -70,7 +70,7 @@ class CommandTest { val json = json.encodeToString(JsonObject.serializer(), buildJsonObject { put("op", OpCode.RequestGuildMembers.code) put("d", buildJsonObject { - put("guild_id", guildId) + put("guild_id", guildId.toLong()) put("query", query) put("limit", limit) }) @@ -95,8 +95,8 @@ class CommandTest { val json = json.encodeToString(JsonObject.serializer(), buildJsonObject { put("op", OpCode.VoiceStateUpdate.code) put("d", buildJsonObject { - put("guild_id", guildId) - put("channel_id", channelId) + put("guild_id", guildId.toLong()) + put("channel_id", channelId.toLong()) put("self_mute", selfMute) put("self_deaf", selfDeaf) }) diff --git a/gateway/src/test/kotlin/json/SnowflakeTest.kt b/gateway/src/test/kotlin/json/SnowflakeTest.kt new file mode 100644 index 00000000000..d2b07551bcd --- /dev/null +++ b/gateway/src/test/kotlin/json/SnowflakeTest.kt @@ -0,0 +1,50 @@ +package json + +import dev.kord.common.entity.Snowflake +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.decodeFromJsonElement +import kotlinx.serialization.json.put +import kotlin.test.Test +import kotlin.test.assertEquals + +class SnowflakeTest { + + @Serializable + private data class SnowflakeContainer(val snowflake: Snowflake) + + @Test + fun `Deserialization of Snowflake as String completes successfully`() { + val value = "1337" + val json = buildJsonObject { + put("snowflake", value) + } + + val container = Json.decodeFromJsonElement(json) + assertEquals(value, container.snowflake.asString) + } + + @Test + fun `Deserialization of Snowflake as Long completes successfully`() { + val value = 1337L + val json = buildJsonObject { + put("snowflake", value) + } + + val container = Json.decodeFromJsonElement(json) + assertEquals(value, container.snowflake.value) + } + + @Test + fun `Reserialization of Snowflake completes successfully`() { + val json = buildJsonObject { put("snowflake", 1337L) } + + val container = Json.decodeFromJsonElement(json) + val reDecodedContainer = Json.decodeFromString(Json.encodeToString(container)) + assertEquals(container, reDecodedContainer) + } + +}