Index: Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj =================================================================== diff -u -r8dfec2e1be6d23c02919ff849906fc89822f99b3 -re41a8cc75ec6e93aee52452aa50f47638a044feb --- Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj (.../Ringtoets.Common.IO.csproj) (revision 8dfec2e1be6d23c02919ff849906fc89822f99b3) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj (.../Ringtoets.Common.IO.csproj) (revision e41a8cc75ec6e93aee52452aa50f47638a044feb) @@ -117,6 +117,7 @@ + Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/CriticalProfileProperties.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/CriticalProfileProperties.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/CriticalProfileProperties.cs (revision e41a8cc75ec6e93aee52452aa50f47638a044feb) @@ -0,0 +1,80 @@ +// 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 Core.Common.Base.IO; +using Core.Common.IO.Readers; +using Core.Common.Utils.Builders; +using Ringtoets.Common.IO.Properties; +using Ringtoets.Common.IO.SoilProfile.Schema; + +namespace Ringtoets.Common.IO.SoilProfile +{ + /// + /// This class describes properties which are critical when reading soil profiles from a data source. + /// If obtaining properties could not be obtained, then it is impossible to guarantee a correct import. + /// + internal class CriticalProfileProperties + { + /// + /// Creates a new instance of , which contains properties + /// that are critical for reading profiles. If these properties cannot be read, then something + /// went wrong while querying the database. + /// + /// The from which to obtain the critical properties. + /// Thrown when the values in the database could not be + /// casted to the expected column types. + public CriticalProfileProperties(IRowBasedDatabaseReader reader) + { + try + { + ProfileName = reader.Read(SoilProfileTableDefinitions.ProfileName); + LayerCount = reader.Read(SoilProfileTableDefinitions.LayerCount); + ProfileId = reader.Read(SoilProfileTableDefinitions.SoilProfileId); + } + catch (InvalidCastException e) + { + var messageBuilder = new FileReaderErrorMessageBuilder(reader.Path); + if (!string.IsNullOrEmpty(ProfileName)) + { + messageBuilder.WithSubject(string.Format(Resources.SoilProfileReader_SoilProfileName_0_, ProfileName)); + } + string message = messageBuilder.Build(Resources.SoilProfileReader_Critical_Unexpected_value_on_column); + throw new CriticalFileReadException(message, e); + } + } + + /// + /// The name of the profile to read + /// + public string ProfileName { get; } + + /// + /// The number of layers that the profile to read has + /// + public long LayerCount { get; } + + /// + /// Gets the database identifier of the profile. + /// + public long ProfileId { get; } + } +} \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs =================================================================== diff -u -r22cfdf3a1943df34a0e6cfd57c82faedfed781db -re41a8cc75ec6e93aee52452aa50f47638a044feb --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs (.../SoilProfile1DReader.cs) (revision 22cfdf3a1943df34a0e6cfd57c82faedfed781db) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs (.../SoilProfile1DReader.cs) (revision e41a8cc75ec6e93aee52452aa50f47638a044feb) @@ -139,50 +139,49 @@ /// Tries to read and create a . /// /// The read . - /// Thrown when reading properties of the profile failed. + /// Thrown when encountering an unrecoverable error + /// while reading the profile. + /// Thrown when reading properties of the profile + /// failed. private SoilProfile1D TryReadSoilProfile() { - long profileId = ReadProfileId(); + var criticalProperties = new CriticalProfileProperties(this); var soilLayers = new List(); RequiredProfileProperties properties; try { - properties = new RequiredProfileProperties(this); + properties = new RequiredProfileProperties(this, criticalProperties.ProfileName); - for (var i = 1; i <= properties.LayerCount; i++) + for (var i = 1; i <= criticalProperties.LayerCount; i++) { - soilLayers.Add(ReadSoilLayerFrom(this, properties.ProfileName)); + soilLayers.Add(ReadSoilLayerFrom(this, criticalProperties.ProfileName)); MoveNext(); } } catch (SoilProfileReadException) { - MoveToNextProfile(profileId); + MoveToNextProfile(criticalProperties.ProfileId); throw; } try { - return new SoilProfile1D(profileId, - properties.ProfileName, + return new SoilProfile1D(criticalProperties.ProfileId, + criticalProperties.ProfileName, properties.Bottom, soilLayers); } catch (ArgumentException exception) { + MoveToNextProfile(criticalProperties.ProfileId); throw new SoilProfileReadException( Resources.SoilProfile1DReader_ReadSoilProfile_Failed_to_construct_profile_from_read_data, - properties.ProfileName, + criticalProperties.ProfileName, exception); } } - private long ReadProfileId() - { - return dataReader.Read(SoilProfileTableDefinitions.SoilProfileId); - } - private void PrepareReader() { string soilProfile1DQuery = SoilDatabaseQueryBuilder.GetSoilProfile1DQuery(); @@ -311,45 +310,31 @@ /// that are required to create a complete . If these properties /// cannot be read, then the reader can proceed to the next profile. /// - /// The to read the required profile property values from. + /// The to read the required + /// profile property values from. + /// The profile name used in generating exceptions messages + /// if casting failed. /// Thrown when the values in the database could not be /// casted to the expected column types. - internal RequiredProfileProperties(IRowBasedDatabaseReader reader) + internal RequiredProfileProperties(IRowBasedDatabaseReader reader, string profileName) { - string readColumn = SoilProfileTableDefinitions.ProfileName; try { - ProfileName = reader.Read(SoilProfileTableDefinitions.ProfileName); - - readColumn = SoilProfileTableDefinitions.Bottom; - Bottom = reader.Read(readColumn); - - readColumn = SoilProfileTableDefinitions.LayerCount; - LayerCount = reader.Read(readColumn); + Bottom = reader.Read(SoilProfileTableDefinitions.Bottom); } catch (InvalidCastException e) { string message = string.Format(Resources.SoilProfileReader_Profile_Name_0_has_invalid_value_on_Column_1, - ProfileName, - readColumn); - throw new SoilProfileReadException(message, ProfileName, e); + profileName, + SoilProfileTableDefinitions.Bottom); + throw new SoilProfileReadException(message, profileName, e); } } /// /// The bottom of the profile. /// public double Bottom { get; } - - /// - /// The name of the profile to read. - /// - public string ProfileName { get; } - - /// - /// The number of layers that the profile has to read. - /// - public long LayerCount { get; } } } } \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj =================================================================== diff -u -rf755184a931f4254129c6c3ccdd67d898562fc47 -re41a8cc75ec6e93aee52452aa50f47638a044feb --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj (.../Ringtoets.Common.IO.Test.csproj) (revision f755184a931f4254129c6c3ccdd67d898562fc47) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj (.../Ringtoets.Common.IO.Test.csproj) (revision e41a8cc75ec6e93aee52452aa50f47638a044feb) @@ -110,6 +110,7 @@ + Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/CriticalProfilePropertiesTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/CriticalProfilePropertiesTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/CriticalProfilePropertiesTest.cs (revision e41a8cc75ec6e93aee52452aa50f47638a044feb) @@ -0,0 +1,127 @@ +// 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 Core.Common.Base.IO; +using Core.Common.IO.Readers; +using Core.Common.Utils.Builders; +using NUnit.Framework; +using Rhino.Mocks; +using Ringtoets.Common.IO.SoilProfile; +using Ringtoets.Common.IO.SoilProfile.Schema; + +namespace Ringtoets.Common.IO.Test.SoilProfile +{ + [TestFixture] + public class CriticalProfilePropertiesTest + { + private MockRepository mocks; + + [SetUp] + public void SetUp() + { + mocks = new MockRepository(); + } + + [TearDown] + public void TearDown() + { + mocks.VerifyAll(); + } + + [Test] + public void Constructor_WithReaderValuesValid_SetProperties() + { + // Setup + var reader = mocks.StrictMock(); + const string profileName = "profile"; + const int layerCount = 1; + const long soilProfileId = 1234; + + reader.Expect(r => r.Read(SoilProfileTableDefinitions.ProfileName)).IgnoreArguments().Return(profileName); + reader.Expect(r => r.Read(SoilProfileTableDefinitions.LayerCount)).IgnoreArguments().Return(layerCount); + reader.Expect(r => r.Read(SoilProfileTableDefinitions.SoilProfileId)).IgnoreArguments().Return(soilProfileId); + + mocks.ReplayAll(); + + // Call + var properties = new CriticalProfileProperties(reader); + + // Assert + Assert.AreEqual(profileName, properties.ProfileName); + Assert.AreEqual(layerCount, properties.LayerCount); + Assert.AreEqual(soilProfileId, properties.ProfileId); + } + + [Test] + public void Constructor_WithReaderInvalidProfileName_SetProperties() + { + // Setup + var reader = mocks.StrictMock(); + const int layerCount = 1; + const string path = "A"; + var invalidCastException = new InvalidCastException(); + + reader.Expect(r => r.Read(SoilProfileTableDefinitions.ProfileName)).IgnoreArguments().Throw(invalidCastException); + reader.Expect(r => r.Read(SoilProfileTableDefinitions.LayerCount)).IgnoreArguments().Return(layerCount).Repeat.Any(); + reader.Expect(r => r.Path).Return(path); + + mocks.ReplayAll(); + + // Call + TestDelegate test = () => new CriticalProfileProperties(reader); + + // Assert + var exception = Assert.Throws(test); + Assert.AreSame(invalidCastException, exception.InnerException); + string expectedMessage = new FileReaderErrorMessageBuilder(path) + .Build("Kritieke fout opgetreden bij het uitlezen van waardes uit kolommen in de database."); + Assert.AreEqual(expectedMessage, exception.Message); + } + + [Test] + public void Constructor_WithReaderInvalidLayerCount_SetProperties() + { + // Setup + var reader = mocks.StrictMock(); + const string profileName = "profile"; + const string path = "A"; + var invalidCastException = new InvalidCastException(); + + reader.Expect(r => r.Read(SoilProfileTableDefinitions.ProfileName)).IgnoreArguments().Return(profileName).Repeat.Any(); + reader.Expect(r => r.Read(SoilProfileTableDefinitions.LayerCount)).Throw(invalidCastException); + reader.Expect(r => r.Path).Return(path); + + mocks.ReplayAll(); + + // Call + TestDelegate test = () => new CriticalProfileProperties(reader); + + // Assert + var exception = Assert.Throws(test); + Assert.AreSame(invalidCastException, exception.InnerException); + string expectedMessage = new FileReaderErrorMessageBuilder(path) + .WithSubject($"ondergrondschematisatie '{profileName}'") + .Build("Kritieke fout opgetreden bij het uitlezen van waardes uit kolommen in de database."); + Assert.AreEqual(expectedMessage, exception.Message); + } + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile1DReaderTest.cs =================================================================== diff -u -r80f04760977eeb1f2f2781ff9600ffa4d51b7060 -re41a8cc75ec6e93aee52452aa50f47638a044feb --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile1DReaderTest.cs (.../SoilProfile1DReaderTest.cs) (revision 80f04760977eeb1f2f2781ff9600ffa4d51b7060) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile1DReaderTest.cs (.../SoilProfile1DReaderTest.cs) (revision e41a8cc75ec6e93aee52452aa50f47638a044feb) @@ -165,9 +165,59 @@ // Assert Assert.AreEqual(1, result.Count); Assert.AreEqual("Profile", result[0].Name); + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); } [Test] + public void ReadSoilProfile_LayerTopInvalidValue_ThrowsSoilProfileReadException() + { + // Setup + string dbFile = Path.Combine(testDataPath, "1dprofileWithInvalidTopLayer.soil"); + + using (var reader = new SoilProfile1DReader(dbFile)) + { + reader.Initialize(); + + // Call + TestDelegate test = () => reader.ReadSoilProfile(); + + // Assert + var exception = Assert.Throws(test); + const string expectedMessage = "Het lezen van de ondergrondschematisatie 'INCORRECT' is mislukt. " + + "Geen geldige waarde in kolom 'Top'."; + Assert.AreEqual(expectedMessage, exception.Message); + Assert.AreEqual("INCORRECT", exception.ProfileName); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + + [Test] + public void ReadSoilProfile_BottomInvalidValue_ThrowsSoilProfileReadException() + { + // Setup + string dbFile = Path.Combine(testDataPath, "1dprofileWithInvalidBottom.soil"); + + using (var reader = new SoilProfile1DReader(dbFile)) + { + reader.Initialize(); + + // Call + TestDelegate test = () => reader.ReadSoilProfile(); + + // Assert + var exception = Assert.Throws(test); + const string expectedMessage = "Het lezen van de ondergrondschematisatie 'Profile' is mislukt. " + + "Geen geldige waarde in kolom 'Bottom'."; + Assert.AreEqual(expectedMessage, exception.Message); + Assert.AreEqual("Profile", exception.ProfileName); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + + [Test] public void ReadSoilProfile_BottomAboveLayers_ThrowsSoilProfileReadException() { // Setup @@ -185,6 +235,8 @@ Assert.AreEqual("Het uitlezen van de ondergrondschematisatie is mislukt.", exception.Message); Assert.AreEqual("Profile", exception.ProfileName); } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); } [Test] @@ -255,6 +307,8 @@ 0.024752 }, profile.Layers.Select(l => l.PermeabilityCoefficientOfVariation)); } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); } } } \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile1DReader/1dprofileWithInvalidBottom.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile1DReader/1dprofileWithInvalidTopLayer.soil =================================================================== diff -u Binary files differ