using ZB.MOM.WW.ScadaBridge.Transport.Import; using ZB.MOM.WW.ScadaBridge.Transport.Serialization; namespace ZB.MOM.WW.ScadaBridge.Transport.Tests.Import; /// /// ScadaBridge#118 — orders a bundle's derived templates /// after their owner and base whatever the bundle order, and reports cycles and malformed /// derivations as errors. /// public sealed class DerivedTemplatePlanTests { private static TemplateDto Base(string name) => new(name, null, null, null, Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty()); private static TemplateDto Derived(string owner, string[] slots, string baseName, params string[] baseSlots) => Base(slots[^1]) with { Derivation = new TemplateDerivationDto(owner, slots, baseName, baseSlots) }; /// Nested slots and cascade slots come after their owner and their (derived) base. [Fact] public void Orders_owner_and_base_before_the_derived_template() { var plan = DerivedTemplatePlan.Build(new[] { Derived("Station", new[] { "P", "M1" }, "Pump", "M1"), // owner Station.P, base Pump.M1 Base("Station"), Derived("Station", new[] { "P" }, "Pump"), Derived("Pump", new[] { "M1" }, "Motor"), }); Assert.Empty(plan.Errors); var order = plan.Ordered.Select(DerivedTemplatePlan.Key).ToList(); Assert.Equal(3, order.Count); Assert.True(order.IndexOf("Station.P") < order.IndexOf("Station.P.M1")); Assert.True(order.IndexOf("Pump.M1") < order.IndexOf("Station.P.M1")); } /// A two-node and a one-node cycle are both reported, naming the templates. [Fact] public void Cycles_are_errors() { var two = DerivedTemplatePlan.Build(new[] { Derived("Pump", new[] { "X" }, "Pump", "Y"), Derived("Pump", new[] { "Y" }, "Pump", "X"), }); var error = Assert.Single(two.Errors); Assert.Contains("cycle", error, StringComparison.Ordinal); Assert.Contains("Pump.X", error, StringComparison.Ordinal); Assert.Contains("Pump.Y", error, StringComparison.Ordinal); var self = DerivedTemplatePlan.Build(new[] { Derived("Pump", new[] { "X" }, "Pump", "X") }); Assert.Contains("cycle", Assert.Single(self.Errors), StringComparison.Ordinal); } /// Malformed derivations and duplicate identities are errors; base templates are ignored. [Fact] public void Malformed_and_duplicate_derivations_are_errors() { var plan = DerivedTemplatePlan.Build(new[] { Base("Pump"), Base("M1") with { Derivation = new TemplateDerivationDto("Pump", Array.Empty(), "Motor", Array.Empty()) }, Derived("Pump", new[] { "M2" }, "Motor"), Derived("Pump", new[] { "M2" }, "Motor"), }); Assert.Equal(2, plan.Errors.Count); Assert.Contains(plan.Errors, e => e.Contains("malformed", StringComparison.Ordinal)); Assert.Contains(plan.Errors, e => e.Contains("more than once", StringComparison.Ordinal)); Assert.Equal("Pump", DerivedTemplatePlan.Key(Base("Pump"))); } }