fix(commons): resolve Commons-008 — replace ValueTuple in SetConnectionBindingsCommand with named ConnectionBinding record (CLI, ManagementService, TemplateEngine, CentralUI)

This commit is contained in:
Joseph Doherty
2026-05-16 23:54:31 -04:00
parent c583598888
commit b1f4251d75
8 changed files with 97 additions and 23 deletions

View File

@@ -1,4 +1,5 @@
using ScadaLink.CLI.Commands;
using ScadaLink.Commons.Messages.Management;
namespace ScadaLink.CLI.Tests;
@@ -17,8 +18,8 @@ public class InstanceArgumentParsingTests
Assert.True(ok);
Assert.Null(error);
Assert.Equal(2, bindings!.Count);
Assert.Equal(("Speed", 5), bindings[0]);
Assert.Equal(("Mode", 7), bindings[1]);
Assert.Equal(new ConnectionBinding("Speed", 5), bindings[0]);
Assert.Equal(new ConnectionBinding("Mode", 7), bindings[1]);
}
[Fact]

View File

@@ -0,0 +1,54 @@
using System.Text.Json;
using ScadaLink.Commons.Messages.Management;
namespace ScadaLink.Commons.Tests.Messages;
/// <summary>
/// Regression tests for Commons-008 — <see cref="SetConnectionBindingsCommand"/>
/// previously declared its bindings as <c>IReadOnlyList&lt;(string, int)&gt;</c>.
/// A <c>ValueTuple</c> serializes as <c>Item1</c>/<c>Item2</c> and cannot evolve
/// additively (REQ-COM-5a). It is now a named <see cref="ConnectionBinding"/> record.
/// </summary>
public class ConnectionBindingSerializationTests
{
[Fact]
public void ConnectionBinding_SerializesWithNamedProperties()
{
var json = JsonSerializer.Serialize(new ConnectionBinding("Temperature", 42));
using var doc = JsonDocument.Parse(json);
Assert.Equal(JsonValueKind.String, doc.RootElement.GetProperty("AttributeName").ValueKind);
Assert.Equal("Temperature", doc.RootElement.GetProperty("AttributeName").GetString());
Assert.Equal(42, doc.RootElement.GetProperty("DataConnectionId").GetInt32());
// The ValueTuple failure mode: Item1/Item2 must NOT appear.
Assert.False(doc.RootElement.TryGetProperty("Item1", out _));
Assert.False(doc.RootElement.TryGetProperty("Item2", out _));
}
[Fact]
public void SetConnectionBindingsCommand_RoundTripsThroughJson()
{
var original = new SetConnectionBindingsCommand(
7,
new List<ConnectionBinding>
{
new("Speed", 5),
new("Mode", 11),
});
var json = JsonSerializer.Serialize(original);
var deserialized = JsonSerializer.Deserialize<SetConnectionBindingsCommand>(json);
Assert.NotNull(deserialized);
Assert.Equal(7, deserialized!.InstanceId);
Assert.Equal(2, deserialized.Bindings.Count);
Assert.Equal("Speed", deserialized.Bindings[0].AttributeName);
Assert.Equal(5, deserialized.Bindings[0].DataConnectionId);
Assert.Equal("Mode", deserialized.Bindings[1].AttributeName);
Assert.Equal(11, deserialized.Bindings[1].DataConnectionId);
// ConnectionBinding is a record: each element compares by value.
Assert.Equal(original.Bindings, deserialized.Bindings);
}
}

View File

@@ -3,6 +3,7 @@ using ScadaLink.Commons.Entities.Instances;
using ScadaLink.Commons.Entities.Templates;
using ScadaLink.Commons.Interfaces.Repositories;
using ScadaLink.Commons.Interfaces.Services;
using ScadaLink.Commons.Messages.Management;
using ScadaLink.Commons.Types.Enums;
using ScadaLink.TemplateEngine.Services;
@@ -260,7 +261,7 @@ public class InstanceServiceTests
_repoMock.Setup(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(1);
var bindings = new List<(string, int)> { ("Temp", 100), ("Pressure", 200) };
var bindings = new List<ConnectionBinding> { new("Temp", 100), new("Pressure", 200) };
var result = await _sut.SetConnectionBindingsAsync(1, bindings, "admin");
Assert.True(result.IsSuccess);