using ZB.MOM.WW.ScadaBridge.Commons.Types; using ZB.MOM.WW.ScadaBridge.Commons.Types.Scripts; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts; namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.Scripts; /// /// Phase 1 of the script-scope rollout: verify path arithmetic for the new /// Attributes / Children / Parent accessors. The actor-mediated reads/writes /// are exercised end-to-end in Phase 2 once flattening carries scope info. /// public class ScopeAccessorTests { [Fact] public void Root_SelfPath_Empty() { Assert.Equal("", ScriptScope.Root.SelfPath); Assert.Null(ScriptScope.Root.ParentPath); Assert.False(ScriptScope.Root.HasParent); } [Fact] public void CompositionScope_HasParent() { var scope = new ScriptScope("TempSensor", ""); Assert.True(scope.HasParent); Assert.Equal("", scope.ParentPath); } [Fact] public void AttributeAccessor_RootScope_ResolvesBareKey() { var acc = new AttributeAccessor(null!, ""); Assert.Equal("Temperature", acc.Resolve("Temperature")); } [Fact] public void AttributeAccessor_ComposedScope_PrependsPath() { var acc = new AttributeAccessor(null!, "TempSensor"); Assert.Equal("TempSensor.Temperature", acc.Resolve("Temperature")); } [Fact] public void AttributeAccessor_NestedScope_ChainsPath() { var acc = new AttributeAccessor(null!, "Motor.TempSensor"); Assert.Equal("Motor.TempSensor.Temperature", acc.Resolve("Temperature")); } [Fact] public void CompositionAccessor_AttributesShareScope() { var comp = new CompositionAccessor(null!, "TempSensor"); Assert.Equal("TempSensor", comp.Path); Assert.Equal("TempSensor", comp.Attributes.ScopePrefix); } [Fact] public void CompositionAccessor_ResolveScript_PrependsPath() { var comp = new CompositionAccessor(null!, "TempSensor"); Assert.Equal("TempSensor.Sample", comp.ResolveScript("Sample")); } [Fact] public void CompositionAccessor_EmptyPath_LeavesScriptNameBare() { var comp = new CompositionAccessor(null!, ""); Assert.Equal("Sample", comp.ResolveScript("Sample")); } [Fact] public void ChildrenAccessor_FromRoot_GivesUnpathedChild() { var children = new ChildrenAccessor(null!, ""); var temp = children["TempSensor"]; Assert.Equal("TempSensor", temp.Path); } [Fact] public void ChildrenAccessor_FromComposition_PrefixesChild() { var children = new ChildrenAccessor(null!, "Motor"); var temp = children["TempSensor"]; Assert.Equal("Motor.TempSensor", temp.Path); } // --- AttributeAccessor encoding contract ---------------------------------- // // AttributeAccessor.this[key].set and SetAsync both route through // ScriptRuntimeContext.SetAttribute(name, encodedString), which requires // a live Akka IActorRef; ScriptRuntimeContext has no virtual members and // its constructor cannot be satisfied without a real ActorSystem, so a // full-round-trip unit test through the accessor+context is not viable // without a heavy Akka harness. // // Instead we test the encoding decision directly: AttributeAccessor is now // documented to delegate value serialisation to AttributeValueCodec.Encode. // These tests verify that contract at the codec level, which is exactly what // the fix makes the accessor invoke. [Fact] public void AttributeValueCodec_Encode_List_ProducesJsonArray() { // A List must encode to a JSON array, not the garbage // "System.Collections.Generic.List`1[System.String]" that .ToString() produced. var list = new List { "a", "b" }; var encoded = AttributeValueCodec.Encode(list); Assert.Equal("[\"a\",\"b\"]", encoded); } [Fact] public void AttributeValueCodec_Encode_Scalar_PassesThrough() { // A plain string scalar must be returned unchanged (byte-identical to // the historical value?.ToString() path for strings). var encoded = AttributeValueCodec.Encode("x"); Assert.Equal("x", encoded); } [Fact] public void AttributeValueCodec_Encode_Null_ReturnsNull() { // AttributeAccessor coalesces null → "" at the call site, // but the codec itself must return null for null input. Assert.Null(AttributeValueCodec.Encode(null)); } [Fact] public void AttributeValueCodec_Encode_IntList_ProducesJsonArray() { // Integer list elements encode as native-typed JSON numbers (NJ-1): // [1,2,3], not the old quoted-element form ["1","2","3"]. var list = new List { 1, 2, 3 }; var encoded = AttributeValueCodec.Encode(list); Assert.Equal("[1,2,3]", encoded); } }