Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/PipingSoilProfileReader.cs =================================================================== diff -u -r15d2770669092ea9574682421c755fc9b6c2e16f -r41d06d91a2ef710ad07b3f474f190400751e09b8 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/PipingSoilProfileReader.cs (.../PipingSoilProfileReader.cs) (revision 15d2770669092ea9574682421c755fc9b6c2e16f) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/PipingSoilProfileReader.cs (.../PipingSoilProfileReader.cs) (revision 41d06d91a2ef710ad07b3f474f190400751e09b8) @@ -82,7 +82,7 @@ return null; } - var dimensionValue = TryRead(dimensionColumn); + var dimensionValue = Read(dimensionColumn); return dimensionValue == 1 ? ReadPipingProfile1D() : ReadPipingProfile2D(); } @@ -106,10 +106,19 @@ private PipingSoilProfile ReadPipingProfile1D() { - var profileName = TryRead(profileNameColumn); - var layerCount = TryRead(layerCountColumn); - var bottom = TryRead(bottomColumn); + var profileName = Read(profileNameColumn); + var layerCount = Read(layerCountColumn); + double bottom; + try + { + bottom = Read(bottomColumn); + } catch (InvalidCastException e) { + SkipRecords((int)layerCount); + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, intersectionXColumn); + throw new PipingSoilProfileReadException(message, e); + } + var soilProfileBuilder = new SoilProfileBuilder1D(profileName, bottom); for (var i = 1; i <= layerCount; i++) @@ -131,12 +140,22 @@ /// to be build. private PipingSoilProfile ReadPipingProfile2D() { - var profileName = TryRead(profileNameColumn); - var layerCount = TryRead(layerCountColumn); - var intersectionX = TryRead(intersectionXColumn); + var profileName = Read(profileNameColumn); + var layerCount = Read(layerCountColumn); try { + double intersectionX; + try + { + intersectionX = TryRead(intersectionXColumn); + } + catch (InvalidCastException e) + { + SkipRecords((int)layerCount); + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, intersectionXColumn); + throw new PipingSoilProfileReadException(message, e); + } var soilProfileBuilder = new SoilProfileBuilder2D(profileName, intersectionX); for (int i = 1; i <= layerCount; i++) @@ -145,27 +164,49 @@ { soilProfileBuilder.Add(ReadPiping2DSoilLayer()); } - catch (SoilLayer2DConversionException e) + catch (XmlException e) { - HandleLayerParseException(layerCount, i, profileName, e); + SkipRecords((int)layerCount + 1 - i); + + var format = string.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, i, profileName); + throw new PipingSoilProfileReadException( + format, e); } - catch (XmlException e) + catch (SoilProfileBuilderException e) { - HandleLayerParseException(layerCount, i, profileName, e); + SkipRecords((int) layerCount + 1 - i); + + var format = string.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, i, profileName); + throw new PipingSoilProfileReadException( + format, e); } + catch (InvalidCastException e) + { + SkipRecords((int)layerCount + 1 - i); + + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, intersectionXColumn); + throw new PipingSoilProfileReadException(message, e); + } MoveNext(); } - return soilProfileBuilder.Build(); + try + { + return soilProfileBuilder.Build(); + } + catch (SoilProfileBuilderException e) + { + SkipRecords((int) 0 + 1 - 1); + var exception = new PipingSoilProfileReadException( + string.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, 1, profileName), e); + + throw exception; + } } catch (ArgumentException e) { HandleCriticalBuildException(profileName, e); } - catch (SoilProfileBuilderException e) - { - HandleCriticalBuildException(profileName, e); - } return null; } @@ -175,15 +216,6 @@ throw new CriticalFileReadException(message, e); } - private void HandleLayerParseException(long layerCount, int i, string profileName, Exception e) - { - SkipRecords((int) layerCount + 1 - i); - var exception = new PipingSoilProfileReadException( - string.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, i, profileName), e); - - throw exception; - } - private void SkipRecords(int count) { for(int i = 0; i < count; i++) @@ -192,12 +224,6 @@ } } - private void SetReaderToFirstRecord() - { - InitializeDataReader(); - MoveNext(); - } - /// /// Reads a value at column from the database. /// @@ -215,39 +241,25 @@ return default(T); } - try - { - return (T)dbValue; - } - catch (InvalidCastException) - { - throw new CriticalFileReadException(Resources.PipingSoilProfileReader_Invalid_value_on_column); - } + return (T)dbValue; } - - private void OpenConnection(string dbFile) - { - var connectionStringBuilder = new SQLiteConnectionStringBuilder - { - FailIfMissing = true, - DataSource = dbFile, - ReadOnly = true, - ForeignKeys = true - }; - connection = new SQLiteConnection(connectionStringBuilder.ConnectionString); - Connect(); - } - - private void Connect() + /// + /// Reads a value at column from the database. + /// + /// The expected type of value in the column with name . + /// The name of the column to read from. + /// The read value from the column with name . + /// Thrown when the value in the column was not of type . + private T Read(string columnName) { try { - connection.Open(); + return (T)dataReader[columnName]; } - catch (SQLiteException) + catch (InvalidCastException) { - connection.Dispose(); + throw new CriticalFileReadException(string.Format(Resources.PipingSoilProfileReader_Critical_Unexpected_value_on_column_0_, columnName)); } } @@ -277,6 +289,7 @@ private SoilLayer2D ReadPiping2DSoilLayer() { var geometryValue = TryRead(layerGeometryColumn); + var isAquiferValue = TryRead(isAquiferColumn); var belowPhreaticLevelValue = TryRead(belowPhreaticLevelColumn); var abovePhreaticLevelValue = TryRead(abovePhreaticLevelColumn); @@ -291,6 +304,38 @@ return pipingSoilLayer; } + private void SetReaderToFirstRecord() + { + InitializeDataReader(); + MoveNext(); + } + + private void OpenConnection(string dbFile) + { + var connectionStringBuilder = new SQLiteConnectionStringBuilder + { + FailIfMissing = true, + DataSource = dbFile, + ReadOnly = true, + ForeignKeys = true + }; + + connection = new SQLiteConnection(connectionStringBuilder.ConnectionString); + Connect(); + } + + private void Connect() + { + try + { + connection.Open(); + } + catch (SQLiteException) + { + connection.Dispose(); + } + } + /// /// Prepares the two queries required for obtaining all the SoilProfile1D and SoilProfile2D with an x defined /// to take an intersection from. Since two separate queries are used, the will @@ -491,7 +536,7 @@ private void GetCount() { dataReader.Read(); - Count = (int)TryRead(profileCountColumn); + Count = (int)Read(profileCountColumn); dataReader.NextResult(); } } Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.Designer.cs =================================================================== diff -u -r15d2770669092ea9574682421c755fc9b6c2e16f -r41d06d91a2ef710ad07b3f474f190400751e09b8 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 15d2770669092ea9574682421c755fc9b6c2e16f) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 41d06d91a2ef710ad07b3f474f190400751e09b8) @@ -196,6 +196,15 @@ } /// + /// Looks up a localized string similar to Database bevat een onverwachte waarde in kolom {0}.. + /// + public static string PipingSoilProfileReader_Critical_Unexpected_value_on_column_0_ { + get { + return ResourceManager.GetString("PipingSoilProfileReader_Critical_Unexpected_value_on_column_0_", resourceCulture); + } + } + + /// /// Looks up a localized string similar to De database '{0}' heeft niet de vereiste versie informatie. Vereiste versie is '{1}'.. /// public static string PipingSoilProfileReader_Database_file_0_incorrect_version_requires_1 { @@ -205,11 +214,11 @@ } /// - /// Looks up a localized string similar to Ondergrondprofiel in database bevat geen geldige waarde in kolom {0}.. + /// Looks up a localized string similar to Ondergrondprofiel '{0}' in database bevat geen geldige waarde in kolom '{1}'.. /// - public static string PipingSoilProfileReader_Invalid_value_on_column { + public static string PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_ { get { - return ResourceManager.GetString("PipingSoilProfileReader_Invalid_value_on_column", resourceCulture); + return ResourceManager.GetString("PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_", resourceCulture); } } Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.resx =================================================================== diff -u -r15d2770669092ea9574682421c755fc9b6c2e16f -r41d06d91a2ef710ad07b3f474f190400751e09b8 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.resx (.../Resources.resx) (revision 15d2770669092ea9574682421c755fc9b6c2e16f) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.resx (.../Resources.resx) (revision 41d06d91a2ef710ad07b3f474f190400751e09b8) @@ -156,8 +156,8 @@ Kon geen ondergrond profielen verkrijgen van de database '{0}'. - - Ondergrondprofiel in database bevat geen geldige waarde in kolom {0}. + + Ondergrondprofiel '{0}' in database bevat geen geldige waarde in kolom '{1}'. Het bestand op '{0}' is niet geschikt om dwarsdoorsneden uit te lezen (Verwachte header: locationid;X1;Y1;Z1). @@ -186,4 +186,7 @@ De segmenten van de geometrie van de laag vormen geen lus. + + Database bevat een onverwachte waarde in kolom {0}. + \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Plugin/FileImporter/PipingSoilProfilesImporter.cs =================================================================== diff -u -r97c9e382dffcf32dc34d2e05e6a8a475b833ebd4 -r41d06d91a2ef710ad07b3f474f190400751e09b8 --- Ringtoets/Piping/src/Ringtoets.Piping.Plugin/FileImporter/PipingSoilProfilesImporter.cs (.../PipingSoilProfilesImporter.cs) (revision 97c9e382dffcf32dc34d2e05e6a8a475b833ebd4) +++ Ringtoets/Piping/src/Ringtoets.Piping.Plugin/FileImporter/PipingSoilProfilesImporter.cs (.../PipingSoilProfilesImporter.cs) (revision 41d06d91a2ef710ad07b3f474f190400751e09b8) @@ -146,8 +146,6 @@ var totalNumberOfSteps = soilProfileReader.Count; var currentStep = 1; - NotifyProgress(ApplicationResources.PipingSoilProfilesImporter_ReadingSoilProfiles, currentStep, totalNumberOfSteps); - var profiles = new Collection(); while (soilProfileReader.HasNext) { Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilProfileReaderTest.cs =================================================================== diff -u -r15d2770669092ea9574682421c755fc9b6c2e16f -r41d06d91a2ef710ad07b3f474f190400751e09b8 --- Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilProfileReaderTest.cs (.../PipingSoilProfileReaderTest.cs) (revision 15d2770669092ea9574682421c755fc9b6c2e16f) +++ Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilProfileReaderTest.cs (.../PipingSoilProfileReaderTest.cs) (revision 41d06d91a2ef710ad07b3f474f190400751e09b8) @@ -6,7 +6,6 @@ using System.Linq; using Core.Common.TestUtils; using NUnit.Framework; -using NUnit.Framework.Constraints; using Ringtoets.Piping.Data; using Ringtoets.Piping.IO.Exceptions; using Ringtoets.Piping.IO.Properties; @@ -154,6 +153,32 @@ } [Test] + public void ReadProfile_DatabaseProfileWithVerticalSegmentAtX_SkipsTheProfile() + { + // Setup + var testFile = "vertical2dGeometry.soil"; + using (var pipingSoilProfilesReader = new PipingSoilProfileReader(Path.Combine(testDataPath, testFile))) + { + // Call + TestDelegate profile = () => pipingSoilProfilesReader.ReadProfile(); + + // Assert + var exception = Assert.Throws(profile); + var message = String.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, 1, "Profile"); + Assert.AreEqual(message, exception.Message); + + // Call + var pipingSoilProfile = pipingSoilProfilesReader.ReadProfile(); + + // Assert + Assert.AreEqual("Profile2", pipingSoilProfile.Name); + Assert.AreEqual(3, pipingSoilProfile.Layers.Count()); + + Assert.IsTrue(FileHelper.CanOpenFileForWrite(testFile)); + } + } + + [Test] public void ReadProfile_DatabaseProfileWithoutValuesForLayerProperties_ReturnsProfileWithAllLayers() { // Setup Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/test-data/PipingSoilProfilesReader/incorrectValue2dProperty.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/test-data/PipingSoilProfilesReader/invalidAtX2dProperty.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/test-data/PipingSoilProfilesReader/invalidBottom1dProfile.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/test-data/PipingSoilProfilesReader/invalidTop1dProfile.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/test-data/PipingSoilProfilesReader/vertical2dGeometry.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Piping/test/Ringtoets.Piping.Plugin.Test/FileImporter/PipingSoilProfilesImporterTest.cs =================================================================== diff -u -r15d2770669092ea9574682421c755fc9b6c2e16f -r41d06d91a2ef710ad07b3f474f190400751e09b8 --- Ringtoets/Piping/test/Ringtoets.Piping.Plugin.Test/FileImporter/PipingSoilProfilesImporterTest.cs (.../PipingSoilProfilesImporterTest.cs) (revision 15d2770669092ea9574682421c755fc9b6c2e16f) +++ Ringtoets/Piping/test/Ringtoets.Piping.Plugin.Test/FileImporter/PipingSoilProfilesImporterTest.cs (.../PipingSoilProfilesImporterTest.cs) (revision 41d06d91a2ef710ad07b3f474f190400751e09b8) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Core.Common.Base; using Core.Common.TestUtils; using NUnit.Framework; @@ -20,7 +21,14 @@ public class PipingSoilProfilesImporterTest { private readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Piping.IO, "PipingSoilProfilesReader"); + private int progress; + [SetUp] + public void SetUp() + { + progress = 0; + } + [Test] public void DefaultConstructor_ExpectedValues() { @@ -83,13 +91,100 @@ } [Test] + public void ImportItem_FromNonExistingFile_LogError() + { + // Setup + var file = "nonexisting.soil"; + string validFilePath = Path.Combine(testDataPath, file); + + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + mocks.ReplayAll(); + + var observableList = new ObservableList(); + observableList.Attach(observer); + + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; + + // Precondition + CollectionAssert.IsEmpty(observableList); + Assert.IsTrue(importer.CanImportOn(observableList)); + + object importedItem = null; + + // Call + Action call = () => importedItem = importer.ImportItem(validFilePath, observableList); + + // Assert + TestHelper.AssertLogMessages(call, messages => + { + string[] messageArray = messages.ToArray(); + var message = string.Format(ApplicationResources.PipingSoilProfilesImporter_Critical_error_reading_File_0_Cause_1_, validFilePath, String.Empty); + StringAssert.StartsWith(message, messageArray[0]); + }); + Assert.AreSame(observableList, importedItem); + CollectionAssert.IsEmpty(observableList); + Assert.AreEqual(1, progress); + + mocks.VerifyAll(); // 'observer' should not be notified + } + + [Test] + public void ImportItem_FromInvalidFileName_LogError() + { + // Setup + var file = "/"; + string validFilePath = Path.Combine(testDataPath, file); + + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + mocks.ReplayAll(); + + var observableList = new ObservableList(); + observableList.Attach(observer); + + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; + + // Precondition + CollectionAssert.IsEmpty(observableList); + Assert.IsTrue(importer.CanImportOn(observableList)); + + object importedItem = null; + + // Call + Action call = () => importedItem = importer.ImportItem(validFilePath, observableList); + + // Assert + TestHelper.AssertLogMessages(call, messages => + { + string[] messageArray = messages.ToArray(); + var message = string.Format(ApplicationResources.PipingSoilProfilesImporter_Critical_error_reading_File_0_Cause_1_, validFilePath, String.Empty); + StringAssert.StartsWith(message, messageArray[0]); + }); + Assert.AreSame(observableList, importedItem); + CollectionAssert.IsEmpty(observableList); + Assert.AreEqual(1, progress); + + mocks.VerifyAll(); // 'observer' should not be notified + } + + [Test] public void ImportItem_ImportingToValidTargetWithValidFile_ImportSoilProfilesToCollection() { // Setup string validFilePath = Path.Combine(testDataPath, "complete.soil"); var piping = new PipingFailureMechanism(); - var importer = new PipingSoilProfilesImporter(); + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; var importTarget = piping.SoilProfiles; @@ -101,6 +196,7 @@ // Assert Assert.AreSame(importTarget, importedItem); + Assert.AreEqual(28, progress); } [Test] @@ -116,7 +212,10 @@ var observableList = new ObservableList(); observableList.Attach(observer); - var importer = new PipingSoilProfilesImporter(); + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; // Precondition CollectionAssert.IsEmpty(observableList); @@ -134,6 +233,7 @@ TestHelper.AssertLogMessageIsGenerated(call, ApplicationResources.PipingSoilProfilesImporter_ImportItem_Import_cancelled, 1); Assert.AreSame(observableList, importedItem); CollectionAssert.IsEmpty(observableList); + Assert.AreEqual(1, progress); mocks.VerifyAll(); // 'observer' should not be notified } @@ -148,7 +248,10 @@ var observer = mocks.StrictMock(); mocks.ReplayAll(); - var importer = new PipingSoilProfilesImporter(); + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; var observableSoilProfileList = new ObservableList(); observableSoilProfileList.Attach(observer); @@ -167,21 +270,26 @@ Assert.AreSame(observableSoilProfileList, importedItem); CollectionAssert.IsEmpty(observableSoilProfileList, "No items should be added to collection when import is aborted."); + Assert.AreEqual(1, progress); + mocks.VerifyAll(); // Expect no calls on 'observer' } [Test] - public void ImportItem_ImportingToValidTargetWithProfileContainingInvalidValue_SkipImportAndLog() + public void ImportItem_ImportingToValidTargetWithProfileContainingInvalidAtX_SkipImportAndLog() { // Setup - string corruptPath = Path.Combine(testDataPath, "invalid2dGeometry.soil"); + string corruptPath = Path.Combine(testDataPath, "invalidAtX2dProperty.soil"); var mocks = new MockRepository(); var observer = mocks.StrictMock(); observer.Expect(o => o.UpdateObserver()); mocks.ReplayAll(); - var importer = new PipingSoilProfilesImporter(); + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; var observableSoilProfileList = new ObservableList(); observableSoilProfileList.Attach(observer); @@ -192,16 +300,53 @@ Action call = () => importedItem = importer.ImportItem(corruptPath, observableSoilProfileList); // Assert - var internalErrorMessage = string.Format(WtiIOResources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, - 1, "Profile"); + var internalErrorMessage = string.Format(WtiIOResources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, + "Profile","IntersectionX"); var expectedLogMessage = string.Format(ApplicationResources.PipingSoilProfilesImporter_ReadSoilProfiles_File_0_Message_1_, corruptPath, internalErrorMessage); TestHelper.AssertLogMessageIsGenerated(call, expectedLogMessage, 1); Assert.AreSame(observableSoilProfileList, importedItem); Assert.AreEqual(1, observableSoilProfileList.Count); + Assert.AreEqual(4, progress); mocks.VerifyAll(); } + + [Test] + public void ImportItem_ImportingToValidTargetWithProfileContainingInvalidParameterValue_ZeroForValue() + { + // Setup + string corruptPath = Path.Combine(testDataPath, "incorrectValue2dProperty.soil"); + + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + observer.Expect(o => o.UpdateObserver()); + mocks.ReplayAll(); + + var importer = new PipingSoilProfilesImporter + { + ProgressChanged = IncrementProgress + }; + + var observableSoilProfileList = new ObservableList(); + observableSoilProfileList.Attach(observer); + + // Call + var importedItem = importer.ImportItem(corruptPath, observableSoilProfileList); + + Assert.AreSame(observableSoilProfileList, importedItem); + Assert.AreEqual(0.0, observableSoilProfileList[0].Layers.ElementAt(0).DryUnitWeight); + Assert.AreEqual(0.0, observableSoilProfileList[1].Layers.ElementAt(1).DryUnitWeight); + Assert.AreEqual(2, observableSoilProfileList.Count); + Assert.AreEqual(4, progress); + + mocks.VerifyAll(); + } + + private void IncrementProgress(string a, int b, int c) + { + progress++; + } } } \ No newline at end of file