// 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.Collections.ObjectModel; using System.Linq; using Core.Common.TestUtil; using NUnit.Framework; using Rhino.Mocks; using Ringtoets.Common.Data.Contribution; using Ringtoets.Common.Data.FailureMechanism; using Ringtoets.Common.Data.Properties; namespace Ringtoets.Common.Data.Test.Contribution { [TestFixture] public class FailureMechanismContributionTest { private MockRepository mocks; [SetUp] public void SetUp() { mocks = new MockRepository(); } [Test] public void Constructor_WithNullFailureMechanisms_ThrowsArgumentNullException() { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double norm = 1.0 / 30000; // Call TestDelegate test = () => new FailureMechanismContribution(null, contribution, norm, norm); // Assert const string expectedMessage = "Kan geen bijdrageoverzicht maken zonder toetsspoor."; TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, expectedMessage); } [Test] public void Constructor_WithNullFailureMechanism_ThrowsArgumentNullException() { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double norm = 1.0 / 30000; // Call TestDelegate test = () => new FailureMechanismContribution(new IFailureMechanism[] { null }, contribution, norm, norm); // Assert const string expectedMessage = "Kan geen bijdrage element maken zonder een toetsspoor."; TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, expectedMessage); } [Test] [TestCaseSource(nameof(GetInvalidNormValues), new object[] { "Constructor_InvalidLowerLimitNorm_ThrowsArgumentOutOfRangeException" })] [SetCulture("nl-NL")] public void Constructor_InvalidLowerLimitNorm_ThrowsArgumentOutOfRangeException(double invalidNorm) { // Setup var random = new Random(21); int contribution = random.Next(1, 100); // Call TestDelegate test = () => new FailureMechanismContribution(Enumerable.Empty(), contribution, invalidNorm, 0.000001); // Assert const string expectedMessage = "De waarde van de norm moet in het bereik [0,000001, 0,1] liggen."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(invalidNorm, exception.ActualValue); } [Test] [TestCaseSource(nameof(GetInvalidNormValues), new object[] { "Constructor_InvalidSignalingNorm_ThrowsArgumentOutOfRangeException" })] [SetCulture("nl-NL")] public void Constructor_InvalidSignalingNorm_ThrowsArgumentOutOfRangeException(double invalidNorm) { // Setup var random = new Random(21); int contribution = random.Next(1, 100); // Call TestDelegate test = () => new FailureMechanismContribution(Enumerable.Empty(), contribution, 0.1, invalidNorm); // Assert const string expectedMessage = "De waarde van de norm moet in het bereik [0,000001, 0,1] liggen."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(invalidNorm, exception.ActualValue); } [Test] public void Constructor_SignalingNormLargerThanLowerLimitNorm_ThrowsArgumentOutOfRangeException() { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double signalingNorm = 0.1; // Call TestDelegate test = () => new FailureMechanismContribution(Enumerable.Empty(), contribution, 0.01, signalingNorm); // Assert const string expectedMessage = "De signaleringswaarde moet gelijk zijn aan of kleiner zijn dan de ondergrens."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(signalingNorm, exception.ActualValue); } [Test] [SetCulture("nl-NL")] [TestCase(-10)] [TestCase(-1e-6)] [TestCase(100 + 1e-6)] [TestCase(150)] [TestCase(double.NaN)] public void Constructor_OtherContributionLessOrEqualTo0OrGreaterThan100_ThrowsArgumentOutOfRangeException(double contribution) { // Call TestDelegate test = () => new FailureMechanismContribution(Enumerable.Empty(), contribution, 1.0 / 30000, 1.0 / 30000); // Assert const string expectedMessage = "De waarde voor de toegestane bijdrage aan de faalkans moet in het bereik [0,0, 100,0] liggen."; TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, expectedMessage); } [Test] [TestCase(50)] [TestCase(0)] [TestCase(100)] public void Constructor_EmptyFailureMechanisms_OnlyOtherFailureMechanismAddedWithContributionSet(double contribution) { // Setup const double norm = 1.0 / 30000; // Call var result = new FailureMechanismContribution(Enumerable.Empty(), contribution, norm, norm); // Assert Assert.AreEqual(1, result.Distribution.Count()); FailureMechanismContributionItem otherFailureMechanismItem = result.Distribution.ElementAt(0); AssertFailureProbabilitySpace(contribution, norm, otherFailureMechanismItem.ProbabilitySpace); Assert.AreEqual(Resources.OtherFailureMechanism_DisplayName, otherFailureMechanismItem.Assessment); Assert.AreEqual(Resources.OtherFailureMechanism_Code, otherFailureMechanismItem.AssessmentCode); Assert.AreEqual(contribution, otherFailureMechanismItem.Contribution); Assert.IsTrue(otherFailureMechanismItem.IsAlwaysRelevant); Assert.IsTrue(otherFailureMechanismItem.IsRelevant); Assert.AreEqual(norm, result.Norm); Assert.AreEqual(norm, result.SignalingNorm); Assert.AreEqual(norm, result.LowerLimitNorm); Assert.AreEqual(NormType.LowerLimit, result.NormativeNorm); } [Test] [TestCase(1)] [TestCase(2)] [TestCase(5)] public void Constructor_OneOrMoreFailureMechanisms_DistributionForFailureMechanismsWithOtherAtEnd(int failureMechanismCount) { // Setup var random = new Random(21); int otherContribution = random.Next(1, 100); const double norm = 1.0 / 30000; var failureMechanismNames = new Collection(); var failureMechanismContributions = new Collection(); var failureMechanisms = new Collection(); const string namePrefixFormat = "mechanism_{0}"; for (var i = 0; i < failureMechanismCount; i++) { string name = string.Format(namePrefixFormat, i); int contribution = random.Next(1, 100); var failureMechanism = mocks.StrictMock(); failureMechanism.Expect(fm => fm.Name).Return(name); failureMechanism.Expect(fm => fm.Contribution).Return(contribution).Repeat.Twice(); failureMechanisms.Add(failureMechanism); failureMechanismNames.Add(name); failureMechanismContributions.Add(contribution); } failureMechanismNames.Add("Overig"); failureMechanismContributions.Add(otherContribution); mocks.ReplayAll(); // Call var result = new FailureMechanismContribution(failureMechanisms, otherContribution, norm, norm); // Assert Assert.AreEqual(failureMechanismCount + 1, result.Distribution.Count()); CollectionAssert.AreEqual(failureMechanismNames, result.Distribution.Select(d => d.Assessment)); CollectionAssert.AreEqual(failureMechanismContributions, result.Distribution.Select(d => d.Contribution)); CollectionAssert.AreEqual(failureMechanismContributions.Select(c => 100.0 / (1.0 / 30000 * c)), result.Distribution.Select(d => d.ProbabilitySpace)); IEnumerable expectedIsAlwaysRelevant = Enumerable.Repeat(false, failureMechanismCount) .Concat(Enumerable.Repeat(true, 1)); CollectionAssert.AreEqual(expectedIsAlwaysRelevant, result.Distribution.Select(d => d.IsAlwaysRelevant)); mocks.VerifyAll(); } [Test] public void UpdateContribution_FailureMechanismsIsNull_ThrowsArgumentNullException() { // Setup IEnumerable failureMechanisms = Enumerable.Empty(); var failureMechanismContribution = new FailureMechanismContribution(failureMechanisms, 12.34, 1.0 / 30000, 1.0 / 30000); // Call TestDelegate call = () => failureMechanismContribution.UpdateContributions(null, 0); // Assert const string message = "Kan geen bijdrageoverzicht maken zonder toetsspoor."; TestHelper.AssertThrowsArgumentExceptionAndTestMessage(call, message); } [Test] [TestCase(0)] [TestCase(34.6)] [TestCase(100)] public void UpdateContributions_NoFailureMechanismsAndValidOtherContribution_UpdateDistribution(double newOtherContribution) { // Setup IEnumerable failureMechanisms = Enumerable.Empty(); const double norm = 1.0 / 30000; var failureMechanismContribution = new FailureMechanismContribution(failureMechanisms, 12.34, norm, norm); // Call failureMechanismContribution.UpdateContributions(failureMechanisms, newOtherContribution); // Assert Assert.AreEqual(1, failureMechanismContribution.Distribution.Count()); FailureMechanismContributionItem otherFailureMechanismContribution = failureMechanismContribution.Distribution.Last(); Assert.AreEqual(newOtherContribution, otherFailureMechanismContribution.Contribution); Assert.AreEqual(norm, otherFailureMechanismContribution.Norm); AssertFailureProbabilitySpace(newOtherContribution, norm, otherFailureMechanismContribution.ProbabilitySpace); } [Test] public void UpdateContributions_MultipleChanges_AllFailureMechanismContributionItemsHaveLatestContribution() { // Given const double norm = 1.0 / 30000; IEnumerable failureMechanisms = Enumerable.Empty(); var failureMechanismContribution = new FailureMechanismContribution(failureMechanisms, 12.34, norm, norm); const double latestContribution = 2.3; // When failureMechanismContribution.UpdateContributions(failureMechanisms, 1); FailureMechanismContributionItem item1 = failureMechanismContribution.Distribution.Single(); failureMechanismContribution.UpdateContributions(failureMechanisms, latestContribution); FailureMechanismContributionItem item2 = failureMechanismContribution.Distribution.Single(); // Then Assert.AreEqual(latestContribution, item1.Contribution); Assert.AreEqual(latestContribution, item2.Contribution); Assert.AreEqual(item1.Assessment, item2.Assessment); } [Test] [TestCase(0)] [TestCase(34.6)] [TestCase(100)] public void UpdateContributions_FailureMechanismsChangesAfterConstruction_UpdateDistribution(double newOtherContribution) { // Setup const string name1 = "A"; const string name2 = "B"; const string name3 = "C"; const string name4 = "D"; const double contribution1 = 1.1; const double contribution2 = 5.5; const double contribution3 = 23.45; const double contribution4 = 67.89; const double norm = 1.0 / 30000; var failureMechanism1 = mocks.Stub(); failureMechanism1.Contribution = contribution1; failureMechanism1.Stub(fm => fm.Name).Return(name1); var failureMechanism2 = mocks.Stub(); failureMechanism2.Contribution = contribution2; failureMechanism2.Stub(fm => fm.Name).Return(name2); var failureMechanism3 = mocks.Stub(); failureMechanism3.Contribution = contribution3; failureMechanism3.Stub(fm => fm.Name).Return(name3); var failureMechanism4 = mocks.Stub(); failureMechanism4.Contribution = contribution4; failureMechanism4.Stub(fm => fm.Name).Return(name4); mocks.ReplayAll(); var failureMechanisms = new List { failureMechanism1, failureMechanism2 }; const double otherContribution = 12.34; var failureMechanismContribution = new FailureMechanismContribution(failureMechanisms, otherContribution, norm, norm); // Change failureMechanisms after construction of FailureMechanismContribution: failureMechanisms.RemoveAt(1); failureMechanisms.Add(failureMechanism3); failureMechanisms.Add(failureMechanism4); // Precondition Assert.AreEqual(3, failureMechanismContribution.Distribution.Count()); var originalNames = new[] { name1, name2, "Overig" }; CollectionAssert.AreEqual(originalNames, failureMechanismContribution.Distribution.Select(d => d.Assessment)); var originalContributionValues = new[] { contribution1, contribution2, otherContribution }; CollectionAssert.AreEqual(originalContributionValues, failureMechanismContribution.Distribution.Select(d => d.Contribution)); // Call failureMechanismContribution.UpdateContributions(failureMechanisms, newOtherContribution); // Assert Assert.AreEqual(4, failureMechanismContribution.Distribution.Count()); var expectedNames = new[] { name1, name3, name4, "Overig" }; CollectionAssert.AreEqual(expectedNames, failureMechanismContribution.Distribution.Select(d => d.Assessment)); var contributionValues = new[] { contribution1, contribution3, contribution4, newOtherContribution }; CollectionAssert.AreEqual(contributionValues, failureMechanismContribution.Distribution.Select(d => d.Contribution)); CollectionAssert.AreEqual(Enumerable.Repeat(1.0 / 30000, 4), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] public void LowerLimitNorm_WhenUpdatedAndNormativeNormLowerLimit_NormUpdatedForEachFailureMechanismContributionItem() { // Setup const double norm = 1.0 / 30000; const double newNorm = 0.1; var failureMechanism = mocks.Stub(); mocks.ReplayAll(); var random = new Random(21); int otherContribution = random.Next(1, 100); var failureMechanismContribution = new FailureMechanismContribution(new[] { failureMechanism }, otherContribution, norm, norm); // Call failureMechanismContribution.LowerLimitNorm = newNorm; // Assert CollectionAssert.AreEqual(Enumerable.Repeat(newNorm, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] public void LowerLimitNorm_WhenUpdatedAndNormativeNormNotLowerLimit_NormNotUpdatedForEachFailureMechanismContributionItem() { // Setup var failureMechanism = mocks.Stub(); mocks.ReplayAll(); var random = new Random(21); int otherContribution = random.Next(1, 100); const double norm = 1.0 / 30000; var failureMechanismContribution = new FailureMechanismContribution(new[] { failureMechanism }, otherContribution, norm, norm) { NormativeNorm = NormType.Signaling }; // Call failureMechanismContribution.LowerLimitNorm = 0.1; // Assert CollectionAssert.AreEqual(Enumerable.Repeat(norm, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] public void SignalingNorm_WhenUpdatedAndNormativeNormSignaling_NormUpdatedForEachFailureMechanismContributionItem() { // Setup const double norm = 1.0 / 30000; const double newNorm = 0.000001; var failureMechanism = mocks.Stub(); mocks.ReplayAll(); var random = new Random(21); int otherContribution = random.Next(1, 100); var failureMechanismContribution = new FailureMechanismContribution(new[] { failureMechanism }, otherContribution, norm, norm) { NormativeNorm = NormType.Signaling }; // Call failureMechanismContribution.SignalingNorm = newNorm; // Assert CollectionAssert.AreEqual(Enumerable.Repeat(newNorm, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] public void SignalingNorm_WhenUpdatedAndNormativeNormNotSignaling_NormNotUpdatedForEachFailureMechanismContributionItem() { // Setup var failureMechanism = mocks.Stub(); mocks.ReplayAll(); var random = new Random(21); int otherContribution = random.Next(1, 100); const double norm = 1.0 / 30000; var failureMechanismContribution = new FailureMechanismContribution(new[] { failureMechanism }, otherContribution, norm, norm); // Call failureMechanismContribution.SignalingNorm = 0.000001; // Assert CollectionAssert.AreEqual(Enumerable.Repeat(norm, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] public void NormativeNorm_WhenUpdated_NormUpdatedForEachFailureMechanismContributionItem() { // Setup var failureMechanism = mocks.Stub(); mocks.ReplayAll(); var random = new Random(21); int otherContribution = random.Next(1, 100); var failureMechanismContribution = new FailureMechanismContribution(new[] { failureMechanism }, otherContribution, 0.1, 0.001); // Precondition CollectionAssert.AreEqual(Enumerable.Repeat(0.1, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); // Call failureMechanismContribution.NormativeNorm = NormType.Signaling; // Assert CollectionAssert.AreEqual(Enumerable.Repeat(0.001, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] [TestCaseSource(nameof(GetInvalidNormValues), new object[] { "Norm_WhenUpdated_NormUpdatedForEachFailureMechanismContributionItem" })] [SetCulture("nl-NL")] public void LowerLimitNorm_InvalidNewNorm_ThrowsArgumentOutOfRangeException(double invalidNorm) { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double norm = 1.0 / 30000; var failureMechanismContribution = new FailureMechanismContribution(Enumerable.Empty(), contribution, norm, norm); // Call TestDelegate test = () => failureMechanismContribution.LowerLimitNorm = invalidNorm; // Assert const string expectedMessage = "De waarde van de norm moet in het bereik [0,000001, 0,1] liggen."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(invalidNorm, exception.ActualValue); } [Test] [TestCaseSource(nameof(GetInvalidNormValues), new object[] { "SignalingNorm_InvalidNewNorm_ThrowsArgumentOutOfRangeException" })] [SetCulture("nl-NL")] public void SignalingNorm_InvalidNewNorm_ThrowsArgumentOutOfRangeException(double invalidNorm) { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double norm = 1.0 / 30000; var failureMechanismContribution = new FailureMechanismContribution(Enumerable.Empty(), contribution, norm, norm); // Call TestDelegate test = () => failureMechanismContribution.SignalingNorm = invalidNorm; // Assert const string expectedMessage = "De waarde van de norm moet in het bereik [0,000001, 0,1] liggen."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(invalidNorm, exception.ActualValue); } [Test] [TestCaseSource(nameof(GetValidNormEdgeValues), new object[] { "Norm_SettingBothNormsToEdgeNorms_ThenPropertiesSet" })] public void GivenFailureMechanismContribution_WhenSettingBothNormsToEdgeNorms_ThenPropertiesSet(double newNorm) { // Given var failureMechanism = mocks.Stub(); mocks.ReplayAll(); var random = new Random(21); // When var failureMechanismContribution = new FailureMechanismContribution(new[] { failureMechanism }, random.Next(1, 100), newNorm, newNorm); // Then CollectionAssert.AreEqual(Enumerable.Repeat(newNorm, 2), failureMechanismContribution.Distribution.Select(d => d.Norm)); mocks.VerifyAll(); } [Test] public void SignalingNorm_SignalingNormBiggerThanLowerLimitNorm_ThrowsArgumentOutOfRangeException() { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double norm = 1.0 / 30000; const double newNorm = 1.0 / 10; var failureMechanismContribution = new FailureMechanismContribution(Enumerable.Empty(), contribution, norm, norm); // Call TestDelegate test = () => failureMechanismContribution.SignalingNorm = newNorm; // Assert const string expectedMessage = "De signaleringswaarde moet gelijk zijn aan of kleiner zijn dan de ondergrens."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(newNorm, exception.ActualValue); } [Test] public void LowerLimitNorm_SignalingNormBiggerThanLowerLimitNorm_ThrowsArgumentOutOfRangeException() { // Setup var random = new Random(21); int contribution = random.Next(1, 100); const double norm = 1.0 / 30000; const double newNorm = 1.0 / 1000000; var failureMechanismContribution = new FailureMechanismContribution(Enumerable.Empty(), contribution, norm, norm); // Call TestDelegate test = () => failureMechanismContribution.LowerLimitNorm = newNorm; // Assert const string expectedMessage = "De ondergrens moet gelijk zijn aan of groter zijn dan de signaleringswaarde."; var exception = Assert.Throws(test); StringAssert.StartsWith(expectedMessage, exception.Message); Assert.AreEqual(newNorm, exception.ActualValue); } [Test] [TestCase(NormType.Signaling, 0.01)] [TestCase(NormType.LowerLimit, 0.1)] public void Norm_DifferentNormativeNormTypes_ReturnNorm(NormType normType, double expectedNorm) { // Setup var random = new Random(21); int contribution = random.Next(1, 100); var failureMechanismContribution = new FailureMechanismContribution(Enumerable.Empty(), contribution, 0.1, 0.01) { NormativeNorm = normType }; // Call double norm = failureMechanismContribution.Norm; // Assert Assert.AreEqual(expectedNorm, norm); } private static void AssertFailureProbabilitySpace(double newOtherContribution, double norm, double probabilitySpace) { double expectedProbabilitySpace = 100.0 / (norm * newOtherContribution); Assert.AreEqual(expectedProbabilitySpace, probabilitySpace); } private static IEnumerable GetValidNormEdgeValues(string name) { yield return new TestCaseData(1.0 / 10) .SetName($"{name} Minimum valid norm"); yield return new TestCaseData(1.0 / 1000000) .SetName($"{name} Maximum valid norm"); } private static IEnumerable GetInvalidNormValues(string name) { yield return new TestCaseData(double.MaxValue) .SetName($"{name} maxValue"); yield return new TestCaseData(double.MinValue) .SetName($"{name} minValue"); yield return new TestCaseData(double.NaN) .SetName($"{name} NaN"); yield return new TestCaseData(0.1 + 1e-6) .SetName($"{name} maximum boundary"); yield return new TestCaseData(0.000001 - 1e-6) .SetName($"{name} minimum boundary"); } } }