Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Registry update fails when Device Model property is an array #1160

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,26 @@ namespace NetDaemon.HassClient.Tests.Json;

public class EnsureStringConverterTests
{
/// <summary>
/// Default Json serialization options, Hass expects intended
/// </summary>
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<HassDevice>(jsonDevice, _defaultSerializerOptions);
var hassDevice = JsonSerializer.Deserialize<HassDevice>("""
{
"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();
Expand All @@ -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<HassDevice>(jsonDevice, _defaultSerializerOptions);
var hassDevice = JsonSerializer.Deserialize<HassDevice>("""
{
"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<HassDevice>("""
{
"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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
using System.Diagnostics;

namespace NetDaemon.Client.Internal.Json;

/// <summary>
/// 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
/// </summary>
class EnsureStringConverter : JsonConverter<string?>
{
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);

Check warning on line 25 in src/Client/NetDaemon.HassClient/Internal/Json/EnsureStringConverter.cs

View check run for this annotation

Codecov / codecov/patch

src/Client/NetDaemon.HassClient/Internal/Json/EnsureStringConverter.cs#L25

Added line #L25 was not covered by tests
}

This file was deleted.

Loading