feat(template): stamp ElementDataType on instance attribute overrides
Set existingOverride.ElementDataType and newOverride.ElementDataType from templateAttr.ElementDataType in both the update and create branches of SetAttributeOverrideAsync, so the persisted InstanceAttributeOverride row always carries the element type for later central normalizer use (#93/M3).
This commit is contained in:
@@ -269,6 +269,106 @@ public class InstanceServiceTests
|
||||
_repoMock.Verify(r => r.AddInstanceConnectionBindingAsync(It.IsAny<InstanceConnectionBinding>(), It.IsAny<CancellationToken>()), Times.Exactly(2));
|
||||
}
|
||||
|
||||
// --- NJ-2: ElementDataType stamping on SetAttributeOverrideAsync ---
|
||||
|
||||
[Fact]
|
||||
public async Task SetAttributeOverride_CreatePath_ListAttribute_StampsElementDataType()
|
||||
{
|
||||
var instance = new Instance("Inst1") { Id = 1, TemplateId = 1 };
|
||||
_repoMock.Setup(r => r.GetInstanceByIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(instance);
|
||||
_repoMock.Setup(r => r.GetAttributesByTemplateIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<TemplateAttribute>
|
||||
{
|
||||
new("Tags")
|
||||
{
|
||||
IsLocked = false,
|
||||
DataType = DataType.List,
|
||||
ElementDataType = DataType.String
|
||||
}
|
||||
});
|
||||
_repoMock.Setup(r => r.GetOverridesByInstanceIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<InstanceAttributeOverride>()); // no existing override → create path
|
||||
_repoMock.Setup(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(1);
|
||||
|
||||
InstanceAttributeOverride? captured = null;
|
||||
_repoMock.Setup(r => r.AddInstanceAttributeOverrideAsync(It.IsAny<InstanceAttributeOverride>(), It.IsAny<CancellationToken>()))
|
||||
.Callback<InstanceAttributeOverride, CancellationToken>((o, _) => captured = o);
|
||||
|
||||
var result = await _sut.SetAttributeOverrideAsync(1, "Tags", "[\"a\"]", "admin");
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.NotNull(captured);
|
||||
Assert.Equal(DataType.String, captured.ElementDataType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetAttributeOverride_UpdatePath_ListAttribute_StampsElementDataType()
|
||||
{
|
||||
var instance = new Instance("Inst1") { Id = 1, TemplateId = 1 };
|
||||
_repoMock.Setup(r => r.GetInstanceByIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(instance);
|
||||
_repoMock.Setup(r => r.GetAttributesByTemplateIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<TemplateAttribute>
|
||||
{
|
||||
new("Tags")
|
||||
{
|
||||
IsLocked = false,
|
||||
DataType = DataType.List,
|
||||
ElementDataType = DataType.String
|
||||
}
|
||||
});
|
||||
|
||||
var existingOverride = new InstanceAttributeOverride("Tags") { Id = 42, InstanceId = 1, OverrideValue = "[\"old\"]" };
|
||||
_repoMock.Setup(r => r.GetOverridesByInstanceIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<InstanceAttributeOverride> { existingOverride }); // pre-existing → update path
|
||||
_repoMock.Setup(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(1);
|
||||
|
||||
InstanceAttributeOverride? captured = null;
|
||||
_repoMock.Setup(r => r.UpdateInstanceAttributeOverrideAsync(It.IsAny<InstanceAttributeOverride>(), It.IsAny<CancellationToken>()))
|
||||
.Callback<InstanceAttributeOverride, CancellationToken>((o, _) => captured = o);
|
||||
|
||||
var result = await _sut.SetAttributeOverrideAsync(1, "Tags", "[\"new\"]", "admin");
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.NotNull(captured);
|
||||
Assert.Equal(DataType.String, captured.ElementDataType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetAttributeOverride_CreatePath_ScalarAttribute_ElementDataTypeIsNull()
|
||||
{
|
||||
var instance = new Instance("Inst1") { Id = 1, TemplateId = 1 };
|
||||
_repoMock.Setup(r => r.GetInstanceByIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(instance);
|
||||
_repoMock.Setup(r => r.GetAttributesByTemplateIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<TemplateAttribute>
|
||||
{
|
||||
new("Threshold")
|
||||
{
|
||||
IsLocked = false,
|
||||
DataType = DataType.Float,
|
||||
ElementDataType = null
|
||||
}
|
||||
});
|
||||
_repoMock.Setup(r => r.GetOverridesByInstanceIdAsync(1, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<InstanceAttributeOverride>());
|
||||
_repoMock.Setup(r => r.SaveChangesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(1);
|
||||
|
||||
InstanceAttributeOverride? captured = null;
|
||||
_repoMock.Setup(r => r.AddInstanceAttributeOverrideAsync(It.IsAny<InstanceAttributeOverride>(), It.IsAny<CancellationToken>()))
|
||||
.Callback<InstanceAttributeOverride, CancellationToken>((o, _) => captured = o);
|
||||
|
||||
var result = await _sut.SetAttributeOverrideAsync(1, "Threshold", "3.14", "admin");
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.NotNull(captured);
|
||||
Assert.Null(captured.ElementDataType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AssignToArea_AreaInDifferentSite_ReturnsFailure()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user