Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingSoilProfile.cs =================================================================== diff -u -rf7d48349feba2a41391fac27dc3fef3028df091d -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingSoilProfile.cs (.../PipingSoilProfile.cs) (revision f7d48349feba2a41391fac27dc3fef3028df091d) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingSoilProfile.cs (.../PipingSoilProfile.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -20,6 +20,7 @@ /// The name of the profile. /// The bottom level of the profile. /// The collection of layers that should be part of the profile. + /// Thrown when is null or contains no layers. public PipingSoilProfile(string name, double bottom, IEnumerable layers) { Name = name; @@ -41,6 +42,7 @@ /// Gets an ordered (by , descending) of /// for the . /// + /// Thrown when the value is null or contains no layers. public IEnumerable Layers { get Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/Segment2D.cs =================================================================== diff -u -r602479eb3666493485aee246d56b08958a6fc958 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/Segment2D.cs (.../Segment2D.cs) (revision 602479eb3666493485aee246d56b08958a6fc958) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/Segment2D.cs (.../Segment2D.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -14,6 +14,8 @@ /// /// The first of the . /// The second of the . + /// Thrown when either the or + /// point is null. public Segment2D(Point2D first, Point2D second) { if (first == null || second == null) @@ -100,7 +102,7 @@ } } - protected bool Equals(Segment2D other) + private bool Equals(Segment2D other) { return FirstPoint.Equals(other.FirstPoint) && SecondPoint.Equals(other.SecondPoint) || FirstPoint.Equals(other.SecondPoint) && SecondPoint.Equals(other.FirstPoint); Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Builders/SoilLayer2D.cs =================================================================== diff -u -r2a49b7243807fe0b95136efd55652201164a6c74 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Builders/SoilLayer2D.cs (.../SoilLayer2D.cs) (revision 2a49b7243807fe0b95136efd55652201164a6c74) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Builders/SoilLayer2D.cs (.../SoilLayer2D.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -50,7 +50,8 @@ /// Gets the outer loop of the as a of , /// for which each of the segments are connected to the next. /// - /// Thrown when the does not form a loop. + /// Thrown when the in + /// do not form a loop. public IEnumerable OuterLoop { get @@ -81,7 +82,8 @@ /// Adds an inner loop to the geometry. /// /// The innerloop to add. - /// Thrown when the does not form a loop. + /// Thrown when the in + /// do not form a loop. internal void AddInnerLoop(IEnumerable innerLoop) { var loop = innerLoop.ToArray(); Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Builders/SoilProfileBuilder1D.cs =================================================================== diff -u -r97c9e382dffcf32dc34d2e05e6a8a475b833ebd4 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Builders/SoilProfileBuilder1D.cs (.../SoilProfileBuilder1D.cs) (revision 97c9e382dffcf32dc34d2e05e6a8a475b833ebd4) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Builders/SoilProfileBuilder1D.cs (.../SoilProfileBuilder1D.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using Ringtoets.Piping.Data; namespace Ringtoets.Piping.IO.Builders @@ -23,6 +24,7 @@ /// Creates a new instances of the based on the layer definitions. /// /// A new . + /// Thrown when no layers have been added through . public PipingSoilProfile Build() { return new PipingSoilProfile(name, bottom, layers); Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Exceptions/PipingSoilProfileReadException.cs =================================================================== diff -u -ra950714ad9510756331d862aa35695fa0b2ed03b -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Exceptions/PipingSoilProfileReadException.cs (.../PipingSoilProfileReadException.cs) (revision a950714ad9510756331d862aa35695fa0b2ed03b) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Exceptions/PipingSoilProfileReadException.cs (.../PipingSoilProfileReadException.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -1,6 +1,6 @@ using System; - using Ringtoets.Piping.Data; +using Ringtoets.Piping.IO.SoilProfile; namespace Ringtoets.Piping.IO.Exceptions { @@ -12,27 +12,41 @@ /// /// Initializes a new instance of the class. /// - public PipingSoilProfileReadException() + /// The name of the profile for which this exception was thrown. + public PipingSoilProfileReadException(string profileName) { + ProfileName = profileName; } /// /// Initializes a new instance of the class /// with a specified error message. /// + /// The name of the profile for which this exception was thrown. /// The message that describes the error. - public PipingSoilProfileReadException(string message) + public PipingSoilProfileReadException(string profileName, string message) : base(message) { + ProfileName = profileName; } /// /// Initializes a new instance of the class with a specified error message /// and a reference to the inner exception that is the cause of this exception. /// + /// The name of the profile for which this exception was thrown. /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, or a /// null reference if no inner exception is specified. - public PipingSoilProfileReadException(string message, Exception innerException) : base(message, innerException) { } + public PipingSoilProfileReadException(string profileName, string message, Exception innerException) + : base(message, innerException) + { + ProfileName = profileName; + } + + /// + /// The name of the profile for which this exception was thrown. + /// + public string ProfileName { get; private set; } } } \ No newline at end of file Fisheye: Tag 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 refers to a dead (removed) revision in file `Ringtoets/Piping/src/Ringtoets.Piping.IO/PipingSoilLayer2DReader.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 refers to a dead (removed) revision in file `Ringtoets/Piping/src/Ringtoets.Piping.IO/PipingSoilProfileReader.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.Designer.cs =================================================================== diff -u -rf69d756f50ae1464a1a11f0780b6d6aa646f3114 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision f69d756f50ae1464a1a11f0780b6d6aa646f3114) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -205,11 +205,11 @@ } /// - /// Looks up a localized string similar to Database bevat een onverwachte waarde in kolom {0}.. + /// Looks up a localized string similar to Kritieke fout opgetreden bij het uitlezen van waarden uit kolommen in de database.. /// - public static string PipingSoilProfileReader_Critical_Unexpected_value_on_column_0_ { + public static string PipingSoilProfileReader_Critical_Unexpected_value_on_column { get { - return ResourceManager.GetString("PipingSoilProfileReader_Critical_Unexpected_value_on_column_0_", resourceCulture); + return ResourceManager.GetString("PipingSoilProfileReader_Critical_Unexpected_value_on_column", resourceCulture); } } @@ -285,5 +285,14 @@ return ResourceManager.GetString("SoilLayer2D_Error_Loop_contains_disconnected_segments", resourceCulture); } } + + /// + /// Looks up a localized string similar to Het XML document dat de geometrie beschrijft voor de laag is niet valide.. + /// + public static string SoilLayer2DReader_Geometry_contains_no_valid_xml { + get { + return ResourceManager.GetString("SoilLayer2DReader_Geometry_contains_no_valid_xml", resourceCulture); + } + } } } Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.resx =================================================================== diff -u -rf69d756f50ae1464a1a11f0780b6d6aa646f3114 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.resx (.../Resources.resx) (revision f69d756f50ae1464a1a11f0780b6d6aa646f3114) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Properties/Resources.resx (.../Resources.resx) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -186,10 +186,13 @@ De segmenten van de geometrie van de laag vormen geen lus. - - Database bevat een onverwachte waarde in kolom {0}. + + Kritieke fout opgetreden bij het uitlezen van waarden uit kolommen in de database. Punten voor een lijn moeten uitelkaar liggen om een lijn te kunnen vormen. + + Het XML document dat de geometrie beschrijft voor de laag is niet valide. + \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/Ringtoets.Piping.IO.csproj =================================================================== diff -u -r2a49b7243807fe0b95136efd55652201164a6c74 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/Ringtoets.Piping.IO.csproj (.../Ringtoets.Piping.IO.csproj) (revision 2a49b7243807fe0b95136efd55652201164a6c74) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/Ringtoets.Piping.IO.csproj (.../Ringtoets.Piping.IO.csproj) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -52,15 +52,20 @@ - - + + + + + + True True Resources.resx + Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/CriticalProfileProperties.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/CriticalProfileProperties.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/CriticalProfileProperties.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,33 @@ +using System; +using Ringtoets.Piping.IO.Exceptions; +using Ringtoets.Piping.IO.Properties; + +namespace Ringtoets.Piping.IO.SoilProfile +{ + internal class CriticalProfileProperties + { + internal readonly string ProfileName; + internal readonly long LayerCount; + + /// + /// 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. + /// + /// + /// Thrown when the values in the database could not be + /// casted to the expected column types. + internal CriticalProfileProperties(IRowBasedReader reader) + { + try + { + ProfileName = reader.Read(SoilProfileDatabaseColumns.ProfileName); + LayerCount = reader.Read(SoilProfileDatabaseColumns.LayerCount); + } + catch (InvalidCastException e) + { + throw new CriticalFileReadException(Resources.PipingSoilProfileReader_Critical_Unexpected_value_on_column, e); + } + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/IRowBasedReader.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/IRowBasedReader.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/IRowBasedReader.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,32 @@ +using System; +using Ringtoets.Piping.IO.Exceptions; + +namespace Ringtoets.Piping.IO.SoilProfile +{ + internal interface IRowBasedReader + { + /// + /// Moves the reader to the next record in the database. + /// + void MoveNext(); + + /// + /// 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 . + T Read(string columnName); + + /// + /// Reads the value in the column with name from the + /// current row that's being pointed at. + /// + /// The type of object to read. + /// The name of the column to read from. + /// The value in the column, or null if the value was . + /// Thrown when the value in the column could not be casted to type . + T? ReadOrNull(string columnName) where T : struct; + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/PipingSoilProfileReader.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/PipingSoilProfileReader.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/PipingSoilProfileReader.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,393 @@ +using System; +using System.Data; +using System.Data.SQLite; +using System.IO; +using Ringtoets.Piping.Data; +using Ringtoets.Piping.IO.Exceptions; +using Ringtoets.Piping.IO.Properties; + +namespace Ringtoets.Piping.IO.SoilProfile +{ + /// + /// This class reads a SqLite database file and constructs instances from this database. + /// + public class PipingSoilProfileReader : IRowBasedReader, IDisposable + { + private const string databaseRequiredVersion = "15.0.5.0"; + private const string pipingMechanismName = "Piping"; + private const string mechanismParameterName = "mechanism"; + + private readonly string databaseFileName; + + private SQLiteConnection connection; + private SQLiteDataReader dataReader; + + /// + /// Creates a new instance of which will use the + /// as its source. The reader will not point to any record at the start. Use to start reading + /// profiles. + /// + /// The path of the database file to open. + /// Thrown when: + /// + /// The contains invalid characters. + /// No file could be found at . + /// Preparing the queries to read from the database failed. + /// + /// + public PipingSoilProfileReader(string databaseFilePath) + { + try + { + FileUtils.ValidateFilePath(databaseFilePath); + } + catch (ArgumentException e) + { + throw new CriticalFileReadException(e.Message, e); + } + if (!File.Exists(databaseFilePath)) + { + throw new CriticalFileReadException(string.Format(Resources.Error_File_0_does_not_exist, databaseFilePath)); + } + + databaseFileName = Path.GetFileName(databaseFilePath); + OpenConnection(databaseFilePath); + SetReaderToFirstRecord(); + } + + /// + /// Gets the total number of profiles that can be read from the database. + /// + public int Count { get; private set; } + + /// + /// Gets the value true if profiles can be read using the . + /// false otherwise. + /// + public bool HasNext { get; private set; } + + /// + /// Reads the information for the next profile from the database and creates a instance + /// of the information. + /// + /// The next from the database, or null if no more profiles can be read. + /// Thrown when reading the profile in the database contained a non-parsable geometry. + /// Thrown when the database returned incorrect values for required properties. + public PipingSoilProfile ReadProfile() + { + if (!HasNext) + { + return null; + } + + try + { + return ReadPipingSoilProfile(); + } + catch (InvalidCastException e) + { + throw new CriticalFileReadException(Resources.PipingSoilProfileReader_Critical_Unexpected_value_on_column, e); + } + } + + /// + /// Reads a from the database. + /// + /// A new . + /// Thrown when a recoverable error occurred while reading from the database. + /// Thrown when recovering from the failed. + private PipingSoilProfile ReadPipingSoilProfile() + { + try + { + var dimensionValue = Read(SoilProfileDatabaseColumns.Dimension); + return dimensionValue == 1 ? SoilProfile1DReader.ReadFrom(this) : SoilProfile2DReader.ReadFrom(this); + } + catch (PipingSoilProfileReadException e) + { + MoveToNextProfile(e.ProfileName); + throw; + } + } + + private void MoveToNextProfile(string profileName) + { + while (Read(SoilProfileDatabaseColumns.ProfileName).Equals(profileName)) + { + MoveNext(); + } + } + + public void Dispose() + { + if (dataReader != null) + { + dataReader.Dispose(); + } + connection.Close(); + connection.Dispose(); + } + + /// + /// Moves the reader to the next record in the database. + /// + public void MoveNext() + { + HasNext = dataReader.Read() || (dataReader.NextResult() && dataReader.Read()); + } + + /// + /// Reads the value in the column with name from the + /// current row that's being pointed at. + /// + /// The type of object to read. + /// The name of the column to read from. + /// The value in the column, or null if the value was . + /// Thrown when the value in the column could not be casted to type . + public T? ReadOrNull(string columnName) where T : struct + { + var valueObject = dataReader[columnName]; + if (valueObject.Equals(DBNull.Value)) + { + return null; + } + return (T) valueObject; + } + + /// + /// 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 . + public T Read(string columnName) + { + return (T) dataReader[columnName]; + } + + private void SetReaderToFirstRecord() + { + InitializeDataReader(); + MoveNext(); + } + + /// Thrown when opening the connection failed. + private void OpenConnection(string dbFile) + { + var connectionStringBuilder = new SQLiteConnectionStringBuilder + { + FailIfMissing = true, + DataSource = dbFile, + ReadOnly = true, + ForeignKeys = true + }; + + connection = new SQLiteConnection(connectionStringBuilder.ConnectionString); + connection.Open(); + } + + /// + /// 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 + /// have two result sets which the method takes into account. + /// + private void InitializeDataReader() + { + string versionQuery = string.Format( + "SELECT Value FROM _Metadata WHERE Key = 'VERSION' AND Value = '{0}';", + databaseRequiredVersion + ); + + string countQuery = string.Format(string.Join( + " ", + "SELECT", + "(SELECT COUNT(*)", + "FROM Mechanism as m", + "JOIN MechanismPointLocation as mpl ON mpl.ME_ID = m.ME_ID", + "JOIN SoilProfile2D as p2 ON p2.SP2D_ID = mpl.SP2D_ID", + "WHERE m.ME_Name = @{0})", + " + ", + "(SELECT COUNT(*)", + "FROM SoilProfile1D) as {1};"), mechanismParameterName, SoilProfileDatabaseColumns.ProfileCount); + + string materialPropertiesQuery = string.Format( + string.Join(" ", + "(SELECT", + "m.MA_ID,", + "sum(case when pn.PN_Name = 'AbovePhreaticLevel' then pv.PV_Value end) {0},", + "sum(case when pn.PN_Name = 'BelowPhreaticLevel' then pv.PV_Value end) {1},", + "sum(case when pn.PN_Name = 'DryUnitWeight' then pv.PV_Value end) {2}", + "FROM ParameterNames as pn", + "JOIN ParameterValues as pv ON pn.PN_ID = pv.PN_ID", + "JOIN Materials as m ON m.MA_ID = pv.MA_ID", + "GROUP BY m.MA_ID) as mat ON l.MA_ID = mat.MA_ID"), + SoilProfileDatabaseColumns.AbovePhreaticLevel, + SoilProfileDatabaseColumns.BelowPhreaticLevel, + SoilProfileDatabaseColumns.DryUnitWeight); + + string layer1DCountQuery = string.Format( + string.Join(" ", + "(SELECT SP1D_ID, COUNT(*) as {0}", + "FROM SoilLayer1D", + "GROUP BY SP1D_ID) lc ON lc.SP1D_ID = p.SP1D_ID"), SoilProfileDatabaseColumns.LayerCount); + + string layer2DCountQuery = string.Format( + string.Join(" ", + "(SELECT SP2D_ID, COUNT(*) as {0}", + "FROM SoilLayer2D", + "GROUP BY SP2D_ID) lc ON lc.SP2D_ID = p.SP2D_ID"), SoilProfileDatabaseColumns.LayerCount); + + string layer1DPropertiesQuery = string.Format( + string.Join(" ", + "(SELECT", + "pv.SL1D_ID,", + "sum(case when pn.PN_Name = 'IsAquifer' then pv.PV_Value end) {0}", + "FROM ParameterNames as pn", + "JOIN LayerParameterValues as pv ON pn.PN_ID = pv.PN_ID", + "GROUP BY pv.SL1D_ID) as lpv ON lpv.SL1D_ID = l.SL1D_ID" + ), SoilProfileDatabaseColumns.IsAquifer); + + string layer2DPropertiesQuery = string.Format( + string.Join(" ", + "(SELECT", + "pv.SL2D_ID,", + "sum(case when pn.PN_Name = 'IsAquifer' then pv.PV_Value end) {0}", + "FROM ParameterNames as pn", + "JOIN LayerParameterValues as pv ON pn.PN_ID = pv.PN_ID", + "GROUP BY pv.SL2D_ID) as lpv ON lpv.SL2D_ID = l.SL2D_ID" + ), SoilProfileDatabaseColumns.IsAquifer); + + var query1D = string.Format( + string.Join(" ", "SELECT", + "1 as {0},", + "p.SP1D_Name as {1},", + "lc.{2},", + "p.BottomLevel as {3},", + "l.TopLevel as {4},", + "{5},", + "{6},", + "{7},", + "{8}", + "FROM SoilProfile1D as p", + "JOIN {9}", + "JOIN SoilLayer1D as l ON l.SP1D_ID = p.SP1D_ID", + "LEFT JOIN {10}", + "LEFT JOIN {11}", + "ORDER BY ProfileName;"), + SoilProfileDatabaseColumns.Dimension, + SoilProfileDatabaseColumns.ProfileName, + SoilProfileDatabaseColumns.LayerCount, + SoilProfileDatabaseColumns.Bottom, + SoilProfileDatabaseColumns.Top, + SoilProfileDatabaseColumns.AbovePhreaticLevel, + SoilProfileDatabaseColumns.BelowPhreaticLevel, + SoilProfileDatabaseColumns.DryUnitWeight, + SoilProfileDatabaseColumns.IsAquifer, + layer1DCountQuery, + materialPropertiesQuery, + layer1DPropertiesQuery); + + var query2D = string.Format( + string.Join(" ", + "SELECT", + "2 as {0},", + "p.SP2D_Name as {1},", + "lc.{2},", + "l.GeometrySurface as {3}, ", + "mpl.X as {4},", + "{5},", + "{6},", + "{7},", + "{8}", + "FROM Mechanism as m", + "JOIN MechanismPointLocation as mpl ON mpl.ME_ID = m.ME_ID", + "JOIN SoilProfile2D as p ON p.SP2D_ID = mpl.SP2D_ID", + "JOIN {9}", + "JOIN SoilLayer2D as l ON l.SP2D_ID = p.SP2D_ID", + "LEFT JOIN {10}", + "LEFT JOIN {11}", + "WHERE m.ME_Name = @{12}", + "ORDER BY ProfileName;"), + SoilProfileDatabaseColumns.Dimension, + SoilProfileDatabaseColumns.ProfileName, + SoilProfileDatabaseColumns.LayerCount, + SoilProfileDatabaseColumns.LayerGeometry, + SoilProfileDatabaseColumns.IntersectionX, + SoilProfileDatabaseColumns.AbovePhreaticLevel, + SoilProfileDatabaseColumns.BelowPhreaticLevel, + SoilProfileDatabaseColumns.DryUnitWeight, + SoilProfileDatabaseColumns.IsAquifer, + layer2DCountQuery, + materialPropertiesQuery, + layer2DPropertiesQuery, + mechanismParameterName); + + CreateDataReader(versionQuery + countQuery + query2D + query1D, new SQLiteParameter + { + DbType = DbType.String, + Value = pipingMechanismName, + ParameterName = mechanismParameterName + }); + } + + /// + /// Creates a new data reader to use in this class. + /// + /// Thrown when + /// + /// Version of the database doesn't match the required version. + /// Version of the database could not be read. + /// Amount of profiles in database could not be read. + /// A query could not be executed on the database schema. + /// + /// + private void CreateDataReader(string queryString, params SQLiteParameter[] parameters) + { + using (var query = new SQLiteCommand(connection) + { + CommandText = queryString + }) + { + query.Parameters.AddRange(parameters); + + try + { + dataReader = query.ExecuteReader(); + CheckVersion(); + GetCount(); + } + catch (SQLiteException e) + { + Dispose(); + var exception = new CriticalFileReadException(string.Format(Resources.Error_SoilProfile_read_from_database, databaseFileName), e); + throw exception; + } + } + } + + /// + /// Checks the version read from the metadata table against the . + /// + /// Thrown when versions don't match. + private void CheckVersion() + { + if (!dataReader.HasRows) + { + Dispose(); + throw new CriticalFileReadException(string.Format( + Resources.PipingSoilProfileReader_Database_file_0_incorrect_version_requires_1, + databaseFileName, + databaseRequiredVersion)); + } + dataReader.NextResult(); + } + + private void GetCount() + { + dataReader.Read(); + Count = (int) Read(SoilProfileDatabaseColumns.ProfileCount); + dataReader.NextResult(); + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilLayer2DReader.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilLayer2DReader.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilLayer2DReader.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Xml; +using Ringtoets.Piping.Data; +using Ringtoets.Piping.IO.Builders; +using Ringtoets.Piping.IO.Properties; + +namespace Ringtoets.Piping.IO.SoilProfile +{ + /// + /// This class is responsible for reading an array of bytes and interpret this as a XML document, which contains information about + /// the geometry of a . + /// + internal class SoilLayer2DReader + { + private const string outerLoopElementName = "OuterLoop"; + private const string innerLoopElementName = "InnerLoop"; + private const string endPointElementName = "EndPoint"; + private const string headPointElementName = "HeadPoint"; + private const string geometryCurveElementName = "GeometryCurve"; + private const string xElementName = "X"; + private const string zElementName = "Z"; + + private readonly XmlTextReader xmlTextReader; + + /// + /// Constructs a new , which uses the as the source of the + /// geometry for a . + /// + /// An array of which contains the information of a + /// in an XML document. + /// Thrown when is null. + internal SoilLayer2DReader(byte[] geometry) + { + try + { + xmlTextReader = new XmlTextReader(new MemoryStream(geometry)); + } + catch (ArgumentNullException e) + { + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); + } + } + + /// + /// Reads the XML document and from this obtains the required information and constructs a based + /// on this information. + /// + /// A new with information taken from the XML document. + /// Thrown when: + /// + /// Reading from the XML document of the failed. + /// The segments do not form a loop for either the inner or outer loop. + /// + /// + internal SoilLayer2D Read() + { + var pipingSoilLayer = new SoilLayer2D(); + + try + { + while (xmlTextReader.Read()) + { + List outerLoop; + List innerLoop; + if (TryParseLoop(outerLoopElementName, out outerLoop)) + { + pipingSoilLayer.OuterLoop = outerLoop; + } + if (TryParseLoop(innerLoopElementName, out innerLoop)) + { + pipingSoilLayer.AddInnerLoop(innerLoop); + } + } + } + catch (XmlException e) + { + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); + } + catch (ArgumentException e) + { + throw new SoilLayer2DConversionException(e.Message, e); + } + + return pipingSoilLayer; + } + + /// + /// Tries to parse the element with the given , which the reader should be currently pointing at, as a loop. + /// + /// The name of the element which the reader should be currently pointing at. + /// The result of parsing the element as a loop. null if the current element's name does not match . + /// True if the reader currently points to an element with name . False otherwise. + /// Thrown when not both HeadPoint and EndPoint are defined in + /// the GeometryCurve XML element. + private bool TryParseLoop(string elementName, out List loop) + { + loop = null; + + if (IsElementWithName(elementName)) + { + loop = new List(); + + if (!IsEmptyElement()) + { + while (xmlTextReader.Read() && !IsEndElementWithName(elementName)) + { + Segment2D segment; + if (TryParseSegment(out segment)) + { + loop.Add(segment); + } + } + } + return true; + } + return false; + } + + /// + /// Tries to parse a GeometryCurve XML element to a . + /// + /// The segment reference in which to put the parsed . + /// true if a segment could be parsed. false otherwise. + /// Thrown when not both HeadPoint and EndPoint are defined in + /// the GeometryCurve XML element. + private bool TryParseSegment(out Segment2D segment) + { + segment = null; + if (IsElementWithName(geometryCurveElementName) || IsElementWithName(endPointElementName)) + { + var points = new Point2D[2]; + var index = 0; + while (xmlTextReader.Read() && !IsEndElementWithName(geometryCurveElementName)) + { + Point2D point; + if (TryParsePoint(out point)) + { + points[index] = point; + index++; + } + } + try + { + segment = new Segment2D(points[0], points[1]); + return true; + } + catch (ArgumentException e) + { + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); + } + } + return false; + } + + /// + /// Finds out whether the element which the reader is currently pointing at is empty. + /// + /// True if the element is empty. False otherwise. + private bool IsEmptyElement() + { + return xmlTextReader.IsEmptyElement; + } + + /// + /// Tries to parse the element which the reader is currently pointing at as a point. + /// + /// The result of parsing the element as a point. null if current element is not a head or end point. + /// True if the reader currently points to an element with name or . False otherwise. + private bool TryParsePoint(out Point2D point) + { + point = null; + + if (IsElementWithName(headPointElementName) || IsElementWithName(endPointElementName)) + { + var pointValues = ReadChildValues(); + point = new Point2D + { + X = double.Parse(pointValues[xElementName], CultureInfo.InvariantCulture), + Y = double.Parse(pointValues[zElementName], CultureInfo.InvariantCulture) + }; + return true; + } + return false; + } + + /// + /// Reads the name and values for the children of the current element and puts them in a name indexed dictionary. + /// + /// A . For each entry, key is equal to child element name and value is equal to the value of the child element's text node. + private Dictionary ReadChildValues() + { + string elementName = xmlTextReader.Name; + var nodeSibblings = new Dictionary(); + + while (xmlTextReader.Read() && !IsEndElementWithName(elementName)) + { + if (xmlTextReader.NodeType == XmlNodeType.Element) + { + nodeSibblings[xmlTextReader.Name] = xmlTextReader.ReadString(); + } + } + + return nodeSibblings; + } + + /// + /// Checks whether the element the reader is currently pointing at is of type and has a name equal to . + /// + /// The name which the element should have. + /// True if the current element has type and its name is equal to . + private bool IsElementWithName(string name) + { + var isElement = xmlTextReader.NodeType == XmlNodeType.Element; + var isPoint = xmlTextReader.Name == name; + + return isElement && isPoint; + } + /// + /// Checks whether the element the reader is currently pointing at is of type and has a name equal to . + /// + /// The name which the end element should have. + /// True if the current element has type and its name is equal to . + private bool IsEndElementWithName(string name) + { + var isElement = xmlTextReader.NodeType == XmlNodeType.EndElement; + var isPoint = xmlTextReader.Name == name; + + return isElement && isPoint; + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfile1DReader.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfile1DReader.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfile1DReader.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,142 @@ +using System; +using System.Data.SQLite; +using Ringtoets.Piping.Data; +using Ringtoets.Piping.IO.Builders; +using Ringtoets.Piping.IO.Exceptions; +using Ringtoets.Piping.IO.Properties; + +namespace Ringtoets.Piping.IO.SoilProfile +{ + internal static class SoilProfile1DReader + { + /// + /// Reads a 1D profile from the given . + /// + /// + /// + /// Thrown when reading the profile encountered an unrecoverable error. + /// Thrown when reading the profile encountered a recoverable error. + internal static PipingSoilProfile ReadFrom(IRowBasedReader reader) + { + var criticalProperties = new CriticalProfileProperties(reader); + var requiredProperties = new RequiredProfileProperties(reader, criticalProperties.ProfileName); + + var soilProfileBuilder = new SoilProfileBuilder1D(criticalProperties.ProfileName, requiredProperties.Bottom); + + for (var i = 1; i <= criticalProperties.LayerCount; i++) + { + SoilLayer1D soilLayer = ReadSoilLayerFrom(reader, criticalProperties.ProfileName); + soilProfileBuilder.Add(soilLayer.AsPipingSoilLayer()); + reader.MoveNext(); + } + + return Build(soilProfileBuilder, criticalProperties.ProfileName); + } + + /// + /// Builds a from the given . + /// + /// Thrown when building the failed. + private static PipingSoilProfile Build(SoilProfileBuilder1D soilProfileBuilder, string profileName) + { + try + { + return soilProfileBuilder.Build(); + } + catch (ArgumentException e) + { + throw new PipingSoilProfileReadException(profileName, e.Message, e); + } + } + + /// + /// Reads a from the given . + /// + /// Thrown when reading properties of the layers failed. + private static SoilLayer1D ReadSoilLayerFrom(IRowBasedReader reader, string profileName) + { + var properties = new LayerProperties(reader, profileName); + + var pipingSoilLayer = new SoilLayer1D(properties.Top) + { + IsAquifer = properties.IsAquifer, + BelowPhreaticLevel = properties.BelowPhreaticLevel, + AbovePhreaticLevel = properties.AbovePhreaticLevel, + DryUnitWeight = properties.DryUnitWeight + }; + return pipingSoilLayer; + } + + private class RequiredProfileProperties + { + internal readonly double Bottom; + + /// + /// Creates a new instance of , which contains properties + /// 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 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(IRowBasedReader reader, string profileName) + { + string readColumn = SoilProfileDatabaseColumns.Bottom; + try + { + Bottom = reader.Read(readColumn); + } + catch (InvalidCastException e) + { + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, readColumn); + throw new PipingSoilProfileReadException(profileName, message, e); + } + } + } + + private class LayerProperties + { + internal readonly double Top; + internal readonly double? IsAquifer; + internal readonly double? BelowPhreaticLevel; + internal readonly double? AbovePhreaticLevel; + internal readonly double? DryUnitWeight; + + /// + /// Creates a new instance of , which contains properties + /// 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 layer 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 LayerProperties(IRowBasedReader reader, string profileName) + { + string readColumn = SoilProfileDatabaseColumns.Top; + try + { + Top = reader.Read(readColumn); + + readColumn = SoilProfileDatabaseColumns.IsAquifer; + IsAquifer = reader.ReadOrNull(readColumn); + + readColumn = SoilProfileDatabaseColumns.BelowPhreaticLevel; + BelowPhreaticLevel = reader.ReadOrNull(readColumn); + + readColumn = SoilProfileDatabaseColumns.AbovePhreaticLevel; + AbovePhreaticLevel = reader.ReadOrNull(readColumn); + + readColumn = SoilProfileDatabaseColumns.DryUnitWeight; + DryUnitWeight = reader.ReadOrNull(readColumn); + } + catch (InvalidCastException e) + { + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, readColumn); + throw new PipingSoilProfileReadException(profileName, message, e); + } + } + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfile2DReader.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfile2DReader.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfile2DReader.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,182 @@ +using System; +using System.Data.SQLite; +using Ringtoets.Piping.Data; +using Ringtoets.Piping.IO.Builders; +using Ringtoets.Piping.IO.Exceptions; +using Ringtoets.Piping.IO.Properties; + +namespace Ringtoets.Piping.IO.SoilProfile +{ + internal static class SoilProfile2DReader + { + + /// + /// Reads information for a profile from the database and creates a based on the information. + /// + /// A new with information from the database. + /// Thrown when reading the profile encountered an unrecoverable error. + /// Thrown when + /// + /// a layer's geometry could not be parsed as XML; + /// the parsed geometry did not contain loops; + /// after reading the layers, no layers were added to be build; + /// unexpected values were encountered for layer properties + /// + /// + internal static PipingSoilProfile ReadFrom(IRowBasedReader reader) + { + var criticalProperties = new CriticalProfileProperties(reader); + var requiredProperties = new RequiredProfileProperties(reader, criticalProperties.ProfileName); + + try + { + var soilProfileBuilder = new SoilProfileBuilder2D(criticalProperties.ProfileName, requiredProperties.IntersectionX); + + for (int i = 1; i <= criticalProperties.LayerCount; i++) + { + var pipingSoilLayer2D = ReadPiping2DSoilLayer(reader, criticalProperties.ProfileName); + soilProfileBuilder.Add(pipingSoilLayer2D); + reader.MoveNext(); + } + + return soilProfileBuilder.Build(); + } + catch (SoilProfileBuilderException e) + { + throw new PipingSoilProfileReadException(criticalProperties.ProfileName, e.Message, e); + } + catch (ArgumentException e) + { + throw new PipingSoilProfileReadException(criticalProperties.ProfileName, e.Message, e); + } + } + + /// + /// Reads a soil layer from a 2d profile in the database. + /// + /// The to read the layer property values from. + /// The profile name used in generating exceptions messages if casting failed. + /// A new instance, based on the information read from the database. + /// Thrown when: + /// + /// A column for a layer property did not contain a value of the expected type. + /// Thrown when the read geometry does not contain segments that form form a loop for either the inner or outer loop. + /// + private static SoilLayer2D ReadPiping2DSoilLayer(IRowBasedReader reader, string profileName) + { + LayerProperties properties = new LayerProperties(reader, profileName); + + SoilLayer2D pipingSoilLayer; + try + { + var geometryValue = ReadGeometryFrom(reader, profileName); + pipingSoilLayer = new SoilLayer2DReader(geometryValue).Read(); + } + catch (SoilLayer2DConversionException e) + { + throw new PipingSoilProfileReadException(profileName, e.Message, e); + } + + if (pipingSoilLayer != null) + { + pipingSoilLayer.IsAquifer = properties.IsAquifer; + pipingSoilLayer.BelowPhreaticLevel = properties.BelowPhreaticLevel; + pipingSoilLayer.AbovePhreaticLevel = properties.AbovePhreaticLevel; + pipingSoilLayer.DryUnitWeight = properties.DryUnitWeight; + } + return pipingSoilLayer; + } + + /// + /// Reads the geometry for a layer from the current + /// + /// The to read the geometry value from. + /// The profile name used in generating exceptions messages if casting failed. + /// + private static byte[] ReadGeometryFrom(IRowBasedReader reader, string profileName) + { + try + { + return reader.Read(SoilProfileDatabaseColumns.LayerGeometry); + } + catch (InvalidCastException e) + { + var message = string.Format( + Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, + profileName, + SoilProfileDatabaseColumns.LayerGeometry + ); + throw new PipingSoilProfileReadException(profileName, message, e); + } + } + + + private class RequiredProfileProperties + { + internal readonly double IntersectionX; + + /// + /// Creates a new instance of , which contains properties + /// 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 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(IRowBasedReader reader, string profileName) + { + string readColumn = SoilProfileDatabaseColumns.IntersectionX; + try + { + IntersectionX = reader.Read(readColumn); + } + catch (InvalidCastException e) + { + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, readColumn); + throw new PipingSoilProfileReadException(profileName, message, e); + } + } + } + + private class LayerProperties + { + internal readonly double? IsAquifer; + internal readonly double? BelowPhreaticLevel; + internal readonly double? AbovePhreaticLevel; + internal readonly double? DryUnitWeight; + + /// + /// Creates a new instance of , which contains properties + /// 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 layer 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 LayerProperties(IRowBasedReader reader, string profileName) + { + string readColumn = SoilProfileDatabaseColumns.IsAquifer; + try + { + IsAquifer = reader.ReadOrNull(readColumn); + + readColumn = SoilProfileDatabaseColumns.BelowPhreaticLevel; + BelowPhreaticLevel = reader.ReadOrNull(readColumn); + + readColumn = SoilProfileDatabaseColumns.AbovePhreaticLevel; + AbovePhreaticLevel = reader.ReadOrNull(readColumn); + + readColumn = SoilProfileDatabaseColumns.DryUnitWeight; + DryUnitWeight = reader.ReadOrNull(readColumn); + } + catch (InvalidCastException e) + { + var message = string.Format(Resources.PipingSoilProfileReader_Profile_0_has_invalid_value_on_column_1_, profileName, readColumn); + throw new PipingSoilProfileReadException(profileName, message, e); + } + } + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfileDatabaseColumns.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfileDatabaseColumns.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilProfileDatabaseColumns.cs (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -0,0 +1,18 @@ +namespace Ringtoets.Piping.IO.SoilProfile +{ + public static class SoilProfileDatabaseColumns + { + public const string ProfileCount = "ProfileCount"; + public const string Dimension = "Dimension"; + public const string IsAquifer = "IsAquifer"; + public const string ProfileName = "ProfileName"; + public const string IntersectionX = "IntersectionX"; + public const string Bottom = "Bottom"; + public const string Top = "Top"; + public const string LayerGeometry = "LayerGeometry"; + public const string AbovePhreaticLevel = "AbovePhreaticLevel"; + public const string BelowPhreaticLevel = "BelowPhreaticLevel"; + public const string DryUnitWeight = "DryUnitWeight"; + public const string LayerCount = "LayerCount"; + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Plugin/FileImporter/PipingSoilProfilesImporter.cs =================================================================== diff -u -rf69d756f50ae1464a1a11f0780b6d6aa646f3114 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/src/Ringtoets.Piping.Plugin/FileImporter/PipingSoilProfilesImporter.cs (.../PipingSoilProfilesImporter.cs) (revision f69d756f50ae1464a1a11f0780b6d6aa646f3114) +++ Ringtoets/Piping/src/Ringtoets.Piping.Plugin/FileImporter/PipingSoilProfilesImporter.cs (.../PipingSoilProfilesImporter.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -6,8 +6,8 @@ using Core.Common.Base; using log4net; using Ringtoets.Piping.Data; -using Ringtoets.Piping.IO; using Ringtoets.Piping.IO.Exceptions; +using Ringtoets.Piping.IO.SoilProfile; using WtiFormsResources = Ringtoets.Piping.Forms.Properties.Resources; using ApplicationResources = Ringtoets.Piping.Plugin.Properties.Resources; @@ -119,18 +119,10 @@ return GetProfileReadResult(path, soilProfileReader); } } - catch (PipingSoilProfileReadException e) + catch (CriticalFileReadException e) { HandleException(path, e); } - catch (FileNotFoundException e) - { - HandleException(path, e); - } - catch (ArgumentException e) - { - HandleException(path, e); - } return new PipingReadResult(true); } Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/Exceptions/PipingSoilProfileReadExceptionTest.cs =================================================================== diff -u -ra950714ad9510756331d862aa35695fa0b2ed03b -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/Exceptions/PipingSoilProfileReadExceptionTest.cs (.../PipingSoilProfileReadExceptionTest.cs) (revision a950714ad9510756331d862aa35695fa0b2ed03b) +++ Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/Exceptions/PipingSoilProfileReadExceptionTest.cs (.../PipingSoilProfileReadExceptionTest.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -7,45 +7,51 @@ public class PipingSoilProfileReadExceptionTest { [Test] - public void DefaultConstructor_InnerExceptionNullAndMessageDefault() + public void Constructor_WithProfileName_InnerExceptionNullMessageDefaultAndProfileNameSet() { // Setup + var profileName = "name"; var expectedMessage = String.Format("Exception of type '{0}' was thrown.", typeof(PipingSoilProfileReadException).FullName); // Call - var exception = new PipingSoilProfileReadException(); + var exception = new PipingSoilProfileReadException(profileName); // Assert Assert.IsNull(exception.InnerException); + Assert.AreEqual(profileName, exception.ProfileName); Assert.AreEqual(expectedMessage, exception.Message); } [Test] public void Constructor_WithCustomMessage_InnerExceptionNullAndMessageSetToCustom() { // Setup - var expectedMessage ="Some exception message"; + var profileName = "name"; + var expectedMessage = "Some exception message"; // Call - var exception = new PipingSoilProfileReadException(expectedMessage); + var exception = new PipingSoilProfileReadException(profileName, expectedMessage); // Assert Assert.IsNull(exception.InnerException); + Assert.AreEqual(profileName, exception.ProfileName); Assert.AreEqual(expectedMessage, exception.Message); } [Test] public void Constructor_WithCustomMessageAndInnerException_InnerExceptionSetAndMessageSetToCustom() { // Setup + var profileName = "name"; var expectedMessage = "Some exception message"; var expectedInnerException = new Exception(); // Call - var exception = new PipingSoilProfileReadException(expectedMessage, expectedInnerException); + var exception = new PipingSoilProfileReadException(profileName, expectedMessage, expectedInnerException); // Assert Assert.AreSame(expectedInnerException, exception.InnerException); + Assert.AreEqual(profileName, exception.ProfileName); Assert.AreEqual(expectedMessage, exception.Message); } } Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilLayer2DReaderTest.cs =================================================================== diff -u -rf69d756f50ae1464a1a11f0780b6d6aa646f3114 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilLayer2DReaderTest.cs (.../PipingSoilLayer2DReaderTest.cs) (revision f69d756f50ae1464a1a11f0780b6d6aa646f3114) +++ Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilLayer2DReaderTest.cs (.../PipingSoilLayer2DReaderTest.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -7,6 +7,8 @@ using NUnit.Framework; using Ringtoets.Piping.Data; +using Ringtoets.Piping.IO.Builders; +using Ringtoets.Piping.IO.SoilProfile; namespace Ringtoets.Piping.IO.Test { @@ -18,32 +20,32 @@ public void Constructor_AnyByteArray_ReturnsNewInstance(int size) { // Call - var result = new PipingSoilLayer2DReader(new byte[size]); + var result = new SoilLayer2DReader(new byte[size]); // Assert Assert.NotNull(result); } [Test] - public void Read_MalformedXmlDocument_ThrowsXmlException() + public void Read_MalformedXmlDocument_ThrowsSoilLayer2DConversionException() { // Setup var xmlDoc = GetBytes("test"); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call TestDelegate test = () => reader.Read(); // Assert - Assert.Throws(test); + Assert.Throws(test); } [Test] public void Read_XmlDocumentWithoutSaneContent_ReturnsLayerWithoutOuterLoopAndEmptyInnerLoops() { // Setup var xmlDoc = GetBytes(""); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); @@ -59,7 +61,7 @@ { // Setup var xmlDoc = GetBytes(""); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); @@ -75,7 +77,7 @@ { // Setup var xmlDoc = GetBytes(""); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); @@ -92,7 +94,7 @@ { // Setup var xmlDoc = GetBytes(""); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); @@ -147,7 +149,7 @@ x1String, y1String, x2String, y2String); var bytes = GetBytes(sometempvarforbassie); var xmlDoc = bytes; - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); @@ -185,7 +187,7 @@ "{0}0.1{1}" + "{2}0.1{3}" + "", x1String, y1String, x2String, y2String)); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); @@ -198,31 +200,31 @@ } [Test] - public void Read_XmlDocumentSinglePointOuterLoopGeometryCurve_ThrowsXmlException() + public void Read_XmlDocumentSinglePointOuterLoopGeometryCurve_ThrowsSoilLayer2DConversionException() { // Setup var xmlDoc = GetBytes("10.11.1"); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call TestDelegate test = () => { reader.Read(); }; // Assert - Assert.Throws(test); + Assert.Throws(test); } [Test] - public void Read_XmlDocumentSinglePointInnerLoopGeometryCurve_ThrowsXmlException() + public void Read_XmlDocumentSinglePointInnerLoopGeometryCurve_ThrowsSoilLayer2DConversionException() { // Setup var xmlDoc = GetBytes("00.11.1"); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call TestDelegate test = () => { reader.Read(); }; // Assert - Assert.Throws(test); + Assert.Throws(test); } [Test] @@ -238,7 +240,7 @@ "" + ""); - var reader = new PipingSoilLayer2DReader(xmlDoc); + var reader = new SoilLayer2DReader(xmlDoc); // Call var result = reader.Read(); Index: Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilProfileReaderTest.cs =================================================================== diff -u -r2a49b7243807fe0b95136efd55652201164a6c74 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilProfileReaderTest.cs (.../PipingSoilProfileReaderTest.cs) (revision 2a49b7243807fe0b95136efd55652201164a6c74) +++ Ringtoets/Piping/test/Ringtoets.Piping.IO.Test/PipingSoilProfileReaderTest.cs (.../PipingSoilProfileReaderTest.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -8,6 +8,7 @@ using Ringtoets.Piping.Data; using Ringtoets.Piping.IO.Exceptions; using Ringtoets.Piping.IO.Properties; +using Ringtoets.Piping.IO.SoilProfile; using Ringtoets.Piping.IO.Test.TestHelpers; namespace Ringtoets.Piping.IO.Test @@ -17,7 +18,7 @@ private readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Piping.IO, "PipingSoilProfilesReader"); [Test] - public void Constructor_NonExistingPath_ThrowsFileNotFoundException() + public void Constructor_NonExistingPath_ThrowsCriticalFileReadException() { // Setup var testFile = Path.Combine(testDataPath, "none.soil"); @@ -26,27 +27,27 @@ TestDelegate test = () => new PipingSoilProfileReader(testFile).Dispose(); // Assert - var exception = Assert.Throws(test); + var exception = Assert.Throws(test); Assert.AreEqual(String.Format(Resources.Error_File_0_does_not_exist, testFile), exception.Message); } [Test] [TestCase(null)] [TestCase("")] - public void Constructor_FileNullOrEmpty_ThrowsArgumentException(string fileName) + public void Constructor_FileNullOrEmpty_ThrowsCriticalFileReadException(string fileName) { // Call TestDelegate test = () => new PipingSoilProfileReader(fileName).Dispose(); // Assert - var exception = Assert.Throws(test); + var exception = Assert.Throws(test); Assert.AreEqual(Resources.Error_Path_must_be_specified, exception.Message); } [Test] [TestCase("text.txt")] [TestCase("empty.soil")] - public void Constructor_IncorrectFormatFileOrInvalidSchema_ThrowsPipingSoilProfileReadException(string dbName) + public void Constructor_IncorrectFormatFileOrInvalidSchema_ThrowsPipingCriticalFileReadException(string dbName) { // Setup var dbFile = Path.Combine(testDataPath, dbName); @@ -58,13 +59,13 @@ TestDelegate test = () => new PipingSoilProfileReader(dbFile).Dispose(); // Assert - var exception = Assert.Throws(test); + var exception = Assert.Throws(test); Assert.AreEqual(String.Format(Resources.Error_SoilProfile_read_from_database, dbName), exception.Message); Assert.IsTrue(FileHelper.CanOpenFileForWrite(dbFile)); } [Test] - public void Constructor_IncorrectVersion_ThrowsPipingSoilProfileReadException() + public void Constructor_IncorrectVersion_ThrowsCriticalFileReadException() { // Setup var version = "15.0.5.0"; @@ -78,7 +79,7 @@ TestDelegate test = () => new PipingSoilProfileReader(dbFile).Dispose(); // Assert - var exception = Assert.Throws(test); + var exception = Assert.Throws(test); Assert.AreEqual(String.Format(Resources.PipingSoilProfileReader_Database_file_0_incorrect_version_requires_1, dbName, version), exception.Message); Assert.IsTrue(FileHelper.CanOpenFileForWrite(dbFile)); } @@ -137,8 +138,7 @@ // Assert var exception = Assert.Throws(profile); - var message = String.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, 1, "Profile"); - Assert.AreEqual(message, exception.Message); + Assert.AreEqual(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, exception.Message); // Call var pipingSoilProfile = pipingSoilProfilesReader.ReadProfile(); @@ -163,7 +163,7 @@ // Assert var exception = Assert.Throws(profile); - var message = String.Format(Resources.PipingSoilProfileReader_CouldNotParseGeometryOfLayer_0_InProfile_1_, 1, "Profile"); + var message = String.Format(Resources.Error_Can_not_determine_1D_profile_with_vertical_segments_at_x, 85.2); Assert.AreEqual(message, exception.Message); // Call Index: Ringtoets/Piping/test/Ringtoets.Piping.Plugin.Test/FileImporter/PipingSoilProfilesImporterTest.cs =================================================================== diff -u -rf69d756f50ae1464a1a11f0780b6d6aa646f3114 -r069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35 --- Ringtoets/Piping/test/Ringtoets.Piping.Plugin.Test/FileImporter/PipingSoilProfilesImporterTest.cs (.../PipingSoilProfilesImporterTest.cs) (revision f69d756f50ae1464a1a11f0780b6d6aa646f3114) +++ Ringtoets/Piping/test/Ringtoets.Piping.Plugin.Test/FileImporter/PipingSoilProfilesImporterTest.cs (.../PipingSoilProfilesImporterTest.cs) (revision 069921ae1e06e13d8e5e19dd9caa5e8f7b9e1f35) @@ -137,7 +137,7 @@ { // Setup var file = "/"; - string validFilePath = Path.Combine(testDataPath, file); + string invalidFilePath = Path.Combine(testDataPath, file); var mocks = new MockRepository(); var observer = mocks.StrictMock(); @@ -158,13 +158,13 @@ object importedItem = null; // Call - Action call = () => importedItem = importer.ImportItem(validFilePath, observableList); + Action call = () => importedItem = importer.ImportItem(invalidFilePath, 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); + var message = string.Format(ApplicationResources.PipingSoilProfilesImporter_Critical_error_reading_File_0_Cause_1_, invalidFilePath, String.Empty); StringAssert.StartsWith(message, messageArray[0]); }); Assert.AreSame(observableList, importedItem);