Index: Riskeer/Revetment/src/Riskeer.Revetment.Service/WaveConditionsDataSynchronizationService.cs =================================================================== diff -u --- Riskeer/Revetment/src/Riskeer.Revetment.Service/WaveConditionsDataSynchronizationService.cs (revision 0) +++ Riskeer/Revetment/src/Riskeer.Revetment.Service/WaveConditionsDataSynchronizationService.cs (revision 4da2af82acf0b1d6ce385c124f871e34d9373021) @@ -0,0 +1,141 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using Core.Common.Base; +using Riskeer.Common.Data.Calculation; +using Riskeer.Common.Data.Contribution; +using Riskeer.Common.Data.FailureMechanism; +using Riskeer.Common.Data.Hydraulics; +using Riskeer.Common.Service; +using Riskeer.Revetment.Data; + +namespace Riskeer.Revetment.Service +{ + /// + /// Service for synchronizing wave conditions data. + /// + public static class WaveConditionsDataSynchronizationService + { + /// + /// Clears the output for all calculations that corresponds with the + /// in the given . + /// + /// The failure mechanism which contains the calculations. + /// The to clear for. + /// The type of the failure mechanism. + /// The type of the calculation. + /// An of calculations which are affected by clearing the output. + /// Thrown when is null. + /// Thrown when is invalid. + /// Thrown when is not supported. + public static IEnumerable ClearAllWaveConditionsCalculationOutput( + TFailureMechanism failureMechanism, NormType normType) + where TFailureMechanism : IFailureMechanism + where TCalculation : ICalculation + { + if (failureMechanism == null) + { + throw new ArgumentNullException(nameof(failureMechanism)); + } + + WaveConditionsInputWaterLevelType waterLevelType = GetWaterLevelTypeFromNormType(normType); + + var affectedItems = new List(); + foreach (TCalculation calculation in failureMechanism.Calculations + .Cast() + .Where(c => c.InputParameters.WaterLevelType == waterLevelType)) + { + affectedItems.AddRange(RiskeerCommonDataSynchronizationService.ClearCalculationOutput(calculation)); + } + + return affectedItems; + } + + /// + /// Clears the output for all calculations that corresponds with the + /// in the given . + /// + /// The failure mechanism which contains the calculations. + /// The + /// to clear for. + /// The type of the failure mechanism. + /// The type of the calculation. + /// An of calculations which are affected by clearing the output. + /// Thrown when any parameter is null. + public static IEnumerable ClearAllWaveConditionsCalculationOutput( + TFailureMechanism failureMechanism, HydraulicBoundaryLocationCalculationsForTargetProbability calculationsForTargetProbability) + where TFailureMechanism : IFailureMechanism + where TCalculation : ICalculation + { + if (failureMechanism == null) + { + throw new ArgumentNullException(nameof(failureMechanism)); + } + + if (calculationsForTargetProbability == null) + { + throw new ArgumentNullException(nameof(calculationsForTargetProbability)); + } + + var affectedItems = new List(); + foreach (TCalculation calculation in failureMechanism.Calculations + .Cast() + .Where(c => c.InputParameters.WaterLevelType == WaveConditionsInputWaterLevelType.UserDefinedTargetProbability + && c.InputParameters.CalculationsTargetProbability == calculationsForTargetProbability)) + { + affectedItems.AddRange(RiskeerCommonDataSynchronizationService.ClearCalculationOutput(calculation)); + } + + return affectedItems; + } + + /// + /// Gets the based on the given . + /// + /// The to get the from. + /// A . + /// Thrown when is invalid. + /// Thrown when is not supported. + private static WaveConditionsInputWaterLevelType GetWaterLevelTypeFromNormType(NormType normType) + { + if (!Enum.IsDefined(typeof(NormType), normType)) + { + throw new InvalidEnumArgumentException(nameof(normType), + (int) normType, + typeof(NormType)); + } + + switch (normType) + { + case NormType.LowerLimit: + return WaveConditionsInputWaterLevelType.LowerLimit; + case NormType.Signaling: + return WaveConditionsInputWaterLevelType.Signaling; + default: + throw new NotSupportedException(); + } + } + } +} \ No newline at end of file Index: Riskeer/Revetment/test/Riskeer.Revetment.Data.TestUtil/TestWaveConditionsCalculation.cs =================================================================== diff -u -r7491928192a7ecf23958f85fbd4669ec17085c95 -r4da2af82acf0b1d6ce385c124f871e34d9373021 --- Riskeer/Revetment/test/Riskeer.Revetment.Data.TestUtil/TestWaveConditionsCalculation.cs (.../TestWaveConditionsCalculation.cs) (revision 7491928192a7ecf23958f85fbd4669ec17085c95) +++ Riskeer/Revetment/test/Riskeer.Revetment.Data.TestUtil/TestWaveConditionsCalculation.cs (.../TestWaveConditionsCalculation.cs) (revision 4da2af82acf0b1d6ce385c124f871e34d9373021) @@ -40,27 +40,24 @@ /// Creates a new instance of . /// /// The wave conditions input to set to the calculation. - public TestWaveConditionsCalculation(T input) + /// Indicator whether output is set. + /// is default set to false. + public TestWaveConditionsCalculation(T input, bool hasOutput = false) { Name = RiskeerCommonDataResources.Calculation_DefaultName; InputParameters = input; + HasOutput = hasOutput; } public T InputParameters { get; } - public bool ShouldCalculate - { - get - { - return !HasOutput; - } - } + public bool ShouldCalculate => !HasOutput; - public bool HasOutput { get; } + public bool HasOutput { get; private set; } public void ClearOutput() { - // Stub doesn't have to clear the output. + HasOutput = false; } #region Irrelevant for test Index: Riskeer/Revetment/test/Riskeer.Revetment.Service.Test/WaveConditionsDataSynchronizationServiceTest.cs =================================================================== diff -u --- Riskeer/Revetment/test/Riskeer.Revetment.Service.Test/WaveConditionsDataSynchronizationServiceTest.cs (revision 0) +++ Riskeer/Revetment/test/Riskeer.Revetment.Service.Test/WaveConditionsDataSynchronizationServiceTest.cs (revision 4da2af82acf0b1d6ce385c124f871e34d9373021) @@ -0,0 +1,208 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using Core.Common.Base; +using Core.Common.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; +using Riskeer.Common.Data.Calculation; +using Riskeer.Common.Data.Contribution; +using Riskeer.Common.Data.FailureMechanism; +using Riskeer.Common.Data.Hydraulics; +using Riskeer.Common.Data.TestUtil; +using Riskeer.Revetment.Data; +using Riskeer.Revetment.Data.TestUtil; + +namespace Riskeer.Revetment.Service.Test +{ + [TestFixture] + public class WaveConditionsDataSynchronizationServiceTest + { + [Test] + public void ClearAllWaveConditionsCalculationOutputWithNormType_FailureMechanismNull_ThrowsArgumentNullException() + { + // Call + void Call() => WaveConditionsDataSynchronizationService.ClearAllWaveConditionsCalculationOutput>( + null, NormType.Signaling); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("failureMechanism", exception.ParamName); + } + + [Test] + public void ClearAllWaveConditionsCalculationOutputWithNormType_InvalidNormType_ThrowsInvalidEnumArgumentException() + { + // Setup + const NormType normType = (NormType) 99; + + // Call + void Call() => WaveConditionsDataSynchronizationService.ClearAllWaveConditionsCalculationOutput>( + new TestFailureMechanism(), normType); + + // Assert + var expectedMessage = $"The value of argument 'normType' ({normType}) is invalid for Enum type '{nameof(NormType)}'."; + var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, expectedMessage); + Assert.AreEqual("normType", exception.ParamName); + } + + [Test] + [TestCase(NormType.LowerLimit)] + [TestCase(NormType.Signaling)] + public void ClearAllWaveConditionsCalculationOutputWithNormType_WithAllData_ClearsOutputAndReturnsAffectedObjects(NormType normType) + { + // Setup + var calculation1 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.Signaling + }, true); + var calculation2 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.LowerLimit + }, true); + var calculation3 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.None + }, true); + var calculation4 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.UserDefinedTargetProbability + }, true); + + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + failureMechanism.Stub(fm => fm.Calculations).Return(new[] + { + calculation1, + calculation2, + calculation3, + calculation4 + }); + mocks.ReplayAll(); + + TestWaveConditionsCalculation[] expectedAffectedCalculations = + { + normType == NormType.LowerLimit + ? calculation2 + : calculation1 + }; + + // Call + IEnumerable affectedCalculations = WaveConditionsDataSynchronizationService.ClearAllWaveConditionsCalculationOutput>( + failureMechanism, normType); + + // Assert + CollectionAssert.AreEqual(expectedAffectedCalculations, affectedCalculations); + Assert.IsTrue(expectedAffectedCalculations.All(c => !c.HasOutput)); + Assert.IsTrue(failureMechanism.Calculations.Except(expectedAffectedCalculations).All(c => c.HasOutput)); + mocks.ReplayAll(); + } + + [Test] + public void ClearAllWaveConditionsCalculationsOutputWithUserDefinedTargetProbability_FailureMechanismNull_ThrowsArgumentNullException() + { + // Call + void Call() => WaveConditionsDataSynchronizationService.ClearAllWaveConditionsCalculationOutput>( + null, new HydraulicBoundaryLocationCalculationsForTargetProbability(0.1)); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("failureMechanism", exception.ParamName); + } + + [Test] + public void ClearAllWaveConditionsCalculationsOutputWithUserDefinedTargetProbability_CalculationsForTargetProbabilityNull_ThrowsArgumentNullException() + { + // Call + void Call() => WaveConditionsDataSynchronizationService.ClearAllWaveConditionsCalculationOutput>( + new TestFailureMechanism(), null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("calculationsForTargetProbability", exception.ParamName); + } + + [Test] + public void ClearAllWaveConditionsCalculationsOutputWithUserDefinedTargetProbability_WithAllData_ClearsOutputAndReturnsAffectedObjects() + { + // Setup + var calculationsForTargetProbabilityToClear = new HydraulicBoundaryLocationCalculationsForTargetProbability(0.1); + var otherCalculationsForTargetProbability = new HydraulicBoundaryLocationCalculationsForTargetProbability(0.01); + + var calculation1 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.Signaling, + CalculationsTargetProbability = calculationsForTargetProbabilityToClear + }, true); + var calculation2 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.LowerLimit, + CalculationsTargetProbability = calculationsForTargetProbabilityToClear + }, true); + var calculation3 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.None, + CalculationsTargetProbability = calculationsForTargetProbabilityToClear + }, true); + var calculation4 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.UserDefinedTargetProbability, + CalculationsTargetProbability = calculationsForTargetProbabilityToClear + }, true); + var calculation5 = new TestWaveConditionsCalculation(new TestWaveConditionsInput + { + WaterLevelType = WaveConditionsInputWaterLevelType.UserDefinedTargetProbability, + CalculationsTargetProbability = otherCalculationsForTargetProbability + }, true); + + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + failureMechanism.Stub(fm => fm.Calculations).Return(new[] + { + calculation1, + calculation2, + calculation3, + calculation4, + calculation5 + }); + mocks.ReplayAll(); + + TestWaveConditionsCalculation[] expectedAffectedCalculations = + { + calculation4 + }; + + // Call + IEnumerable affectedCalculations = WaveConditionsDataSynchronizationService.ClearAllWaveConditionsCalculationOutput>( + failureMechanism, calculationsForTargetProbabilityToClear); + + // Assert + CollectionAssert.AreEqual(expectedAffectedCalculations, affectedCalculations); + Assert.IsTrue(expectedAffectedCalculations.All(c => !c.HasOutput)); + Assert.IsTrue(failureMechanism.Calculations.Except(expectedAffectedCalculations).All(c => c.HasOutput)); + mocks.ReplayAll(); + } + } +} \ No newline at end of file