Index: Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Service/ClosingStructuresDataSynchronizationService.cs =================================================================== diff -u -rac8798cf0a66cf04df1294d4fd08e0b1915a5b91 -r916bdbd134da55d8f1373fea9b29aba97db34348 --- Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Service/ClosingStructuresDataSynchronizationService.cs (.../ClosingStructuresDataSynchronizationService.cs) (revision ac8798cf0a66cf04df1294d4fd08e0b1915a5b91) +++ Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Service/ClosingStructuresDataSynchronizationService.cs (.../ClosingStructuresDataSynchronizationService.cs) (revision 916bdbd134da55d8f1373fea9b29aba97db34348) @@ -25,6 +25,8 @@ using System.Linq; using Core.Common.Base; using Ringtoets.ClosingStructures.Data; +using Ringtoets.ClosingStructures.Util; +using Ringtoets.Common.Data; using Ringtoets.Common.Data.Calculation; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.Structures; @@ -38,6 +40,47 @@ public static class ClosingStructuresDataSynchronizationService { /// + /// Removes the , unassigns it from the calculations in + /// and clears all dependent data, either directly or indirectly. + /// + /// The structure to be removed. + /// The + /// to clear the data from. + /// All objects affected by the removal. + /// Thrown when any parameter is null. + public static IEnumerable RemoveStructure(ClosingStructure structure, + ClosingStructuresFailureMechanism failureMechanism) + { + if (structure == null) + { + throw new ArgumentNullException(nameof(structure)); + } + + if (failureMechanism == null) + { + throw new ArgumentNullException(nameof(failureMechanism)); + } + + IEnumerable> calculations = + failureMechanism.Calculations.Cast>(); + + StructuresCalculation[] calculationWithRemovedStructure = calculations + .Where(c => ReferenceEquals(c.InputParameters.Structure, structure)) + .ToArray(); + + List changedObservables = ClearStructureDependentData( + failureMechanism.SectionResults2, + calculationWithRemovedStructure, + calculations); + + StructureCollection structures = failureMechanism.ClosingStructures; + structures.Remove(structure); + changedObservables.Add(structures); + + return changedObservables; + } + + /// /// Clears the output for all calculations in the . /// /// The @@ -133,7 +176,28 @@ input }; } + return Enumerable.Empty(); } + + private static List ClearStructureDependentData(IEnumerable sectionResults, + IEnumerable> calculationWithRemovedStructure, + IEnumerable> structureCalculations) + { + var changedObservables = new List(); + foreach (StructuresCalculation calculation in calculationWithRemovedStructure) + { + changedObservables.AddRange(RingtoetsCommonDataSynchronizationService.ClearCalculationOutput(calculation)); + + calculation.InputParameters.ClearStructure(); + changedObservables.Add(calculation.InputParameters); + } + + IEnumerable affectedSectionResults = + ClosingStructuresHelper.UpdateCalculationToSectionResultAssignments(sectionResults, structureCalculations); + + changedObservables.AddRange(affectedSectionResults); + return changedObservables; + } } } \ No newline at end of file Index: Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Service/Ringtoets.ClosingStructures.Service.csproj =================================================================== diff -u -r63fc151e9cf722527465c1eddfa6567a90feb5e6 -r916bdbd134da55d8f1373fea9b29aba97db34348 --- Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Service/Ringtoets.ClosingStructures.Service.csproj (.../Ringtoets.ClosingStructures.Service.csproj) (revision 63fc151e9cf722527465c1eddfa6567a90feb5e6) +++ Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Service/Ringtoets.ClosingStructures.Service.csproj (.../Ringtoets.ClosingStructures.Service.csproj) (revision 916bdbd134da55d8f1373fea9b29aba97db34348) @@ -64,6 +64,11 @@ Ringtoets.ClosingStructures.Forms False + + {673b4a0b-96b1-4e98-bb49-e3c7bcb5f179} + Ringtoets.ClosingStructures.Util + False + Index: Ringtoets/ClosingStructures/test/Ringtoets.ClosingStructures.Service.Test/ClosingStructureDataSynchronizationServiceTest.cs =================================================================== diff -u -rac8798cf0a66cf04df1294d4fd08e0b1915a5b91 -r916bdbd134da55d8f1373fea9b29aba97db34348 --- Ringtoets/ClosingStructures/test/Ringtoets.ClosingStructures.Service.Test/ClosingStructureDataSynchronizationServiceTest.cs (.../ClosingStructureDataSynchronizationServiceTest.cs) (revision ac8798cf0a66cf04df1294d4fd08e0b1915a5b91) +++ Ringtoets/ClosingStructures/test/Ringtoets.ClosingStructures.Service.Test/ClosingStructureDataSynchronizationServiceTest.cs (.../ClosingStructureDataSynchronizationServiceTest.cs) (revision 916bdbd134da55d8f1373fea9b29aba97db34348) @@ -40,6 +40,131 @@ public class ClosingStructuresDataSynchronizationServiceTest { [Test] + public void RemoveStructure_StructureNull_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => ClosingStructuresDataSynchronizationService.RemoveStructure( + null, + new ClosingStructuresFailureMechanism()); + + // Assert + var exception = Assert.Throws(test); + Assert.AreEqual("structure", exception.ParamName); + } + + [Test] + public void RemoveStructure_FailureMechanismNull_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => ClosingStructuresDataSynchronizationService.RemoveStructure( + new TestClosingStructure(), + null); + + // Assert + var exception = Assert.Throws(test); + Assert.AreEqual("failureMechanism", exception.ParamName); + } + + [Test] + public void RemoveStructure_FullyConfiguredFailureMechanism_RemovesStructureAndClearsDependentData() + { + // Setup + var failureMechanism = new ClosingStructuresFailureMechanism(); + + var locationStructureToRemove = new Point2D(0, 0); + var structureToRemove = new TestClosingStructure(locationStructureToRemove, "id1"); + + var locationStructureToKeep = new Point2D(2, 2); + var structureToKeep = new TestClosingStructure(locationStructureToKeep, "id2"); + + failureMechanism.ClosingStructures.AddRange(new[] + { + structureToRemove, + structureToKeep + }, "path/to/structures"); + + var calculationWithOutput = new TestClosingStructuresCalculation + { + Output = new TestStructuresOutput() + }; + var calculationWithStructureToRemove = new TestClosingStructuresCalculation + { + InputParameters = + { + Structure = structureToRemove + } + }; + var calculationWithStructureToKeepAndOutput = new TestClosingStructuresCalculation + { + InputParameters = + { + Structure = structureToKeep + }, + Output = new TestStructuresOutput() + }; + var calculationWithStructureToRemoveAndOutput = new TestClosingStructuresCalculation + { + InputParameters = + { + Structure = structureToRemove + }, + Output = new TestStructuresOutput() + }; + failureMechanism.CalculationsGroup.Children.AddRange(new[] + { + calculationWithOutput, + calculationWithStructureToRemove, + calculationWithStructureToKeepAndOutput, + calculationWithStructureToRemoveAndOutput + }); + + var affectedSection = new FailureMechanismSection(string.Empty, new[] + { + new Point2D(0, 0), + new Point2D(1, 1) + }); + failureMechanism.AddSection(affectedSection); + ClosingStructuresFailureMechanismSectionResult sectionWithCalculationAtStructureToRemove = failureMechanism.SectionResults2.ElementAt(0); + sectionWithCalculationAtStructureToRemove.Calculation = calculationWithStructureToRemove; + + var unaffectedSection = new FailureMechanismSection(string.Empty, new[] + { + new Point2D(1, 1), + new Point2D(2, 2) + }); + failureMechanism.AddSection(unaffectedSection); + ClosingStructuresFailureMechanismSectionResult sectionWithCalculationAtStructureToKeep = failureMechanism.SectionResults2.ElementAt(1); + sectionWithCalculationAtStructureToKeep.Calculation = calculationWithStructureToKeepAndOutput; + + // Call + IEnumerable affectedObjects = ClosingStructuresDataSynchronizationService.RemoveStructure( + structureToRemove, failureMechanism); + + // Assert + // Note: To make sure the clear is performed regardless of what is done with + // the return result, no ToArray() should be called before these assertions: + CollectionAssert.DoesNotContain(failureMechanism.ClosingStructures, structureToRemove); + Assert.IsNull(calculationWithStructureToRemove.InputParameters.Structure); + Assert.IsNull(calculationWithStructureToRemoveAndOutput.InputParameters.Structure); + Assert.IsNull(calculationWithStructureToRemoveAndOutput.Output); + Assert.IsNull(sectionWithCalculationAtStructureToRemove.Calculation); + Assert.IsNotNull(calculationWithOutput.Output); + Assert.IsNotNull(calculationWithStructureToKeepAndOutput.Output); + Assert.IsNotNull(calculationWithStructureToKeepAndOutput.InputParameters.Structure); + Assert.AreSame(sectionWithCalculationAtStructureToKeep.Calculation, calculationWithStructureToKeepAndOutput); + + IObservable[] expectedAffectedObjects = + { + calculationWithStructureToRemove.InputParameters, + calculationWithStructureToRemoveAndOutput, + calculationWithStructureToRemoveAndOutput.InputParameters, + sectionWithCalculationAtStructureToRemove, + failureMechanism.ClosingStructures + }; + CollectionAssert.AreEquivalent(expectedAffectedObjects, affectedObjects); + } + + [Test] public void ClearAllCalculationOutput_FailureMechanismNull_ThrowsArgumentNullException() { // Call