// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets 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.IO; using System.Linq; using Core.Common.Base.Data; using Core.Common.TestUtil; using NUnit.Framework; using Rhino.Mocks; using Ringtoets.Common.Data.DikeProfiles; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.TestUtil; using Ringtoets.Common.Service.TestUtil; using Ringtoets.HydraRing.Calculation.Calculator.Factory; using Ringtoets.HydraRing.Calculation.Data; using Ringtoets.HydraRing.Calculation.Data.Input.WaveConditions; using Ringtoets.HydraRing.Calculation.Exceptions; using Ringtoets.HydraRing.Calculation.TestUtil; using Ringtoets.HydraRing.Calculation.TestUtil.Calculator; using Ringtoets.Revetment.Data; using Ringtoets.Revetment.Data.TestUtil; namespace Ringtoets.Revetment.Service.Test { [TestFixture] public class WaveConditionsCalculationServiceBaseTest { private static readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Integration.Service, "HydraRingCalculation"); private static readonly string validFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); private static readonly string validPreprocessorDirectory = TestHelper.GetScratchPadPath(); [Test] public void Validate_InputNull_ThrowArgumentNullException() { // Call TestDelegate action = () => TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(null, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, string.Empty); // Assert var exception = Assert.Throws(action); Assert.AreEqual("waveConditionsInput", exception.ParamName); } [Test] public void Validate_DesignWaterLevelNameNull_ThrowArgumentNullException() { // Setup var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new HydraulicBoundaryLocation(1, string.Empty, 0, 0) }; // Call TestDelegate action = () => TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, null); // Assert var exception = Assert.Throws(action); Assert.AreEqual("designWaterLevelName", exception.ParamName); } [Test] public void Validate_HydraulicBoundaryDatabasePathInvalid_ReturnsFalseAndLogsValidationError() { // Setup var isValid = false; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(new TestWaveConditionsInput(), GetValidAssessmentLevel(), string.Empty, validPreprocessorDirectory, string.Empty); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); StringAssert.StartsWith("Fout bij het lezen van bestand '': bestandspad mag niet leeg of ongedefinieerd zijn.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] public void Validate_InvalidHydraulicBoundaryDatabaseFileLocation_ReturnsFalseAndLogsValidationError() { // Setup var isValid = false; string invalidFilePath = Path.Combine(testDataPath, "NonExisting.sqlite"); // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(new TestWaveConditionsInput(), GetValidAssessmentLevel(), invalidFilePath, validPreprocessorDirectory, string.Empty); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); Assert.AreEqual($"Fout bij het lezen van bestand '{invalidFilePath}': het bestand bestaat niet.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] public void Validate_InvalidPreprocessorDirectory_ReturnsFalseAndLogsValidationError() { // Setup var isValid = false; const string invalidPreprocessorDirectory = "NonExistingPreprocessorDirectory"; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(new TestWaveConditionsInput(), GetValidAssessmentLevel(), validFilePath, invalidPreprocessorDirectory, string.Empty); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); Assert.AreEqual("De bestandsmap waar de preprocessor bestanden opslaat is ongeldig. De bestandsmap bestaat niet.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] public void Validate_ValidHydraulicBoundaryDatabaseWithoutSettings_LogsValidationMessageAndReturnFalse() { // Setup var isValid = false; string dbFilePath = Path.Combine(testDataPath, "HRD nosettings.sqlite"); // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(new TestWaveConditionsInput(), GetValidAssessmentLevel(), dbFilePath, validPreprocessorDirectory, string.Empty); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); StringAssert.StartsWith("Fout bij het lezen van bestand", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] public void Validate_NoHydraulicBoundaryLocation_ReturnsFalseAndLogsValidationError() { // Setup var isValid = false; var input = new TestWaveConditionsInput(); // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, string.Empty); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); Assert.AreEqual("Er is geen hydraulische randvoorwaardenlocatie geselecteerd.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] public void Validate_AssessmentLevelNaN_ReturnsFalseAndLogsValidationError() { // Setup var isValid = false; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new HydraulicBoundaryLocation(1, string.Empty, 0, 0) }; const string designWaterLevelName = ""; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, RoundedDouble.NaN, validFilePath, validPreprocessorDirectory, designWaterLevelName); // Assert string expectedMessage = $"Kan {designWaterLevelName} niet afleiden op basis van de invoer"; TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); StringAssert.StartsWith(expectedMessage, msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] [TestCase(double.NaN, 10.0, 12.0)] [TestCase(1.0, double.NaN, 12.0)] public void Validate_NoWaterLevels_ReturnsFalseAndLogsValidationError(double lowerBoundaryRevetments, double upperBoundaryRevetments, double assessmentLevel) { // Setup var isValid = false; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), Orientation = (RoundedDouble) 0, LowerBoundaryRevetment = (RoundedDouble) lowerBoundaryRevetments, UpperBoundaryRevetment = (RoundedDouble) upperBoundaryRevetments, StepSize = WaveConditionsInputStepSize.One, LowerBoundaryWaterLevels = (RoundedDouble) 1.0, UpperBoundaryWaterLevels = (RoundedDouble) 10.0 }; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, (RoundedDouble) assessmentLevel, validFilePath, validPreprocessorDirectory, "DesignWaterLevelName"); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); Assert.AreEqual("Kan geen waterstanden afleiden op basis van de invoer. Controleer de opgegeven boven- en ondergrenzen.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] [TestCase(double.NaN)] [TestCase(double.PositiveInfinity)] [TestCase(double.NegativeInfinity)] public void Validate_ForeshoreProfileUseBreakWaterAndHasInvalidBreakWaterHeight_ReturnsFalseAndLogsValidationMessages(double breakWaterHeight) { // Setup var isValid = false; WaveConditionsInput input = GetDefaultValidationInput(); input.ForeshoreProfile = new TestForeshoreProfile(new BreakWater(BreakWaterType.Dam, breakWaterHeight)); input.UseBreakWater = true; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, "DesignWaterLevelName"); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); StringAssert.StartsWith("De waarde voor 'hoogte' van de dam moet een concreet getal zijn.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] [TestCase(double.NaN)] [TestCase(double.PositiveInfinity)] [TestCase(double.NegativeInfinity)] public void Validate_ForeshoreProfileDoesNotUseBreakWaterAndHasInvalidBreakwaterHeight_ReturnsTrueAndLogsValidationStartAndEnd(double breakWaterHeight) { // Setup var isValid = false; WaveConditionsInput input = GetDefaultValidationInput(); input.ForeshoreProfile = new TestForeshoreProfile(new BreakWater(BreakWaterType.Wall, breakWaterHeight)); input.UseBreakWater = false; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, "DesignWaterLevelName"); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(2, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[1]); }); Assert.IsTrue(isValid); } [Test] [TestCase(CalculationType.NoForeshore)] [TestCase(CalculationType.ForeshoreWithoutBreakWater)] [TestCase(CalculationType.ForeshoreWithValidBreakWater)] public void Validate_ValidInputValidateForeshoreProfile_ReturnsTrueAndLogsValidationStartAndEnd(CalculationType calculationType) { // Setup var isValid = false; WaveConditionsInput input = GetDefaultValidationInput(); switch (calculationType) { case CalculationType.NoForeshore: input.ForeshoreProfile = null; input.UseBreakWater = false; input.UseForeshore = false; input.Orientation = (RoundedDouble) 0; break; case CalculationType.ForeshoreWithoutBreakWater: input.ForeshoreProfile = new TestForeshoreProfile(); input.UseBreakWater = false; break; case CalculationType.ForeshoreWithValidBreakWater: break; } // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, "DesignWaterLevelName"); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(2, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[1]); }); Assert.IsTrue(isValid); } [Test] public void Validate_StructureNormalOrientationInvalid_ReturnsFalse() { // Setup var isValid = false; WaveConditionsInput input = GetDefaultValidationInput(); input.Orientation = RoundedDouble.NaN; // Call Action action = () => isValid = TestWaveConditionsCalculationService.PublicValidateWaveConditionsInput(input, GetValidAssessmentLevel(), validFilePath, validPreprocessorDirectory, "DesignWaterLevelName"); // Assert TestHelper.AssertLogMessages(action, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(3, msgs.Length); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[0]); Assert.AreEqual("De waarde voor 'oriëntatie' moet een concreet getal zijn.", msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); }); Assert.IsFalse(isValid); } [Test] public void Calculate_InputNull_ThrowArgumentNullException() { // Setup var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; string hcldFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); // Call TestDelegate test = () => new TestWaveConditionsCalculationService().PublicCalculate(a, b, c, norm, null, GetValidAssessmentLevel(), hcldFilePath, string.Empty); // Assert var exception = Assert.Throws(test); Assert.AreEqual("waveConditionsInput", exception.ParamName); } [Test] [TestCase(true)] [TestCase(false)] public void Calculate_WithoutBreakWater_StartsCalculationWithRightParameters(bool useForeshore) { // Setup var waterLevel = (RoundedDouble) 4.20; var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(true), UpperBoundaryRevetment = (RoundedDouble) 4, LowerBoundaryRevetment = (RoundedDouble) 3, StepSize = WaveConditionsInputStepSize.Two, UseBreakWater = false, UseForeshore = useForeshore, Orientation = (RoundedDouble) 0 }; string hcldFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); var calculator = new TestWaveConditionsCosineCalculator(); RoundedDouble[] waterLevels = input.GetWaterLevels(waterLevel).ToArray(); int nrOfCalculators = waterLevels.Length; var mockRepository = new MockRepository(); var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, string.Empty)) .Return(calculator) .Repeat .Times(nrOfCalculators); mockRepository.ReplayAll(); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call new TestWaveConditionsCalculationService().PublicCalculate(a, b, c, norm, input, waterLevel, hcldFilePath, string.Empty); // Assert for (var i = 0; i < nrOfCalculators; i++) { WaveConditionsCosineCalculationInput expectedInput = CreateInput(waterLevels[i], a, b, c, norm, input, useForeshore, false); HydraRingDataEqualityHelper.AreEqual(expectedInput, calculator.ReceivedInputs[i]); } } mockRepository.VerifyAll(); } [Test] [TestCase(BreakWaterType.Caisson)] [TestCase(BreakWaterType.Wall)] [TestCase(BreakWaterType.Dam)] public void Calculate_WithBreakWater_StartsCalculationWithRightParameters(BreakWaterType breakWaterType) { // Setup var waterLevel = (RoundedDouble) 4.20; var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(true), UpperBoundaryRevetment = (RoundedDouble) 4, LowerBoundaryRevetment = (RoundedDouble) 3, StepSize = WaveConditionsInputStepSize.Two, UseBreakWater = true, UseForeshore = true, Orientation = (RoundedDouble) 0, BreakWater = { Type = breakWaterType } }; string hcldFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); var calculator = new TestWaveConditionsCosineCalculator(); RoundedDouble[] waterLevels = input.GetWaterLevels(waterLevel).ToArray(); int nrOfCalculators = waterLevels.Length; var mockRepository = new MockRepository(); var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, validPreprocessorDirectory)) .Return(calculator) .Repeat .Times(nrOfCalculators); mockRepository.ReplayAll(); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call new TestWaveConditionsCalculationService().PublicCalculate(a, b, c, norm, input, waterLevel, hcldFilePath, validPreprocessorDirectory); // Assert for (var i = 0; i < nrOfCalculators; i++) { WaveConditionsCosineCalculationInput expectedInput = CreateInput(waterLevels[i], a, b, c, norm, input, true, true); HydraRingDataEqualityHelper.AreEqual(expectedInput, calculator.ReceivedInputs[i]); } } mockRepository.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void Calculate_PreprocessorDirectorySet_StartsCalculationWithRightParameters(bool usePreprocessor) { // Setup string preprocessorDirectory = usePreprocessor ? validPreprocessorDirectory : string.Empty; var waterLevel = (RoundedDouble) 4.20; var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(true), UpperBoundaryRevetment = (RoundedDouble) 4, LowerBoundaryRevetment = (RoundedDouble) 3, StepSize = WaveConditionsInputStepSize.Two, Orientation = (RoundedDouble) 0 }; string hcldFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); var calculator = new TestWaveConditionsCosineCalculator(); int nrOfCalculators = input.GetWaterLevels(waterLevel).Count(); var mockRepository = new MockRepository(); var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, preprocessorDirectory)) .Return(calculator) .Repeat .Times(nrOfCalculators); mockRepository.ReplayAll(); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call new TestWaveConditionsCalculationService().PublicCalculate(a, b, c, norm, input, waterLevel, hcldFilePath, preprocessorDirectory); // Assert for (var i = 0; i < nrOfCalculators; i++) { Assert.AreEqual(usePreprocessor, calculator.ReceivedInputs[i].PreprocessorSetting.RunPreprocessor); } } mockRepository.VerifyAll(); } [Test] [TestCaseSource(typeof(HydraRingCalculatorTestCaseProvider), nameof(HydraRingCalculatorTestCaseProvider.GetCalculatorFailingConditionsWithReportDetails), new object[] { nameof(Calculate_ThreeCalculationsFail_ThrowsHydraRingCalculationExceptionAndLogError) })] public void Calculate_ThreeCalculationsFail_ThrowsHydraRingCalculationExceptionAndLogError(bool endInFailure, string lastErrorFileContent, string detailedReport) { // Setup var waterLevel = (RoundedDouble) 4.20; var waterLevelUpperBoundaryRevetment = new RoundedDouble(2, 4.00); var waterLevelLowerBoundaryRevetment = new RoundedDouble(2, 3.00); var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(), UpperBoundaryRevetment = waterLevelUpperBoundaryRevetment, LowerBoundaryRevetment = waterLevelLowerBoundaryRevetment }; int nrOfCalculators = input.GetWaterLevels(waterLevel).Count(); var calculatorThatFails = new TestWaveConditionsCosineCalculator { EndInFailure = endInFailure, LastErrorFileContent = lastErrorFileContent }; var mockRepository = new MockRepository(); var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, string.Empty)) .Return(calculatorThatFails) .Repeat .Times(nrOfCalculators); mockRepository.ReplayAll(); var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; string hcldFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); HydraRingCalculationException exception = null; using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call Action call = () => { try { new TestWaveConditionsCalculationService().PublicCalculate(a, b, c, norm, input, waterLevel, hcldFilePath, string.Empty); } catch (HydraRingCalculationException e) { exception = e; } }; // Assert TestHelper.AssertLogMessages(call, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(13, msgs.Length); var waterLevelMiddleRevetment = new RoundedDouble(2, 3.50); Assert.AreEqual($"Berekening voor waterstand '{waterLevelUpperBoundaryRevetment}' is gestart.", msgs[0]); Assert.AreEqual($"Berekening is mislukt voor waterstand '{waterLevelUpperBoundaryRevetment}'. {detailedReport}", msgs[1]); StringAssert.StartsWith("Golfcondities berekening is uitgevoerd op de tijdelijke locatie", msgs[2]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelUpperBoundaryRevetment}' is beëindigd.", msgs[3]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelMiddleRevetment}' is gestart.", msgs[4]); Assert.AreEqual($"Berekening is mislukt voor waterstand '{waterLevelMiddleRevetment}'. {detailedReport}", msgs[5]); StringAssert.StartsWith("Golfcondities berekening is uitgevoerd op de tijdelijke locatie", msgs[6]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelMiddleRevetment}' is beëindigd.", msgs[7]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelLowerBoundaryRevetment}' is gestart.", msgs[8]); Assert.AreEqual($"Berekening is mislukt voor waterstand '{waterLevelLowerBoundaryRevetment}'. {detailedReport}", msgs[9]); StringAssert.StartsWith("Golfcondities berekening is uitgevoerd op de tijdelijke locatie", msgs[10]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelLowerBoundaryRevetment}' is beëindigd.", msgs[11]); Assert.AreEqual("Berekening is mislukt voor alle waterstanden.", msgs[12]); }); Assert.IsInstanceOf(exception); Assert.AreEqual("Berekening is mislukt voor alle waterstanden.", exception.Message); } mockRepository.VerifyAll(); } [Test] [TestCaseSource(typeof(HydraRingCalculatorTestCaseProvider), nameof(HydraRingCalculatorTestCaseProvider.GetCalculatorFailingConditionsWithReportDetails), new object[] { nameof(Calculate_OneOutOfThreeCalculationsFails_ReturnsOutputsAndLogError) })] public void Calculate_OneOutOfThreeCalculationsFails_ReturnsOutputsAndLogError(bool endInFailure, string lastErrorFileContent, string detailedReport) { // Setup var calculatorThatFails = new TestWaveConditionsCosineCalculator { EndInFailure = endInFailure, LastErrorFileContent = lastErrorFileContent }; var mockRepository = new MockRepository(); var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, string.Empty)).Return(calculatorThatFails); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, string.Empty)).Return(new TestWaveConditionsCosineCalculator()); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, string.Empty)).Return(new TestWaveConditionsCosineCalculator()); mockRepository.ReplayAll(); var waterLevelUpperBoundary = new RoundedDouble(2, 4.00); var waterLevelLowerBoundary = new RoundedDouble(2, 3.00); var waterLevel = (RoundedDouble) 4.2; var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(), UpperBoundaryRevetment = waterLevelUpperBoundary, LowerBoundaryRevetment = waterLevelLowerBoundary }; string hcldFilePath = Path.Combine(testDataPath, "HRD ijsselmeer.sqlite"); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { var service = new TestWaveConditionsCalculationService(); // Call Action call = () => service.PublicCalculate(a, b, c, norm, input, waterLevel, hcldFilePath, string.Empty); // Assert TestHelper.AssertLogMessages(call, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(10, msgs.Length); var waterLevelMiddle = new RoundedDouble(2, 3.50); Assert.AreEqual($"Berekening voor waterstand '{waterLevelUpperBoundary}' is gestart.", msgs[0]); Assert.AreEqual($"Berekening is mislukt voor waterstand '{waterLevelUpperBoundary}'. {detailedReport}", msgs[1]); StringAssert.StartsWith("Golfcondities berekening is uitgevoerd op de tijdelijke locatie", msgs[2]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelUpperBoundary}' is beëindigd.", msgs[3]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelMiddle}' is gestart.", msgs[4]); StringAssert.StartsWith("Golfcondities berekening is uitgevoerd op de tijdelijke locatie", msgs[5]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelMiddle}' is beëindigd.", msgs[6]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelLowerBoundary}' is gestart.", msgs[7]); StringAssert.StartsWith("Golfcondities berekening is uitgevoerd op de tijdelijke locatie", msgs[8]); Assert.AreEqual($"Berekening voor waterstand '{waterLevelLowerBoundary}' is beëindigd.", msgs[9]); }); WaveConditionsOutput[] waveConditionsOutputs = service.Outputs.ToArray(); Assert.AreEqual(3, waveConditionsOutputs.Length); WaveConditionsOutputTestHelper.AssertFailedOutput(waterLevelUpperBoundary, norm, waveConditionsOutputs[0]); } mockRepository.VerifyAll(); } [Test] public void Calculate_CancelCalculationWithValidInput_CancelsCalculator() { // Setup var waterLevel = (RoundedDouble) 4.2; var a = (RoundedDouble) 1.0; var b = (RoundedDouble) 0.8; var c = (RoundedDouble) 0.4; const double norm = 0.2; var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(), UpperBoundaryRevetment = waterLevel, LowerBoundaryRevetment = (RoundedDouble) 3 }; var calculator = new TestWaveConditionsCosineCalculator(); var mockRepository = new MockRepository(); var calculatorFactory = mockRepository.Stub(); calculatorFactory.Expect(cf => cf.CreateWaveConditionsCosineCalculator(testDataPath, validPreprocessorDirectory)).Return(calculator); mockRepository.ReplayAll(); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { var service = new TestWaveConditionsCalculationService(); calculator.CalculationFinishedHandler += (s, e) => service.Cancel(); // Call service.PublicCalculate(a, b, c, norm, input, waterLevel, validFilePath, validPreprocessorDirectory); // Assert Assert.IsTrue(calculator.IsCanceled); } mockRepository.VerifyAll(); } private static WaveConditionsInput GetDefaultValidationInput() { var input = new TestWaveConditionsInput { HydraulicBoundaryLocation = new TestHydraulicBoundaryLocation(), ForeshoreProfile = new TestForeshoreProfile(true), UseBreakWater = true, UseForeshore = true, LowerBoundaryRevetment = (RoundedDouble) 1.0, UpperBoundaryRevetment = (RoundedDouble) 10.0, StepSize = WaveConditionsInputStepSize.One, LowerBoundaryWaterLevels = (RoundedDouble) 1.0, UpperBoundaryWaterLevels = (RoundedDouble) 10.0, Orientation = (RoundedDouble) 0 }; return input; } private static WaveConditionsCosineCalculationInput CreateInput(double waterLevel, double a, double b, double c, double norm, WaveConditionsInput input, bool useForeshore, bool useBreakWater) { return new WaveConditionsCosineCalculationInput(1, input.Orientation, input.HydraulicBoundaryLocation.Id, norm, useForeshore ? input.ForeshoreGeometry.Select(coordinate => new HydraRingForelandPoint(coordinate.X, coordinate.Y)) : new HydraRingForelandPoint[0], useBreakWater ? new HydraRingBreakWater(BreakWaterTypeHelper.GetHydraRingBreakWaterType(input.BreakWater.Type), input.BreakWater.Height) : null, waterLevel, a, b, c); } private static RoundedDouble GetValidAssessmentLevel() { return (RoundedDouble) 12; } private class TestWaveConditionsCalculationService : WaveConditionsCalculationServiceBase { public IEnumerable Outputs; public static bool PublicValidateWaveConditionsInput(WaveConditionsInput waveConditionsInput, RoundedDouble assessmentLevel, string dbFilePath, string preprocessorDirectory, string valueName) { return ValidateWaveConditionsInput(waveConditionsInput, assessmentLevel, dbFilePath, preprocessorDirectory, valueName); } public void PublicCalculate(RoundedDouble a, RoundedDouble b, RoundedDouble c, double norm, WaveConditionsInput input, RoundedDouble assessmentLevel, string dbFilePath, string preprocessorDirectory) { Outputs = CalculateWaveConditions(input, assessmentLevel, a, b, c, norm, dbFilePath, preprocessorDirectory); } } } }