diff --git a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/FlatteningService.cs b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/FlatteningService.cs index 7b45d22a..c99af3e4 100644 --- a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/FlatteningService.cs +++ b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Flattening/FlatteningService.cs @@ -175,6 +175,7 @@ public class FlatteningService CanonicalName = attr.Name, Value = attr.Value, DataType = attr.DataType.ToString(), + ElementDataType = attr.ElementDataType?.ToString(), IsLocked = attr.IsLocked, Description = attr.Description, DataSourceReference = attr.DataSourceReference, diff --git a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/FlatteningServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/FlatteningServiceTests.cs index 47e92e8a..7f06d7cc 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/FlatteningServiceTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Flattening/FlatteningServiceTests.cs @@ -788,4 +788,67 @@ public class FlatteningServiceTests Assert.Equal("ns=2;s=Tank07", result.Value.NativeAlarmSources[0].SourceReference); Assert.Equal("Override", result.Value.NativeAlarmSources[0].Source); } + + // ── MV-4: ElementDataType carried through flatten/override ──────────── + + [Fact] + public void Flatten_ListAttribute_ElementDataTypeCarriedToResolvedAttribute() + { + // A template with a List attribute whose ElementDataType is String. + // The flattened result must carry DataType == "List" and ElementDataType == "String". + var template = CreateTemplate(1, "Base"); + template.Attributes.Add(new TemplateAttribute("Tags") + { + DataType = DataType.List, + ElementDataType = DataType.String, + Value = null + }); + + var instance = CreateInstance(); + var result = _sut.Flatten( + instance, + [template], + new Dictionary>(), + new Dictionary>(), + new Dictionary()); + + Assert.True(result.IsSuccess); + var attr = result.Value.Attributes.First(a => a.CanonicalName == "Tags"); + Assert.Equal("List", attr.DataType); + Assert.Equal("String", attr.ElementDataType); + } + + [Fact] + public void Flatten_ListAttributeWithInstanceOverride_ElementDataTypePreservedThroughOverride() + { + // An instance override replaces the VALUE of a List attribute. + // The ElementDataType must survive the override path unchanged. + var template = CreateTemplate(1, "Base"); + template.Attributes.Add(new TemplateAttribute("Tags") + { + DataType = DataType.List, + ElementDataType = DataType.String, + Value = "[\"a\",\"b\"]" + }); + + var instance = CreateInstance(); + instance.AttributeOverrides.Add(new InstanceAttributeOverride("Tags") + { + OverrideValue = "[\"x\",\"y\",\"z\"]" + }); + + var result = _sut.Flatten( + instance, + [template], + new Dictionary>(), + new Dictionary>(), + new Dictionary()); + + Assert.True(result.IsSuccess); + var attr = result.Value.Attributes.First(a => a.CanonicalName == "Tags"); + Assert.Equal("[\"x\",\"y\",\"z\"]", attr.Value); // override applied + Assert.Equal("Override", attr.Source); // came from override path + Assert.Equal("List", attr.DataType); // type unchanged + Assert.Equal("String", attr.ElementDataType); // element type preserved + } }