// 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");
}
}
}