Index: Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Plugin/FileImporters/ClosingStructureReplaceDataStrategy.cs =================================================================== diff -u -r12cec002453a1828efc68633fbd25219632c6c47 -r3ce69e451a97f622288b172d1dcef1ac3fbc9bc1 --- Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Plugin/FileImporters/ClosingStructureReplaceDataStrategy.cs (.../ClosingStructureReplaceDataStrategy.cs) (revision 12cec002453a1828efc68633fbd25219632c6c47) +++ Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Plugin/FileImporters/ClosingStructureReplaceDataStrategy.cs (.../ClosingStructureReplaceDataStrategy.cs) (revision 3ce69e451a97f622288b172d1dcef1ac3fbc9bc1) @@ -24,14 +24,9 @@ using System.Linq; using Core.Common.Base; using Ringtoets.Common.Data; -using Ringtoets.Common.Data.Exceptions; using Ringtoets.Common.Data.UpdateDataStrategies; -using Ringtoets.Common.IO.Exceptions; -using Ringtoets.Common.IO.Properties; using Ringtoets.Common.IO.Structures; using Ringtoets.ClosingStructures.Data; -using Ringtoets.ClosingStructures.Service; -using Ringtoets.Common.Data.FailureMechanism; using Ringtoets.Common.Data.Structures; using Ringtoets.Common.Service; Index: Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Plugin/FileImporters/ClosingStructureUpdateDataStrategy.cs =================================================================== diff -u -r12cec002453a1828efc68633fbd25219632c6c47 -r3ce69e451a97f622288b172d1dcef1ac3fbc9bc1 --- Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Plugin/FileImporters/ClosingStructureUpdateDataStrategy.cs (.../ClosingStructureUpdateDataStrategy.cs) (revision 12cec002453a1828efc68633fbd25219632c6c47) +++ Ringtoets/ClosingStructures/src/Ringtoets.ClosingStructures.Plugin/FileImporters/ClosingStructureUpdateDataStrategy.cs (.../ClosingStructureUpdateDataStrategy.cs) (revision 3ce69e451a97f622288b172d1dcef1ac3fbc9bc1) @@ -24,16 +24,12 @@ using System.Linq; using Core.Common.Base; using Ringtoets.Common.Data; -using Ringtoets.Common.Data.Exceptions; using Ringtoets.Common.Data.Structures; using Ringtoets.Common.Data.UpdateDataStrategies; -using Ringtoets.Common.IO.Exceptions; -using Ringtoets.Common.IO.Properties; using Ringtoets.Common.IO.Structures; using Ringtoets.Common.Service; using Ringtoets.Common.Utils; using Ringtoets.ClosingStructures.Data; -using Ringtoets.ClosingStructures.Service; namespace Ringtoets.ClosingStructures.Plugin.FileImporters { Index: Ringtoets/Common/test/Ringtoets.Common.Service.Test/Ringtoets.Common.Service.Test.csproj =================================================================== diff -u -r8aeff3f1153aaac2b2980ca207e298b6d764947b -r3ce69e451a97f622288b172d1dcef1ac3fbc9bc1 --- Ringtoets/Common/test/Ringtoets.Common.Service.Test/Ringtoets.Common.Service.Test.csproj (.../Ringtoets.Common.Service.Test.csproj) (revision 8aeff3f1153aaac2b2980ca207e298b6d764947b) +++ Ringtoets/Common/test/Ringtoets.Common.Service.Test/Ringtoets.Common.Service.Test.csproj (.../Ringtoets.Common.Service.Test.csproj) (revision 3ce69e451a97f622288b172d1dcef1ac3fbc9bc1) @@ -116,6 +116,10 @@ {D951D6DA-FE83-4920-9FDB-63BF96480B54} Ringtoets.Common.Service + + {6A074D65-A81C-4C1C-8E24-F36C916E4ED7} + Ringtoets.Common.Utils + {4843D6E5-066F-4795-94F5-1D53932DD03C} Ringtoets.Common.Data.TestUtil Index: Ringtoets/Common/test/Ringtoets.Common.Service.Test/RingtoetsCommonDataSynchronizationServicesTest.cs =================================================================== diff -u -rb3b6c13cf736c134476b3db34281332d01ca86b1 -r3ce69e451a97f622288b172d1dcef1ac3fbc9bc1 --- Ringtoets/Common/test/Ringtoets.Common.Service.Test/RingtoetsCommonDataSynchronizationServicesTest.cs (.../RingtoetsCommonDataSynchronizationServicesTest.cs) (revision b3b6c13cf736c134476b3db34281332d01ca86b1) +++ Ringtoets/Common/test/Ringtoets.Common.Service.Test/RingtoetsCommonDataSynchronizationServicesTest.cs (.../RingtoetsCommonDataSynchronizationServicesTest.cs) (revision 3ce69e451a97f622288b172d1dcef1ac3fbc9bc1) @@ -26,10 +26,13 @@ using NUnit.Framework; using Ringtoets.Common.Data; using Ringtoets.Common.Data.Calculation; +using Ringtoets.Common.Data.FailureMechanism; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.Probability; using Ringtoets.Common.Data.Structures; using Ringtoets.Common.Data.TestUtil; +using Ringtoets.Common.Utils; +using Enumerable = System.Linq.Enumerable; namespace Ringtoets.Common.Service.Test { @@ -217,6 +220,240 @@ }, affectedObjects); } + [Test] + public void RemoveStructure_FullyConfiguredFailureMechanism_RemovesStructureAndClearsDependentData() + { + // Setup + var locationStructureToRemove = new Point2D(0, 0); + var locationStructureToKeep = new Point2D(5, 5); + + var structureToRemove = new TestStructure("ToRemove", locationStructureToRemove); + var structureToKeep = new TestStructure("ToKeep", locationStructureToKeep); + + var structures = new StructureCollection(); + structures.AddRange(new[] + { + structureToRemove, + structureToKeep + }, "path/to/structures"); + var calculationWithOutput = new StructuresCalculation + { + Output = new ProbabilityAssessmentOutput(0, 0, 0, 0, 0) + }; + var calculationWithStructureToRemove = new StructuresCalculation + { + InputParameters = + { + Structure = structureToRemove + } + }; + var calculationWithStructureToKeepAndOutput = new StructuresCalculation + { + InputParameters = + { + Structure = structureToKeep + }, + Output = new ProbabilityAssessmentOutput(0, 0, 0, 0, 0) + }; + var calculationWithStructureToRemoveAndOutput = new StructuresCalculation + { + InputParameters = + { + Structure = structureToRemove + }, + Output = new ProbabilityAssessmentOutput(0, 0, 0, 0, 0) + }; + StructuresCalculation[] calculations = + { + calculationWithOutput, + calculationWithStructureToRemove, + calculationWithStructureToKeepAndOutput, + calculationWithStructureToRemoveAndOutput + }; + var sectionWithCalculationAtStructureToRemove = new TestSectionResult(locationStructureToRemove) + { + Calculation = calculationWithStructureToRemove + }; + var sectionWithCalculationAtStructureToKeep = new TestSectionResult(locationStructureToKeep) + { + Calculation = calculationWithStructureToKeepAndOutput + }; + StructuresFailureMechanismSectionResult[] sectionResults = + { + sectionWithCalculationAtStructureToRemove, + sectionWithCalculationAtStructureToKeep + }; + + // Call + IEnumerable affectedObjects = RingtoetsCommonDataSynchronizationService.RemoveStructure( + structureToRemove, + calculations, + structures, + sectionResults); + + // 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(structures, 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, + structures + }; + CollectionAssert.AreEquivalent(expectedAffectedObjects, affectedObjects); + } + + [Test] + public void RemoveAllStructures_CalculationsNull_ThrowsArgumentNullException() + { + // Call + TestDelegate call = () => RingtoetsCommonDataSynchronizationService.RemoveAllStructures( + null, + new StructureCollection(), + Enumerable.Empty>()); + + // Assert + string paramName = Assert.Throws(call).ParamName; + Assert.AreEqual("calculations", paramName); + } + + [Test] + public void RemoveAllStructures_StructuresNull_ThrowsArgumentNullException() + { + // Call + TestDelegate call = () => RingtoetsCommonDataSynchronizationService.RemoveAllStructures( + Enumerable.Empty>(), + null, + Enumerable.Empty>()); + + // Assert + string paramName = Assert.Throws(call).ParamName; + Assert.AreEqual("structures", paramName); + } + + [Test] + public void RemoveAllStructures_SectionResultsNull_ThrowsArgumentNullException() + { + // Call + TestDelegate call = () => RingtoetsCommonDataSynchronizationService.RemoveAllStructures( + Enumerable.Empty>(), + new StructureCollection(), + null); + + // Assert + string paramName = Assert.Throws(call).ParamName; + Assert.AreEqual("sectionResults", paramName); + } + + [Test] + public void RemoveAllStructures_FullyConfiguredFailureMechanism_RemoveAllHeightStructuresAndClearDependentData() + { + // Setup + var locationStructureA = new Point2D(0, 0); + var locationStructureB = new Point2D(5, 5); + + var structureA = new TestStructure("A", locationStructureA); + var structureB = new TestStructure("B", locationStructureB); + + var structures = new StructureCollection(); + structures.AddRange(new[] + { + structureA, + structureB + }, "path/to/structures"); + var calculationWithOutput = new StructuresCalculation + { + Output = new ProbabilityAssessmentOutput(0, 0, 0, 0, 0) + }; + var calculationWithStructureA = new StructuresCalculation + { + InputParameters = + { + Structure = structureA + } + }; + var calculationWithStructureBAndOutput = new StructuresCalculation + { + InputParameters = + { + Structure = structureB + }, + Output = new ProbabilityAssessmentOutput(0, 0, 0, 0, 0) + }; + var calculationWithStructureAAndOutput = new StructuresCalculation + { + InputParameters = + { + Structure = structureA + }, + Output = new ProbabilityAssessmentOutput(0, 0, 0, 0, 0) + }; + StructuresCalculation[] calculations = + { + calculationWithOutput, + calculationWithStructureA, + calculationWithStructureBAndOutput, + calculationWithStructureAAndOutput + }; + var sectionWithCalculationAtStructureA = new TestSectionResult(locationStructureA) + { + Calculation = calculationWithStructureA + }; + var sectionWithCalculationAtStructureB = new TestSectionResult(locationStructureB) + { + Calculation = calculationWithStructureBAndOutput + }; + StructuresFailureMechanismSectionResult[] sectionResults = + { + sectionWithCalculationAtStructureA, + sectionWithCalculationAtStructureB + }; + + // Call + IEnumerable affectedObjects = RingtoetsCommonDataSynchronizationService.RemoveAllStructures( + calculations, + structures, + sectionResults); + + // 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(structures, structureA); + Assert.IsNull(calculationWithStructureA.InputParameters.Structure); + Assert.IsNull(calculationWithStructureAAndOutput.InputParameters.Structure); + Assert.IsNull(calculationWithStructureBAndOutput.InputParameters.Structure); + Assert.IsNull(calculationWithStructureAAndOutput.Output); + Assert.IsNull(calculationWithStructureBAndOutput.Output); + Assert.IsNull(sectionWithCalculationAtStructureA.Calculation); + Assert.IsNull(sectionWithCalculationAtStructureB.Calculation); + Assert.IsNotNull(calculationWithOutput.Output); + + IObservable[] expectedAffectedObjects = + { + calculationWithStructureA.InputParameters, + calculationWithStructureAAndOutput, + calculationWithStructureAAndOutput.InputParameters, + calculationWithStructureBAndOutput, + calculationWithStructureBAndOutput.InputParameters, + sectionWithCalculationAtStructureA, + sectionWithCalculationAtStructureB, + structures + }; + CollectionAssert.AreEquivalent(expectedAffectedObjects, affectedObjects); + } + private class TestInput : ICalculationInput { public void Attach(IObserver observer) @@ -240,4 +477,28 @@ protected override void UpdateStructureParameters() {} } } + + public class TestSectionResult : StructuresFailureMechanismSectionResult + { + public TestSectionResult(Point2D point2D) : base(new FailureMechanismSection($"Location {point2D}", new[] + { + point2D, + point2D + })) {} + } + + public class TestStructureInput : StructuresInputBase + { + protected override void UpdateStructureParameters() {} + } + + public class TestStructure : StructureBase + { + public TestStructure(string id, Point2D location) : base(new ConstructionProperties + { + Name = $"{id} name", + Id = id, + Location = location + }) {} + } } \ No newline at end of file Index: Ringtoets/HeightStructures/src/Ringtoets.HeightStructures.Service/HeightStructuresDataSynchronizationService.cs =================================================================== diff -u -r12cec002453a1828efc68633fbd25219632c6c47 -r3ce69e451a97f622288b172d1dcef1ac3fbc9bc1 --- Ringtoets/HeightStructures/src/Ringtoets.HeightStructures.Service/HeightStructuresDataSynchronizationService.cs (.../HeightStructuresDataSynchronizationService.cs) (revision 12cec002453a1828efc68633fbd25219632c6c47) +++ Ringtoets/HeightStructures/src/Ringtoets.HeightStructures.Service/HeightStructuresDataSynchronizationService.cs (.../HeightStructuresDataSynchronizationService.cs) (revision 3ce69e451a97f622288b172d1dcef1ac3fbc9bc1) @@ -23,12 +23,10 @@ using System.Collections.Generic; using System.Linq; using Core.Common.Base; -using Ringtoets.Common.Data; using Ringtoets.Common.Data.Calculation; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.Structures; using Ringtoets.Common.Service; -using Ringtoets.Common.Utils; using Ringtoets.HeightStructures.Data; namespace Ringtoets.HeightStructures.Service Index: Ringtoets/HeightStructures/test/Ringtoets.HeightStructures.Service.Test/HeightStructuresDataSynchronizationServiceTest.cs =================================================================== diff -u -r12cec002453a1828efc68633fbd25219632c6c47 -r3ce69e451a97f622288b172d1dcef1ac3fbc9bc1 --- Ringtoets/HeightStructures/test/Ringtoets.HeightStructures.Service.Test/HeightStructuresDataSynchronizationServiceTest.cs (.../HeightStructuresDataSynchronizationServiceTest.cs) (revision 12cec002453a1828efc68633fbd25219632c6c47) +++ Ringtoets/HeightStructures/test/Ringtoets.HeightStructures.Service.Test/HeightStructuresDataSynchronizationServiceTest.cs (.../HeightStructuresDataSynchronizationServiceTest.cs) (revision 3ce69e451a97f622288b172d1dcef1ac3fbc9bc1) @@ -308,169 +308,6 @@ CollectionAssert.AreEquivalent(expectedRemovedObjects, results.RemovedObjects); } - [Test] - public void RemoveHeightStructure_FullyConfiguredFailureMechanism_RemovesStructureAndClearsDependentData() - { - // Setup - HeightStructuresFailureMechanism failureMechanism = CreateFullyConfiguredFailureMechanism(); - HeightStructure structure = failureMechanism.HeightStructures[0]; - StructuresCalculation[] calculationsWithStructure = failureMechanism.Calculations - .Cast>() - .Where(c => ReferenceEquals(c.InputParameters.Structure, structure)) - .ToArray(); - HeightStructuresFailureMechanismSectionResult[] sectionResultsWithStructure = failureMechanism.SectionResults - .Where(sr => calculationsWithStructure.Contains(sr.Calculation)) - .ToArray(); - StructuresCalculation[] calculationsWithOutput = calculationsWithStructure.Where(c => c.HasOutput) - .ToArray(); - - int originalNumberOfSectionResultAssignments = failureMechanism.SectionResults.Count(sr => sr.Calculation != null); - HeightStructuresFailureMechanismSectionResult[] sectionResults = failureMechanism.SectionResults - .Where(sr => calculationsWithStructure.Contains(sr.Calculation)) - .ToArray(); - - // Precondition - CollectionAssert.IsNotEmpty(calculationsWithOutput); - CollectionAssert.IsNotEmpty(calculationsWithStructure); - CollectionAssert.IsNotEmpty(sectionResultsWithStructure); - - // Call - IEnumerable affectedObjects = RingtoetsCommonDataSynchronizationService.RemoveStructure( - structure, - failureMechanism.Calculations.Cast>(), - failureMechanism.HeightStructures, - failureMechanism.SectionResults); - - // 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.HeightStructures, structure); - foreach (StructuresCalculation calculation in calculationsWithStructure) - { - Assert.IsNull(calculation.InputParameters.Structure); - } - foreach (StructuresCalculation calculation in calculationsWithOutput) - { - Assert.IsFalse(calculation.HasOutput); - } - foreach (HeightStructuresFailureMechanismSectionResult sectionResult in sectionResultsWithStructure) - { - Assert.IsNull(sectionResult.Calculation); - } - - IObservable[] array = affectedObjects.ToArray(); - Assert.AreEqual(1 + calculationsWithOutput.Length + calculationsWithStructure.Length + sectionResultsWithStructure.Length, - array.Length); - CollectionAssert.Contains(array, failureMechanism.HeightStructures); - foreach (StructuresCalculation calculation in calculationsWithStructure) - { - CollectionAssert.Contains(array, calculation.InputParameters); - } - foreach (StructuresCalculation calculation in calculationsWithOutput) - { - CollectionAssert.Contains(array, calculation); - } - foreach (HeightStructuresFailureMechanismSectionResult result in sectionResultsWithStructure) - { - CollectionAssert.Contains(array, result); - } - Assert.AreEqual(originalNumberOfSectionResultAssignments - sectionResults.Length, failureMechanism.SectionResults.Count(sr => sr.Calculation != null), - "Other section results with a different calculation/structure should still have their association."); - } - - [Test] - public void RemoveAllStructures_CalculationsNull_ThrowsArgumentNullException() - { - // Call - TestDelegate call = () => RingtoetsCommonDataSynchronizationService.RemoveAllStructures( - null, - new StructureCollection(), - Enumerable.Empty>()); - - // Assert - string paramName = Assert.Throws(call).ParamName; - Assert.AreEqual("calculations", paramName); - } - - [Test] - public void RemoveAllStructures_StructuresNull_ThrowsArgumentNullException() - { - // Call - TestDelegate call = () => RingtoetsCommonDataSynchronizationService.RemoveAllStructures( - Enumerable.Empty>(), - null, - Enumerable.Empty>()); - - // Assert - string paramName = Assert.Throws(call).ParamName; - Assert.AreEqual("structures", paramName); - } - - [Test] - public void RemoveAllStructures_SectionResultsNull_ThrowsArgumentNullException() - { - // Call - TestDelegate call = () => RingtoetsCommonDataSynchronizationService.RemoveAllStructures( - Enumerable.Empty>(), - new StructureCollection(), - null); - - // Assert - string paramName = Assert.Throws(call).ParamName; - Assert.AreEqual("sectionResults", paramName); - } - - [Test] - public void RemoveAllStructures_FullyConfiguredFailureMechanism_RemoveAllHeightStructuresAndClearDependentData() - { - // Setup - HeightStructuresFailureMechanism failureMechanism = CreateFullyConfiguredFailureMechanism(); - StructuresCalculation[] calculationsWithStructure = failureMechanism.Calculations - .Cast>() - .Where(calc => calc.InputParameters.Structure != null) - .ToArray(); - StructuresCalculation[] calculationsWithOutput = calculationsWithStructure.Where(c => c.HasOutput) - .ToArray(); - - HeightStructuresFailureMechanismSectionResult[] sectionResultsWithStructure = failureMechanism.SectionResults - .Where(sr => calculationsWithStructure.Contains(sr.Calculation)) - .ToArray(); - - // Precondition - CollectionAssert.IsNotEmpty(calculationsWithStructure); - - // Call - IEnumerable observables = RingtoetsCommonDataSynchronizationService.RemoveAllStructures( - failureMechanism.Calculations.Cast>(), - failureMechanism.HeightStructures, - failureMechanism.SectionResults); - - // 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.IsEmpty(failureMechanism.HeightStructures); - foreach (StructuresCalculation calculation in calculationsWithStructure) - { - Assert.IsNull(calculation.InputParameters.Structure); - } - - foreach (StructuresCalculation calculation in calculationsWithOutput) - { - Assert.IsFalse(calculation.HasOutput); - } - - IEnumerable expectedAffectedObjects = - calculationsWithStructure.Select(calc => calc.InputParameters) - .Cast() - .Concat(calculationsWithOutput) - .Concat(sectionResultsWithStructure) - .Concat(new IObservable[] - { - failureMechanism.HeightStructures - }); - CollectionAssert.AreEquivalent(expectedAffectedObjects, observables); - } - private HeightStructuresFailureMechanism CreateFullyConfiguredFailureMechanism() { var section1 = new FailureMechanismSection("A", new[]