// 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.Linq;
using Core.Common.Base;
using Core.Common.Base.Data;
using Core.Common.Base.Geometry;
using Core.Common.TestUtil;
using NUnit.Framework;
using Ringtoets.Common.Data.DikeProfiles;
using Ringtoets.Common.Data.Exceptions;
using Ringtoets.Common.Data.FailureMechanism;
using Ringtoets.Common.Data.TestUtil;
using Ringtoets.Common.Data.UpdateDataStrategies;
using Ringtoets.Common.IO.FileImporters;
using Ringtoets.Integration.Plugin.FileImporters;
namespace Ringtoets.Integration.Plugin.Test.FileImporters
{
[TestFixture]
public class ForeshoreProfileUpdateDataStrategyTest
{
private const string sourceFilePath = "some/path/to/foreshoreProfiles";
private static IEnumerable DifferentForeshoreProfileWithSameId
{
get
{
var random = new Random(21);
var defaultForeshoreProfile = new TestForeshoreProfile();
string defaultId = defaultForeshoreProfile.Id;
string defaultName = defaultForeshoreProfile.Name;
RoundedPoint2DCollection defaultGeometry = defaultForeshoreProfile.Geometry;
BreakWater defaultBreakWater = defaultForeshoreProfile.BreakWater;
Point2D defaultReferencePoint = defaultForeshoreProfile.WorldReferencePoint;
double defaultX0 = defaultForeshoreProfile.X0;
RoundedDouble defaultOrientation = defaultForeshoreProfile.Orientation;
yield return new TestCaseData(new TestForeshoreProfile("different name", defaultId))
.SetName("DifferentName");
yield return new TestCaseData(new TestForeshoreProfile(new Point2D(defaultReferencePoint.X + random.NextDouble(),
defaultReferencePoint.Y + random.NextDouble())))
.SetName("DifferentWorldReferencePoint");
yield return new TestCaseData(new TestForeshoreProfile(new BreakWater(random.NextEnumValue(),
random.NextDouble())))
.SetName("DifferentBreakWater");
yield return new TestCaseData(new TestForeshoreProfile(new[]
{
new Point2D(random.NextDouble(),
random.NextDouble())
}))
.SetName("DifferentGeometry");
yield return new TestCaseData(new ForeshoreProfile(defaultReferencePoint, defaultGeometry, defaultBreakWater,
new ForeshoreProfile.ConstructionProperties
{
Id = defaultId,
Name = defaultName,
Orientation = defaultOrientation,
X0 = defaultX0 + random.NextDouble()
}))
.SetName("DifferentX0");
yield return new TestCaseData(new ForeshoreProfile(defaultReferencePoint, defaultGeometry, defaultBreakWater,
new ForeshoreProfile.ConstructionProperties
{
Id = defaultId,
Name = defaultName,
Orientation = defaultOrientation + random.NextDouble(),
X0 = defaultX0
}))
.SetName("DifferentOrientation");
}
}
[Test]
public void Constructor_FailureMechanismNull_ThrowsArgumentNullException()
{
// Call
TestDelegate call = () => new ForeshoreProfileUpdateDataStrategy(null, new ForeshoreProfileCollection());
// Assert
var exception = Assert.Throws(call);
Assert.AreEqual("failureMechanism", exception.ParamName);
}
[Test]
public void Constructor_ForeshoreProfilesNull_ThrowsArgumentNullException()
{
// Call
TestDelegate call = () => new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), null);
// Assert
var exception = Assert.Throws(call);
Assert.AreEqual("targetCollection", exception.ParamName);
}
[Test]
public void Constructor_CreatesNewInstance()
{
// Call
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), new ForeshoreProfileCollection());
// Assert
Assert.IsInstanceOf(strategy);
Assert.IsInstanceOf>(strategy);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_ImportedDataCollectionNull_ThrowsArgumentNullException()
{
// Setup
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), new ForeshoreProfileCollection());
// Call
TestDelegate call = () => strategy.UpdateForeshoreProfilesWithImportedData(null,
sourceFilePath);
// Assert
var exception = Assert.Throws(call);
Assert.AreEqual("importedDataCollection", exception.ParamName);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_SourceFilePathNull_ThrowsArgumentNullException()
{
// Setup
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), new ForeshoreProfileCollection());
// Call
TestDelegate call = () => strategy.UpdateForeshoreProfilesWithImportedData(Enumerable.Empty(),
null);
// Assert
var exception = Assert.Throws(call);
Assert.AreEqual("sourceFilePath", exception.ParamName);
}
[Test]
[TestCaseSource(nameof(DifferentForeshoreProfileWithSameId))]
public void UpdateForeshoreProfilesWithImportedData_ForeshoreProfilePropertiesChanged_UpdateRelevantProperties(
ForeshoreProfile readForeshoreProfile)
{
// Setup
var profileToBeUpdated = new TestForeshoreProfile();
var targetCollection = new ForeshoreProfileCollection();
targetCollection.AddRange(new[]
{
profileToBeUpdated
}, sourceFilePath);
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), targetCollection);
// Call
strategy.UpdateForeshoreProfilesWithImportedData(new[]
{
readForeshoreProfile
}, sourceFilePath);
// Assert
Assert.AreEqual(1, targetCollection.Count);
Assert.AreSame(profileToBeUpdated, targetCollection[0]);
AssertForeshoreProfile(readForeshoreProfile, profileToBeUpdated);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_CurrentCollectionEmptyImportedCollectionContainDuplicateIDs_ThrowUpdateException()
{
// Setup
var foreshoreProfiles = new ForeshoreProfileCollection();
const string duplicateId = "duplicate ID";
var importedForeshoreProfiles = new[]
{
new TestForeshoreProfile("Name A", duplicateId),
new TestForeshoreProfile("Name B", duplicateId)
};
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), foreshoreProfiles);
// Call
TestDelegate call = () => strategy.UpdateForeshoreProfilesWithImportedData(importedForeshoreProfiles,
sourceFilePath);
// Assert
var exception = Assert.Throws(call);
const string expectedMessage = "Geïmporteerde data moet unieke elementen bevatten.";
Assert.AreEqual(expectedMessage, exception.Message);
CollectionAssert.IsEmpty(foreshoreProfiles);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_WithCurrentCollectionNotEmptyAndImportedCollectionHasProfilesWithSameId_ThrowsUpdateException()
{
// Setup
var foreshoreProfiles = new ForeshoreProfileCollection();
var originalForeshoreProfiles = new[]
{
new TestForeshoreProfile("name 1", "different ID")
};
foreshoreProfiles.AddRange(originalForeshoreProfiles, sourceFilePath);
const string duplicateId = "duplicate ID";
var importedForeshoreProfiles = new[]
{
new TestForeshoreProfile("Name A", duplicateId),
new TestForeshoreProfile("Name B", duplicateId)
};
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), foreshoreProfiles);
// Call
TestDelegate call = () => strategy.UpdateForeshoreProfilesWithImportedData(importedForeshoreProfiles,
sourceFilePath);
// Assert
var exception = Assert.Throws(call);
const string expectedMessage = "Geïmporteerde data moet unieke elementen bevatten.";
Assert.AreEqual(expectedMessage, exception.Message);
CollectionAssert.AreEqual(originalForeshoreProfiles, foreshoreProfiles);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_CurrentCollectionAndImportedCollectionHasNoOverlap_UpdatesTargetCollection()
{
// Setup
const string currentForeshoreProfile = "Current ID";
var targetForeshoreProfile = new TestForeshoreProfile(string.Empty, currentForeshoreProfile);
const string readForeshoreProfileId = "Read ID";
var readForeshoreProfile = new TestForeshoreProfile(string.Empty, readForeshoreProfileId);
TestForeshoreProfile[] readForeshoreProfiles =
{
readForeshoreProfile
};
var foreshoreProfiles = new ForeshoreProfileCollection();
foreshoreProfiles.AddRange(new[]
{
targetForeshoreProfile
}, sourceFilePath);
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), foreshoreProfiles);
// Call
IEnumerable affectedObjects =
strategy.UpdateForeshoreProfilesWithImportedData(readForeshoreProfiles,
sourceFilePath);
// Assert
Assert.AreEqual(1, foreshoreProfiles.Count);
Assert.AreSame(readForeshoreProfile, foreshoreProfiles[0]);
CollectionAssert.AreEqual(new[]
{
foreshoreProfiles
}, affectedObjects);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_WithCurrentCollectionAndImportedCollectionHasFullOverlap_UpdatesTargetDataCollection()
{
// Setup
var foreshoreProfiles = new ForeshoreProfileCollection();
var targetForeshoreProfile = new TestForeshoreProfile("Name", "ID");
foreshoreProfiles.AddRange(new[]
{
targetForeshoreProfile
}, sourceFilePath);
ForeshoreProfile readForeshoreProfile = DeepCloneAndModify(targetForeshoreProfile);
ForeshoreProfile[] importedForeshoreProfiles =
{
readForeshoreProfile
};
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), foreshoreProfiles);
// Call
IEnumerable affectedObjects = strategy.UpdateForeshoreProfilesWithImportedData(importedForeshoreProfiles,
sourceFilePath);
// Assert
Assert.AreEqual(1, foreshoreProfiles.Count);
Assert.AreSame(targetForeshoreProfile, foreshoreProfiles[0]);
AssertForeshoreProfile(readForeshoreProfile, targetForeshoreProfile);
CollectionAssert.AreEquivalent(new IObservable[]
{
targetForeshoreProfile,
foreshoreProfiles
}, affectedObjects);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_WithCurrentCollectionAndImportedCollectionHasPartialOverlap_UpdatesTargetDataCollection()
{
// Setup
var commonName = "Name";
var foreshoreProfileToBeUpdated = new TestForeshoreProfile(commonName, "Updated ID");
var foreshoreProfileToBeRemoved = new TestForeshoreProfile(commonName, "Removed ID");
var foreshoreProfiles = new ForeshoreProfileCollection();
foreshoreProfiles.AddRange(new[]
{
foreshoreProfileToBeUpdated,
foreshoreProfileToBeRemoved
}, sourceFilePath);
ForeshoreProfile foreshoreProfileToUpdateFrom = DeepCloneAndModify(foreshoreProfileToBeUpdated);
var foreshoreProfileToBeAdded = new TestForeshoreProfile(commonName, "Added ID");
ForeshoreProfile[] importedForeshoreProfiles =
{
foreshoreProfileToUpdateFrom,
foreshoreProfileToBeAdded
};
var strategy = new ForeshoreProfileUpdateDataStrategy(new TestFailureMechanism(), foreshoreProfiles);
// Call
IEnumerable affectedObjects = strategy.UpdateForeshoreProfilesWithImportedData(importedForeshoreProfiles,
sourceFilePath);
// Assert
Assert.AreEqual(2, foreshoreProfiles.Count);
CollectionAssert.AreEqual(new[]
{
foreshoreProfileToBeUpdated,
foreshoreProfileToBeAdded
}, foreshoreProfiles);
ForeshoreProfile updatedForeshoreProfile = foreshoreProfiles[0];
Assert.AreSame(foreshoreProfileToBeUpdated, updatedForeshoreProfile);
AssertForeshoreProfile(foreshoreProfileToUpdateFrom, updatedForeshoreProfile);
ForeshoreProfile addedForeshoreProfile = foreshoreProfiles[1];
Assert.AreSame(foreshoreProfileToBeAdded, addedForeshoreProfile);
AssertForeshoreProfile(foreshoreProfileToBeAdded, addedForeshoreProfile);
CollectionAssert.AreEquivalent(new IObservable[]
{
foreshoreProfileToBeUpdated,
foreshoreProfiles
}, affectedObjects);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_CalculationWithOutputAssignedToRemovedProfile_UpdatesCalculation()
{
// Setup
var profileToBeRemoved = new TestForeshoreProfile("Name", "Removed ID");
TestCalculationWithForeshoreProfile calculation =
TestCalculationWithForeshoreProfile.CreateCalculationWithOutput(profileToBeRemoved);
var foreshoreProfiles = new ForeshoreProfileCollection();
foreshoreProfiles.AddRange(new[]
{
profileToBeRemoved
}, sourceFilePath);
var failureMechanism = new TestFailureMechanism(new[]
{
calculation
});
var strategy = new ForeshoreProfileUpdateDataStrategy(failureMechanism, foreshoreProfiles);
// Call
IEnumerable affectedObjects =
strategy.UpdateForeshoreProfilesWithImportedData(Enumerable.Empty(),
sourceFilePath);
// Assert
Assert.IsFalse(calculation.HasOutput);
Assert.IsNull(calculation.InputParameters.ForeshoreProfile);
CollectionAssert.IsEmpty(foreshoreProfiles);
CollectionAssert.AreEquivalent(new IObservable[]
{
calculation,
calculation.InputParameters,
foreshoreProfiles
}, affectedObjects);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_MultipleCalculationsWithOutputAndProfile_UpdatesCalculationWithUpdatedProfile()
{
// Setup
var affectedProfile = new TestForeshoreProfile("Name", "Updated ID");
TestCalculationWithForeshoreProfile affectedCalculation =
TestCalculationWithForeshoreProfile.CreateCalculationWithOutput(affectedProfile);
ForeshoreProfile profileToUpdateFrom = DeepCloneAndModify(affectedProfile);
const string unaffectedProfileId = "Unaffected ID";
const string unaffectedProfileName = "Name";
var unaffectedProfile = new TestForeshoreProfile(unaffectedProfileName, unaffectedProfileId);
TestCalculationWithForeshoreProfile unaffectedCalculation =
TestCalculationWithForeshoreProfile.CreateCalculationWithOutput(unaffectedProfile);
var foreshoreProfiles = new ForeshoreProfileCollection();
TestForeshoreProfile[] originalForeshoreProfiles =
{
affectedProfile,
unaffectedProfile
};
foreshoreProfiles.AddRange(originalForeshoreProfiles, sourceFilePath);
var failureMechanism = new TestFailureMechanism(new[]
{
affectedCalculation,
unaffectedCalculation
});
var strategy = new ForeshoreProfileUpdateDataStrategy(failureMechanism, foreshoreProfiles);
// Call
IEnumerable affectedObjects =
strategy.UpdateForeshoreProfilesWithImportedData(new[]
{
new TestForeshoreProfile(unaffectedProfileName,
unaffectedProfileId),
profileToUpdateFrom
},
sourceFilePath);
// Assert
Assert.IsTrue(unaffectedCalculation.HasOutput);
Assert.AreSame(unaffectedProfile,
unaffectedCalculation.InputParameters.ForeshoreProfile);
Assert.IsFalse(affectedCalculation.HasOutput);
Assert.AreSame(affectedProfile, affectedCalculation.InputParameters.ForeshoreProfile);
CollectionAssert.AreEquivalent(originalForeshoreProfiles, foreshoreProfiles);
CollectionAssert.AreEquivalent(new IObservable[]
{
affectedCalculation,
affectedCalculation.InputParameters,
affectedProfile,
foreshoreProfiles
}, affectedObjects);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_MultipleCalculationsWithSameReference_OnlyReturnsDistinctCalculations()
{
// Setup
var affectedProfile = new TestForeshoreProfile("Name", "Updated ID");
TestCalculationWithForeshoreProfile affectedCalculation =
TestCalculationWithForeshoreProfile.CreateCalculationWithOutput(affectedProfile);
ForeshoreProfile profileToUpdateFrom = DeepCloneAndModify(affectedProfile);
TestCalculationWithForeshoreProfile calculationSameReference = affectedCalculation;
var foreshoreProfiles = new ForeshoreProfileCollection();
TestForeshoreProfile[] originalForeshoreProfiles =
{
affectedProfile
};
foreshoreProfiles.AddRange(originalForeshoreProfiles, sourceFilePath);
var failureMechanism = new TestFailureMechanism(new[]
{
affectedCalculation,
calculationSameReference
});
var strategy = new ForeshoreProfileUpdateDataStrategy(failureMechanism, foreshoreProfiles);
// Call
IEnumerable affectedObjects =
strategy.UpdateForeshoreProfilesWithImportedData(new[]
{
profileToUpdateFrom
},
sourceFilePath);
// Assert
CollectionAssert.AreEquivalent(new IObservable[]
{
affectedCalculation,
affectedCalculation.InputParameters,
affectedProfile,
foreshoreProfiles
}, affectedObjects);
}
[Test]
public void UpdateForeshoreProfilesWithImportedData_CalculationWithOutputAndForeshoreProfileUpdatedWithProfileWithoutGeometry_UpdatesCalculation()
{
// Setup
const string id = "profile ID";
IEnumerable geometry = new[]
{
new Point2D(1, 2),
new Point2D(3, 4)
};
var affectedProfile = new TestForeshoreProfile(id, geometry);
TestCalculationWithForeshoreProfile affectedCalculation =
TestCalculationWithForeshoreProfile.CreateCalculationWithOutput(affectedProfile);
affectedCalculation.InputParameters.UseForeshore = true;
var profileToUpdateFrom = new TestForeshoreProfile(id, Enumerable.Empty());
var foreshoreProfiles = new ForeshoreProfileCollection();
TestForeshoreProfile[] originalForeshoreProfiles =
{
affectedProfile
};
foreshoreProfiles.AddRange(originalForeshoreProfiles, sourceFilePath);
var failureMechanism = new TestFailureMechanism(new[]
{
affectedCalculation
});
var strategy = new ForeshoreProfileUpdateDataStrategy(failureMechanism, foreshoreProfiles);
// Call
IEnumerable affectedObjects =
strategy.UpdateForeshoreProfilesWithImportedData(new[]
{
profileToUpdateFrom
},
sourceFilePath);
// Assert
Assert.IsFalse(affectedCalculation.HasOutput);
Assert.IsFalse(affectedCalculation.InputParameters.UseForeshore);
AssertForeshoreProfile(affectedProfile, profileToUpdateFrom);
CollectionAssert.AreEquivalent(new IObservable[]
{
affectedCalculation,
affectedCalculation.InputParameters,
affectedProfile,
foreshoreProfiles
}, affectedObjects);
}
///
/// Makes a deep clone of the foreshore profile and modifies all the properties,
/// except the .
///
/// The foreshore profile to deep clone.
/// A deep clone of the .
private static ForeshoreProfile DeepCloneAndModify(ForeshoreProfile foreshoreProfile)
{
var random = new Random(21);
Point2D originalWorldCoordinate = foreshoreProfile.WorldReferencePoint;
var modifiedWorldCoordinate = new Point2D(originalWorldCoordinate.X + random.NextDouble(),
originalWorldCoordinate.Y + random.NextDouble());
List modifiedForeshoreGeometry = foreshoreProfile.Geometry.ToList();
modifiedForeshoreGeometry.Add(new Point2D(1, 2));
RoundedDouble originalBreakWaterHeight = foreshoreProfile.BreakWater?.Height ?? (RoundedDouble) 0.0;
var modifiedBreakWater = new BreakWater(random.NextEnumValue(),
originalBreakWaterHeight + random.NextDouble());
string modifiedName = $"new_name_{foreshoreProfile.Name}";
double modifiedOrientation = foreshoreProfile.Orientation + random.NextDouble();
double modifiedX0 = foreshoreProfile.X0 + random.NextDouble();
return new ForeshoreProfile(modifiedWorldCoordinate, modifiedForeshoreGeometry,
modifiedBreakWater,
new ForeshoreProfile.ConstructionProperties
{
Name = modifiedName,
Id = foreshoreProfile.Id,
Orientation = modifiedOrientation,
X0 = modifiedX0
});
}
private static void AssertForeshoreProfile(ForeshoreProfile expectedForeshoreProfile,
ForeshoreProfile actualForeshoreProfile)
{
Assert.AreEqual(expectedForeshoreProfile.WorldReferencePoint, actualForeshoreProfile.WorldReferencePoint);
CollectionAssert.AreEqual(expectedForeshoreProfile.Geometry, actualForeshoreProfile.Geometry);
Assert.AreEqual(expectedForeshoreProfile.BreakWater, actualForeshoreProfile.BreakWater);
Assert.AreEqual(expectedForeshoreProfile.Id, actualForeshoreProfile.Id);
Assert.AreEqual(expectedForeshoreProfile.Name, actualForeshoreProfile.Name);
Assert.AreEqual(expectedForeshoreProfile.X0, actualForeshoreProfile.X0);
Assert.AreEqual(expectedForeshoreProfile.Orientation, actualForeshoreProfile.Orientation);
}
}
}