// Copyright (C) Stichting Deltares 2024. All rights reserved. // // This file is part of the application DAM - UI. // // DAM - UI 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 Deltares.Dam.Data.CsvImporters; using Deltares.Dam.Data.Importers; using Deltares.Maps; using NetTopologySuite.Geometries; using NUnit.Framework; using NSubstitute; namespace Deltares.Dam.Tests.Importers { [TestFixture] public class LineAttributeImporterTest { private IFeatureRepository crossSectionRepository, attributesRepository; private Feature crossSection, attributeLine, outsideLine; private LineAttributeImporter importer; [Test] public void Import_NoRepositorySet_Throws() { Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("No repository set")); } [Test] public void Import_NoAttributesInRepository_Throws() { importer.AttributeRepository = new FeatureRepository(); Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("The repository doesn't contain attributes")); } [Test] public void Import_LocationIDEmpty_Throws() { importer.AttributeRepository = new FeatureRepository(); importer.AttributeRepository.Add(Feature.Create(0, 0, new[] { new KeyValuePair("test", 0) })); importer.LocationIDAttributeName = ""; Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("The location ID attribute name is not valid")); } [Test] public void Import_LocationIDNull_Throws() { importer.AttributeRepository = new FeatureRepository(); importer.AttributeRepository.Add(Feature.Create(0, 0, new[] { new KeyValuePair("test", 0) })); importer.LocationIDAttributeName = null; Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("The location ID attribute name is not valid")); } [Test] public void Import_LocationIDWhiteSpace_Throws() { importer.AttributeRepository = new FeatureRepository(); importer.AttributeRepository.Add(Feature.Create(0, 0, new[] { new KeyValuePair("test", 0) })); importer.LocationIDAttributeName = " "; Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("The location ID attribute name is not valid")); } [Test] public void Import_NoCrossSectionSet_Throws() { importer.AttributeRepository = new FeatureRepository(); importer.AttributeRepository.Add(Feature.Create(0, 0, new[] { new KeyValuePair("test", 0) })); importer.LocationIDAttributeName = "Test"; Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("No cross section repository set")); } [Test] public void Import_NoAttributeMappingListSet_Throws() { importer.AttributeRepository = new FeatureRepository(); importer.AttributeRepository.Add(Feature.Create(0, 0, new[] { new KeyValuePair("test", 0) })); importer.CrossSectionRepository = new FeatureRepository(); importer.LocationIDAttributeName = "Test"; Assert.That(() => importer.Import(), Throws.InvalidOperationException.With.Message.EqualTo("No attribute mappings set")); } [Test] [Category("Integration")] public void PerformanceOfImport_UsingSmallList_IsAcceptable() { string crossSectionFile = Path.Combine(Directory.GetCurrentDirectory(), @"TestData\HHNKShapeFiles\Crosssection.shp"); string attributeFile = Path.Combine(Directory.GetCurrentDirectory(), @"TestData\HHNKShapeFiles\DampingFactorPL3.shp"); var locations = new List { new() { LocationId = "TPL_Hempolder_0010" }, new() { LocationId = "TPL_Hempolder_0020" }, new() { LocationId = "TPL_Hempolder_0030" }, new() { LocationId = "TPL_Hempolder_0040" }, new() { LocationId = "TPL_Hempolder_0050" }, new() { LocationId = "TPL_Hempolder_0060" }, new() { LocationId = "TPL_Hempolder_0070" }, new() { LocationId = "TPL_Hempolder_0080" }, new() { LocationId = "TPL_Hempolder_0090" }, new() { LocationId = "TPL_Hempolder_0100" } }; IFeatureRepository crossSections = FeatureRepository.CreateFromShapeFile(crossSectionFile); IFeatureRepository attributes = FeatureRepository.CreateFromShapeFile(attributeFile); LocationAttributeMapping crossSectionMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.CrossSectionAttributId); importer.LocationIDAttributeName = crossSectionMapping.Name; importer.Targets = locations; importer.CrossSectionRepository = crossSections; importer.AttributeRepository = attributes; LocationAttributeMapping mapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.DampingFactorPl3AttributeId); importer.AttributeMappings = new[] { mapping }; importer.Import(); Assert.That(locations, Has.Count.EqualTo(10)); Assert.Multiple(() => { Assert.That(locations.First().LocationId, Is.EqualTo("TPL_Hempolder_0010")); Assert.That(locations.Last().LocationId, Is.EqualTo("TPL_Hempolder_0100")); }); } [Test] public void Import_IntersectionFoundBetweenCrossSectionAndAttributeLine_ValuesFromAttributeLineAreSetOnTarget() { const string locationId = "Test_Location_01"; const double expectedValue = 5.7; var location = new CsvImporterLocations.LocationRecord { LocationId = locationId }; importer.Targets = new[] { location }; importer.CrossSectionRepository = crossSectionRepository; importer.AttributeRepository = attributesRepository; LocationAttributeMapping crossSectionMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.CrossSectionAttributId); crossSection.AddAttribute(crossSectionMapping.Name, locationId); crossSectionRepository.Features.Returns(new[] { crossSection }); importer.LocationIDAttributeName = crossSectionMapping.Name; LocationAttributeMapping trafLoadMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.TrafficLoadAttributeId); importer.AttributeMappings = new[] { trafLoadMapping }; attributeLine.AddAttribute(trafLoadMapping.Name, expectedValue); attributesRepository.Query(Arg.Any()).Returns(new[] { attributeLine }); attributesRepository.SupportedAttributes.Returns(new[] { LocationShapeFileAttributeMap.TrafficLoadAttributeId }); importer.Import(); Assert.That(location.TrafficLoad, Is.EqualTo(expectedValue)); } [Test] public void Import_NoIntersectionFoundBetweenCrossSectionAndOutsideLine_ValuesFromAttributeLineAreNotSetOnTarget() { const string locationId = "Test_Location_02"; const double expectedValue = 5.7; var location = new CsvImporterLocations.LocationRecord { LocationId = locationId, TrafficLoad = expectedValue }; importer.Targets = new[] { location }; importer.CrossSectionRepository = crossSectionRepository; importer.AttributeRepository = attributesRepository; LocationAttributeMapping crossSectionMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.CrossSectionAttributId); crossSection.AddAttribute(crossSectionMapping.Name, locationId); crossSectionRepository.Features.Returns(new[] { crossSection }); importer.LocationIDAttributeName = crossSectionMapping.Name; LocationAttributeMapping trafLoadMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.TrafficLoadAttributeId); importer.AttributeMappings = new[] { trafLoadMapping }; attributeLine.AddAttribute(trafLoadMapping.Name, expectedValue); attributesRepository.Query(Arg.Any()).Returns(new[] { outsideLine }); attributesRepository.SupportedAttributes.Returns(new[] { LocationShapeFileAttributeMap.TrafficLoadAttributeId }); importer.Import(); Assert.That(location.TrafficLoad, Is.EqualTo(expectedValue)); } [Test] public void Import_NoIntersectionFoundBetweenCrossSectionAndOutsideLine_ExceptionIsAdded() { const string locationId = "Test_Location_02"; const double expectedValue = 5.7; var location = new CsvImporterLocations.LocationRecord { LocationId = locationId, TrafficLoad = expectedValue }; importer.Targets = new[] { location }; importer.CrossSectionRepository = crossSectionRepository; importer.AttributeRepository = attributesRepository; LocationAttributeMapping crossSectionMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.CrossSectionAttributId); crossSection.AddAttribute(crossSectionMapping.Name, locationId); crossSectionRepository.Features.Returns(new[] { crossSection }); importer.LocationIDAttributeName = crossSectionMapping.Name; LocationAttributeMapping trafLoadMapping = LocationShapeFileAttributeMap.GetAttributeMapping(LocationShapeFileAttributeMap.TrafficLoadAttributeId); importer.AttributeMappings = new[] { trafLoadMapping }; attributeLine.AddAttribute(trafLoadMapping.Name, expectedValue); attributesRepository.Query(Arg.Any()).Returns(new[] { outsideLine }); attributesRepository.SupportedAttributes.Returns(new[] { LocationShapeFileAttributeMap.TrafficLoadAttributeId }); importer.Import(); Assert.That(importer.Errors.OfType().Count(), Is.EqualTo(1), "The NotSupported error was not added to the error list for logging when no intersections are found. "); } #region Fixture Setup/Teardown [SetUp] public void FixtureSetup() {} [TearDown] public void FixtureTearDown() {} #endregion #region Setup/Teardown [SetUp] public void TestSetup() { importer = new LineAttributeImporter(); crossSectionRepository = Substitute.For(); attributesRepository = Substitute.For(); crossSection = Feature.Create(new LineString(new[] { new Coordinate(-1, 0), new Coordinate(1, 0) })); attributeLine = Feature.Create(new LineString(new[] { new Coordinate(0, -1), new Coordinate(0, 1) })); // this line should not touch outsideLine = Feature.Create(new LineString(new[] { new Coordinate(10, -1), new Coordinate(10, 1) })); } [TearDown] public void TestTearDown() {} #endregion } }