Index: Ringtoets/Integration/src/Ringtoets.Integration.Service/Comparers/AssessmentSectionMergeComparer.cs =================================================================== diff -u --- Ringtoets/Integration/src/Ringtoets.Integration.Service/Comparers/AssessmentSectionMergeComparer.cs (revision 0) +++ Ringtoets/Integration/src/Ringtoets.Integration.Service/Comparers/AssessmentSectionMergeComparer.cs (revision 48b3f7c813c181320c85aa269973dac65f0d1d68) @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Core.Common.Base.Geometry; +using Ringtoets.Common.Data.AssessmentSection; +using Ringtoets.Common.Data.Contribution; +using Ringtoets.Common.Data.Hydraulics; + +namespace Ringtoets.Integration.Service.Comparers +{ + /// + /// Class which compares to + /// determine whether they are equal and can be used to merged. + /// + public class AssessmentSectionMergeComparer : IAssessmentSectionMergeComparer + { + public bool Compare(IAssessmentSection referenceAssessmentSection, IAssessmentSection assessmentSectionToCompare) + { + if (referenceAssessmentSection == null) + { + throw new ArgumentNullException(nameof(referenceAssessmentSection)); + } + + if (assessmentSectionToCompare == null) + { + throw new ArgumentNullException(nameof(assessmentSectionToCompare)); + } + + return referenceAssessmentSection.Id == assessmentSectionToCompare.Id + && referenceAssessmentSection.Composition == assessmentSectionToCompare.Composition + && AreReferenceLinesEquivalent(referenceAssessmentSection.ReferenceLine, assessmentSectionToCompare.ReferenceLine) + && AreHydraulicBoundaryDatabasesEquivalent(referenceAssessmentSection.HydraulicBoundaryDatabase, assessmentSectionToCompare.HydraulicBoundaryDatabase) + && AreFailureMechanismContributionsEquivalent(referenceAssessmentSection.FailureMechanismContribution, assessmentSectionToCompare.FailureMechanismContribution); + } + + private static bool AreReferenceLinesEquivalent(ReferenceLine referenceLine, ReferenceLine otherReferenceLine) + { + if (referenceLine == null && otherReferenceLine == null) + { + return true; + } + + IEnumerable referenceLineGeometry = referenceLine?.Points; + IEnumerable otherReferenceLineGeometry = otherReferenceLine?.Points; + + if (referenceLineGeometry == null || otherReferenceLineGeometry == null) + { + return false; + } + + int nrOfPoints = referenceLineGeometry.Count(); + if (otherReferenceLineGeometry.Count() != nrOfPoints) + { + return false; + } + + for (var i = 0; i < nrOfPoints; i++) + { + if (!referenceLineGeometry.ElementAt(i).Equals(otherReferenceLineGeometry.ElementAt(i))) + { + return false; + } + } + + return true; + } + + private static bool AreHydraulicBoundaryDatabasesEquivalent(HydraulicBoundaryDatabase hydraulicBoundaryDatabase, + HydraulicBoundaryDatabase otherHydraulicBoundaryDatabase) + { + return hydraulicBoundaryDatabase.Version == otherHydraulicBoundaryDatabase.Version; + } + + private static bool AreFailureMechanismContributionsEquivalent(FailureMechanismContribution failureMechanismContribution, + FailureMechanismContribution otherFailureMechanismContribution) + { + return AreNormsEquivalent(failureMechanismContribution.LowerLimitNorm, otherFailureMechanismContribution.LowerLimitNorm) + && AreNormsEquivalent(failureMechanismContribution.SignalingNorm, otherFailureMechanismContribution.SignalingNorm) + && failureMechanismContribution.NormativeNorm == otherFailureMechanismContribution.NormativeNorm; + } + + private static bool AreNormsEquivalent(double norm, double otherNorm) + { + return Math.Abs(norm - otherNorm) < 1e-5; + } + } +} \ No newline at end of file Index: Ringtoets/Integration/src/Ringtoets.Integration.Service/Ringtoets.Integration.Service.csproj =================================================================== diff -u -r66626f5c114e03e5aad4ec0e4e1400dd43608fb6 -r48b3f7c813c181320c85aa269973dac65f0d1d68 --- Ringtoets/Integration/src/Ringtoets.Integration.Service/Ringtoets.Integration.Service.csproj (.../Ringtoets.Integration.Service.csproj) (revision 66626f5c114e03e5aad4ec0e4e1400dd43608fb6) +++ Ringtoets/Integration/src/Ringtoets.Integration.Service/Ringtoets.Integration.Service.csproj (.../Ringtoets.Integration.Service.csproj) (revision 48b3f7c813c181320c85aa269973dac65f0d1d68) @@ -11,6 +11,7 @@ + Index: Ringtoets/Integration/test/Ringtoets.Integration.Service.Test/Comparers/AssessmentSectionMergeComparerTest.cs =================================================================== diff -u --- Ringtoets/Integration/test/Ringtoets.Integration.Service.Test/Comparers/AssessmentSectionMergeComparerTest.cs (revision 0) +++ Ringtoets/Integration/test/Ringtoets.Integration.Service.Test/Comparers/AssessmentSectionMergeComparerTest.cs (revision 48b3f7c813c181320c85aa269973dac65f0d1d68) @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Core.Common.Base; +using Core.Common.Base.Geometry; +using Core.Common.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; +using Ringtoets.Common.Data; +using Ringtoets.Common.Data.AssessmentSection; +using Ringtoets.Common.Data.Contribution; +using Ringtoets.Common.Data.FailureMechanism; +using Ringtoets.Common.Data.Hydraulics; +using Ringtoets.Integration.Service.Comparers; + +namespace Ringtoets.Integration.Service.Test.Comparers +{ + [TestFixture] + public class AssessmentSectionMergeComparerTest + { + [Test] + public void Constructor_ExpectedValues() + { + // Call + var comparer = new AssessmentSectionMergeComparer(); + + // Assert + Assert.IsInstanceOf(comparer); + } + + [Test] + public void Compare_ReferenceAssessmentSectionNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var assessmentSectionToCompare = mocks.Stub(); + mocks.ReplayAll(); + + var comparer = new AssessmentSectionMergeComparer(); + + // Call + TestDelegate call = () => comparer.Compare(null, assessmentSectionToCompare); + + // Assert + var exception = Assert.Throws(call); + Assert.AreEqual("referenceAssessmentSection", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + public void Compare_AssessmentSectionToCompareNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var referenceAssessmentSection = mocks.Stub(); + mocks.ReplayAll(); + + var comparer = new AssessmentSectionMergeComparer(); + + // Call + TestDelegate call = () => comparer.Compare(referenceAssessmentSection, null); + + // Assert + var exception = Assert.Throws(call); + Assert.AreEqual("assessmentSectionToCompare", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + public void Compare_AssessmentSectionsAreEqual_ReturnsTrue() + { + // Setup + IAssessmentSection referenceAssessmentSection = CreateAssessmentSection(); + IAssessmentSection assessmentSectionToCompare = CreateAssessmentSection(); + + var comparer = new AssessmentSectionMergeComparer(); + + // Call + bool result = comparer.Compare(referenceAssessmentSection, assessmentSectionToCompare); + + // Assert + Assert.IsTrue(result); + } + + [Test] + [TestCaseSource(nameof(GetUnequalTestCases))] + public void Compare_AssessmentSectionsUnequalFailureMechanismContributions_ReturnsFalse( + IAssessmentSection assessmentSection) + { + // Setup + IAssessmentSection referenceAssessmentSection = CreateAssessmentSection(); + + var comparer = new AssessmentSectionMergeComparer(); + + // Call + bool result = comparer.Compare(referenceAssessmentSection, assessmentSection); + + // Assert + Assert.IsFalse(result); + } + + private static IAssessmentSection CreateAssessmentSection() + { + var referenceLine = new ReferenceLine(); + referenceLine.SetGeometry(new [] + { + new Point2D(1, 1), + new Point2D(1, 2) + }); + return new TestAssessmentSection("Id", AssessmentSectionComposition.Dike) + { + ReferenceLine = referenceLine + }; + } + + private static IEnumerable GetUnequalTestCases() + { + IAssessmentSection referenceAssessmentSection = CreateAssessmentSection(); + yield return new TestCaseData(new TestAssessmentSection("DifferentId", referenceAssessmentSection.Composition)) + .SetName("ID"); + yield return new TestCaseData(new TestAssessmentSection(referenceAssessmentSection.Id, AssessmentSectionComposition.DikeAndDune)) + .SetName("Composition"); + + foreach (ChangePropertyData changeSingleDataProperty in ChangeSingleDataProperties()) + { + IAssessmentSection assessmentSection = CreateAssessmentSection(); + changeSingleDataProperty.ActionToChangeProperty(assessmentSection); + yield return new TestCaseData(assessmentSection).SetName(changeSingleDataProperty.PropertyName); + } + } + + private static IEnumerable> ChangeSingleDataProperties() + { + var referenceLineDifferentPointCount = new ReferenceLine(); + referenceLineDifferentPointCount.SetGeometry(new[] + { + new Point2D(1, 1) + }); + yield return new ChangePropertyData(sec => sec.ReferenceLine = referenceLineDifferentPointCount, + "Referenceline different point count"); + yield return new ChangePropertyData(sec => sec.ReferenceLine = null, + "Referenceline null"); + + var referenceLineDifferentPoint = new ReferenceLine(); + referenceLineDifferentPoint.SetGeometry(new[] + { + new Point2D(1, 1), + new Point2D(1, 3) + }); + yield return new ChangePropertyData(sec => sec.ReferenceLine = referenceLineDifferentPoint, + "Referenceline different point"); + + yield return new ChangePropertyData(sec => sec.HydraulicBoundaryDatabase.Version = "DifferentVersion", + "HydraulicBoundaryDataBase"); + yield return new ChangePropertyData(sec => sec.FailureMechanismContribution.LowerLimitNorm = sec.FailureMechanismContribution.LowerLimitNorm - 0.05, + "LowerLimitNorm"); + yield return new ChangePropertyData(sec => sec.FailureMechanismContribution.SignalingNorm = sec.FailureMechanismContribution.SignalingNorm - 0.005, + "SignalingNorm"); + yield return new ChangePropertyData(sec => sec.FailureMechanismContribution.NormativeNorm = sec.FailureMechanismContribution.NormativeNorm == NormType.LowerLimit + ? NormType.Signaling + : NormType.LowerLimit, + "NormType"); + } + + private class TestAssessmentSection : IAssessmentSection + { + public TestAssessmentSection(string id, AssessmentSectionComposition composition) + { + Id = id; + Composition = composition; + FailureMechanismContribution = new FailureMechanismContribution(Enumerable.Empty(), 0, 0.1, 0.025); + HydraulicBoundaryDatabase = new HydraulicBoundaryDatabase(); + } + + public IEnumerable Observers { get; } + + public void Attach(IObserver observer) + { + throw new NotImplementedException(); + } + + public void Detach(IObserver observer) + { + throw new NotImplementedException(); + } + + public void NotifyObservers() + { + throw new NotImplementedException(); + } + + public string Id { get; } + public string Name { get; set; } + public Comment Comments { get; } + public AssessmentSectionComposition Composition { get; } + public ReferenceLine ReferenceLine { get; set; } + public FailureMechanismContribution FailureMechanismContribution { get; } + public HydraulicBoundaryDatabase HydraulicBoundaryDatabase { get; } + public BackgroundData BackgroundData { get; } + public IObservableEnumerable WaterLevelCalculationsForFactorizedSignalingNorm { get; } + public IObservableEnumerable WaterLevelCalculationsForSignalingNorm { get; } + public IObservableEnumerable WaterLevelCalculationsForLowerLimitNorm { get; } + public IObservableEnumerable WaterLevelCalculationsForFactorizedLowerLimitNorm { get; } + public IObservableEnumerable WaveHeightCalculationsForFactorizedSignalingNorm { get; } + public IObservableEnumerable WaveHeightCalculationsForSignalingNorm { get; } + public IObservableEnumerable WaveHeightCalculationsForLowerLimitNorm { get; } + public IObservableEnumerable WaveHeightCalculationsForFactorizedLowerLimitNorm { get; } + + public IEnumerable GetFailureMechanisms() + { + throw new NotImplementedException(); + } + + public void ChangeComposition(AssessmentSectionComposition newComposition) + { + throw new NotImplementedException(); + } + } + } +} \ No newline at end of file Index: Ringtoets/Integration/test/Ringtoets.Integration.Service.Test/Ringtoets.Integration.Service.Test.csproj =================================================================== diff -u -r4376a372caaaeb42bf19c90fbf1cc012e56766ea -r48b3f7c813c181320c85aa269973dac65f0d1d68 --- Ringtoets/Integration/test/Ringtoets.Integration.Service.Test/Ringtoets.Integration.Service.Test.csproj (.../Ringtoets.Integration.Service.Test.csproj) (revision 4376a372caaaeb42bf19c90fbf1cc012e56766ea) +++ Ringtoets/Integration/test/Ringtoets.Integration.Service.Test/Ringtoets.Integration.Service.Test.csproj (.../Ringtoets.Integration.Service.Test.csproj) (revision 48b3f7c813c181320c85aa269973dac65f0d1d68) @@ -19,6 +19,7 @@ + @@ -33,6 +34,10 @@ {3bbfd65b-b277-4e50-ae6d-bd24c3434609} Core.Common.Base + + {D749EE4C-CE50-4C17-BF01-9A953028C126} + Core.Common.TestUtil + {C6309704-D67B-434C-BC98-9F8910BC1D10} Ringtoets.ClosingStructures.Data