feat(cli): --element-type and JSON --value for List attributes
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
using System.CommandLine;
|
||||
using ZB.MOM.WW.ScadaBridge.CLI.Commands;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.CLI.Tests.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// MV-11: the <c>template attribute add</c> / <c>update</c> commands must support
|
||||
/// structured multi-value (List) attributes — a new <c>--element-type</c> option,
|
||||
/// a JSON-array <c>--value</c>, client-side element-type validation, and
|
||||
/// <see cref="AddTemplateAttributeCommand.ElementDataType"/> /
|
||||
/// <see cref="UpdateTemplateAttributeCommand.ElementDataType"/> wired into the
|
||||
/// payload sent to the Management API.
|
||||
/// </summary>
|
||||
public class TemplateAttributeListTests
|
||||
{
|
||||
private static readonly Option<string> Url = new("--url") { Recursive = true };
|
||||
private static readonly Option<string> Username = new("--username") { Recursive = true };
|
||||
private static readonly Option<string> Password = new("--password") { Recursive = true };
|
||||
private static readonly Option<string> Format = CliOptions.CreateFormatOption();
|
||||
|
||||
private static Command AttributeGroup()
|
||||
=> TemplateCommands.Build(Url, Format, Username, Password)
|
||||
.Subcommands.Single(c => c.Name == "attribute");
|
||||
|
||||
// ---- option surface ----
|
||||
|
||||
[Fact]
|
||||
public void AttributeAdd_HasElementTypeOption()
|
||||
{
|
||||
var add = AttributeGroup().Subcommands.Single(c => c.Name == "add");
|
||||
Assert.Contains("--element-type", add.Options.Select(o => o.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeUpdate_HasElementTypeOption()
|
||||
{
|
||||
var update = AttributeGroup().Subcommands.Single(c => c.Name == "update");
|
||||
Assert.Contains("--element-type", update.Options.Select(o => o.Name));
|
||||
}
|
||||
|
||||
// ---- client-side element-type validation (both directions) ----
|
||||
|
||||
[Theory]
|
||||
[InlineData("String")]
|
||||
[InlineData("Int32")]
|
||||
[InlineData("Float")]
|
||||
[InlineData("Double")]
|
||||
[InlineData("Boolean")]
|
||||
[InlineData("DateTime")]
|
||||
public void ValidateElementType_ListWithValidScalar_Ok(string elementType)
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("List", elementType, out var error);
|
||||
Assert.True(ok);
|
||||
Assert.Null(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ListWithValidScalar_CaseInsensitive()
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("List", "string", out var error);
|
||||
Assert.True(ok);
|
||||
Assert.Null(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ListWithoutElementType_Error()
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("List", null, out var error);
|
||||
Assert.False(ok);
|
||||
Assert.NotNull(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ListWithBlankElementType_Error()
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("List", " ", out var error);
|
||||
Assert.False(ok);
|
||||
Assert.NotNull(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ListWithInvalidScalar_Error()
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("List", "List", out var error);
|
||||
Assert.False(ok);
|
||||
Assert.NotNull(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ListWithBinaryScalar_Error()
|
||||
{
|
||||
// Binary is a DataType but not a permitted List element scalar.
|
||||
var ok = TemplateCommands.TryValidateElementType("List", "Binary", out var error);
|
||||
Assert.False(ok);
|
||||
Assert.NotNull(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ScalarWithElementType_Error()
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("String", "Int32", out var error);
|
||||
Assert.False(ok);
|
||||
Assert.NotNull(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateElementType_ScalarWithoutElementType_Ok()
|
||||
{
|
||||
var ok = TemplateCommands.TryValidateElementType("Float", null, out var error);
|
||||
Assert.True(ok);
|
||||
Assert.Null(error);
|
||||
}
|
||||
|
||||
// ---- payload wiring: the raw JSON value + ElementDataType flow into the command ----
|
||||
|
||||
[Fact]
|
||||
public void BuildAddCommand_ListAttribute_CarriesElementTypeAndRawJsonValue()
|
||||
{
|
||||
var cmd = TemplateCommands.BuildAddAttributeCommand(
|
||||
templateId: 7,
|
||||
name: "WorkOrders",
|
||||
dataType: "List",
|
||||
value: """["WO-1","WO-2"]""",
|
||||
description: null,
|
||||
dataSource: null,
|
||||
isLocked: false,
|
||||
elementType: "String");
|
||||
|
||||
Assert.Equal(7, cmd.TemplateId);
|
||||
Assert.Equal("List", cmd.DataType);
|
||||
Assert.Equal("String", cmd.ElementDataType);
|
||||
// The CLI forwards the raw JSON string unchanged — the API/codec parses it.
|
||||
Assert.Equal("""["WO-1","WO-2"]""", cmd.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildUpdateCommand_ListAttribute_CarriesElementTypeAndRawJsonValue()
|
||||
{
|
||||
var cmd = TemplateCommands.BuildUpdateAttributeCommand(
|
||||
attributeId: 42,
|
||||
name: "WorkOrders",
|
||||
dataType: "List",
|
||||
value: """["A","B"]""",
|
||||
description: null,
|
||||
dataSource: null,
|
||||
isLocked: false,
|
||||
elementType: "Int32");
|
||||
|
||||
Assert.Equal(42, cmd.AttributeId);
|
||||
Assert.Equal("List", cmd.DataType);
|
||||
Assert.Equal("Int32", cmd.ElementDataType);
|
||||
Assert.Equal("""["A","B"]""", cmd.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildAddCommand_ScalarAttribute_LeavesElementTypeNull()
|
||||
{
|
||||
var cmd = TemplateCommands.BuildAddAttributeCommand(
|
||||
templateId: 1,
|
||||
name: "Speed",
|
||||
dataType: "Float",
|
||||
value: "0",
|
||||
description: null,
|
||||
dataSource: null,
|
||||
isLocked: false,
|
||||
elementType: null);
|
||||
|
||||
Assert.Null(cmd.ElementDataType);
|
||||
Assert.Equal("Float", cmd.DataType);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user