diff --git a/src/StevesBot.Worker.Tests/Unit/DiscordEventConverterTests.cs b/src/StevesBot.Worker.Tests/Unit/DiscordEventConverterTests.cs index a64a528..05d34f4 100644 --- a/src/StevesBot.Worker.Tests/Unit/DiscordEventConverterTests.cs +++ b/src/StevesBot.Worker.Tests/Unit/DiscordEventConverterTests.cs @@ -4,6 +4,8 @@ public class DiscordEventConverterTests { private readonly JsonSerializerOptions _options = new() { + ReferenceHandler = ReferenceHandler.IgnoreCycles, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DiscordEventConverter() @@ -12,36 +14,31 @@ public class DiscordEventConverterTests private readonly Type _discordEventType = typeof(DiscordEvent); private readonly DiscordEventConverter _converter = new(); - [Fact] - public void Read_WhenCalledWithUnknownOpCode_ItShouldReturnDiscordEvent() + [Theory] + [MemberData(nameof(TestData))] + public void Read_WhenCalledWithOpCode_ItShouldReturnDiscordEvent(object data, Type expectedType) { - var data = new - { - op = 99, - s = null as int?, - t = null as string, - d = null as object - }; - var result = Read(data); - result.Should().BeOfType(); + result.Should().BeOfType(expectedType); } [Fact] - public void Read_WhenCalledWithDispatchOpCodeAndNoType_ItShouldReturnDispatchEvent() + public void Write_WhenCalledWithDiscordEvent_ItShouldReturnJson() { - var data = new + var discordEvent = new DiscordEvent { - op = DiscordOpCodes.Dispatch, - s = null as int?, - t = null as string, - d = null as object + OpCode = DiscordOpCodes.Dispatch, + Sequence = null, + Type = null, + Data = null }; - var result = Read(data); + var result = JsonSerializer.Serialize(discordEvent, _options); - result.Should().BeOfType(); + var expectedJson = /*lang=json,strict*/ "{\"op\":0,\"s\":null,\"t\":null,\"d\":null}"; + + result.Should().Be(expectedJson); } private DiscordEvent? Read(object data) @@ -51,4 +48,58 @@ public class DiscordEventConverterTests var reader = new Utf8JsonReader(utf8Json); return _converter.Read(ref reader, _discordEventType, _options); } + + public static TheoryData TestData => new() + { + { + new + { + op = DiscordOpCodes.Hello, + s = null as int?, + t = null as string, + d = null as object, + }, + typeof(HelloDiscordEvent) + }, + { + new + { + op = DiscordOpCodes.Dispatch, + s = null as int?, + t = null as string, + d = null as object + }, + typeof(DiscordEvent) + }, + { + new + { + op = DiscordOpCodes.Dispatch, + s = null as int?, + t = DiscordEventTypes.Ready, + d = null as object + }, + typeof(ReadyDiscordEvent) + }, + { + new + { + op = DiscordOpCodes.HeartbeatAck, + s = null as int?, + t = null as string, + d = null as object + }, + typeof(HeartbeatAckDiscordEvent) + }, + { + new + { + op = -1, + s = null as int?, + t = null as string, + d = null as object + }, + typeof(DiscordEvent) + } + }; } \ No newline at end of file diff --git a/src/StevesBot.Worker.Tests/Usings.cs b/src/StevesBot.Worker.Tests/Usings.cs index 7d617df..6bc9191 100644 --- a/src/StevesBot.Worker.Tests/Usings.cs +++ b/src/StevesBot.Worker.Tests/Usings.cs @@ -1,6 +1,7 @@ global using System.Net.WebSockets; global using System.Text; global using System.Text.Json; +global using System.Text.Json.Serialization; global using Microsoft.AspNetCore.Builder; global using Microsoft.AspNetCore.Hosting; diff --git a/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs b/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs index 2bb3592..29afce6 100644 --- a/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs +++ b/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs @@ -2,12 +2,6 @@ namespace StevesBot.Worker.Discord.Events; internal sealed class DiscordEventConverter : JsonConverter { - private readonly JsonSerializerOptions _jsonSerializerOptions = new() - { - ReferenceHandler = ReferenceHandler.IgnoreCycles, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }; - private const string OpPropertyName = "op"; public override DiscordEvent? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -15,29 +9,46 @@ internal sealed class DiscordEventConverter : JsonConverter using var jsonDoc = JsonDocument.ParseValue(ref reader); var root = jsonDoc.RootElement; var op = root.GetProperty(OpPropertyName).GetInt32(); + var modifiedOptions = CopyAndRemoveConverter(options); return op switch { - DiscordOpCodes.Dispatch => DeserializeDispatchEvent(root, options), + DiscordOpCodes.Dispatch => DeserializeDispatchEvent(root, options, modifiedOptions), DiscordOpCodes.Hello => JsonSerializer.Deserialize(root.GetRawText(), options), DiscordOpCodes.HeartbeatAck => JsonSerializer.Deserialize(root.GetRawText(), options), - _ => JsonSerializer.Deserialize(root.GetRawText(), _jsonSerializerOptions), + _ => JsonSerializer.Deserialize(root.GetRawText(), modifiedOptions), }; } public override void Write(Utf8JsonWriter writer, DiscordEvent value, JsonSerializerOptions options) { - JsonSerializer.Serialize(writer, value, value.GetType(), options); + var modifiedOptions = CopyAndRemoveConverter(options); + JsonSerializer.Serialize(writer, value, value.GetType(), modifiedOptions); } - private DiscordEvent? DeserializeDispatchEvent(JsonElement root, JsonSerializerOptions options) + private static DiscordEvent? DeserializeDispatchEvent(JsonElement root, JsonSerializerOptions options, JsonSerializerOptions modifiedOptions) { var type = root.GetProperty("t").GetString(); return type switch { DiscordEventTypes.Ready => JsonSerializer.Deserialize(root.GetRawText(), options), - _ => JsonSerializer.Deserialize(root.GetRawText(), _jsonSerializerOptions), + _ => JsonSerializer.Deserialize(root.GetRawText(), modifiedOptions), }; } + + private static JsonSerializerOptions CopyAndRemoveConverter(JsonSerializerOptions options) + { + var newOptions = new JsonSerializerOptions(options); + + foreach (var converter in options.Converters) + { + if (converter is DiscordEventConverter) + { + newOptions.Converters.Remove(converter); + } + } + + return newOptions; + } } \ No newline at end of file