From 2abec7b498e92f26b997812e95b9ee9da0ccbe2b Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Sat, 24 Aug 2024 14:12:35 +0200 Subject: [PATCH] Fix: Registry update fails when Device Model property is an array --- .../Json/EnsureStringConverterTests.cs | 102 ++++++++++-------- .../Common/HomeAssistant/Model/HassDevice.cs | 5 +- .../Internal/Json/EnsureStringConverter.cs | 23 ++-- .../Json/ReadNumberAsStringConverter.cs | 25 ----- 4 files changed, 73 insertions(+), 82 deletions(-) delete mode 100644 src/Client/NetDaemon.HassClient/Internal/Json/ReadNumberAsStringConverter.cs diff --git a/src/Client/NetDaemon.HassClient.Tests/Json/EnsureStringConverterTests.cs b/src/Client/NetDaemon.HassClient.Tests/Json/EnsureStringConverterTests.cs index 18434d2b5..4e72fd44e 100644 --- a/src/Client/NetDaemon.HassClient.Tests/Json/EnsureStringConverterTests.cs +++ b/src/Client/NetDaemon.HassClient.Tests/Json/EnsureStringConverterTests.cs @@ -3,35 +3,26 @@ namespace NetDaemon.HassClient.Tests.Json; public class EnsureStringConverterTests { - /// - /// Default Json serialization options, Hass expects intended - /// - private readonly JsonSerializerOptions _defaultSerializerOptions = new() - { - WriteIndented = false, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }; - [Fact] public void TestConvertAValidString() { - const string jsonDevice = @" - { - ""config_entries"": [], - ""connections"": [], - ""manufacturer"": ""Google Inc."", - ""model"": 123123, - ""name"": 123, - ""serial_number"": ""1.0"", - ""sw_version"": ""100"", - ""hw_version"": null, - ""id"": ""42cdda32a2a3428e86c2e27699d79ead"", - ""via_device_id"": null, - ""area_id"": null, - ""name_by_user"": null - } - "; - var hassDevice = JsonSerializer.Deserialize(jsonDevice, _defaultSerializerOptions); + var hassDevice = JsonSerializer.Deserialize(""" + { + "config_entries": [], + "connections": [], + "manufacturer": "Google Inc.", + "model": 123123, + "name": 123, + "serial_number": "1.0", + "sw_version": "100", + "hw_version": null, + "id": "42cdda32a2a3428e86c2e27699d79ead", + "via_device_id": null, + "area_id": null, + "name_by_user": null + } + """); + hassDevice!.SerialNumber.Should().Be("1.0"); hassDevice!.SoftwareVersion.Should().Be("100"); hassDevice!.HardwareVersion.Should().BeNull(); @@ -40,30 +31,53 @@ public void TestConvertAValidString() [Fact] public void TestConverAInvalidString() { - const string jsonDevice = @" - { - ""config_entries"": [], - ""connections"": [], - ""model"": ""Chromecast"", - ""serial_number"": [""1.0"", ""2.0""], - ""name"": ""My TV"", - ""sw_version"": { ""attribute"": ""1.0"" }, - ""manufacturer"": ""Google Inc."", - ""hw_version"": 100, - ""id"": ""42cdda32a2a3428e86c2e27699d79ead"", - ""via_device_id"": null, - ""area_id"": null, - ""name_by_user"": null - } - "; - var hassDevice = JsonSerializer.Deserialize(jsonDevice, _defaultSerializerOptions); + var hassDevice = JsonSerializer.Deserialize(""" + { + "config_entries": [], + "connections": [], + "model": "Chromecast", + "serial_number": ["1.0", "2.0"], + "name": "My TV", + "sw_version": { "attribute": "1.0" }, + "manufacturer": "Google Inc.", + "hw_version": 100, + "id": "42cdda32a2a3428e86c2e27699d79ead", + "via_device_id": null, + "area_id": null, + "name_by_user": null + } + """); + hassDevice!.SerialNumber.Should().BeNull(); hassDevice!.SoftwareVersion.Should().BeNull(); - hassDevice!.HardwareVersion.Should().BeNull(); + hassDevice!.HardwareVersion.Should().Be("100"); // Make sure it is skipped correctly by checking the next property is read hassDevice!.Manufacturer.Should().Be("Google Inc."); hassDevice!.Id.Should().Be("42cdda32a2a3428e86c2e27699d79ead"); hassDevice!.Name.Should().Be("My TV"); } + + [Fact] + public void TestConverModelIsArrayInvalidString() + { + var hassDevice = JsonSerializer.Deserialize(""" + { + "config_entries": [], + "connections": [], + "model": ["Chromecast"], + "serial_number": ["1.0", "2.0"], + "name": "My TV", + "sw_version": { "attribute": "1.0" }, + "manufacturer": "Google Inc.", + "hw_version": 100, + "id": "42cdda32a2a3428e86c2e27699d79ead", + "via_device_id": null, + "area_id": null, + "name_by_user": null + } + """); + + hassDevice!.Model.Should().BeNull(); + } } diff --git a/src/Client/NetDaemon.HassClient/Common/HomeAssistant/Model/HassDevice.cs b/src/Client/NetDaemon.HassClient/Common/HomeAssistant/Model/HassDevice.cs index d7a7241dc..2869b8f08 100644 --- a/src/Client/NetDaemon.HassClient/Common/HomeAssistant/Model/HassDevice.cs +++ b/src/Client/NetDaemon.HassClient/Common/HomeAssistant/Model/HassDevice.cs @@ -5,14 +5,13 @@ public record HassDevice [JsonPropertyName("manufacturer")] public string? Manufacturer { get; init; } [JsonPropertyName("model")] - [JsonConverter(typeof(ReadNumberAsStringConverter))] + [JsonConverter(typeof(EnsureStringConverter))] public string? Model { get; init; } [JsonPropertyName("id")] public string? Id { get; init; } [JsonPropertyName("area_id")] public string? AreaId { get; init; } - - [JsonConverter(typeof(ReadNumberAsStringConverter))] + [JsonConverter(typeof(EnsureStringConverter))] [JsonPropertyName("name")] public string? Name { get; init; } [JsonPropertyName("name_by_user")] public string? NameByUser { get; init; } diff --git a/src/Client/NetDaemon.HassClient/Internal/Json/EnsureStringConverter.cs b/src/Client/NetDaemon.HassClient/Internal/Json/EnsureStringConverter.cs index 1e09bd253..470c25db4 100644 --- a/src/Client/NetDaemon.HassClient/Internal/Json/EnsureStringConverter.cs +++ b/src/Client/NetDaemon.HassClient/Internal/Json/EnsureStringConverter.cs @@ -1,23 +1,26 @@ -using System.Diagnostics; - namespace NetDaemon.Client.Internal.Json; /// -/// Converts a Json element that can be a string or returns null if it is not a string +/// Converts a Json element that can be a string or a number to as string, and returns null if not /// class EnsureStringConverter : JsonConverter { public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.String) + switch (reader.TokenType) { - return reader.GetString() ?? throw new UnreachableException("Token is expected to be a string"); - } + case JsonTokenType.String: + return reader.GetString(); - // Skip the children of current token - reader.Skip(); - return null; + case JsonTokenType.Number: + var stringValue = reader.GetInt32(); + return stringValue.ToString(CultureInfo.InvariantCulture); + + default: + reader.Skip(); + return null; + } } - public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options) => throw new NotSupportedException(); + public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options) => writer.WriteStringValue(value); } diff --git a/src/Client/NetDaemon.HassClient/Internal/Json/ReadNumberAsStringConverter.cs b/src/Client/NetDaemon.HassClient/Internal/Json/ReadNumberAsStringConverter.cs deleted file mode 100644 index faa5db566..000000000 --- a/src/Client/NetDaemon.HassClient/Internal/Json/ReadNumberAsStringConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace NetDaemon.Client.Internal.Json; - -internal class ReadNumberAsStringConverter : JsonConverter -{ - public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - switch (reader.TokenType) - { - case JsonTokenType.Number: - { - var stringValue = reader.GetInt32(); - return stringValue.ToString(CultureInfo.InvariantCulture); - } - case JsonTokenType.String: - return reader.GetString(); - default: - throw new JsonException(); - } - } - - public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) - { - writer.WriteStringValue(value); - } -} \ No newline at end of file