From 33c3016e92ac7e708b10406b4263e458ecf3aa99 Mon Sep 17 00:00:00 2001 From: Scott Olson Jr Date: Sat, 14 Feb 2026 08:01:37 -0800 Subject: [PATCH 1/5] Add DisableAllFieldObjects functionality across decorators - Implemented DisableAllFieldObjects method in RowObjectDecorator, OptionObjectDecorator, OptionObject2Decorator, and OptionObject2015Decorator to disable all FieldObjects. - Added overloads to allow exclusion of specific FieldNumbers during the disabling process. - Updated corresponding helper classes to support the new functionality. - Enhanced unit tests to cover various scenarios for disabling field objects, including null checks and exclusion lists. - Adjusted exception handling to throw ArgumentException for missing forms instead of ArgumentNullException. --- .../OptionObject2015DecoratorTests.cs | 277 +++++++++++++++++ .../Decorators/OptionObject2DecoratorTests.cs | 277 +++++++++++++++++ .../Decorators/OptionObjectDecoratorTests.cs | 283 ++++++++++++++++++ .../Decorators/FormObjectDecorator.cs | 21 ++ .../Decorators/FormObjectDecoratorHelper.cs | 36 +++ .../Decorators/OptionObject2015Decorator.cs | 11 + .../OptionObject2015DecoratorHelper.cs | 29 ++ .../Decorators/OptionObject2Decorator.cs | 11 + .../OptionObject2DecoratorHelper.cs | 29 ++ .../Decorators/OptionObjectDecorator.cs | 11 + .../Decorators/OptionObjectDecoratorHelper.cs | 29 ++ .../Decorators/RowObjectDecorator.cs | 17 ++ .../Decorators/RowObjectDecoratorHelper.cs | 35 +++ .../DisableAllFieldObjectsTests.cs | 2 +- .../OptionObject/DisableAllFieldObjects.cs | 2 +- 15 files changed, 1068 insertions(+), 2 deletions(-) diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs index 8a082165..81d8f991 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs @@ -1713,4 +1713,281 @@ public void TestOptionObject2015Decorator_Constructor_WithEmptyFormsCollection() } #endregion + + #region DisableAllFieldObjects + + [TestMethod] + public void DisableAllFieldObjects_AllFieldsDisabled() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_WithExcludedFields() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject1, fieldObject2], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(new List { "123" }); + Assert.IsTrue(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[1].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_NullExcludedFieldsList_ThrowsException() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(null)); + } + + [TestMethod] + public void DisableAllFieldObjects_EmptyForms_ThrowsException() + { + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObject2015Decorator(optionObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); + } + + [TestMethod] + public void DisableAllFieldObjects_EmptyExclusionList() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesSessionToken() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + SessionToken = "SESSIONTOKEN123", + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("SESSIONTOKEN123", decorator.SessionToken); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesNamespaceName() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + NamespaceName = "NAMESPACE", + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("NAMESPACE", decorator.NamespaceName); + } + + [TestMethod] + public void DisableAllFieldObjects_MultipleIterationForm() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + MultipleIteration = true, + OtherRows = [otherRow] + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_SetsRowActionToEdit() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("EDIT", decorator.Forms[0].CurrentRow.RowAction); + } + + #endregion } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs index 3d771098..e75d9de1 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs @@ -1730,4 +1730,281 @@ public void TestOptionObject2Decorator_Constructor_WithEmptyFormsCollection() } #endregion + + #region DisableAllFieldObjects + + [TestMethod] + public void DisableAllFieldObjects_AllFieldsDisabled() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_WithExcludedFields() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject1, fieldObject2], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(new List { "123" }); + Assert.IsTrue(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[1].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_NullExcludedFieldsList_ThrowsException() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(null)); + } + + [TestMethod] + public void DisableAllFieldObjects_EmptyForms_ThrowsException() + { + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObject2Decorator(optionObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); + } + + [TestMethod] + public void DisableAllFieldObjects_EmptyExclusionList() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesNamespaceName() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + NamespaceName = "NAMESPACE", + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("NAMESPACE", decorator.NamespaceName); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesServerName() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + ServerName = "SERVERNAME", + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("SERVERNAME", decorator.ServerName); + } + + [TestMethod] + public void DisableAllFieldObjects_MultipleIterationForm() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + MultipleIteration = true, + OtherRows = [otherRow] + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_SetsRowActionToEdit() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("EDIT", decorator.Forms[0].CurrentRow.RowAction); + } + + #endregion } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs index b012985d..4acfdb39 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs @@ -1731,4 +1731,287 @@ public void TestOptionObjectDecorator_Constructor_WithEmptyFormsCollection() } #endregion + + #region DisableAllFieldObjects + + [TestMethod] + public void DisableAllFieldObjects_NullOptionObject_ThrowsException() + { + OptionObjectDecorator decorator = null; + Assert.ThrowsException(() => decorator = new OptionObjectDecorator(null)); + } + + [TestMethod] + public void DisableAllFieldObjects_AllFieldsDisabled() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_WithExcludedFields() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject1, fieldObject2], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(new List { "123" }); + Assert.IsTrue(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[1].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_EmptyExclusionList() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_NullExcludedFieldsList_ThrowsException() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(null)); + } + + [TestMethod] + public void DisableAllFieldObjects_EmptyForms_ThrowsException() + { + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObjectDecorator(optionObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesEntityID() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + EntityID = "123456", + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("123456", decorator.EntityID); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesOptionId() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("TEST123", decorator.OptionId); + } + + [TestMethod] + public void DisableAllFieldObjects_MultipleIterationForm() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + MultipleIteration = true, + OtherRows = [otherRow] + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_SetsRowActionToEdit() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("EDIT", decorator.Forms[0].CurrentRow.RowAction); + } + + #endregion } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecorator.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecorator.cs index e7a7c225..d4e525ef 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecorator.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecorator.cs @@ -96,6 +96,27 @@ public void DeleteRowObject(string rowId) OtherRows = tempDecorator.OtherRows; } + /// + /// Disables all in the . + /// + public void DisableAllFieldObjects() + { + var tempDecorator = Helper.DisableAllFieldObjects(this); + CurrentRow = tempDecorator.CurrentRow; + OtherRows = tempDecorator.OtherRows; + } + + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + public void DisableAllFieldObjects(List excludedFields) + { + var tempDecorator = Helper.DisableAllFieldObjects(this, excludedFields); + CurrentRow = tempDecorator.CurrentRow; + OtherRows = tempDecorator.OtherRows; + } + /// /// Returns the RowId of the . /// diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs index 06189337..46592655 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs @@ -407,6 +407,42 @@ public static FormObjectDecorator DeleteRowObject(FormObjectDecorator formObject throw new ArgumentException(resourceManager.GetString("noRowObjectsFoundByRowId", CultureInfo.CurrentCulture), nameof(rowId)); } + /// + /// Disables all in the . + /// + /// + /// + public static FormObjectDecorator DisableAllFieldObjects(FormObjectDecorator formObject) + { + if (formObject == null) + throw new ArgumentNullException(nameof(formObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + return DisableAllFieldObjects(formObject, new List()); + } + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + /// + /// + public static FormObjectDecorator DisableAllFieldObjects(FormObjectDecorator formObject, List excludedFields) + { + if (formObject == null) + throw new ArgumentNullException(nameof(formObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (excludedFields == null) + throw new ArgumentNullException(nameof(excludedFields), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + + if (formObject.CurrentRow != null) + { + formObject.CurrentRow.DisableAllFieldObjects(excludedFields); + } + + if (formObject.MultipleIteration) + { + formObject.OtherRows.ForEach(r => r.DisableAllFieldObjects(excludedFields)); + } + + return formObject; + } } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015Decorator.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015Decorator.cs index 28739afd..39414c2f 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015Decorator.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015Decorator.cs @@ -77,6 +77,17 @@ public OptionObject2015Decorator(OptionObject2015 optionObject) /// public void DeleteRowObject(string formId, string rowId) => Forms = Helper.DeleteRowObject(this, formId, rowId).Forms; + /// + /// Disables all in the . + /// + public void DisableAllFieldObjects() => Forms = Helper.DisableAllFieldObjects(this).Forms; + + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + public void DisableAllFieldObjects(List excludedFields) => Forms = Helper.DisableAllFieldObjects(this, excludedFields).Forms; + /// /// Returns the CurrentRow RowId of the form matching the FormId. /// diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs index 0ba8292a..371af37f 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs @@ -444,6 +444,35 @@ public static OptionObject2015Decorator DeleteRowObject(OptionObject2015Decorato throw new ArgumentNullException(nameof(rowId), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); return ExecuteOnForm(optionObject, formId, form => form.DeleteRowObject(rowId)); } + /// + /// Disables all in the . + /// + /// + /// + public static OptionObject2015Decorator DisableAllFieldObjects(OptionObject2015Decorator optionObject) + { + if (optionObject == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + return DisableAllFieldObjects(optionObject, new List()); + } + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + /// + /// + public static OptionObject2015Decorator DisableAllFieldObjects(OptionObject2015Decorator optionObject, List excludedFields) + { + if (optionObject == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms.Count == 0) + throw new ArgumentException(resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture), nameof(optionObject)); + if (excludedFields == null) + throw new ArgumentNullException(nameof(excludedFields), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + + optionObject.Forms.ForEach(f => f.DisableAllFieldObjects(excludedFields)); + return optionObject; + } } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2Decorator.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2Decorator.cs index f6789915..fc11de1d 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2Decorator.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2Decorator.cs @@ -76,6 +76,17 @@ public OptionObject2Decorator(OptionObject2 optionObject) /// public void DeleteRowObject(string formId, string rowId) => Forms = Helper.DeleteRowObject(this, formId, rowId).Forms; + /// + /// Disables all in the . + /// + public void DisableAllFieldObjects() => Forms = Helper.DisableAllFieldObjects(this).Forms; + + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + public void DisableAllFieldObjects(List excludedFields) => Forms = Helper.DisableAllFieldObjects(this, excludedFields).Forms; + /// /// Returns the CurrentRow RowId of the form matching the FormId. /// diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs index e75ec1c1..fa39a2b6 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs @@ -444,6 +444,35 @@ public static OptionObject2Decorator DeleteRowObject(OptionObject2Decorator opti throw new ArgumentNullException(nameof(rowId), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); return ExecuteOnForm(optionObject, formId, form => form.DeleteRowObject(rowId)); } + /// + /// Disables all in the . + /// + /// + /// + public static OptionObject2Decorator DisableAllFieldObjects(OptionObject2Decorator optionObject) + { + if (optionObject == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + return DisableAllFieldObjects(optionObject, new List()); + } + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + /// + /// + public static OptionObject2Decorator DisableAllFieldObjects(OptionObject2Decorator optionObject, List excludedFields) + { + if (optionObject == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms.Count == 0) + throw new ArgumentException(resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture), nameof(optionObject)); + if (excludedFields == null) + throw new ArgumentNullException(nameof(excludedFields), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + + optionObject.Forms.ForEach(f => f.DisableAllFieldObjects(excludedFields)); + return optionObject; + } } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecorator.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecorator.cs index 17a8d51c..0d703e6d 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecorator.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecorator.cs @@ -73,6 +73,17 @@ public OptionObjectDecorator(OptionObject optionObject) /// public void DeleteRowObject(string formId, string rowId) => Forms = Helper.DeleteRowObject(this, formId, rowId).Forms; + /// + /// Disables all in the . + /// + public void DisableAllFieldObjects() => Forms = Helper.DisableAllFieldObjects(this).Forms; + + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + public void DisableAllFieldObjects(List excludedFields) => Forms = Helper.DisableAllFieldObjects(this, excludedFields).Forms; + /// /// Returns the CurrentRow RowId of the form matching the FormId. /// diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs index 21964244..1c8fbab9 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs @@ -444,6 +444,35 @@ public static OptionObjectDecorator DeleteRowObject(OptionObjectDecorator option throw new ArgumentNullException(nameof(rowId), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); return ExecuteOnForm(optionObject, formId, form => form.DeleteRowObject(rowId)); } + /// + /// Disables all in the . + /// + /// + /// + public static OptionObjectDecorator DisableAllFieldObjects(OptionObjectDecorator optionObject) + { + if (optionObject == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + return DisableAllFieldObjects(optionObject, new List()); + } + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + /// + /// + public static OptionObjectDecorator DisableAllFieldObjects(OptionObjectDecorator optionObject, List excludedFields) + { + if (optionObject == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms.Count == 0) + throw new ArgumentException(resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture), nameof(optionObject)); + if (excludedFields == null) + throw new ArgumentNullException(nameof(excludedFields), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + + optionObject.Forms.ForEach(f => f.DisableAllFieldObjects(excludedFields)); + return optionObject; + } } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecorator.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecorator.cs index 981df774..a3a13b62 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecorator.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecorator.cs @@ -85,5 +85,22 @@ public RowObjectDecoratorReturnBuilder Return() /// /// public void SetFieldValue(string fieldNumber, string fieldValue) => Fields = Helper.SetFieldValue(this, fieldNumber, fieldValue).Fields; + + /// + /// Disables all in the . + /// + public void DisableAllFieldObjects() + { + Fields = Helper.DisableAllFieldObjects(this).Fields; + } + + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + public void DisableAllFieldObjects(List excludedFields) + { + Fields = Helper.DisableAllFieldObjects(this, excludedFields).Fields; + } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs index a91b94fe..520ca3e6 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using System.Reflection; using System.Resources; using RarelySimple.AvatarScriptLink.Net.Exceptions; @@ -189,6 +190,40 @@ public static RowObjectDecorator SetFieldValue(RowObjectDecorator decorator, str } return decorator; } + /// + /// Disables all in the . + /// + /// + /// + public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowObject) + { + if (rowObject == null) + throw new ArgumentNullException(nameof(rowObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + return DisableAllFieldObjects(rowObject, new System.Collections.Generic.List()); + } + /// + /// Disables all in the , except for the FieldNumbers specified in the list. + /// + /// + /// + /// + public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowObject, System.Collections.Generic.List excludedFields) + { + if (rowObject == null) + throw new ArgumentNullException(nameof(rowObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (excludedFields == null) + throw new ArgumentNullException(nameof(excludedFields), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + + foreach (var field in rowObject.Fields.Where(f => !excludedFields.Contains(f.FieldNumber))) + { + field.Enabled = false; + } + + if (rowObject.RowAction == RowActions.None) + rowObject.RowAction = RowActions.Edit; + + return rowObject; + } } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs index 5dcb7a7b..b822b1e0 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs @@ -429,7 +429,7 @@ public void DisableAllFieldObjects_OptionObject2015_ExcludesFields_NoForms() "2", "4" ]; - Assert.ThrowsException(() => (OptionObject2015)OptionObjectHelpers.DisableAllFieldObjects(optionObject2015, excludedFields)); + Assert.ThrowsException(() => (OptionObject2015)OptionObjectHelpers.DisableAllFieldObjects(optionObject2015, excludedFields)); } } } diff --git a/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs b/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs index 972cc557..78a3c6cf 100644 --- a/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs +++ b/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs @@ -30,7 +30,7 @@ public static IOptionObject DisableAllFieldObjects(IOptionObject optionObject, L if (optionObject == null) throw new ArgumentNullException(nameof(optionObject), ScriptLinkHelpers.GetLocalizedString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); if (optionObject.Forms.Count == 0) - throw new ArgumentNullException(nameof(optionObject), ScriptLinkHelpers.GetLocalizedString("optionObjectMissingForms", CultureInfo.CurrentCulture)); + throw new ArgumentException(ScriptLinkHelpers.GetLocalizedString("optionObjectMissingForms", CultureInfo.CurrentCulture), nameof(optionObject)); if (excludedFields == null) throw new ArgumentNullException(nameof(excludedFields), ScriptLinkHelpers.GetLocalizedString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); return DisableAllFieldObjectsByOptionObject(optionObject, excludedFields); From 5b45e07326a62a7dc1c95f7e6478da8dbfefd54b Mon Sep 17 00:00:00 2001 From: Scott Olson Jr Date: Sat, 14 Feb 2026 08:29:18 -0800 Subject: [PATCH 2/5] address reviewer comments --- .../Decorators/OptionObjectDecoratorTests.cs | 7 ------- .../Decorators/OptionObject2015DecoratorHelper.cs | 2 ++ .../Decorators/OptionObject2DecoratorHelper.cs | 2 ++ .../Decorators/OptionObjectDecoratorHelper.cs | 2 ++ 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs index 4acfdb39..93fcdcb3 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs @@ -1734,13 +1734,6 @@ public void TestOptionObjectDecorator_Constructor_WithEmptyFormsCollection() #region DisableAllFieldObjects - [TestMethod] - public void DisableAllFieldObjects_NullOptionObject_ThrowsException() - { - OptionObjectDecorator decorator = null; - Assert.ThrowsException(() => decorator = new OptionObjectDecorator(null)); - } - [TestMethod] public void DisableAllFieldObjects_AllFieldsDisabled() { diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs index 371af37f..d3c9293c 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2015DecoratorHelper.cs @@ -465,6 +465,8 @@ public static OptionObject2015Decorator DisableAllFieldObjects(OptionObject2015D { if (optionObject == null) throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture)); if (optionObject.Forms.Count == 0) throw new ArgumentException(resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture), nameof(optionObject)); if (excludedFields == null) diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs index fa39a2b6..692c4093 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObject2DecoratorHelper.cs @@ -465,6 +465,8 @@ public static OptionObject2Decorator DisableAllFieldObjects(OptionObject2Decorat { if (optionObject == null) throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture)); if (optionObject.Forms.Count == 0) throw new ArgumentException(resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture), nameof(optionObject)); if (excludedFields == null) diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs index 1c8fbab9..40193d6b 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/OptionObjectDecoratorHelper.cs @@ -465,6 +465,8 @@ public static OptionObjectDecorator DisableAllFieldObjects(OptionObjectDecorator { if (optionObject == null) throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms == null) + throw new ArgumentNullException(nameof(optionObject), resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture)); if (optionObject.Forms.Count == 0) throw new ArgumentException(resourceManager.GetString(OptionObjectMissingForms, CultureInfo.CurrentCulture), nameof(optionObject)); if (excludedFields == null) From 871ac64366c9c6b0fef7385362a0c8c085b42fb3 Mon Sep 17 00:00:00 2001 From: Scott Olson Jr Date: Sat, 14 Feb 2026 08:42:38 -0800 Subject: [PATCH 3/5] Add unit tests for DisableAllFieldObjects method across decorators --- .../Decorators/FormObjectDecoratorTests.cs | 199 ++++++++++++++++++ .../OptionObject2015DecoratorTests.cs | 115 ++++++++++ .../Decorators/OptionObject2DecoratorTests.cs | 115 ++++++++++ .../Decorators/OptionObjectDecoratorTests.cs | 114 ++++++++++ .../Decorators/RowObjectDecoratorTests.cs | 180 ++++++++++++++++ 5 files changed, 723 insertions(+) diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs index 45184741..be6e9b6a 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs @@ -1190,4 +1190,203 @@ public void TestFormObjectDecorator_AddRowObject_WithNullOtherRows_BecomesCurren } #endregion + + #region DisableAllFieldObjects + + [TestMethod] + public void DisableAllFieldObjects_NullExclusionList_ThrowsException() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var decorator = new FormObjectDecorator(formObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(null)); + } + + [TestMethod] + public void DisableAllFieldObjects_DisablesFieldsInCurrentRow() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.CurrentRow.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_DisablesFieldsInOtherRowsWhenMultipleIteration() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var currentRow = new RowObject() + { + Fields = [fieldObject1], + RowId = "1" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject2], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = currentRow, + MultipleIteration = true, + OtherRows = [otherRow] + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.CurrentRow.Fields[0].Enabled); + Assert.IsFalse(decorator.OtherRows[0].Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_ExcludedFieldsRemainEnabled() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject1, fieldObject2], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(new List { "123" }); + Assert.IsTrue(decorator.CurrentRow.Fields[0].Enabled); + Assert.IsFalse(decorator.CurrentRow.Fields[1].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_WithNullCurrentRow() + { + var formObject = new FormObject() + { + FormId = "1" + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsNull(decorator.CurrentRow); + } + + [TestMethod] + public void DisableAllFieldObjects_SetsRowActionToEdit() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(new List()); + Assert.AreEqual(RowActions.Edit, decorator.CurrentRow.RowAction); + } + + [TestMethod] + public void DisableAllFieldObjects_WithoutExclusionList() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.CurrentRow.Fields[0].Enabled); + Assert.AreEqual(RowActions.Edit, decorator.CurrentRow.RowAction); + } + + #endregion } \ No newline at end of file diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs index 81d8f991..f972375e 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs @@ -1829,6 +1829,32 @@ public void DisableAllFieldObjects_EmptyForms_ThrowsException() Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); } + [TestMethod] + public void DisableAllFieldObjects_NullForms_ThrowsException() + { + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.Forms = null; + Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); + } + + [TestMethod] + public void DisableAllFieldObjects_NullForms_WithExclusionList_ThrowsException() + { + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.Forms = null; + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(new List())); + } + [TestMethod] public void DisableAllFieldObjects_EmptyExclusionList() { @@ -1989,5 +2015,94 @@ public void DisableAllFieldObjects_SetsRowActionToEdit() Assert.AreEqual("EDIT", decorator.Forms[0].CurrentRow.RowAction); } + [TestMethod] + public void DisableAllFieldObjects_PreservesExistingRowAction() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "DELETE" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("DELETE", decorator.Forms[0].CurrentRow.RowAction); + } + + [TestMethod] + public void DisableAllFieldObjects_WithNullCurrentRow() + { + var formObject = new FormObject() + { + FormId = "1" + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsNull(decorator.Forms[0].CurrentRow); + } + + [TestMethod] + public void DisableAllFieldObjects_NonMultipleIterationForm() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject, + MultipleIteration = false, + OtherRows = [otherRow] + }; + var optionObject = new OptionObject2015() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2015Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + Assert.IsTrue(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + } + #endregion } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs index e75d9de1..bfa82925 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs @@ -1846,6 +1846,32 @@ public void DisableAllFieldObjects_EmptyForms_ThrowsException() Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); } + [TestMethod] + public void DisableAllFieldObjects_NullForms_ThrowsException() + { + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.Forms = null; + Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); + } + + [TestMethod] + public void DisableAllFieldObjects_NullForms_WithExclusionList_ThrowsException() + { + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.Forms = null; + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(new List())); + } + [TestMethod] public void DisableAllFieldObjects_EmptyExclusionList() { @@ -2006,5 +2032,94 @@ public void DisableAllFieldObjects_SetsRowActionToEdit() Assert.AreEqual("EDIT", decorator.Forms[0].CurrentRow.RowAction); } + [TestMethod] + public void DisableAllFieldObjects_PreservesExistingRowAction() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "DELETE" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("DELETE", decorator.Forms[0].CurrentRow.RowAction); + } + + [TestMethod] + public void DisableAllFieldObjects_WithNullCurrentRow() + { + var formObject = new FormObject() + { + FormId = "1" + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsNull(decorator.Forms[0].CurrentRow); + } + + [TestMethod] + public void DisableAllFieldObjects_NonMultipleIterationForm() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject, + MultipleIteration = false, + OtherRows = [otherRow] + }; + var optionObject = new OptionObject2() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObject2Decorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + Assert.IsTrue(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + } + #endregion } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs index 93fcdcb3..e6e687bc 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs @@ -1878,6 +1878,32 @@ public void DisableAllFieldObjects_EmptyForms_ThrowsException() Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); } + [TestMethod] + public void DisableAllFieldObjects_NullForms_ThrowsException() + { + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.Forms = null; + Assert.ThrowsException(() => decorator.DisableAllFieldObjects()); + } + + [TestMethod] + public void DisableAllFieldObjects_NullForms_WithExclusionList_ThrowsException() + { + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = new List() + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.Forms = null; + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(new List())); + } + [TestMethod] public void DisableAllFieldObjects_PreservesEntityID() { @@ -2006,5 +2032,93 @@ public void DisableAllFieldObjects_SetsRowActionToEdit() Assert.AreEqual("EDIT", decorator.Forms[0].CurrentRow.RowAction); } + [TestMethod] + public void DisableAllFieldObjects_PreservesExistingRowAction() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "DELETE" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.AreEqual("DELETE", decorator.Forms[0].CurrentRow.RowAction); + } + + [TestMethod] + public void DisableAllFieldObjects_WithNullCurrentRow() + { + var formObject = new FormObject() + { + FormId = "1" + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsNull(decorator.Forms[0].CurrentRow); + } + + [TestMethod] + public void DisableAllFieldObjects_NonMultipleIterationForm() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject], + RowId = "2" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = rowObject, + MultipleIteration = false, + OtherRows = [otherRow] + }; + var optionObject = new OptionObject() + { + OptionId = "TEST123", + Forms = [formObject] + }; + var decorator = new OptionObjectDecorator(optionObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); + Assert.IsTrue(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + } + #endregion } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/RowObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/RowObjectDecoratorTests.cs index 819b5133..1d6494ce 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/RowObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/RowObjectDecoratorTests.cs @@ -484,4 +484,184 @@ public void TestRowObjectDecorator_SetFieldValue_ReturnsExpectedFields() } #endregion + + #region DisableAllFieldObjects + + [TestMethod] + public void DisableAllFieldObjects_NullExclusionList_ThrowsException() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var decorator = new RowObjectDecorator(rowObject); + Assert.ThrowsException(() => decorator.DisableAllFieldObjects(null)); + } + + [TestMethod] + public void DisableAllFieldObjects_DisablesAllFields() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var decorator = new RowObjectDecorator(rowObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.Fields[0].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_ExcludedFieldsRemainEnabled() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject1, fieldObject2], + RowId = "1" + }; + var decorator = new RowObjectDecorator(rowObject); + decorator.DisableAllFieldObjects(new List { "123" }); + Assert.IsTrue(decorator.Fields[0].Enabled); + Assert.IsFalse(decorator.Fields[1].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_MultipleFields() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject3 = new FieldObject() + { + Enabled = "1", + FieldNumber = "125", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject1, fieldObject2, fieldObject3], + RowId = "1" + }; + var decorator = new RowObjectDecorator(rowObject); + decorator.DisableAllFieldObjects(new List { "124" }); + Assert.IsFalse(decorator.Fields[0].Enabled); + Assert.IsTrue(decorator.Fields[1].Enabled); + Assert.IsFalse(decorator.Fields[2].Enabled); + } + + [TestMethod] + public void DisableAllFieldObjects_SetsRowActionToEdit() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "" + }; + var decorator = new RowObjectDecorator(rowObject); + decorator.DisableAllFieldObjects(new List()); + Assert.AreEqual(RowActions.Edit, decorator.RowAction); + } + + [TestMethod] + public void DisableAllFieldObjects_PreservesExistingRowAction() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1", + RowAction = "DELETE" + }; + var decorator = new RowObjectDecorator(rowObject); + decorator.DisableAllFieldObjects(new List()); + Assert.AreEqual("DELETE", decorator.RowAction); + } + + [TestMethod] + public void DisableAllFieldObjects_WithoutExclusionList() + { + var fieldObject = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var rowObject = new RowObject() + { + Fields = [fieldObject], + RowId = "1" + }; + var decorator = new RowObjectDecorator(rowObject); + decorator.DisableAllFieldObjects(); + Assert.IsFalse(decorator.Fields[0].Enabled); + Assert.AreEqual(RowActions.Edit, decorator.RowAction); + } + + #endregion } \ No newline at end of file From dcc9c649356ce2fccff81329fcce5d29475ed07d Mon Sep 17 00:00:00 2001 From: Scott Olson Jr Date: Sat, 14 Feb 2026 08:57:50 -0800 Subject: [PATCH 4/5] address reviewer comments --- .github/instructions/dotnet.instructions.md | 13 ++++++ .../Decorators/FormObjectDecoratorTests.cs | 43 +++++++++++++++++++ .../OptionObject2015DecoratorTests.cs | 2 +- .../Decorators/OptionObject2DecoratorTests.cs | 2 +- .../Decorators/OptionObjectDecoratorTests.cs | 2 +- .../Decorators/FormObjectDecoratorHelper.cs | 7 ++- .../Decorators/RowObjectDecoratorHelper.cs | 11 ++++- .../DisableAllFieldObjectsTests.cs | 28 ++++++++++++ .../OptionObject/DisableAllFieldObjects.cs | 2 + 9 files changed, 101 insertions(+), 9 deletions(-) diff --git a/.github/instructions/dotnet.instructions.md b/.github/instructions/dotnet.instructions.md index 7fc8939d..b8f3f096 100644 --- a/.github/instructions/dotnet.instructions.md +++ b/.github/instructions/dotnet.instructions.md @@ -66,9 +66,22 @@ To provide the broadest compatiblity, the projects target .NET Standard 2.0, all - Avoid catching generic `Exception` types; catch specific exceptions - Log exceptions with sufficient context for troubleshooting +### RowAction Semantics +Understanding RowAction values is critical for proper row state management in ScriptLink operations: +- **RowActions.None** (`""` empty string): No action pending on the row. Use this to indicate that a row should be preserved as-is. When modifying fields in a row with RowAction.None, set it to RowActions.Edit to indicate modification. +- **RowActions.Add** (`"ADD"`): A new row is being added to the form. Preserve this action when modifying the row; do not override with Edit. +- **RowActions.Edit** (`"EDIT"`): An existing row is being modified. Set a row's RowAction to Edit when making field changes on a row that was previously in None state. +- **RowActions.Delete** (`"DELETE"`): The row is marked for removal from the form. Do not change this action even if fields are modified; the row deletion takes precedence. + +When implementing helper methods that modify rows (e.g., `DisableAllFieldObjects`, `SetFieldValue`): +- Only set RowAction to Edit if it's currently None +- Preserve existing RowAction values (Add, Edit, Delete) to avoid overriding the intended operation +- This ensures that a row marked for deletion remains marked for deletion, a row being added retains that intent, etc. + ### Documentation - Include XML documentation for all public types and members - Document non-obvious logic with inline comments +- Explain why certain decisions are made, especially regarding RowAction handling - Include examples in XML documentation for complex methods - Keep documentation up-to-date with code changes - Document breaking changes and migration paths in release notes diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs index be6e9b6a..9add3587 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/FormObjectDecoratorTests.cs @@ -1287,6 +1287,49 @@ public void DisableAllFieldObjects_DisablesFieldsInOtherRowsWhenMultipleIteratio Assert.IsFalse(decorator.OtherRows[0].Fields[0].Enabled); } + [TestMethod] + public void DisableAllFieldObjects_DisablesFieldsInOtherRowsEvenWhenNotMultipleIteration() + { + var fieldObject1 = new FieldObject() + { + Enabled = "1", + FieldNumber = "123", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var fieldObject2 = new FieldObject() + { + Enabled = "1", + FieldNumber = "124", + FieldValue = "test", + Lock = "0", + Required = "0" + }; + var currentRow = new RowObject() + { + Fields = [fieldObject1], + RowId = "1" + }; + var otherRow = new RowObject() + { + Fields = [fieldObject2], + RowId = "2", + ParentRowId = "1" + }; + var formObject = new FormObject() + { + FormId = "1", + CurrentRow = currentRow, + MultipleIteration = false, + OtherRows = [otherRow] + }; + var decorator = new FormObjectDecorator(formObject); + decorator.DisableAllFieldObjects(new List()); + Assert.IsFalse(decorator.CurrentRow.Fields[0].Enabled); + Assert.IsFalse(decorator.OtherRows[0].Fields[0].Enabled); + } + [TestMethod] public void DisableAllFieldObjects_ExcludedFieldsRemainEnabled() { diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs index f972375e..9806780e 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2015DecoratorTests.cs @@ -2101,7 +2101,7 @@ public void DisableAllFieldObjects_NonMultipleIterationForm() var decorator = new OptionObject2015Decorator(optionObject); decorator.DisableAllFieldObjects(); Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); - Assert.IsTrue(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + Assert.IsFalse(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); } #endregion diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs index bfa82925..d6231509 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObject2DecoratorTests.cs @@ -2118,7 +2118,7 @@ public void DisableAllFieldObjects_NonMultipleIterationForm() var decorator = new OptionObject2Decorator(optionObject); decorator.DisableAllFieldObjects(); Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); - Assert.IsTrue(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + Assert.IsFalse(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); } #endregion diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs index e6e687bc..4f974cf6 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net.Tests/Decorators/OptionObjectDecoratorTests.cs @@ -2117,7 +2117,7 @@ public void DisableAllFieldObjects_NonMultipleIterationForm() var decorator = new OptionObjectDecorator(optionObject); decorator.DisableAllFieldObjects(); Assert.IsFalse(decorator.Forms[0].CurrentRow.Fields[0].Enabled); - Assert.IsTrue(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); + Assert.IsFalse(decorator.Forms[0].OtherRows[0].Fields[0].Enabled); } #endregion diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs index 46592655..3a00e590 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/FormObjectDecoratorHelper.cs @@ -436,10 +436,9 @@ public static FormObjectDecorator DisableAllFieldObjects(FormObjectDecorator for formObject.CurrentRow.DisableAllFieldObjects(excludedFields); } - if (formObject.MultipleIteration) - { - formObject.OtherRows.ForEach(r => r.DisableAllFieldObjects(excludedFields)); - } + // Process all OtherRows unconditionally, matching legacy implementation behavior. + // This ensures fields in OtherRows are disabled regardless of the MultipleIteration flag. + formObject.OtherRows.ForEach(r => r.DisableAllFieldObjects(excludedFields)); return formObject; } diff --git a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs index 520ca3e6..d25e8c8b 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Net/Decorators/RowObjectDecoratorHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; @@ -199,7 +200,7 @@ public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowOb { if (rowObject == null) throw new ArgumentNullException(nameof(rowObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); - return DisableAllFieldObjects(rowObject, new System.Collections.Generic.List()); + return DisableAllFieldObjects(rowObject, new List()); } /// /// Disables all in the , except for the FieldNumbers specified in the list. @@ -207,7 +208,7 @@ public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowOb /// /// /// - public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowObject, System.Collections.Generic.List excludedFields) + public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowObject, List excludedFields) { if (rowObject == null) throw new ArgumentNullException(nameof(rowObject), resourceManager.GetString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); @@ -219,6 +220,12 @@ public static RowObjectDecorator DisableAllFieldObjects(RowObjectDecorator rowOb field.Enabled = false; } + // Only set RowAction to Edit if it's currently None (no action). + // This preserves existing RowActions like DELETE, ADD, or EDIT: + // - RowActions.None: No action pending (preserve the row; enable Edit mode) + // - RowActions.Add: Adding a new row to the form (don't override) + // - RowActions.Edit: Modifying an existing row (don't override) + // - RowActions.Delete: Removing the row (don't override) if (rowObject.RowAction == RowActions.None) rowObject.RowAction = RowActions.Edit; diff --git a/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs b/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs index b822b1e0..84920ea7 100644 --- a/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs +++ b/dotnet/RarelySimple.AvatarScriptLink.Tests/Helpers/OptionObject/DisableAllFieldObjectsTests.cs @@ -103,6 +103,34 @@ public void DisableAllFieldObjects_OptionObject_Null() Assert.ThrowsException(() => (OptionObject)OptionObjectHelpers.DisableAllFieldObjects(null)); } + [TestMethod] + [TestCategory("ScriptLinkHelpers")] + public void DisableAllFieldObjects_OptionObject_NullForms_Throws() + { + var invalidOptionObject = new OptionObject + { + EntityID = "123456", + EpisodeNumber = 1, + OptionId = "USER00", + Forms = null + }; + Assert.ThrowsException(() => (OptionObject)OptionObjectHelpers.DisableAllFieldObjects(invalidOptionObject)); + } + + [TestMethod] + [TestCategory("ScriptLinkHelpers")] + public void DisableAllFieldObjects_OptionObject_NullForms_WithExcludedFields_Throws() + { + var invalidOptionObject = new OptionObject + { + EntityID = "123456", + EpisodeNumber = 1, + OptionId = "USER00", + Forms = null + }; + Assert.ThrowsException(() => (OptionObject)OptionObjectHelpers.DisableAllFieldObjects(invalidOptionObject, new List())); + } + [TestMethod] [TestCategory("ScriptLinkHelpers")] public void DisableAllFieldObjects_OptionObject_EntityID_AreEqual() diff --git a/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs b/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs index 78a3c6cf..66c5d1af 100644 --- a/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs +++ b/dotnet/RarelySimple.AvatarScriptLink/Helpers/OptionObject/DisableAllFieldObjects.cs @@ -29,6 +29,8 @@ public static IOptionObject DisableAllFieldObjects(IOptionObject optionObject, L { if (optionObject == null) throw new ArgumentNullException(nameof(optionObject), ScriptLinkHelpers.GetLocalizedString(ParameterCannotBeNull, CultureInfo.CurrentCulture)); + if (optionObject.Forms == null) + throw new ArgumentNullException(nameof(optionObject), ScriptLinkHelpers.GetLocalizedString("optionObjectMissingForms", CultureInfo.CurrentCulture)); if (optionObject.Forms.Count == 0) throw new ArgumentException(ScriptLinkHelpers.GetLocalizedString("optionObjectMissingForms", CultureInfo.CurrentCulture), nameof(optionObject)); if (excludedFields == null) From f347d416e05a55b358ba85690006572d47a0c344 Mon Sep 17 00:00:00 2001 From: Scott Olson Jr Date: Sat, 14 Feb 2026 13:00:21 -0800 Subject: [PATCH 5/5] Enhance RowAction semantics in documentation for clarity on response payload inclusion --- .github/instructions/dotnet.instructions.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/instructions/dotnet.instructions.md b/.github/instructions/dotnet.instructions.md index b8f3f096..521f63d1 100644 --- a/.github/instructions/dotnet.instructions.md +++ b/.github/instructions/dotnet.instructions.md @@ -67,16 +67,16 @@ To provide the broadest compatiblity, the projects target .NET Standard 2.0, all - Log exceptions with sufficient context for troubleshooting ### RowAction Semantics -Understanding RowAction values is critical for proper row state management in ScriptLink operations: -- **RowActions.None** (`""` empty string): No action pending on the row. Use this to indicate that a row should be preserved as-is. When modifying fields in a row with RowAction.None, set it to RowActions.Edit to indicate modification. -- **RowActions.Add** (`"ADD"`): A new row is being added to the form. Preserve this action when modifying the row; do not override with Edit. -- **RowActions.Edit** (`"EDIT"`): An existing row is being modified. Set a row's RowAction to Edit when making field changes on a row that was previously in None state. -- **RowActions.Delete** (`"DELETE"`): The row is marked for removal from the form. Do not change this action even if fields are modified; the row deletion takes precedence. +Understanding RowAction values is critical for proper row state management in ScriptLink operations. The RowAction determines which rows are included in the response payload sent back to myAvatar: +- **RowActions.None** (`""` empty string or `null`): No action pending on the row. Both empty string and null are treated equivalently as None. Rows with RowAction.None are **excluded from the response payload** and not sent back to myAvatar, effectively preserving them as-is. When modifying fields in a row initially in None state, set it to RowActions.Edit to include it in the response payload. +- **RowActions.Add** (`"ADD"`): A new row is being added to the form. This row **is included in the response payload** to instruct myAvatar to add it. Preserve this action when modifying the row; do not override with Edit. +- **RowActions.Edit** (`"EDIT"`): An existing row is being modified. This row **is included in the response payload** to instruct myAvatar to update it. Set a row's RowAction to Edit when making field changes on a row that was previously in None state to ensure the modifications are sent to myAvatar. +- **RowActions.Delete** (`"DELETE"`): The row is marked for removal from the form. This row **is included in the response payload** to instruct myAvatar to delete it. Do not change this action even if fields are modified; the row deletion takes precedence. When implementing helper methods that modify rows (e.g., `DisableAllFieldObjects`, `SetFieldValue`): -- Only set RowAction to Edit if it's currently None +- Only set RowAction to Edit if it's currently None (use `string.IsNullOrEmpty()` to check for None), so the modified row is included in the response payload - Preserve existing RowAction values (Add, Edit, Delete) to avoid overriding the intended operation -- This ensures that a row marked for deletion remains marked for deletion, a row being added retains that intent, etc. +- This ensures that a row marked for deletion remains marked for deletion, a row being added retains that intent, and rows with no changes are not unnecessarily included in the response ### Documentation - Include XML documentation for all public types and members