using ScadaLink.Commons.Entities.Templates; using ScadaLink.Commons.Types.Enums; namespace ScadaLink.TemplateEngine.Tests; public class LockEnforcerTests { // ======================================================================== // WP-8: Override Granularity // ======================================================================== [Fact] public void ValidateAttributeOverride_LockedAttribute_ReturnsError() { var original = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = true, Value = "0" }; var proposed = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = true, Value = "100" }; var result = LockEnforcer.ValidateAttributeOverride(original, proposed); Assert.NotNull(result); Assert.Contains("locked", result); } [Fact] public void ValidateAttributeOverride_DataTypeChanged_ReturnsError() { var original = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = false }; var proposed = new TemplateAttribute("Speed") { DataType = DataType.String, IsLocked = false // DataType changed! }; var result = LockEnforcer.ValidateAttributeOverride(original, proposed); Assert.NotNull(result); Assert.Contains("DataType", result); } [Fact] public void ValidateAttributeOverride_DataSourceReferenceChanged_ReturnsError() { var original = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = false, DataSourceReference = "tag1" }; var proposed = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = false, DataSourceReference = "tag2" // Changed! }; var result = LockEnforcer.ValidateAttributeOverride(original, proposed); Assert.NotNull(result); Assert.Contains("DataSourceReference", result); } [Fact] public void ValidateAttributeOverride_ValueAndDescriptionChanged_ReturnsNull() { var original = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = false, Value = "0", Description = "old" }; var proposed = new TemplateAttribute("Speed") { DataType = DataType.Float, IsLocked = false, Value = "100", Description = "new" }; var result = LockEnforcer.ValidateAttributeOverride(original, proposed); Assert.Null(result); } [Fact] public void ValidateAlarmOverride_LockedAlarm_ReturnsError() { var original = new TemplateAlarm("HighTemp") { TriggerType = AlarmTriggerType.ValueMatch, IsLocked = true, PriorityLevel = 500 }; var proposed = new TemplateAlarm("HighTemp") { TriggerType = AlarmTriggerType.ValueMatch, IsLocked = true, PriorityLevel = 600 }; var result = LockEnforcer.ValidateAlarmOverride(original, proposed); Assert.NotNull(result); Assert.Contains("locked", result); } [Fact] public void ValidateAlarmOverride_TriggerTypeChanged_ReturnsError() { var original = new TemplateAlarm("HighTemp") { TriggerType = AlarmTriggerType.ValueMatch, IsLocked = false }; var proposed = new TemplateAlarm("HighTemp") { TriggerType = AlarmTriggerType.RangeViolation, IsLocked = false // Changed! }; var result = LockEnforcer.ValidateAlarmOverride(original, proposed); Assert.NotNull(result); Assert.Contains("TriggerType", result); } [Fact] public void ValidateAlarmOverride_OverridableFieldsChanged_ReturnsNull() { var original = new TemplateAlarm("HighTemp") { TriggerType = AlarmTriggerType.ValueMatch, IsLocked = false, PriorityLevel = 500, Description = "old" }; var proposed = new TemplateAlarm("HighTemp") { TriggerType = AlarmTriggerType.ValueMatch, IsLocked = false, PriorityLevel = 700, Description = "new", TriggerConfiguration = """{"value": 100}""" }; var result = LockEnforcer.ValidateAlarmOverride(original, proposed); Assert.Null(result); } [Fact] public void ValidateScriptOverride_LockedScript_ReturnsError() { var original = new TemplateScript("OnStart", "code") { IsLocked = true }; var proposed = new TemplateScript("OnStart", "new code") { IsLocked = true }; var result = LockEnforcer.ValidateScriptOverride(original, proposed); Assert.NotNull(result); Assert.Contains("locked", result); } [Fact] public void ValidateScriptOverride_NameChanged_ReturnsError() { var original = new TemplateScript("OnStart", "code") { IsLocked = false }; var proposed = new TemplateScript("OnStop", "code") { IsLocked = false }; // Name changed! var result = LockEnforcer.ValidateScriptOverride(original, proposed); Assert.NotNull(result); Assert.Contains("Name", result); } [Fact] public void ValidateScriptOverride_OverridableFieldsChanged_ReturnsNull() { var original = new TemplateScript("OnStart", "old code") { IsLocked = false }; var proposed = new TemplateScript("OnStart", "new code") { IsLocked = false, TriggerType = "Timer", MinTimeBetweenRuns = TimeSpan.FromSeconds(30) }; var result = LockEnforcer.ValidateScriptOverride(original, proposed); Assert.Null(result); } // ======================================================================== // WP-9: Locking Rules // ======================================================================== [Fact] public void ValidateLockChange_UnlockLocked_ReturnsError() { var result = LockEnforcer.ValidateLockChange(true, false, "Speed"); Assert.NotNull(result); Assert.Contains("cannot be unlocked", result); } [Fact] public void ValidateLockChange_LockUnlocked_ReturnsNull() { var result = LockEnforcer.ValidateLockChange(false, true, "Speed"); Assert.Null(result); } [Fact] public void ValidateLockChange_KeepLocked_ReturnsNull() { var result = LockEnforcer.ValidateLockChange(true, true, "Speed"); Assert.Null(result); } [Fact] public void ValidateLockChange_KeepUnlocked_ReturnsNull() { var result = LockEnforcer.ValidateLockChange(false, false, "Speed"); Assert.Null(result); } }