Index: Riskeer/Integration/src/Riskeer.Integration.IO/Exporters/HydraulicBoundaryLocationsExporter.cs =================================================================== diff -u -rc36b47c2e1e8cf948767cca33f80ad735f370ad0 -rd4d2d3b67710d9e5f2ccedbebf38bcb29c354d77 --- Riskeer/Integration/src/Riskeer.Integration.IO/Exporters/HydraulicBoundaryLocationsExporter.cs (.../HydraulicBoundaryLocationsExporter.cs) (revision c36b47c2e1e8cf948767cca33f80ad735f370ad0) +++ Riskeer/Integration/src/Riskeer.Integration.IO/Exporters/HydraulicBoundaryLocationsExporter.cs (.../HydraulicBoundaryLocationsExporter.cs) (revision d4d2d3b67710d9e5f2ccedbebf38bcb29c354d77) @@ -20,12 +20,18 @@ // All rights reserved. using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; using Core.Common.Base.IO; -using Core.Common.IO.Exceptions; using Core.Common.Util; using log4net; using Riskeer.Common.Data.AssessmentSection; -using Riskeer.Common.Util; +using Riskeer.Common.Data.Hydraulics; +using Riskeer.Common.Forms.Helpers; +using Riskeer.Integration.IO.Properties; +using RiskeerCommonFormsResources = Riskeer.Common.Forms.Properties.Resources; using RiskeerCommonIOResources = Riskeer.Common.IO.Properties.Resources; namespace Riskeer.Integration.IO.Exporters @@ -38,6 +44,7 @@ private static readonly ILog log = LogManager.GetLogger(typeof(HydraulicBoundaryLocationsExporter)); private readonly IAssessmentSection assessmentSection; private readonly string filePath; + private readonly string tempFolderPath; /// /// Creates a new instance of . @@ -58,22 +65,111 @@ this.assessmentSection = assessmentSection; this.filePath = filePath; + string folderPath = Path.GetDirectoryName(filePath); + tempFolderPath = Path.Combine(folderPath, "~temp"); } public bool Export() { try { - HydraulicBoundaryLocationsWriter.WriteHydraulicBoundaryLocations( - AggregatedHydraulicBoundaryLocationFactory.CreateAggregatedHydraulicBoundaryLocations(assessmentSection), - filePath); + if (!ExportWaterLevelsForNormProbabilities() + || !ExportWaterLevelCalculationsForUserDefinedTargetProbabilities() + || !ExportWaveHeightCalculationsForUserDefinedTargetProbabilities()) + { + return false; + } + + ZipFile.CreateFromDirectory(tempFolderPath, filePath); + return true; } - catch (CriticalFileWriteException e) + catch (Exception e) { - log.ErrorFormat(RiskeerCommonIOResources.HydraulicBoundaryLocationsExporter_Error_Exception_0_no_HydraulicBoundaryLocations_exported, e.Message); + log.ErrorFormat(RiskeerCommonIOResources.HydraulicBoundaryLocationsExporter_Error_Exception_0_no_HydraulicBoundaryLocations_exported, + e.Message); return false; } + finally + { + if (Directory.Exists(tempFolderPath)) + { + Directory.Delete(tempFolderPath, true); + } + } + } + private bool ExportWaterLevelsForNormProbabilities() + { + return ExportLocationCalculationsForTargetProbabilities( + new[] + { + new Tuple, double>( + assessmentSection.WaterLevelCalculationsForLowerLimitNorm, assessmentSection.FailureMechanismContribution.LowerLimitNorm), + new Tuple, double>( + assessmentSection.WaterLevelCalculationsForSignalingNorm, assessmentSection.FailureMechanismContribution.SignalingNorm) + }, + HydraulicBoundaryLocationCalculationsType.WaterLevel, + Path.Combine(tempFolderPath, RiskeerCommonFormsResources.WaterLevelCalculationsForNormTargetProbabilities_DisplayName)); + } + + private bool ExportWaterLevelCalculationsForUserDefinedTargetProbabilities() + { + return ExportLocationCalculationsForTargetProbabilities( + assessmentSection.WaterLevelCalculationsForUserDefinedTargetProbabilities + .Select(tp => new Tuple, double>( + tp.HydraulicBoundaryLocationCalculations, tp.TargetProbability)), + HydraulicBoundaryLocationCalculationsType.WaterLevel, + Path.Combine(tempFolderPath, RiskeerCommonFormsResources.WaterLevelCalculationsForUserDefinedTargetProbabilities_DisplayName)); + } + + private bool ExportWaveHeightCalculationsForUserDefinedTargetProbabilities() + { + return ExportLocationCalculationsForTargetProbabilities( + assessmentSection.WaveHeightCalculationsForUserDefinedTargetProbabilities + .Select(tp => new Tuple, double>( + tp.HydraulicBoundaryLocationCalculations, tp.TargetProbability)), + HydraulicBoundaryLocationCalculationsType.WaveHeight, + Path.Combine(tempFolderPath, RiskeerCommonFormsResources.WaveHeightCalculationsForUserDefinedTargetProbabilities_DisplayName)); + } + + private static bool ExportLocationCalculationsForTargetProbabilities( + IEnumerable, double>> calculationsForTargetProbabilities, + HydraulicBoundaryLocationCalculationsType calculationsType, string folderPath) + { + var exportedCalculations = new Dictionary, string>(); + return calculationsForTargetProbabilities.All( + calculationsForTargetProbability => ExportLocationCalculationsForTargetProbability( + calculationsForTargetProbability, exportedCalculations, calculationsType, folderPath)); + } + + private static bool ExportLocationCalculationsForTargetProbability( + Tuple, double> calculationsForTargetProbability, + IDictionary, string> exportedCalculations, + HydraulicBoundaryLocationCalculationsType calculationsType, + string folderPath) + { + IEnumerable calculations = calculationsForTargetProbability.Item1; + double targetProbability = calculationsForTargetProbability.Item2; + + string exportType = calculationsType == HydraulicBoundaryLocationCalculationsType.WaterLevel + ? Resources.WaterLevels_DisplayName + : Resources.WaveHeights_DisplayName; + + string uniqueName = NamingHelper.GetUniqueName( + exportedCalculations, $"{exportType}_{ReturnPeriodFormattingHelper.FormatFromProbability(targetProbability)}", + c => c.Value); + + string tempFilePath = Path.Combine(folderPath, $"{uniqueName}.{RiskeerCommonIOResources.Shape_file_filter_Extension}"); + + var exporter = new HydraulicBoundaryLocationCalculationsExporter( + calculations, tempFilePath, calculationsType); + + if (!exporter.Export()) + { + return false; + } + + exportedCalculations.Add(calculations, uniqueName); return true; } } Index: Riskeer/Integration/test/Riskeer.Integration.IO.Test/Exporters/HydraulicBoundaryLocationCalculationsForTargetProbabilitiesExporterTest.cs =================================================================== diff -u -rc45c5e9b2cf66499f4f175d2605826c4cdec5774 -rd4d2d3b67710d9e5f2ccedbebf38bcb29c354d77 --- Riskeer/Integration/test/Riskeer.Integration.IO.Test/Exporters/HydraulicBoundaryLocationCalculationsForTargetProbabilitiesExporterTest.cs (.../HydraulicBoundaryLocationCalculationsForTargetProbabilitiesExporterTest.cs) (revision c45c5e9b2cf66499f4f175d2605826c4cdec5774) +++ Riskeer/Integration/test/Riskeer.Integration.IO.Test/Exporters/HydraulicBoundaryLocationCalculationsForTargetProbabilitiesExporterTest.cs (.../HydraulicBoundaryLocationCalculationsForTargetProbabilitiesExporterTest.cs) (revision d4d2d3b67710d9e5f2ccedbebf38bcb29c354d77) @@ -1,4 +1,4 @@ -// Copyright (C) Stichting Deltares 2021. All rights reserved. +// Copyright (C) Stichting Deltares 2021. All rights reserved. // // This file is part of Riskeer. // @@ -110,8 +110,6 @@ var exporter = new HydraulicBoundaryLocationCalculationsForTargetProbabilitiesExporter( calculationsForTargetProbabilities, HydraulicBoundaryLocationCalculationsType.WaterLevel, filePath); - string expectedFilePath = Path.Combine(directoryPath, "~temp", "Waterstanden_10.shp"); - try { using (new DirectoryPermissionsRevoker(directoryPath, FileSystemRights.CreateDirectories)) @@ -121,6 +119,7 @@ void Call() => isExported = exporter.Export(); // Assert + string expectedFilePath = Path.Combine(directoryPath, "~temp", "Waterstanden_10.shp"); string expectedMessage = $"Er is een onverwachte fout opgetreden tijdens het schrijven van het bestand '{expectedFilePath}'. " + "Er zijn geen hydraulische belastingenlocaties geëxporteerd."; TestHelper.AssertLogMessageIsGenerated(Call, expectedMessage); Index: Riskeer/Integration/test/Riskeer.Integration.IO.Test/Exporters/HydraulicBoundaryLocationsExporterTest.cs =================================================================== diff -u -rc36b47c2e1e8cf948767cca33f80ad735f370ad0 -rd4d2d3b67710d9e5f2ccedbebf38bcb29c354d77 --- Riskeer/Integration/test/Riskeer.Integration.IO.Test/Exporters/HydraulicBoundaryLocationsExporterTest.cs (.../HydraulicBoundaryLocationsExporterTest.cs) (revision c36b47c2e1e8cf948767cca33f80ad735f370ad0) +++ Riskeer/Integration/test/Riskeer.Integration.IO.Test/Exporters/HydraulicBoundaryLocationsExporterTest.cs (.../HydraulicBoundaryLocationsExporterTest.cs) (revision d4d2d3b67710d9e5f2ccedbebf38bcb29c354d77) @@ -21,6 +21,8 @@ using System; using System.IO; +using System.IO.Compression; +using System.Linq; using System.Security.AccessControl; using Core.Common.Base.IO; using Core.Common.TestUtil; @@ -29,7 +31,6 @@ using Riskeer.Common.Data.AssessmentSection; using Riskeer.Common.Data.Hydraulics; using Riskeer.Common.Data.TestUtil; -using Riskeer.Common.IO.TestUtil; using Riskeer.Integration.IO.Exporters; namespace Riskeer.Integration.IO.Test.Exporters @@ -44,10 +45,10 @@ string filePath = TestHelper.GetScratchPadPath(Path.Combine("export", "test.shp")); // Call - TestDelegate call = () => new HydraulicBoundaryLocationsExporter(null, filePath); + void Call() => new HydraulicBoundaryLocationsExporter(null, filePath); // Assert - var exception = Assert.Throws(call); + var exception = Assert.Throws(Call); Assert.AreEqual("assessmentSection", exception.ParamName); } @@ -60,10 +61,10 @@ mocks.ReplayAll(); // Call - TestDelegate call = () => new HydraulicBoundaryLocationsExporter(assessmentSection, null); + void Call() => new HydraulicBoundaryLocationsExporter(assessmentSection, null); // Assert - Assert.Throws(call); + Assert.Throws(Call); mocks.VerifyAll(); } @@ -95,32 +96,75 @@ new HydraulicBoundaryLocation(123, "aName", 1.1, 2.2) }); - string directoryPath = TestHelper.GetScratchPadPath("Export_ValidData_ReturnsTrueAndWritesCorrectData"); + string directoryPath = TestHelper.GetScratchPadPath(nameof(Export_ValidData_ReturnsTrueAndWritesCorrectData)); Directory.CreateDirectory(directoryPath); - string filePath = Path.Combine(directoryPath, "test.shp"); - const string baseName = "test"; + string filePath = Path.Combine(directoryPath, "test.zip"); var exporter = new HydraulicBoundaryLocationsExporter(assessmentSection, filePath); - // Precondition - FileTestHelper.AssertEssentialShapefilesExist(directoryPath, baseName, false); + try + { + // Call + bool isExported = exporter.Export(); + // Assert + Assert.IsTrue(isExported); + string[] expectedFiles = + { + "Waterstanden bij norm/Waterstanden_30.000.shp", + "Waterstanden bij norm/Waterstanden_30.000 (1).shp", + "Waterstanden bij doelkans/Waterstanden_10.000.shp", + "Waterstanden bij doelkans/Waterstanden_100.000.shp", + "Golfhoogten bij doelkans/Golfhoogten_4.000.shp", + "Golfhoogten bij doelkans/Golfhoogten_40.000.shp" + }; + + using (ZipArchive zipArchive = ZipFile.OpenRead(filePath)) + { + CollectionAssert.IsSubsetOf(expectedFiles, zipArchive.Entries.Select(e => e.FullName)); + } + } + finally + { + Directory.Delete(directoryPath, true); + } + } + + [Test] + public void Export_AssessmentSectionWithoutUserDefinedTargetProbabilities_ReturnsTrueAndWritesCorrectData() + { + // Setup + var assessmentSection = new AssessmentSectionStub(); + assessmentSection.SetHydraulicBoundaryLocationCalculations(new[] + { + new HydraulicBoundaryLocation(123, "aName", 1.1, 2.2) + }); + assessmentSection.WaterLevelCalculationsForUserDefinedTargetProbabilities.Clear(); + assessmentSection.WaveHeightCalculationsForUserDefinedTargetProbabilities.Clear(); + + string directoryPath = TestHelper.GetScratchPadPath(nameof(Export_AssessmentSectionWithoutUserDefinedTargetProbabilities_ReturnsTrueAndWritesCorrectData)); + Directory.CreateDirectory(directoryPath); + string filePath = Path.Combine(directoryPath, "test.zip"); + + var exporter = new HydraulicBoundaryLocationsExporter(assessmentSection, filePath); + try { // Call bool isExported = exporter.Export(); // Assert - FileTestHelper.AssertEssentialShapefilesExist(directoryPath, baseName, true); - FileTestHelper.AssertEssentialShapefileMd5Hashes(directoryPath, - baseName, - Path.Combine(TestHelper.GetTestDataPath(TestDataPath.Riskeer.Integration.IO), - nameof(HydraulicBoundaryLocationsExporter)), - "ExpectedExport", - 28, - 8, - 2637); Assert.IsTrue(isExported); + string[] expectedFiles = + { + "Waterstanden bij norm/Waterstanden_30.000.shp", + "Waterstanden bij norm/Waterstanden_30.000 (1).shp" + }; + + using (ZipArchive zipArchive = ZipFile.OpenRead(filePath)) + { + CollectionAssert.IsSubsetOf(expectedFiles, zipArchive.Entries.Select(e => e.FullName)); + } } finally { @@ -138,9 +182,9 @@ new HydraulicBoundaryLocation(123, "aName", 1.1, 2.2) }); - string directoryPath = TestHelper.GetScratchPadPath("Export_InvalidDirectoryRights_LogErrorAndReturnFalse"); + string directoryPath = TestHelper.GetScratchPadPath(nameof(Export_InvalidDirectoryRights_LogErrorAndReturnFalse)); Directory.CreateDirectory(directoryPath); - string filePath = Path.Combine(directoryPath, "test.shp"); + string filePath = Path.Combine(directoryPath, "test.zip"); var exporter = new HydraulicBoundaryLocationsExporter(assessmentSection, filePath); @@ -150,12 +194,13 @@ { // Call var isExported = true; - Action call = () => isExported = exporter.Export(); + void Call() => isExported = exporter.Export(); // Assert - string expectedMessage = $"Er is een onverwachte fout opgetreden tijdens het schrijven van het bestand '{filePath}'. " + + string expectedFilePath = Path.Combine(directoryPath, "~temp", "Waterstanden bij norm", "Waterstanden_30.000.shp"); + string expectedMessage = $"Er is een onverwachte fout opgetreden tijdens het schrijven van het bestand '{expectedFilePath}'. " + "Er zijn geen hydraulische belastingenlocaties geëxporteerd."; - TestHelper.AssertLogMessageIsGenerated(call, expectedMessage); + TestHelper.AssertLogMessageIsGenerated(Call, expectedMessage); Assert.IsFalse(isExported); } }