diff --git a/Core/Assets/ErrorMessages.Designer.cs b/Core/Assets/ErrorMessages.Designer.cs new file mode 100644 index 0000000..9449e1b --- /dev/null +++ b/Core/Assets/ErrorMessages.Designer.cs @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace TagHierarchyManager.Assets { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ErrorMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ErrorMessages() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TagHierarchyManager.Assets.ErrorMessages", typeof(ErrorMessages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Excessive indent was detected at line {0}.. + /// + internal static string ImporterMusicBeeIndentExcessive { + get { + return ResourceManager.GetString("ImporterMusicBeeIndentExcessive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uneven indent was found at line {0}.. + /// + internal static string ImporterMusicBeeIndentUneven { + get { + return ResourceManager.GetString("ImporterMusicBeeIndentUneven", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Process exited abruptly due to an error with handling the indent. (current line's indent level was greater than the amount of tags in the parent stack). + /// + internal static string ImporterMusicBeePopOutOfRange { + get { + return ResourceManager.GetString("ImporterMusicBeePopOutOfRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tag hierarchy starts with a space, which is not valid for a tag hierarchy template's structure.. + /// + internal static string ImporterMusicBeeStartsWithSpace { + get { + return ResourceManager.GetString("ImporterMusicBeeStartsWithSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tab characters were detected, which is an invalid structure for MusicBee tag hierarchy templates.. + /// + internal static string ImporterMusicBeeTabsDetected { + get { + return ResourceManager.GetString("ImporterMusicBeeTabsDetected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This setting is required and cannot be deleted.. + /// + internal static string TagDatabaseDeletingRequiredSetting { + get { + return ResourceManager.GetString("TagDatabaseDeletingRequiredSetting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No usable parameters received.. + /// + internal static string TagDatabaseEmptyParameters { + get { + return ResourceManager.GetString("TagDatabaseEmptyParameters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File path cannot be empty.. + /// + internal static string TagDatabaseFilePathEmpty { + get { + return ResourceManager.GetString("TagDatabaseFilePathEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is not a valid SQLite database.. + /// + internal static string TagDatabaseInvalidFile { + get { + return ResourceManager.GetString("TagDatabaseInvalidFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File extension must be .thdb.. + /// + internal static string TagDatabaseInvalidFileExt { + get { + return ResourceManager.GetString("TagDatabaseInvalidFileExt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is not a valid database file for the Tag Hierarchy Manager application.. + /// + internal static string TagDatabaseInvalidStructure { + get { + return ResourceManager.GetString("TagDatabaseInvalidStructure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tag hierarchy database has not been initialised.. + /// + internal static string TagDatabaseNotInitialised { + get { + return ResourceManager.GetString("TagDatabaseNotInitialised", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Setting {0} already exists in the database.. + /// + internal static string TagDatabaseSettingKeyExists { + get { + return ResourceManager.GetString("TagDatabaseSettingKeyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Setting {0} was not found in the settings table.. + /// + internal static string TagDatabaseSettingKeyNotFound { + get { + return ResourceManager.GetString("TagDatabaseSettingKeyNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot execute function on database due to SQLite error. Error code: {0}. + /// + internal static string TagDatabaseSqliteGeneric { + get { + return ResourceManager.GetString("TagDatabaseSqliteGeneric", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tag requested has child tags and cannot currently be deleted. Delete its children first and try again.. + /// + internal static string TagDatabaseTagHasChildren { + get { + return ResourceManager.GetString("TagDatabaseTagHasChildren", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tag requested does not exist in the database.. + /// + internal static string TagDatabaseTagNotFound { + get { + return ResourceManager.GetString("TagDatabaseTagNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tag {0} has no parents specified and is not top-level, which is invalid.. + /// + internal static string TagNameIsBlank { + get { + return ResourceManager.GetString("TagNameIsBlank", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tag {0} has no parents specified and is not top-level, which is invalid.. + /// + internal static string TagOrphanAttempt { + get { + return ResourceManager.GetString("TagOrphanAttempt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tag {0} has itself in Parents, which is invalid.. + /// + internal static string TagSelfParentAttempt { + get { + return ResourceManager.GetString("TagSelfParentAttempt", resourceCulture); + } + } + } +} diff --git a/Core/Assets/ErrorMessages.resx b/Core/Assets/ErrorMessages.resx new file mode 100644 index 0000000..eb587b7 --- /dev/null +++ b/Core/Assets/ErrorMessages.resx @@ -0,0 +1,83 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Tag {0} has itself in Parents, which is invalid. + + + Tag {0} has no parents specified and is not top-level, which is invalid. + + + Tag {0} has no parents specified and is not top-level, which is invalid. + + + This is not a valid SQLite database. + + + This is not a valid database file for the Tag Hierarchy Manager application. + + + File extension must be .thdb. + + + The tag hierarchy database has not been initialised. + + + No usable parameters received. + + + File path cannot be empty. + + + This setting is required and cannot be deleted. + + + + The tag requested has child tags and cannot currently be deleted. Delete its children first and try again. + + + The tag requested does not exist in the database. + + + Setting {0} already exists in the database. + + + Setting {0} was not found in the settings table. + + + Cannot execute function on database due to SQLite error. Error code: {0} + + + Excessive indent was detected at line {0}. + + + Uneven indent was found at line {0}. + + + Process exited abruptly due to an error with handling the indent. (current line's indent level was greater than the amount of tags in the parent stack) + + + Tag hierarchy starts with a space, which is not valid for a tag hierarchy template's structure. + + + Tab characters were detected, which is an invalid structure for MusicBee tag hierarchy templates. + + + \ No newline at end of file diff --git a/Core/ErrorMessages.cs b/Core/ErrorMessages.cs index 77e92d8..6d7a630 100644 --- a/Core/ErrorMessages.cs +++ b/Core/ErrorMessages.cs @@ -1,104 +1,3 @@ using TagHierarchyManager.Models; namespace TagHierarchyManager; - -// TODO Migrate to RESX -/// -/// A static class storing error message strings for use when showing errors or throwing exceptions.

-/// Some classes can have their own error message classes for more specific messages, this is intended for error -/// messages that are used by multiple classes or do not fit into a specific class. -///
-public static class ErrorMessages -{ - /// - /// Indicates an attempt to load a file that is not a valid SQLite database. - /// - public const string DbFileNotValid = "This is not a valid SQLite database file."; - - /// - /// Indicates an attempt to use a that has not been fully initialised yet. - /// - public const string DbNotInitialised = "The tag hierarchy database has not been initialised."; - - /// - /// Indicates an attempt to load a database with a structure that doesn't match what the application expects. - /// - public const string DbNotValid = "This is not a valid database file for the Tag Hierarchy Manager application."; - - /// - /// Indicates no parameters being received in a method. - /// - public const string EmptyParameters = "No usable parameters received."; - - /// - /// Indicates an attempt to send an empty file path. - /// - public const string FilePathIsEmpty = "File path cannot be empty."; - - /// - /// Indicates an attempt to load a file that does not exist, when loading a . - /// - public const string FilePathNotFound = "No file exists at the specified path."; - - /// - /// Indicates an attempt to save to/load a file with an extension other than .thdb. - /// - public const string InvalidFileExtension = "File extension must be .thdb."; - - // Settings - /// - /// Indicates an attempt to delete a setting that is required. - /// - public const string SettingIsRequired = "This setting is required and cannot be deleted."; - - /// - /// Indicates that the specified tag cannot be deleted since it has child tags. - /// - public const string TagHasChildren = - "The tag requested has child tags and cannot currently be deleted. Delete its children first and try again."; - - /// - /// Indicates that the specified tag doesn't exist in the database. - /// - public const string TagNotFound = "The tag requested does not exist in the database."; - - /// - /// Generates a string indicating that the specified setting already exists in the . - /// - /// The specified setting key. - /// A string indicating the setting already exists. - public static string SettingKeyAlreadyExists(string key) - { - return $"Setting {key} already exists in the database."; - } - - /// - /// Generates a string indicating that the specified setting does not exist in the . - /// - /// The specified setting key. - /// A string indicating the setting does not exist. - public static string SettingKeyNotFound(string key) - { - return $"The setting key \"{key}\" was not found in the settings table."; - } - - /// - /// Method to construct a string for generic errors from SQLite. - /// - /// The SQLite error code. - /// A string indicating that the database couldn't be loaded due to an error in SQLite. - public static string SqliteGenericWithCode(int errorCode) - { - return $"Cannot load database due to an a SQLite error. Error code: {errorCode}"; - } - - /// - /// Method to construct a string for when attempting to save a new tag that already exists into the TagDatabase. - /// - /// The offending name of the tag. - /// A string indicating that the specified tag already exists in the TagDatabase. - public static string TagAlreadyExists(string tagName) - { - return $"Tag \"{tagName}\" already exists in the database."; - } -} \ No newline at end of file diff --git a/Core/Importers/MusicBeeTagHierarchyImporter/MusicBeeTagHierarchyImporter.cs b/Core/Importers/MusicBeeTagHierarchyImporter.cs similarity index 93% rename from Core/Importers/MusicBeeTagHierarchyImporter/MusicBeeTagHierarchyImporter.cs rename to Core/Importers/MusicBeeTagHierarchyImporter.cs index c9dcdef..235460b 100644 --- a/Core/Importers/MusicBeeTagHierarchyImporter/MusicBeeTagHierarchyImporter.cs +++ b/Core/Importers/MusicBeeTagHierarchyImporter.cs @@ -1,3 +1,4 @@ +using TagHierarchyManager.Assets; using TagHierarchyManager.Common; using TagHierarchyManager.Models; @@ -6,7 +7,7 @@ namespace TagHierarchyManager.Importers; /// Implements an importer for converting a MusicBee tag hierarchy template to a Dictionary of s. /// /// TODO add manual intervention for tags with duplicate names. -public partial class MusicBeeTagHierarchyImporter : Importer +public class MusicBeeTagHierarchyImporter : Importer { private const int IndentSize = 4; // MusicBee is strict about having an indent size of 4 spaces. private const string TagBindingSeparator = "::"; @@ -78,7 +79,7 @@ public partial class MusicBeeTagHierarchyImporter : Importer { if (currentLine.IndentLevel - previousIndent > 1) throw new ArgumentException( - ErrorMessages.TagHierarchyIndentIsExcessive(currentLine.LineNumber)); + string.Format(ErrorMessages.ImporterMusicBeeIndentExcessive, currentLine.LineNumber)); if (!string.IsNullOrEmpty(parentName)) parentStack.Add(parentName); } @@ -87,16 +88,16 @@ public partial class MusicBeeTagHierarchyImporter : Importer if (currentLine.IndentLevel <= parentStack.Count) parentStack.RemoveRange(currentLine.IndentLevel, parentStack.Count - currentLine.IndentLevel); else - throw new InvalidOperationException(ErrorMessages.TagHierarchyPopAttemptOutOfRange); + throw new InvalidOperationException(ErrorMessages.ImporterMusicBeePopOutOfRange); } } private static void ValidateHierarchyData(string tagHierarchyData) { // TODO change on the fly instead of erroring out? - if (tagHierarchyData.Contains('\t')) throw new ArgumentException(ErrorMessages.TagHierarchyTabsDetected); + if (tagHierarchyData.Contains('\t')) throw new ArgumentException(ErrorMessages.ImporterMusicBeeTabsDetected); - if (tagHierarchyData.StartsWith(' ')) throw new ArgumentException(ErrorMessages.TagHierarchyStartsWithSpace); + if (tagHierarchyData.StartsWith(' ')) throw new ArgumentException(ErrorMessages.ImporterMusicBeeStartsWithSpace); } private static void ImportTag(Dictionary importDict, TagHierarchyLine line, List parentStack) @@ -158,7 +159,7 @@ public partial class MusicBeeTagHierarchyImporter : Importer int indentRemainder = (line.Length - trimmedLine.Length) % IndentSize; if (indentRemainder != 0) throw new ArgumentException( - ErrorMessages.TagHierarchyIndentIsUneven(lineCounter)); + string.Format(ErrorMessages.ImporterMusicBeeIndentUneven, lineCounter)); this.IndentLevel = (line.Length - trimmedLine.Length) / IndentSize; } diff --git a/Core/Importers/MusicBeeTagHierarchyImporter/ErrorMessages.cs b/Core/Importers/MusicBeeTagHierarchyImporter/ErrorMessages.cs deleted file mode 100644 index 0782726..0000000 --- a/Core/Importers/MusicBeeTagHierarchyImporter/ErrorMessages.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace TagHierarchyManager.Importers; - -public partial class MusicBeeTagHierarchyImporter -{ - /// - /// A class storing error messages for exceptions. - /// - public static class ErrorMessages - { - /// - /// Indicates that an excessive amount of indents was detected in the tag hierarchy template, with a - /// placeholder for the line number. - /// - public const string IndentIsExcessiveTemplate = - "Excessive indent was detected at line {0}."; - - /// - /// Indicates that an uneven amount of indents was detected in the tag hierarchy template, with a - /// placeholder for the line number. - /// - public const string IndentIsUnevenTemplate = - "Uneven indent was found at line {0}."; - - /// - /// Indicates an attempt to remove a parent tag from the parent stack resulting in an Exception. - /// - public const string TagHierarchyPopAttemptOutOfRange = - "Process exited abruptly due to an error with handling the indent. (current line's indent level was greater than the amount of tags in the parent stack)"; - - /// - /// Indicates that a space character was detected at the beginning of the tag hierarchy template. - /// - public const string TagHierarchyStartsWithSpace = - "Tag hierarchy starts with a space, which is not valid for a tag hierarchy template's structure."; - - /// - /// Indicates that a tab character was detected in tag hierarchy template. - /// - public const string TagHierarchyTabsDetected = - "Tab characters were detected, which is an invalid structure for MusicBee tag hierarchy templates."; - - /// - /// Constructs a string indicating an excessive amount of indents in the tag hierarchy template. - /// - /// The offending line number of the template. - /// A string stating that an excessive amount of indents was found at a particular given line. - public static string TagHierarchyIndentIsExcessive(int lineNumber) - { - return string.Format(IndentIsExcessiveTemplate, lineNumber); - } - - /// - /// Constructs a string indicating an uneven indent in the tag hierarchy template. - /// - /// The offending line number of the template. - /// A formatted string stating that an uneven indent was found at a particular given line. - public static string TagHierarchyIndentIsUneven(int lineNumber) - { - return string.Format(IndentIsUnevenTemplate, lineNumber); - } - } -} \ No newline at end of file diff --git a/Core/Models/Tag/Tag.ErrorMessages.cs b/Core/Models/Tag/Tag.ErrorMessages.cs deleted file mode 100644 index c28d130..0000000 --- a/Core/Models/Tag/Tag.ErrorMessages.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace TagHierarchyManager.Models; - -// TODO migrate to RESX -public partial class Tag -{ - /// - /// Error messages associated with the Tag object. - /// - public static class ErrorMessages - { - /// - /// Constructs a string indicating an attempt to make a tag a parent of itself. - /// - /// The name of the offending Tag object. - /// - /// An error message string indicating that the tag has itself in Parents (id) or ParentNames (name). - /// - public static string MakingSelfParentAttempt(string name) - { - return $"Tag '{name}' has itself in Parents or ParentNames, which is invalid."; - } - - /// - /// Constructs a string indicating that a specified tag is an orphan. - /// - /// The name of the offending Tag object. - /// A string indicating that the tag has no parents specified and can't be top level. - public static string OrphanTagAttempt(string name) - { - return $"Tag '{name}' has no parents specified, so cannot be non-top-level."; - } - } -} \ No newline at end of file diff --git a/Core/Models/Tag/Tag.cs b/Core/Models/Tag/Tag.cs index 1c7c1d4..19ecbd3 100644 --- a/Core/Models/Tag/Tag.cs +++ b/Core/Models/Tag/Tag.cs @@ -1,3 +1,5 @@ +using TagHierarchyManager.Assets; + namespace TagHierarchyManager.Models; /// @@ -79,13 +81,17 @@ public partial class Tag public bool Validate() { if (string.IsNullOrWhiteSpace(this.Name)) - throw new TagValidationException("Tag name cannot be blank."); + throw new TagValidationException(ErrorMessages.TagNameIsBlank); if (!this.IsTopLevel && this.ParentIds.Count == 0 && this.Parents.Count == 0) - throw new TagValidationException(ErrorMessages.OrphanTagAttempt(this.Name)); + throw new TagValidationException( + string.Format(ErrorMessages.TagOrphanAttempt, this.Name) + ); if (this.Parents.Contains(this.Name) || this.ParentIds.Contains(this.Id)) - throw new TagValidationException(ErrorMessages.MakingSelfParentAttempt(this.Name)); + throw new TagValidationException( + string.Format(ErrorMessages.TagSelfParentAttempt, this.Name) + ); return true; } diff --git a/Core/Models/TagDatabase/TagDatabase.DeleteMethods.cs b/Core/Models/TagDatabase/TagDatabase.DeleteMethods.cs index 0028e8d..84967d9 100644 --- a/Core/Models/TagDatabase/TagDatabase.DeleteMethods.cs +++ b/Core/Models/TagDatabase/TagDatabase.DeleteMethods.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using Microsoft.Data.Sqlite; +using TagHierarchyManager.Assets; namespace TagHierarchyManager.Models; @@ -98,9 +99,9 @@ partial class TagDatabase private void PerformDeletionChecks(Tag? targetTag) { - if (targetTag is null) throw new ArgumentException(ErrorMessages.TagNotFound); + if (targetTag is null) throw new ArgumentException(ErrorMessages.TagDatabaseTagNotFound); if (this.GetTagChildren(targetTag.Id).Count > 0) - throw new InvalidOperationException(ErrorMessages.TagHasChildren); + throw new InvalidOperationException(ErrorMessages.TagDatabaseTagHasChildren); } } \ No newline at end of file diff --git a/Core/Models/TagDatabase/TagDatabase.ImportMethods.cs b/Core/Models/TagDatabase/TagDatabase.ImportMethods.cs index bdca1bf..5d7b0a3 100644 --- a/Core/Models/TagDatabase/TagDatabase.ImportMethods.cs +++ b/Core/Models/TagDatabase/TagDatabase.ImportMethods.cs @@ -1,4 +1,5 @@ using Microsoft.Data.Sqlite; +using TagHierarchyManager.Assets; using TagHierarchyManager.Utilities; namespace TagHierarchyManager.Models; @@ -8,7 +9,7 @@ public partial class TagDatabase private async Task ImportAsync(Dictionary importDict) { if (this.currentConnection is null) - throw new InvalidOperationException(ErrorMessages.DbNotInitialised); + throw new InvalidOperationException(ErrorMessages.TagDatabaseNotInitialised); await using SqliteTransaction transaction = (SqliteTransaction)await this.currentConnection.BeginTransactionAsync().ConfigureAwait(false); @@ -30,7 +31,7 @@ public partial class TagDatabase //currentTag = currentTagList[0]; } if (currentTag is null) - throw new InvalidOperationException(ErrorMessages.TagNotFound); + throw new InvalidOperationException(ErrorMessages.TagDatabaseTagNotFound); // todo search parent here then save the parents. await this.SaveTagParents(transaction, currentTag.Id, tag.Parents, currentTag).ConfigureAwait(false); } @@ -48,7 +49,7 @@ public partial class TagDatabase private async Task WriteImportedTagToDatabase(SqliteTransaction transaction, ImportedTag tag) { if (this.currentConnection is null) - throw new InvalidOperationException(ErrorMessages.DbNotInitialised); + throw new InvalidOperationException(ErrorMessages.TagDatabaseNotInitialised); SqliteCommand addCommand = this.currentConnection.CreateCommand(); addCommand.Transaction = transaction; diff --git a/Core/Models/TagDatabase/TagDatabase.Initialisation.cs b/Core/Models/TagDatabase/TagDatabase.Initialisation.cs index 43df686..c40a16e 100644 --- a/Core/Models/TagDatabase/TagDatabase.Initialisation.cs +++ b/Core/Models/TagDatabase/TagDatabase.Initialisation.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.Data.Sqlite; +using TagHierarchyManager.Assets; namespace TagHierarchyManager.Models; @@ -24,7 +25,7 @@ public partial class TagDatabase private void CheckInitialisation() { if (!this.Initialised || this.currentConnection is null || this.Connection is null) - throw new InvalidOperationException(ErrorMessages.DbNotInitialised); + throw new InvalidOperationException(ErrorMessages.TagDatabaseNotInitialised); } /// @@ -66,12 +67,12 @@ public partial class TagDatabase { if (filePath == InMemoryDbPath) return null; - if (string.IsNullOrEmpty(filePath)) return ErrorMessages.FilePathIsEmpty; + if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentException(ErrorMessages.TagDatabaseFilePathEmpty); string fileExt = Path.GetExtension(filePath); - if (fileExt != TagHierarchyDbFileExt) return ErrorMessages.InvalidFileExtension; + if (fileExt != TagHierarchyDbFileExt) throw new ArgumentException(ErrorMessages.TagDatabaseInvalidFileExt); - if (loadMode && !File.Exists(filePath)) return ErrorMessages.FilePathNotFound; + if (loadMode && !File.Exists(filePath)) throw new FileNotFoundException(null, filePath); return null; } @@ -83,11 +84,7 @@ public partial class TagDatabase { if (overwrite && File.Exists(filePath)) File.Delete(filePath); - string? errorString = ValidateFilePath(filePath); - if (errorString is not null) - { - throw new ArgumentException(errorString); - } + ValidateFilePath(filePath); this.currentConnection = new SqliteConnection($"Data Source={filePath};Pooling=False"); @@ -164,7 +161,7 @@ public partial class TagDatabase { this.Logger.Information("[TagHierarchyDatabase.Initialise] Initialising..."); SqliteCommand command = this.currentConnection?.CreateCommand() ?? - throw new InvalidOperationException(ErrorMessages.DbNotInitialised); + throw new InvalidOperationException(ErrorMessages.TagDatabaseNotInitialised); command.CommandText = "SELECT * FROM SETTINGS;"; try { @@ -278,14 +275,14 @@ public partial class TagDatabase if (notTagDatabase) { this.Close(); - throw new ArgumentException(ErrorMessages.DbNotValid); + throw new ArgumentException(ErrorMessages.TagDatabaseInvalidStructure); } } catch (SqliteException ex) { this.Close(); if (ex.SqliteErrorCode == 1) - throw new ArgumentException(ErrorMessages.DbNotValid); + throw new ArgumentException(ErrorMessages.TagDatabaseInvalidStructure); throw; } @@ -302,14 +299,14 @@ public partial class TagDatabase CultureInfo.InvariantCulture); if (schemaVersion == 0) { - throw new ArgumentException(ErrorMessages.DbFileNotValid); + throw new ArgumentException(ErrorMessages.TagDatabaseInvalidFile); } } catch (SqliteException ex) { this.Close(); if (ex.SqliteErrorCode == 26) - throw new ArgumentException(ErrorMessages.DbFileNotValid); + throw new ArgumentException(ErrorMessages.TagDatabaseInvalidFile); throw; } diff --git a/Core/Models/TagDatabase/TagDatabase.Migration.cs b/Core/Models/TagDatabase/TagDatabase.Migration.cs index 77888cf..6aee9b4 100644 --- a/Core/Models/TagDatabase/TagDatabase.Migration.cs +++ b/Core/Models/TagDatabase/TagDatabase.Migration.cs @@ -1,4 +1,5 @@ using Microsoft.Data.Sqlite; +using TagHierarchyManager.Assets; namespace TagHierarchyManager.Models; @@ -11,7 +12,7 @@ public partial class TagDatabase private async Task PerformNeededMigrations() { if (this.currentConnection is null) - throw new InvalidOperationException(ErrorMessages.DbNotInitialised); + throw new InvalidOperationException(ErrorMessages.TagDatabaseNotInitialised); var transaction = (SqliteTransaction) await this.currentConnection.BeginTransactionAsync().ConfigureAwait(false); @@ -36,7 +37,7 @@ public partial class TagDatabase updateModifiedCommand.ExecuteNonQuery(); var deleteOldTableCommand = this.currentConnection.CreateCommand() ?? - throw new InvalidOperationException(ErrorMessages.DbNotInitialised); + throw new InvalidOperationException(ErrorMessages.TagDatabaseNotInitialised); deleteOldTableCommand.Transaction = transaction; deleteOldTableCommand.CommandText = "DROP TABLE alias;"; diff --git a/Core/Models/TagDatabase/TagDatabase.QueryProcessorHandler.cs b/Core/Models/TagDatabase/TagDatabase.QueryProcessorHandler.cs index 7315f2b..1779ee6 100644 --- a/Core/Models/TagDatabase/TagDatabase.QueryProcessorHandler.cs +++ b/Core/Models/TagDatabase/TagDatabase.QueryProcessorHandler.cs @@ -1,4 +1,5 @@ using Microsoft.Data.Sqlite; +using TagHierarchyManager.Assets; namespace TagHierarchyManager.Models; @@ -79,7 +80,7 @@ public partial class TagDatabase private static void ProcessTagParentSelectionInt(SqliteCommand command, int id) { if (id == 0) - throw new ArgumentException(ErrorMessages.EmptyParameters); + throw new ArgumentException(ErrorMessages.TagDatabaseEmptyParameters); command.CommandText = TagParentSelectionBaseCommand; command.Parameters.AddWithValue("@target_id", id); diff --git a/Core/Models/TagDatabase/TagDatabase.SettingsHandler.cs b/Core/Models/TagDatabase/TagDatabase.SettingsHandler.cs index 6fc8c17..0d0ecb8 100644 --- a/Core/Models/TagDatabase/TagDatabase.SettingsHandler.cs +++ b/Core/Models/TagDatabase/TagDatabase.SettingsHandler.cs @@ -1,5 +1,6 @@ using System.Globalization; using Microsoft.Data.Sqlite; +using TagHierarchyManager.Assets; namespace TagHierarchyManager.Models; @@ -49,7 +50,7 @@ public partial class TagDatabase db.CheckInitialisation(); if (await this.CheckSettingExistenceAsync(key).ConfigureAwait(false)) - throw new ArgumentException(ErrorMessages.SettingKeyAlreadyExists(key)); + throw new ArgumentException(string.Format(ErrorMessages.TagDatabaseSettingKeyExists, key)); SqliteCommand insertCommand = db.Connection.CreateCommand(); insertCommand.CommandText = $""" @@ -74,10 +75,10 @@ public partial class TagDatabase db.CheckInitialisation(); if (RequiredSettingsKeys.Contains(key)) - throw new InvalidOperationException(ErrorMessages.SettingIsRequired); + throw new InvalidOperationException(ErrorMessages.TagDatabaseDeletingRequiredSetting); if (!await this.CheckSettingExistenceAsync(key).ConfigureAwait(false)) - throw new KeyNotFoundException(ErrorMessages.SettingKeyNotFound(key)); + throw new KeyNotFoundException(string.Format(ErrorMessages.TagDatabaseSettingKeyNotFound, key)); SqliteCommand command = db.Connection.CreateCommand(); command.CommandText = $""" DELETE FROM settings @@ -120,7 +121,7 @@ public partial class TagDatabase db.CheckInitialisation(); if (!await this.CheckSettingExistenceAsync(key).ConfigureAwait(false)) - throw new KeyNotFoundException(ErrorMessages.SettingKeyNotFound(key)); + throw new KeyNotFoundException(string.Format(ErrorMessages.TagDatabaseSettingKeyNotFound, key)); SqliteCommand command = db.Connection.CreateCommand(); command.CommandText = $""" SELECT value FROM settings @@ -153,7 +154,7 @@ public partial class TagDatabase db.CheckInitialisation(); if (!await this.CheckSettingExistenceAsync(key).ConfigureAwait(false)) - throw new KeyNotFoundException(ErrorMessages.SettingKeyNotFound(key)); + throw new KeyNotFoundException(string.Format(ErrorMessages.TagDatabaseSettingKeyNotFound, key)); SqliteCommand command = db.Connection.CreateCommand(); command.CommandText = $""" UPDATE settings diff --git a/Core/TagHierarchyManager.csproj b/Core/TagHierarchyManager.csproj index 7dcc757..0526602 100644 --- a/Core/TagHierarchyManager.csproj +++ b/Core/TagHierarchyManager.csproj @@ -15,4 +15,19 @@ + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + True + True + ErrorMessages.resx + + + diff --git a/Tests/ImporterTests.cs b/Tests/ImporterTests.cs index 8373001..c04b85b 100644 --- a/Tests/ImporterTests.cs +++ b/Tests/ImporterTests.cs @@ -79,7 +79,6 @@ public class ImporterTests : TestBase /// that starts with a space. /// /// The string to attempt to send to the importer. - /// The expected error message. [Test] [TestCase( #pragma warning disable SA1027 @@ -87,10 +86,9 @@ public class ImporterTests : TestBase Ambient Ambient::genre Ambient::style - """, MusicBeeTagHierarchyImporter.ErrorMessages.TagHierarchyTabsDetected)] - [TestCase(" Ambient", MusicBeeTagHierarchyImporter.ErrorMessages.TagHierarchyStartsWithSpace)] - public async Task ImportAsync_ImportMusicBeeTagHierarchy_ArgumentExceptionThrown(string brokenHierarchy, - string exceptionMessage) + """)] + [TestCase(" Ambient")] + public async Task ImportAsync_ImportMusicBeeTagHierarchy_ArgumentExceptionThrown(string brokenHierarchy) { string tempFilePath = Path.GetTempFileName(); await File.WriteAllTextAsync(tempFilePath, brokenHierarchy); @@ -98,7 +96,6 @@ public class ImporterTests : TestBase Importer importer = new MusicBeeTagHierarchyImporter(); Exception? ex = Assert.ThrowsAsync(async () => await importer.ImportFromFileAsync(tempFilePath)); - Assert.That(ex!.Message, Is.EqualTo(exceptionMessage)); } /// @@ -108,30 +105,26 @@ public class ImporterTests : TestBase /// /// The string to attempt to send to the importer. /// The line number to be expected. - /// The expected error message template. [Test] [TestCase( """ Ambient Ambient::genre Ambient::style - """, 2, MusicBeeTagHierarchyImporter.ErrorMessages.IndentIsUnevenTemplate)] + """, 2)] [TestCase( """ Ambient Ambient::genre Ambient::style - """, 2, MusicBeeTagHierarchyImporter.ErrorMessages.IndentIsExcessiveTemplate)] + """, 2)] public async Task ImportAsync_ImportMusicBeeTagHierarchy_TagHierarchyDataExceptionThrown(string brokenHierarchy, - int lineNumber, string exceptionMessage) + int lineNumber) { - // Arrange - string expectedExceptionMessage = string.Format(exceptionMessage, lineNumber); string tempFilePath = Path.GetTempFileName(); await File.WriteAllTextAsync(tempFilePath, brokenHierarchy); Importer importer = new MusicBeeTagHierarchyImporter(); Exception? ex = Assert.ThrowsAsync(async () => await importer.ImportFromFileAsync(tempFilePath)); - Assert.That(ex!.Message, Is.EqualTo(expectedExceptionMessage)); } } \ No newline at end of file diff --git a/Tests/SettingsTests.cs b/Tests/SettingsTests.cs index c5a776a..eca21ca 100644 --- a/Tests/SettingsTests.cs +++ b/Tests/SettingsTests.cs @@ -41,7 +41,6 @@ public class SettingsTests : TestBase // Act/Assert ArgumentException ex = Assert.ThrowsAsync(async () => await this.Database.Settings.CreateSettingAsync(AddedTestKey, AddedTestValue)) !; - Assert.That(ex.Message, Is.EqualTo(ErrorMessages.SettingKeyAlreadyExists(AddedTestKey))); } /// @@ -56,7 +55,7 @@ public class SettingsTests : TestBase List changedTagBindings = ["genre", "album genre"]; // Act - this.Database.DefaultTagBindings = changedTagBindings; + await this.Database.SetDefaultTagBindingsAsync(changedTagBindings); // Assert string? settingValueString = await this.Database.Settings.GetSettingValueAsync(ExpectedTagBindKey); @@ -105,7 +104,6 @@ public class SettingsTests : TestBase { KeyNotFoundException ex = Assert.ThrowsAsync(async () => await this.Database.Settings.DeleteSettingAsync(NonExistentKey)) !; - Assert.That(ex.Message, Is.EqualTo(ErrorMessages.SettingKeyNotFound(NonExistentKey))); } /// @@ -180,7 +178,6 @@ public class SettingsTests : TestBase { KeyNotFoundException? ex = Assert.ThrowsAsync(async () => await this.Database.Settings.UpdateSettingAsync(NonExistentKey, "testvalue")); - Assert.That(ex!.Message, Is.EqualTo(ErrorMessages.SettingKeyNotFound(NonExistentKey))); } /// diff --git a/Tests/TagDatabaseInitTests.cs b/Tests/TagDatabaseInitTests.cs index 3b9f30f..80936ae 100644 --- a/Tests/TagDatabaseInitTests.cs +++ b/Tests/TagDatabaseInitTests.cs @@ -41,10 +41,9 @@ public class TagDatabaseInitTests : TestBase } TagDatabase dummyDb = new(); - Exception? ex = Assert.ThrowsAsync(async () => await dummyDb.LoadAsync(invalidDbPath)); - + // Act/Assert - Assert.That(ex?.Message, Is.EqualTo(ErrorMessages.DbFileNotValid)); + Exception? ex = Assert.ThrowsAsync(async () => await dummyDb.LoadAsync(invalidDbPath)); } /// @@ -54,14 +53,12 @@ public class TagDatabaseInitTests : TestBase /// The expected error message. /// A representing the asynchronous test. [Test] - [TestCase("", ErrorMessages.FilePathIsEmpty)] - [TestCase("invalid_file.exe", ErrorMessages.InvalidFileExtension)] - public void TagDatabaseInit_NewTagDatabase_ErrorCaughtFileBased(string fileName, string errorMessage) + [TestCase("")] + [TestCase("invalid_file.exe")] + public void TagDatabaseInit_NewTagDatabase_ErrorCaughtFileBased(string fileName) { TagDatabase invalidDb = new(); Exception? ex = Assert.ThrowsAsync(async () => await invalidDb.CreateAsync(fileName)); - - Assert.That(ex?.Message, Is.EqualTo(errorMessage)); } /// @@ -82,12 +79,10 @@ public class TagDatabaseInitTests : TestBase """; await command.ExecuteNonQueryAsync(); + // Act/Assert Exception? ex = Assert.ThrowsAsync(async () => await this.Database.LoadAsync(connection: invalidConnection)); - - // Act/Assert - Assert.That(ex?.Message, Is.EqualTo(ErrorMessages.DbNotValid)); } /// diff --git a/Tests/TagDatabaseSaveTests.cs b/Tests/TagDatabaseSaveTests.cs index b51cfd1..1b5119f 100644 --- a/Tests/TagDatabaseSaveTests.cs +++ b/Tests/TagDatabaseSaveTests.cs @@ -72,7 +72,6 @@ public class TagDatabaseWriteTests : TestBase { ArgumentException? exId = Assert.ThrowsAsync(async () => await this.Database.DeleteTag(1000)); - Assert.That(exId?.Message, Is.EqualTo(ErrorMessages.TagNotFound)); } ///