From 37d6bd040b6028ddf29693665dbb226b536a22a3 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:40:45 +0200 Subject: [PATCH 01/20] add basic code conventions --- .editorconfig | 193 +++++++++++++++++- .../AudioCuesheetEditor.End2EndTests.csproj | 11 - .../AudioCuesheetEditor.Tests.csproj | 10 - .../AudioCuesheetEditor.csproj | 12 -- Directory.Build.props | 11 + 5 files changed, 203 insertions(+), 34 deletions(-) create mode 100644 Directory.Build.props diff --git a/.editorconfig b/.editorconfig index d735b55b..6008f9ad 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1 +1,192 @@ -[*.cs] \ No newline at end of file +root = true + +[*] +charset = utf-8 +end_of_line = crlf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{csproj,props,targets,xml,json,yml,yaml}] +indent_size = 2 + +[*.cs] +indent_size = 4 +tab_width = 4 + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true + +# Qualification and framework type names +dotnet_style_qualification_for_event = false:warning +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning + +# General .NET style +dotnet_style_coalesce_expression = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_namespace_match_folder = true:warning +dotnet_style_null_propagation = true:warning +dotnet_style_object_initializer = true:warning +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = false:warning +dotnet_style_prefer_conditional_expression_over_return = false:warning +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_simplified_boolean_expressions = true:warning +dotnet_style_prefer_simplified_interpolation = true:warning +dotnet_style_readonly_field = true:warning +dotnet_style_require_accessibility_modifiers = omit_if_default:warning + +# C# language style +csharp_style_conditional_delegate_call = true:warning +csharp_style_deconstructed_variable_declaration = true:warning +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_constructors = false:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_lambdas = when_on_single_line:warning +csharp_style_expression_bodied_local_functions = false:warning +csharp_style_expression_bodied_methods = when_on_single_line:warning +csharp_style_expression_bodied_operators = false:warning +csharp_style_expression_bodied_properties = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_inlined_variable_declaration = true:warning +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_prefer_extended_property_pattern = true:warning +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_local_over_anonymous_function = true:warning +csharp_style_prefer_method_group_conversion = true:warning +csharp_style_prefer_not_pattern = true:warning +csharp_style_prefer_null_check_over_type_check = true:warning +csharp_style_prefer_pattern_matching = true:warning +csharp_style_prefer_primary_constructors = false:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_prefer_switch_expression = true:warning +csharp_style_prefer_tuple_swap = true:warning +csharp_style_prefer_utf8_string_literals = true:warning +csharp_style_throw_expression = true:warning +csharp_style_unused_value_assignment_preference = discard_variable:warning +csharp_style_unused_value_expression_statement_preference = discard_variable:warning + +# var preferences +csharp_style_var_elsewhere = true:error +csharp_style_var_for_built_in_types = true:error +csharp_style_var_when_type_is_apparent = true:error + +# Modifiers and braces +csharp_prefer_braces = true:warning +csharp_prefer_simple_using_statement = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:warning + +# New lines +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_between_query_expression_clauses = true +csharp_new_line_before_open_brace = all + +# Indentation +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Spacing +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +# Naming +dotnet_naming_rule.types_and_namespaces_should_be_pascal_case.severity = warning +dotnet_naming_rule.types_and_namespaces_should_be_pascal_case.symbols = types_and_namespaces +dotnet_naming_rule.types_and_namespaces_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.members_should_be_pascal_case.severity = warning +dotnet_naming_rule.members_should_be_pascal_case.symbols = members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.interfaces_should_have_prefix.severity = warning +dotnet_naming_rule.interfaces_should_have_prefix.symbols = interfaces +dotnet_naming_rule.interfaces_should_have_prefix.style = interface_prefix + +dotnet_naming_rule.parameters_and_locals_should_be_camel_case.severity = warning +dotnet_naming_rule.parameters_and_locals_should_be_camel_case.symbols = parameters_and_locals +dotnet_naming_rule.parameters_and_locals_should_be_camel_case.style = camel_case + +dotnet_naming_rule.private_fields_should_be_camel_case.severity = warning +dotnet_naming_rule.private_fields_should_be_camel_case.symbols = private_fields +dotnet_naming_rule.private_fields_should_be_camel_case.style = underscore_camel_case + +dotnet_naming_style.underscore_camel_case.required_prefix = _ +dotnet_naming_style.underscore_camel_case.capitalization = camel_case + +dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace,class,struct,enum,delegate +dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = * + +dotnet_naming_symbols.members.applicable_kinds = property,event,method +dotnet_naming_symbols.members.applicable_accessibilities = * + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = * + +dotnet_naming_symbols.parameters_and_locals.applicable_kinds = parameter,local +dotnet_naming_symbols.parameters_and_locals.applicable_accessibilities = * + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private + +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_naming_style.camel_case.capitalization = camel_case +dotnet_naming_style.interface_prefix.required_prefix = I +dotnet_naming_style.interface_prefix.capitalization = pascal_case + +# Generated code +[**/Migrations/*.cs] +generated_code = true + +[*.Designer.cs] +generated_code = true + +[*.g.cs] +generated_code = true + +[*.generated.cs] +generated_code = true diff --git a/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj b/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj index d02d940a..3922ee65 100644 --- a/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj +++ b/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj @@ -1,10 +1,7 @@ - net10.0 latest - enable - enable true Exe true @@ -15,14 +12,6 @@ true - - True - - - - True - - diff --git a/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj b/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj index 8fec56a1..9bfee3fd 100644 --- a/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj +++ b/AudioCuesheetEditor.Tests/AudioCuesheetEditor.Tests.csproj @@ -1,23 +1,13 @@ - net10.0 latest - enable false true Exe true - - True - - - - True - - diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index 491b0b94..246c8e24 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -1,10 +1,7 @@ - net10.0 true - enable - enable https://github.com/NeoCoderMatrix86/AudioCuesheetEditor Latest 13.3.0 @@ -13,17 +10,8 @@ true service-worker-assets.js - - - True - - - - True - - diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..bbc49dd2 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,11 @@ + + + net10.0 + enable + enable + latest-recommended + true + true + 9999 + + From 9fdc3cb9ffc84cc17e9a6f330f18c703703703df Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:44:48 +0200 Subject: [PATCH 02/20] add exceptions for tests --- AudioCuesheetEditor.End2EndTests/.editorconfig | 3 +++ AudioCuesheetEditor.Tests/.editorconfig | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 AudioCuesheetEditor.End2EndTests/.editorconfig create mode 100644 AudioCuesheetEditor.Tests/.editorconfig diff --git a/AudioCuesheetEditor.End2EndTests/.editorconfig b/AudioCuesheetEditor.End2EndTests/.editorconfig new file mode 100644 index 00000000..3c08f724 --- /dev/null +++ b/AudioCuesheetEditor.End2EndTests/.editorconfig @@ -0,0 +1,3 @@ +[*.cs] +# Underscore used in Testnames is best practise +dotnet_diagnostic.CA1707.severity = none \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/.editorconfig b/AudioCuesheetEditor.Tests/.editorconfig new file mode 100644 index 00000000..3c08f724 --- /dev/null +++ b/AudioCuesheetEditor.Tests/.editorconfig @@ -0,0 +1,3 @@ +[*.cs] +# Underscore used in Testnames is best practise +dotnet_diagnostic.CA1707.severity = none \ No newline at end of file From 057d392dcfa75194d319648bfd948fe7d8bb3e7c Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:49:53 +0200 Subject: [PATCH 03/20] fix code analysis --- .../Models/About.cs | 25 +- .../Models/AppBar.cs | 131 +- .../Models/DetailView.cs | 175 +- .../Models/ExportDialog.cs | 15 +- .../Models/ImportView.cs | 157 +- .../Models/RecordView.cs | 67 +- .../Models/ViewModes.cs | 27 +- .../Tests/Desktop/BasicTest.cs | 243 +- .../Tests/Desktop/ExportTest.cs | 201 +- .../Tests/Desktop/ImportTest.cs | 197 +- .../Tests/Desktop/RecordTest.cs | 45 +- .../Tests/Desktop/TracingTest.cs | 175 +- .../Tests/PlaywrightTestBase.cs | 95 +- .../Tests/Smartphone/BasicTest.cs | 247 +- .../Tests/Smartphone/ExportTest.cs | 205 +- .../Tests/Smartphone/ImportTest.cs | 201 +- .../Tests/Smartphone/RecordTest.cs | 47 +- .../Tests/Smartphone/TracingTest.cs | 179 +- .../Model/AudioCuesheet/AudiofileTests.cs | 143 +- .../Model/AudioCuesheet/CuesheetTests.cs | 125 +- .../Model/AudioCuesheet/TrackTests.cs | 141 +- .../Model/Entity/ValidateableTests.cs | 97 +- .../Model/Entity/ValidationResultTests.cs | 157 +- .../Model/IO/Export/ExportprofileTests.cs | 403 ++- .../Model/IO/Import/ImportprofileTests.cs | 43 +- .../Model/IO/ProjectfileTests.cs | 151 +- .../Model/Options/ExportOptionsTest.cs | 67 +- .../Model/Utility/TimeSpanFormatTests.cs | 31 +- .../Model/Utility/TimeSpanUtilityTests.cs | 298 +- .../AudioCuesheet/AudiofileManagerTests.cs | 1275 ++++---- .../AudioCuesheet/CuesheetManagerTests.cs | 2673 ++++++++--------- .../AudioCuesheet/TrackManagerTests.cs | 1319 ++++---- .../Services/IO/AudioImportServiceTests.cs | 169 +- .../Services/IO/CuesheetExportServiceTests.cs | 561 ++-- .../Services/IO/CuesheetImportServiceTests.cs | 187 +- .../Services/IO/ExportfileGeneratorTests.cs | 325 +- .../Services/IO/FileInputManagerTests.cs | 411 ++- .../Services/IO/ImportManagerTests.cs | 717 +++-- .../Services/IO/TextImportServiceTests.cs | 1223 ++++---- .../LocalStorageOptionsProviderTests.cs | 127 +- .../ApplicationOptionsTimeSpanParserTests.cs | 263 +- .../Services/UI/SessionStateContainerTests.cs | 609 ++-- .../Services/UI/TraceChangeManagerTests.cs | 699 +++-- .../Utility/TestHelper.cs | 23 +- .../Extensions/FlagJsonConverter.cs | 33 +- .../Extensions/WebAssemblyHostExtension.cs | 23 +- .../Model/AudioCuesheet/CDTextfile.cs | 43 +- .../Model/AudioCuesheet/Cuesheet.cs | 109 +- .../Model/AudioCuesheet/CuesheetConstants.cs | 39 +- .../Model/AudioCuesheet/Flag.cs | 85 +- .../Model/AudioCuesheet/IAudiofile.cs | 9 +- .../Model/AudioCuesheet/ICuesheet.cs | 13 +- .../Model/AudioCuesheet/ITrack.cs | 27 +- .../AudioCuesheet/Import/ImportAudiofile.cs | 11 +- .../AudioCuesheet/Import/ImportCuesheet.cs | 19 +- .../Model/AudioCuesheet/Import/ImportTrack.cs | 29 +- .../Model/AudioCuesheet/Track.cs | 219 +- .../Model/Entity/IValidateable.cs | 79 +- .../Model/Entity/Validateable.cs | 65 +- .../Model/Entity/ValidationMessage.cs | 51 +- .../Model/IO/Audio/AudioCodec.cs | 43 +- .../Model/IO/Audio/Audiofile.cs | 203 +- .../Model/IO/Export/Exportfile.cs | 13 +- .../Model/IO/Export/Exportprofile.cs | 291 +- .../Model/IO/FileExtensions.cs | 17 +- AudioCuesheetEditor/Model/IO/FileMimeTypes.cs | 15 +- AudioCuesheetEditor/Model/IO/FileUpload.cs | 15 +- .../Model/IO/Import/IImportfile.cs | 47 +- .../Model/IO/Import/Importfile.cs | 25 +- .../Model/IO/Import/Importprofile.cs | 141 +- AudioCuesheetEditor/Model/IO/Projectfile.cs | 63 +- .../Model/Options/ApplicationOptions.cs | 37 +- .../Model/Options/DownloadOptions.cs | 133 +- .../Model/Options/ExportOptions.cs | 101 +- AudioCuesheetEditor/Model/Options/IOptions.cs | 9 +- .../Model/Options/ImportOptions.cs | 85 +- .../Model/Options/RecordOptions.cs | 9 +- .../Model/Options/ViewOptions.cs | 41 +- .../Model/UI/EditMultipleTracksModalResult.cs | 41 +- .../Model/UI/TraceableChange.cs | 23 +- AudioCuesheetEditor/Model/UI/TracedChange.cs | 31 +- AudioCuesheetEditor/Model/UI/TracedChanges.cs | 11 +- .../Model/Utility/TimeSpanFormat.cs | 163 +- .../Model/Utility/TimeSpanUtility.cs | 29 +- .../Services/Audio/PlaybackService.cs | 417 ++- .../AudioCuesheet/AudiofileManager.cs | 375 ++- .../Services/AudioCuesheet/CuesheetManager.cs | 525 ++-- .../AudioCuesheet/IAudiofileManager.cs | 85 +- .../AudioCuesheet/ICuesheetManager.cs | 161 +- .../Services/AudioCuesheet/ITrackManager.cs | 103 +- .../Services/AudioCuesheet/TrackManager.cs | 289 +- .../Services/IO/AudioImportService.cs | 105 +- .../Services/IO/CuesheetExportService.cs | 135 +- .../Services/IO/CuesheetImportService.cs | 419 ++- .../Services/IO/ExportfileGenerator.cs | 137 +- .../Services/IO/FileInputManager.cs | 213 +- .../Services/IO/IAudioImportService.cs | 19 +- .../Services/IO/IFileInputManager.cs | 81 +- .../Services/IO/ITextImportService.cs | 9 +- .../Services/IO/ImportManager.cs | 481 ++- .../Services/IO/TextImportService.cs | 513 ++-- .../Options/ILocalStorageOptionsProvider.cs | 17 +- .../Options/LocalStorageOptionsProvider.cs | 207 +- .../Provider/MusicBrainzDataProvider.cs | 159 +- AudioCuesheetEditor/Services/Result.cs | 189 +- .../UI/ApplicationOptionsTimeSpanParser.cs | 137 +- .../Services/UI/AutocompleteManager.cs | 63 +- .../Services/UI/DialogManager.cs | 413 ++- .../Services/UI/IDialogManager.cs | 39 +- .../Services/UI/ISessionStateContainer.cs | 45 +- .../Services/UI/ITraceChangeManager.cs | 51 +- .../Services/UI/LocalizationService.cs | 73 +- .../Services/UI/SessionStateContainer.cs | 203 +- .../Services/UI/TraceChangeManager.cs | 275 +- .../Services/Validation/ValidationService.cs | 57 +- .../Shared/BaseLocalizedComponent.cs | 89 +- 116 files changed, 11547 insertions(+), 11646 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Models/About.cs b/AudioCuesheetEditor.End2EndTests/Models/About.cs index 115417b5..2ac1d0af 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/About.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/About.cs @@ -15,22 +15,21 @@ //. using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +class About(IPage page) { - internal class About(IPage page) - { - internal const string BaseUrl = "http://localhost:5132/about"; + internal const string BaseUrl = "http://localhost:5132/about"; - private readonly IPage _page = page; + readonly IPage _page = page; - internal ILocator AboutHeading => _page.GetByRole(AriaRole.Heading, new() { Name = "About AudioCuesheetEditor" }); + internal ILocator AboutHeading => _page.GetByRole(AriaRole.Heading, new() { Name = "About AudioCuesheetEditor" }); - internal async Task GotoAsync() - { - await _page.GotoAsync(BaseUrl); - await _page.WaitForURLAsync(BaseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); - } + internal async Task GotoAsync() + { + await _page.GotoAsync(BaseUrl); + await _page.WaitForURLAsync(BaseUrl); + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs index 7495aadd..bab19e64 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs @@ -15,73 +15,72 @@ //. using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +partial class AppBar(IPage page) { - partial class AppBar(IPage page) + readonly IPage _page = page; + internal ILocator MenuButton => _page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button, new() { Name = "More" }); + + internal ILocator UndoButton => _page.GetByRole(AriaRole.Button, new() { Name = "undo" }); + + internal ILocator RedoButton => _page.GetByRole(AriaRole.Button, new() { Name = "redo" }); + + internal ILocator HomeButton => _page.Locator(".mud-button-root").First; + + internal async Task OpenSettingsAsync() + { + await MenuButton.ClickAsync(); + await _page.GetByText("Settings").ClickAsync(); + } + + internal async Task ChangeLanguageAsync(string language) + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Change language" }).ClickAsync(); + await _page.GetByText(language).ClickAsync(); + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + } + + internal async Task UndoAsync() + { + await UndoButton.ClickAsync(); + } + + internal async Task RedoAsync() + { + await RedoButton.ClickAsync(); + } + + internal async Task OpenFileAsync(string file) + { + await OpenFileDialogAsync(); + await _page.GetByLabel("Open file upload").SetInputFilesAsync(file); + } + + internal async Task OpenFileDialogAsync() + { + await _page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button, new() { Name = "More" }).ClickAsync(); + await _page.GetByRole(AriaRole.Menuitem, new() { Name = "Open file" }).ClickAsync(); + } + + internal async Task OpenExportDialogAsync(string exportType) + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Export menu" }).ClickAsync(); + await _page.GetByText(exportType, new() { Exact = true }).ClickAsync(); + } + + internal async Task OpenDisplayHotkeysAsync() + { + await MenuButton.ClickAsync(); + await _page.GetByText("Hotkeys").ClickAsync(); + } + + internal async Task ResetCuesheetAsync() { - private readonly IPage _page = page; - internal ILocator MenuButton => _page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button, new() { Name = "More" }); - - internal ILocator UndoButton => _page.GetByRole(AriaRole.Button, new() { Name = "undo" }); - - internal ILocator RedoButton => _page.GetByRole(AriaRole.Button, new() { Name = "redo" }); - - internal ILocator HomeButton => _page.Locator(".mud-button-root").First; - - internal async Task OpenSettingsAsync() - { - await MenuButton.ClickAsync(); - await _page.GetByText("Settings").ClickAsync(); - } - - internal async Task ChangeLanguageAsync(string language) - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Change language" }).ClickAsync(); - await _page.GetByText(language).ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); - } - - internal async Task UndoAsync() - { - await UndoButton.ClickAsync(); - } - - internal async Task RedoAsync() - { - await RedoButton.ClickAsync(); - } - - internal async Task OpenFileAsync(string file) - { - await OpenFileDialogAsync(); - await _page.GetByLabel("Open file upload").SetInputFilesAsync(file); - } - - internal async Task OpenFileDialogAsync() - { - await _page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button, new() { Name = "More" }).ClickAsync(); - await _page.GetByRole(AriaRole.Menuitem, new() { Name = "Open file" }).ClickAsync(); - } - - internal async Task OpenExportDialogAsync(string exportType) - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Export menu" }).ClickAsync(); - await _page.GetByText(exportType, new() { Exact = true }).ClickAsync(); - } - - internal async Task OpenDisplayHotkeysAsync() - { - await MenuButton.ClickAsync(); - await _page.GetByText("Hotkeys").ClickAsync(); - } - - internal async Task ResetCuesheetAsync() - { - await MenuButton.ClickAsync(); - await _page.GetByRole(AriaRole.Menuitem, new() { Name = "Reset" }).ClickAsync(); - await _page.GetByText("Reset cuesheet").ClickAsync(); - await _page.GetByRole(AriaRole.Button, new() { Name = "Yes" }).ClickAsync(); - } + await MenuButton.ClickAsync(); + await _page.GetByRole(AriaRole.Menuitem, new() { Name = "Reset" }).ClickAsync(); + await _page.GetByText("Reset cuesheet").ClickAsync(); + await _page.GetByRole(AriaRole.Button, new() { Name = "Yes" }).ClickAsync(); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs index 4199c03c..8bc4d4a3 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs @@ -15,121 +15,120 @@ //. using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +class DetailView(IPage page) { - internal class DetailView(IPage page) - { - internal const string BaseUrl = "http://localhost:5132/"; + internal const string BaseUrl = "http://localhost:5132/"; - private readonly IPage _page = page; + readonly IPage _page = page; - internal ILocator CuesheetArtistInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" }); + internal ILocator CuesheetArtistInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" }); - internal ILocator CuesheetTitleInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" }); + internal ILocator CuesheetTitleInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" }); - internal ILocator NewFileNameInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "New file name" }); + internal ILocator NewFileNameInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "New file name" }); - internal async Task GotoAsync() + internal async Task GotoAsync() + { + await _page.GotoAsync(BaseUrl); + await _page.WaitForURLAsync(BaseUrl); + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + } + + internal async Task AddAudiofileAsync() + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Add file" }).ClickAsync(); + } + + internal async Task SetAudiofileInputFileAsync(int audiofileIndex, string file) + { + await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "No file uploaded!" }).Nth(audiofileIndex).Locator("input[type=\"file\"]").SetInputFilesAsync(file); + } + + internal async Task AddTrackAsync(int audiofileIndex) + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Add new track" }).Nth(audiofileIndex).ClickAsync(); + } + + internal async Task EditTrackAsync(string? artist = null, string? title = null, TimeSpan? begin = null, TimeSpan? end = null, int trackPosition = 1) + { + if (artist != null) { - await _page.GotoAsync(BaseUrl); - await _page.WaitForURLAsync(BaseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + await EditTrackFieldAsync(trackPosition, "Artist", artist); } - - internal async Task AddAudiofileAsync() + if (title != null) { - await _page.GetByRole(AriaRole.Button, new() { Name = "Add file" }).ClickAsync(); + await EditTrackFieldAsync(trackPosition, "Title", title); } - - internal async Task SetAudiofileInputFileAsync(int audiofileIndex, string file) + if (begin != null) { - await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "No file uploaded!" }).Nth(audiofileIndex).Locator("input[type=\"file\"]").SetInputFilesAsync(file); + await EditTrackFieldAsync(trackPosition, "Begin", begin.ToString() ?? string.Empty); } - - internal async Task AddTrackAsync(int audiofileIndex) + if (end != null) { - await _page.GetByRole(AriaRole.Button, new() { Name = "Add new track" }).Nth(audiofileIndex).ClickAsync(); + await EditTrackFieldAsync(trackPosition, "End", end.ToString() ?? string.Empty); } + } - internal async Task EditTrackAsync(string? artist = null, string? title = null, TimeSpan? begin = null, TimeSpan? end = null, int trackPosition = 1) + internal async Task SelectTracksAsync(IEnumerable trackTablePositions, Boolean uncheck = false) + { + foreach (var trackTablePosition in trackTablePositions) { - if (artist != null) - { - await EditTrackFieldAsync(trackPosition, "Artist", artist); - } - if (title != null) + if (uncheck) { - await EditTrackFieldAsync(trackPosition, "Title", title); + await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).UncheckAsync(); } - if (begin != null) + else { - await EditTrackFieldAsync(trackPosition, "Begin", begin.ToString() ?? string.Empty); - } - if (end != null) - { - await EditTrackFieldAsync(trackPosition, "End", end.ToString() ?? string.Empty); - } - } - - internal async Task SelectTracksAsync(IEnumerable trackTablePositions, Boolean uncheck = false) - { - foreach (var trackTablePosition in trackTablePositions) - { - if (uncheck) - { - await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).UncheckAsync(); - } - else - { - await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).CheckAsync(); - } + await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).CheckAsync(); } } + } - internal async Task EditSelectedTracksModalAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); - } + internal async Task EditSelectedTracksModalAsync() + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); + } - internal async Task EditTracksModalAsync(string artist, string title, string end, IEnumerable flagsToSelect) + internal async Task EditTracksModalAsync(string artist, string title, string end, IEnumerable flagsToSelect) + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).FillAsync(artist); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).PressAsync("Tab"); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).FillAsync(title); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).PressAsync("Tab"); + await _page.GetByRole(AriaRole.Textbox, new() { Name = "End" }).FillAsync(end); + foreach (var flag in flagsToSelect) { - await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).FillAsync(artist); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).PressAsync("Tab"); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).FillAsync(title); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).PressAsync("Tab"); - await _page.GetByRole(AriaRole.Textbox, new() { Name = "End" }).FillAsync(end); - foreach (var flag in flagsToSelect) - { - await _page.GetByRole(AriaRole.Button, new() { Name = flag }).ClickAsync(); - } - await _page.GetByRole(AriaRole.Button, new() { Name = "Save changes" }).ClickAsync(); + await _page.GetByRole(AriaRole.Button, new() { Name = flag }).ClickAsync(); } + await _page.GetByRole(AriaRole.Button, new() { Name = "Save changes" }).ClickAsync(); + } - internal async Task RenameAudiofileAsync(int audiofileIndex, string filename) - { - await OpenRenameAudiofileDialogAsync(audiofileIndex); - await NewFileNameInput.FillAsync(filename); - await _page.GetByRole(AriaRole.Button, new() { Name = "Ok" }).ClickAsync(); - } + internal async Task RenameAudiofileAsync(int audiofileIndex, string filename) + { + await OpenRenameAudiofileDialogAsync(audiofileIndex); + await NewFileNameInput.FillAsync(filename); + await _page.GetByRole(AriaRole.Button, new() { Name = "Ok" }).ClickAsync(); + } - internal async Task OpenRenameAudiofileDialogAsync(int audiofileIndex) - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Rename file" }).Nth(audiofileIndex).ClickAsync(); - } + internal async Task OpenRenameAudiofileDialogAsync(int audiofileIndex) + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Rename file" }).Nth(audiofileIndex).ClickAsync(); + } - async Task EditTrackFieldAsync(int trackPosition, string dataLabel, string value) - { - var row = _page.Locator("tbody tr").Nth(trackPosition); - var cell = row.Locator($"td[data-label='{dataLabel}']"); - await cell.ClickAsync(); - var textbox = cell.Locator("input[type='text']"); - await textbox.FillAsync(value); - await textbox.PressAsync("Tab"); - // Click outside the autocomplete to have an focus lost event for getting the value written to model - await _page.GetByRole(AriaRole.Heading, new() { Name = "Playback" }).ClickAsync(new() { Force = true }); - await _page.WaitForTimeoutAsync(100); - } + async Task EditTrackFieldAsync(int trackPosition, string dataLabel, string value) + { + var row = _page.Locator("tbody tr").Nth(trackPosition); + var cell = row.Locator($"td[data-label='{dataLabel}']"); + await cell.ClickAsync(); + var textbox = cell.Locator("input[type='text']"); + await textbox.FillAsync(value); + await textbox.PressAsync("Tab"); + // Click outside the autocomplete to have an focus lost event for getting the value written to model + await _page.GetByRole(AriaRole.Heading, new() { Name = "Playback" }).ClickAsync(new() { Force = true }); + await _page.WaitForTimeoutAsync(100); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs b/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs index 218b8ef3..14e15895 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs @@ -16,15 +16,14 @@ using Microsoft.Playwright; using System.Text.RegularExpressions; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +class ExportDialog(IPage page) { - internal class ExportDialog(IPage page) - { - private readonly IPage _page = page; + readonly IPage _page = page; - internal async Task OpenSchemeMenuAsync(string schemeHeadMenuName = "Scheme head") - { - await _page.Locator("div").Filter(new() { HasTextRegex = new Regex($"^{schemeHeadMenuName}$") }).GetByRole(AriaRole.Button).Nth(1).ClickAsync(); - } + internal async Task OpenSchemeMenuAsync(string schemeHeadMenuName = "Scheme head") + { + await _page.Locator("div").Filter(new() { HasTextRegex = new Regex($"^{schemeHeadMenuName}$") }).GetByRole(AriaRole.Button).Nth(1).ClickAsync(); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs index 174e6fd1..3106e556 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs @@ -16,112 +16,111 @@ using Microsoft.Playwright; using System.Text.RegularExpressions; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +partial class ImportView(IPage page, bool mobile) { - partial class ImportView(IPage page, bool mobile) - { - [GeneratedRegex("^Scheme common data$")] - private static partial Regex SchemeCommonData(); + [GeneratedRegex("^Scheme common data$")] + private static partial Regex SchemeCommonData(); - [GeneratedRegex("^Scheme audiofiles$")] - private static partial Regex SchemeAudiofiles(); + [GeneratedRegex("^Scheme audiofiles$")] + private static partial Regex SchemeAudiofiles(); - internal const string BaseUrl = "http://localhost:5132/"; + internal const string BaseUrl = "http://localhost:5132/"; - private readonly IPage _page = page; - private readonly bool _isMobile = mobile; + readonly IPage _page = page; + readonly bool _isMobile = mobile; - internal ILocator CuesheetArtistInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" }); + internal ILocator CuesheetArtistInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" }); - internal ILocator CuesheetTitleInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" }); + internal ILocator CuesheetTitleInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" }); - internal ILocator CatalogueNumberInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cataloguenumber" }); + internal ILocator CatalogueNumberInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cataloguenumber" }); - internal async Task GotoAsync() - { - await _page.GotoAsync(BaseUrl); - await _page.WaitForURLAsync(BaseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); - await _page.GetByText("Import view").ClickAsync(); - } + internal async Task GotoAsync() + { + await _page.GotoAsync(BaseUrl); + await _page.WaitForURLAsync(BaseUrl); + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + await _page.GetByText("Import view").ClickAsync(); + } - internal async Task ImportFileAsync(string filepath) - { - await _page.GetByLabel("TextField file upload").SetInputFilesAsync(filepath); - } + internal async Task ImportFileAsync(string filepath) + { + await _page.GetByLabel("TextField file upload").SetInputFilesAsync(filepath); + } + + internal async Task ImportTextAsync(string text) + { + await _page.GetByRole(AriaRole.Textbox, new() { Name = "Please enter text or upload a" }).FillAsync(text); + } - internal async Task ImportTextAsync(string text) + internal async Task Analyze() + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Analyze" }).ClickAsync(); + } + + internal async Task CompleteImportAsync() + { + if (_isMobile) { - await _page.GetByRole(AriaRole.Textbox, new() { Name = "Please enter text or upload a" }).FillAsync(text); + await _page.Locator(".mud-button-root.mud-fab").ClickAsync(); + await _page.GetByText("Import data").ClickAsync(); } - - internal async Task Analyze() + else { - await _page.GetByRole(AriaRole.Button, new() { Name = "Analyze" }).ClickAsync(); + await _page.GetByRole(AriaRole.Button, new() { Name = "Import data" }).ClickAsync(); } + } - internal async Task CompleteImportAsync() + internal async Task SelectTracksAsync(IEnumerable trackTablePositions, Boolean uncheck = false) + { + foreach (var trackTablePosition in trackTablePositions) { - if (_isMobile) + if (uncheck) { - await _page.Locator(".mud-button-root.mud-fab").ClickAsync(); - await _page.GetByText("Import data").ClickAsync(); + await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).UncheckAsync(); } else { - await _page.GetByRole(AriaRole.Button, new() { Name = "Import data" }).ClickAsync(); - } - } - - internal async Task SelectTracksAsync(IEnumerable trackTablePositions, Boolean uncheck = false) - { - foreach (var trackTablePosition in trackTablePositions) - { - if (uncheck) - { - await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).UncheckAsync(); - } - else - { - await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).CheckAsync(); - } + await _page.Locator($"tr:nth-child({trackTablePosition + 1}) > td").First.GetByRole(AriaRole.Checkbox).CheckAsync(); } } + } - internal async Task EditTracksModalAsync(string title) - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).FillAsync(title); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).PressAsync("Tab"); - await _page.GetByRole(AriaRole.Button, new() { Name = "Save changes" }).ClickAsync(); - } + internal async Task EditTracksModalAsync(string title) + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).FillAsync(title); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).PressAsync("Tab"); + await _page.GetByRole(AriaRole.Button, new() { Name = "Save changes" }).ClickAsync(); + } - internal async Task SwitchImportProfileAsync(string profile) - { - await _page.GetByText("Textfile (common data in").ClickAsync(); - await _page.GetByText(profile).ClickAsync(); - } + internal async Task SwitchImportProfileAsync(string profile) + { + await _page.GetByText("Textfile (common data in").ClickAsync(); + await _page.GetByText(profile).ClickAsync(); + } - internal async Task ClearSchemeCommonDataAsync() - { - await _page.Locator("div").Filter(new() { HasTextRegex = SchemeCommonData() }).GetByLabel("Clear").ClickAsync(); - } + internal async Task ClearSchemeCommonDataAsync() + { + await _page.Locator("div").Filter(new() { HasTextRegex = SchemeCommonData() }).GetByLabel("Clear").ClickAsync(); + } - internal async Task ClearSchemeAudiofilesAsync() - { - await _page.Locator("div").Filter(new() { HasTextRegex = SchemeAudiofiles() }).GetByLabel("Clear").ClickAsync(); - } + internal async Task ClearSchemeAudiofilesAsync() + { + await _page.Locator("div").Filter(new() { HasTextRegex = SchemeAudiofiles() }).GetByLabel("Clear").ClickAsync(); + } - internal async Task SetSchemeCommonDataAsync(string schemeCommonData) - { - await _page.GetByRole(AriaRole.Textbox, new() { Name = "Scheme common data" }).FillAsync(schemeCommonData); - } + internal async Task SetSchemeCommonDataAsync(string schemeCommonData) + { + await _page.GetByRole(AriaRole.Textbox, new() { Name = "Scheme common data" }).FillAsync(schemeCommonData); + } - internal async Task SelectSchemeCommonDataPlaceholderAsync(string placeholder) - { - await _page.Locator("div").Filter(new() { HasTextRegex = SchemeCommonData() }).GetByRole(AriaRole.Button).Nth(1).ClickAsync(); - await _page.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = placeholder }).ClickAsync(); - } + internal async Task SelectSchemeCommonDataPlaceholderAsync(string placeholder) + { + await _page.Locator("div").Filter(new() { HasTextRegex = SchemeCommonData() }).GetByRole(AriaRole.Button).Nth(1).ClickAsync(); + await _page.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = placeholder }).ClickAsync(); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs b/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs index fba8bafb..e7b2a148 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs @@ -15,41 +15,40 @@ //. using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +class RecordView(IPage page) { - internal class RecordView(IPage page) + internal const string BaseUrl = "http://localhost:5132/"; + + readonly IPage _page = page; + + internal async Task GotoAsync() + { + await _page.GotoAsync(BaseUrl); + await _page.WaitForURLAsync(BaseUrl); + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + await _page.GetByText("Record view").ClickAsync(); + } + + internal async Task StartRecordingAsync() + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Start recording" }).ClickAsync(); + } + + internal async Task StopRecordingAsync() + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Stop recording" }).ClickAsync(); + } + + internal async Task AddRecordingTrackAsync(string artist, string title) { - internal const string BaseUrl = "http://localhost:5132/"; - - private readonly IPage _page = page; - - internal async Task GotoAsync() - { - await _page.GotoAsync(BaseUrl); - await _page.WaitForURLAsync(BaseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); - await _page.GetByText("Record view").ClickAsync(); - } - - internal async Task StartRecordingAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Start recording" }).ClickAsync(); - } - - internal async Task StopRecordingAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Stop recording" }).ClickAsync(); - } - - internal async Task AddRecordingTrackAsync(string artist, string title) - { - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).ClickAsync(); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).FillAsync(artist); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).PressAsync("Tab"); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).FillAsync(title); - await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).PressAsync("Tab"); - await _page.GetByRole(AriaRole.Button, new() { Name = "Add track" }).ClickAsync(); - } + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).ClickAsync(); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).FillAsync(artist); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Artist" }).PressAsync("Tab"); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).FillAsync(title); + await _page.GetByRole(AriaRole.Combobox, new() { Name = "Title" }).PressAsync("Tab"); + await _page.GetByRole(AriaRole.Button, new() { Name = "Add track" }).ClickAsync(); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs b/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs index f1a69508..58783602 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs @@ -16,23 +16,22 @@ using Microsoft.Playwright; using System.Text.RegularExpressions; -namespace AudioCuesheetEditor.End2EndTests.Models +namespace AudioCuesheetEditor.End2EndTests.Models; + +partial class ViewModes(IPage page, bool mobile) { - internal partial class ViewModes(IPage page, bool mobile) - { - private readonly IPage _page = page; - private readonly bool _isMobile = mobile; + readonly IPage _page = page; + readonly bool _isMobile = mobile; - internal async Task SwitchView(string viewMode) + internal async Task SwitchView(string viewMode) + { + if (_isMobile) { - if (_isMobile) - { - await _page.GetByRole(AriaRole.Button).Filter(new() { HasTextRegex = ViewModeForward() }).Nth(4).ClickAsync(); - } - await _page.GetByText(viewMode).ClickAsync(); + await _page.GetByRole(AriaRole.Button).Filter(new() { HasTextRegex = ViewModeForward() }).Nth(4).ClickAsync(); } - - [GeneratedRegex("^$")] - internal static partial Regex ViewModeForward(); + await _page.GetByText(viewMode).ClickAsync(); } + + [GeneratedRegex("^$")] + internal static partial Regex ViewModeForward(); } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs index 874a59b2..35f541a5 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs @@ -16,77 +16,77 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop +namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop; + +[TestClass] +public class BasicTest : PlaywrightTestBase { - [TestClass] - public class BasicTest : PlaywrightTestBase + [TestMethod] + public async Task Application_HasTitle_WhenBrowsingIndex() { - [TestMethod] - public async Task Application_HasTitle_WhenBrowsingIndex() - { - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - var appBar = new AppBar(TestPage); - await Expect(appBar.HomeButton).ToBeVisibleAsync(); - await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); - } + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + var appBar = new AppBar(TestPage); + await Expect(appBar.HomeButton).ToBeVisibleAsync(); + await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); + } - [TestMethod] - public async Task AboutHeader_HasTitle_WhenBrowsingAbout() - { - var about = new About(TestPage); - await about.GotoAsync(); - await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); - await Expect(about.AboutHeading).ToBeVisibleAsync(); - } + [TestMethod] + public async Task AboutHeader_HasTitle_WhenBrowsingAbout() + { + var about = new About(TestPage); + await about.GotoAsync(); + await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); + await Expect(about.AboutHeading).ToBeVisibleAsync(); + } - [TestMethod] - public async Task Audiofile_ShouldBeRenamed_WhenEditingFilename() - { - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.RenameAudiofileAsync(0, "Kalimba test 123.mp3"); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Kalimba test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Kalimba test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); - } + [TestMethod] + public async Task Audiofile_ShouldBeRenamed_WhenEditingFilename() + { + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.RenameAudiofileAsync(0, "Kalimba test 123.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Kalimba test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Kalimba test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); + } - [TestMethod] - public async Task OpenSettings_ShouldDisplaySettings_WhenSelectingSettings() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await bar.OpenSettingsAsync(); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Settings" })).ToBeVisibleAsync(); - } + [TestMethod] + public async Task OpenSettings_ShouldDisplaySettings_WhenSelectingSettings() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await bar.OpenSettingsAsync(); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Settings" })).ToBeVisibleAsync(); + } - [TestMethod] - public async Task ResetCuesheet_ShouldResetAllCuesheetReferences_WhenResettingCuesheetAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await bar.ResetCuesheetAsync(); - await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- group:\n - paragraph: \"--:--:--\"\n - slider \"Playback slider\" [disabled]: \"0\"\n - paragraph: \"--:--:--\"\n- group:\n - button \"Play\" [disabled]\n - group:\n - button \"Jump to previous track\" [disabled]\n - button \"Stop the current playback\" [disabled]\n - button \"Jump to next track\" [disabled]"); - } + [TestMethod] + public async Task ResetCuesheet_ShouldResetAllCuesheetReferences_WhenResettingCuesheetAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await bar.ResetCuesheetAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- group:\n - paragraph: \"--:--:--\"\n - slider \"Playback slider\" [disabled]: \"0\"\n - paragraph: \"--:--:--\"\n- group:\n - button \"Play\" [disabled]\n - group:\n - button \"Jump to previous track\" [disabled]\n - button \"Stop the current playback\" [disabled]\n - button \"Jump to next track\" [disabled]"); + } - [TestMethod] - public async Task ChangeLanguage_ShouldSwitchLanguage_WhenGermanIsSelected() - { - var bar = new AppBar(TestPage); - var exportDialog = new ExportDialog(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await bar.ChangeLanguageAsync("German (Germany)"); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Allgemeine Informationen" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByText("Aufnahmeansicht")).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Dateien" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Wiedergabe" })).ToBeVisibleAsync(); - await bar.OpenExportDialogAsync("Textdatei"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- dialog ""Exportprofile Close"": + [TestMethod] + public async Task ChangeLanguage_ShouldSwitchLanguage_WhenGermanIsSelected() + { + var bar = new AppBar(TestPage); + var exportDialog = new ExportDialog(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await bar.ChangeLanguageAsync("German (Germany)"); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Allgemeine Informationen" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByText("Aufnahmeansicht")).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Dateien" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Wiedergabe" })).ToBeVisibleAsync(); + await bar.OpenExportDialogAsync("Textdatei"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- dialog ""Exportprofile Close"": - heading ""Exportprofile"" [level=6] - button ""Close"" - text: ""Export ist derzeit nicht möglich: Künstler hat keinen Wert! Titel hat keinen Wert! Audiodateien hat ungültige Anzahl (0)!"" @@ -137,23 +137,23 @@ await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- d - text: Schema Fuß - group: - button ""Export erzeugen"" [disabled]"); - await exportDialog.OpenSchemeMenuAsync("Schema Kopf"); - await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"CDTextdatei\":\r\n - paragraph: CDTextdatei\r\n - menuitem \"Katalognummer\":\r\n - paragraph: Katalognummer\r\n - menuitem \"Datum\":\r\n - paragraph: Datum\r\n - menuitem \"Datum & Uhrzeit\":\r\n - paragraph: Datum & Uhrzeit\r\n - menuitem \"Uhrzeit\":\r\n - paragraph: Uhrzeit"); - await TestPage.GetByText("CDTextdatei").ClickAsync(); - await exportDialog.OpenSchemeMenuAsync("Schema Titel"); - await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"End\":\r\n - paragraph: End\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); - } + await exportDialog.OpenSchemeMenuAsync("Schema Kopf"); + await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"CDTextdatei\":\r\n - paragraph: CDTextdatei\r\n - menuitem \"Katalognummer\":\r\n - paragraph: Katalognummer\r\n - menuitem \"Datum\":\r\n - paragraph: Datum\r\n - menuitem \"Datum & Uhrzeit\":\r\n - paragraph: Datum & Uhrzeit\r\n - menuitem \"Uhrzeit\":\r\n - paragraph: Uhrzeit"); + await TestPage.GetByText("CDTextdatei").ClickAsync(); + await exportDialog.OpenSchemeMenuAsync("Schema Titel"); + await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"End\":\r\n - paragraph: End\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); + } - [TestMethod] - public async Task TrackTableControls_ShouldBeEnabled_WhenSelectingFirstTrackAsync() - { - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.SelectTracksAsync([1]); - await Expect(TestPage.GetByLabel("Track table controls")).ToMatchAriaSnapshotAsync(@"- group: + [TestMethod] + public async Task TrackTableControls_ShouldBeEnabled_WhenSelectingFirstTrackAsync() + { + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.SelectTracksAsync([1]); + await Expect(TestPage.GetByLabel("Track table controls")).ToMatchAriaSnapshotAsync(@"- group: - button ""Add new track"" - button ""Edit selected tracks"" - button ""Copy selected tracks"" @@ -164,48 +164,47 @@ await Expect(TestPage.GetByLabel("Track table controls")).ToMatchAriaSnapshotAsy - button ""Move selected tracks down"" - group: - button ""Fixed table header"""); - } + } - [TestMethod] - public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenExportDialogAsync("Cuesheet"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenExportDialogAsync("Projectfile"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenExportDialogAsync("Textfile"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenSettingsAsync(); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenDisplayHotkeysAsync(); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.OpenRenameAudiofileDialogAsync(0); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await detailView.NewFileNameInput.FillAsync("Test 123"); - await TestPage.Keyboard.PressAsync("Enter"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); - } + [TestMethod] + public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenExportDialogAsync("Cuesheet"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenExportDialogAsync("Projectfile"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenExportDialogAsync("Textfile"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenSettingsAsync(); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenDisplayHotkeysAsync(); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.OpenRenameAudiofileDialogAsync(0); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await detailView.NewFileNameInput.FillAsync("Test 123"); + await TestPage.Keyboard.PressAsync("Enter"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs index ea6aefe5..8a4f17e8 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs @@ -16,32 +16,32 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop +namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop; + +[TestClass] +public class ExportTest : PlaywrightTestBase { - [TestClass] - public class ExportTest : PlaywrightTestBase + [TestMethod] + public async Task DownloadCuesheet_GeneratesCuesheetFile_WhenCuesheetIsValid() { - [TestMethod] - public async Task DownloadCuesheet_GeneratesCuesheetFile_WhenCuesheetIsValid() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); - await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); - await bar.OpenExportDialogAsync("Cuesheet"); - var downloadTask = TestPage.WaitForDownloadAsync(); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); - var download = await downloadTask; - using var stream = await download.CreateReadStreamAsync(); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - content = content.Replace("\n", Environment.NewLine); - Assert.AreEqual(@"TITLE ""Cuesheet Title 1"" + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); + await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); + await bar.OpenExportDialogAsync("Cuesheet"); + var downloadTask = TestPage.WaitForDownloadAsync(); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); + var download = await downloadTask; + using var stream = await download.CreateReadStreamAsync(); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(TestContext.CancellationToken); + content = content.Replace("\n", Environment.NewLine); + Assert.AreEqual(@"TITLE ""Cuesheet Title 1"" PERFORMER ""Cuesheet Artist 1"" FILE ""Kalimba.mp3"" MP3 TRACK 01 AUDIO @@ -49,84 +49,84 @@ TRACK 01 AUDIO PERFORMER ""Track Artist 1"" INDEX 01 00:00:00 ", content); - } + } - [TestMethod] - public async Task DownloadProject_GeneratesProjectFile_WhenCuesheetIsValidAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); - await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); - await bar.OpenExportDialogAsync("Projectfile"); - var downloadTask = TestPage.WaitForDownloadAsync(); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download project" }).ClickAsync(); - var download = await downloadTask; - using var stream = await download.CreateReadStreamAsync(); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); - } + [TestMethod] + public async Task DownloadProject_GeneratesProjectFile_WhenCuesheetIsValidAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); + await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); + await bar.OpenExportDialogAsync("Projectfile"); + var downloadTask = TestPage.WaitForDownloadAsync(); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download project" }).ClickAsync(); + var download = await downloadTask; + using var stream = await download.CreateReadStreamAsync(); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(TestContext.CancellationToken); + Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); + } - [TestMethod] - public async Task DownloadText_GeneratesTextFile_WhenCuesheetIsValidAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); - await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Track Artist 1", "Track Title 1", TimeSpan.Zero, new TimeSpan(0, 0, 10), 1); - await detailView.EditTrackAsync("Track Artist 2", "Track Title 2", new TimeSpan(0, 0, 10), new TimeSpan(0, 0, 20), 2); - await detailView.EditTrackAsync("Track Artist 3", "Track Title 3", new TimeSpan(0, 0, 20), new TimeSpan(0, 0, 30), 3); - await detailView.EditTrackAsync("Track Artist 4", "Track Title 4", new TimeSpan(0, 0, 30), new TimeSpan(0, 0, 40), 4); - await detailView.EditTrackAsync("Track Artist 5", "Track Title 5", new TimeSpan(0, 0, 40), new TimeSpan(0, 0, 50), 5); - await detailView.EditTrackAsync("Track Artist 6", "Track Title 6", new TimeSpan(0, 0, 50), new TimeSpan(0, 1, 0), 6); - await detailView.EditTrackAsync("Track Artist 7", "Track Title 7", new TimeSpan(0, 1, 0), new TimeSpan(0, 1, 10), 7); - await detailView.EditTrackAsync("Track Artist 8", "Track Title 8", new TimeSpan(0, 1, 10), new TimeSpan(0, 1, 20), 8); - await detailView.EditTrackAsync("Track Artist 9", "Track Title 9", new TimeSpan(0, 1, 20), new TimeSpan(0, 1, 30), 9); - await detailView.EditTrackAsync("Track Artist 10", "Track Title 10", new TimeSpan(0, 1, 30), new TimeSpan(0, 1, 40), 10); - await detailView.EditTrackAsync("Track Artist 11", "Track Title 11", new TimeSpan(0, 1, 40), new TimeSpan(0, 1, 50), 11); - await detailView.EditTrackAsync("Track Artist 12", "Track Title 12", new TimeSpan(0, 1, 50), new TimeSpan(0, 2, 0), 12); - await detailView.EditTrackAsync("Track Artist 13", "Track Title 13", new TimeSpan(0, 2, 0), new TimeSpan(0, 2, 10), 13); - await detailView.EditTrackAsync("Track Artist 14", "Track Title 14", new TimeSpan(0, 2, 10), new TimeSpan(0, 2, 20), 14); - await detailView.EditTrackAsync("Track Artist 15", "Track Title 15", new TimeSpan(0, 2, 20), new TimeSpan(0, 2, 30), 15); - await detailView.EditTrackAsync("Track Artist 16", "Track Title 16", new TimeSpan(0, 2, 30), null, 16); - await bar.OpenExportDialogAsync("Textfile"); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Generate export" }).ClickAsync(); - await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Copy to clipboard" })).ToBeVisibleAsync(); - var downloadTask = TestPage.WaitForDownloadAsync(); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); - var download = await downloadTask; - using var stream = await download.CreateReadStreamAsync(); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - content = content.Replace("\n", Environment.NewLine); - Assert.AreEqual(@"Cuesheet Artist 1 - Cuesheet Title 1 + [TestMethod] + public async Task DownloadText_GeneratesTextFile_WhenCuesheetIsValidAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); + await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Track Artist 1", "Track Title 1", TimeSpan.Zero, new TimeSpan(0, 0, 10), 1); + await detailView.EditTrackAsync("Track Artist 2", "Track Title 2", new TimeSpan(0, 0, 10), new TimeSpan(0, 0, 20), 2); + await detailView.EditTrackAsync("Track Artist 3", "Track Title 3", new TimeSpan(0, 0, 20), new TimeSpan(0, 0, 30), 3); + await detailView.EditTrackAsync("Track Artist 4", "Track Title 4", new TimeSpan(0, 0, 30), new TimeSpan(0, 0, 40), 4); + await detailView.EditTrackAsync("Track Artist 5", "Track Title 5", new TimeSpan(0, 0, 40), new TimeSpan(0, 0, 50), 5); + await detailView.EditTrackAsync("Track Artist 6", "Track Title 6", new TimeSpan(0, 0, 50), new TimeSpan(0, 1, 0), 6); + await detailView.EditTrackAsync("Track Artist 7", "Track Title 7", new TimeSpan(0, 1, 0), new TimeSpan(0, 1, 10), 7); + await detailView.EditTrackAsync("Track Artist 8", "Track Title 8", new TimeSpan(0, 1, 10), new TimeSpan(0, 1, 20), 8); + await detailView.EditTrackAsync("Track Artist 9", "Track Title 9", new TimeSpan(0, 1, 20), new TimeSpan(0, 1, 30), 9); + await detailView.EditTrackAsync("Track Artist 10", "Track Title 10", new TimeSpan(0, 1, 30), new TimeSpan(0, 1, 40), 10); + await detailView.EditTrackAsync("Track Artist 11", "Track Title 11", new TimeSpan(0, 1, 40), new TimeSpan(0, 1, 50), 11); + await detailView.EditTrackAsync("Track Artist 12", "Track Title 12", new TimeSpan(0, 1, 50), new TimeSpan(0, 2, 0), 12); + await detailView.EditTrackAsync("Track Artist 13", "Track Title 13", new TimeSpan(0, 2, 0), new TimeSpan(0, 2, 10), 13); + await detailView.EditTrackAsync("Track Artist 14", "Track Title 14", new TimeSpan(0, 2, 10), new TimeSpan(0, 2, 20), 14); + await detailView.EditTrackAsync("Track Artist 15", "Track Title 15", new TimeSpan(0, 2, 20), new TimeSpan(0, 2, 30), 15); + await detailView.EditTrackAsync("Track Artist 16", "Track Title 16", new TimeSpan(0, 2, 30), null, 16); + await bar.OpenExportDialogAsync("Textfile"); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Generate export" }).ClickAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Copy to clipboard" })).ToBeVisibleAsync(); + var downloadTask = TestPage.WaitForDownloadAsync(); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); + var download = await downloadTask; + using var stream = await download.CreateReadStreamAsync(); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(TestContext.CancellationToken); + content = content.Replace("\n", Environment.NewLine); + Assert.AreEqual(@"Cuesheet Artist 1 - Cuesheet Title 1 Track Artist 1 - Track Title 1 00:00:00 Track Artist 2 - Track Title 2 00:00:10 @@ -146,6 +146,5 @@ public async Task DownloadText_GeneratesTextFile_WhenCuesheetIsValidAsync() Track Artist 16 - Track Title 16 00:02:30 ", content); - } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs index 00dfb6ef..c982b351 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs @@ -17,20 +17,20 @@ using Microsoft.Playwright; using Microsoft.VisualStudio.TestPlatform.ObjectModel; -namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop +namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop; + +[TestClass] +public class ImportTest : PlaywrightTestBase { - [TestClass] - public class ImportTest : PlaywrightTestBase + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile() { - [TestMethod] - public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Sample_Inputfile.txt"); - await importView.Analyze(); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -212,22 +212,22 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "c:\\AudioFile.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"c:\\\\AudioFile.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); - await importView.GotoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); - } + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "c:\\AudioFile.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"c:\\\\AudioFile.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); + await importView.GotoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); + } - [TestMethod] - public async Task Import_ShouldBeEditable_WhenEditingTrack() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Sample_Inputfile.txt"); - await importView.Analyze(); - await importView.SelectTracksAsync([5]); - await importView.EditTracksModalAsync("Sample Title Edited 5"); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldBeEditable_WhenEditingTrack() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); + await importView.SelectTracksAsync([5]); + await importView.EditTracksModalAsync("Sample Title Edited 5"); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -409,17 +409,17 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - } + } - [TestMethod] - public async Task Import_ShouldImportTracks_WithSpecialTextfile() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Textimport-Bug-#54.txt"); - await importView.SwitchImportProfileAsync("Textfile (just track data)"); - await importView.Analyze(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WithSpecialTextfile() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Textimport-Bug-#54.txt"); + await importView.SwitchImportProfileAsync("Textfile (just track data)"); + await importView.Analyze(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length""': - columnheader ""Select all rows"": @@ -1174,20 +1174,20 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - textbox - rowgroup: - row"); - } + } - [TestMethod] - public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile2() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Sample_Inputfile2.txt"); - await importView.ClearSchemeCommonDataAsync(); - await importView.ClearSchemeAudiofilesAsync(); - await importView.Analyze(); - await Expect(importView.CuesheetArtistInput).ToBeEmptyAsync(); - await Expect(importView.CuesheetTitleInput).ToBeEmptyAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile2() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Sample_Inputfile2.txt"); + await importView.ClearSchemeCommonDataAsync(); + await importView.ClearSchemeAudiofilesAsync(); + await importView.Analyze(); + await Expect(importView.CuesheetArtistInput).ToBeEmptyAsync(); + await Expect(importView.CuesheetTitleInput).ToBeEmptyAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length""': - columnheader ""Select all rows"": @@ -1353,18 +1353,18 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - textbox: 00:30:00 - rowgroup: - row"); - } + } - [TestMethod] - public async Task Import_ShouldImportTracks_WithTraktorOutput() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Traktor Export.html"); - await importView.SwitchImportProfileAsync("Traktor history"); - await importView.Analyze(); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WithTraktorOutput() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Traktor Export.html"); + await importView.SwitchImportProfileAsync("Traktor history"); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -2238,18 +2238,18 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - } + } - [TestMethod] - public async Task Open_ShouldImportProject_WhenUsingProjectfile() - { - var detailView = new DetailView(TestPage); - var appBar = new AppBar(TestPage); - await detailView.GotoAsync(); - await appBar.OpenFileAsync("Sample_Project.ace"); - await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); - await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Open_ShouldImportProject_WhenUsingProjectfile() + { + var detailView = new DetailView(TestPage); + var appBar = new AppBar(TestPage); + await detailView.GotoAsync(); + await appBar.OpenFileAsync("Sample_Project.ace"); + await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); + await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -2431,20 +2431,20 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); - } + await appBar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); + } - [TestMethod] - public async Task Open_ShouldImportCuesheet_WhenUsingCuesheetfile() - { - var detailView = new DetailView(TestPage); - var appBar = new AppBar(TestPage); - await detailView.GotoAsync(); - await appBar.OpenFileAsync("Sample_Cuesheet.cue"); - await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); - await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Open_ShouldImportCuesheet_WhenUsingCuesheetfile() + { + var detailView = new DetailView(TestPage); + var appBar = new AppBar(TestPage); + await detailView.GotoAsync(); + await appBar.OpenFileAsync("Sample_Cuesheet.cue"); + await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); + await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -2626,20 +2626,20 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); - } + await appBar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); + } - [TestMethod] - public async Task Import_ShouldImportTracks_WhenUsingText() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); - await importView.ImportTextAsync(text); - await importView.Analyze(); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingText() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); + await importView.ImportTextAsync(text); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -2821,6 +2821,5 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/RecordTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/RecordTest.cs index 99e78b87..dbe6ed24 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/RecordTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/RecordTest.cs @@ -16,30 +16,29 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop +namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop; + +[TestClass] +public class RecordTest : PlaywrightTestBase { - [TestClass] - public class RecordTest : PlaywrightTestBase + [TestMethod] + public async Task Record_ShouldRecordTracks_WhenTracksAdded() { - [TestMethod] - public async Task Record_ShouldRecordTracks_WhenTracksAdded() - { - var recordView = new RecordView(TestPage); - var viewModes = new ViewModes(TestPage, DeviceName != null); - var detailView = new DetailView(TestPage); - await recordView.GotoAsync(); - await recordView.StartRecordingAsync(); - await recordView.AddRecordingTrackAsync("Test Track 1 Artist", "Test Track 1 Title"); - await recordView.AddRecordingTrackAsync("Test Track 2 Artist", "Test Track 2 Title"); - await recordView.StopRecordingAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Artist Clear" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Title Clear" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Artist Clear" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Title Clear" })).ToBeVisibleAsync(); - await viewModes.SwitchView("Detail view"); - await detailView.SelectTracksAsync([1]); - await detailView.EditSelectedTracksModalAsync(); - await Expect(TestPage.GetByRole(AriaRole.Switch, new() { Name = "Link to previous track" })).ToBeCheckedAsync(); - } + var recordView = new RecordView(TestPage); + var viewModes = new ViewModes(TestPage, DeviceName != null); + var detailView = new DetailView(TestPage); + await recordView.GotoAsync(); + await recordView.StartRecordingAsync(); + await recordView.AddRecordingTrackAsync("Test Track 1 Artist", "Test Track 1 Title"); + await recordView.AddRecordingTrackAsync("Test Track 2 Artist", "Test Track 2 Title"); + await recordView.StopRecordingAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Artist Clear" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Title Clear" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Artist Clear" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Title Clear" })).ToBeVisibleAsync(); + await viewModes.SwitchView("Detail view"); + await detailView.SelectTracksAsync([1]); + await detailView.EditSelectedTracksModalAsync(); + await Expect(TestPage.GetByRole(AriaRole.Switch, new() { Name = "Link to previous track" })).ToBeCheckedAsync(); } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs index 30f8cef1..0e390152 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs @@ -16,28 +16,28 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop +namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop; + +[TestClass] +public class TracingTest : PlaywrightTestBase { - [TestClass] - public class TracingTest : PlaywrightTestBase + [TestMethod] + public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoAndRedoAreUsed() { - [TestMethod] - public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoAndRedoAreUsed() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Test Artist 1"); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await detailView.EditTrackAsync(title: "Test Title 1"); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await bar.UndoAsync(); - await bar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Test Artist 1"); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await detailView.EditTrackAsync(title: "Test Title 1"); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await bar.UndoAsync(); + await bar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -70,10 +70,10 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - await Expect(bar.RedoButton).ToBeEnabledAsync(); - await bar.RedoAsync(); - await bar.RedoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await Expect(bar.RedoButton).ToBeEnabledAsync(); + await bar.RedoAsync(); + await bar.RedoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -108,8 +108,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - await detailView.EditTrackAsync("Mozart", "Eine kleine Nachtmusik"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await detailView.EditTrackAsync("Mozart", "Eine kleine Nachtmusik"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -144,8 +144,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - await bar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -180,19 +180,19 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - } + } - [TestMethod] - public async Task UndoRedo_ShouldRestoreTrackState_WhenModalEdit() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.AddTrackAsync(0); - await detailView.SelectTracksAsync([1]); - await detailView.EditTracksModalAsync("Test Track Artist 1", "Test Track Title 1", "00:02:23", ["channel audio (4CH)", "Serial copy management system"]); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreTrackState_WhenModalEdit() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.AddTrackAsync(0); + await detailView.SelectTracksAsync([1]); + await detailView.EditTracksModalAsync("Test Track Artist 1", "Test Track Title 1", "00:02:23", ["channel audio (4CH)", "Serial copy management system"]); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -227,8 +227,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - await bar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -261,8 +261,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - await bar.RedoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.RedoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -297,32 +297,32 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - } + } - [TestMethod] - public async Task UndoRedo_ShouldRestoreCuesheet_WhenUsingImport() - { - var bar = new AppBar(TestPage); - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Textimport with Cuesheetdata.txt"); - await importView.SetSchemeCommonDataAsync("Artist - Title - "); - await importView.SelectSchemeCommonDataPlaceholderAsync("Cataloguenumber"); - await importView.ClearSchemeAudiofilesAsync(); - await importView.Analyze(); - await Expect(bar.UndoButton).ToBeDisabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await importView.CompleteImportAsync(); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await bar.UndoAsync(); - await Expect(bar.UndoButton).ToBeDisabledAsync(); - await Expect(bar.RedoButton).ToBeEnabledAsync(); - await bar.RedoAsync(); - await Expect(importView.CuesheetArtistInput).ToHaveValueAsync("DJFreezeT"); - await Expect(importView.CuesheetTitleInput).ToHaveValueAsync("Rabbit Hole Mix"); - await Expect(importView.CatalogueNumberInput).ToHaveValueAsync("01 23456 78912 3"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreCuesheet_WhenUsingImport() + { + var bar = new AppBar(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Textimport with Cuesheetdata.txt"); + await importView.SetSchemeCommonDataAsync("Artist - Title - "); + await importView.SelectSchemeCommonDataPlaceholderAsync("Cataloguenumber"); + await importView.ClearSchemeAudiofilesAsync(); + await importView.Analyze(); + await Expect(bar.UndoButton).ToBeDisabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await importView.CompleteImportAsync(); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await bar.UndoAsync(); + await Expect(bar.UndoButton).ToBeDisabledAsync(); + await Expect(bar.RedoButton).ToBeEnabledAsync(); + await bar.RedoAsync(); + await Expect(importView.CuesheetArtistInput).ToHaveValueAsync("DJFreezeT"); + await Expect(importView.CuesheetTitleInput).ToHaveValueAsync("Rabbit Hole Mix"); + await Expect(importView.CatalogueNumberInput).ToHaveValueAsync("01 23456 78912 3"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -1155,21 +1155,21 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - } + } - [TestMethod] - public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoWithAudiofile() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoWithAudiofile() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -1221,10 +1221,10 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - await bar.UndoAsync(); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeEnabledAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.UndoAsync(); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeEnabledAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - 'row ""Select all rows # Artist Title Begin End Length Status""': - columnheader ""Select all rows"": @@ -1257,6 +1257,5 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell - rowgroup: - row"); - } } } \ No newline at end of file diff --git a/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs b/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs index 3fdebf6c..836b8c96 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs @@ -16,60 +16,59 @@ using Microsoft.Playwright; using Microsoft.Playwright.MSTest; -namespace AudioCuesheetEditor.End2EndTests.Tests +namespace AudioCuesheetEditor.End2EndTests.Tests; + +public abstract class PlaywrightTestBase : PageTest { - public abstract class PlaywrightTestBase : PageTest - { - private IBrowserContext _testContextInstance = null!; - protected IPage TestPage = null!; + IBrowserContext _testContextInstance = null!; + protected IPage TestPage = null!; - protected virtual string? DeviceName => null; + protected virtual string? DeviceName => null; - [TestInitialize] - public async Task TestInitializeAsync() + [TestInitialize] + public async Task TestInitializeAsync() + { + //On mobile we start a new context, on desktop we use the default one + if (DeviceName != null) + { + var device = Playwright.Devices[DeviceName]; + _testContextInstance = await Browser.NewContextAsync(device); + TestPage = await _testContextInstance.NewPageAsync(); + } + else { - //On mobile we start a new context, on desktop we use the default one - if (DeviceName != null) - { - var device = Playwright.Devices[DeviceName]; - _testContextInstance = await Browser.NewContextAsync(device); - TestPage = await _testContextInstance.NewPageAsync(); - } - else - { - _testContextInstance = Context; - TestPage = Page; - } - await _testContextInstance.ClearCookiesAsync(); - await _testContextInstance.Tracing.StartAsync(new() - { - Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}", - Screenshots = true, - Snapshots = true, - Sources = true - }); + _testContextInstance = Context; + TestPage = Page; } + await _testContextInstance.ClearCookiesAsync(); + await _testContextInstance.Tracing.StartAsync(new() + { + Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}", + Screenshots = true, + Snapshots = true, + Sources = true + }); + } - [TestCleanup] - public async Task TestCleanupAsync() + [TestCleanup] + public async Task TestCleanupAsync() + { + var failed = new[] { - var failed = new[] - { - UnitTestOutcome.Failed, - UnitTestOutcome.Error, - UnitTestOutcome.Timeout, - UnitTestOutcome.Aborted - }.Contains(TestContext.CurrentTestOutcome); + UnitTestOutcome.Failed, + UnitTestOutcome.Error, + UnitTestOutcome.Timeout, + UnitTestOutcome.Aborted + }.Contains(TestContext.CurrentTestOutcome); - await _testContextInstance.Tracing.StopAsync(new() - { - Path = failed ? Path.Combine( - Environment.CurrentDirectory, - "playwright-traces", - $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip" - ) : null, - }); - await _testContextInstance.CloseAsync(); - } + await _testContextInstance.Tracing.StopAsync(new() + { + Path = failed ? Path.Combine( + Environment.CurrentDirectory, + "playwright-traces", + $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip" + ) : null, + }); + await _testContextInstance.CloseAsync(); } -} +} \ No newline at end of file diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs index eb0bf1b6..698e38ab 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs @@ -16,79 +16,79 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone +namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone; + +[TestClass] +public class BasicTest : PlaywrightTestBase { - [TestClass] - public class BasicTest : PlaywrightTestBase - { - protected override string? DeviceName => "iPhone 13"; + protected override string? DeviceName => "iPhone 13"; - [TestMethod] - public async Task Application_HasTitle_WhenBrowsingIndex() - { - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - var appBar = new AppBar(TestPage); - await Expect(appBar.HomeButton).ToBeVisibleAsync(); - await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); - } + [TestMethod] + public async Task Application_HasTitle_WhenBrowsingIndex() + { + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + var appBar = new AppBar(TestPage); + await Expect(appBar.HomeButton).ToBeVisibleAsync(); + await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); + } - [TestMethod] - public async Task AboutHeader_HasTitle_WhenBrowsingAbout() - { - var about = new About(TestPage); - await about.GotoAsync(); - await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); - await Expect(about.AboutHeading).ToBeVisibleAsync(); - } + [TestMethod] + public async Task AboutHeader_HasTitle_WhenBrowsingAbout() + { + var about = new About(TestPage); + await about.GotoAsync(); + await Expect(TestPage).ToHaveTitleAsync("AudioCuesheetEditor"); + await Expect(about.AboutHeading).ToBeVisibleAsync(); + } - [TestMethod] - public async Task Audiofile_ShouldBeRenamed_WhenEditingFilename() - { - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.RenameAudiofileAsync(0, "Kalimba test 123.mp3"); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Kalimba test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Kalimba test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); - } + [TestMethod] + public async Task Audiofile_ShouldBeRenamed_WhenEditingFilename() + { + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.RenameAudiofileAsync(0, "Kalimba test 123.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Kalimba test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Kalimba test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); + } - [TestMethod] - public async Task OpenSettings_ShouldDisplaySettings_WhenSelectingSettings() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await bar.OpenSettingsAsync(); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Settings" })).ToBeVisibleAsync(); - } + [TestMethod] + public async Task OpenSettings_ShouldDisplaySettings_WhenSelectingSettings() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await bar.OpenSettingsAsync(); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Settings" })).ToBeVisibleAsync(); + } - [TestMethod] - public async Task ResetCuesheet_ShouldResetAllCuesheetReferences_WhenResettingCuesheetAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await bar.ResetCuesheetAsync(); - await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- group:\n - paragraph: \"--:--:--\"\n - slider \"Playback slider\" [disabled]: \"0\"\n - paragraph: \"--:--:--\"\n- group:\n - button \"Play\" [disabled]\n - group:\n - button \"Jump to previous track\" [disabled]\n - button \"Stop the current playback\" [disabled]\n - button \"Jump to next track\" [disabled]"); - } + [TestMethod] + public async Task ResetCuesheet_ShouldResetAllCuesheetReferences_WhenResettingCuesheetAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await bar.ResetCuesheetAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- group:\n - paragraph: \"--:--:--\"\n - slider \"Playback slider\" [disabled]: \"0\"\n - paragraph: \"--:--:--\"\n- group:\n - button \"Play\" [disabled]\n - group:\n - button \"Jump to previous track\" [disabled]\n - button \"Stop the current playback\" [disabled]\n - button \"Jump to next track\" [disabled]"); + } - [TestMethod] - public async Task ChangeLanguage_ShouldSwitchLanguage_WhenGermanIsSelected() - { - var bar = new AppBar(TestPage); - var exportDialog = new ExportDialog(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await bar.ChangeLanguageAsync("German (Germany)"); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Allgemeine Informationen" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByText("Aufnahmeansicht")).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Dateien" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Wiedergabe" })).ToBeVisibleAsync(); - await bar.OpenExportDialogAsync("Textdatei"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- dialog ""Exportprofile Close"": + [TestMethod] + public async Task ChangeLanguage_ShouldSwitchLanguage_WhenGermanIsSelected() + { + var bar = new AppBar(TestPage); + var exportDialog = new ExportDialog(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await bar.ChangeLanguageAsync("German (Germany)"); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Allgemeine Informationen" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByText("Aufnahmeansicht")).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Dateien" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Heading, new() { Name = "Wiedergabe" })).ToBeVisibleAsync(); + await bar.OpenExportDialogAsync("Textdatei"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- dialog ""Exportprofile Close"": - heading ""Exportprofile"" [level=6] - button ""Close"" - text: ""Export ist derzeit nicht möglich: Künstler hat keinen Wert! Titel hat keinen Wert! Audiodateien hat ungültige Anzahl (0)!"" @@ -141,70 +141,69 @@ await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- d - text: Schema Fuß - group: - button ""Export erzeugen"" [disabled]"); - await exportDialog.OpenSchemeMenuAsync("Schema Kopf"); - await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"CDTextdatei\":\r\n - paragraph: CDTextdatei\r\n - menuitem \"Katalognummer\":\r\n - paragraph: Katalognummer\r\n - menuitem \"Datum\":\r\n - paragraph: Datum\r\n - menuitem \"Datum & Uhrzeit\":\r\n - paragraph: Datum & Uhrzeit\r\n - menuitem \"Uhrzeit\":\r\n - paragraph: Uhrzeit"); - await TestPage.GetByText("CDTextdatei").ClickAsync(); - await exportDialog.OpenSchemeMenuAsync("Schema Titel"); - await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"End\":\r\n - paragraph: End\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); - } + await exportDialog.OpenSchemeMenuAsync("Schema Kopf"); + await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"CDTextdatei\":\r\n - paragraph: CDTextdatei\r\n - menuitem \"Katalognummer\":\r\n - paragraph: Katalognummer\r\n - menuitem \"Datum\":\r\n - paragraph: Datum\r\n - menuitem \"Datum & Uhrzeit\":\r\n - paragraph: Datum & Uhrzeit\r\n - menuitem \"Uhrzeit\":\r\n - paragraph: Uhrzeit"); + await TestPage.GetByText("CDTextdatei").ClickAsync(); + await exportDialog.OpenSchemeMenuAsync("Schema Titel"); + await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"End\":\r\n - paragraph: End\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); + } - [TestMethod] - public async Task TrackTableControls_ShouldBeEnabled_WhenSelectingFirstTrackAsync() - { - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.SelectTracksAsync([1]); - await Expect(TestPage.GetByLabel("Track table controls")).ToMatchAriaSnapshotAsync(@"- group: + [TestMethod] + public async Task TrackTableControls_ShouldBeEnabled_WhenSelectingFirstTrackAsync() + { + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.SelectTracksAsync([1]); + await Expect(TestPage.GetByLabel("Track table controls")).ToMatchAriaSnapshotAsync(@"- group: - button ""Add new track"" - button ""Edit selected tracks"" - button - button ""Delete all tracks"" - button"); - } + } - [TestMethod] - public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenExportDialogAsync("Cuesheet"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenExportDialogAsync("Projectfile"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenExportDialogAsync("Textfile"); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenSettingsAsync(); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await bar.OpenDisplayHotkeysAsync(); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); - await TestPage.Keyboard.PressAsync("Escape"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.OpenRenameAudiofileDialogAsync(0); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await detailView.NewFileNameInput.FillAsync("Test 123"); - await TestPage.Keyboard.PressAsync("Enter"); - await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); - } + [TestMethod] + public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenExportDialogAsync("Cuesheet"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenExportDialogAsync("Projectfile"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenExportDialogAsync("Textfile"); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenSettingsAsync(); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await bar.OpenDisplayHotkeysAsync(); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await TestPage.GetByRole(AriaRole.Dialog).FocusAsync(); + await TestPage.Keyboard.PressAsync("Escape"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.OpenRenameAudiofileDialogAsync(0); + await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); + await detailView.NewFileNameInput.FillAsync("Test 123"); + await TestPage.Keyboard.PressAsync("Enter"); + await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs index 859ae80d..0ce32dc2 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs @@ -16,34 +16,34 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone +namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone; + +[TestClass] +public class ExportTest : PlaywrightTestBase { - [TestClass] - public class ExportTest : PlaywrightTestBase - { - protected override string? DeviceName => "iPhone 13"; + protected override string? DeviceName => "iPhone 13"; - [TestMethod] - public async Task DownloadCuesheet_GeneratesCuesheetFile_WhenCuesheetIsValid() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); - await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); - await bar.OpenExportDialogAsync("Cuesheet"); - var downloadTask = TestPage.WaitForDownloadAsync(); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); - var download = await downloadTask; - using var stream = await download.CreateReadStreamAsync(); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - content = content.Replace("\n", Environment.NewLine); - Assert.AreEqual(@"TITLE ""Cuesheet Title 1"" + [TestMethod] + public async Task DownloadCuesheet_GeneratesCuesheetFile_WhenCuesheetIsValid() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); + await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); + await bar.OpenExportDialogAsync("Cuesheet"); + var downloadTask = TestPage.WaitForDownloadAsync(); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); + var download = await downloadTask; + using var stream = await download.CreateReadStreamAsync(); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(TestContext.CancellationToken); + content = content.Replace("\n", Environment.NewLine); + Assert.AreEqual(@"TITLE ""Cuesheet Title 1"" PERFORMER ""Cuesheet Artist 1"" FILE ""Kalimba.mp3"" MP3 TRACK 01 AUDIO @@ -51,84 +51,84 @@ TRACK 01 AUDIO PERFORMER ""Track Artist 1"" INDEX 01 00:00:00 ", content); - } + } - [TestMethod] - public async Task DownloadProject_GeneratesProjectFile_WhenCuesheetIsValidAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); - await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); - await bar.OpenExportDialogAsync("Projectfile"); - var downloadTask = TestPage.WaitForDownloadAsync(); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download project" }).ClickAsync(); - var download = await downloadTask; - using var stream = await download.CreateReadStreamAsync(); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); - } + [TestMethod] + public async Task DownloadProject_GeneratesProjectFile_WhenCuesheetIsValidAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); + await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Track Artist 1", "Track Title 1"); + await bar.OpenExportDialogAsync("Projectfile"); + var downloadTask = TestPage.WaitForDownloadAsync(); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download project" }).ClickAsync(); + var download = await downloadTask; + using var stream = await download.CreateReadStreamAsync(); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(TestContext.CancellationToken); + Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); + } - [TestMethod] - public async Task DownloadText_GeneratesTextFile_WhenCuesheetIsValidAsync() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); - await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Track Artist 1", "Track Title 1", TimeSpan.Zero, new TimeSpan(0, 0, 10), 1); - await detailView.EditTrackAsync("Track Artist 2", "Track Title 2", new TimeSpan(0, 0, 10), new TimeSpan(0, 0, 20), 2); - await detailView.EditTrackAsync("Track Artist 3", "Track Title 3", new TimeSpan(0, 0, 20), new TimeSpan(0, 0, 30), 3); - await detailView.EditTrackAsync("Track Artist 4", "Track Title 4", new TimeSpan(0, 0, 30), new TimeSpan(0, 0, 40), 4); - await detailView.EditTrackAsync("Track Artist 5", "Track Title 5", new TimeSpan(0, 0, 40), new TimeSpan(0, 0, 50), 5); - await detailView.EditTrackAsync("Track Artist 6", "Track Title 6", new TimeSpan(0, 0, 50), new TimeSpan(0, 1, 0), 6); - await detailView.EditTrackAsync("Track Artist 7", "Track Title 7", new TimeSpan(0, 1, 0), new TimeSpan(0, 1, 10), 7); - await detailView.EditTrackAsync("Track Artist 8", "Track Title 8", new TimeSpan(0, 1, 10), new TimeSpan(0, 1, 20), 8); - await detailView.EditTrackAsync("Track Artist 9", "Track Title 9", new TimeSpan(0, 1, 20), new TimeSpan(0, 1, 30), 9); - await detailView.EditTrackAsync("Track Artist 10", "Track Title 10", new TimeSpan(0, 1, 30), new TimeSpan(0, 1, 40), 10); - await detailView.EditTrackAsync("Track Artist 11", "Track Title 11", new TimeSpan(0, 1, 40), new TimeSpan(0, 1, 50), 11); - await detailView.EditTrackAsync("Track Artist 12", "Track Title 12", new TimeSpan(0, 1, 50), new TimeSpan(0, 2, 0), 12); - await detailView.EditTrackAsync("Track Artist 13", "Track Title 13", new TimeSpan(0, 2, 0), new TimeSpan(0, 2, 10), 13); - await detailView.EditTrackAsync("Track Artist 14", "Track Title 14", new TimeSpan(0, 2, 10), new TimeSpan(0, 2, 20), 14); - await detailView.EditTrackAsync("Track Artist 15", "Track Title 15", new TimeSpan(0, 2, 20), new TimeSpan(0, 2, 30), 15); - await detailView.EditTrackAsync("Track Artist 16", "Track Title 16", new TimeSpan(0, 2, 30), null, 16); - await bar.OpenExportDialogAsync("Textfile"); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Generate export" }).ClickAsync(); - await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Copy to clipboard" })).ToBeVisibleAsync(); - var downloadTask = TestPage.WaitForDownloadAsync(); - await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); - var download = await downloadTask; - using var stream = await download.CreateReadStreamAsync(); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - content = content.Replace("\n", Environment.NewLine); - Assert.AreEqual(@"Cuesheet Artist 1 - Cuesheet Title 1 + [TestMethod] + public async Task DownloadText_GeneratesTextFile_WhenCuesheetIsValidAsync() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.CuesheetArtistInput.FillAsync("Cuesheet Artist 1"); + await detailView.CuesheetTitleInput.FillAsync("Cuesheet Title 1"); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Track Artist 1", "Track Title 1", TimeSpan.Zero, new TimeSpan(0, 0, 10), 1); + await detailView.EditTrackAsync("Track Artist 2", "Track Title 2", new TimeSpan(0, 0, 10), new TimeSpan(0, 0, 20), 2); + await detailView.EditTrackAsync("Track Artist 3", "Track Title 3", new TimeSpan(0, 0, 20), new TimeSpan(0, 0, 30), 3); + await detailView.EditTrackAsync("Track Artist 4", "Track Title 4", new TimeSpan(0, 0, 30), new TimeSpan(0, 0, 40), 4); + await detailView.EditTrackAsync("Track Artist 5", "Track Title 5", new TimeSpan(0, 0, 40), new TimeSpan(0, 0, 50), 5); + await detailView.EditTrackAsync("Track Artist 6", "Track Title 6", new TimeSpan(0, 0, 50), new TimeSpan(0, 1, 0), 6); + await detailView.EditTrackAsync("Track Artist 7", "Track Title 7", new TimeSpan(0, 1, 0), new TimeSpan(0, 1, 10), 7); + await detailView.EditTrackAsync("Track Artist 8", "Track Title 8", new TimeSpan(0, 1, 10), new TimeSpan(0, 1, 20), 8); + await detailView.EditTrackAsync("Track Artist 9", "Track Title 9", new TimeSpan(0, 1, 20), new TimeSpan(0, 1, 30), 9); + await detailView.EditTrackAsync("Track Artist 10", "Track Title 10", new TimeSpan(0, 1, 30), new TimeSpan(0, 1, 40), 10); + await detailView.EditTrackAsync("Track Artist 11", "Track Title 11", new TimeSpan(0, 1, 40), new TimeSpan(0, 1, 50), 11); + await detailView.EditTrackAsync("Track Artist 12", "Track Title 12", new TimeSpan(0, 1, 50), new TimeSpan(0, 2, 0), 12); + await detailView.EditTrackAsync("Track Artist 13", "Track Title 13", new TimeSpan(0, 2, 0), new TimeSpan(0, 2, 10), 13); + await detailView.EditTrackAsync("Track Artist 14", "Track Title 14", new TimeSpan(0, 2, 10), new TimeSpan(0, 2, 20), 14); + await detailView.EditTrackAsync("Track Artist 15", "Track Title 15", new TimeSpan(0, 2, 20), new TimeSpan(0, 2, 30), 15); + await detailView.EditTrackAsync("Track Artist 16", "Track Title 16", new TimeSpan(0, 2, 30), null, 16); + await bar.OpenExportDialogAsync("Textfile"); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Generate export" }).ClickAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Copy to clipboard" })).ToBeVisibleAsync(); + var downloadTask = TestPage.WaitForDownloadAsync(); + await TestPage.GetByRole(AriaRole.Button, new() { Name = "Download" }).ClickAsync(); + var download = await downloadTask; + using var stream = await download.CreateReadStreamAsync(); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(TestContext.CancellationToken); + content = content.Replace("\n", Environment.NewLine); + Assert.AreEqual(@"Cuesheet Artist 1 - Cuesheet Title 1 Track Artist 1 - Track Title 1 00:00:00 Track Artist 2 - Track Title 2 00:00:10 @@ -148,6 +148,5 @@ public async Task DownloadText_GeneratesTextFile_WhenCuesheetIsValidAsync() Track Artist 16 - Track Title 16 00:02:30 ", content); - } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs index 4bfc7b7a..b3355e54 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs @@ -16,22 +16,22 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone +namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone; + +[TestClass] +public class ImportTest : PlaywrightTestBase { - [TestClass] - public class ImportTest : PlaywrightTestBase - { - protected override string? DeviceName => "iPhone 13"; + protected override string? DeviceName => "iPhone 13"; - [TestMethod] - public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Sample_Inputfile.txt"); - await importView.Analyze(); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00 Status""': @@ -248,22 +248,22 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "c:\\AudioFile.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"c:\\\\AudioFile.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); - await importView.GotoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); - } + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "c:\\AudioFile.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"c:\\\\AudioFile.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); + await importView.GotoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); + } - [TestMethod] - public async Task Import_ShouldBeEditable_WhenEditingTrack() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Sample_Inputfile.txt"); - await importView.Analyze(); - await importView.SelectTracksAsync([5]); - await importView.EditTracksModalAsync("Sample Title Edited 5"); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldBeEditable_WhenEditingTrack() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); + await importView.SelectTracksAsync([5]); + await importView.EditTracksModalAsync("Sample Title Edited 5"); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00 Status""': @@ -480,17 +480,17 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - } + } - [TestMethod] - public async Task Import_ShouldImportTracks_WithSpecialTextfile() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Textimport-Bug-#54.txt"); - await importView.SwitchImportProfileAsync("Textfile (just track data)"); - await importView.Analyze(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WithSpecialTextfile() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Textimport-Bug-#54.txt"); + await importView.SwitchImportProfileAsync("Textfile (just track data)"); + await importView.Analyze(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Adriatique Clear Title X. Clear Begin 00:00:00 End 00:05:24 Length 00:05:24""': @@ -1429,20 +1429,20 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Length"": - text: Length - textbox"); - } + } - [TestMethod] - public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile2() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Sample_Inputfile2.txt"); - await importView.ClearSchemeCommonDataAsync(); - await importView.ClearSchemeAudiofilesAsync(); - await importView.Analyze(); - await Expect(importView.CuesheetArtistInput).ToBeEmptyAsync(); - await Expect(importView.CuesheetTitleInput).ToBeEmptyAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile2() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Sample_Inputfile2.txt"); + await importView.ClearSchemeCommonDataAsync(); + await importView.ClearSchemeAudiofilesAsync(); + await importView.Analyze(); + await Expect(importView.CuesheetArtistInput).ToBeEmptyAsync(); + await Expect(importView.CuesheetTitleInput).ToBeEmptyAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00""': @@ -1637,18 +1637,18 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Length 00:30:00"": - text: Length - textbox: 00:30:00"); - } + } - [TestMethod] - public async Task Import_ShouldImportTracks_WithTraktorOutput() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Traktor Export.html"); - await importView.SwitchImportProfileAsync("Traktor history"); - await importView.Analyze(); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WithTraktorOutput() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Traktor Export.html"); + await importView.SwitchImportProfileAsync("Traktor history"); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Nachap Clear Title Glass Clear Begin 00:00:00 End 00:11:56 Length 00:11:56 Status""': @@ -2755,18 +2755,18 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - } + } - [TestMethod] - public async Task Open_ShouldImportProject_WhenUsingProjectfile() - { - var detailView = new DetailView(TestPage); - var appBar = new AppBar(TestPage); - await detailView.GotoAsync(); - await appBar.OpenFileAsync("Sample_Project.ace"); - await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); - await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Open_ShouldImportProject_WhenUsingProjectfile() + { + var detailView = new DetailView(TestPage); + var appBar = new AppBar(TestPage); + await detailView.GotoAsync(); + await appBar.OpenFileAsync("Sample_Project.ace"); + await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); + await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00 Status""': @@ -2983,20 +2983,20 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); - } + await appBar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); + } - [TestMethod] - public async Task Open_ShouldImportCuesheet_WhenUsingCuesheetfile() - { - var detailView = new DetailView(TestPage); - var appBar = new AppBar(TestPage); - await detailView.GotoAsync(); - await appBar.OpenFileAsync("Sample_Cuesheet.cue"); - await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); - await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Open_ShouldImportCuesheet_WhenUsingCuesheetfile() + { + var detailView = new DetailView(TestPage); + var appBar = new AppBar(TestPage); + await detailView.GotoAsync(); + await appBar.OpenFileAsync("Sample_Cuesheet.cue"); + await Expect(detailView.CuesheetArtistInput).ToHaveValueAsync("Sample CD Artist"); + await Expect(detailView.CuesheetTitleInput).ToHaveValueAsync("Sample CD Title"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00 Status""': @@ -3213,20 +3213,20 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); - } + await appBar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); + } - [TestMethod] - public async Task Import_ShouldImportTracks_WhenUsingText() - { - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); - await importView.ImportTextAsync(text); - await importView.Analyze(); - await importView.CompleteImportAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingText() + { + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); + await importView.ImportTextAsync(text); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00 Status""': @@ -3443,6 +3443,5 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/RecordTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/RecordTest.cs index a28c370f..62ec6707 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/RecordTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/RecordTest.cs @@ -16,31 +16,30 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone +namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone; + +[TestClass] +public class RecordTest : PlaywrightTestBase { - [TestClass] - public class RecordTest : PlaywrightTestBase + protected override string? DeviceName => "iPhone 13"; + [TestMethod] + public async Task Record_ShouldRecordTracks_WhenTracksAdded() { - protected override string? DeviceName => "iPhone 13"; - [TestMethod] - public async Task Record_ShouldRecordTracks_WhenTracksAdded() - { - var recordView = new RecordView(TestPage); - var viewModes = new ViewModes(TestPage, DeviceName != null); - var detailView = new DetailView(TestPage); - await recordView.GotoAsync(); - await recordView.StartRecordingAsync(); - await recordView.AddRecordingTrackAsync("Test Track 1 Artist", "Test Track 1 Title"); - await recordView.AddRecordingTrackAsync("Test Track 2 Artist", "Test Track 2 Title"); - await recordView.StopRecordingAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Artist Clear" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Title Clear" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Artist Clear" })).ToBeVisibleAsync(); - await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Title Clear" })).ToBeVisibleAsync(); - await viewModes.SwitchView("Detail view"); - await detailView.SelectTracksAsync([1]); - await detailView.EditSelectedTracksModalAsync(); - await Expect(TestPage.GetByRole(AriaRole.Switch, new() { Name = "Link to previous track" })).ToBeCheckedAsync(); - } + var recordView = new RecordView(TestPage); + var viewModes = new ViewModes(TestPage, DeviceName != null); + var detailView = new DetailView(TestPage); + await recordView.GotoAsync(); + await recordView.StartRecordingAsync(); + await recordView.AddRecordingTrackAsync("Test Track 1 Artist", "Test Track 1 Title"); + await recordView.AddRecordingTrackAsync("Test Track 2 Artist", "Test Track 2 Title"); + await recordView.StopRecordingAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Artist Clear" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Title Clear" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Artist Clear" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Title Clear" })).ToBeVisibleAsync(); + await viewModes.SwitchView("Detail view"); + await detailView.SelectTracksAsync([1]); + await detailView.EditSelectedTracksModalAsync(); + await Expect(TestPage.GetByRole(AriaRole.Switch, new() { Name = "Link to previous track" })).ToBeCheckedAsync(); } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTest.cs index 78705658..a32d63cb 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTest.cs @@ -16,30 +16,30 @@ using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; -namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone +namespace AudioCuesheetEditor.End2EndTests.Tests.Smartphone; + +[TestClass] +public class TracingTest : PlaywrightTestBase { - [TestClass] - public class TracingTest : PlaywrightTestBase - { - protected override string? DeviceName => "iPhone 13"; + protected override string? DeviceName => "iPhone 13"; - [TestMethod] - public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoAndRedoAreUsed() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.AddTrackAsync(0); - await detailView.EditTrackAsync("Test Artist 1"); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await detailView.EditTrackAsync(title: "Test Title 1"); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await bar.UndoAsync(); - await bar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoAndRedoAreUsed() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.AddTrackAsync(0); + await detailView.EditTrackAsync("Test Artist 1"); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await detailView.EditTrackAsync(title: "Test Title 1"); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await bar.UndoAsync(); + await bar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Title Begin 00:00:00 End Length Status""': @@ -65,10 +65,10 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox - cell ""Status"""); - await Expect(bar.RedoButton).ToBeEnabledAsync(); - await bar.RedoAsync(); - await bar.RedoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await Expect(bar.RedoButton).ToBeEnabledAsync(); + await bar.RedoAsync(); + await bar.RedoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Test Artist 1 Clear Title Test Title 1 Clear Begin 00:00:00 End Length Status""': @@ -96,8 +96,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox - cell ""Status"""); - await detailView.EditTrackAsync("Mozart", "Eine kleine Nachtmusik"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await detailView.EditTrackAsync("Mozart", "Eine kleine Nachtmusik"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Mozart Clear Title Eine kleine Nachtmusik Clear Begin 00:00:00 End Length Status""': @@ -125,8 +125,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox - cell ""Status"""); - await bar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Mozart Clear Title Test Title 1 Clear Begin 00:00:00 End Length Status""': @@ -154,19 +154,19 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox - cell ""Status"""); - } + } - [TestMethod] - public async Task UndoRedo_ShouldRestoreTrackState_WhenModalEdit() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.AddTrackAsync(0); - await detailView.SelectTracksAsync([1]); - await detailView.EditTracksModalAsync("Test Track Artist 1", "Test Track Title 1", "00:02:23", ["channel audio (4CH)", "Serial copy management system"]); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreTrackState_WhenModalEdit() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.AddTrackAsync(0); + await detailView.SelectTracksAsync([1]); + await detailView.EditTracksModalAsync("Test Track Artist 1", "Test Track Title 1", "00:02:23", ["channel audio (4CH)", "Serial copy management system"]); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Test Track Artist 1 Clear Title Test Track Title 1 Clear Begin 00:00:00 End 00:02:23 Length 00:02:23 Status"" [selected]': @@ -194,8 +194,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox: 00:02:23 - cell ""Status"""); - await bar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.UndoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Title Begin 00:00:00 End Length Status"" [selected]': @@ -221,8 +221,8 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox - cell ""Status"""); - await bar.RedoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.RedoAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Test Track Artist 1 Clear Title Test Track Title 1 Clear Begin 00:00:00 End 00:02:23 Length 00:02:23 Status"" [selected]': @@ -250,32 +250,32 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox: 00:02:23 - cell ""Status"""); - } + } - [TestMethod] - public async Task UndoRedo_ShouldRestoreCuesheet_WhenUsingImport() - { - var bar = new AppBar(TestPage); - var importView = new ImportView(TestPage, DeviceName != null); - await importView.GotoAsync(); - await importView.ImportFileAsync("Textimport with Cuesheetdata.txt"); - await importView.SetSchemeCommonDataAsync("Artist - Title - "); - await importView.SelectSchemeCommonDataPlaceholderAsync("Cataloguenumber"); - await importView.ClearSchemeAudiofilesAsync(); - await importView.Analyze(); - await Expect(bar.UndoButton).ToBeDisabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await importView.CompleteImportAsync(); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await bar.UndoAsync(); - await Expect(bar.UndoButton).ToBeDisabledAsync(); - await Expect(bar.RedoButton).ToBeEnabledAsync(); - await bar.RedoAsync(); - await Expect(importView.CuesheetArtistInput).ToHaveValueAsync("DJFreezeT"); - await Expect(importView.CuesheetTitleInput).ToHaveValueAsync("Rabbit Hole Mix"); - await Expect(importView.CatalogueNumberInput).ToHaveValueAsync("01 23456 78912 3"); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreCuesheet_WhenUsingImport() + { + var bar = new AppBar(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); + await importView.GotoAsync(); + await importView.ImportFileAsync("Textimport with Cuesheetdata.txt"); + await importView.SetSchemeCommonDataAsync("Artist - Title - "); + await importView.SelectSchemeCommonDataPlaceholderAsync("Cataloguenumber"); + await importView.ClearSchemeAudiofilesAsync(); + await importView.Analyze(); + await Expect(bar.UndoButton).ToBeDisabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await importView.CompleteImportAsync(); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await bar.UndoAsync(); + await Expect(bar.UndoButton).ToBeDisabledAsync(); + await Expect(bar.RedoButton).ToBeEnabledAsync(); + await bar.RedoAsync(); + await Expect(importView.CuesheetArtistInput).ToHaveValueAsync("DJFreezeT"); + await Expect(importView.CuesheetTitleInput).ToHaveValueAsync("Rabbit Hole Mix"); + await Expect(importView.CatalogueNumberInput).ToHaveValueAsync("01 23456 78912 3"); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Adriatique Clear Title X. Clear Begin 00:00:00 End 00:05:24.2500000 Length 00:05:24.2500000 Status""': @@ -1329,21 +1329,21 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - } + } - [TestMethod] - public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoWithAudiofile() - { - var bar = new AppBar(TestPage); - var detailView = new DetailView(TestPage); - await detailView.GotoAsync(); - await detailView.AddAudiofileAsync(); - await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); - await detailView.AddTrackAsync(0); - await detailView.AddTrackAsync(0); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeDisabledAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + [TestMethod] + public async Task UndoRedo_ShouldRestoreTrackState_WhenUndoWithAudiofile() + { + var bar = new AppBar(TestPage); + var detailView = new DetailView(TestPage); + await detailView.GotoAsync(); + await detailView.AddAudiofileAsync(); + await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); + await detailView.AddTrackAsync(0); + await detailView.AddTrackAsync(0); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeDisabledAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Title Begin 00:00:00 End Length Status""': @@ -1394,10 +1394,10 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - await bar.UndoAsync(); - await Expect(bar.UndoButton).ToBeEnabledAsync(); - await Expect(bar.RedoButton).ToBeEnabledAsync(); - await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + await bar.UndoAsync(); + await Expect(bar.UndoButton).ToBeEnabledAsync(); + await Expect(bar.RedoButton).ToBeEnabledAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup - rowgroup: - 'row ""Select row # 1 Artist Title Begin 00:00:00 End 00:05:48.0608330 Length 00:05:48.0608330 Status""': @@ -1423,6 +1423,5 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Length - textbox: 00:05:48.0608330 - cell ""Status"""); - } } } diff --git a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs index 3feb39f8..477976a2 100644 --- a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -20,83 +20,82 @@ using System; using System.Linq; -namespace AudioCuesheetEditor.Tests.Model.AudioCuesheet +namespace AudioCuesheetEditor.Tests.Model.AudioCuesheet; + +[TestClass] +public class AudiofileTests { - [TestClass] - public class AudiofileTests + [TestMethod] + public void Validate_FilenameNull_ReturnsValidationStatusError() { - [TestMethod] - public void Validate_FilenameNull_ReturnsValidationStatusError() - { - // Arrange - var audiofile = new Audiofile(); - // Act - var validationResult = audiofile.Validate(nameof(Audiofile.Name)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - } + // Arrange + var audiofile = new Audiofile(); + // Act + var validationResult = audiofile.Validate(nameof(Audiofile.Name)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + } - [TestMethod] - public void Validate_TracksEmpty_ReturnsValidationStatusError() - { - // Arrange - var audiofile = new Audiofile(); - // Act - var validationResult = audiofile.Validate(nameof(Audiofile.Tracks)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} has invalid count ({1})!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Audiofile.Tracks), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - } + [TestMethod] + public void Validate_TracksEmpty_ReturnsValidationStatusError() + { + // Arrange + var audiofile = new Audiofile(); + // Act + var validationResult = audiofile.Validate(nameof(Audiofile.Tracks)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} has invalid count ({1})!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Audiofile.Tracks), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + } - [TestMethod] - public void Validate_TracksWithSamePosition_ReturnsValidationStatusError() + [TestMethod] + public void Validate_TracksWithSamePosition_ReturnsValidationStatusError() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Position = 1 - }; - var track2 = new Track() - { - Position = 1 - }; - var audiofile = new Audiofile() - { - Tracks = [track1, track2] - }; - // Act - var validationResult = audiofile.Validate(nameof(Audiofile.Tracks)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", validationResult.ValidationMessages.First().Message); - } + Position = 1 + }; + var track2 = new Track() + { + Position = 1 + }; + var audiofile = new Audiofile() + { + Tracks = [track1, track2] + }; + // Act + var validationResult = audiofile.Validate(nameof(Audiofile.Tracks)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", validationResult.ValidationMessages.First().Message); + } - [TestMethod] - public void Validate_TracksOverlapping_ReturnsValidationStatusError() + [TestMethod] + public void Validate_TracksOverlapping_ReturnsValidationStatusError() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 45) + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 42), + End = new TimeSpan(0, 6, 32) + }; + var audiofile = new Audiofile() { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 45) - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 42), - End = new TimeSpan(0, 6, 32) - }; - var audiofile = new Audiofile() - { - Tracks = [track1, track2] - }; - // Act - var validationResult = audiofile.Validate(nameof(Audiofile.Tracks)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", validationResult.ValidationMessages.First().Message); - } + Tracks = [track1, track2] + }; + // Act + var validationResult = audiofile.Validate(nameof(Audiofile.Tracks)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", validationResult.ValidationMessages.First().Message); } } diff --git a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs index 2268757c..195e6305 100644 --- a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs +++ b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/CuesheetTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,75 +18,74 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; -namespace AudioCuesheetEditor.Tests.Model.AudioCuesheet +namespace AudioCuesheetEditor.Tests.Model.AudioCuesheet; + +[TestClass()] +public class CuesheetTests { - [TestClass()] - public class CuesheetTests + [TestMethod] + public void Validate_AudiofilesEmpty_ReturnsValidationStatusError() { - [TestMethod] - public void Validate_AudiofilesEmpty_ReturnsValidationStatusError() - { - // Arrange - var cuesheet = new Cuesheet(); - // Act - var validationResult = cuesheet.Validate(nameof(Cuesheet.Audiofiles)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - } + // Arrange + var cuesheet = new Cuesheet(); + // Act + var validationResult = cuesheet.Validate(nameof(Cuesheet.Audiofiles)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + } - [TestMethod] - public void Validate_ArtistNull_ReturnsValidationStatusError() - { - // Arrange - var cuesheet = new Cuesheet(); - // Act - var validationResult = cuesheet.Validate(nameof(Cuesheet.Artist)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - } + [TestMethod] + public void Validate_ArtistNull_ReturnsValidationStatusError() + { + // Arrange + var cuesheet = new Cuesheet(); + // Act + var validationResult = cuesheet.Validate(nameof(Cuesheet.Artist)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + } - [TestMethod] - public void Validate_TitleNull_ReturnsValidationStatusError() - { - // Arrange - var cuesheet = new Cuesheet(); - // Act - var validationResult = cuesheet.Validate(nameof(Cuesheet.Title)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - } + [TestMethod] + public void Validate_TitleNull_ReturnsValidationStatusError() + { + // Arrange + var cuesheet = new Cuesheet(); + // Act + var validationResult = cuesheet.Validate(nameof(Cuesheet.Title)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + } - [TestMethod] - public void Validate_CataloguenumberWithLetters_ReturnsValidationStatusError() + [TestMethod] + public void Validate_CataloguenumberWithLetters_ReturnsValidationStatusError() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Cataloguenumber = nameof(Validate_CataloguenumberWithLetters_ReturnsValidationStatusError) - }; - // Act - var validationResult = cuesheet.Validate(nameof(Cuesheet.Cataloguenumber)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} must only contain numbers!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Cuesheet.Cataloguenumber), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - } + Cataloguenumber = nameof(Validate_CataloguenumberWithLetters_ReturnsValidationStatusError) + }; + // Act + var validationResult = cuesheet.Validate(nameof(Cuesheet.Cataloguenumber)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} must only contain numbers!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Cuesheet.Cataloguenumber), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + } - [TestMethod] - public void Validate_CataloguenumberLengthUnequal13_ReturnsValidationStatusError() + [TestMethod] + public void Validate_CataloguenumberLengthUnequal13_ReturnsValidationStatusError() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Cataloguenumber = "012345678" - }; - // Act - var validationResult = cuesheet.Validate(nameof(Cuesheet.Cataloguenumber)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} has an invalid length. Allowed length is {1}!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Cuesheet.Cataloguenumber), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(13, validationResult.ValidationMessages.First().Parameter?.Last()); - } + Cataloguenumber = "012345678" + }; + // Act + var validationResult = cuesheet.Validate(nameof(Cuesheet.Cataloguenumber)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} has an invalid length. Allowed length is {1}!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Cuesheet.Cataloguenumber), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(13, validationResult.ValidationMessages.First().Parameter?.Last()); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs index 46982836..410b6976 100644 --- a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs +++ b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,85 +18,84 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -namespace AudioCuesheetEditor.Tests.Model.AudioCuesheet +namespace AudioCuesheetEditor.Tests.Model.AudioCuesheet; + +[TestClass()] +public class TrackTests { - [TestClass()] - public class TrackTests + [TestMethod()] + public void Validate_PositionNull_ReturnsValidationStatusError() { - [TestMethod()] - public void Validate_PositionNull_ReturnsValidationStatusError() - { - // Arrange - var track = new Track(); - // Act - var endValidationResult = track.Validate(nameof(Track.Position)); - // Assert - Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); - } + // Arrange + var track = new Track(); + // Act + var endValidationResult = track.Validate(nameof(Track.Position)); + // Assert + Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); + } - [TestMethod()] - public void Validate_Position0_ReturnsValidationStatusError() + [TestMethod()] + public void Validate_Position0_ReturnsValidationStatusError() + { + // Arrange + var track = new Track() { - // Arrange - var track = new Track() - { - Position = 0 - }; - // Act - var endValidationResult = track.Validate(nameof(Track.Position)); - // Assert - Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); - } + Position = 0 + }; + // Act + var endValidationResult = track.Validate(nameof(Track.Position)); + // Assert + Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); + } - [TestMethod()] - public void Validate_PositionOvverlapping_ReturnsValidationStatusError() + [TestMethod()] + public void Validate_PositionOvverlapping_ReturnsValidationStatusError() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Position = 1 - }; - var track = new Track() - { - Position = 1 - }; - var cuesheet = new Cuesheet(); - track1.Cuesheet = cuesheet; - track.Cuesheet = cuesheet; - // Act - var endValidationResult = track.Validate(nameof(Track.Position)); - // Assert - Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); - } + Position = 1 + }; + var track = new Track() + { + Position = 1 + }; + var cuesheet = new Cuesheet(); + track1.Cuesheet = cuesheet; + track.Cuesheet = cuesheet; + // Act + var endValidationResult = track.Validate(nameof(Track.Position)); + // Assert + Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); + } - [TestMethod()] - public void Validate_InvalidEnd_ReturnsValidationStatusError() + [TestMethod()] + public void Validate_InvalidEnd_ReturnsValidationStatusError() + { + // Arrange + var track = new Track { - // Arrange - var track = new Track - { - Begin = new TimeSpan(0, 2, 32), - End = new TimeSpan(0, 1, 15) - }; - // Act - var endValidationResult = track.Validate(nameof(Track.End)); - // Assert - Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); - } + Begin = new TimeSpan(0, 2, 32), + End = new TimeSpan(0, 1, 15) + }; + // Act + var endValidationResult = track.Validate(nameof(Track.End)); + // Assert + Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); + } - [TestMethod()] - public void Validate_InvalidBegin_ReturnsValidationStatusError() + [TestMethod()] + public void Validate_InvalidBegin_ReturnsValidationStatusError() + { + // Arrange + var track = new Track { - // Arrange - var track = new Track - { - Begin = new TimeSpan(0, 4, 53), - End = new TimeSpan(0, 3, 15) - }; - // Act - var endValidationResult = track.Validate(nameof(Track.Begin)); - // Assert - Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); - } + Begin = new TimeSpan(0, 4, 53), + End = new TimeSpan(0, 3, 15) + }; + // Act + var endValidationResult = track.Validate(nameof(Track.Begin)); + // Assert + Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs index 809dab4c..1585fe73 100644 --- a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,64 +17,63 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; -namespace AudioCuesheetEditor.Tests.Model.Entity +namespace AudioCuesheetEditor.Tests.Model.Entity; + +public class ValidateableTestClass : Validateable { - public class ValidateableTestClass : Validateable - { - private string? testProperty; - private int? testProperty2; + string? testProperty; + int? testProperty2; - public string? TestProperty + public string? TestProperty + { + get => testProperty; + set { - get => testProperty; - set - { - testProperty = value; - OnValidateablePropertyChanged(); - } + testProperty = value; + OnValidateablePropertyChanged(); } - public int? TestProperty2 + } + public int? TestProperty2 + { + get => testProperty2; + set { - get => testProperty2; - set - { - testProperty2 = value; - OnValidateablePropertyChanged(); - } + testProperty2 = value; + OnValidateablePropertyChanged(); } - public override ValidationResult Validate(string property) + } + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List? validationMessages = null; - switch (property) - { - case nameof(TestProperty): - validationStatus = ValidationStatus.Success; - if (string.IsNullOrEmpty(TestProperty)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(TestProperty))); - } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + case nameof(TestProperty): + validationStatus = ValidationStatus.Success; + if (string.IsNullOrEmpty(TestProperty)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(TestProperty))); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); } - [TestClass()] - public class ValidateableTests +} +[TestClass()] +public class ValidateableTests +{ + [TestMethod()] + public void ValidateTest() { - [TestMethod()] - public void ValidateTest() + var testObject = new ValidateableTestClass { - var testObject = new ValidateableTestClass - { - TestProperty = string.Empty - }; - Assert.AreEqual(ValidationStatus.Error, testObject.Validate().Status); - Assert.IsNotNull(testObject.Validate().ValidationMessages); - Assert.AreEqual(1, testObject.Validate().ValidationMessages?.Count); - testObject.TestProperty = "Test"; - Assert.AreEqual(ValidationStatus.Success, testObject.Validate().Status); - } + TestProperty = string.Empty + }; + Assert.AreEqual(ValidationStatus.Error, testObject.Validate().Status); + Assert.IsNotNull(testObject.Validate().ValidationMessages); + Assert.AreEqual(1, testObject.Validate().ValidationMessages?.Count); + testObject.TestProperty = "Test"; + Assert.AreEqual(ValidationStatus.Success, testObject.Validate().Status); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/Entity/ValidationResultTests.cs b/AudioCuesheetEditor.Tests/Model/Entity/ValidationResultTests.cs index 1b30435f..624b3d7f 100644 --- a/AudioCuesheetEditor.Tests/Model/Entity/ValidationResultTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Entity/ValidationResultTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -19,100 +19,99 @@ using System.Collections.Generic; using System.Linq; -namespace AudioCuesheetEditor.Tests.Model.Entity +namespace AudioCuesheetEditor.Tests.Model.Entity; + +[TestClass()] +public class ValidationResultTests { - [TestClass()] - public class ValidationResultTests + [TestMethod] + public void Create_NoValidation_ReturnsExpectedResult() { - [TestMethod] - public void Create_NoValidation_ReturnsExpectedResult() - { - // Arrange & Act - var validationResult = ValidationResult.Create(ValidationStatus.NoValidation); + // Arrange & Act + var validationResult = ValidationResult.Create(ValidationStatus.NoValidation); - // Assert - Assert.AreEqual(ValidationStatus.NoValidation, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } + // Assert + Assert.AreEqual(ValidationStatus.NoValidation, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); + } - [TestMethod] - public void Create_Success_ReturnsExpectedResult() - { - // Arrange & Act - var validationResult = ValidationResult.Create(ValidationStatus.Success); + [TestMethod] + public void Create_Success_ReturnsExpectedResult() + { + // Arrange & Act + var validationResult = ValidationResult.Create(ValidationStatus.Success); - // Assert - Assert.AreEqual(ValidationStatus.Success, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } + // Assert + Assert.AreEqual(ValidationStatus.Success, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); + } - [TestMethod] - public void Create_Error_ReturnsExpectedResult() - { - // Arrange & Act - var validationResult = ValidationResult.Create(ValidationStatus.Error); + [TestMethod] + public void Create_Error_ReturnsExpectedResult() + { + // Arrange & Act + var validationResult = ValidationResult.Create(ValidationStatus.Error); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); + } - [TestMethod] - public void Create_SuccessWithMessages_ReturnsErrorStatus() - { - // Arrange - var validationMessages = new List { new("Testmessage!") }; + [TestMethod] + public void Create_SuccessWithMessages_ReturnsErrorStatus() + { + // Arrange + var validationMessages = new List { new("Testmessage!") }; - // Act - var validationResult = ValidationResult.Create(ValidationStatus.Success, validationMessages); + // Act + var validationResult = ValidationResult.Create(ValidationStatus.Success, validationMessages); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - CollectionAssert.AreEqual(validationMessages.ToList(), validationResult.ValidationMessages.ToList()); - } + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + CollectionAssert.AreEqual(validationMessages.ToList(), validationResult.ValidationMessages.ToList()); + } - [TestMethod] - public void Create_NoValidationWithMessages_ReturnsErrorStatus() - { - // Arrange - var validationMessages = new List { new("Testmessage!") }; + [TestMethod] + public void Create_NoValidationWithMessages_ReturnsErrorStatus() + { + // Arrange + var validationMessages = new List { new("Testmessage!") }; - // Act - var validationResult = ValidationResult.Create(ValidationStatus.NoValidation, validationMessages); + // Act + var validationResult = ValidationResult.Create(ValidationStatus.NoValidation, validationMessages); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - CollectionAssert.AreEqual(validationMessages.ToList(), validationResult.ValidationMessages.ToList()); - } + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + CollectionAssert.AreEqual(validationMessages.ToList(), validationResult.ValidationMessages.ToList()); + } - [TestMethod] - public void Default_Status_IsNoValidation() - { - // Arrange & Act - var validationResult = new ValidationResult(); + [TestMethod] + public void Default_Status_IsNoValidation() + { + // Arrange & Act + var validationResult = new ValidationResult(); - // Assert - Assert.AreEqual(ValidationStatus.NoValidation, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } + // Assert + Assert.AreEqual(ValidationStatus.NoValidation, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); + } - [TestMethod] - public void Setting_ValidationMessages_SetsStatusToError() + [TestMethod] + public void Setting_ValidationMessages_SetsStatusToError() + { + // Arrange + var validationResult = new ValidationResult(); + var messages = new List { - // Arrange - var validationResult = new ValidationResult(); - var messages = new List - { - new("Unit Test error1"), - new("Unit Test error2") - }; - - // Act - validationResult.ValidationMessages = messages; - - // Assert - CollectionAssert.AreEqual(messages.ToList(), validationResult.ValidationMessages.ToList()); - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - } + new("Unit Test error1"), + new("Unit Test error2") + }; + + // Act + validationResult.ValidationMessages = messages; + + // Assert + CollectionAssert.AreEqual(messages.ToList(), validationResult.ValidationMessages.ToList()); + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/IO/Export/ExportprofileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/Export/ExportprofileTests.cs index 14e1dc34..853c4c2a 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/Export/ExportprofileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/Export/ExportprofileTests.cs @@ -18,222 +18,221 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; -namespace AudioCuesheetEditor.Tests.Model.IO.Export +namespace AudioCuesheetEditor.Tests.Model.IO.Export; + +[TestClass()] +public class ExportprofileTests { - [TestClass()] - public class ExportprofileTests + [TestMethod()] + public void Validate_EmptyFilename_ReturnsError() { - [TestMethod()] - public void Validate_EmptyFilename_ReturnsError() + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - Filename = string.Empty - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.Filename)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} has no value!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.Filename), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - } - - [TestMethod()] - public void Validate_EmptyName_ReturnsError() + Filename = string.Empty + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.Filename)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} has no value!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.Filename), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + } + + [TestMethod()] + public void Validate_EmptyName_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - Name = string.Empty - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.Name)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} has no value!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.Name), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - } - - [TestMethod()] - public void Validate_SchemeHeadWithTrackPlaceholder_ReturnsError() + Name = string.Empty + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.Name)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} has no value!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.Name), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + } + + [TestMethod()] + public void Validate_SchemeHeadWithTrackPlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeHead = Exportprofile.SchemeTrackTitle - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeHead)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeHead), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeTrackTitle, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeHeadWithAudiofilePlaceholder_ReturnsError() + SchemeHead = Exportprofile.SchemeTrackTitle + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeHead)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeHead), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeTrackTitle, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeHeadWithAudiofilePlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeHead = Exportprofile.SchemeAudiofileName - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeHead)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeHead), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeAudiofileName, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeTrackWithCuesheetPlaceholder_ReturnsError() + SchemeHead = Exportprofile.SchemeAudiofileName + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeHead)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeHead), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeAudiofileName, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeTrackWithCuesheetPlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeTracks = Exportprofile.SchemeCuesheetArtist - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeTracks)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeTracks), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeCuesheetArtist, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeTrackWithAudiofilePlaceholder_ReturnsError() + SchemeTracks = Exportprofile.SchemeCuesheetArtist + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeTracks)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeTracks), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeCuesheetArtist, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeTrackWithAudiofilePlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeTracks = Exportprofile.SchemeAudiofileName - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeTracks)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeTracks), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeAudiofileName, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeFooterWithTrackPlaceholder_ReturnsError() + SchemeTracks = Exportprofile.SchemeAudiofileName + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeTracks)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeTracks), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeAudiofileName, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeFooterWithTrackPlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeFooter = Exportprofile.SchemeTrackBegin - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeFooter)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeFooter), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeTrackBegin, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeFooterWithAudiofilePlaceholder_ReturnsError() + SchemeFooter = Exportprofile.SchemeTrackBegin + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeFooter)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeFooter), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeTrackBegin, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeFooterWithAudiofilePlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeFooter = Exportprofile.SchemeAudiofileName - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeFooter)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeFooter), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeAudiofileName, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeHeadCorrectPlaceholder_ReturnsSuccess() + SchemeFooter = Exportprofile.SchemeAudiofileName + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeFooter)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeFooter), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeAudiofileName, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeHeadCorrectPlaceholder_ReturnsSuccess() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeHead = Exportprofile.SchemeCuesheetTitle - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeHead)); - // Assert - Assert.AreEqual(ValidationStatus.Success, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } - - [TestMethod()] - public void Validate_SchemeTrackCorrectPlaceholder_ReturnsSuccess() + SchemeHead = Exportprofile.SchemeCuesheetTitle + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeHead)); + // Assert + Assert.AreEqual(ValidationStatus.Success, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); + } + + [TestMethod()] + public void Validate_SchemeTrackCorrectPlaceholder_ReturnsSuccess() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeTracks = Exportprofile.SchemeTrackPreGap - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeTracks)); - // Assert - Assert.AreEqual(ValidationStatus.Success, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } - - [TestMethod()] - public void Validate_SchemeAudiofilesWithTrackPlaceholder_ReturnsError() + SchemeTracks = Exportprofile.SchemeTrackPreGap + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeTracks)); + // Assert + Assert.AreEqual(ValidationStatus.Success, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); + } + + [TestMethod()] + public void Validate_SchemeAudiofilesWithTrackPlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeAudiofiles = Exportprofile.SchemeTrackArtist - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeAudiofiles)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeAudiofiles), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeTrackArtist, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeAudiofilesWithCuesheetPlaceholder_ReturnsError() + SchemeAudiofiles = Exportprofile.SchemeTrackArtist + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeAudiofiles)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeAudiofiles), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeTrackArtist, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeAudiofilesWithCuesheetPlaceholder_ReturnsError() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeAudiofiles = Exportprofile.SchemeCuesheetCatalogueNumber - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeAudiofiles)); - // Assert - Assert.AreEqual(ValidationStatus.Error, validationResult.Status); - Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Exportprofile.SchemeAudiofiles), validationResult.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual(Exportprofile.SchemeCuesheetCatalogueNumber, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); - } - - [TestMethod()] - public void Validate_SchemeAudiofilesCorrectPlaceholder_ReturnsNoValidation() + SchemeAudiofiles = Exportprofile.SchemeCuesheetCatalogueNumber + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeAudiofiles)); + // Assert + Assert.AreEqual(ValidationStatus.Error, validationResult.Status); + Assert.AreEqual("{0} contains placeholder '{1}' that can not be resolved!", validationResult.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Exportprofile.SchemeAudiofiles), validationResult.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual(Exportprofile.SchemeCuesheetCatalogueNumber, validationResult.ValidationMessages.First().Parameter?.ElementAt(1).ToString()); + } + + [TestMethod()] + public void Validate_SchemeAudiofilesCorrectPlaceholder_ReturnsNoValidation() + { + // Arrange + var exportprofile = new Exportprofile { - // Arrange - var exportprofile = new Exportprofile - { - SchemeAudiofiles = Exportprofile.SchemeAudiofileName - }; - // Act - var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeAudiofiles)); - // Assert - Assert.AreEqual(ValidationStatus.Success, validationResult.Status); - Assert.IsEmpty(validationResult.ValidationMessages); - } + SchemeAudiofiles = Exportprofile.SchemeAudiofileName + }; + // Act + var validationResult = exportprofile.Validate(nameof(Exportprofile.SchemeAudiofiles)); + // Assert + Assert.AreEqual(ValidationStatus.Success, validationResult.Status); + Assert.IsEmpty(validationResult.ValidationMessages); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs index e91fe976..ca4c99a1 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/Import/ImportprofileTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -19,29 +19,28 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; -namespace AudioCuesheetEditor.Tests.Model.IO.Import +namespace AudioCuesheetEditor.Tests.Model.IO.Import; + +[TestClass()] +public class ImportprofileTests { - [TestClass()] - public class ImportprofileTests + [TestMethod()] + public void Validate_WithoutPlaceholder_ReturnsInvalid() { - [TestMethod()] - public void Validate_WithoutPlaceholder_ReturnsInvalid() + // Arrange + var importprofile = new Importprofile() { - // Arrange - var importprofile = new Importprofile() - { - SchemeCuesheet = "Test 1", - SchemeTracks = "Here comes next track" - }; - // Act - var result = importprofile.Validate(); - // Assert - Assert.AreEqual(ValidationStatus.Error, result.Status); - Assert.HasCount(2, result.ValidationMessages); - Assert.AreEqual("{0} contains no placeholder!", result.ValidationMessages.First().Message); - Assert.AreEqual(nameof(Importprofile.SchemeCuesheet), result.ValidationMessages.First().Parameter?.First().ToString()); - Assert.AreEqual("{0} contains no placeholder!", result.ValidationMessages.Last().Message); - Assert.AreEqual(nameof(Importprofile.SchemeTracks), result.ValidationMessages.Last().Parameter?.First().ToString()); - } + SchemeCuesheet = "Test 1", + SchemeTracks = "Here comes next track" + }; + // Act + var result = importprofile.Validate(); + // Assert + Assert.AreEqual(ValidationStatus.Error, result.Status); + Assert.HasCount(2, result.ValidationMessages); + Assert.AreEqual("{0} contains no placeholder!", result.ValidationMessages.First().Message); + Assert.AreEqual(nameof(Importprofile.SchemeCuesheet), result.ValidationMessages.First().Parameter?.First().ToString()); + Assert.AreEqual("{0} contains no placeholder!", result.ValidationMessages.Last().Message); + Assert.AreEqual(nameof(Importprofile.SchemeTracks), result.ValidationMessages.Last().Parameter?.First().ToString()); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs index 807be58d..92742382 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs @@ -22,90 +22,89 @@ using System.Linq; using System.Text.Json; -namespace AudioCuesheetEditor.Tests.Model.IO +namespace AudioCuesheetEditor.Tests.Model.IO; + +[TestClass()] +public class ProjectfileTests { - [TestClass()] - public class ProjectfileTests + [TestMethod()] + public void GenerateFile_WithoutSections_GeneratesOneFile() { - [TestMethod()] - public void GenerateFile_WithoutSections_GeneratesOneFile() + // Arrange + var cuesheet = new Cuesheet + { + Artist = "CuesheetArtist", + Title = "CuesheetTitle", + Audiofiles = [ + new () { Name = "AudioFile.mp3" }, + new () { Name = "Other audiofile.wav" } + ], + CDTextfile = new CDTextfile("CDTextfile.cdt"), + Cataloguenumber = "A123" + }; + var begin = TimeSpan.Zero; + var tracks = new List(); + for (ushort i = 1; i <= 10; i++) { - // Arrange - var cuesheet = new Cuesheet + var track = new Track { - Artist = "CuesheetArtist", - Title = "CuesheetTitle", - Audiofiles = [ - new () { Name = "AudioFile.mp3" }, - new () { Name = "Other audiofile.wav" } - ], - CDTextfile = new CDTextfile("CDTextfile.cdt"), - Cataloguenumber = "A123" + Position = i, + Artist = string.Format("Artist {0}", i), + Title = string.Format("Title {0}", i), + Begin = begin }; - var begin = TimeSpan.Zero; - var tracks = new List(); - for (ushort i = 1; i <= 10; i++) + var rand = new Random(); + var flagsToAdd = rand.Next(1, 3); + var flags = new List(); + for (int x = 0; x < flagsToAdd; x++) { - var track = new Track - { - Position = i, - Artist = string.Format("Artist {0}", i), - Title = string.Format("Title {0}", i), - Begin = begin - }; - var rand = new Random(); - var flagsToAdd = rand.Next(1, 3); - var flags = new List(); - for (int x = 0; x < flagsToAdd; x++) - { - flags.Add(Flag.AvailableFlags.ElementAt(x)); - } - track.Flags = flags; - begin = begin.Add(new TimeSpan(0, i, i)); - track.End = begin; - track.Cuesheet = cuesheet; - tracks.Add(track); + flags.Add(Flag.AvailableFlags.ElementAt(x)); } - cuesheet.Audiofiles.First().Tracks = tracks.GetRange(0, 5); - cuesheet.Audiofiles.Last().Tracks = tracks.GetRange(4, 5); - // Act - var projectFile = new Projectfile(cuesheet); - // Assert - var generatedFile = projectFile.GenerateFile(); - Assert.IsNotNull(generatedFile); - var fileName = Path.GetTempFileName(); - File.WriteAllBytes(fileName, generatedFile); - var fileContent = File.ReadAllLines(fileName); - var json = JsonSerializer.Serialize(cuesheet, Projectfile.Options); - Assert.AreEqual(json, fileContent.FirstOrDefault()); - File.Delete(fileName); + track.Flags = flags; + begin = begin.Add(new TimeSpan(0, i, i)); + track.End = begin; + track.Cuesheet = cuesheet; + tracks.Add(track); } + cuesheet.Audiofiles.First().Tracks = tracks.GetRange(0, 5); + cuesheet.Audiofiles.Last().Tracks = tracks.GetRange(4, 5); + // Act + var projectFile = new Projectfile(cuesheet); + // Assert + var generatedFile = projectFile.GenerateFile(); + Assert.IsNotNull(generatedFile); + var fileName = Path.GetTempFileName(); + File.WriteAllBytes(fileName, generatedFile); + var fileContent = File.ReadAllLines(fileName); + var json = JsonSerializer.Serialize(cuesheet, Projectfile.Options); + Assert.AreEqual(json, fileContent.FirstOrDefault()); + File.Delete(fileName); + } - [TestMethod()] - public void ImportFile_ValidProjectfile_ShouldImportFile() - { - // Arrange - var fileContent = "{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Cataloguenumber\":\"A123\",\"Audiofiles\":[{\"Name\":\"AudioFile.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true}]},{\"Name\":\"Other audiofile.wav\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/wav\",\"FileExtension\":\".wav\",\"Name\":\"AudioCodec WAVE\"},\"Tracks\":[{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}]}],\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"}}"; - // Act - var cuesheet = Projectfile.ImportFile(fileContent); - // Assert - Assert.IsNotNull(cuesheet); - Assert.HasCount(2, cuesheet.Audiofiles); - Assert.HasCount(5, cuesheet.Audiofiles.First().Tracks); - Assert.HasCount(5, cuesheet.Audiofiles.Last().Tracks); - Assert.IsTrue(cuesheet.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Cuesheet == cuesheet)); - Assert.IsTrue(cuesheet.Audiofiles.SelectMany(x => x.Tracks).All(x => x.IsLinkedToPreviousTrack)); - Assert.AreEqual("CuesheetArtist", cuesheet.Artist); - Assert.AreEqual("CuesheetTitle", cuesheet.Title); - Assert.AreEqual("AudioFile.mp3", cuesheet.Audiofiles.First().Name); - Assert.AreEqual("A123", cuesheet.Cataloguenumber); - Assert.AreEqual(2, cuesheet.Validate(nameof(Cuesheet.Cataloguenumber)).ValidationMessages?.Count); - Assert.HasCount(10, cuesheet.Audiofiles.SelectMany(x => x.Tracks)); - Assert.Contains(Flag.DCP, cuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); - Assert.Contains(Flag.FourCH, cuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); - Assert.AreEqual("Artist 10", cuesheet.Audiofiles.Last().Tracks.Last().Artist); - Assert.AreEqual(new TimeSpan(0, 55, 55), cuesheet.Audiofiles.Last().Tracks.Last().End); - Assert.AreEqual((ushort)10, cuesheet.Audiofiles.Last().Tracks.Last().Position); - } + [TestMethod()] + public void ImportFile_ValidProjectfile_ShouldImportFile() + { + // Arrange + var fileContent = "{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Cataloguenumber\":\"A123\",\"Audiofiles\":[{\"Name\":\"AudioFile.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true}]},{\"Name\":\"Other audiofile.wav\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/wav\",\"FileExtension\":\".wav\",\"Name\":\"AudioCodec WAVE\"},\"Tracks\":[{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}]}],\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"}}"; + // Act + var cuesheet = Projectfile.ImportFile(fileContent); + // Assert + Assert.IsNotNull(cuesheet); + Assert.HasCount(2, cuesheet.Audiofiles); + Assert.HasCount(5, cuesheet.Audiofiles.First().Tracks); + Assert.HasCount(5, cuesheet.Audiofiles.Last().Tracks); + Assert.IsTrue(cuesheet.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Cuesheet == cuesheet)); + Assert.IsTrue(cuesheet.Audiofiles.SelectMany(x => x.Tracks).All(x => x.IsLinkedToPreviousTrack)); + Assert.AreEqual("CuesheetArtist", cuesheet.Artist); + Assert.AreEqual("CuesheetTitle", cuesheet.Title); + Assert.AreEqual("AudioFile.mp3", cuesheet.Audiofiles.First().Name); + Assert.AreEqual("A123", cuesheet.Cataloguenumber); + Assert.AreEqual(2, cuesheet.Validate(nameof(Cuesheet.Cataloguenumber)).ValidationMessages?.Count); + Assert.HasCount(10, cuesheet.Audiofiles.SelectMany(x => x.Tracks)); + Assert.Contains(Flag.DCP, cuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); + Assert.Contains(Flag.FourCH, cuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); + Assert.AreEqual("Artist 10", cuesheet.Audiofiles.Last().Tracks.Last().Artist); + Assert.AreEqual(new TimeSpan(0, 55, 55), cuesheet.Audiofiles.Last().Tracks.Last().End); + Assert.AreEqual((ushort)10, cuesheet.Audiofiles.Last().Tracks.Last().Position); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/Options/ExportOptionsTest.cs b/AudioCuesheetEditor.Tests/Model/Options/ExportOptionsTest.cs index 77486245..15f8a41d 100644 --- a/AudioCuesheetEditor.Tests/Model/Options/ExportOptionsTest.cs +++ b/AudioCuesheetEditor.Tests/Model/Options/ExportOptionsTest.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,40 +18,39 @@ using System.Linq; using System.Text.Json; -namespace AudioCuesheetEditor.Tests.Model.Options +namespace AudioCuesheetEditor.Tests.Model.Options; + +[TestClass()] +public class ExportOptionsTest { - [TestClass()] - public class ExportOptionsTest + readonly JsonSerializerOptions serializerOptions = new() + { + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull + }; + + [TestMethod()] + public void SerializationTest() + { + var exportOptions = new ExportOptions(); + var optionsJson = JsonSerializer.Serialize(exportOptions, serializerOptions); + Assert.IsNotNull(optionsJson); + } + + [TestMethod()] + public void DeserializationTest() + { + var optionsJson = "{\"ExportProfiles\":[{\"Id\":\"ba65845a-f264-4ca1-b342-d99871e961da\",\"Name\":\"YouTube\",\"SchemeHead\":\"%Cuesheet.Artist% - %Cuesheet.Title%\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"YouTube.txt\"},{\"Id\":\"325cefed-ccdf-4694-9e0c-3fa28f38e9c6\",\"Name\":\"Mixcloud\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"Mixcloud.txt\"},{\"Id\":\"17c526a5-eec5-439a-b968-789975003600\",\"Name\":\"CSV Export\",\"SchemeHead\":\"%Cuesheet.Artist%;%Cuesheet.Title%;\",\"SchemeTracks\":\"%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%\",\"SchemeFooter\":\"Exported at %DateTime% using AudioCuesheetEditor (https://neocodermatrix86.github.io/AudioCuesheetEditor/)\",\"Filename\":\"Export.csv\"},{\"Id\":\"e85c8a42-a5a9-4df5-a580-48f0b85a19af\",\"Name\":\"Tracks only\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Position% - %Track.Artist% - %Track.Title% - %Track.Begin% - %Track.End% - %Track.Length%\",\"SchemeFooter\":\"\",\"Filename\":\"Tracks.txt\"}],\"SelectedProfileId\":\"e85c8a42-a5a9-4df5-a580-48f0b85a19af\"}"; + var options = JsonSerializer.Deserialize(optionsJson); + Assert.IsNotNull(options); + Assert.AreEqual(options.ExportProfiles.Last(), options.SelectedExportProfile); + } + + [TestMethod()] + public void DeserializeBackwardCompabilityTest() { - private readonly JsonSerializerOptions serializerOptions = new() - { - DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull - }; - - [TestMethod()] - public void SerializationTest() - { - var exportOptions = new ExportOptions(); - var optionsJson = JsonSerializer.Serialize(exportOptions, serializerOptions); - Assert.IsNotNull(optionsJson); - } - - [TestMethod()] - public void DeserializationTest() - { - var optionsJson = "{\"ExportProfiles\":[{\"Id\":\"ba65845a-f264-4ca1-b342-d99871e961da\",\"Name\":\"YouTube\",\"SchemeHead\":\"%Cuesheet.Artist% - %Cuesheet.Title%\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"YouTube.txt\"},{\"Id\":\"325cefed-ccdf-4694-9e0c-3fa28f38e9c6\",\"Name\":\"Mixcloud\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"Mixcloud.txt\"},{\"Id\":\"17c526a5-eec5-439a-b968-789975003600\",\"Name\":\"CSV Export\",\"SchemeHead\":\"%Cuesheet.Artist%;%Cuesheet.Title%;\",\"SchemeTracks\":\"%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%\",\"SchemeFooter\":\"Exported at %DateTime% using AudioCuesheetEditor (https://neocodermatrix86.github.io/AudioCuesheetEditor/)\",\"Filename\":\"Export.csv\"},{\"Id\":\"e85c8a42-a5a9-4df5-a580-48f0b85a19af\",\"Name\":\"Tracks only\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Position% - %Track.Artist% - %Track.Title% - %Track.Begin% - %Track.End% - %Track.Length%\",\"SchemeFooter\":\"\",\"Filename\":\"Tracks.txt\"}],\"SelectedProfileId\":\"e85c8a42-a5a9-4df5-a580-48f0b85a19af\"}"; - var options = JsonSerializer.Deserialize(optionsJson); - Assert.IsNotNull(options); - Assert.AreEqual(options.ExportProfiles.Last(), options.SelectedExportProfile); - } - - [TestMethod()] - public void DeserializeBackwardCompabilityTest() - { - var optionsJson = "{\"ExportProfiles\":[{\"Name\":\"YouTube\",\"SchemeHead\":\"%Cuesheet.Artist% - %Cuesheet.Title%\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"YouTube.txt\"},{\"Name\":\"Mixcloud\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"Mixcloud.txt\"},{\"Name\":\"CSV Export\",\"SchemeHead\":\"%Cuesheet.Artist%;%Cuesheet.Title%;\",\"SchemeTracks\":\"%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%\",\"SchemeFooter\":\"Exported at %DateTime% using AudioCuesheetEditor (https://neocodermatrix86.github.io/AudioCuesheetEditor/)\",\"Filename\":\"Export.csv\"},{\"Name\":\"Tracks only\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Position% - %Track.Artist% - %Track.Title% - %Track.Begin% - %Track.End% - %Track.Length%\",\"SchemeFooter\":\"\",\"Filename\":\"Tracks.txt\"}]}"; - var options = JsonSerializer.Deserialize(optionsJson); - Assert.IsNotNull(options); - Assert.HasCount(4, options.ExportProfiles); - } + var optionsJson = "{\"ExportProfiles\":[{\"Name\":\"YouTube\",\"SchemeHead\":\"%Cuesheet.Artist% - %Cuesheet.Title%\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"YouTube.txt\"},{\"Name\":\"Mixcloud\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Artist% - %Track.Title% %Track.Begin%\",\"SchemeFooter\":\"\",\"Filename\":\"Mixcloud.txt\"},{\"Name\":\"CSV Export\",\"SchemeHead\":\"%Cuesheet.Artist%;%Cuesheet.Title%;\",\"SchemeTracks\":\"%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%\",\"SchemeFooter\":\"Exported at %DateTime% using AudioCuesheetEditor (https://neocodermatrix86.github.io/AudioCuesheetEditor/)\",\"Filename\":\"Export.csv\"},{\"Name\":\"Tracks only\",\"SchemeHead\":\"\",\"SchemeTracks\":\"%Track.Position% - %Track.Artist% - %Track.Title% - %Track.Begin% - %Track.End% - %Track.Length%\",\"SchemeFooter\":\"\",\"Filename\":\"Tracks.txt\"}]}"; + var options = JsonSerializer.Deserialize(optionsJson); + Assert.IsNotNull(options); + Assert.HasCount(4, options.ExportProfiles); } } diff --git a/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanFormatTests.cs b/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanFormatTests.cs index 9e0e5c1e..5cc1b317 100644 --- a/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanFormatTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanFormatTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,23 +17,22 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -namespace AudioCuesheetEditor.Tests.Model.Utility +namespace AudioCuesheetEditor.Tests.Model.Utility; + +[TestClass()] +public class TimeSpanFormatTests { - [TestClass()] - public class TimeSpanFormatTests + [TestMethod()] + public void ParseTimeSpan_WithScheme_ReturnsTimeSpan() { - [TestMethod()] - public void ParseTimeSpan_WithScheme_ReturnsTimeSpan() + //Arrange + var format = new TimeSpanFormat() { - //Arrange - var format = new TimeSpanFormat() - { - Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" - }; - //Act - var timespan = format.ParseTimeSpan("63:12"); - //Assert - Assert.AreEqual(new TimeSpan(1,3,12), timespan); - } + Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" + }; + //Act + var timespan = format.ParseTimeSpan("63:12"); + //Assert + Assert.AreEqual(new TimeSpan(1,3,12), timespan); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs b/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs index fdcd8cbd..9bb47bb8 100644 --- a/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,157 +17,155 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -namespace AudioCuesheetEditor.Tests.Model.Utility +namespace AudioCuesheetEditor.Tests.Model.Utility; + +[TestClass()] +public class TimeSpanUtilityTests { - [TestClass()] - public class TimeSpanUtilityTests + [TestMethod()] + public void ParseTimeSpan_Valid_HoursMinutesSeconds() + { + // Arrange + string input = "01:23:45"; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(1, 23, 45), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Valid_MinutesSeconds() + { + // Arrange + string input = "3:12"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(0, 3, 12), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Valid_OverflowMinutes() + { + // Arrange + string input = "63:12"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(1, 3, 12), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Valid_HoursMinutes() + { + // Arrange + string input = "23:12"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(23, 12, 0), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Valid_FullFormat() + { + // Arrange + string input = "23:45:56"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(0, 23, 45, 56), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Valid_WithDays() + { + // Arrange + string input = "2.23:45:56"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Days}.{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(2, 23, 45, 56), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Valid_WithMilliseconds() + { + // Arrange + string input = "23:45:56.599"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNotNull(timespan); + Assert.AreEqual(new TimeSpan(0, 23, 45, 56, 599), timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Invalid_Format() { - [TestMethod()] - public void ParseTimeSpan_Valid_HoursMinutesSeconds() - { - // Arrange - string input = "01:23:45"; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(1, 23, 45), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Valid_MinutesSeconds() - { - // Arrange - string input = "3:12"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(0, 3, 12), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Valid_OverflowMinutes() - { - // Arrange - string input = "63:12"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(1, 3, 12), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Valid_HoursMinutes() - { - // Arrange - string input = "23:12"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(23, 12, 0), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Valid_FullFormat() - { - // Arrange - string input = "23:45:56"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(0, 23, 45, 56), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Valid_WithDays() - { - // Arrange - string input = "2.23:45:56"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Days}.{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(2, 23, 45, 56), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Valid_WithMilliseconds() - { - // Arrange - string input = "23:45:56.599"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNotNull(timespan); - Assert.AreEqual(new TimeSpan(0, 23, 45, 56, 599), timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Invalid_Format() - { - // Arrange - string input = "1.2e:45:87.h3a"; - - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNull(timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Invalid_Text() - { - // Arrange - string input = "Test"; - var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNull(timespan); - } - - [TestMethod()] - public void ParseTimeSpan_Invalid_Scheme() - { - // Arrange - string input = "Test"; - var format = new TimeSpanFormat() { Scheme = "this is a test" }; - - // Act - var timespan = TimeSpanUtility.ParseTimeSpan(input, format); - - // Assert - Assert.IsNull(timespan); - } + // Arrange + string input = "1.2e:45:87.h3a"; + + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNull(timespan); + } + + [TestMethod()] + public void ParseTimeSpan_Invalid_Text() + { + // Arrange + string input = "Test"; + var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNull(timespan); } + [TestMethod()] + public void ParseTimeSpan_Invalid_Scheme() + { + // Arrange + string input = "Test"; + var format = new TimeSpanFormat() { Scheme = "this is a test" }; + + // Act + var timespan = TimeSpanUtility.ParseTimeSpan(input, format); + + // Assert + Assert.IsNull(timespan); + } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs index 00da412f..f0e8e649 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -30,675 +30,674 @@ using System.Reflection; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.AudioCuesheet +namespace AudioCuesheetEditor.Tests.Services.AudioCuesheet; + +[TestClass] +public class AudiofileManagerTests { - [TestClass] - public class AudiofileManagerTests + readonly AudiofileManager _audiofileManager; + readonly Mock _fileInputManager; + readonly Mock _traceChangeManager; + readonly Mock _jsRuntime; + readonly Mock _trackManager; + readonly Mock _sessionStateContainer; + + public AudiofileManagerTests() { - private readonly AudiofileManager _audiofileManager; - private readonly Mock _fileInputManager; - private readonly Mock _traceChangeManager; - private readonly Mock _jsRuntime; - private readonly Mock _trackManager; - private readonly Mock _sessionStateContainer; - - public AudiofileManagerTests() - { - _fileInputManager = new Mock(); - _traceChangeManager = new Mock(); - _jsRuntime = new Mock(); - _trackManager = new Mock(); - _trackManager.Setup(x => x.SetProperty(It.IsAny(), It.IsAny>>(), It.IsAny())) - .Callback((Track track, LambdaExpression propExpr, object value) => - { - var memberExpression = propExpr.Body as MemberExpression; - if (memberExpression?.Member is PropertyInfo propertyInfo) - { - propertyInfo.SetValue(track, value); - } - }); - _trackManager.Setup(x => x.GetPreviousLinkedTrack(It.IsAny())).Returns(delegate (Track track) - { - if (track.IsLinkedToPreviousTrack == false) - { - return null; - } - if (track.Position.HasValue && (track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Position.HasValue) == true)) - { - return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.Position == track.Position - 1 && Equals(x, track) == false); - } - if (track.Begin.HasValue) + _fileInputManager = new Mock(); + _traceChangeManager = new Mock(); + _jsRuntime = new Mock(); + _trackManager = new Mock(); + _trackManager.Setup(x => x.SetProperty(It.IsAny(), It.IsAny>>(), It.IsAny())) + .Callback((Track track, LambdaExpression propExpr, object value) => + { + var memberExpression = propExpr.Body as MemberExpression; + if (memberExpression?.Member is PropertyInfo propertyInfo) { - return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); + propertyInfo.SetValue(track, value); } - return null; }); - _sessionStateContainer = new Mock(); - _audiofileManager = new AudiofileManager(_fileInputManager.Object, _traceChangeManager.Object, _jsRuntime.Object, _trackManager.Object, _sessionStateContainer.Object); - } - - [TestMethod] - public async Task ClearPropertiesAsync_ValidBrowserFile_ShouldClearPropertiesAsync() + _trackManager.Setup(x => x.GetPreviousLinkedTrack(It.IsAny())).Returns(delegate (Track track) { - // Arrange - var audiofile = new Audiofile + if (track.IsLinkedToPreviousTrack == false) { - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Name = "test.mp3", - ObjectURL = "Just a test", - Duration = TimeSpan.FromSeconds(120) - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate(object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; - } - }; - var expectedUrl = audiofile.ObjectURL; - // Act - await _audiofileManager.ClearPropertiesAsync(audiofile); - // Assert - Assert.IsNull(audiofile.AudioCodec); - Assert.IsNull(audiofile.Name); - Assert.IsNull(audiofile.ObjectURL); - Assert.IsNull(audiofile.Duration); - Assert.AreEqual(1, audiofileChangedFired); - _jsRuntime.Verify(js => js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() - { - // Arrange - var objectUrl = "blob:123"; - var filename = "song.mp3"; - var browserFile = new Mock(); - browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); - browserFile.SetupGet(b => b.Name).Returns(filename); - - var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); - _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); - _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); - - var audiofile = new Audiofile(); - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; + return null; + } + if (track.Position.HasValue && (track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Position.HasValue) == true)) + { + return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.Position == track.Position - 1 && Equals(x, track) == false); + } + if (track.Begin.HasValue) + { + return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); + } + return null; + }); + _sessionStateContainer = new Mock(); + _audiofileManager = new AudiofileManager(_fileInputManager.Object, _traceChangeManager.Object, _jsRuntime.Object, _trackManager.Object, _sessionStateContainer.Object); + } - } - }; - // Act - await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object); - - // Assert - Assert.AreEqual(codec, audiofile.AudioCodec); - Assert.AreEqual(filename, audiofile.Name); - Assert.AreEqual(objectUrl, audiofile.ObjectURL); - Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); - Assert.AreEqual(1, audiofileChangedFired); - _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); - _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); - _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); - } - - [TestMethod] - public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() - { - // Arrange - var objectUrl = "blob:123"; - var filename = "song.mp3"; - var browserFile = new Mock(); - browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); - browserFile.SetupGet(b => b.Name).Returns(filename); - - var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); - _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); - _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.FromSeconds(0), - End = TimeSpan.FromSeconds(30) - }; - var track2 = new Track() - { - Position = 2, - Begin = track1.End - }; - var audiofile = new Audiofile() - { - Tracks = [track1, track2] - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; - } - }; - // Act - await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object); - - // Assert - Assert.AreEqual(codec, audiofile.AudioCodec); - Assert.AreEqual(filename, audiofile.Name); - Assert.AreEqual(objectUrl, audiofile.ObjectURL); - Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); - Assert.AreEqual(TimeSpan.FromSeconds(90), track2.End); - Assert.AreEqual(1, audiofileChangedFired); - _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); - _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); - _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); - } - - [TestMethod] - public async Task SetPropertiesAsync_PreviouslySetAudiofile_ShouldClearFirstAndSetPropertiesAsync() - { - // Arrange - var objectUrl = "blob:123"; - var filename = "song.mp3"; - var browserFile = new Mock(); - browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); - browserFile.SetupGet(b => b.Name).Returns(filename); - - var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); - _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); - _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); - - var audiofile = new Audiofile - { - ObjectURL = "previouslySetObjectUrl" - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; - } - }; - // Act - await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object); - - // Assert - Assert.AreEqual(codec, audiofile.AudioCodec); - Assert.AreEqual(filename, audiofile.Name); - Assert.AreEqual(objectUrl, audiofile.ObjectURL); - Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); - Assert.AreEqual(1, audiofileChangedFired); - _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); - _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); - _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public async Task ClearPropertiesAsync_WithExistingObjectUrl_ShouldRevokeObjectUrl() - { - // Arrange - var audiofile = new Audiofile - { - ObjectURL = "just a test" - }; - var expectedUrl = audiofile.ObjectURL; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; + [TestMethod] + public async Task ClearPropertiesAsync_ValidBrowserFile_ShouldClearPropertiesAsync() + { + // Arrange + var audiofile = new Audiofile + { + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Name = "test.mp3", + ObjectURL = "Just a test", + Duration = TimeSpan.FromSeconds(120) + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate(object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + var expectedUrl = audiofile.ObjectURL; + // Act + await _audiofileManager.ClearPropertiesAsync(audiofile); + // Assert + Assert.IsNull(audiofile.AudioCodec); + Assert.IsNull(audiofile.Name); + Assert.IsNull(audiofile.ObjectURL); + Assert.IsNull(audiofile.Duration); + Assert.AreEqual(1, audiofileChangedFired); + _jsRuntime.Verify(js => js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } - } - }; - // Act - await _audiofileManager.ClearPropertiesAsync(audiofile); - - // Assert - Assert.AreEqual(1, audiofileChangedFired); - _jsRuntime.Verify(js =>js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)),Times.Once); - Assert.IsNull(audiofile.ObjectURL); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public void SetProperty_ChangedName_UpdatesPropertyAndAddsTrace() - { - // Arrange - var audiofile = new Audiofile - { - Name = "oldname.mp3" - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; + [TestMethod] + public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() + { + // Arrange + var objectUrl = "blob:123"; + var filename = "song.mp3"; + var browserFile = new Mock(); + browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + browserFile.SetupGet(b => b.Name).Returns(filename); + + var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); + _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); + _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); + _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); + + var audiofile = new Audiofile(); + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + + } + }; + // Act + await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object); + + // Assert + Assert.AreEqual(codec, audiofile.AudioCodec); + Assert.AreEqual(filename, audiofile.Name); + Assert.AreEqual(objectUrl, audiofile.ObjectURL); + Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); + Assert.AreEqual(1, audiofileChangedFired); + _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); + _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); + } - } - }; - // Act - _audiofileManager.SetProperty(audiofile, x => x.Name, "newname.mp3"); + [TestMethod] + public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() + { + // Arrange + var objectUrl = "blob:123"; + var filename = "song.mp3"; + var browserFile = new Mock(); + browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + browserFile.SetupGet(b => b.Name).Returns(filename); + + var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); + _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); + _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); + _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.FromSeconds(0), + End = TimeSpan.FromSeconds(30) + }; + var track2 = new Track() + { + Position = 2, + Begin = track1.End + }; + var audiofile = new Audiofile() + { + Tracks = [track1, track2] + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + // Act + await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object); + + // Assert + Assert.AreEqual(codec, audiofile.AudioCodec); + Assert.AreEqual(filename, audiofile.Name); + Assert.AreEqual(objectUrl, audiofile.ObjectURL); + Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); + Assert.AreEqual(TimeSpan.FromSeconds(90), track2.End); + Assert.AreEqual(1, audiofileChangedFired); + _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); + _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); + } - // Assert - Assert.AreEqual("newname.mp3", audiofile.Name); - Assert.AreEqual(1, audiofileChangedFired); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue!.Equals("oldname.mp3") && y.TraceableChange.PropertyName == nameof(Audiofile.Name))), Times.Once); - } + [TestMethod] + public async Task SetPropertiesAsync_PreviouslySetAudiofile_ShouldClearFirstAndSetPropertiesAsync() + { + // Arrange + var objectUrl = "blob:123"; + var filename = "song.mp3"; + var browserFile = new Mock(); + browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + browserFile.SetupGet(b => b.Name).Returns(filename); + + var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); + _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); + _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); + _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); + + var audiofile = new Audiofile + { + ObjectURL = "previouslySetObjectUrl" + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + // Act + await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object); + + // Assert + Assert.AreEqual(codec, audiofile.AudioCodec); + Assert.AreEqual(filename, audiofile.Name); + Assert.AreEqual(objectUrl, audiofile.ObjectURL); + Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); + Assert.AreEqual(1, audiofileChangedFired); + _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); + _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } - [TestMethod] - public void SetProperty_EqualValue_DoesntChangeProperty() + [TestMethod] + public async Task ClearPropertiesAsync_WithExistingObjectUrl_ShouldRevokeObjectUrl() + { + // Arrange + var audiofile = new Audiofile { - // Arrange - var audiofile = new Audiofile - { - Name = "oldname.mp3" - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + ObjectURL = "just a test" + }; + var expectedUrl = audiofile.ObjectURL; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) { - if (e == audiofile) - { - audiofileChangedFired++; + audiofileChangedFired++; - } - }; - // Act - _audiofileManager.SetProperty(audiofile, x => x.Name, "oldname.mp3"); + } + }; + // Act + await _audiofileManager.ClearPropertiesAsync(audiofile); - // Assert - Assert.AreEqual(0, audiofileChangedFired); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue!.Equals("oldname.mp3") && y.TraceableChange.PropertyName == nameof(Audiofile.Name))), Times.Never); - } + // Assert + Assert.AreEqual(1, audiofileChangedFired); + _jsRuntime.Verify(js =>js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)),Times.Once); + Assert.IsNull(audiofile.ObjectURL); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } - [TestMethod] - public void SetProperty_DurationChanged_SetsLastTrackEndAlso() + [TestMethod] + public void SetProperty_ChangedName_UpdatesPropertyAndAddsTrace() + { + // Arrange + var audiofile = new Audiofile { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.FromSeconds(0), - End = TimeSpan.FromSeconds(30) - }; - var track2 = new Track() - { - Position = 2, - Begin = track1.End - }; - var audiofile = new Audiofile - { - Tracks = [track1, track2], - }; - var duration = new TimeSpan(0, 3, 37, 12); - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + Name = "oldname.mp3" + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) { - if (e == audiofile) - { - audiofileChangedFired++; + audiofileChangedFired++; - } - }; - // Act - _audiofileManager.SetProperty(audiofile, x => x.Duration, duration); - - // Assert - Assert.AreEqual(duration, audiofile.Duration); - Assert.AreEqual(duration, track2.End); - Assert.AreEqual(1, audiofileChangedFired); - } - - [TestMethod] - public void AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties() - { - // Arrange - var duration = new TimeSpan(0, 27, 56); - var audiofile = new Audiofile("Audio.mp3", nameof(AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties), Audiofile.AudioCodecs.First(), duration); - var cuesheet = new Cuesheet() - { - Audiofiles = [audiofile] - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; + } + }; + // Act + _audiofileManager.SetProperty(audiofile, x => x.Name, "newname.mp3"); - } - }; - var track = new Track(); - // Act - _audiofileManager.AddTrack(audiofile, track); - // Assert - Assert.HasCount(1, audiofile.Tracks); - Assert.AreEqual(1, audiofileChangedFired); - Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); - Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); - Assert.AreEqual(duration, audiofile.Tracks.First().End); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && ((ICollection)y.TraceableChange.PreviousValue!).Count == 0 && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); - } - - [TestMethod] - public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackProperties() - { - // Arrange - var duration = new TimeSpan(0, 27, 56); - var tracks = new List - { - new() - { - Position = 1, - Begin = TimeSpan.Zero, - End = duration, - IsLinkedToPreviousTrack = true - } - }; - var audiofile = new Audiofile("Audio.mp3", nameof(AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackProperties), Audiofile.AudioCodecs.First(), duration) - { - Tracks = tracks - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [audiofile] - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var track = new Track() - { - IsLinkedToPreviousTrack = true - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; - } - }; - // Act - _audiofileManager.AddTrack(audiofile, track); - // Assert - Assert.HasCount(2, audiofile.Tracks); - Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); - Assert.IsFalse(audiofile.Tracks.First().End.HasValue); - Assert.AreEqual(duration, audiofile.Tracks.Last().End); - Assert.AreEqual(cuesheet, track.Cuesheet); - Assert.AreEqual(audiofile, track.Audiofile); - Assert.AreEqual(1, audiofileChangedFired); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == tracks && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public void AddTrack_DuringRecording_AddsNewTrackWithCalulatedTrackProperties() - { - // Arrange - var tracks = new List - { - new() - { - Position = 1, - Begin = TimeSpan.Zero, - IsLinkedToPreviousTrack = true - } - }; - var audiofile = new Audiofile() - { - Tracks = tracks - }; - var cuesheet = new Cuesheet() - { - RecordingStart = DateTime.UtcNow, - Audiofiles = [audiofile] - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var track = new Track() - { - IsLinkedToPreviousTrack = true - }; - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; + // Assert + Assert.AreEqual("newname.mp3", audiofile.Name); + Assert.AreEqual(1, audiofileChangedFired); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue!.Equals("oldname.mp3") && y.TraceableChange.PropertyName == nameof(Audiofile.Name))), Times.Once); + } - } - }; - // Act - _audiofileManager.AddTrack(audiofile, track); - // Assert - Assert.AreEqual(1, audiofileChangedFired); - Assert.HasCount(2, audiofile.Tracks); - Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); - Assert.IsNotNull(audiofile.Tracks.First().End); - Assert.IsNotNull(audiofile.Tracks.Last().Begin); - Assert.AreEqual(cuesheet, track.Cuesheet); - Assert.AreEqual(audiofile, track.Audiofile); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == tracks && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public void AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackProperties() - { - // Arrange - var duration = new TimeSpan(0, 27, 56); - var audiofile = new Audiofile("Audio.mp3", nameof(AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackProperties), Audiofile.AudioCodecs.First(), duration); - var importCuesheet = new Cuesheet() + [TestMethod] + public void SetProperty_EqualValue_DoesntChangeProperty() + { + // Arrange + var audiofile = new Audiofile + { + Name = "oldname.mp3" + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) { - Audiofiles = [audiofile] - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); - var track = new Track(); - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + audiofileChangedFired++; + + } + }; + // Act + _audiofileManager.SetProperty(audiofile, x => x.Name, "oldname.mp3"); + + // Assert + Assert.AreEqual(0, audiofileChangedFired); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue!.Equals("oldname.mp3") && y.TraceableChange.PropertyName == nameof(Audiofile.Name))), Times.Never); + } + + [TestMethod] + public void SetProperty_DurationChanged_SetsLastTrackEndAlso() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.FromSeconds(0), + End = TimeSpan.FromSeconds(30) + }; + var track2 = new Track() + { + Position = 2, + Begin = track1.End + }; + var audiofile = new Audiofile + { + Tracks = [track1, track2], + }; + var duration = new TimeSpan(0, 3, 37, 12); + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) { - if (e == audiofile) - { - audiofileChangedFired++; + audiofileChangedFired++; - } - }; - // Act - _audiofileManager.AddTrack(audiofile, track); - // Assert - Assert.AreEqual(1, audiofileChangedFired); - Assert.HasCount(1, audiofile.Tracks); - Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); - Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); - Assert.AreEqual(duration, audiofile.Tracks.First().End); - Assert.AreEqual(importCuesheet, track.Cuesheet); - Assert.AreEqual(audiofile, track.Audiofile); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && ((ICollection) y.TraceableChange.PreviousValue!).Count == 0 && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainingTrackProperties() - { - // Arrange - var track1 = new Track() + } + }; + // Act + _audiofileManager.SetProperty(audiofile, x => x.Duration, duration); + + // Assert + Assert.AreEqual(duration, audiofile.Duration); + Assert.AreEqual(duration, track2.End); + Assert.AreEqual(1, audiofileChangedFired); + } + + [TestMethod] + public void AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties() + { + // Arrange + var duration = new TimeSpan(0, 27, 56); + var audiofile = new Audiofile("Audio.mp3", nameof(AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties), Audiofile.AudioCodecs.First(), duration); + var cuesheet = new Cuesheet() + { + Audiofiles = [audiofile] + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + + } + }; + var track = new Track(); + // Act + _audiofileManager.AddTrack(audiofile, track); + // Assert + Assert.HasCount(1, audiofile.Tracks); + Assert.AreEqual(1, audiofileChangedFired); + Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); + Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); + Assert.AreEqual(duration, audiofile.Tracks.First().End); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && ((ICollection)y.TraceableChange.PreviousValue!).Count == 0 && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); + } + + [TestMethod] + public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackProperties() + { + // Arrange + var duration = new TimeSpan(0, 27, 56); + var tracks = new List + { + new() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + End = duration, IsLinkedToPreviousTrack = true - }; - var track4 = new Track() - { - Position = 4, - Begin = new TimeSpan(0, 10, 4), - End = new TimeSpan(0, 14, 54), - IsLinkedToPreviousTrack = true - }; - var track5 = new Track() - { - Position = 5, - Begin = new TimeSpan(0, 14, 54), - IsLinkedToPreviousTrack = true - }; - var previousValue = new List() { track1, track2, track3, track4, track5 }; - var duration = new TimeSpan(0, 19, 38); - var audiofile = new Audiofile("Audio.mp3", nameof(RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainingTrackProperties), Audiofile.AudioCodecs.First(), duration) - { - Tracks = previousValue - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [audiofile] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track4.Cuesheet = cuesheet; - track5.Cuesheet = cuesheet; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; - } - }; - // Act - _audiofileManager.RemoveTracks(audiofile, [track2, track4]); - // Assert - Assert.HasCount(3, audiofile.Tracks); - Assert.Contains(track1, audiofile.Tracks); - Assert.Contains(track3, audiofile.Tracks); - Assert.Contains(track5, audiofile.Tracks); - Assert.AreEqual(1, audiofileChangedFired); - Assert.AreEqual((ushort)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1.End, track3.Begin); - Assert.AreEqual((ushort)2, track3.Position); - Assert.AreEqual(track5.Begin, track3.End); - Assert.AreEqual((ushort)3, track5.Position); - Assert.AreEqual(duration, track5.End); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } - - [TestMethod] - public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrackProperties() - { - // Arrange - var track1 = new Track() + } + }; + var audiofile = new Audiofile("Audio.mp3", nameof(AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackProperties), Audiofile.AudioCodecs.First(), duration) + { + Tracks = tracks + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [audiofile] + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + var track = new Track() + { + IsLinkedToPreviousTrack = true + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + // Act + _audiofileManager.AddTrack(audiofile, track); + // Assert + Assert.HasCount(2, audiofile.Tracks); + Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); + Assert.IsFalse(audiofile.Tracks.First().End.HasValue); + Assert.AreEqual(duration, audiofile.Tracks.Last().End); + Assert.AreEqual(cuesheet, track.Cuesheet); + Assert.AreEqual(audiofile, track.Audiofile); + Assert.AreEqual(1, audiofileChangedFired); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == tracks && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } + + [TestMethod] + public void AddTrack_DuringRecording_AddsNewTrackWithCalulatedTrackProperties() + { + // Arrange + var tracks = new List + { + new() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var track4 = new Track() - { - Position = 4, - Begin = new TimeSpan(0, 10, 4), - End = new TimeSpan(0, 14, 54), - IsLinkedToPreviousTrack = true - }; - var track5 = new Track() - { - Position = 5, - Begin = new TimeSpan(0, 14, 54), IsLinkedToPreviousTrack = true - }; - var previousValue = new List() { track1, track2, track3, track4, track5 }; - var duration = new TimeSpan(0, 19, 38); - var audiofile = new Audiofile("Audio.mp3", nameof(RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrackProperties), Audiofile.AudioCodecs.First(), duration) - { - Tracks = previousValue - }; - var importCuesheet = new Cuesheet() - { - Audiofiles = [audiofile] - }; - track1.Cuesheet = importCuesheet; - track2.Cuesheet = importCuesheet; - track3.Cuesheet = importCuesheet; - track4.Cuesheet = importCuesheet; - track5.Cuesheet = importCuesheet; - track1.Audiofile = audiofile; - track2.Audiofile = audiofile; - track3.Audiofile = audiofile; - track4.Audiofile = audiofile; - track5.Audiofile = audiofile; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); - var audiofileChangedFired = 0; - _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) - { - if (e == audiofile) - { - audiofileChangedFired++; - } - }; - // Act - _audiofileManager.RemoveTracks(audiofile, [track2, track4]); - // Assert - Assert.HasCount(3, audiofile.Tracks); - Assert.Contains(track1, audiofile.Tracks); - Assert.Contains(track3, audiofile.Tracks); - Assert.Contains(track5, audiofile.Tracks); - Assert.AreEqual((ushort)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1.End, track3.Begin); - Assert.AreEqual((ushort)2, track3.Position); - Assert.AreEqual(track5.Begin, track3.End); - Assert.AreEqual((ushort)3, track5.Position); - Assert.AreEqual(1, audiofileChangedFired); - Assert.AreEqual(duration, track5.End); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); - } + } + }; + var audiofile = new Audiofile() + { + Tracks = tracks + }; + var cuesheet = new Cuesheet() + { + RecordingStart = DateTime.UtcNow, + Audiofiles = [audiofile] + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + var track = new Track() + { + IsLinkedToPreviousTrack = true + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + + } + }; + // Act + _audiofileManager.AddTrack(audiofile, track); + // Assert + Assert.AreEqual(1, audiofileChangedFired); + Assert.HasCount(2, audiofile.Tracks); + Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); + Assert.IsNotNull(audiofile.Tracks.First().End); + Assert.IsNotNull(audiofile.Tracks.Last().Begin); + Assert.AreEqual(cuesheet, track.Cuesheet); + Assert.AreEqual(audiofile, track.Audiofile); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == tracks && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } + + [TestMethod] + public void AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackProperties() + { + // Arrange + var duration = new TimeSpan(0, 27, 56); + var audiofile = new Audiofile("Audio.mp3", nameof(AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackProperties), Audiofile.AudioCodecs.First(), duration); + var importCuesheet = new Cuesheet() + { + Audiofiles = [audiofile] + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); + var track = new Track(); + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + + } + }; + // Act + _audiofileManager.AddTrack(audiofile, track); + // Assert + Assert.AreEqual(1, audiofileChangedFired); + Assert.HasCount(1, audiofile.Tracks); + Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); + Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); + Assert.AreEqual(duration, audiofile.Tracks.First().End); + Assert.AreEqual(importCuesheet, track.Cuesheet); + Assert.AreEqual(audiofile, track.Audiofile); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && ((ICollection) y.TraceableChange.PreviousValue!).Count == 0 && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } + + [TestMethod] + public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainingTrackProperties() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12), + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 12), + End = new TimeSpan(0, 7, 34), + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = new TimeSpan(0, 7, 34), + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var track4 = new Track() + { + Position = 4, + Begin = new TimeSpan(0, 10, 4), + End = new TimeSpan(0, 14, 54), + IsLinkedToPreviousTrack = true + }; + var track5 = new Track() + { + Position = 5, + Begin = new TimeSpan(0, 14, 54), + IsLinkedToPreviousTrack = true + }; + var previousValue = new List() { track1, track2, track3, track4, track5 }; + var duration = new TimeSpan(0, 19, 38); + var audiofile = new Audiofile("Audio.mp3", nameof(RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainingTrackProperties), Audiofile.AudioCodecs.First(), duration) + { + Tracks = previousValue + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [audiofile] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track4.Cuesheet = cuesheet; + track5.Cuesheet = cuesheet; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + // Act + _audiofileManager.RemoveTracks(audiofile, [track2, track4]); + // Assert + Assert.HasCount(3, audiofile.Tracks); + Assert.Contains(track1, audiofile.Tracks); + Assert.Contains(track3, audiofile.Tracks); + Assert.Contains(track5, audiofile.Tracks); + Assert.AreEqual(1, audiofileChangedFired); + Assert.AreEqual((ushort)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1.End, track3.Begin); + Assert.AreEqual((ushort)2, track3.Position); + Assert.AreEqual(track5.Begin, track3.End); + Assert.AreEqual((ushort)3, track5.Position); + Assert.AreEqual(duration, track5.End); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } + + [TestMethod] + public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrackProperties() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12), + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 12), + End = new TimeSpan(0, 7, 34), + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = new TimeSpan(0, 7, 34), + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var track4 = new Track() + { + Position = 4, + Begin = new TimeSpan(0, 10, 4), + End = new TimeSpan(0, 14, 54), + IsLinkedToPreviousTrack = true + }; + var track5 = new Track() + { + Position = 5, + Begin = new TimeSpan(0, 14, 54), + IsLinkedToPreviousTrack = true + }; + var previousValue = new List() { track1, track2, track3, track4, track5 }; + var duration = new TimeSpan(0, 19, 38); + var audiofile = new Audiofile("Audio.mp3", nameof(RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrackProperties), Audiofile.AudioCodecs.First(), duration) + { + Tracks = previousValue + }; + var importCuesheet = new Cuesheet() + { + Audiofiles = [audiofile] + }; + track1.Cuesheet = importCuesheet; + track2.Cuesheet = importCuesheet; + track3.Cuesheet = importCuesheet; + track4.Cuesheet = importCuesheet; + track5.Cuesheet = importCuesheet; + track1.Audiofile = audiofile; + track2.Audiofile = audiofile; + track3.Audiofile = audiofile; + track4.Audiofile = audiofile; + track5.Audiofile = audiofile; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + // Act + _audiofileManager.RemoveTracks(audiofile, [track2, track4]); + // Assert + Assert.HasCount(3, audiofile.Tracks); + Assert.Contains(track1, audiofile.Tracks); + Assert.Contains(track3, audiofile.Tracks); + Assert.Contains(track5, audiofile.Tracks); + Assert.AreEqual((ushort)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1.End, track3.Begin); + Assert.AreEqual((ushort)2, track3.Position); + Assert.AreEqual(track5.Begin, track3.End); + Assert.AreEqual((ushort)3, track5.Position); + Assert.AreEqual(1, audiofileChangedFired); + Assert.AreEqual(duration, track5.End); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); } } diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs index dea190de..53754066 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -28,1406 +28,1405 @@ using System.Linq.Expressions; using System.Reflection; -namespace AudioCuesheetEditor.Tests.Services.AudioCuesheet +namespace AudioCuesheetEditor.Tests.Services.AudioCuesheet; + +[TestClass] +public class CuesheetManagerTests { - [TestClass] - public class CuesheetManagerTests - { - private readonly CuesheetManager _cuesheetManager; - private readonly Mock _traceChangeManager; - private readonly Mock _sessionStateContainer; - private readonly Mock _trackManager; - private readonly Mock _audiofileManager; - private readonly Mock _jsRuntime; + readonly CuesheetManager _cuesheetManager; + readonly Mock _traceChangeManager; + readonly Mock _sessionStateContainer; + readonly Mock _trackManager; + readonly Mock _audiofileManager; + readonly Mock _jsRuntime; - public CuesheetManagerTests() - { - _traceChangeManager = new(); - _sessionStateContainer = new(); - _audiofileManager = new(); - _trackManager = new(); - _jsRuntime = new Mock(); - _trackManager.Setup(x => x.SetProperty(It.IsAny(),It.IsAny>>(),It.IsAny())) - .Callback((Track track, LambdaExpression propExpr, object value) => + public CuesheetManagerTests() + { + _traceChangeManager = new(); + _sessionStateContainer = new(); + _audiofileManager = new(); + _trackManager = new(); + _jsRuntime = new Mock(); + _trackManager.Setup(x => x.SetProperty(It.IsAny(),It.IsAny>>(),It.IsAny())) + .Callback((Track track, LambdaExpression propExpr, object value) => + { + var memberExpression = propExpr.Body as MemberExpression; + if (memberExpression?.Member is PropertyInfo propertyInfo) { - var memberExpression = propExpr.Body as MemberExpression; - if (memberExpression?.Member is PropertyInfo propertyInfo) - { - propertyInfo.SetValue(track, value); - } - }); - _cuesheetManager = new(_traceChangeManager.Object, _sessionStateContainer.Object, _trackManager.Object, _audiofileManager.Object, _jsRuntime.Object); - } + propertyInfo.SetValue(track, value); + } + }); + _cuesheetManager = new(_traceChangeManager.Object, _sessionStateContainer.Object, _trackManager.Object, _audiofileManager.Object, _jsRuntime.Object); + } - [TestMethod] - public void SetProperty_NewValue_ChangesPropertyAndSetsTracedChange() - { - // Arrange - var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - _cuesheetManager.SetProperty(x => x.Artist, "Artist"); - // Assert - Assert.AreEqual("Artist", cuesheet.Artist); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Cuesheet.Artist))), Times.Once); - } + [TestMethod] + public void SetProperty_NewValue_ChangesPropertyAndSetsTracedChange() + { + // Arrange + var cuesheet = new Cuesheet(); + _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + _cuesheetManager.SetProperty(x => x.Artist, "Artist"); + // Assert + Assert.AreEqual("Artist", cuesheet.Artist); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Cuesheet.Artist))), Times.Once); + } - [TestMethod] - public void SetProperty_EqualValue_DoesntChangeProperty() + [TestMethod] + public void SetProperty_EqualValue_DoesntChangeProperty() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Artist = "Artist" - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - _cuesheetManager.SetProperty(x => x.Artist, cuesheet.Artist); - // Assert - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Cuesheet.Artist))), Times.Never); - } + Artist = "Artist" + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + _cuesheetManager.SetProperty(x => x.Artist, cuesheet.Artist); + // Assert + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Cuesheet.Artist))), Times.Never); + } - [TestMethod] - public void SetProperty_DeletedAudiofile_RevokesObjectURLs() + [TestMethod] + public void SetProperty_DeletedAudiofile_RevokesObjectURLs() + { + // Arrange + var audiofile1 = new Audiofile() { - // Arrange - var audiofile1 = new Audiofile() - { - Name = "Test 1.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - ObjectURL = "objecturl 1" - }; - var audiofile2 = new Audiofile() - { - Name = "Test 2.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - ObjectURL = "objecturl 2" - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [audiofile1, audiofile2] - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var files = new List(cuesheet.Audiofiles); - files.Remove(audiofile2); - // Act - _cuesheetManager.SetProperty(x => x.Audiofiles, files); - // Assert - _jsRuntime.Verify(x => x.InvokeAsync("revokeAudioObjectURL", It.Is(args => args.Length == 1 && args[0].Equals(audiofile2.ObjectURL))), Times.Once()); - } + Name = "Test 1.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + ObjectURL = "objecturl 1" + }; + var audiofile2 = new Audiofile() + { + Name = "Test 2.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + ObjectURL = "objecturl 2" + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [audiofile1, audiofile2] + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + var files = new List(cuesheet.Audiofiles); + files.Remove(audiofile2); + // Act + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + // Assert + _jsRuntime.Verify(x => x.InvokeAsync("revokeAudioObjectURL", It.Is(args => args.Length == 1 && args[0].Equals(audiofile2.ObjectURL))), Times.Once()); + } - [TestMethod] - public void SetProperty_OnImportCuesheet_DoesNotTraceChanges() - { - // Arrange - var importCuesheet = new Cuesheet(); - var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(importCuesheet); - _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(importCuesheet); - // Act - _cuesheetManager.SetProperty(x => x.Artist, nameof(SetProperty_OnImportCuesheet_DoesNotTraceChanges)); - // Assert - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == importCuesheet)), Times.Never); - } + [TestMethod] + public void SetProperty_OnImportCuesheet_DoesNotTraceChanges() + { + // Arrange + var importCuesheet = new Cuesheet(); + var cuesheet = new Cuesheet(); + _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(importCuesheet); + _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); + _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(importCuesheet); + // Act + _cuesheetManager.SetProperty(x => x.Artist, nameof(SetProperty_OnImportCuesheet_DoesNotTraceChanges)); + // Assert + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == importCuesheet)), Times.Never); + } - [TestMethod] - public void IsRecordingPossible_WithoutTracks_ReturnsSuccess() - { - // Arrange - var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - // Act - var result = _cuesheetManager.IsRecordingPossible; - // Assert - Assert.IsTrue(result.IsSuccess); - } + [TestMethod] + public void IsRecordingPossible_WithoutTracks_ReturnsSuccess() + { + // Arrange + var cuesheet = new Cuesheet(); + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + // Act + var result = _cuesheetManager.IsRecordingPossible; + // Assert + Assert.IsTrue(result.IsSuccess); + } - [TestMethod] - public void IsRecordingPossible_WithTracks_ReturnsFailure() + [TestMethod] + public void IsRecordingPossible_WithTracks_ReturnsFailure() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [ - new() - ] - } - ] - }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - // Act - var result = _cuesheetManager.IsRecordingPossible; - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual("Cuesheet already contains tracks!", result.Error!.Message); - } + Audiofiles = [ + new() { + Tracks = [ + new() + ] + } + ] + }; + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + // Act + var result = _cuesheetManager.IsRecordingPossible; + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual("Cuesheet already contains tracks!", result.Error!.Message); + } - [TestMethod] - public void IsRecordingPossible_RecordingAlreadyRunning_ReturnsFailure() + [TestMethod] + public void IsRecordingPossible_RecordingAlreadyRunning_ReturnsFailure() + { + // Arrange + var cuesheet = new Cuesheet { - // Arrange - var cuesheet = new Cuesheet - { - Audiofiles = [ - new() { - } - ], - RecordingStart = DateTime.UtcNow - }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - // Act - var result = _cuesheetManager.IsRecordingPossible; - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual("Record is already running!", result.Error!.Message); - } + Audiofiles = [ + new() { + } + ], + RecordingStart = DateTime.UtcNow + }; + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + // Act + var result = _cuesheetManager.IsRecordingPossible; + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual("Record is already running!", result.Error!.Message); + } - [TestMethod] - public void StartRecording_RecordingPossible_ReturnsSuccess() - { - // Arrange - var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - var isRecordingChanged = false; - _cuesheetManager.IsRecordingChanged += delegate - { - isRecordingChanged = true; - }; - // Act - var result = _cuesheetManager.StartRecording(); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.IsTrue(isRecordingChanged); - Assert.IsNotNull(cuesheet.RecordingStart); - Assert.HasCount(1, cuesheet.Audiofiles); - } + [TestMethod] + public void StartRecording_RecordingPossible_ReturnsSuccess() + { + // Arrange + var cuesheet = new Cuesheet(); + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + var isRecordingChanged = false; + _cuesheetManager.IsRecordingChanged += delegate + { + isRecordingChanged = true; + }; + // Act + var result = _cuesheetManager.StartRecording(); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.IsTrue(isRecordingChanged); + Assert.IsNotNull(cuesheet.RecordingStart); + Assert.HasCount(1, cuesheet.Audiofiles); + } - [TestMethod] - public void StartRecording_RecordingNotPossible_ReturnsFailure() + [TestMethod] + public void StartRecording_RecordingNotPossible_ReturnsFailure() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - RecordingStart = DateTime.UtcNow.AddDays(-1) - }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - var isRecordingChanged = false; - _cuesheetManager.IsRecordingChanged += delegate - { - isRecordingChanged = true; - }; - // Act - var result = _cuesheetManager.StartRecording(); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.IsFalse(isRecordingChanged); - Assert.AreEqual("Record is already running!", result.Error!.Message); - } + RecordingStart = DateTime.UtcNow.AddDays(-1) + }; + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + var isRecordingChanged = false; + _cuesheetManager.IsRecordingChanged += delegate + { + isRecordingChanged = true; + }; + // Act + var result = _cuesheetManager.StartRecording(); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.IsFalse(isRecordingChanged); + Assert.AreEqual("Record is already running!", result.Error!.Message); + } - [TestMethod] - public void StopRecording_WithActiveRecording_StopsRecordAndSetsTrackDetails() + [TestMethod] + public void StopRecording_WithActiveRecording_StopsRecordAndSetsTrackDetails() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - RecordingStart = DateTime.UtcNow.AddDays(-1), - Audiofiles = [ - new() { - Tracks = [ - new() { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }, - new() { - Position = 2, - Begin = new TimeSpan(0, 3, 12) - } - ] - } - ] - }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - var isRecordingChanged = false; - _cuesheetManager.IsRecordingChanged += delegate - { - isRecordingChanged = true; - }; - // Act - _cuesheetManager.StopRecording(); - // Assert - Assert.IsFalse(cuesheet.IsRecording); - Assert.IsNull(cuesheet.RecordingStart); - Assert.IsTrue(isRecordingChanged); - Assert.IsNotNull(cuesheet.Audiofiles.First().Tracks.Last().End); - } + RecordingStart = DateTime.UtcNow.AddDays(-1), + Audiofiles = [ + new() { + Tracks = [ + new() { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }, + new() { + Position = 2, + Begin = new TimeSpan(0, 3, 12) + } + ] + } + ] + }; + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + var isRecordingChanged = false; + _cuesheetManager.IsRecordingChanged += delegate + { + isRecordingChanged = true; + }; + // Act + _cuesheetManager.StopRecording(); + // Assert + Assert.IsFalse(cuesheet.IsRecording); + Assert.IsNull(cuesheet.RecordingStart); + Assert.IsTrue(isRecordingChanged); + Assert.IsNotNull(cuesheet.Audiofiles.First().Tracks.Last().End); + } - [TestMethod] - public void StopRecording_WithoutActiveRecording_ChangesNothing() + [TestMethod] + public void StopRecording_WithoutActiveRecording_ChangesNothing() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [ - new() { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }, - new() { - Position = 2, - Begin = new TimeSpan(0, 3, 12) - } - ] - } - ] - }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - var isRecordingChanged = false; - _cuesheetManager.IsRecordingChanged += delegate - { - isRecordingChanged = true; - }; - // Act - _cuesheetManager.StopRecording(); - // Assert - Assert.IsFalse(isRecordingChanged); - Assert.IsNull(cuesheet.Audiofiles.First().Tracks.Last().End); - } + Audiofiles = [ + new() { + Tracks = [ + new() { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }, + new() { + Position = 2, + Begin = new TimeSpan(0, 3, 12) + } + ] + } + ] + }; + _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + var isRecordingChanged = false; + _cuesheetManager.IsRecordingChanged += delegate + { + isRecordingChanged = true; + }; + // Act + _cuesheetManager.StopRecording(); + // Assert + Assert.IsFalse(isRecordingChanged); + Assert.IsNull(cuesheet.Audiofiles.First().Tracks.Last().End); + } - [TestMethod] - public void IsMoveUpPossible_TracksAbove_ReturnsTrue() + [TestMethod] + public void IsMoveUpPossible_TracksAbove_ReturnsTrue() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - // Act - var result = _cuesheetManager.IsMoveUpPossible([track2, track3]); - // Assert - Assert.IsTrue(result); - } + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12), + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 12), + End = new TimeSpan(0, 7, 34), + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = new TimeSpan(0, 7, 34), + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + // Act + var result = _cuesheetManager.IsMoveUpPossible([track2, track3]); + // Assert + Assert.IsTrue(result); + } - [TestMethod] - public void IsMoveUpPossible_NoTracksAbove_ReturnsFalse() + [TestMethod] + public void IsMoveUpPossible_NoTracksAbove_ReturnsFalse() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track2, track1, track3] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - // Act - var result = _cuesheetManager.IsMoveUpPossible([track1, track2]); - // Assert - Assert.IsFalse(result); - } + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12), + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 12), + End = new TimeSpan(0, 7, 34), + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = new TimeSpan(0, 7, 34), + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track2, track1, track3] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + // Act + var result = _cuesheetManager.IsMoveUpPossible([track1, track2]); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveUpPossible_EmptyTracksCollection_ReturnsFalse() - { - // Arrange - // Act - var result = _cuesheetManager.IsMoveUpPossible(new HashSet()); - // Assert - Assert.IsFalse(result); - } + [TestMethod] + public void IsMoveUpPossible_EmptyTracksCollection_ReturnsFalse() + { + // Arrange + // Act + var result = _cuesheetManager.IsMoveUpPossible(new HashSet()); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveUpPossible_AudiofilesAbove_ReturnsTrue() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.IsMoveUpPossible([file2, file3]); - // Assert - Assert.IsTrue(result); - } + [TestMethod] + public void IsMoveUpPossible_AudiofilesAbove_ReturnsTrue() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.IsMoveUpPossible([file2, file3]); + // Assert + Assert.IsTrue(result); + } - [TestMethod] - public void IsMoveUpPossible_NoAudiofilesAbove_ReturnsFalse() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.IsMoveUpPossible([file1, file2]); - // Assert - Assert.IsFalse(result); - } + [TestMethod] + public void IsMoveUpPossible_NoAudiofilesAbove_ReturnsFalse() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.IsMoveUpPossible([file1, file2]); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveUpPossible_EmptyAudiofileCollection_ReturnsFalse() - { - // Arrange - // Act - var result = _cuesheetManager.IsMoveUpPossible(new HashSet()); - // Assert - Assert.IsFalse(result); - } + [TestMethod] + public void IsMoveUpPossible_EmptyAudiofileCollection_ReturnsFalse() + { + // Arrange + // Act + var result = _cuesheetManager.IsMoveUpPossible(new HashSet()); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveDownPossible_TracksBelow_ReturnsTrue() + [TestMethod] + public void IsMoveDownPossible_TracksBelow_ReturnsTrue() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.IsMoveDownPossible([track2, track1]); - // Assert - Assert.IsTrue(result); - } + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12), + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 12), + End = new TimeSpan(0, 7, 34), + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = new TimeSpan(0, 7, 34), + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.IsMoveDownPossible([track2, track1]); + // Assert + Assert.IsTrue(result); + } - [TestMethod] - public void IsMoveDownPossible_NoTracksBelow_ReturnsFalse() + [TestMethod] + public void IsMoveDownPossible_NoTracksBelow_ReturnsFalse() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - Position = 2, - Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - // Act - var result = _cuesheetManager.IsMoveDownPossible([track3, track2]); - // Assert - Assert.IsFalse(result); - } + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12), + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + Position = 2, + Begin = new TimeSpan(0, 3, 12), + End = new TimeSpan(0, 7, 34), + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = new TimeSpan(0, 7, 34), + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + // Act + var result = _cuesheetManager.IsMoveDownPossible([track3, track2]); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveDownPossible_EmptyTracksCollection_ReturnsFalse() - { - // Arrange - // Act - var result = _cuesheetManager.IsMoveDownPossible(new HashSet()); - // Assert - Assert.IsFalse(result); - } + [TestMethod] + public void IsMoveDownPossible_EmptyTracksCollection_ReturnsFalse() + { + // Arrange + // Act + var result = _cuesheetManager.IsMoveDownPossible(new HashSet()); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveDownPossible_AudiofilesBelow_ReturnsTrue() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.IsMoveDownPossible([file2, file1]); - // Assert - Assert.IsTrue(result); - } + [TestMethod] + public void IsMoveDownPossible_AudiofilesBelow_ReturnsTrue() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.IsMoveDownPossible([file2, file1]); + // Assert + Assert.IsTrue(result); + } - [TestMethod] - public void IsMoveDownPossible_NoAudiofilesBelow_ReturnsFalse() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.IsMoveDownPossible([file3, file2]); - // Assert - Assert.IsFalse(result); - } + [TestMethod] + public void IsMoveDownPossible_NoAudiofilesBelow_ReturnsFalse() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.IsMoveDownPossible([file3, file2]); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void IsMoveDownPossible_EmptyAudiofileCollection_ReturnsFalse() - { - // Arrange - // Act - var result = _cuesheetManager.IsMoveDownPossible(new HashSet()); - // Assert - Assert.IsFalse(result); - } + [TestMethod] + public void IsMoveDownPossible_EmptyAudiofileCollection_ReturnsFalse() + { + // Arrange + // Act + var result = _cuesheetManager.IsMoveDownPossible(new HashSet()); + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public void MoveUp_TracksSwitchingAudiofile_ReturnsSuccess() + [TestMethod] + public void MoveUp_TracksSwitchingAudiofile_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track1] - }, - new() { - Tracks = [track3, track2] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.Last(); - track3.Audiofile = cuesheet.Audiofiles.Last(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp([track2, track3]); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual(cuesheet.Audiofiles.First(), track1.Audiofile); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(cuesheet.Audiofiles.First(), track2.Audiofile); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - Assert.AreEqual(cuesheet.Audiofiles.First(), track3.Audiofile); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Exactly(2)); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track1] + }, + new() { + Tracks = [track3, track2] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.Last(); + track3.Audiofile = cuesheet.Audiofiles.Last(); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp([track2, track3]); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(cuesheet.Audiofiles.First(), track1.Audiofile); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(cuesheet.Audiofiles.First(), track2.Audiofile); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + Assert.AreEqual(cuesheet.Audiofiles.First(), track3.Audiofile); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Exactly(2)); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveUp_TracksAbove_ReturnsSuccess() + [TestMethod] + public void MoveUp_TracksAbove_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp([track2, track3]); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual((ushort?)1, track2.Position); - Assert.AreEqual(TimeSpan.Zero, track2.Begin); - Assert.AreEqual(track1End, track2.End); - Assert.AreEqual((ushort?)2, track3.Position); - Assert.AreEqual(track1End, track3.Begin); - Assert.AreEqual(track2End, track3.End); - Assert.AreEqual((ushort?)3, track1.Position); - Assert.AreEqual(track2End, track1.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp([track2, track3]); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual((ushort?)1, track2.Position); + Assert.AreEqual(TimeSpan.Zero, track2.Begin); + Assert.AreEqual(track1End, track2.End); + Assert.AreEqual((ushort?)2, track3.Position); + Assert.AreEqual(track1End, track3.Begin); + Assert.AreEqual(track2End, track3.End); + Assert.AreEqual((ushort?)3, track1.Position); + Assert.AreEqual(track2End, track1.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveUp_Move2Positions_ReturnsSuccess() + [TestMethod] + public void MoveUp_Move2Positions_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3End = new TimeSpan(0, 10, 4); - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = track3End, - IsLinkedToPreviousTrack = true - }; - var track4 = new Track() - { - Position = 4, - Begin = track3End, - End = new TimeSpan(0, 13, 45), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track4, track3, track2, track1] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track4.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - track4.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp([track2, track3], 2); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual((ushort?)1, track2.Position); - Assert.AreEqual(TimeSpan.Zero, track2.Begin); - Assert.AreEqual(track1End, track2.End); - Assert.AreEqual((ushort?)2, track3.Position); - Assert.AreEqual(track1End, track3.Begin); - Assert.AreEqual(track2End, track3.End); - Assert.AreEqual((ushort?)3, track1.Position); - Assert.AreEqual(track2End, track1.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3End = new TimeSpan(0, 10, 4); + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = track3End, + IsLinkedToPreviousTrack = true + }; + var track4 = new Track() + { + Position = 4, + Begin = track3End, + End = new TimeSpan(0, 13, 45), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track4, track3, track2, track1] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track4.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + track4.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp([track2, track3], 2); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual((ushort?)1, track2.Position); + Assert.AreEqual(TimeSpan.Zero, track2.Begin); + Assert.AreEqual(track1End, track2.End); + Assert.AreEqual((ushort?)2, track3.Position); + Assert.AreEqual(track1End, track3.Begin); + Assert.AreEqual(track2End, track3.End); + Assert.AreEqual((ushort?)3, track1.Position); + Assert.AreEqual(track2End, track1.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveUp_NoTracksAbove_ReturnsFailure() + [TestMethod] + public void MoveUp_NoTracksAbove_ReturnsFailure() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp([track2, track1]); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp([track2, track1]); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveUp_NoTracksSelected_ReturnsFailure() + [TestMethod] + public void MoveUp_NoTracksSelected_ReturnsFailure() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ], - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp(new HashSet()); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ], + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp(new HashSet()); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveUp_AudiofilesAbove_ReturnsSuccess() + [TestMethod] + public void MoveUp_AudiofilesAbove_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var file1 = new Audiofile("Audiofile 1", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM); - var file2 = new Audiofile("Audiofile 2", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) - { - Tracks = [track1, track2] - }; - var file3 = new Audiofile("Audiofile 3", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) - { - Tracks = [track3] - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = file2; - track2.Audiofile = file2; - track3.Audiofile = file3; - // Act - var result = _cuesheetManager.MoveUp([file2, file3]); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreSequenceEqual(new List([file2, file3, file1]), cuesheet.Audiofiles); - Assert.IsEmpty(file1.Tracks); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual(file2, track1.Audiofile); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual(file2, track2.Audiofile); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - Assert.AreEqual(file3, track3.Audiofile); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var file1 = new Audiofile("Audiofile 1", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM); + var file2 = new Audiofile("Audiofile 2", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) + { + Tracks = [track1, track2] + }; + var file3 = new Audiofile("Audiofile 3", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) + { + Tracks = [track3] + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = file2; + track2.Audiofile = file2; + track3.Audiofile = file3; + // Act + var result = _cuesheetManager.MoveUp([file2, file3]); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreSequenceEqual(new List([file2, file3, file1]), cuesheet.Audiofiles); + Assert.IsEmpty(file1.Tracks); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(file2, track1.Audiofile); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(file2, track2.Audiofile); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + Assert.AreEqual(file3, track3.Audiofile); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveUp_NoAudiofilesAbove_ReturnsFailure() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp([file1, file2]); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + [TestMethod] + public void MoveUp_NoAudiofilesAbove_ReturnsFailure() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp([file1, file2]); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveUp_NoAudiofilesSelected_ReturnsFailure() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveUp(new HashSet()); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + [TestMethod] + public void MoveUp_NoAudiofilesSelected_ReturnsFailure() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveUp(new HashSet()); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveDown_TracksSwitchingAudiofile_ReturnsSuccess() + [TestMethod] + public void MoveDown_TracksSwitchingAudiofile_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track2, track1] - }, - new() { - Tracks = [track3] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.Last(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown([track2, track1]); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual(cuesheet.Audiofiles.Last(), track1.Audiofile); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual(cuesheet.Audiofiles.Last(), track2.Audiofile); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - Assert.AreEqual(cuesheet.Audiofiles.Last(), track3.Audiofile); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Exactly(2)); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track2, track1] + }, + new() { + Tracks = [track3] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.Last(); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown([track2, track1]); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(cuesheet.Audiofiles.Last(), track1.Audiofile); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(cuesheet.Audiofiles.Last(), track2.Audiofile); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + Assert.AreEqual(cuesheet.Audiofiles.Last(), track3.Audiofile); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Exactly(2)); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveDown_TracksBelow_ReturnsSuccess() + [TestMethod] + public void MoveDown_TracksBelow_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown([track2, track1]); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual((ushort?)1, track3.Position); - Assert.AreEqual(TimeSpan.Zero, track3.Begin); - Assert.AreEqual(track1End, track3.End); - Assert.AreEqual((ushort?)2, track1.Position); - Assert.AreEqual(track1End, track1.Begin); - Assert.AreEqual(track2End, track1.End); - Assert.AreEqual((ushort?)3, track2.Position); - Assert.AreEqual(track2End, track2.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown([track2, track1]); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual((ushort?)1, track3.Position); + Assert.AreEqual(TimeSpan.Zero, track3.Begin); + Assert.AreEqual(track1End, track3.End); + Assert.AreEqual((ushort?)2, track1.Position); + Assert.AreEqual(track1End, track1.Begin); + Assert.AreEqual(track2End, track1.End); + Assert.AreEqual((ushort?)3, track2.Position); + Assert.AreEqual(track2End, track2.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveDown_Move2Positions_ReturnsSuccess() + [TestMethod] + public void MoveDown_Move2Positions_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3End = new TimeSpan(0, 10, 4); - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = track3End, - IsLinkedToPreviousTrack = true - }; - var track4 = new Track() - { - Position = 4, - Begin = track3End, - End = new TimeSpan(0, 13, 45), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track4, track3, track2, track1] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track4.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - track4.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown([track2, track1], 2); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual((ushort?)1, track3.Position); - Assert.AreEqual(TimeSpan.Zero, track3.Begin); - Assert.AreEqual(track1End, track3.End); - Assert.AreEqual((ushort?)2, track4.Position); - Assert.AreEqual(track1End, track4.Begin); - Assert.AreEqual(track2End, track4.End); - Assert.AreEqual((ushort?)3, track1.Position); - Assert.AreEqual(track2End, track1.Begin); - Assert.AreEqual(track3End, track1.End); - Assert.AreEqual((ushort?)4, track2.Position); - Assert.AreEqual(track3End, track2.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3End = new TimeSpan(0, 10, 4); + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = track3End, + IsLinkedToPreviousTrack = true + }; + var track4 = new Track() + { + Position = 4, + Begin = track3End, + End = new TimeSpan(0, 13, 45), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track4, track3, track2, track1] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track4.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + track4.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown([track2, track1], 2); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual((ushort?)1, track3.Position); + Assert.AreEqual(TimeSpan.Zero, track3.Begin); + Assert.AreEqual(track1End, track3.End); + Assert.AreEqual((ushort?)2, track4.Position); + Assert.AreEqual(track1End, track4.Begin); + Assert.AreEqual(track2End, track4.End); + Assert.AreEqual((ushort?)3, track1.Position); + Assert.AreEqual(track2End, track1.Begin); + Assert.AreEqual(track3End, track1.End); + Assert.AreEqual((ushort?)4, track2.Position); + Assert.AreEqual(track3End, track2.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveDown_NoTracksBelow_ReturnsFailure() + [TestMethod] + public void MoveDown_NoTracksBelow_ReturnsFailure() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown([track2, track3]); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown([track2, track3]); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveDown_NoTracksSelected_ReturnsFailure() + [TestMethod] + public void MoveDown_NoTracksSelected_ReturnsFailure() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track3, track2, track1] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown(new HashSet()); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [track3, track2, track1] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + track3.Audiofile = cuesheet.Audiofiles.First(); + _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown(new HashSet()); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == cuesheet.Audiofiles && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveDown_AudiofilesBelow_ReturnsSuccess() + [TestMethod] + public void MoveDown_AudiofilesBelow_ReturnsSuccess() + { + // Arrange + var track1End = new TimeSpan(0, 3, 12); + var track1 = new Track() { - // Arrange - var track1End = new TimeSpan(0, 3, 12); - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = track1End, - IsLinkedToPreviousTrack = true - }; - var track2End = new TimeSpan(0, 7, 34); - var track2 = new Track() - { - Position = 2, - Begin = track1End, - End = track2End, - IsLinkedToPreviousTrack = true - }; - var track3 = new Track() - { - Position = 3, - Begin = track2End, - End = new TimeSpan(0, 10, 4), - IsLinkedToPreviousTrack = true - }; - var file1 = new Audiofile("Audiofile 1", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM); - var file2 = new Audiofile("Audiofile 2", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) - { - Tracks = [track1, track2] - }; - var file3 = new Audiofile("Audiofile 3", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) - { - Tracks = [track3] - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track1.Audiofile = file2; - track2.Audiofile = file2; - track3.Audiofile = file3; - // Act - var result = _cuesheetManager.MoveDown([file2, file1]); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreSequenceEqual(new List([file3, file1, file2]), cuesheet.Audiofiles); - Assert.AreEqual((ushort?)1, track1.Position); - Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); - Assert.AreEqual(file2, track1.Audiofile); - Assert.AreEqual((ushort?)2, track2.Position); - Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); - Assert.AreEqual(file2, track2.Audiofile); - Assert.AreEqual((ushort?)3, track3.Position); - Assert.AreEqual(track2End, track3.Begin); - Assert.AreEqual(file3, track3.Audiofile); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); - } + Position = 1, + Begin = TimeSpan.Zero, + End = track1End, + IsLinkedToPreviousTrack = true + }; + var track2End = new TimeSpan(0, 7, 34); + var track2 = new Track() + { + Position = 2, + Begin = track1End, + End = track2End, + IsLinkedToPreviousTrack = true + }; + var track3 = new Track() + { + Position = 3, + Begin = track2End, + End = new TimeSpan(0, 10, 4), + IsLinkedToPreviousTrack = true + }; + var file1 = new Audiofile("Audiofile 1", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM); + var file2 = new Audiofile("Audiofile 2", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) + { + Tracks = [track1, track2] + }; + var file3 = new Audiofile("Audiofile 3", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM) + { + Tracks = [track3] + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track1.Audiofile = file2; + track2.Audiofile = file2; + track3.Audiofile = file3; + // Act + var result = _cuesheetManager.MoveDown([file2, file1]); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreSequenceEqual(new List([file3, file1, file2]), cuesheet.Audiofiles); + Assert.AreEqual((ushort?)1, track1.Position); + Assert.AreEqual(TimeSpan.Zero, track1.Begin); + Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(file2, track1.Audiofile); + Assert.AreEqual((ushort?)2, track2.Position); + Assert.AreEqual(track1End, track2.Begin); + Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(file2, track2.Audiofile); + Assert.AreEqual((ushort?)3, track3.Position); + Assert.AreEqual(track2End, track3.Begin); + Assert.AreEqual(file3, track3.Audiofile); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Once); + } - [TestMethod] - public void MoveDown_NoAudiofilesBelow_ReturnsFailure() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown([file2, file3]); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + [TestMethod] + public void MoveDown_NoAudiofilesBelow_ReturnsFailure() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown([file2, file3]); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); + } - [TestMethod] - public void MoveDown_NoAudiofilesSelected_ReturnsFailure() - { - // Arrange - var file1 = new Audiofile(); - var file2 = new Audiofile(); - var file3 = new Audiofile(); - var cuesheet = new Cuesheet() - { - Audiofiles = [file1, file2, file3], - }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = _cuesheetManager.MoveDown(new HashSet()); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); - _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); - _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); - } + [TestMethod] + public void MoveDown_NoAudiofilesSelected_ReturnsFailure() + { + // Arrange + var file1 = new Audiofile(); + var file2 = new Audiofile(); + var file3 = new Audiofile(); + var cuesheet = new Cuesheet() + { + Audiofiles = [file1, file2, file3], + }; + _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = _cuesheetManager.MoveDown(new HashSet()); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); + _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); } } diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs index 514081c8..46064005 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -22,688 +22,687 @@ using Moq; using System; -namespace AudioCuesheetEditor.Tests.Services.AudioCuesheet +namespace AudioCuesheetEditor.Tests.Services.AudioCuesheet; + +[TestClass] +public class TrackManagerTests { - [TestClass] - public class TrackManagerTests - { - private readonly TrackManager _trackManager; - private readonly Mock _traceChangeManager; + readonly TrackManager _trackManager; + readonly Mock _traceChangeManager; - public TrackManagerTests() - { - _traceChangeManager = new Mock(); - _trackManager = new(_traceChangeManager.Object); - } + public TrackManagerTests() + { + _traceChangeManager = new Mock(); + _trackManager = new(_traceChangeManager.Object); + } - [TestMethod] - public void SetProperty_NewValue_ChangesPropertyAndSetsTracedChange() - { - // Arrange - var track = new Track(); - var artist = "Artist 1"; - // Act - _trackManager.SetProperty(track, x => x.Artist, artist); - // Assert - Assert.AreEqual(artist, track.Artist); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Artist))), Times.Once); - } + [TestMethod] + public void SetProperty_NewValue_ChangesPropertyAndSetsTracedChange() + { + // Arrange + var track = new Track(); + var artist = "Artist 1"; + // Act + _trackManager.SetProperty(track, x => x.Artist, artist); + // Assert + Assert.AreEqual(artist, track.Artist); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Artist))), Times.Once); + } - [TestMethod] - public void SetProperty_EqualValue_DoesntChangeProperty() - { - // Arrange - var artist = "Artist 1"; - var track = new Track() - { - Artist = artist, - Position = 2 - }; - // Act - _trackManager.SetProperty(track, x => x.Artist, artist); - // Assert - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Artist))), Times.Never); - } + [TestMethod] + public void SetProperty_EqualValue_DoesntChangeProperty() + { + // Arrange + var artist = "Artist 1"; + var track = new Track() + { + Artist = artist, + Position = 2 + }; + // Act + _trackManager.SetProperty(track, x => x.Artist, artist); + // Assert + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Artist))), Times.Never); + } - [TestMethod] - public void Clone_ImportTrack_ReturnsTrackClone() - { - // Arrange - var importTrack = new ImportTrack() - { - Artist = "Artist 1", - Title = "Title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 2, 54), - IsLinkedToPreviousTrack = true, - Position = 1, - PostGap = new TimeSpan(0, 0, 2), - PreGap = new TimeSpan(0, 0, 4), - Flags = [Flag.FourCH, Flag.DCP], - StartDateTime = new DateTime(2024, 2, 28, 19, 23, 54) - }; - // Act - var track = _trackManager.Clone(importTrack); - // Assert - Assert.AreEqual(importTrack.Artist, track.Artist); - Assert.AreEqual(importTrack.Title, track.Title); - Assert.AreEqual(importTrack.Begin, track.Begin); - Assert.AreEqual(importTrack.End, track.End); - Assert.AreEqual(importTrack.IsLinkedToPreviousTrack, track.IsLinkedToPreviousTrack); - Assert.AreEqual(importTrack.Position, track.Position); - Assert.AreEqual(importTrack.PostGap, track.PostGap); - Assert.AreEqual(importTrack.PreGap, track.PreGap); - Assert.AreEquivalent(importTrack.Flags, track.Flags); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track)), Times.Never); - } + [TestMethod] + public void Clone_ImportTrack_ReturnsTrackClone() + { + // Arrange + var importTrack = new ImportTrack() + { + Artist = "Artist 1", + Title = "Title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 2, 54), + IsLinkedToPreviousTrack = true, + Position = 1, + PostGap = new TimeSpan(0, 0, 2), + PreGap = new TimeSpan(0, 0, 4), + Flags = [Flag.FourCH, Flag.DCP], + StartDateTime = new DateTime(2024, 2, 28, 19, 23, 54) + }; + // Act + var track = _trackManager.Clone(importTrack); + // Assert + Assert.AreEqual(importTrack.Artist, track.Artist); + Assert.AreEqual(importTrack.Title, track.Title); + Assert.AreEqual(importTrack.Begin, track.Begin); + Assert.AreEqual(importTrack.End, track.End); + Assert.AreEqual(importTrack.IsLinkedToPreviousTrack, track.IsLinkedToPreviousTrack); + Assert.AreEqual(importTrack.Position, track.Position); + Assert.AreEqual(importTrack.PostGap, track.PostGap); + Assert.AreEqual(importTrack.PreGap, track.PreGap); + Assert.AreEquivalent(importTrack.Flags, track.Flags); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track)), Times.Never); + } - [TestMethod] - public void Clone_ImportTrackWithLength_ReturnsTrackCloneWithLengthSet() - { - // Arrange - var importTrack = new ImportTrack() - { - Artist = "Artist 1", - Title = "Title 1", - Begin = TimeSpan.Zero, - Length = new TimeSpan(0, 2, 54), - IsLinkedToPreviousTrack = true, - Position = 1, - PostGap = new TimeSpan(0, 0, 2), - PreGap = new TimeSpan(0, 0, 4), - Flags = [Flag.FourCH, Flag.DCP], - StartDateTime = new DateTime(2024, 2, 28, 19, 23, 54) - }; - // Act - var track = _trackManager.Clone(importTrack); - // Assert - Assert.AreEqual(importTrack.Artist, track.Artist); - Assert.AreEqual(importTrack.Title, track.Title); - Assert.AreEqual(importTrack.Begin, track.Begin); - Assert.AreEqual(importTrack.Length, track.End); - Assert.AreEqual(importTrack.IsLinkedToPreviousTrack, track.IsLinkedToPreviousTrack); - Assert.AreEqual(importTrack.Position, track.Position); - Assert.AreEqual(importTrack.PostGap, track.PostGap); - Assert.AreEqual(importTrack.PreGap, track.PreGap); - Assert.AreEquivalent(importTrack.Flags, track.Flags); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track)), Times.Never); - } + [TestMethod] + public void Clone_ImportTrackWithLength_ReturnsTrackCloneWithLengthSet() + { + // Arrange + var importTrack = new ImportTrack() + { + Artist = "Artist 1", + Title = "Title 1", + Begin = TimeSpan.Zero, + Length = new TimeSpan(0, 2, 54), + IsLinkedToPreviousTrack = true, + Position = 1, + PostGap = new TimeSpan(0, 0, 2), + PreGap = new TimeSpan(0, 0, 4), + Flags = [Flag.FourCH, Flag.DCP], + StartDateTime = new DateTime(2024, 2, 28, 19, 23, 54) + }; + // Act + var track = _trackManager.Clone(importTrack); + // Assert + Assert.AreEqual(importTrack.Artist, track.Artist); + Assert.AreEqual(importTrack.Title, track.Title); + Assert.AreEqual(importTrack.Begin, track.Begin); + Assert.AreEqual(importTrack.Length, track.End); + Assert.AreEqual(importTrack.IsLinkedToPreviousTrack, track.IsLinkedToPreviousTrack); + Assert.AreEqual(importTrack.Position, track.Position); + Assert.AreEqual(importTrack.PostGap, track.PostGap); + Assert.AreEqual(importTrack.PreGap, track.PreGap); + Assert.AreEquivalent(importTrack.Flags, track.Flags); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track)), Times.Never); + } - [TestMethod] - public void CopyValues_AllDefaultValues_CopiesAllValues() - { - // Arrange - var source = new Track() - { - Artist = "Artist 1", - Title = "Title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 2, 54), - IsLinkedToPreviousTrack = true, - Position = 1, - PostGap = new TimeSpan(0, 0, 2), - PreGap = new TimeSpan(0, 0, 4), - Flags = [Flag.FourCH, Flag.DCP] - }; - var target = new Track(); - // Act - _trackManager.CopyValues(source, target); - // Assert - Assert.AreEqual(source.Artist, target.Artist); - Assert.AreEqual(source.Title, target.Title); - Assert.AreEqual(source.Begin, target.Begin); - Assert.AreEqual(source.End, target.End); - Assert.AreEqual(source.IsLinkedToPreviousTrack, target.IsLinkedToPreviousTrack); - Assert.AreEqual(source.Position, target.Position); - Assert.AreEqual(source.PostGap, target.PostGap); - Assert.AreEqual(source.PreGap, target.PreGap); - Assert.AreEquivalent(source.Flags, target.Flags); - Assert.AreEqual(source.Length, target.Length); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == target)), Times.Exactly(9)); - } + [TestMethod] + public void CopyValues_AllDefaultValues_CopiesAllValues() + { + // Arrange + var source = new Track() + { + Artist = "Artist 1", + Title = "Title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 2, 54), + IsLinkedToPreviousTrack = true, + Position = 1, + PostGap = new TimeSpan(0, 0, 2), + PreGap = new TimeSpan(0, 0, 4), + Flags = [Flag.FourCH, Flag.DCP] + }; + var target = new Track(); + // Act + _trackManager.CopyValues(source, target); + // Assert + Assert.AreEqual(source.Artist, target.Artist); + Assert.AreEqual(source.Title, target.Title); + Assert.AreEqual(source.Begin, target.Begin); + Assert.AreEqual(source.End, target.End); + Assert.AreEqual(source.IsLinkedToPreviousTrack, target.IsLinkedToPreviousTrack); + Assert.AreEqual(source.Position, target.Position); + Assert.AreEqual(source.PostGap, target.PostGap); + Assert.AreEqual(source.PreGap, target.PreGap); + Assert.AreEquivalent(source.Flags, target.Flags); + Assert.AreEqual(source.Length, target.Length); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == target)), Times.Exactly(9)); + } - [TestMethod] - public void CopyValues_ValuesSet_CopiesOnlySetValues() - { - // Arrange - var source = new Track() - { - Artist = "Artist 1", - Title = "Title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 2, 54), - IsLinkedToPreviousTrack = true, - Position = 1, - PostGap = new TimeSpan(0, 0, 2), - PreGap = new TimeSpan(0, 0, 4), - Flags = [Flag.FourCH, Flag.DCP] - }; - var target = new Track(); - // Act - _trackManager.CopyValues(source, target, setBegin: false, setPostGap:false, setLength: false, setFlags: false); - // Assert - Assert.AreEqual(source.Artist, target.Artist); - Assert.AreEqual(source.Title, target.Title); - Assert.AreNotEqual(source.Begin, target.Begin); - Assert.AreEqual(source.End, target.End); - Assert.AreEqual(source.IsLinkedToPreviousTrack, target.IsLinkedToPreviousTrack); - Assert.AreEqual(source.Position, target.Position); - Assert.AreNotEqual(source.PostGap, target.PostGap); - Assert.AreEqual(source.PreGap, target.PreGap); - Assert.AreNotEquivalent(source.Flags, target.Flags); - Assert.AreNotEqual(source.Length, target.Length); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == target)), Times.Exactly(6)); - } + [TestMethod] + public void CopyValues_ValuesSet_CopiesOnlySetValues() + { + // Arrange + var source = new Track() + { + Artist = "Artist 1", + Title = "Title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 2, 54), + IsLinkedToPreviousTrack = true, + Position = 1, + PostGap = new TimeSpan(0, 0, 2), + PreGap = new TimeSpan(0, 0, 4), + Flags = [Flag.FourCH, Flag.DCP] + }; + var target = new Track(); + // Act + _trackManager.CopyValues(source, target, setBegin: false, setPostGap:false, setLength: false, setFlags: false); + // Assert + Assert.AreEqual(source.Artist, target.Artist); + Assert.AreEqual(source.Title, target.Title); + Assert.AreNotEqual(source.Begin, target.Begin); + Assert.AreEqual(source.End, target.End); + Assert.AreEqual(source.IsLinkedToPreviousTrack, target.IsLinkedToPreviousTrack); + Assert.AreEqual(source.Position, target.Position); + Assert.AreNotEqual(source.PostGap, target.PostGap); + Assert.AreEqual(source.PreGap, target.PreGap); + Assert.AreNotEquivalent(source.Flags, target.Flags); + Assert.AreNotEqual(source.Length, target.Length); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == target)), Times.Exactly(6)); + } - [TestMethod] - public void GetPreviousLinkedTrack_LinkedTracks_ReturnsTrack() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 1 - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); - // Assert - Assert.IsNotNull(linkedTrack); - Assert.AreEqual(track1, linkedTrack); - } + [TestMethod] + public void GetPreviousLinkedTrack_LinkedTracks_ReturnsTrack() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 1 + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); + // Assert + Assert.IsNotNull(linkedTrack); + Assert.AreEqual(track1, linkedTrack); + } - [TestMethod] - public void GetPreviousLinkedTrack_NotLinkedTracks_ReturnsNull() - { - // Arrange - var track1 = new Track() - { - Position = 1 - }; - var track2 = new Track() - { - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); - // Assert - Assert.IsNull(linkedTrack); - } + [TestMethod] + public void GetPreviousLinkedTrack_NotLinkedTracks_ReturnsNull() + { + // Arrange + var track1 = new Track() + { + Position = 1 + }; + var track2 = new Track() + { + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); + // Assert + Assert.IsNull(linkedTrack); + } - [TestMethod] - public void GetPreviousLinkedTrack_WithoutPosition_ReturnsNull() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 1 - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); - // Assert - Assert.IsNull(linkedTrack); - } + [TestMethod] + public void GetPreviousLinkedTrack_WithoutPosition_ReturnsNull() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 1 + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); + // Assert + Assert.IsNull(linkedTrack); + } - [TestMethod] - public void GetPreviousLinkedTrack_WithBegin_ReturnsTrack() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 6, 37) - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Begin = track1.End - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); - // Assert - Assert.IsNotNull(linkedTrack); - Assert.AreEqual(track1, linkedTrack); - } + [TestMethod] + public void GetPreviousLinkedTrack_WithBegin_ReturnsTrack() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 6, 37) + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Begin = track1.End + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetPreviousLinkedTrack(track2); + // Assert + Assert.IsNotNull(linkedTrack); + Assert.AreEqual(track1, linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_LinkedTracks_ReturnsTrack() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 1 - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNotNull(linkedTrack); - Assert.AreEqual(track2, linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_LinkedTracks_ReturnsTrack() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 1 + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNotNull(linkedTrack); + Assert.AreEqual(track2, linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_NotLinkedTracks_ReturnsNull() - { - // Arrange - var track1 = new Track() - { - Position = 1 - }; - var track2 = new Track() - { - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNull(linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_NotLinkedTracks_ReturnsNull() + { + // Arrange + var track1 = new Track() + { + Position = 1 + }; + var track2 = new Track() + { + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNull(linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_WithoutPosition_ReturnsNull() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNull(linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_WithoutPosition_ReturnsNull() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNull(linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_WithBegin_ReturnsTrack() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 8, 32) - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 2, - Begin = track1.End, - End = new TimeSpan(0, 13, 54) - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNotNull(linkedTrack); - Assert.AreEqual(track2, linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_WithBegin_ReturnsTrack() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 8, 32) + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 2, + Begin = track1.End, + End = new TimeSpan(0, 13, 54) + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNotNull(linkedTrack); + Assert.AreEqual(track2, linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_OnlyOneTrack_ReturnsNull() - { - // Arrange - var track1 = new Track() - { - IsLinkedToPreviousTrack = true, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 8, 32) - }; - var cuesheet = new Cuesheet(); - track1.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNull(linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_OnlyOneTrack_ReturnsNull() + { + // Arrange + var track1 = new Track() + { + IsLinkedToPreviousTrack = true, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 8, 32) + }; + var cuesheet = new Cuesheet(); + track1.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNull(linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_MultiplePositions_ReturnsTrack() - { - // Arrange - var track1 = new Track() - { - Position = 1, - IsLinkedToPreviousTrack = true, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 8, 32) - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 2, - Begin = track1.End, - End = new TimeSpan(0, 13, 54) - }; - var track3 = new Track() - { - IsLinkedToPreviousTrack = true, - Position = 2, - Begin = track2.End, - End = new TimeSpan(0, 17, 32) - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2, track3] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNotNull(linkedTrack); - Assert.AreEqual(track2, linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_MultiplePositions_ReturnsTrack() + { + // Arrange + var track1 = new Track() + { + Position = 1, + IsLinkedToPreviousTrack = true, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 8, 32) + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 2, + Begin = track1.End, + End = new TimeSpan(0, 13, 54) + }; + var track3 = new Track() + { + IsLinkedToPreviousTrack = true, + Position = 2, + Begin = track2.End, + End = new TimeSpan(0, 17, 32) + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2, track3] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNotNull(linkedTrack); + Assert.AreEqual(track2, linkedTrack); + } - [TestMethod] - public void GetNextLinkedTrack_WithPosition_ReturnsTrack() - { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }; - var track2 = new Track() - { - Begin = track1.End, - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - var linkedTrack = _trackManager.GetNextLinkedTrack(track1); - // Assert - Assert.IsNotNull(linkedTrack); - Assert.AreEqual(track2, linkedTrack); - } + [TestMethod] + public void GetNextLinkedTrack_WithPosition_ReturnsTrack() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }; + var track2 = new Track() + { + Begin = track1.End, + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + var linkedTrack = _trackManager.GetNextLinkedTrack(track1); + // Assert + Assert.IsNotNull(linkedTrack); + Assert.AreEqual(track2, linkedTrack); + } - [TestMethod] - public void RecalculateLinkedTracksProperties_TrackHasNoBegin_SetsBegin() - { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }; - var track2 = new Track() - { - Position = 2, - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - _trackManager.RecalculateLinkedTracksProperties(track2); - // Assert - Assert.AreEqual(track1.End, track2.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Begin))), Times.Once); - } + [TestMethod] + public void RecalculateLinkedTracksProperties_TrackHasNoBegin_SetsBegin() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }; + var track2 = new Track() + { + Position = 2, + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + _trackManager.RecalculateLinkedTracksProperties(track2); + // Assert + Assert.AreEqual(track1.End, track2.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Begin))), Times.Once); + } - [TestMethod] - public void RecalculateLinkedTracksProperties_TrackHasNoPosition_SetsPosition() - { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }; - var track2 = new Track() - { - IsLinkedToPreviousTrack = true, - Begin = track1.End - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - _trackManager.RecalculateLinkedTracksProperties(track2); - // Assert - Assert.AreEqual((ushort?)2, track2.Position); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Position))), Times.Once); - } + [TestMethod] + public void RecalculateLinkedTracksProperties_TrackHasNoPosition_SetsPosition() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }; + var track2 = new Track() + { + IsLinkedToPreviousTrack = true, + Begin = track1.End + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + _trackManager.RecalculateLinkedTracksProperties(track2); + // Assert + Assert.AreEqual((ushort?)2, track2.Position); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Position))), Times.Once); + } - [TestMethod] - public void RecalculateLinkedTracksProperties_PreviousTrackHasNoEnd_SetsEnd() - { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - }; - var track2 = new Track() - { - Position = 2, - IsLinkedToPreviousTrack = true, - Begin = new TimeSpan(0, 3, 12) - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - _trackManager.RecalculateLinkedTracksProperties(track2); - // Assert - Assert.AreEqual(track2.Begin, track1.End); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track1 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.End))), Times.Once); - } + [TestMethod] + public void RecalculateLinkedTracksProperties_PreviousTrackHasNoEnd_SetsEnd() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + }; + var track2 = new Track() + { + Position = 2, + IsLinkedToPreviousTrack = true, + Begin = new TimeSpan(0, 3, 12) + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + _trackManager.RecalculateLinkedTracksProperties(track2); + // Assert + Assert.AreEqual(track2.Begin, track1.End); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track1 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.End))), Times.Once); + } - [TestMethod] - public void RecalculateLinkedTracksProperties_NextTrackNoPosition_SetsPosition() - { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }; - var track2 = new Track() - { - Begin = track1.End, - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - _trackManager.RecalculateLinkedTracksProperties(track1); - // Assert - Assert.AreEqual((ushort?)2, track2.Position); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Position))), Times.Once); - } + [TestMethod] + public void RecalculateLinkedTracksProperties_NextTrackNoPosition_SetsPosition() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }; + var track2 = new Track() + { + Begin = track1.End, + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + _trackManager.RecalculateLinkedTracksProperties(track1); + // Assert + Assert.AreEqual((ushort?)2, track2.Position); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Position))), Times.Once); + } - [TestMethod] - public void RecalculateLinkedTracksProperties_NextTrackNoBegin_SetsBegin() - { - // Arrange - var track1 = new Track() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) - }; - var track2 = new Track() - { - Position = 2, - IsLinkedToPreviousTrack = true - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - { - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - // Act - _trackManager.RecalculateLinkedTracksProperties(track1); - // Assert - Assert.AreEqual(track1.End, track2.Begin); - _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Begin))), Times.Once); - } + [TestMethod] + public void RecalculateLinkedTracksProperties_NextTrackNoBegin_SetsBegin() + { + // Arrange + var track1 = new Track() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 12) + }; + var track2 = new Track() + { + Position = 2, + IsLinkedToPreviousTrack = true + }; + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() + { + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + // Act + _trackManager.RecalculateLinkedTracksProperties(track1); + // Assert + Assert.AreEqual(track1.End, track2.Begin); + _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Begin))), Times.Once); } } diff --git a/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs index 751e3aaa..5bca1388 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -23,98 +23,97 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass] +public class AudioImportServiceTests { - [TestClass] - public class AudioImportServiceTests + readonly AudioImportService _service; + readonly Mock _dialogManager; + readonly Mock _sessionStateContainer; + readonly Mock _cuesheetManager; + + public AudioImportServiceTests() { - private readonly AudioImportService _service; - private readonly Mock _dialogManager; - private readonly Mock _sessionStateContainer; - private readonly Mock _cuesheetManager; + _dialogManager = new(); + _sessionStateContainer = new(); + _cuesheetManager = new(); + _service = new(_dialogManager.Object, _sessionStateContainer.Object, _cuesheetManager.Object); + } - public AudioImportServiceTests() - { - _dialogManager = new(); - _sessionStateContainer = new(); - _cuesheetManager = new(); - _service = new(_dialogManager.Object, _sessionStateContainer.Object, _cuesheetManager.Object); - } + [TestMethod] + public async Task MapAudioImportAsync_WhenMappingIsNotRequired_ReturnsTrueAsync() + { + // Arrange + var cuesheet = new Cuesheet(); + var importAudiofileMapping = new Dictionary(); + _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); + _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); + _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny>()).Callback>(cs => importAudiofileMapping = cs); + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns([]); + _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = await _service.MapAudioImportAsync(); + // Assert + Assert.IsTrue(result); + } - [TestMethod] - public async Task MapAudioImportAsync_WhenMappingIsNotRequired_ReturnsTrueAsync() + [TestMethod] + public async Task MapAudioImportAsync_WhenMappingIsRequiredAndDoneAutomatically_ReturnsTrueAsync() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet(); - var importAudiofileMapping = new Dictionary(); - _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); - _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); - _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny>()).Callback>(cs => importAudiofileMapping = cs); - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns([]); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = await _service.MapAudioImportAsync(); - // Assert - Assert.IsTrue(result); - } + Audiofiles = [ + new() + ] + }; + var importAudiofileMapping = new Dictionary + { + { new(), null } + }; + var importAudioFiles = new List + { + new() + }; + _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); + _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); + _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny>()).Callback>(cs => importAudiofileMapping = cs); + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); + _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = await _service.MapAudioImportAsync(); + // Assert + Assert.IsTrue(result); + } - [TestMethod] - public async Task MapAudioImportAsync_WhenMappingIsRequiredAndDoneAutomatically_ReturnsTrueAsync() + [TestMethod] + public async Task MapAudioImportAsync_WhenMappingIsRequiredAndCannotBeDoneAutomatically_ReturnsDialogResultAsync() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - ] - }; - var importAudiofileMapping = new Dictionary - { - { new(), null } - }; - var importAudioFiles = new List - { + Audiofiles = [ new() - }; - _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); - _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); - _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny>()).Callback>(cs => importAudiofileMapping = cs); - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = await _service.MapAudioImportAsync(); - // Assert - Assert.IsTrue(result); - } - - [TestMethod] - public async Task MapAudioImportAsync_WhenMappingIsRequiredAndCannotBeDoneAutomatically_ReturnsDialogResultAsync() + ] + }; + var importAudiofileMapping = new Dictionary + { + { new(), null } + }; + var importAudioFiles = new List { - // Arrange - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() - ] - }; - var importAudiofileMapping = new Dictionary - { - { new(), null } - }; - var importAudioFiles = new List - { - new(), new() - }; - var dialogResultAborted = true; - _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(dialogResultAborted); - _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); - _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny>()).Callback>(cs => importAudiofileMapping = cs); - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); - // Act - var result = await _service.MapAudioImportAsync(); - // Assert - Assert.AreEqual(!dialogResultAborted, result); - } + new(), new() + }; + var dialogResultAborted = true; + _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(dialogResultAborted); + _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); + _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny>()).Callback>(cs => importAudiofileMapping = cs); + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); + _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); + // Act + var result = await _service.MapAudioImportAsync(); + // Assert + Assert.AreEqual(!dialogResultAborted, result); } } diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs index 622d6607..5c48c554 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -24,194 +24,194 @@ using System; using System.Linq; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass()] +public class CuesheetExportServiceTests { - [TestClass()] - public class CuesheetExportServiceTests + readonly Mock _sessionStateContainerMock; + readonly Mock> _localizerMock; + readonly CuesheetExportService _cuesheetExportService; + + public CuesheetExportServiceTests() { - private readonly Mock _sessionStateContainerMock; - private readonly Mock> _localizerMock; - private readonly CuesheetExportService _cuesheetExportService; + _sessionStateContainerMock = new Mock(); + _localizerMock = new Mock>(); + _cuesheetExportService = new CuesheetExportService(_sessionStateContainerMock.Object, _localizerMock.Object); + } - public CuesheetExportServiceTests() - { - _sessionStateContainerMock = new Mock(); - _localizerMock = new Mock>(); - _cuesheetExportService = new CuesheetExportService(_sessionStateContainerMock.Object, _localizerMock.Object); - } + [TestMethod] + public void CanGenerateExportfile_InvalidExtension_ReturnsValidationMessage() + { + // Arrange + string invalidFilename = "test.txt"; + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); + _localizerMock.Setup(x => x["File extension is not '{0}'", It.IsAny()]).Returns(new LocalizedString("File extension is not '{0}'", "File extension is not '{0}'")); - [TestMethod] - public void CanGenerateExportfile_InvalidExtension_ReturnsValidationMessage() + // Act + var result = _cuesheetExportService.CanGenerateExportfile(invalidFilename); + + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.IsTrue(result.Error?.Message.Contains("File extension is not")); + } + + [TestMethod] + public void CanGenerateExportfile_InvalidAudiofileName_ReturnsValidationMessage() + { + // Arrange + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet() { - // Arrange - string invalidFilename = "test.txt"; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); - _localizerMock.Setup(x => x["File extension is not '{0}'", It.IsAny()]).Returns(new LocalizedString("File extension is not '{0}'", "File extension is not '{0}'")); + Audiofiles = [new()] + }); + _localizerMock.Setup(x => x["{0} has no value!", It.IsAny()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _localizerMock.Setup(x => x[nameof(Audiofile.Name)]).Returns(new LocalizedString(nameof(Audiofile.Name), nameof(Audiofile.Name))); + + // Act + var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); - // Act - var result = _cuesheetExportService.CanGenerateExportfile(invalidFilename); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Audiofile.Name)} has no value!")); + } + + [TestMethod] + public void CanGenerateExportfile_InvalidCuesheeetTitle_ReturnsValidationMessage() + { + // Arrange + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); + _localizerMock.Setup(x => x["{0} has no value!", It.IsAny()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _localizerMock.Setup(x => x[nameof(Cuesheet.Title)]).Returns(new LocalizedString(nameof(Cuesheet.Title), nameof(Cuesheet.Title))); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains("File extension is not")); - } + // Act + var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); + + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Cuesheet.Title)} has no value!")); + } - [TestMethod] - public void CanGenerateExportfile_InvalidAudiofileName_ReturnsValidationMessage() + [TestMethod] + public void CanGenerateExportfile_InvalidTrackEnd_ReturnsValidationMessage() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet() - { - Audiofiles = [new()] - }); - _localizerMock.Setup(x => x["{0} has no value!", It.IsAny()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); - _localizerMock.Setup(x => x[nameof(Audiofile.Name)]).Returns(new LocalizedString(nameof(Audiofile.Name), nameof(Audiofile.Name))); - - // Act - var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); - - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Audiofile.Name)} has no value!")); - } - - [TestMethod] - public void CanGenerateExportfile_InvalidCuesheeetTitle_ReturnsValidationMessage() + Artist = "Test Artist", + Title = "Test Title", + Audiofiles = + [ + new() + { + Name = "Test audiofile.mp3", + Tracks = + [ + new() + { + Position = 1, + Begin = TimeSpan.Zero + } + ] + } + ], + + }; + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + _localizerMock.Setup(x => x["{0} has no value!", It.IsAny()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _localizerMock.Setup(x => x[nameof(Track.End)]).Returns(new LocalizedString(nameof(Track.End), nameof(Track.End))); + + // Act + var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); + + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Track.End)} has no value!")); + } + + [TestMethod] + public void CanGenerateExportfiles_ValidExtension_ReturnsSuccess() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); - _localizerMock.Setup(x => x["{0} has no value!", It.IsAny()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); - _localizerMock.Setup(x => x[nameof(Cuesheet.Title)]).Returns(new LocalizedString(nameof(Cuesheet.Title), nameof(Cuesheet.Title))); + Artist = "Test Artist", + Title = "Test Title", + Audiofiles = + [ + new() + { + Name = "Test audiofile.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Tracks = + [ + new() + { + Position = 1, + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 3, 43) + } + ] + } + ], - // Act - var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); + }; + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Cuesheet.Title)} has no value!")); - } + // Act + var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); - [TestMethod] - public void CanGenerateExportfile_InvalidTrackEnd_ReturnsValidationMessage() + // Assert + Assert.IsTrue(result.IsSuccess); + } + + [TestMethod] + public void GenerateExportfiles_SingleAudiofile_ReturnsExportFile() + { + // Arrange + var filename = "Test valid Filename.cue"; + var track1 = new Track() { - // Arrange - var cuesheet = new Cuesheet() - { - Artist = "Test Artist", - Title = "Test Title", - Audiofiles = - [ - new() - { - Name = "Test audiofile.mp3", - Tracks = - [ - new() - { - Position = 1, - Begin = TimeSpan.Zero - } - ] - } - ], - - }; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - _localizerMock.Setup(x => x["{0} has no value!", It.IsAny()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); - _localizerMock.Setup(x => x[nameof(Track.End)]).Returns(new LocalizedString(nameof(Track.End), nameof(Track.End))); - - // Act - var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); - - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Track.End)} has no value!")); - } - - [TestMethod] - public void CanGenerateExportfiles_ValidExtension_ReturnsSuccess() + Artist = "Test artist 1", + Title = "Test title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 4, 12), + Position = 1 + }; + var track2 = new Track() { - // Arrange - var cuesheet = new Cuesheet() - { - Artist = "Test Artist", - Title = "Test Title", - Audiofiles = - [ - new() - { - Name = "Test audiofile.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Tracks = - [ - new() - { - Position = 1, - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 43) - } - ] - } - ], - - }; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - - // Act - var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); - - // Assert - Assert.IsTrue(result.IsSuccess); - } - - [TestMethod] - public void GenerateExportfiles_SingleAudiofile_ReturnsExportFile() + Artist = "Test artist 2", + Title = "Test title 2", + Begin = track1.End, + End = new TimeSpan(0, 8, 32), + Position = 2 + }; + var cuesheet = new Cuesheet() { - // Arrange - var filename = "Test valid Filename.cue"; - var track1 = new Track() - { - Artist = "Test artist 1", - Title = "Test title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), - Position = 1 - }; - var track2 = new Track() - { - Artist = "Test artist 2", - Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Artist = "Test artist cuesheet", - Title = "Test title cuesheet", - Audiofiles = - [ - new() - { - Name = "Test audiofile.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - - // Act - var result = _cuesheetExportService.GenerateExportfile(filename); - - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual(filename, result.Value!.Name); - var content = result.Value!.Content; - Assert.IsNotNull(content); - Assert.AreEqual(@"TITLE ""Test title cuesheet"" + Artist = "Test artist cuesheet", + Title = "Test title cuesheet", + Audiofiles = + [ + new() + { + Name = "Test audiofile.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + + // Act + var result = _cuesheetExportService.GenerateExportfile(filename); + + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual(filename, result.Value!.Name); + var content = result.Value!.Content; + Assert.IsNotNull(content); + Assert.AreEqual(@"TITLE ""Test title cuesheet"" PERFORMER ""Test artist cuesheet"" FILE ""Test audiofile.mp3"" MP3 TRACK 01 AUDIO @@ -223,80 +223,80 @@ TRACK 02 AUDIO PERFORMER ""Test artist 2"" INDEX 01 04:12:00 ", content); - } + } - [TestMethod] - public void GenerateExportfiles_MultipleAudiofiles_ReturnsExportFile() + [TestMethod] + public void GenerateExportfiles_MultipleAudiofiles_ReturnsExportFile() + { + // Arrange + var filename = "Test valid Filename.cue"; + var track1 = new Track() + { + Artist = "Test artist 1", + Title = "Test title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 4, 12), + Position = 1 + }; + var track2 = new Track() { - // Arrange - var filename = "Test valid Filename.cue"; - var track1 = new Track() - { - Artist = "Test artist 1", - Title = "Test title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), - Position = 1 - }; - var track2 = new Track() - { - Artist = "Test artist 2", - Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), - Position = 2 - }; - var track3 = new Track() - { - Artist = "Test artist 3", - Title = "Test title 3", - Begin = track2.End, - End = new TimeSpan(0, 12, 43), - Position = 3 - }; - var track4 = new Track() - { - Artist = "Test artist 4", - Title = "Test title 4", - Begin = track3.End, - End = new TimeSpan(0, 15, 54), - Position = 4 - }; - var cuesheet = new Cuesheet() - { - Artist = "Test artist cuesheet", - Title = "Test title cuesheet", - Audiofiles = - [ - new() - { - Name = "Test audiofile.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Tracks = [track1, track2] - }, - new() - { - Name = "Test audiofile2.wav", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".wav"), - Tracks = [track3, track4] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track3.Cuesheet = cuesheet; - track4.Cuesheet = cuesheet; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - - // Act - var result = _cuesheetExportService.GenerateExportfile(filename); - - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual(filename, result.Value!.Name); - var content = result.Value!.Content; - Assert.IsNotNull(content); - Assert.AreEqual(@"TITLE ""Test title cuesheet"" + Artist = "Test artist 2", + Title = "Test title 2", + Begin = track1.End, + End = new TimeSpan(0, 8, 32), + Position = 2 + }; + var track3 = new Track() + { + Artist = "Test artist 3", + Title = "Test title 3", + Begin = track2.End, + End = new TimeSpan(0, 12, 43), + Position = 3 + }; + var track4 = new Track() + { + Artist = "Test artist 4", + Title = "Test title 4", + Begin = track3.End, + End = new TimeSpan(0, 15, 54), + Position = 4 + }; + var cuesheet = new Cuesheet() + { + Artist = "Test artist cuesheet", + Title = "Test title cuesheet", + Audiofiles = + [ + new() + { + Name = "Test audiofile.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Tracks = [track1, track2] + }, + new() + { + Name = "Test audiofile2.wav", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".wav"), + Tracks = [track3, track4] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track3.Cuesheet = cuesheet; + track4.Cuesheet = cuesheet; + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + + // Act + var result = _cuesheetExportService.GenerateExportfile(filename); + + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual(filename, result.Value!.Name); + var content = result.Value!.Content; + Assert.IsNotNull(content); + Assert.AreEqual(@"TITLE ""Test title cuesheet"" PERFORMER ""Test artist cuesheet"" FILE ""Test audiofile.mp3"" MP3 TRACK 01 AUDIO @@ -317,43 +317,42 @@ TRACK 04 AUDIO PERFORMER ""Test artist 4"" INDEX 01 12:43:00 ", content); - } + } - [TestMethod] - public void GenerateExportfiles_WithInvalidTracks_ReturnsFailure() + [TestMethod] + public void GenerateExportfiles_WithInvalidTracks_ReturnsFailure() + { + // Arrange + var cuesheet = new Cuesheet() { - // Arrange - var cuesheet = new Cuesheet() - { - Artist = "Test Artist", - Title = "Test Title", - Audiofiles = - [ - new () - { - Name = "Audio.mp3", - Tracks = - [ - new() - { - Position = 1, - Begin = TimeSpan.Zero, - }, - new() - { - Position = 2, - } - ] - } - ] - }; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - - // Act - var result = _cuesheetExportService.GenerateExportfile("test.cue"); - - // Assert - Assert.IsFalse(result.IsSuccess); - } + Artist = "Test Artist", + Title = "Test Title", + Audiofiles = + [ + new () + { + Name = "Audio.mp3", + Tracks = + [ + new() + { + Position = 1, + Begin = TimeSpan.Zero, + }, + new() + { + Position = 2, + } + ] + } + ] + }; + _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + + // Act + var result = _cuesheetExportService.GenerateExportfile("test.cue"); + + // Assert + Assert.IsFalse(result.IsSuccess); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs index 679262ec..6654cd35 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -20,16 +20,16 @@ using System.IO; using System.Linq; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass()] +public class CuesheetImportServiceTests { - [TestClass()] - public class CuesheetImportServiceTests + [TestMethod()] + public void Analyse_WithSampleCuesheet_CreatesValidCuesheet() { - [TestMethod()] - public void Analyse_WithSampleCuesheet_CreatesValidCuesheet() - { - // Arrange - var fileContent = @"PERFORMER ""Sample CD Artist"" + // Arrange + var fileContent = @"PERFORMER ""Sample CD Artist"" TITLE ""Sample CD Title"" FILE ""AC DC - TNT.mp3"" MP3 CDTEXTFILE ""Testfile.cdt"" @@ -66,74 +66,74 @@ TRACK 08 AUDIO PERFORMER ""Sample Artist 8"" TITLE ""Sample Title 8"" INDEX 01 45:51:00"; - // Act - var importFile = CuesheetImportService.Analyse(fileContent); - // Assert - Assert.IsNotNull(importFile); - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.IsNotNull(importFile.FileContentRecognized); - var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample CD Artist\""), lines.ElementAt(0)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample CD Title\""), lines.ElementAt(1)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "FILE \"AC DC - TNT.mp3\" MP3"), lines.ElementAt(2)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CDTEXTFILE \"Testfile.cdt\""), lines.ElementAt(3)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CATALOG 0123456789012"), lines.ElementAt(4)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TRACK 01 AUDIO"), lines.ElementAt(5)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample Artist 1\"")), lines.ElementAt(6)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample Title 1\"")), lines.ElementAt(7)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "INDEX 01 00:00:00")), lines.ElementAt(8)); - } + // Act + var importFile = CuesheetImportService.Analyse(fileContent); + // Assert + Assert.IsNotNull(importFile); + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.IsNotNull(importFile.FileContentRecognized); + var lines = importFile.FileContentRecognized.Split(Environment.NewLine); + Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample CD Artist\""), lines.ElementAt(0)); + Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample CD Title\""), lines.ElementAt(1)); + Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "FILE \"AC DC - TNT.mp3\" MP3"), lines.ElementAt(2)); + Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CDTEXTFILE \"Testfile.cdt\""), lines.ElementAt(3)); + Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CATALOG 0123456789012"), lines.ElementAt(4)); + Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TRACK 01 AUDIO"), lines.ElementAt(5)); + Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample Artist 1\"")), lines.ElementAt(6)); + Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample Title 1\"")), lines.ElementAt(7)); + Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "INDEX 01 00:00:00")), lines.ElementAt(8)); + } - [TestMethod()] - public void Analyse_WithCuesheetBug30_CreatesValidCuesheet() - { - //Arrange - var fileContent = File.ReadAllText("Resources/Playlist-Bug#30.cue"); - //Act - var importFile = CuesheetImportService.Analyse(fileContent); - //Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - } + [TestMethod()] + public void Analyse_WithCuesheetBug30_CreatesValidCuesheet() + { + //Arrange + var fileContent = File.ReadAllText("Resources/Playlist-Bug#30.cue"); + //Act + var importFile = CuesheetImportService.Analyse(fileContent); + //Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + } - [TestMethod()] - public void Analyse_WithCuesheetBug57_CreatesValidCuesheet() - { - //Arrange - var fileContent = File.ReadAllText("Resources/Playlist-Bug#57.cue"); - //Act - var importFile = CuesheetImportService.Analyse(fileContent); - //Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(39, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual(new TimeSpan(2, 8, 21), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(24).Begin); - } + [TestMethod()] + public void Analyse_WithCuesheetBug57_CreatesValidCuesheet() + { + //Arrange + var fileContent = File.ReadAllText("Resources/Playlist-Bug#57.cue"); + //Act + var importFile = CuesheetImportService.Analyse(fileContent); + //Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(39, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual(new TimeSpan(2, 8, 21), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(24).Begin); + } - [TestMethod()] - public void Analyse_WithCuesheetBug36_CreatesValidCuesheet() - { - //Arrange - var fileContent = File.ReadAllText("Resources/Playlist-#36-Frames.cue"); - //Act - var importFile = CuesheetImportService.Analyse(fileContent); - //Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(12, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual(new TimeSpan(0, 0, 9, 15, 600), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).Begin); - } + [TestMethod()] + public void Analyse_WithCuesheetBug36_CreatesValidCuesheet() + { + //Arrange + var fileContent = File.ReadAllText("Resources/Playlist-#36-Frames.cue"); + //Act + var importFile = CuesheetImportService.Analyse(fileContent); + //Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(12, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual(new TimeSpan(0, 0, 9, 15, 600), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).Begin); + } - [TestMethod()] - public void Analyse_WithCDTextFileCatalogueNumberAndPreAndPostGap_CreatesValidCuesheet() - { - // Arrange - var fileContent = @"PERFORMER ""Sample CD Artist"" + [TestMethod()] + public void Analyse_WithCDTextFileCatalogueNumberAndPreAndPostGap_CreatesValidCuesheet() + { + // Arrange + var fileContent = @"PERFORMER ""Sample CD Artist"" TITLE ""Sample CD Title"" FILE ""Sample Audiofile.mp3"" MP3 CDTEXTFILE ""Testfile.cdt"" @@ -175,26 +175,25 @@ TRACK 08 AUDIO PERFORMER ""Sample Artist 8"" TITLE ""Sample Title 8"" INDEX 01 25:51:00"; - // Act - var importFile = CuesheetImportService.Analyse(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.IsNotNull(importFile.FileContentRecognized); - var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "FLAGS 4CH DCP PRE SCMS")), lines.ElementAt(8)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PREGAP 00:04:00")), lines.ElementAt(36)); - Assert.HasCount(2, importFile.AnalyzedCuesheet.Audiofiles); - Assert.AreEqual("Sample Audiofile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); - Assert.AreEqual("Sample Input.wav", importFile.AnalyzedCuesheet.Audiofiles.Last().Name); - Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.IsNotNull(importFile.AnalyzedCuesheet.CDTextfile); - Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Flags); - Assert.HasCount(2, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Flags); - Assert.IsNotNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Flags.SingleOrDefault(x => x.CuesheetLabel == "DCP")); - Assert.IsNotNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Flags.SingleOrDefault(x => x.CuesheetLabel == "PRE")); - Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.Last().Tracks.ElementAt(0).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.Last().Tracks.ElementAt(2).PreGap); - } + // Act + var importFile = CuesheetImportService.Analyse(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.IsNotNull(importFile.FileContentRecognized); + var lines = importFile.FileContentRecognized.Split(Environment.NewLine); + Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "FLAGS 4CH DCP PRE SCMS")), lines.ElementAt(8)); + Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PREGAP 00:04:00")), lines.ElementAt(36)); + Assert.HasCount(2, importFile.AnalyzedCuesheet.Audiofiles); + Assert.AreEqual("Sample Audiofile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); + Assert.AreEqual("Sample Input.wav", importFile.AnalyzedCuesheet.Audiofiles.Last().Name); + Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.IsNotNull(importFile.AnalyzedCuesheet.CDTextfile); + Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Flags); + Assert.HasCount(2, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Flags); + Assert.IsNotNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Flags.SingleOrDefault(x => x.CuesheetLabel == "DCP")); + Assert.IsNotNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Flags.SingleOrDefault(x => x.CuesheetLabel == "PRE")); + Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.Last().Tracks.ElementAt(0).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.Last().Tracks.ElementAt(2).PreGap); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs index 047c6c47..6a480c66 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -25,187 +25,186 @@ using System; using System.Linq; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass] +public class ExportfileGeneratorTests { - [TestClass] - public class ExportfileGeneratorTests + readonly Mock _mockSessionStateContainer; + readonly ExportfileGenerator _exportfileGenerator; + + public ExportfileGeneratorTests() { - private readonly Mock _mockSessionStateContainer; - private readonly ExportfileGenerator _exportfileGenerator; + _mockSessionStateContainer = new Mock(); + var mockLocalizer = new Mock>(); + _exportfileGenerator = new ExportfileGenerator(_mockSessionStateContainer.Object, mockLocalizer.Object); + } - public ExportfileGeneratorTests() + [TestMethod] + public void GenerateExportFile_SeveralAudiofiles_ReturnsSuccess() + { + // Arrange + var exportProfile = new Exportprofile { - _mockSessionStateContainer = new Mock(); - var mockLocalizer = new Mock>(); - _exportfileGenerator = new ExportfileGenerator(_mockSessionStateContainer.Object, mockLocalizer.Object); - } - - [TestMethod] - public void GenerateExportFile_SeveralAudiofiles_ReturnsSuccess() + Name = "TestProfile", + SchemeHead = "%Cuesheet.Artist% - %Cuesheet.Title%", + SchemeAudiofiles = Exportprofile.SchemeAudiofileName, + SchemeTracks = "%Track.Position% %Track.Artist% - %Track.Title%", + Filename = "TestExport.txt" + }; + var track1 = new Track() + { + Artist = "Test artist 1", + Title = "Test title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 4, 12), + Position = 1 + }; + var track2 = new Track() { - // Arrange - var exportProfile = new Exportprofile - { - Name = "TestProfile", - SchemeHead = "%Cuesheet.Artist% - %Cuesheet.Title%", - SchemeAudiofiles = Exportprofile.SchemeAudiofileName, - SchemeTracks = "%Track.Position% %Track.Artist% - %Track.Title%", - Filename = "TestExport.txt" - }; - var track1 = new Track() - { - Artist = "Test artist 1", - Title = "Test title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), - Position = 1 - }; - var track2 = new Track() - { - Artist = "Test artist 2", - Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Artist = "Test artist cuesheet", - Title = "Test title cuesheet", - Audiofiles = [ - new() - { - Name = "Test audiofile.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Tracks = [track1] - }, - new() - { - Name = "Test audiofile 2.wav", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".wav"), - Tracks = [track1] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.Last(); - _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + Artist = "Test artist 2", + Title = "Test title 2", + Begin = track1.End, + End = new TimeSpan(0, 8, 32), + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Artist = "Test artist cuesheet", + Title = "Test title cuesheet", + Audiofiles = [ + new() + { + Name = "Test audiofile.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Tracks = [track1] + }, + new() + { + Name = "Test audiofile 2.wav", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".wav"), + Tracks = [track1] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.Last(); + _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - // Act - var result = _exportfileGenerator.GenerateExportfile(exportProfile); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual(exportProfile.Filename, result.Value!.Name); - var content = result.Value!.Content; - Assert.IsNotNull(content); - Assert.AreEqual(@"Test artist cuesheet - Test title cuesheet + // Act + var result = _exportfileGenerator.GenerateExportfile(exportProfile); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual(exportProfile.Filename, result.Value!.Name); + var content = result.Value!.Content; + Assert.IsNotNull(content); + Assert.AreEqual(@"Test artist cuesheet - Test title cuesheet Test audiofile.mp3 1 Test artist 1 - Test title 1 Test audiofile 2.wav 1 Test artist 1 - Test title 1 ", content); - } + } - [TestMethod] - public void GenerateExportFile_EmptyExportprofile_ReturnsSuccess() + [TestMethod] + public void GenerateExportFile_EmptyExportprofile_ReturnsSuccess() + { + // Arrange + var exportProfile = new Exportprofile(); + var track1 = new Track() + { + Artist = "Test artist 1", + Title = "Test title 1", + Begin = TimeSpan.Zero, + End = new TimeSpan(0, 4, 12), + Position = 1 + }; + var track2 = new Track() { - // Arrange - var exportProfile = new Exportprofile(); - var track1 = new Track() - { - Artist = "Test artist 1", - Title = "Test title 1", - Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), - Position = 1 - }; - var track2 = new Track() - { - Artist = "Test artist 2", - Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Artist = "Test artist cuesheet", - Title = "Test title cuesheet", - Audiofiles = [ - new() - { - Name = "Test audiofile.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + Artist = "Test artist 2", + Title = "Test title 2", + Begin = track1.End, + End = new TimeSpan(0, 8, 32), + Position = 2 + }; + var cuesheet = new Cuesheet() + { + Artist = "Test artist cuesheet", + Title = "Test title cuesheet", + Audiofiles = [ + new() + { + Name = "Test audiofile.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - // Act - var result = _exportfileGenerator.GenerateExportfile(exportProfile); + // Act + var result = _exportfileGenerator.GenerateExportfile(exportProfile); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.AreEqual(Exportprofile.DefaultFileName, result.Value!.Name); - Assert.IsNotNull(result.Value!.Content); - } + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.AreEqual(Exportprofile.DefaultFileName, result.Value!.Name); + Assert.IsNotNull(result.Value!.Content); + } - [TestMethod] - public void GenerateExportFile_ReturnsEmpty_WithInvalidTracks() + [TestMethod] + public void GenerateExportFile_ReturnsEmpty_WithInvalidTracks() + { + // Arrange + var exportProfile = new Exportprofile + { + Name = "TestProfile", + SchemeHead = "%Cuesheet.Artist% - %Cuesheet.Title%", + SchemeTracks = "%Track.Position% %Track.Artist% - %Track.Title%", + Filename = "TestExport.txt" + }; + var track1 = new Track() + { + Artist = "Test artist 1", + Title = "Test title 1", + Begin = TimeSpan.Zero, + Position = 1 + }; + var track2 = new Track() + { + Artist = "Test artist 2", + Title = "Test title 2", + Position = 2 + }; + var cuesheet = new Cuesheet() { - // Arrange - var exportProfile = new Exportprofile - { - Name = "TestProfile", - SchemeHead = "%Cuesheet.Artist% - %Cuesheet.Title%", - SchemeTracks = "%Track.Position% %Track.Artist% - %Track.Title%", - Filename = "TestExport.txt" - }; - var track1 = new Track() - { - Artist = "Test artist 1", - Title = "Test title 1", - Begin = TimeSpan.Zero, - Position = 1 - }; - var track2 = new Track() - { - Artist = "Test artist 2", - Title = "Test title 2", - Position = 2 - }; - var cuesheet = new Cuesheet() - { - Artist = "Test artist cuesheet", - Title = "Test title cuesheet", - Audiofiles = [ - new() - { - Name = "Test audiofile.mp3", - AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), - Tracks = [track1, track2] - } - ] - }; - track1.Cuesheet = cuesheet; - track2.Cuesheet = cuesheet; - track1.Audiofile = cuesheet.Audiofiles.First(); - track2.Audiofile = cuesheet.Audiofiles.First(); - _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + Artist = "Test artist cuesheet", + Title = "Test title cuesheet", + Audiofiles = [ + new() + { + Name = "Test audiofile.mp3", + AudioCodec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"), + Tracks = [track1, track2] + } + ] + }; + track1.Cuesheet = cuesheet; + track2.Cuesheet = cuesheet; + track1.Audiofile = cuesheet.Audiofiles.First(); + track2.Audiofile = cuesheet.Audiofiles.First(); + _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); - // Act - var result = _exportfileGenerator.GenerateExportfile(exportProfile); + // Act + var result = _exportfileGenerator.GenerateExportfile(exportProfile); - // Assert - Assert.IsFalse(result.IsSuccess); - } + // Assert + Assert.IsFalse(result.IsSuccess); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs index 90d6038e..9604c3b2 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -27,256 +27,255 @@ using System.Text; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass()] +public class FileInputManagerTests { - [TestClass()] - public class FileInputManagerTests - { - private readonly FileInputManager _service; - private readonly Mock _jsRuntimeMock = new(); + readonly FileInputManager _service; + readonly Mock _jsRuntimeMock = new(); - public FileInputManagerTests() - { - var loggerMock = new Mock>(); - _service = new FileInputManager(_jsRuntimeMock.Object, loggerMock.Object); - } + public FileInputManagerTests() + { + var loggerMock = new Mock>(); + _service = new FileInputManager(_jsRuntimeMock.Object, loggerMock.Object); + } - [TestMethod()] - public void CheckFileMimeType_ReturnsTrue_WhenContentTypeDoesNotMatchButExtension() - { - // Arrange - var fileName = "test.mp3"; - var contentType = "audio/wav"; + [TestMethod()] + public void CheckFileMimeType_ReturnsTrue_WhenContentTypeDoesNotMatchButExtension() + { + // Arrange + var fileName = "test.mp3"; + var contentType = "audio/wav"; - // Act - var result = _service.CheckFileMimeType(contentType, fileName, "audio/mpeg", [".mp3"]); + // Act + var result = _service.CheckFileMimeType(contentType, fileName, "audio/mpeg", [".mp3"]); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [TestMethod()] - public void CheckFileMimeType_ReturnsTrue_WhenContentTypeDoesMatchButNotExtension() - { - // Arrange - var fileName = "test.mpeg"; - var contentType = "audio/mpeg"; + [TestMethod()] + public void CheckFileMimeType_ReturnsTrue_WhenContentTypeDoesMatchButNotExtension() + { + // Arrange + var fileName = "test.mpeg"; + var contentType = "audio/mpeg"; - // Act - var result = _service.CheckFileMimeType(contentType, fileName, "audio/mpeg", [".mp3", ".txt"]); + // Act + var result = _service.CheckFileMimeType(contentType, fileName, "audio/mpeg", [".mp3", ".txt"]); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [TestMethod()] - public void CheckFileMimeType_ReturnsFalse_WhenExtensionDoesNotMatchAndContentTypeIsEmpty() - { - // Arrange - var fileName = "test.flac"; - var contentType = string.Empty; + [TestMethod()] + public void CheckFileMimeType_ReturnsFalse_WhenExtensionDoesNotMatchAndContentTypeIsEmpty() + { + // Arrange + var fileName = "test.flac"; + var contentType = string.Empty; - // Act - var result = _service.CheckFileMimeType(contentType, fileName, "audio/flac", [".mp3"]); + // Act + var result = _service.CheckFileMimeType(contentType, fileName, "audio/flac", [".mp3"]); - // Assert - Assert.IsFalse(result); - } + // Assert + Assert.IsFalse(result); + } - [TestMethod()] - public void CheckFileMimeType_ReturnsTrue_WhenContentTypeAndExtensionMatch() - { - // Arrange - var fileName = "test.wav"; - var contentType = "audio/wave"; + [TestMethod()] + public void CheckFileMimeType_ReturnsTrue_WhenContentTypeAndExtensionMatch() + { + // Arrange + var fileName = "test.wav"; + var contentType = "audio/wave"; - // Act - var result = _service.CheckFileMimeType(contentType, fileName, "audio/wave", [".wav"]); + // Act + var result = _service.CheckFileMimeType(contentType, fileName, "audio/wave", [".wav"]); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [TestMethod()] - public void CheckFileMimeType_ReturnsTrue_WhenContentMainTypeMatch() - { - // Arrange + [TestMethod()] + public void CheckFileMimeType_ReturnsTrue_WhenContentMainTypeMatch() + { + // Arrange - var fileName = "history.txt"; - var contentType = "text/plain"; + var fileName = "history.txt"; + var contentType = "text/plain"; - // Act - var result = _service.CheckFileMimeType(contentType, fileName, "text/*", [".txt", ".text"]); + // Act + var result = _service.CheckFileMimeType(contentType, fileName, "text/*", [".txt", ".text"]); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [TestMethod()] - public void IsValidAudiofile_ReturnsTrue_WithValidAudiocodec() - { - // Arrange - var fileName = "test.wav"; - var contentType = "audio/wav"; + [TestMethod()] + public void IsValidAudiofile_ReturnsTrue_WithValidAudiocodec() + { + // Arrange + var fileName = "test.wav"; + var contentType = "audio/wav"; - // Act - var result = _service.IsValidAudiofile(fileName, contentType); + // Act + var result = _service.IsValidAudiofile(fileName, contentType); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [TestMethod()] - public void IsValidAudiofile_ReturnsFalse_WithInvalidAudiocodecAndExtension() - { - // Arrange - var fileName = "test.mock"; - var contentType = "just a fantasy"; + [TestMethod()] + public void IsValidAudiofile_ReturnsFalse_WithInvalidAudiocodecAndExtension() + { + // Arrange + var fileName = "test.mock"; + var contentType = "just a fantasy"; - // Act - var result = _service.IsValidAudiofile(fileName, contentType); + // Act + var result = _service.IsValidAudiofile(fileName, contentType); - // Assert - Assert.IsFalse(result); - } + // Assert + Assert.IsFalse(result); + } - [TestMethod()] - public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeMatches() - { - // Arrange - var fileName = "test.wbem"; - var contentType = "audio/webm"; + [TestMethod()] + public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeMatches() + { + // Arrange + var fileName = "test.wbem"; + var contentType = "audio/webm"; - // Act - var result = _service.GetAudioCodec(fileName, contentType); + // Act + var result = _service.GetAudioCodec(fileName, contentType); - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(Audiofile.AudioCodecWEBM, result); - } + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(Audiofile.AudioCodecWEBM, result); + } - [TestMethod()] - public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeAndFileExtensionMatches() - { - // Arrange - var fileName = "test.wbem"; - var contentType = "audio/webm"; + [TestMethod()] + public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeAndFileExtensionMatches() + { + // Arrange + var fileName = "test.wbem"; + var contentType = "audio/webm"; - // Act - var result = _service.GetAudioCodec(fileName, contentType); + // Act + var result = _service.GetAudioCodec(fileName, contentType); - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(Audiofile.AudioCodecWEBM, result); - } + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(Audiofile.AudioCodecWEBM, result); + } - [TestMethod()] - public void GetAudioCodec_ReturnsNull_WhenContentTypeAndFileExtensionNotMatch() - { - // Arrange - var fileName = "test.acx"; - var contentType = "fantasy stuff"; + [TestMethod()] + public void GetAudioCodec_ReturnsNull_WhenContentTypeAndFileExtensionNotMatch() + { + // Arrange + var fileName = "test.acx"; + var contentType = "fantasy stuff"; - // Act - var result = _service.GetAudioCodec(fileName, contentType); + // Act + var result = _service.GetAudioCodec(fileName, contentType); - // Assert - Assert.IsNull(result); - } + // Assert + Assert.IsNull(result); + } - [TestMethod()] - public void GetAudioCodec_ReturnsAudiocodec_WhenFileExtensionMatches() - { - // Arrange - var fileName = "test.mP3"; + [TestMethod()] + public void GetAudioCodec_ReturnsAudiocodec_WhenFileExtensionMatches() + { + // Arrange + var fileName = "test.mP3"; - // Act - var result = _service.GetAudioCodec(fileName); + // Act + var result = _service.GetAudioCodec(fileName); - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(Audiofile.AudioCodecs.Single(x => x.FileExtension.Equals(".mp3", StringComparison.OrdinalIgnoreCase)), result); - } + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(Audiofile.AudioCodecs.Single(x => x.FileExtension.Equals(".mp3", StringComparison.OrdinalIgnoreCase)), result); + } - [TestMethod()] - public void IsValidForImportView_ReturnsTrue_WhenFileIsHtml() - { - // Arrange - var fileName = "test.html"; - var contentType = "text/html"; + [TestMethod()] + public void IsValidForImportView_ReturnsTrue_WhenFileIsHtml() + { + // Arrange + var fileName = "test.html"; + var contentType = "text/html"; - // Act - var result = _service.IsValidForImportView(contentType, fileName); + // Act + var result = _service.IsValidForImportView(contentType, fileName); - // Assert - Assert.IsTrue(result); - } + // Assert + Assert.IsTrue(result); + } - [TestMethod()] - public void IsValidForImportView_ReturnsFalse_WhenFileIsBinary() - { - // Arrange - var fileName = "test.dat"; - var contentType = "application/octet-stream"; + [TestMethod()] + public void IsValidForImportView_ReturnsFalse_WhenFileIsBinary() + { + // Arrange + var fileName = "test.dat"; + var contentType = "application/octet-stream"; - // Act - var result = _service.IsValidForImportView(contentType, fileName); + // Act + var result = _service.IsValidForImportView(contentType, fileName); - // Assert - Assert.IsFalse(result); - } + // Assert + Assert.IsFalse(result); + } - [TestMethod] - public async Task CreateFileUploadsAsync_ReturnsFileUploads_WhenFileHasTextContentAsync() - { - // Arrange - var firstFile = CreateBrowserFile("Test.txt", "text/plain", "Just a test!"); - var secondFile = CreateBrowserFile("Test.mp3", "audio/mpeg"); - IReadOnlyList browserfiles = [ - firstFile, - secondFile - ]; - var objectUrl = "Some object url!"; - _jsRuntimeMock.Setup(js => js.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(objectUrl); - // Act - var result = await _service.CreateFileUploadsAsync(browserfiles); - // Assert - Assert.HasCount(2, result); - Assert.AreEqual(firstFile.Name, result.First().Name); - Assert.AreEqual(firstFile.ContentType, result.First().ContentType); - Assert.AreEqual("Just a test!", result.First().Content); - Assert.AreEqual(secondFile.Name, result.Last().Name); - Assert.AreEqual(secondFile.ContentType, result.Last().ContentType); - Assert.IsNull(result.Last().Content); - Assert.AreEqual(objectUrl, result.Last().ObjectUrl); - } + [TestMethod] + public async Task CreateFileUploadsAsync_ReturnsFileUploads_WhenFileHasTextContentAsync() + { + // Arrange + var firstFile = CreateBrowserFile("Test.txt", "text/plain", "Just a test!"); + var secondFile = CreateBrowserFile("Test.mp3", "audio/mpeg"); + IReadOnlyList browserfiles = [ + firstFile, + secondFile + ]; + var objectUrl = "Some object url!"; + _jsRuntimeMock.Setup(js => js.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(objectUrl); + // Act + var result = await _service.CreateFileUploadsAsync(browserfiles); + // Assert + Assert.HasCount(2, result); + Assert.AreEqual(firstFile.Name, result.First().Name); + Assert.AreEqual(firstFile.ContentType, result.First().ContentType); + Assert.AreEqual("Just a test!", result.First().Content); + Assert.AreEqual(secondFile.Name, result.Last().Name); + Assert.AreEqual(secondFile.ContentType, result.Last().ContentType); + Assert.IsNull(result.Last().Content); + Assert.AreEqual(objectUrl, result.Last().ObjectUrl); + } - [TestMethod] - public async Task CreateFileUploadsAsync_ReturnsEmpty_WhenFilesHaveInvalidMimeTypeAsync() - { - // Arrange - var firstFile = CreateBrowserFile("Test.bin", "binary", "Just a test!"); - var secondFile = CreateBrowserFile("Test.bin", "octet/stream"); - IReadOnlyList browserfiles = [ - firstFile, - secondFile - ]; - // Act - var result = await _service.CreateFileUploadsAsync(browserfiles); - // Assert - Assert.IsEmpty(result); - } + [TestMethod] + public async Task CreateFileUploadsAsync_ReturnsEmpty_WhenFilesHaveInvalidMimeTypeAsync() + { + // Arrange + var firstFile = CreateBrowserFile("Test.bin", "binary", "Just a test!"); + var secondFile = CreateBrowserFile("Test.bin", "octet/stream"); + IReadOnlyList browserfiles = [ + firstFile, + secondFile + ]; + // Act + var result = await _service.CreateFileUploadsAsync(browserfiles); + // Assert + Assert.IsEmpty(result); + } - static IBrowserFile CreateBrowserFile(string name, string contentType, string? content = null) - { - var fileMock = new Mock(); - fileMock.Setup(f => f.Name).Returns(name); - fileMock.Setup(f => f.ContentType).Returns(contentType); - if (content != null) - { - fileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(Encoding.UTF8.GetBytes(content))); - } - return fileMock.Object; + static IBrowserFile CreateBrowserFile(string name, string contentType, string? content = null) + { + var fileMock = new Mock(); + fileMock.Setup(f => f.Name).Returns(name); + fileMock.Setup(f => f.ContentType).Returns(contentType); + if (content != null) + { + fileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(Encoding.UTF8.GetBytes(content))); } + return fileMock.Object; } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index fabbd9fa..07ac8825 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -32,212 +32,212 @@ using System.Reflection; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass()] +public class ImportManagerTests { - [TestClass()] - public class ImportManagerTests + readonly ImportManager _service; + readonly Mock _sessionStateContainer; + readonly Mock _traceChangeManager; + readonly Mock _fileInputManager; + readonly Mock _textImportService; + readonly Mock _trackManager; + readonly Mock _audioImportService; + public ImportManagerTests() { - private readonly ImportManager _service; - private readonly Mock _sessionStateContainer; - private readonly Mock _traceChangeManager; - private readonly Mock _fileInputManager; - private readonly Mock _textImportService; - private readonly Mock _trackManager; - private readonly Mock _audioImportService; - public ImportManagerTests() - { - _traceChangeManager = new(); - _sessionStateContainer = new(); - _fileInputManager = new(); - _textImportService = new(); - _trackManager = new(); - _trackManager.Setup(x => x.SetProperty(It.IsAny(), It.IsAny>>(), It.IsAny())) - .Callback((Track track, LambdaExpression propExpr, object value) => - { - var memberExpression = propExpr.Body as MemberExpression; - if (memberExpression?.Member is PropertyInfo propertyInfo) - { - propertyInfo.SetValue(track, value); - } - }); - _trackManager.Setup(x => x.CopyValues(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((source, target, setIsLinkedToPreviousTrack, setPosition, setArtist, setTitle, setBegin, setEnd, setLength, setFlags, setPreGap, setPostGap) => - { - if (setIsLinkedToPreviousTrack) - { - TrackManager_SetValue(target, x => x.IsLinkedToPreviousTrack, source.IsLinkedToPreviousTrack, false); - } - if (setPosition) - { - TrackManager_SetValue(target, x => x.Position, source.Position, false); - } - if (setArtist) - { - TrackManager_SetValue(target, x => x.Artist, source.Artist, false); - } - if (setTitle) - { - TrackManager_SetValue(target, x => x.Title, source.Title, false); - } - if (setBegin) - { - TrackManager_SetValue(target, x => x.Begin, source.Begin, false); - } - if (setEnd) - { - TrackManager_SetValue(target, x => x.End, source.End, false); - } - if (setLength) - { - TrackManager_SetValue(target, x => x.Length, source.Length, false); - } - if (setFlags) - { - TrackManager_SetValue(target, x => x.Flags, source.Flags, false); - } - if (setPreGap) - { - TrackManager_SetValue(target, x => x.PreGap, source.PreGap, false); - } - if (setPostGap) - { - TrackManager_SetValue(target, x => x.PostGap, source.PostGap, false); - } - }); - _trackManager.Setup(x => x.Clone(It.IsAny())).Returns(track => + _traceChangeManager = new(); + _sessionStateContainer = new(); + _fileInputManager = new(); + _textImportService = new(); + _trackManager = new(); + _trackManager.Setup(x => x.SetProperty(It.IsAny(), It.IsAny>>(), It.IsAny())) + .Callback((Track track, LambdaExpression propExpr, object value) => { - var clone = new Track(); - Boolean setLength = true; - if (track.Begin.HasValue && track.End.HasValue) + var memberExpression = propExpr.Body as MemberExpression; + if (memberExpression?.Member is PropertyInfo propertyInfo) { - setLength = false; + propertyInfo.SetValue(track, value); } - _trackManager.Object.CopyValues(track, clone, setLength: setLength); - return clone; }); - _audioImportService = new(); - var loggerMock = new Mock>(); - _service = new ImportManager(_sessionStateContainer.Object, _traceChangeManager.Object, _fileInputManager.Object, _textImportService.Object, _trackManager.Object, _audioImportService.Object, loggerMock.Object); - } - - void TrackManager_SetValue(Track track, Expression> propertyExpression, TProperty value, Boolean signalTraceChangeManager = true) + _trackManager.Setup(x => x.CopyValues(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((source, target, setIsLinkedToPreviousTrack, setPosition, setArtist, setTitle, setBegin, setEnd, setLength, setFlags, setPreGap, setPostGap) => { - if (propertyExpression.Body is not MemberExpression memberExpression) + if (setIsLinkedToPreviousTrack) { - throw new ArgumentException("Expression must be a property"); + TrackManager_SetValue(target, x => x.IsLinkedToPreviousTrack, source.IsLinkedToPreviousTrack, false); } - - if (memberExpression.Member is not PropertyInfo propertyInfo) + if (setPosition) { - throw new ArgumentException("Member is not a property"); + TrackManager_SetValue(target, x => x.Position, source.Position, false); } - - var previousValue = (TProperty?)propertyInfo.GetValue(track); - if (Equals(previousValue, value)) + if (setArtist) { - return; + TrackManager_SetValue(target, x => x.Artist, source.Artist, false); } - - propertyInfo.SetValue(track, value); - if (signalTraceChangeManager) + if (setTitle) { - _traceChangeManager.Object.AddChange(new(track, new(previousValue, propertyInfo.Name))); + TrackManager_SetValue(target, x => x.Title, source.Title, false); } - } - - [TestMethod()] - public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() - { - // Arrange - var fileContent = "This is just a test"; - var importAudiofile = new ImportAudiofile() + if (setBegin) { - Name = "Test Cuesheet Audiofile" - }; - var importCuesheet = new ImportCuesheet() + TrackManager_SetValue(target, x => x.Begin, source.Begin, false); + } + if (setEnd) { - Artist = "Test Cuesheet Artist", - Title = "Test Cuesheet Title", - Audiofiles = [importAudiofile], - Cataloguenumber = "Test Cuesheet Cataloguenumber", - CDTextfile = "Test Cuesheet CDTextfile" - }; - importAudiofile.Tracks.Add(new() + TrackManager_SetValue(target, x => x.End, source.End, false); + } + if (setLength) { - Artist = "Test Track Artist 1", - Title = "Test Track Title 1", - Begin = new TimeSpan(0, 3, 20), - End = new TimeSpan(0, 7, 43), - Flags = [Flag.DCP], - Position = 1, - PreGap = new TimeSpan(0, 0, 2), - PostGap = new TimeSpan(0, 0, 4) - }); - var importFile = new Importfile() + TrackManager_SetValue(target, x => x.Length, source.Length, false); + } + if (setFlags) + { + TrackManager_SetValue(target, x => x.Flags, source.Flags, false); + } + if (setPreGap) { - FileContent = fileContent, - FileType = ImportFileType.Textfile, - AnalyzedCuesheet = importCuesheet - }; - _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); - _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); - IList? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); - Cuesheet? sessionStateContainerImportCuesheet = null; - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cs => sessionStateContainerImportCuesheet = cs); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - // Act - await _service.AnalyseImportfile(); - // Assert - Assert.AreEqual(importFile, sessionStateContainerImportfile); - Assert.IsNotNull(sessionStateContainerImportCuesheet); - Assert.AreEqual(importCuesheet.Artist, sessionStateContainerImportCuesheet.Artist); - Assert.AreEqual(importCuesheet.Title, sessionStateContainerImportCuesheet.Title); - Assert.HasCount(1, sessionStateContainerImportCuesheet.Audiofiles); - Assert.AreEqual(importAudiofile.Name, sessionStateContainerImportCuesheet.Audiofiles.First().Name); - Assert.AreEqual(importCuesheet.Cataloguenumber, sessionStateContainerImportCuesheet.Cataloguenumber); - Assert.IsNotNull(sessionStateContainerImportCuesheet.CDTextfile); - Assert.AreEqual(importCuesheet.CDTextfile, sessionStateContainerImportCuesheet.CDTextfile.Name); - Assert.AreEqual(importAudiofile.Tracks.First().Artist, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Artist); - Assert.AreEqual(importAudiofile.Tracks.First().Title, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); - Assert.AreEqual(importAudiofile.Tracks.First().Begin, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); - Assert.AreEqual(importAudiofile.Tracks.First().End, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().End); - Assert.AreSequenceEqual([.. importAudiofile.Tracks.First().Flags], sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Flags.ToList(), Microsoft.VisualStudio.TestTools.UnitTesting.SequenceOrder.InAnyOrder); - Assert.AreEqual(importAudiofile.Tracks.First().Position, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Position); - Assert.AreEqual(importAudiofile.Tracks.First().PreGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PreGap); - Assert.AreEqual(importAudiofile.Tracks.First().PostGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PostGap); + TrackManager_SetValue(target, x => x.PreGap, source.PreGap, false); + } + if (setPostGap) + { + TrackManager_SetValue(target, x => x.PostGap, source.PostGap, false); + } + }); + _trackManager.Setup(x => x.Clone(It.IsAny())).Returns(track => + { + var clone = new Track(); + Boolean setLength = true; + if (track.Begin.HasValue && track.End.HasValue) + { + setLength = false; + } + _trackManager.Object.CopyValues(track, clone, setLength: setLength); + return clone; + }); + _audioImportService = new(); + var loggerMock = new Mock>(); + _service = new ImportManager(_sessionStateContainer.Object, _traceChangeManager.Object, _fileInputManager.Object, _textImportService.Object, _trackManager.Object, _audioImportService.Object, loggerMock.Object); + } + + void TrackManager_SetValue(Track track, Expression> propertyExpression, TProperty value, Boolean signalTraceChangeManager = true) + { + if (propertyExpression.Body is not MemberExpression memberExpression) + { + throw new ArgumentException("Expression must be a property"); } - [TestMethod()] - public async Task AnalyseImportfile_WithoutAnalysedCuesheet_DoesNothing() + if (memberExpression.Member is not PropertyInfo propertyInfo) { - // Arrange - var fileContent = "This is just a test"; - var importFile = new Importfile() - { - FileContent = fileContent, - FileType = ImportFileType.Textfile, - }; - _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); - _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); - Cuesheet? sessionStateContainerImportCuesheet = null; - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cs => sessionStateContainerImportCuesheet = cs); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - // Act - await _service.AnalyseImportfile(); - // Assert - Assert.AreEqual(importFile, sessionStateContainerImportfile); - Assert.IsNull(sessionStateContainerImportCuesheet); + throw new ArgumentException("Member is not a property"); } - [TestMethod()] - public async Task AnalyseImportfile_ExistingCuesheet_SetsImportfileCuesheet() + var previousValue = (TProperty?)propertyInfo.GetValue(track); + if (Equals(previousValue, value)) { - // Arrange - var fileContent = @"PERFORMER ""Sample CD Artist"" + return; + } + + propertyInfo.SetValue(track, value); + if (signalTraceChangeManager) + { + _traceChangeManager.Object.AddChange(new(track, new(previousValue, propertyInfo.Name))); + } + } + + [TestMethod()] + public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() + { + // Arrange + var fileContent = "This is just a test"; + var importAudiofile = new ImportAudiofile() + { + Name = "Test Cuesheet Audiofile" + }; + var importCuesheet = new ImportCuesheet() + { + Artist = "Test Cuesheet Artist", + Title = "Test Cuesheet Title", + Audiofiles = [importAudiofile], + Cataloguenumber = "Test Cuesheet Cataloguenumber", + CDTextfile = "Test Cuesheet CDTextfile" + }; + importAudiofile.Tracks.Add(new() + { + Artist = "Test Track Artist 1", + Title = "Test Track Title 1", + Begin = new TimeSpan(0, 3, 20), + End = new TimeSpan(0, 7, 43), + Flags = [Flag.DCP], + Position = 1, + PreGap = new TimeSpan(0, 0, 2), + PostGap = new TimeSpan(0, 0, 4) + }); + var importFile = new Importfile() + { + FileContent = fileContent, + FileType = ImportFileType.Textfile, + AnalyzedCuesheet = importCuesheet + }; + _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); + _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); + IList? sessionStateContainerImportAudiofiles = []; + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + Cuesheet? sessionStateContainerImportCuesheet = null; + _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cs => sessionStateContainerImportCuesheet = cs); + _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + // Act + await _service.AnalyseImportfile(); + // Assert + Assert.AreEqual(importFile, sessionStateContainerImportfile); + Assert.IsNotNull(sessionStateContainerImportCuesheet); + Assert.AreEqual(importCuesheet.Artist, sessionStateContainerImportCuesheet.Artist); + Assert.AreEqual(importCuesheet.Title, sessionStateContainerImportCuesheet.Title); + Assert.HasCount(1, sessionStateContainerImportCuesheet.Audiofiles); + Assert.AreEqual(importAudiofile.Name, sessionStateContainerImportCuesheet.Audiofiles.First().Name); + Assert.AreEqual(importCuesheet.Cataloguenumber, sessionStateContainerImportCuesheet.Cataloguenumber); + Assert.IsNotNull(sessionStateContainerImportCuesheet.CDTextfile); + Assert.AreEqual(importCuesheet.CDTextfile, sessionStateContainerImportCuesheet.CDTextfile.Name); + Assert.AreEqual(importAudiofile.Tracks.First().Artist, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Artist); + Assert.AreEqual(importAudiofile.Tracks.First().Title, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); + Assert.AreEqual(importAudiofile.Tracks.First().Begin, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); + Assert.AreEqual(importAudiofile.Tracks.First().End, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().End); + Assert.AreSequenceEqual([.. importAudiofile.Tracks.First().Flags], sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Flags.ToList(), Microsoft.VisualStudio.TestTools.UnitTesting.SequenceOrder.InAnyOrder); + Assert.AreEqual(importAudiofile.Tracks.First().Position, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Position); + Assert.AreEqual(importAudiofile.Tracks.First().PreGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PreGap); + Assert.AreEqual(importAudiofile.Tracks.First().PostGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PostGap); + } + + [TestMethod()] + public async Task AnalyseImportfile_WithoutAnalysedCuesheet_DoesNothing() + { + // Arrange + var fileContent = "This is just a test"; + var importFile = new Importfile() + { + FileContent = fileContent, + FileType = ImportFileType.Textfile, + }; + _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); + _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); + Cuesheet? sessionStateContainerImportCuesheet = null; + _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cs => sessionStateContainerImportCuesheet = cs); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + // Act + await _service.AnalyseImportfile(); + // Assert + Assert.AreEqual(importFile, sessionStateContainerImportfile); + Assert.IsNull(sessionStateContainerImportCuesheet); + } + + [TestMethod()] + public async Task AnalyseImportfile_ExistingCuesheet_SetsImportfileCuesheet() + { + // Arrange + var fileContent = @"PERFORMER ""Sample CD Artist"" TITLE ""Sample CD Title"" FILE ""Sample.mp3"" MP3 TRACK 01 AUDIO @@ -273,201 +273,200 @@ TRACK 08 AUDIO TITLE ""Sample Title 8"" INDEX 01 45:54:00 "; - IImportfile sessionStateContainerImportFile = new Importfile() - { - FileContent = fileContent, - FileType = ImportFileType.Cuesheet - }; - IList? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); - _sessionStateContainer.SetupGet(x => x.Importfile).Returns(() => sessionStateContainerImportFile); - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(importfile => sessionStateContainerImportFile = importfile); - Cuesheet? sessionStateContainerImportCuesheet = null; - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cuesheet => sessionStateContainerImportCuesheet = cuesheet); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); + IImportfile sessionStateContainerImportFile = new Importfile() + { + FileContent = fileContent, + FileType = ImportFileType.Cuesheet + }; + IList? sessionStateContainerImportAudiofiles = []; + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + _sessionStateContainer.SetupGet(x => x.Importfile).Returns(() => sessionStateContainerImportFile); + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(importfile => sessionStateContainerImportFile = importfile); + Cuesheet? sessionStateContainerImportCuesheet = null; + _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cuesheet => sessionStateContainerImportCuesheet = cuesheet); + _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); - // Act - await _service.AnalyseImportfile(); - // Assert - Assert.IsNotNull(sessionStateContainerImportCuesheet); - Assert.AreEqual("Sample CD Artist", sessionStateContainerImportCuesheet.Artist); - Assert.AreEqual("Sample CD Title", sessionStateContainerImportCuesheet.Title); - Assert.HasCount(1, sessionStateContainerImportCuesheet.Audiofiles); - Assert.AreEqual("Sample.mp3", sessionStateContainerImportCuesheet.Audiofiles.First().Name); - Assert.HasCount(8, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("Sample Artist 1", sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Artist); - Assert.AreEqual(TimeSpan.Zero, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); - Assert.AreEqual("Sample Title 1", sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); - Assert.AreEqual((ushort)1, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Position); - Assert.AreEqual((ushort)8, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.Last().Position); - } + // Act + await _service.AnalyseImportfile(); + // Assert + Assert.IsNotNull(sessionStateContainerImportCuesheet); + Assert.AreEqual("Sample CD Artist", sessionStateContainerImportCuesheet.Artist); + Assert.AreEqual("Sample CD Title", sessionStateContainerImportCuesheet.Title); + Assert.HasCount(1, sessionStateContainerImportCuesheet.Audiofiles); + Assert.AreEqual("Sample.mp3", sessionStateContainerImportCuesheet.Audiofiles.First().Name); + Assert.HasCount(8, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("Sample Artist 1", sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Artist); + Assert.AreEqual(TimeSpan.Zero, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); + Assert.AreEqual("Sample Title 1", sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); + Assert.AreEqual((ushort)1, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Position); + Assert.AreEqual((ushort)8, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.Last().Position); + } - [TestMethod] - public async Task UploadFilesAsync_ProjectFile_ImportsCorrectly() - { - // Arrange - var fileContent = "This is the content"; - var file = new FileUpload("test.projectfile", "text/plain", fileContent); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(true); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); + [TestMethod] + public async Task UploadFilesAsync_ProjectFile_ImportsCorrectly() + { + // Arrange + var fileContent = "This is the content"; + var file = new FileUpload("test.projectfile", "text/plain", fileContent); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(true); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); + _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - // Act - await _service.UploadFilesAsync([file]); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + // Act + await _service.UploadFilesAsync([file]); - // Assert - Assert.IsNotNull(sessionStateContainerImportfile); - Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContent); - Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContentRecognized); - Assert.AreEqual(ImportFileType.ProjectFile, sessionStateContainerImportfile.FileType); - } + // Assert + Assert.IsNotNull(sessionStateContainerImportfile); + Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContent); + Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContentRecognized); + Assert.AreEqual(ImportFileType.ProjectFile, sessionStateContainerImportfile.FileType); + } - [TestMethod] - public async Task UploadFilesAsync_CuesheetFile_ImportsCorrectly() - { - // Arrange - var fileContent = "Cuesheet file content"; - var file = new FileUpload("test.cue", "text/plain", fileContent); + [TestMethod] + public async Task UploadFilesAsync_CuesheetFile_ImportsCorrectly() + { + // Arrange + var fileContent = "Cuesheet file content"; + var file = new FileUpload("test.cue", "text/plain", fileContent); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(true); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(true); + _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - // Act - await _service.UploadFilesAsync([file]); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + // Act + await _service.UploadFilesAsync([file]); - // Assert - Assert.IsNotNull(sessionStateContainerImportfile); - Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContent); - Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContentRecognized); - Assert.AreEqual(ImportFileType.Cuesheet, sessionStateContainerImportfile.FileType); - } + // Assert + Assert.IsNotNull(sessionStateContainerImportfile); + Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContent); + Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContentRecognized); + Assert.AreEqual(ImportFileType.Cuesheet, sessionStateContainerImportfile.FileType); + } - [TestMethod] - public async Task UploadFilesAsync_TextFile_ImportsCorrectly() - { - // Arrange - var fileContent = "TextFileContent"; - var file = new FileUpload("test.txt", "text/plain", fileContent); + [TestMethod] + public async Task UploadFilesAsync_TextFile_ImportsCorrectly() + { + // Arrange + var fileContent = "TextFileContent"; + var file = new FileUpload("test.txt", "text/plain", fileContent); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(true); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); + _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(true); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - // Act - await _service.UploadFilesAsync([file]); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + // Act + await _service.UploadFilesAsync([file]); - // Assert - Assert.IsNotNull(sessionStateContainerImportfile); - Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContent); - Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContentRecognized); - Assert.AreEqual(ImportFileType.Textfile, sessionStateContainerImportfile.FileType); - } + // Assert + Assert.IsNotNull(sessionStateContainerImportfile); + Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContent); + Assert.AreEqual(fileContent, sessionStateContainerImportfile.FileContentRecognized); + Assert.AreEqual(ImportFileType.Textfile, sessionStateContainerImportfile.FileType); + } - [TestMethod] - public async Task UploadFilesAsync_WithAudiofile_ImportsCorrectly() - { - // Arrange - var file = new FileUpload("test.mp3", "audio/mpeg"); + [TestMethod] + public async Task UploadFilesAsync_WithAudiofile_ImportsCorrectly() + { + // Arrange + var file = new FileUpload("test.mp3", "audio/mpeg"); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); - _fileInputManager.Setup(f => f.IsValidAudiofile(file.Name, file.ContentType)).Returns(true); - _fileInputManager.Setup(f => f.CreateAudiofileAsync(It.IsAny())).ReturnsAsync(new Audiofile() { Name = file.Name }); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); + _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); + _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); + _fileInputManager.Setup(f => f.IsValidAudiofile(file.Name, file.ContentType)).Returns(true); + _fileInputManager.Setup(f => f.CreateAudiofileAsync(It.IsAny())).ReturnsAsync(new Audiofile() { Name = file.Name }); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - IList? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); - _sessionStateContainer.SetupSet(x => x.ImportAudiofiles = It.IsAny>()).Callback>(x => sessionStateContainerImportAudiofiles = x); - // Act - await _service.UploadFilesAsync([file]); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + IList? sessionStateContainerImportAudiofiles = []; + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + _sessionStateContainer.SetupSet(x => x.ImportAudiofiles = It.IsAny>()).Callback>(x => sessionStateContainerImportAudiofiles = x); + // Act + await _service.UploadFilesAsync([file]); - // Assert - Assert.IsNull(sessionStateContainerImportfile); - Assert.HasCount(1, sessionStateContainerImportAudiofiles); - } + // Assert + Assert.IsNull(sessionStateContainerImportfile); + Assert.HasCount(1, sessionStateContainerImportAudiofiles); + } - [TestMethod] - public async Task ImportCuesheetAsync_WithImportCuesheetAvailable_ImportsCuesheetDataAsync() + [TestMethod] + public async Task ImportCuesheetAsync_WithImportCuesheetAvailable_ImportsCuesheetDataAsync() + { + // Arrange + var track1 = new Track() { - // Arrange - var track1 = new Track() - { - Artist = "Track Artist 1", - Title = "Track Title 1", - End = new TimeSpan(0, 4, 23), - }; - var track2 = new Track() - { - Artist = "Track Artist 2", - Title = "Track Title 2", - }; - var audiofileDuration = new TimeSpan(0, 12, 45); - var sessionStateContainerImportCuesheet = new Cuesheet() - { - Artist = "Artist 123", - Title = "Title 456", - Audiofiles = [ - new Audiofile() - { - Name = "song.mp3", - ObjectURL = "Just a test", - Tracks = [track1, track2], - Duration = audiofileDuration - } - ] - }; - track1.Cuesheet = sessionStateContainerImportCuesheet; - track2.Cuesheet = sessionStateContainerImportCuesheet; - track1.Audiofile = sessionStateContainerImportCuesheet.Audiofiles.First(); - track2.Audiofile = sessionStateContainerImportCuesheet.Audiofiles.First(); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(sessionStateContainerImportCuesheet); - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cuesheet => sessionStateContainerImportCuesheet = cuesheet); - Cuesheet sessionStateContainerCuesheet = new(); - _sessionStateContainer.SetupSet(x => x.Cuesheet = It.IsAny()).Callback(cuesheet => sessionStateContainerCuesheet = cuesheet); - _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(() => sessionStateContainerCuesheet); - IList? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); - // Act - await _service.ImportCuesheetAsync(); - // Assert - Assert.IsNotNull(sessionStateContainerCuesheet); - Assert.AreEqual(sessionStateContainerImportCuesheet.Artist, sessionStateContainerCuesheet.Artist); - Assert.AreEqual(sessionStateContainerImportCuesheet.Title, sessionStateContainerCuesheet.Title); - Assert.HasCount(1, sessionStateContainerCuesheet.Audiofiles); - Assert.AreEqual(track1.Artist, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Artist); - Assert.AreEqual(track1.Title, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Title); - Assert.AreEqual(TimeSpan.Zero, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Begin); - Assert.AreEqual(track1.End, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().End); - Assert.AreEqual(track2.Artist, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Artist); - Assert.AreEqual(track2.Title, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Title); - Assert.AreEqual(track1.End, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Begin); - Assert.AreEqual(audiofileDuration, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().End); - _traceChangeManager.Verify(x => x.RemoveTracedChanges(It.IsAny>())); - } - - [TestMethod] - public void ImportData_ValidData_SetsImportfile() + Artist = "Track Artist 1", + Title = "Track Title 1", + End = new TimeSpan(0, 4, 23), + }; + var track2 = new Track() { - // Arrange - var importData = nameof(ImportData_ValidData_SetsImportfile); - IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); - // Act - _service.ImportData(importData); - // Assert - Assert.IsNotNull(sessionStateContainerImportfile); - Assert.AreEqual(importData, sessionStateContainerImportfile.FileContent); - Assert.AreEqual(importData, sessionStateContainerImportfile.FileContentRecognized); - Assert.AreEqual(ImportFileType.Textfile, sessionStateContainerImportfile.FileType); - } + Artist = "Track Artist 2", + Title = "Track Title 2", + }; + var audiofileDuration = new TimeSpan(0, 12, 45); + var sessionStateContainerImportCuesheet = new Cuesheet() + { + Artist = "Artist 123", + Title = "Title 456", + Audiofiles = [ + new Audiofile() + { + Name = "song.mp3", + ObjectURL = "Just a test", + Tracks = [track1, track2], + Duration = audiofileDuration + } + ] + }; + track1.Cuesheet = sessionStateContainerImportCuesheet; + track2.Cuesheet = sessionStateContainerImportCuesheet; + track1.Audiofile = sessionStateContainerImportCuesheet.Audiofiles.First(); + track2.Audiofile = sessionStateContainerImportCuesheet.Audiofiles.First(); + _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(sessionStateContainerImportCuesheet); + _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny()).Callback(cuesheet => sessionStateContainerImportCuesheet = cuesheet); + Cuesheet sessionStateContainerCuesheet = new(); + _sessionStateContainer.SetupSet(x => x.Cuesheet = It.IsAny()).Callback(cuesheet => sessionStateContainerCuesheet = cuesheet); + _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(() => sessionStateContainerCuesheet); + IList? sessionStateContainerImportAudiofiles = []; + _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + // Act + await _service.ImportCuesheetAsync(); + // Assert + Assert.IsNotNull(sessionStateContainerCuesheet); + Assert.AreEqual(sessionStateContainerImportCuesheet.Artist, sessionStateContainerCuesheet.Artist); + Assert.AreEqual(sessionStateContainerImportCuesheet.Title, sessionStateContainerCuesheet.Title); + Assert.HasCount(1, sessionStateContainerCuesheet.Audiofiles); + Assert.AreEqual(track1.Artist, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Artist); + Assert.AreEqual(track1.Title, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Title); + Assert.AreEqual(TimeSpan.Zero, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Begin); + Assert.AreEqual(track1.End, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().End); + Assert.AreEqual(track2.Artist, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Artist); + Assert.AreEqual(track2.Title, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Title); + Assert.AreEqual(track1.End, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Begin); + Assert.AreEqual(audiofileDuration, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().End); + _traceChangeManager.Verify(x => x.RemoveTracedChanges(It.IsAny>())); + } + + [TestMethod] + public void ImportData_ValidData_SetsImportfile() + { + // Arrange + var importData = nameof(ImportData_ValidData_SetsImportfile); + IImportfile? sessionStateContainerImportfile = null; + _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny()).Callback(x => sessionStateContainerImportfile = x); + // Act + _service.ImportData(importData); + // Assert + Assert.IsNotNull(sessionStateContainerImportfile); + Assert.AreEqual(importData, sessionStateContainerImportfile.FileContent); + Assert.AreEqual(importData, sessionStateContainerImportfile.FileContentRecognized); + Assert.AreEqual(ImportFileType.Textfile, sessionStateContainerImportfile.FileType); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs index df44aa1b..2ba0c515 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -27,25 +27,25 @@ using System.Linq; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.IO +namespace AudioCuesheetEditor.Tests.Services.IO; + +[TestClass()] +public class TextImportServiceTests { - [TestClass()] - public class TextImportServiceTests - { - private readonly Mock _localStorageOptionsProviderMock; - private readonly TextImportService _textImportService; + readonly Mock _localStorageOptionsProviderMock; + readonly TextImportService _textImportService; - public TextImportServiceTests() - { - _localStorageOptionsProviderMock = new(); - _textImportService = new (_localStorageOptionsProviderMock.Object); - } + public TextImportServiceTests() + { + _localStorageOptionsProviderMock = new(); + _textImportService = new (_localStorageOptionsProviderMock.Object); + } - [TestMethod()] - public async Task AnalyseAsync_SampleCuesheet_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = @"CuesheetArtist - CuesheetTitle + [TestMethod()] + public async Task AnalyseAsync_SampleCuesheet_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = @"CuesheetArtist - CuesheetTitle - c:\tmp\Testfile.mp3 Sample Artist 1 - Sample Title 1 00:05:00 Sample Artist 2 - Sample Title 2 00:09:23 @@ -55,38 +55,38 @@ public async Task AnalyseAsync_SampleCuesheet_CreatesValidCuesheetAsync() Sample Artist 6 - Sample Title 6 00:31:54 Sample Artist 7 - Sample Title 7 00:45:54 Sample Artist 8 - Sample Title 8 01:15:54"; - - var importOptions = new ImportOptions - { - SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(importOptions); - var applicationOptions = new ApplicationOptions() - { - DefaultIsLinkedToPreviousTrack = true - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.AreEqual("c:\\tmp\\Testfile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); - Assert.IsTrue(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).IsLinkedToPreviousTrack); - } - - [TestMethod()] - public async Task AnalyseAsync_InvalidAudiofileSchemeWithMatchingTrackScheme_DoesNotMarkTracksFoundAsync() - { - // Arrange - var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3 + + var importOptions = new ImportOptions + { + SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(importOptions); + var applicationOptions = new ApplicationOptions() + { + DefaultIsLinkedToPreviousTrack = true + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.AreEqual("c:\\tmp\\Testfile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + Assert.IsTrue(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).IsLinkedToPreviousTrack); + } + + [TestMethod()] + public async Task AnalyseAsync_InvalidAudiofileSchemeWithMatchingTrackScheme_DoesNotMarkTracksFoundAsync() + { + // Arrange + var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3 Sample Artist 1 - Sample Title 1 00:05:00 Sample Artist 2 - Sample Title 2 00:09:23 Sample Artist 3 - Sample Title 3 00:15:54 @@ -96,36 +96,36 @@ public async Task AnalyseAsync_InvalidAudiofileSchemeWithMatchingTrackScheme_Doe Sample Artist 7 - Sample Title 7 00:45:54 Sample Artist 8 - Sample Title 8 01:15:54"; - var importOptions = new ImportOptions - { - SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(importOptions); - var applicationOptions = new ApplicationOptions() - { - DefaultIsLinkedToPreviousTrack = true - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3", importFile.AnalyzedCuesheet.Title); - Assert.IsEmpty(importFile.AnalyzedCuesheet.Audiofiles); - var lines = importFile.FileContentRecognized!.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3")), lines.First()); - Assert.AreEqual("Sample Artist 8 - Sample Title 8\t\t\t\t01:15:54", lines.Last()); - } - - [TestMethod()] - public async Task AnalyseAsync_InvalidSchemeTracks_CreatesAnalyseExceptionAsync() - { - // Arrange - var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt + var importOptions = new ImportOptions + { + SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(importOptions); + var applicationOptions = new ApplicationOptions() + { + DefaultIsLinkedToPreviousTrack = true + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3", importFile.AnalyzedCuesheet.Title); + Assert.IsEmpty(importFile.AnalyzedCuesheet.Audiofiles); + var lines = importFile.FileContentRecognized!.Split(Environment.NewLine); + Assert.AreEqual(string.Format("{0} - {1}", + string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), + string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3")), lines.First()); + Assert.AreEqual("Sample Artist 8 - Sample Title 8\t\t\t\t01:15:54", lines.Last()); + } + + [TestMethod()] + public async Task AnalyseAsync_InvalidSchemeTracks_CreatesAnalyseExceptionAsync() + { + // Arrange + var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt 1|Sample Artist 1 - Sample Title 1 00:05:00 2|Sample Artist 2 - Sample Title 2 00:09:23 3|Sample Artist 3 - Sample Title 3 00:15:54 @@ -134,28 +134,28 @@ public async Task AnalyseAsync_InvalidSchemeTracks_CreatesAnalyseExceptionAsync( 6|Sample Artist 6 - Sample Title 6 00:31:54 7|Sample Artist 7 - Sample Title 7 00:45:54 8|Sample Artist 8 - Sample Title 8 01:15:54"; - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeCuesheet = @"(?'Cuesheet.Artist'\A.*)[|](?'Cuesheet.Title'\w{1,})\t{1,}(?'Cuesheet.CDTextfile'.{1,})", - SchemeTracks = @"(?'Track.Position'.{1,})|(?'Track.Artist'.{1,}) - (?'Track.Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Track.End'.{1,})" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - // Act - var importfile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNotNull(importfile.AnalyseException); - } - - [TestMethod()] - public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt + var profile = new Importprofile() + { + UseRegularExpression = true, + SchemeCuesheet = @"(?'Cuesheet.Artist'\A.*)[|](?'Cuesheet.Title'\w{1,})\t{1,}(?'Cuesheet.CDTextfile'.{1,})", + SchemeTracks = @"(?'Track.Position'.{1,})|(?'Track.Artist'.{1,}) - (?'Track.Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Track.End'.{1,})" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + // Act + var importfile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNotNull(importfile.AnalyseException); + } + + [TestMethod()] + public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt 1|Sample Artist 1 - Sample Title 1 00:05:00 2|Sample Artist 2 - Sample Title 2 00:09:23 3|Sample Artist 3 - Sample Title 3 00:15:54 @@ -164,39 +164,39 @@ public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetA 6|Sample Artist 6 - Sample Title 6 00:31:54 7|Sample Artist 7 - Sample Title 7 00:45:54 8|Sample Artist 8 - Sample Title 8 01:15:54"; - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[^\r\n]+)", - SchemeTracks = @"(?'Position'\d{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importfile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importfile.AnalyseException); - Assert.IsNotNull(importfile.AnalyzedCuesheet); - Assert.AreEqual("CuesheetArtist", importfile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle", importfile.AnalyzedCuesheet.Title); - Assert.AreEqual("c:\\tmp\\TestTextFile.cdt", importfile.AnalyzedCuesheet.CDTextfile); - Assert.HasCount(1, importfile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importfile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual((ushort)6, importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); - Assert.AreEqual("Sample Artist 1", importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("Sample Title 1", importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); - } - - [TestMethod()] - public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCuesheetAsync() + var profile = new Importprofile() { - var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt + UseRegularExpression = true, + SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[^\r\n]+)", + SchemeTracks = @"(?'Position'\d{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importfile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importfile.AnalyseException); + Assert.IsNotNull(importfile.AnalyzedCuesheet); + Assert.AreEqual("CuesheetArtist", importfile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle", importfile.AnalyzedCuesheet.Title); + Assert.AreEqual("c:\\tmp\\TestTextFile.cdt", importfile.AnalyzedCuesheet.CDTextfile); + Assert.HasCount(1, importfile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importfile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual((ushort)6, importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); + Assert.AreEqual("Sample Artist 1", importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("Sample Title 1", importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new TimeSpan(0, 5, 0), importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + } + + [TestMethod()] + public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCuesheetAsync() + { + var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt 1|Sample Artist 1 - Sample Title 1 00:05:00 2|Sample Artist 2 - Sample Title 2 00:09:23 3|Sample Artist 3 - Sample Title 3 00:15:54 @@ -205,40 +205,40 @@ public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCueshee 6|Sample Artist 6 - Sample Title 6 00:31:54 7|Sample Artist 7 - Sample Title 7 00:45:54 8|Sample Artist 8 - Sample Title 8 01:15:54"; - var profile = new Importprofile() - { - UseRegularExpression = false, - SchemeCuesheet = @"Artist|Title CDTextfile", - SchemeTracks = @"Position|Artist - Title End" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); - Assert.AreEqual("c:\\tmp\\TestTextFile.cdt", importFile.AnalyzedCuesheet.CDTextfile); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual((ushort)6, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); - Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); - } - - [TestMethod()] - public async Task AnalyseAsync_InvalidScheme_CreatesAnalyseExceptionAsync() - { - // Arrange - var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt A83412346734 + var profile = new Importprofile() + { + UseRegularExpression = false, + SchemeCuesheet = @"Artist|Title CDTextfile", + SchemeTracks = @"Position|Artist - Title End" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); + Assert.AreEqual("c:\\tmp\\TestTextFile.cdt", importFile.AnalyzedCuesheet.CDTextfile); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual((ushort)6, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); + Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + } + + [TestMethod()] + public async Task AnalyseAsync_InvalidScheme_CreatesAnalyseExceptionAsync() + { + // Arrange + var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt A83412346734 1|Sample Artist 1 - Sample Title 1 00:05:00 2|Sample Artist 2 - Sample Title 2 00:09:23 3|Sample Artist 3 - Sample Title 3 00:15:54 @@ -256,30 +256,30 @@ public async Task AnalyseAsync_InvalidScheme_CreatesAnalyseExceptionAsync() "; - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeCuesheet = @"(?'Cuesheet.Artist'\A.*)[|](?'Cuesheet.Title'\w{1,})\t{1,}(?'Cuesheet.CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cuesheet.Cataloguenumber'.{1,})", - SchemeTracks = @"(?'Track.Position'.{1,})|(?'Track.Artist'.{1,}) - (?'Track.Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Track.End'.{1,})" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNotNull(importFile.AnalyseException); - } - - [TestMethod()] - public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt A83412346734 + var profile = new Importprofile() + { + UseRegularExpression = true, + SchemeCuesheet = @"(?'Cuesheet.Artist'\A.*)[|](?'Cuesheet.Title'\w{1,})\t{1,}(?'Cuesheet.CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cuesheet.Cataloguenumber'.{1,})", + SchemeTracks = @"(?'Track.Position'.{1,})|(?'Track.Artist'.{1,}) - (?'Track.Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Track.End'.{1,})" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNotNull(importFile.AnalyseException); + } + + [TestMethod()] + public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = @"CuesheetArtist|CuesheetTitle c:\tmp\TestTextFile.cdt A83412346734 1|Sample Artist 1 - Sample Title 1 00:05:00 2|Sample Artist 2 - Sample Title 2 00:09:23 3|Sample Artist 3 - Sample Title 3 00:15:54 @@ -297,41 +297,41 @@ public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesVal "; - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cataloguenumber'[^\r\n]+)", - SchemeTracks = @"(?'Position'.{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); - Assert.AreEqual("c:\\tmp\\TestTextFile.cdt", importFile.AnalyzedCuesheet.CDTextfile); - Assert.AreEqual("A83412346734", importFile.AnalyzedCuesheet.Cataloguenumber); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual((ushort)6, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); - Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); - } - - [TestMethod()] - public async Task AnalyseAsync_CuesheetTracksOnly_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = @"Sample Artist 1 - Sample Title 1 00:05:00 + var profile = new Importprofile() + { + UseRegularExpression = true, + SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cataloguenumber'[^\r\n]+)", + SchemeTracks = @"(?'Position'.{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); + Assert.AreEqual("c:\\tmp\\TestTextFile.cdt", importFile.AnalyzedCuesheet.CDTextfile); + Assert.AreEqual("A83412346734", importFile.AnalyzedCuesheet.Cataloguenumber); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual((ushort)6, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); + Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + } + + [TestMethod()] + public async Task AnalyseAsync_CuesheetTracksOnly_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = @"Sample Artist 1 - Sample Title 1 00:05:00 Sample Artist 2 - Sample Title 2 00:09:23 Sample Artist 3 - Sample Title 3 00:15:54 Sample Artist 4 - Sample Title 4 00:20:13 @@ -340,61 +340,61 @@ public async Task AnalyseAsync_CuesheetTracksOnly_CreatesValidCuesheetAsync() Sample Artist 7 - Sample Title 7 00:45:54 Sample Artist 8 - Sample Title 8 01:15:54 Sample Artist 9 - Sample Title 9 "; - var profile = new Importprofile() - { - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(9, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(1, 15, 54), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).End); - } - - [TestMethod()] - public async Task AnalyseAsync_CuesheetBug213_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = File.ReadAllText("Resources/Textimport_Bug_213.txt"); - var profile = new Importprofile() - { - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}", - TimeSpanFormat = new() { Scheme = $"{nameof(TimeSpanFormat.Minutes)}:{nameof(TimeSpanFormat.Seconds)}" } - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual(new TimeSpan(2, 3, 23), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).End); - } - - [TestMethod()] - public async Task AnalyseAsync_CuesheetWithFlags_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = @"Sample Artist 1 - Sample Title 1 00:05:00 DCP + var profile = new Importprofile() + { + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(9, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new TimeSpan(1, 15, 54), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).End); + } + + [TestMethod()] + public async Task AnalyseAsync_CuesheetBug213_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = File.ReadAllText("Resources/Textimport_Bug_213.txt"); + var profile = new Importprofile() + { + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}", + TimeSpanFormat = new() { Scheme = $"{nameof(TimeSpanFormat.Minutes)}:{nameof(TimeSpanFormat.Seconds)}" } + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual(new TimeSpan(2, 3, 23), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).End); + } + + [TestMethod()] + public async Task AnalyseAsync_CuesheetWithFlags_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = @"Sample Artist 1 - Sample Title 1 00:05:00 DCP Sample Artist 2 - Sample Title 2 00:09:23 Sample Artist 3 - Sample Title 3 00:15:54 PRE, DCP Sample Artist 4 - Sample Title 4 00:20:13 4CH @@ -402,43 +402,43 @@ public async Task AnalyseAsync_CuesheetWithFlags_CreatesValidCuesheetAsync() Sample Artist 6 - Sample Title 6 00:31:54 PRE DCP 4CH Sample Artist 7 - Sample Title 7 00:45:54 Sample Artist 8 - Sample Title 8 01:15:54 PRE DCP 4CH SCMS"; - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]+) - (?'Title'[a-zA-Z0-9_ .();äöü]+)[\t ]+(?'End'[0-9]{2}:[0-9]{2}:[0-9]{2})(?:[\t ]+(?'Flags'[A-Za-z0-9 ,]+))?(?=[\t ]*(?:\r?\n|$))" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Flags); - Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).Flags); - Assert.Contains(Flag.PRE, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).Flags); - Assert.Contains(Flag.FourCH, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); - Assert.Contains(Flag.FourCH, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Flags); - Assert.Contains(Flag.PRE, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Flags); - Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Flags); - Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); - Assert.Contains(Flag.PRE, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); - Assert.Contains(Flag.FourCH, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); - Assert.Contains(Flag.SCMS, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); - } - - [TestMethod()] - public async Task AnalyseAsync_CuesheetWithPreGapAndPostGap_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = @"Sample Artist 1 - Sample Title 1 00:00:02 00:05:00 00:00:00 + var profile = new Importprofile() + { + UseRegularExpression = true, + SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]+) - (?'Title'[a-zA-Z0-9_ .();äöü]+)[\t ]+(?'End'[0-9]{2}:[0-9]{2}:[0-9]{2})(?:[\t ]+(?'Flags'[A-Za-z0-9 ,]+))?(?=[\t ]*(?:\r?\n|$))" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Flags); + Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).Flags); + Assert.Contains(Flag.PRE, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).Flags); + Assert.Contains(Flag.FourCH, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); + Assert.Contains(Flag.FourCH, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Flags); + Assert.Contains(Flag.PRE, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Flags); + Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Flags); + Assert.Contains(Flag.DCP, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); + Assert.Contains(Flag.PRE, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); + Assert.Contains(Flag.FourCH, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); + Assert.Contains(Flag.SCMS, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Flags); + } + + [TestMethod()] + public async Task AnalyseAsync_CuesheetWithPreGapAndPostGap_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = @"Sample Artist 1 - Sample Title 1 00:00:02 00:05:00 00:00:00 Sample Artist 2 - Sample Title 2 00:00:04 00:09:23 00:00:00 Sample Artist 3 - Sample Title 3 00:00:00 00:15:54 00:00:02 Sample Artist 4 - Sample Title 4 00:00:00 00:20:13 00:00:03 @@ -446,48 +446,48 @@ public async Task AnalyseAsync_CuesheetWithPreGapAndPostGap_CreatesValidCuesheet Sample Artist 6 - Sample Title 6 00:00:00 00:31:54 00:00:01 Sample Artist 7 - Sample Title 7 00:00:00 00:45:54 00:00:00 Sample Artist 8 - Sample Title 8 00:00:02 01:15:54 00:00:00"; - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Title'[a-zA-Z0-9_ .();äöü]{1,})\t{1,}(?'PreGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'End'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'PostGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 3), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(4).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(4).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 1), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(6).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(6).PostGap); - Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).PreGap); - Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).PostGap); - } - - [TestMethod()] - public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOnlyForCuesheetAsync() - { - // Arrange - var fileContent = @"CuesheetArtist - CuesheetTitle + var profile = new Importprofile() + { + UseRegularExpression = true, + SchemeTracks = "(?'Artist'[a-zA-Z0-9_ .();äöü&:,]{1,}) - (?'Title'[a-zA-Z0-9_ .();äöü]{1,})\t{1,}(?'PreGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'End'[0-9]{2}[:][0-9]{2}[:][0-9]{2})\t{1,}(?'PostGap'[0-9]{2}[:][0-9]{2}[:][0-9]{2})" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(2).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 3), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(4).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(4).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 1), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(6).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(6).PostGap); + Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).PreGap); + Assert.AreEqual(new TimeSpan(0, 0, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).PostGap); + } + + [TestMethod()] + public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOnlyForCuesheetAsync() + { + // Arrange + var fileContent = @"CuesheetArtist - CuesheetTitle - c:\tmp\Testfile.mp3 Sample Artist 1 - Sample Title 1 00:05:00 Sample Artist 2 - Sample Title 2 00:09:23 @@ -497,46 +497,46 @@ public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOn Sample Artist 6 - Sample Title 6 00:31:54 Sample Artist 7 - Sample Title 7 00:45:54 Sample Artist 8 - Sample Title 8 01:15:54"; - var profile = new Importprofile() - { - SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.IsNotNull(importFile.FileContentRecognized); - var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle")), lines.First()); - Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); - Assert.HasCount(0, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("- c:\\tmp\\Testfile.mp3", lines.ElementAt(1)); - Assert.AreEqual("Sample Artist 1 - Sample Title 1 00:05:00", lines.ElementAt(2)); - Assert.AreEqual("Sample Artist 2 - Sample Title 2 00:09:23", lines.ElementAt(3)); - Assert.AreEqual("Sample Artist 3 - Sample Title 3 00:15:54", lines.ElementAt(4)); - Assert.AreEqual("Sample Artist 4 - Sample Title 4 00:20:13", lines.ElementAt(5)); - Assert.AreEqual("Sample Artist 5 - Sample Title 5 00:24:54", lines.ElementAt(6)); - Assert.AreEqual("Sample Artist 6 - Sample Title 6 00:31:54", lines.ElementAt(7)); - Assert.AreEqual("Sample Artist 7 - Sample Title 7 00:45:54", lines.ElementAt(8)); - Assert.AreEqual("Sample Artist 8 - Sample Title 8 01:15:54", lines.ElementAt(9)); - } - - [TestMethod()] - public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentRecognizedAsync() - { - // Arrange - var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3 + var profile = new Importprofile() + { + SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.IsNotNull(importFile.FileContentRecognized); + var lines = importFile.FileContentRecognized.Split(Environment.NewLine); + Assert.AreEqual(string.Format("{0} - {1}", + string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), + string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle")), lines.First()); + Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); + Assert.HasCount(0, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("- c:\\tmp\\Testfile.mp3", lines.ElementAt(1)); + Assert.AreEqual("Sample Artist 1 - Sample Title 1 00:05:00", lines.ElementAt(2)); + Assert.AreEqual("Sample Artist 2 - Sample Title 2 00:09:23", lines.ElementAt(3)); + Assert.AreEqual("Sample Artist 3 - Sample Title 3 00:15:54", lines.ElementAt(4)); + Assert.AreEqual("Sample Artist 4 - Sample Title 4 00:20:13", lines.ElementAt(5)); + Assert.AreEqual("Sample Artist 5 - Sample Title 5 00:24:54", lines.ElementAt(6)); + Assert.AreEqual("Sample Artist 6 - Sample Title 6 00:31:54", lines.ElementAt(7)); + Assert.AreEqual("Sample Artist 7 - Sample Title 7 00:45:54", lines.ElementAt(8)); + Assert.AreEqual("Sample Artist 8 - Sample Title 8 01:15:54", lines.ElementAt(9)); + } + + [TestMethod()] + public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentRecognizedAsync() + { + // Arrange + var fileContent = @"CuesheetArtist - CuesheetTitle c:\tmp\Testfile.mp3 Sample Artist 1 - Sample Title 1 00:05:00 Sample Artist 2 - Sample Title 2 00:09:23 Sample Artist 3 - Sample Title 3 00:15:54 @@ -545,153 +545,153 @@ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentReco Sample Artist 6 - Sample Title 6 00:31:54 Sample Artist 7 - Sample Title 7 00:45:54 Sample Artist 8 - Sample Title 8 01:15:54"; - var importProfile = new Importprofile() - { - UseRegularExpression = true, - SchemeCuesheet = @$"^(?<{nameof(ImportCuesheet.Artist)}>.+?)\s*-\s*(?<{nameof(ImportCuesheet.Title)}>.+?)\t+", - SchemeAudiofiles = @$"\s+(?<{nameof(ImportAudiofile.Name)}>\S+.mp3)", - SchemeTracks = @$"(?<{nameof(ImportTrack.Artist)}>.+?)\s*-\s*(?<{nameof(ImportTrack.Title)}>.+?)\s+(?<{nameof(ImportTrack.End)}>\d{{2}}:\d{{2}}:\d{{2}})" - }; - var options = new ImportOptions - { - SelectedImportProfile = importProfile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.IsNotNull(importFile.FileContentRecognized); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); - var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1} {2}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Title 8"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "01:15:54")), lines.Last()); - } - - [TestMethod()] - public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedAsync() - { - // Arrange - var profile = new Importprofile() - { - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" - }; - var fileContent = File.ReadAllText("Resources/Textimport_Bug_#233.txt"); - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.IsNotNull(importFile.FileContentRecognized); - var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1}\t\t\t\t\t\t\t\t{2}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "Age Of Love"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "04:29:28")), lines.ElementAt(53)); - } - - [TestMethod()] - public async Task AnalyseAsync_WithRegularExpression_ReturnsCuesheetAsync() - { - // Arrange - var profile = new Importprofile() - { - UseRegularExpression = true, - SchemeTracks = "\\s*\\d+\\s*(?.*?)\\s*(?.*?)</td>\\s*<td>(?<StartDateTime>.*?)</td>\\s*</tr>" - }; - var fileContent = File.ReadAllText("Resources/Traktor Export.html"); - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.AreEqual(fileContent, importFile.FileContent); - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.IsNull(importFile.AnalyzedCuesheet.Artist); - Assert.IsNull(importFile.AnalyzedCuesheet.Title); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(41, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("Nachap", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Artist); - Assert.AreEqual("Glass", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Title); - Assert.AreEqual(new DateTime(2025, 1, 29, 18, 52, 10), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().StartDateTime); - Assert.AreEqual("Inache", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Artist); - Assert.AreEqual("Andale (MONTA (TN) Remix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); - Assert.AreEqual(new DateTime(2025, 1, 29, 22, 30, 3), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().StartDateTime); - Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sasha Fashion"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "2025/1/29 21:48:55"), importFile.FileContentRecognized); - } - - [TestMethod()] - public async Task AnalyseAsync_WithoutRegularExpression_ReturnsCuesheetAsync() - { - // Arrange - var profile = new Importprofile() - { - UseRegularExpression = false, - SchemeCuesheet = "Artist - Title - Cataloguenumber", - SchemeTracks = "Artist - Title\tBegin" - }; - var fileContent = File.ReadAllText("Resources/Textimport with Cuesheetdata.txt"); - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.AreEqual("DJFreezeT", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("Rabbit Hole Mix", importFile.AnalyzedCuesheet.Title); - Assert.AreEqual("0123456789123", importFile.AnalyzedCuesheet.Cataloguenumber); - Assert.AreEqual("Adriatique", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Artist); - Assert.AreEqual("X.", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Title); - Assert.AreEqual(new TimeSpan(0, 0, 5, 24, 250), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Begin); - Assert.AreEqual("Nikolay Kirov", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Artist); - Assert.AreEqual("Chasing the Sun (Original Mix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); - Assert.IsNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Begin); - Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "DJFreezeT"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Rabbit Hole Mix"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "0123456789123"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Nikolay Kirov"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Chasing the Sun (Original Mix)"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "SHDW & Obscure Shape"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Wächter der Nacht (Original Mix)"), importFile.FileContentRecognized); - } - - [TestMethod()] - public async Task AnalyseAsync_TextfileWithStartDateTime_CreatesValidCuesheetAsync() - { - // Arrange - var fileContent = $@"Innellea~The Golden Fort~{new DateTime(2024, 8, 14, 20, 10, 48)} + var importProfile = new Importprofile() + { + UseRegularExpression = true, + SchemeCuesheet = @$"^(?<{nameof(ImportCuesheet.Artist)}>.+?)\s*-\s*(?<{nameof(ImportCuesheet.Title)}>.+?)\t+", + SchemeAudiofiles = @$"\s+(?<{nameof(ImportAudiofile.Name)}>\S+.mp3)", + SchemeTracks = @$"(?<{nameof(ImportTrack.Artist)}>.+?)\s*-\s*(?<{nameof(ImportTrack.Title)}>.+?)\s+(?<{nameof(ImportTrack.End)}>\d{{2}}:\d{{2}}:\d{{2}})" + }; + var options = new ImportOptions + { + SelectedImportProfile = importProfile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.IsNotNull(importFile.FileContentRecognized); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + var lines = importFile.FileContentRecognized.Split(Environment.NewLine); + Assert.AreEqual(string.Format("{0} - {1} {2}", + string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), + string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Title 8"), + string.Format(CuesheetConstants.RecognizedMarkHTML, "01:15:54")), lines.Last()); + } + + [TestMethod()] + public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedAsync() + { + // Arrange + var profile = new Importprofile() + { + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + }; + var fileContent = File.ReadAllText("Resources/Textimport_Bug_#233.txt"); + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.IsNotNull(importFile.FileContentRecognized); + var lines = importFile.FileContentRecognized.Split(Environment.NewLine); + Assert.AreEqual(string.Format("{0} - {1}\t\t\t\t\t\t\t\t{2}", + string.Format(CuesheetConstants.RecognizedMarkHTML, "Age Of Love"), + string.Format(CuesheetConstants.RecognizedMarkHTML, "The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)"), + string.Format(CuesheetConstants.RecognizedMarkHTML, "04:29:28")), lines.ElementAt(53)); + } + + [TestMethod()] + public async Task AnalyseAsync_WithRegularExpression_ReturnsCuesheetAsync() + { + // Arrange + var profile = new Importprofile() + { + UseRegularExpression = true, + SchemeTracks = "<tr>\\s*<td>\\d+</td>\\s*<td>(?<Artist>.*?)</td>\\s*<td>(?<Title>.*?)</td>\\s*<td>(?<StartDateTime>.*?)</td>\\s*</tr>" + }; + var fileContent = File.ReadAllText("Resources/Traktor Export.html"); + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.AreEqual(fileContent, importFile.FileContent); + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.IsNull(importFile.AnalyzedCuesheet.Artist); + Assert.IsNull(importFile.AnalyzedCuesheet.Title); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(41, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("Nachap", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Artist); + Assert.AreEqual("Glass", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Title); + Assert.AreEqual(new DateTime(2025, 1, 29, 18, 52, 10), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().StartDateTime); + Assert.AreEqual("Inache", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Artist); + Assert.AreEqual("Andale (MONTA (TN) Remix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); + Assert.AreEqual(new DateTime(2025, 1, 29, 22, 30, 3), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().StartDateTime); + Assert.IsNotNull(importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sasha Fashion"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "2025/1/29 21:48:55"), importFile.FileContentRecognized); + } + + [TestMethod()] + public async Task AnalyseAsync_WithoutRegularExpression_ReturnsCuesheetAsync() + { + // Arrange + var profile = new Importprofile() + { + UseRegularExpression = false, + SchemeCuesheet = "Artist - Title - Cataloguenumber", + SchemeTracks = "Artist - Title\tBegin" + }; + var fileContent = File.ReadAllText("Resources/Textimport with Cuesheetdata.txt"); + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.AreEqual("DJFreezeT", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("Rabbit Hole Mix", importFile.AnalyzedCuesheet.Title); + Assert.AreEqual("0123456789123", importFile.AnalyzedCuesheet.Cataloguenumber); + Assert.AreEqual("Adriatique", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Artist); + Assert.AreEqual("X.", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Title); + Assert.AreEqual(new TimeSpan(0, 0, 5, 24, 250), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.First().Begin); + Assert.AreEqual("Nikolay Kirov", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Artist); + Assert.AreEqual("Chasing the Sun (Original Mix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); + Assert.IsNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Begin); + Assert.IsNotNull(importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "DJFreezeT"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Rabbit Hole Mix"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "0123456789123"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Nikolay Kirov"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Chasing the Sun (Original Mix)"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "SHDW & Obscure Shape"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Wächter der Nacht (Original Mix)"), importFile.FileContentRecognized); + } + + [TestMethod()] + public async Task AnalyseAsync_TextfileWithStartDateTime_CreatesValidCuesheetAsync() + { + // Arrange + var fileContent = $@"Innellea~The Golden Fort~{new DateTime(2024, 8, 14, 20, 10, 48)} Nora En Pure~Diving with Whales (Daniel Portman Remix)~{new DateTime(2024, 8, 14, 20, 15, 21)} WhoMadeWho & Adriatique~Miracle (RÜFÜS DU SOL Remix)~{new DateTime(2024, 8, 14, 20, 20, 42)} Ella Wild~Poison D'araignee (Original Mix)~{new DateTime(2024, 8, 14, 20, 28, 03)} @@ -722,70 +722,69 @@ public async Task AnalyseAsync_TextfileWithStartDateTime_CreatesValidCuesheetAsy Eli Brown & Love Regenerator~Don't You Want Me (Original Mix)~{new DateTime(2024, 8, 14, 22, 21, 23)} Local Singles~Voices~{new DateTime(2024, 8, 14, 22, 25, 59)}"; - var profile = new Importprofile() - { - UseRegularExpression = false, - SchemeTracks = $"{nameof(ImportTrack.Artist)}~{nameof(ImportTrack.Title)}~{nameof(ImportTrack.StartDateTime)}" - }; - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.HasCount(30, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual("Innellea", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); - Assert.AreEqual("The Golden Fort", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new DateTime(2024, 8, 14, 20, 10, 48), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).StartDateTime); - Assert.AreEqual("Nora En Pure", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Artist); - Assert.AreEqual("Diving with Whales (Daniel Portman Remix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Title); - Assert.AreEqual(new DateTime(2024, 8, 14, 20, 15, 21), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).StartDateTime); - Assert.AreEqual("Local Singles", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(29).Artist); - Assert.AreEqual("Voices", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(29).Title); - Assert.AreEqual(new DateTime(2024, 8, 14, 22, 25, 59), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(29).StartDateTime); - } - - [TestMethod()] - public async Task AnalyseAsync_WithCommonDataMatchingMultipleLines_SetsCommonDataOnceAsync() - { - // Arrange - var profile = new Importprofile() - { - UseRegularExpression = false, - SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}", - SchemeAudiofiles = $"- {nameof(ImportAudiofile.Name)}", - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.StartDateTime)}" - }; - var fileContent = File.ReadAllText("Resources/Sample_Inputfile.txt"); - var options = new ImportOptions - { - SelectedImportProfile = profile - }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); - var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); - // Act - var importFile = await _textImportService.AnalyseAsync(fileContent); - // Assert - Assert.IsNull(importFile.AnalyseException); - Assert.IsNotNull(importFile.AnalyzedCuesheet); - Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); - Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); - Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); - Assert.AreEqual("c:\\AudioFile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); - Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\AudioFile.mp3"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), importFile.FileContentRecognized); - } + var profile = new Importprofile() + { + UseRegularExpression = false, + SchemeTracks = $"{nameof(ImportTrack.Artist)}~{nameof(ImportTrack.Title)}~{nameof(ImportTrack.StartDateTime)}" + }; + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.HasCount(30, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.AreEqual("Innellea", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); + Assert.AreEqual("The Golden Fort", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); + Assert.AreEqual(new DateTime(2024, 8, 14, 20, 10, 48), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).StartDateTime); + Assert.AreEqual("Nora En Pure", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Artist); + Assert.AreEqual("Diving with Whales (Daniel Portman Remix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).Title); + Assert.AreEqual(new DateTime(2024, 8, 14, 20, 15, 21), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(1).StartDateTime); + Assert.AreEqual("Local Singles", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(29).Artist); + Assert.AreEqual("Voices", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(29).Title); + Assert.AreEqual(new DateTime(2024, 8, 14, 22, 25, 59), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(29).StartDateTime); + } + + [TestMethod()] + public async Task AnalyseAsync_WithCommonDataMatchingMultipleLines_SetsCommonDataOnceAsync() + { + // Arrange + var profile = new Importprofile() + { + UseRegularExpression = false, + SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}", + SchemeAudiofiles = $"- {nameof(ImportAudiofile.Name)}", + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.StartDateTime)}" + }; + var fileContent = File.ReadAllText("Resources/Sample_Inputfile.txt"); + var options = new ImportOptions + { + SelectedImportProfile = profile + }; + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + var applicationOptions = new ApplicationOptions(); + _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + // Act + var importFile = await _textImportService.AnalyseAsync(fileContent); + // Assert + Assert.IsNull(importFile.AnalyseException); + Assert.IsNotNull(importFile.AnalyzedCuesheet); + Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); + Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); + Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); + Assert.AreEqual("c:\\AudioFile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); + Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.IsNotNull(importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\AudioFile.mp3"), importFile.FileContentRecognized); + Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), importFile.FileContentRecognized); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs b/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs index d23853d7..c49a0f45 100644 --- a/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs +++ b/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -28,77 +28,76 @@ using System.Text; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.Options +namespace AudioCuesheetEditor.Tests.Services.Options; + +[TestClass()] +public class LocalStorageOptionsProviderTests { - [TestClass()] - public class LocalStorageOptionsProviderTests + readonly LocalStorageOptionsProvider _service; + readonly Mock<IJSRuntime> _jsRuntime = new(); + readonly Mock<IStringLocalizer<ValidationMessage>> _localizer = new(); + + public LocalStorageOptionsProviderTests() { - private readonly LocalStorageOptionsProvider _service; - private readonly Mock<IJSRuntime> _jsRuntime = new(); - private readonly Mock<IStringLocalizer<ValidationMessage>> _localizer = new(); + _service = new(_jsRuntime.Object, _localizer.Object); + } - public LocalStorageOptionsProviderTests() + [TestMethod] + public async Task SaveOptionsAsync_NonValidatableOptions_ReturnsSuccessAsync() + { + // Arrange + var options = new ExportOptions(); + Boolean eventRaised = false; + _service.OptionSaved += delegate { - _service = new(_jsRuntime.Object, _localizer.Object); - } + eventRaised = true; + }; + // Act + var result = await _service.SaveOptionsAsync(options); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.IsTrue(eventRaised); + } - [TestMethod] - public async Task SaveOptionsAsync_NonValidatableOptions_ReturnsSuccessAsync() + [TestMethod] + public async Task SaveOptionsAsync_ValidOptions_ReturnsSuccessAsync() + { + // Arrange + var options = new DownloadOptions() { - // Arrange - var options = new ExportOptions(); - Boolean eventRaised = false; - _service.OptionSaved += delegate - { - eventRaised = true; - }; - // Act - var result = await _service.SaveOptionsAsync(options); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.IsTrue(eventRaised); - } - - [TestMethod] - public async Task SaveOptionsAsync_ValidOptions_ReturnsSuccessAsync() + ProjectFilename = "Test.ace", + CuesheetFilename = "Test.cue" + }; + Boolean eventRaised = false; + _service.OptionSaved += delegate { - // Arrange - var options = new DownloadOptions() - { - ProjectFilename = "Test.ace", - CuesheetFilename = "Test.cue" - }; - Boolean eventRaised = false; - _service.OptionSaved += delegate - { - eventRaised = true; - }; - // Act - var result = await _service.SaveOptionsAsync(options); - // Assert - Assert.IsTrue(result.IsSuccess); - Assert.IsTrue(eventRaised); - } + eventRaised = true; + }; + // Act + var result = await _service.SaveOptionsAsync(options); + // Assert + Assert.IsTrue(result.IsSuccess); + Assert.IsTrue(eventRaised); + } - [TestMethod] - public async Task SaveOptionsAsync_InvalidOptions_ReturnsFailureAsync() + [TestMethod] + public async Task SaveOptionsAsync_InvalidOptions_ReturnsFailureAsync() + { + // Arrange + var options = new DownloadOptions() + { + CuesheetFilename = null, + ProjectFilename = null + }; + Boolean eventRaised = false; + _service.OptionSaved += delegate { - // Arrange - var options = new DownloadOptions() - { - CuesheetFilename = null, - ProjectFilename = null - }; - Boolean eventRaised = false; - _service.OptionSaved += delegate - { - eventRaised = true; - }; - // Act - var result = await _service.SaveOptionsAsync(options); - // Assert - Assert.IsFalse(result.IsSuccess); - Assert.IsFalse(eventRaised); - } + eventRaised = true; + }; + // Act + var result = await _service.SaveOptionsAsync(options); + // Assert + Assert.IsFalse(result.IsSuccess); + Assert.IsFalse(eventRaised); } } diff --git a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs index 6412aa39..1ef18686 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -23,154 +23,153 @@ using System; using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.UI +namespace AudioCuesheetEditor.Tests.Services.UI; + +[TestClass()] +public class ApplicationOptionsTimeSpanParserTests { - [TestClass()] - public class ApplicationOptionsTimeSpanParserTests + [TestMethod] + public async Task TimespanTextChanged_ValidInput_SetsPropertyCorrectly() { - [TestMethod] - public async Task TimespanTextChanged_ValidInput_SetsPropertyCorrectly() + // Arrange + var options = new ApplicationOptions() { - // Arrange - var options = new ApplicationOptions() + TimeSpanFormat = new() { - TimeSpanFormat = new() - { - Scheme = "Minutes:Seconds" - } - }; - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - var track = new Track(); - // Act - await parser.TimespanTextChanged(track, x => x.Begin, "92:12"); - // Assert - Assert.AreEqual(new TimeSpan(1, 32, 12), track.Begin); - } + Scheme = "Minutes:Seconds" + } + }; + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + var track = new Track(); + // Act + await parser.TimespanTextChanged(track, x => x.Begin, "92:12"); + // Assert + Assert.AreEqual(new TimeSpan(1, 32, 12), track.Begin); + } - [TestMethod] - public async Task TimespanTextChanged_InvalidInput_SetsNull() + [TestMethod] + public async Task TimespanTextChanged_InvalidInput_SetsNull() + { + var options = new ApplicationOptions() { - var options = new ApplicationOptions() + TimeSpanFormat = new() { - TimeSpanFormat = new() - { - Scheme = "Minutes:Seconds" - } - }; - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - var track = new Track(); - // Act - await parser.TimespanTextChanged(track, x => x.End, "not a time"); - // Assert - Assert.IsNull(track.End); - } + Scheme = "Minutes:Seconds" + } + }; + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + var track = new Track(); + // Act + await parser.TimespanTextChanged(track, x => x.End, "not a time"); + // Assert + Assert.IsNull(track.End); + } - [TestMethod()] - public void GetTimespanFormatted_ValidFormat_ReturnsCorrectString() + [TestMethod()] + public void GetTimespanFormatted_ValidFormat_ReturnsCorrectString() + { + // Arrange + var options = new ApplicationOptions() { - // Arrange - var options = new ApplicationOptions() - { - DisplayTimeSpanFormat = @"hh\:mm\:ss" - }; - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - // Act - var result = parser.GetTimespanFormatted(new TimeSpan(0, 1, 30, 27, 200, 103)); - // Assert - Assert.AreEqual("01:30:27", result); - } + DisplayTimeSpanFormat = @"hh\:mm\:ss" + }; + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + // Act + var result = parser.GetTimespanFormatted(new TimeSpan(0, 1, 30, 27, 200, 103)); + // Assert + Assert.AreEqual("01:30:27", result); + } - [TestMethod()] - public void GetTimespanFormatted_InvalidFormat_FallbackToDefault() + [TestMethod()] + public void GetTimespanFormatted_InvalidFormat_FallbackToDefault() + { + // Arrange + var options = new ApplicationOptions() { - // Arrange - var options = new ApplicationOptions() - { - DisplayTimeSpanFormat = "INVALID_FORMAT" - }; - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - // Act - var result = parser.GetTimespanFormatted(new TimeSpan(0, 1, 30, 27, 200, 103)); - // Assert - Assert.AreEqual("01:30:27.2001030", result); - } + DisplayTimeSpanFormat = "INVALID_FORMAT" + }; + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + // Act + var result = parser.GetTimespanFormatted(new TimeSpan(0, 1, 30, 27, 200, 103)); + // Assert + Assert.AreEqual("01:30:27.2001030", result); + } - [TestMethod()] - public async Task GetTimespanAsync_CustomValidFormat_ReturnsTimeSpanAsync() + [TestMethod()] + public async Task GetTimespanAsync_CustomValidFormat_ReturnsTimeSpanAsync() + { + // Arrange + var options = new ApplicationOptions() { - // Arrange - var options = new ApplicationOptions() + TimeSpanFormat = new() { - TimeSpanFormat = new() - { - Scheme = $"{TimeSpanFormat.Hours}-{TimeSpanFormat.Minutes}-{TimeSpanFormat.Seconds}" - } - }; - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - // Act - var result = await parser.GetTimespanAsync("23-45-56"); - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(new TimeSpan(23, 45, 56), result); - } + Scheme = $"{TimeSpanFormat.Hours}-{TimeSpanFormat.Minutes}-{TimeSpanFormat.Seconds}" + } + }; + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + // Act + var result = await parser.GetTimespanAsync("23-45-56"); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(new TimeSpan(23, 45, 56), result); + } - [TestMethod()] - public async Task GetTimespanAsync_CustomInvalidFormat_ReturnsNullAsync() + [TestMethod()] + public async Task GetTimespanAsync_CustomInvalidFormat_ReturnsNullAsync() + { + // Arrange + var options = new ApplicationOptions() { - // Arrange - var options = new ApplicationOptions() + TimeSpanFormat = new() { - TimeSpanFormat = new() - { - Scheme = $"INVALID_FORMAT" - } - }; - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - // Act - var result = await parser.GetTimespanAsync("23-45-56"); - // Assert - Assert.IsNull(result); - } + Scheme = $"INVALID_FORMAT" + } + }; + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + // Act + var result = await parser.GetTimespanAsync("23-45-56"); + // Assert + Assert.IsNull(result); + } - [TestMethod()] - public async Task GetTimespanAsync_DefaultFormat_ReturnsTimeSpanAsync() - { - // Arrange - var options = new ApplicationOptions(); - var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider - .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) - .ReturnsAsync(options); - var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); - // Act - var result = await parser.GetTimespanAsync("23:45:56"); - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(new TimeSpan(23, 45, 56), result); - } + [TestMethod()] + public async Task GetTimespanAsync_DefaultFormat_ReturnsTimeSpanAsync() + { + // Arrange + var options = new ApplicationOptions(); + var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); + mockOptionsProvider + .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + // Act + var result = await parser.GetTimespanAsync("23:45:56"); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(new TimeSpan(23, 45, 56), result); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs b/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs index 3d00bf25..962e647a 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -20,327 +20,344 @@ using AudioCuesheetEditor.Services.Options; using AudioCuesheetEditor.Services.UI; using Microsoft.JSInterop; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using System; -using System.Threading.Tasks; -namespace AudioCuesheetEditor.Tests.Services.UI +namespace AudioCuesheetEditor.Tests.Services.UI; + +[TestClass] +public class SessionStateContainerTests : IDisposable { - [TestClass] - public class SessionStateContainerTests - { - private readonly SessionStateContainer _sessionStateContainer; - private readonly Mock<ILocalStorageOptionsProvider> _localStorageOptionsProvider; - private readonly Mock<IJSRuntime> _jsRuntime; + readonly SessionStateContainer _sessionStateContainer; + readonly Mock<ILocalStorageOptionsProvider> _localStorageOptionsProvider; + readonly Mock<IJSRuntime> _jsRuntime; + bool _disposedValue; - public SessionStateContainerTests() - { - _localStorageOptionsProvider = new(); - _jsRuntime = new(); - _sessionStateContainer = new(_localStorageOptionsProvider.Object, _jsRuntime.Object); - } + public SessionStateContainerTests() + { + _localStorageOptionsProvider = new(); + _jsRuntime = new(); + _sessionStateContainer = new(_localStorageOptionsProvider.Object, _jsRuntime.Object); + } - [TestMethod] - public async Task Cuesheet_SetNewValueInDetailView_ShouldTriggerActiveCuesheetChangedEventAsync() - { - // Arrange - var newCuesheet = new Cuesheet(); - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - bool activeCuesheetChangedEvent = false; - bool cuesheetChangedEvent = false; - _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => activeCuesheetChangedEvent = true; - _sessionStateContainer.CuesheetChanged += (sender, args) => cuesheetChangedEvent = true; - - // Act - _sessionStateContainer.Cuesheet = newCuesheet; - - // Assert - Assert.IsTrue(activeCuesheetChangedEvent); - Assert.IsTrue(cuesheetChangedEvent); - } - [TestMethod] - public async Task Cuesheet_SetNewValueInImportView_ShouldNotTriggerActiveCuesheetChangedEventAsync() + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) { - // Arrange - var newCuesheet = new Cuesheet(); - var viewOptions = new ViewOptions() + if (disposing) { - ActiveTab = ViewMode.ImportView - }; - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - bool eventTriggered = false; - bool cuesheetChangedEvent = false; - _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; - _sessionStateContainer.CuesheetChanged += (sender, args) => cuesheetChangedEvent = true; - // Act - _sessionStateContainer.Cuesheet = newCuesheet; - - // Assert - Assert.IsFalse(eventTriggered); - Assert.IsTrue(cuesheetChangedEvent); + _sessionStateContainer.Dispose(); + } + _disposedValue = true; } + } - [TestMethod] - public async Task ImportCuesheet_SetNewValueInImportView_ShouldTriggerActiveCuesheetChangedEventAsync() - { - // Arrange - var newImportCuesheet = new Cuesheet(); - var viewOptions = new ViewOptions() - { - ActiveTab = ViewMode.ImportView - }; - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - bool eventTriggered = false; - _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; - - // Act - _sessionStateContainer.ImportCuesheet = newImportCuesheet; - - // Assert - Assert.IsTrue(eventTriggered); - } + public void Dispose() + { + // Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(bool disposing)" ein. + Dispose(disposing: true); + GC.SuppressFinalize(this); + } - [TestMethod] - public async Task ImportCuesheet_SetNewValueInDetailView_ShouldTriggerActiveCuesheetChangedEventAsync() - { - // Arrange - var newImportCuesheet = new Cuesheet(); - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - bool eventTriggered = false; - _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; - - // Act - _sessionStateContainer.ImportCuesheet = newImportCuesheet; - - // Assert - Assert.IsFalse(eventTriggered); - } + [TestMethod] + public async Task Cuesheet_SetNewValueInDetailView_ShouldTriggerActiveCuesheetChangedEventAsync() + { + // Arrange + var newCuesheet = new Cuesheet(); + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + bool activeCuesheetChangedEvent = false; + bool cuesheetChangedEvent = false; + _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => activeCuesheetChangedEvent = true; + _sessionStateContainer.CuesheetChanged += (sender, args) => cuesheetChangedEvent = true; - [TestMethod] - public async Task ResetImportAsync_RevokeObjectUrls_ShouldClearPropertiesAsync() - { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - _sessionStateContainer.Importfile = Mock.Of<IImportfile>(); - _sessionStateContainer.ImportCuesheet = new Cuesheet(); - _sessionStateContainer.ImportIsAnalyzed = true; - var importAudiofile1 = new Audiofile() - { - ObjectURL = "File 1" - }; - var importAudiofile2 = new Audiofile() - { - ObjectURL = "File 2" - }; - _sessionStateContainer.ImportAudiofiles.Add(importAudiofile1); - _sessionStateContainer.ImportAudiofiles.Add(importAudiofile2); - var importAudiofile3 = new Audiofile() - { - ObjectURL = "File 3" - }; - var importAudiofile4 = new Audiofile() - { - ObjectURL = "File 4" - }; - _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile3); - _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile4); - - // Act - await _sessionStateContainer.ResetImportAsync(true); - - // Assert - Assert.IsNull(_sessionStateContainer.Importfile); - Assert.IsEmpty(_sessionStateContainer.ImportAudiofiles); - Assert.IsNull(_sessionStateContainer.ImportCuesheet); - Assert.IsFalse(_sessionStateContainer.ImportIsAnalyzed); - Assert.IsEmpty(_sessionStateContainer.ImportAudiofileMapping); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile1.ObjectURL)), Times.Once); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile2.ObjectURL)), Times.Once); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile3.ObjectURL)), Times.Once); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile4.ObjectURL)), Times.Once); - } + // Act + _sessionStateContainer.Cuesheet = newCuesheet; - [TestMethod] - public async Task ResetImportAsync_RevokeObjectUrlsNotSet_ShouldClearPropertiesAsync() - { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - _sessionStateContainer.Importfile = Mock.Of<IImportfile>(); - _sessionStateContainer.ImportCuesheet = new Cuesheet(); - _sessionStateContainer.ImportIsAnalyzed = true; - var importAudiofile1 = new Audiofile() - { - ObjectURL = "File 1" - }; - var importAudiofile2 = new Audiofile() - { - ObjectURL = "File 2" - }; - _sessionStateContainer.ImportAudiofiles.Add(importAudiofile1); - _sessionStateContainer.ImportAudiofiles.Add(importAudiofile2); - var importAudiofile3 = new Audiofile() - { - ObjectURL = "File 3" - }; - var importAudiofile4 = new Audiofile() - { - ObjectURL = "File 4" - }; - _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile3); - _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile4); - - // Act - await _sessionStateContainer.ResetImportAsync(false); - - // Assert - Assert.IsNull(_sessionStateContainer.Importfile); - Assert.IsEmpty(_sessionStateContainer.ImportAudiofiles); - Assert.IsNull(_sessionStateContainer.ImportCuesheet); - Assert.IsFalse(_sessionStateContainer.ImportIsAnalyzed); - Assert.IsEmpty(_sessionStateContainer.ImportAudiofileMapping); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile1.ObjectURL)), Times.Never); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile2.ObjectURL)), Times.Never); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile3.ObjectURL)), Times.Never); - _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile4.ObjectURL)), Times.Never); - } + // Assert + Assert.IsTrue(activeCuesheetChangedEvent); + Assert.IsTrue(cuesheetChangedEvent); + } - [TestMethod] - public async Task InitializeAsync_NotInitialized_ShouldInitializeAsync() + [TestMethod] + public async Task Cuesheet_SetNewValueInImportView_ShouldNotTriggerActiveCuesheetChangedEventAsync() + { + // Arrange + var newCuesheet = new Cuesheet(); + var viewOptions = new ViewOptions() { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - // Act - await _sessionStateContainer.InitializeAsync(); - // Assert - _localStorageOptionsProvider.Verify(x => x.GetOptionsAsync<ViewOptions>(), Times.Once); - } + ActiveTab = ViewMode.ImportView + }; + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + bool eventTriggered = false; + bool cuesheetChangedEvent = false; + _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; + _sessionStateContainer.CuesheetChanged += (sender, args) => cuesheetChangedEvent = true; + // Act + _sessionStateContainer.Cuesheet = newCuesheet; + + // Assert + Assert.IsFalse(eventTriggered); + Assert.IsTrue(cuesheetChangedEvent); + } - [TestMethod] - public async Task InitializeAsync_Initialized_ShouldNotInitializeAsync() + [TestMethod] + public async Task ImportCuesheet_SetNewValueInImportView_ShouldTriggerActiveCuesheetChangedEventAsync() + { + // Arrange + var newImportCuesheet = new Cuesheet(); + var viewOptions = new ViewOptions() { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - // Act - await _sessionStateContainer.InitializeAsync(); - // Assert - _localStorageOptionsProvider.Verify(x => x.GetOptionsAsync<ViewOptions>(), Times.Once); - } + ActiveTab = ViewMode.ImportView + }; + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + bool eventTriggered = false; + _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; + + // Act + _sessionStateContainer.ImportCuesheet = newImportCuesheet; - [TestMethod] - public async Task ActiveCuesheet_Initialized_ReturnsDetailViewCuesheet() + // Assert + Assert.IsTrue(eventTriggered); + } + + [TestMethod] + public async Task ImportCuesheet_SetNewValueInDetailView_ShouldTriggerActiveCuesheetChangedEventAsync() + { + // Arrange + var newImportCuesheet = new Cuesheet(); + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + bool eventTriggered = false; + _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; + + // Act + _sessionStateContainer.ImportCuesheet = newImportCuesheet; + + // Assert + Assert.IsFalse(eventTriggered); + } + + [TestMethod] + public async Task ResetImportAsync_RevokeObjectUrls_ShouldClearPropertiesAsync() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + _sessionStateContainer.Importfile = Mock.Of<IImportfile>(); + _sessionStateContainer.ImportCuesheet = new Cuesheet(); + _sessionStateContainer.ImportIsAnalyzed = true; + var importAudiofile1 = new Audiofile() { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - // Act - var cuesheet = _sessionStateContainer.ActiveCuesheet; - // Assert - Assert.AreEqual(_sessionStateContainer.Cuesheet, cuesheet); - } + ObjectURL = "File 1" + }; + var importAudiofile2 = new Audiofile() + { + ObjectURL = "File 2" + }; + _sessionStateContainer.ImportAudiofiles.Add(importAudiofile1); + _sessionStateContainer.ImportAudiofiles.Add(importAudiofile2); + var importAudiofile3 = new Audiofile() + { + ObjectURL = "File 3" + }; + var importAudiofile4 = new Audiofile() + { + ObjectURL = "File 4" + }; + _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile3); + _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile4); + + // Act + await _sessionStateContainer.ResetImportAsync(true); + + // Assert + Assert.IsNull(_sessionStateContainer.Importfile); + Assert.IsEmpty(_sessionStateContainer.ImportAudiofiles); + Assert.IsNull(_sessionStateContainer.ImportCuesheet); + Assert.IsFalse(_sessionStateContainer.ImportIsAnalyzed); + Assert.IsEmpty(_sessionStateContainer.ImportAudiofileMapping); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile1.ObjectURL)), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile2.ObjectURL)), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile3.ObjectURL)), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile4.ObjectURL)), Times.Once); + } - [TestMethod] - public async Task ActiveCuesheet_SwitchViewSignalesUpdate_ReturnsImportViewCuesheet() + [TestMethod] + public async Task ResetImportAsync_RevokeObjectUrlsNotSet_ShouldClearPropertiesAsync() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + _sessionStateContainer.Importfile = Mock.Of<IImportfile>(); + _sessionStateContainer.ImportCuesheet = new Cuesheet(); + _sessionStateContainer.ImportIsAnalyzed = true; + var importAudiofile1 = new Audiofile() + { + ObjectURL = "File 1" + }; + var importAudiofile2 = new Audiofile() { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - viewOptions.ActiveTab = ViewMode.ImportView; + ObjectURL = "File 2" + }; + _sessionStateContainer.ImportAudiofiles.Add(importAudiofile1); + _sessionStateContainer.ImportAudiofiles.Add(importAudiofile2); + var importAudiofile3 = new Audiofile() + { + ObjectURL = "File 3" + }; + var importAudiofile4 = new Audiofile() + { + ObjectURL = "File 4" + }; + _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile3); + _sessionStateContainer.ImportAudiofileMapping.Add(new(), importAudiofile4); - _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => - { - _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions); - }); - - Boolean activeCuesheetChangedEventTriggered = false; - _sessionStateContainer.ActiveCuesheetChanged += delegate - { - activeCuesheetChangedEventTriggered = true; - }; - _sessionStateContainer.Cuesheet.Title = "Cuesheet"; - _sessionStateContainer.ImportCuesheet = new() - { - Title = "ImportCuesheet" - }; - await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); - // Act - var cuesheet = _sessionStateContainer.ActiveCuesheet; - // Assert - Assert.AreEqual(_sessionStateContainer.ImportCuesheet, cuesheet); - Assert.IsTrue(activeCuesheetChangedEventTriggered); - } + // Act + await _sessionStateContainer.ResetImportAsync(false); + + // Assert + Assert.IsNull(_sessionStateContainer.Importfile); + Assert.IsEmpty(_sessionStateContainer.ImportAudiofiles); + Assert.IsNull(_sessionStateContainer.ImportCuesheet); + Assert.IsFalse(_sessionStateContainer.ImportIsAnalyzed); + Assert.IsEmpty(_sessionStateContainer.ImportAudiofileMapping); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile1.ObjectURL)), Times.Never); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile2.ObjectURL)), Times.Never); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile3.ObjectURL)), Times.Never); + _jsRuntime.Verify(js => js.InvokeAsync<object>("revokeAudioObjectURL", It.Is<object?[]>(args => args != null && args.Length > 0 && (args[0] as string) == importAudiofile4.ObjectURL)), Times.Never); + } + + [TestMethod] + public async Task InitializeAsync_NotInitialized_ShouldInitializeAsync() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + // Act + await _sessionStateContainer.InitializeAsync(); + // Assert + _localStorageOptionsProvider.Verify(x => x.GetOptionsAsync<ViewOptions>(), Times.Once); + } + + [TestMethod] + public async Task InitializeAsync_Initialized_ShouldNotInitializeAsync() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + // Act + await _sessionStateContainer.InitializeAsync(); + // Assert + _localStorageOptionsProvider.Verify(x => x.GetOptionsAsync<ViewOptions>(), Times.Once); + } - [TestMethod] - public async Task ActiveCuesheet_SaveOptionsSetsActiveCuesheetOnce_ReturnsDetailViewCuesheet() + [TestMethod] + public async Task ActiveCuesheet_Initialized_ReturnsDetailViewCuesheet() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + // Act + var cuesheet = _sessionStateContainer.ActiveCuesheet; + // Assert + Assert.AreEqual(_sessionStateContainer.Cuesheet, cuesheet); + } + + [TestMethod] + public async Task ActiveCuesheet_SwitchViewSignalesUpdate_ReturnsImportViewCuesheet() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + viewOptions.ActiveTab = ViewMode.ImportView; + + _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => { - // Arrange - var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => - { - _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions); - }); - _sessionStateContainer.Cuesheet.Title = "Cuesheet"; - _sessionStateContainer.ImportCuesheet = new() - { - Title = "ImportCuesheet" - }; - viewOptions.ActiveTab = ViewMode.ImportView; - await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); - Boolean activeCuesheetChangedEventTriggered = false; - _sessionStateContainer.ActiveCuesheetChanged += delegate - { - activeCuesheetChangedEventTriggered = true; - }; - await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); - // Act - var cuesheet = _sessionStateContainer.ActiveCuesheet; - // Assert - Assert.AreEqual(_sessionStateContainer.ImportCuesheet, cuesheet); - Assert.IsFalse(activeCuesheetChangedEventTriggered); - } + _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions); + }); + + Boolean activeCuesheetChangedEventTriggered = false; + _sessionStateContainer.ActiveCuesheetChanged += delegate + { + activeCuesheetChangedEventTriggered = true; + }; + _sessionStateContainer.Cuesheet.Title = "Cuesheet"; + _sessionStateContainer.ImportCuesheet = new() + { + Title = "ImportCuesheet" + }; + await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); + // Act + var cuesheet = _sessionStateContainer.ActiveCuesheet; + // Assert + Assert.AreEqual(_sessionStateContainer.ImportCuesheet, cuesheet); + Assert.IsTrue(activeCuesheetChangedEventTriggered); + } - [TestMethod] - public async Task ActiveCuesheet_InitializedWithImportView_ReturnsDetailViewCuesheet() + [TestMethod] + public async Task ActiveCuesheet_SaveOptionsSetsActiveCuesheetOnce_ReturnsDetailViewCuesheet() + { + // Arrange + var viewOptions = new ViewOptions(); + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => { - // Arrange - var viewOptions = new ViewOptions() - { - ActiveTab = ViewMode.ImportView - }; - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); - await _sessionStateContainer.InitializeAsync(); - // Act - var result = _sessionStateContainer.ActiveCuesheet; - // Assert - Assert.AreEqual(_sessionStateContainer.ImportCuesheet, result); - } + _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions); + }); + _sessionStateContainer.Cuesheet.Title = "Cuesheet"; + _sessionStateContainer.ImportCuesheet = new() + { + Title = "ImportCuesheet" + }; + viewOptions.ActiveTab = ViewMode.ImportView; + await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); + Boolean activeCuesheetChangedEventTriggered = false; + _sessionStateContainer.ActiveCuesheetChanged += delegate + { + activeCuesheetChangedEventTriggered = true; + }; + await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); + // Act + var cuesheet = _sessionStateContainer.ActiveCuesheet; + // Assert + Assert.AreEqual(_sessionStateContainer.ImportCuesheet, cuesheet); + Assert.IsFalse(activeCuesheetChangedEventTriggered); + } - [TestMethod] - public void ActiveCuesheet_NotInitialized_ReturnsNull() + [TestMethod] + public async Task ActiveCuesheet_InitializedWithImportView_ReturnsDetailViewCuesheet() + { + // Arrange + var viewOptions = new ViewOptions() { - // Arrange - // Act - var cuesheet = _sessionStateContainer.ActiveCuesheet; - // Assert - Assert.IsNull(cuesheet); - } + ActiveTab = ViewMode.ImportView + }; + _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + await _sessionStateContainer.InitializeAsync(); + // Act + var result = _sessionStateContainer.ActiveCuesheet; + // Assert + Assert.AreEqual(_sessionStateContainer.ImportCuesheet, result); + } + + [TestMethod] + public void ActiveCuesheet_NotInitialized_ReturnsNull() + { + // Arrange + // Act + var cuesheet = _sessionStateContainer.ActiveCuesheet; + // Assert + Assert.IsNull(cuesheet); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs index f1eeef6f..c610fe94 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -22,382 +22,381 @@ using System.Collections.Generic; using System.Linq; -namespace AudioCuesheetEditor.Tests.Services.UI +namespace AudioCuesheetEditor.Tests.Services.UI; + +[TestClass()] +public class TraceChangeManagerTests { - [TestClass()] - public class TraceChangeManagerTests - { - private readonly TraceChangeManager _traceChangeManager = new(TestHelper.CreateLogger<TraceChangeManager>()); + readonly TraceChangeManager _traceChangeManager = new(TestHelper.CreateLogger<TraceChangeManager>()); - [TestMethod()] - public void AddChange_SingleChange_EnablesUndo() + [TestMethod()] + public void AddChange_SingleChange_EnablesUndo() + { + // Arrange + var cuesheet = new Cuesheet { - // Arrange - var cuesheet = new Cuesheet - { - Artist = "Test Artist 1" - }; - var tracedObjectHistoryChangedFired = false; - _traceChangeManager.TracedObjectHistoryChanged += delegate - { - tracedObjectHistoryChangedFired = true; - }; - // Act - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Artist)))); - // Assert - Assert.IsTrue(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - Assert.IsTrue(tracedObjectHistoryChangedFired); - } - - [TestMethod()] - public void AddChange_BulkChange_EnablesUndo() + Artist = "Test Artist 1" + }; + var tracedObjectHistoryChangedFired = false; + _traceChangeManager.TracedObjectHistoryChanged += delegate { - // Arrange - var cuesheet = new Cuesheet - { - Artist = "Test Artist 1", - Title = "Test Title 1", - Cataloguenumber = "1234567890" - }; - var tracedObjectHistoryChangedFired = false; - _traceChangeManager.TracedObjectHistoryChanged += delegate - { - tracedObjectHistoryChangedFired = true; - }; - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Artist)))); - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Title)))); - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Cataloguenumber)))); - // Act - _traceChangeManager.BulkEdit = false; - // Assert - Assert.IsTrue(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - Assert.IsTrue(tracedObjectHistoryChangedFired); - } + tracedObjectHistoryChangedFired = true; + }; + // Act + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Artist)))); + // Assert + Assert.IsTrue(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + Assert.IsTrue(tracedObjectHistoryChangedFired); + } - [TestMethod()] - public void BulkEdit_WithoutChange_DoesntAddChange() + [TestMethod()] + public void AddChange_BulkChange_EnablesUndo() + { + // Arrange + var cuesheet = new Cuesheet { - // Arrange - _traceChangeManager.BulkEdit = true; - // Act - _traceChangeManager.BulkEdit = false; - // Assert - Assert.IsFalse(_traceChangeManager.CanUndo); - } - - [TestMethod()] - public void BulkEdit_AlreadyEnabledBulkEdit_DoesntDropPreviousEdits() + Artist = "Test Artist 1", + Title = "Test Title 1", + Cataloguenumber = "1234567890" + }; + var tracedObjectHistoryChangedFired = false; + _traceChangeManager.TracedObjectHistoryChanged += delegate { - // Arrange - var cuesheet = new Cuesheet - { - Artist = "Test Artist 1", - Title = "Test Title 1", - Cataloguenumber = "1234567890" - }; - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Artist)))); - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Title)))); - _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Cataloguenumber)))); - _traceChangeManager.BulkEdit = true; - _traceChangeManager.BulkEdit = false; - // Act - _traceChangeManager.Undo(); - // Assert - Assert.IsNull(cuesheet.Artist); - Assert.IsNull(cuesheet.Title); - Assert.IsNull(cuesheet.Cataloguenumber); - Assert.IsTrue(_traceChangeManager.CanRedo); - } + tracedObjectHistoryChangedFired = true; + }; + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Artist)))); + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Title)))); + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Cataloguenumber)))); + // Act + _traceChangeManager.BulkEdit = false; + // Assert + Assert.IsTrue(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + Assert.IsTrue(tracedObjectHistoryChangedFired); + } + [TestMethod()] + public void BulkEdit_WithoutChange_DoesntAddChange() + { + // Arrange + _traceChangeManager.BulkEdit = true; + // Act + _traceChangeManager.BulkEdit = false; + // Assert + Assert.IsFalse(_traceChangeManager.CanUndo); + } - [TestMethod()] - public void BulkEditFalse_AfterBulkEditAndUndo_ResetsRedoStack() + [TestMethod()] + public void BulkEdit_AlreadyEnabledBulkEdit_DoesntDropPreviousEdits() + { + // Arrange + var cuesheet = new Cuesheet { - // Arrange - var audiofile = new Audiofile(); - var track1 = new Track(); - var track2 = new Track(); - var track3 = new Track(); - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(audiofile, new(new List<Track>() { track1 }, nameof(Audiofile.Tracks)))); - track1.Audiofile = audiofile; - _traceChangeManager.BulkEdit = false; - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(audiofile, new(new List<Track>() { track1, track2 }, nameof(Audiofile.Tracks)))); - track1.Audiofile = audiofile; - track2.Audiofile = audiofile; - _traceChangeManager.BulkEdit = false; - _traceChangeManager.Undo(); - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(audiofile, new(new List<Track>() { track1, track2, track3 }, nameof(Audiofile.Tracks)))); - track1.Audiofile = audiofile; - track2.Audiofile = audiofile; - track3.Audiofile = audiofile; - _traceChangeManager.BulkEdit = false; - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(track2, new("Testartist", nameof(Track.Artist)))); - // Act - _traceChangeManager.BulkEdit = false; - // Assert - Assert.IsTrue(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - } + Artist = "Test Artist 1", + Title = "Test Title 1", + Cataloguenumber = "1234567890" + }; + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Artist)))); + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Title)))); + _traceChangeManager.AddChange(new(cuesheet, new(null, nameof(Cuesheet.Cataloguenumber)))); + _traceChangeManager.BulkEdit = true; + _traceChangeManager.BulkEdit = false; + // Act + _traceChangeManager.Undo(); + // Assert + Assert.IsNull(cuesheet.Artist); + Assert.IsNull(cuesheet.Title); + Assert.IsNull(cuesheet.Cataloguenumber); + Assert.IsTrue(_traceChangeManager.CanRedo); + } + + + [TestMethod()] + public void BulkEditFalse_AfterBulkEditAndUndo_ResetsRedoStack() + { + // Arrange + var audiofile = new Audiofile(); + var track1 = new Track(); + var track2 = new Track(); + var track3 = new Track(); + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(audiofile, new(new List<Track>() { track1 }, nameof(Audiofile.Tracks)))); + track1.Audiofile = audiofile; + _traceChangeManager.BulkEdit = false; + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(audiofile, new(new List<Track>() { track1, track2 }, nameof(Audiofile.Tracks)))); + track1.Audiofile = audiofile; + track2.Audiofile = audiofile; + _traceChangeManager.BulkEdit = false; + _traceChangeManager.Undo(); + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(audiofile, new(new List<Track>() { track1, track2, track3 }, nameof(Audiofile.Tracks)))); + track1.Audiofile = audiofile; + track2.Audiofile = audiofile; + track3.Audiofile = audiofile; + _traceChangeManager.BulkEdit = false; + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(track2, new("Testartist", nameof(Track.Artist)))); + // Act + _traceChangeManager.BulkEdit = false; + // Assert + Assert.IsTrue(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + } - [TestMethod()] - public void Undo_SingleChange_UndoesChange() + [TestMethod()] + public void Undo_SingleChange_UndoesChange() + { + // Arrange + var track = new Track { - // Arrange - var track = new Track - { - Position = 3 - }; - var undoDoneEventFired = false; - _traceChangeManager.UndoDone += delegate - { - undoDoneEventFired = true; - }; - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); - // Act - _traceChangeManager.Undo(); - // Assert - Assert.IsNull(track.Position); - Assert.IsTrue(undoDoneEventFired); - Assert.IsFalse(_traceChangeManager.CanUndo); - Assert.IsTrue(_traceChangeManager.CanRedo); - } + Position = 3 + }; + var undoDoneEventFired = false; + _traceChangeManager.UndoDone += delegate + { + undoDoneEventFired = true; + }; + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); + // Act + _traceChangeManager.Undo(); + // Assert + Assert.IsNull(track.Position); + Assert.IsTrue(undoDoneEventFired); + Assert.IsFalse(_traceChangeManager.CanUndo); + Assert.IsTrue(_traceChangeManager.CanRedo); + } - [TestMethod()] - public void Undo_BulkChange_UndoesChanges() + [TestMethod()] + public void Undo_BulkChange_UndoesChanges() + { + // Arrange + var track = new Track { - // Arrange - var track = new Track - { - Position = 3, - Artist = "Artist" - }; - var undoDoneEventFired = false; - _traceChangeManager.UndoDone += delegate - { - undoDoneEventFired = true; - }; - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); - _traceChangeManager.BulkEdit = false; - // Act - _traceChangeManager.Undo(); - // Assert - Assert.IsNull(track.Position); - Assert.IsNull(track.Artist); - Assert.IsTrue(undoDoneEventFired); - Assert.IsFalse(_traceChangeManager.CanUndo); - Assert.IsTrue(_traceChangeManager.CanRedo); - } + Position = 3, + Artist = "Artist" + }; + var undoDoneEventFired = false; + _traceChangeManager.UndoDone += delegate + { + undoDoneEventFired = true; + }; + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); + _traceChangeManager.BulkEdit = false; + // Act + _traceChangeManager.Undo(); + // Assert + Assert.IsNull(track.Position); + Assert.IsNull(track.Artist); + Assert.IsTrue(undoDoneEventFired); + Assert.IsFalse(_traceChangeManager.CanUndo); + Assert.IsTrue(_traceChangeManager.CanRedo); + } - [TestMethod()] - public void Redo_SingleChange_UndoesChange() + [TestMethod()] + public void Redo_SingleChange_UndoesChange() + { + // Arrange + var track = new Track + { + Position = 3 + }; + var redoDoneEventFired = false; + _traceChangeManager.RedoDone += delegate { - // Arrange - var track = new Track - { - Position = 3 - }; - var redoDoneEventFired = false; - _traceChangeManager.RedoDone += delegate - { - redoDoneEventFired = true; - }; - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); - _traceChangeManager.Undo(); - // Act - _traceChangeManager.Redo(); - // Assert - Assert.AreEqual((ushort)3, track.Position); - Assert.IsTrue(redoDoneEventFired); - Assert.IsTrue(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - } + redoDoneEventFired = true; + }; + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); + _traceChangeManager.Undo(); + // Act + _traceChangeManager.Redo(); + // Assert + Assert.AreEqual((ushort)3, track.Position); + Assert.IsTrue(redoDoneEventFired); + Assert.IsTrue(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + } - [TestMethod()] - public void Redo_BulkChange_UndoesChanges() + [TestMethod()] + public void Redo_BulkChange_UndoesChanges() + { + // Arrange + var track = new Track + { + Position = 3, + Artist = "Artist" + }; + var redoDoneEventFired = false; + _traceChangeManager.RedoDone += delegate { - // Arrange - var track = new Track - { - Position = 3, - Artist = "Artist" - }; - var redoDoneEventFired = false; - _traceChangeManager.RedoDone += delegate - { - redoDoneEventFired = true; - }; - _traceChangeManager.BulkEdit = true; - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); - _traceChangeManager.BulkEdit = false; - _traceChangeManager.Undo(); - // Act - _traceChangeManager.Redo(); - // Assert - Assert.AreEqual((ushort)3, track.Position); - Assert.AreEqual("Artist", track.Artist); - Assert.IsTrue(redoDoneEventFired); - Assert.IsTrue(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - } + redoDoneEventFired = true; + }; + _traceChangeManager.BulkEdit = true; + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Position)))); + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); + _traceChangeManager.BulkEdit = false; + _traceChangeManager.Undo(); + // Act + _traceChangeManager.Redo(); + // Assert + Assert.AreEqual((ushort)3, track.Position); + Assert.AreEqual("Artist", track.Artist); + Assert.IsTrue(redoDoneEventFired); + Assert.IsTrue(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + } - [TestMethod] - public void Undo_ObjectReferences_UndoesChanges() + [TestMethod] + public void Undo_ObjectReferences_UndoesChanges() + { + // Arrange + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [new()] + } + ] + }; + var undoDoneEventFired = false; + _traceChangeManager.UndoDone += delegate { - // Arrange - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [new()] - } - ] - }; - var undoDoneEventFired = false; - _traceChangeManager.UndoDone += delegate - { - undoDoneEventFired = true; - }; - _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); - // Act - _traceChangeManager.Undo(); - // Assert - Assert.IsEmpty(cuesheet.Audiofiles.First().Tracks); - Assert.IsFalse(_traceChangeManager.CanUndo); - Assert.IsTrue(_traceChangeManager.CanRedo); - Assert.IsTrue(undoDoneEventFired); - } + undoDoneEventFired = true; + }; + _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); + // Act + _traceChangeManager.Undo(); + // Assert + Assert.IsEmpty(cuesheet.Audiofiles.First().Tracks); + Assert.IsFalse(_traceChangeManager.CanUndo); + Assert.IsTrue(_traceChangeManager.CanRedo); + Assert.IsTrue(undoDoneEventFired); + } - [TestMethod] - public void Redo_ObjectReferences_UndoesChanges() + [TestMethod] + public void Redo_ObjectReferences_UndoesChanges() + { + // Arrange + var cuesheet = new Cuesheet() + { + Audiofiles = [ + new() { + Tracks = [new()] + } + ] + }; + var redoDoneEventFired = false; + _traceChangeManager.RedoDone += delegate { - // Arrange - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [new()] - } - ] - }; - var redoDoneEventFired = false; - _traceChangeManager.RedoDone += delegate - { - redoDoneEventFired = true; - }; - _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); - _traceChangeManager.Undo(); - // Act - _traceChangeManager.Redo(); - // Assert - Assert.HasCount(1, cuesheet.Audiofiles.First().Tracks); - Assert.IsTrue(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - Assert.IsTrue(redoDoneEventFired); - } + redoDoneEventFired = true; + }; + _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); + _traceChangeManager.Undo(); + // Act + _traceChangeManager.Redo(); + // Assert + Assert.HasCount(1, cuesheet.Audiofiles.First().Tracks); + Assert.IsTrue(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + Assert.IsTrue(redoDoneEventFired); + } - [TestMethod] - public void Reset_HasChanges_ResetsAllChanges() + [TestMethod] + public void Reset_HasChanges_ResetsAllChanges() + { + // Arrange + var track = new Track() + { + Artist = "Track 1 Artist", + Title = "Track 1 Title", + End = new TimeSpan(0, 2, 30) + }; + var cuesheet = new Cuesheet() { - // Arrange - var track = new Track() - { - Artist = "Track 1 Artist", - Title = "Track 1 Title", - End = new TimeSpan(0, 2, 30) - }; - var cuesheet = new Cuesheet() - { - Audiofiles = [ - new() { - Tracks = [track], - } - ] - }; - _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.End)))); - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Title)))); - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); - _traceChangeManager.Undo(); - // Act - _traceChangeManager.Reset(); - // Assert - Assert.IsFalse(_traceChangeManager.CanUndo); - Assert.IsFalse(_traceChangeManager.CanRedo); - } + Audiofiles = [ + new() { + Tracks = [track], + } + ] + }; + _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.End)))); + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Title)))); + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); + _traceChangeManager.Undo(); + // Act + _traceChangeManager.Reset(); + // Assert + Assert.IsFalse(_traceChangeManager.CanUndo); + Assert.IsFalse(_traceChangeManager.CanRedo); + } - [TestMethod()] - public void RemoveTracedChanges_RemovesChanges_WhenChangesAvailable() + [TestMethod()] + public void RemoveTracedChanges_RemovesChanges_WhenChangesAvailable() + { + // Arrange + var cuesheet1 = new Cuesheet() { - // Arrange - var cuesheet1 = new Cuesheet() - { - Artist = "Test Artist Cuesheet 1", - Title = "Test Title Cuesheet 1" - }; - var cuesheet2 = new Cuesheet() - { - CDTextfile = new("CD Testfile.cdt"), - Title = "Test Title Cuesheet 2" - }; - _traceChangeManager.AddChange(new(cuesheet1, new(null, nameof(Cuesheet.Artist)))); - _traceChangeManager.AddChange(new(cuesheet1, new(null, nameof(Cuesheet.Title)))); - _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.CDTextfile)))); - _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.Title)))); - var tracedObjectHistoryChangedFired = false; - _traceChangeManager.TracedObjectHistoryChanged += delegate - { - tracedObjectHistoryChangedFired = true; - }; - // Act - _traceChangeManager.RemoveTracedChanges([cuesheet1]); - // Assert - Assert.IsTrue(tracedObjectHistoryChangedFired); - Assert.IsTrue(_traceChangeManager.CanUndo); - _traceChangeManager.Undo(); - _traceChangeManager.Undo(); - Assert.IsFalse(_traceChangeManager.CanUndo); - Assert.IsNull(cuesheet2.CDTextfile); - Assert.IsNull(cuesheet2.Title); - } + Artist = "Test Artist Cuesheet 1", + Title = "Test Title Cuesheet 1" + }; + var cuesheet2 = new Cuesheet() + { + CDTextfile = new("CD Testfile.cdt"), + Title = "Test Title Cuesheet 2" + }; + _traceChangeManager.AddChange(new(cuesheet1, new(null, nameof(Cuesheet.Artist)))); + _traceChangeManager.AddChange(new(cuesheet1, new(null, nameof(Cuesheet.Title)))); + _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.CDTextfile)))); + _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.Title)))); + var tracedObjectHistoryChangedFired = false; + _traceChangeManager.TracedObjectHistoryChanged += delegate + { + tracedObjectHistoryChangedFired = true; + }; + // Act + _traceChangeManager.RemoveTracedChanges([cuesheet1]); + // Assert + Assert.IsTrue(tracedObjectHistoryChangedFired); + Assert.IsTrue(_traceChangeManager.CanUndo); + _traceChangeManager.Undo(); + _traceChangeManager.Undo(); + Assert.IsFalse(_traceChangeManager.CanUndo); + Assert.IsNull(cuesheet2.CDTextfile); + Assert.IsNull(cuesheet2.Title); + } - [TestMethod()] - public void RemoveTracedChanges_RemovesNoChanges_WhenNoChangesAvailable() + [TestMethod()] + public void RemoveTracedChanges_RemovesNoChanges_WhenNoChangesAvailable() + { + // Arrange + var cuesheet1 = new Cuesheet(); + var cuesheet2 = new Cuesheet() + { + CDTextfile = new("CD Testfile.cdt"), + Title = "Test Title Cuesheet 2" + }; + _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.CDTextfile)))); + _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.Title)))); + var tracedObjectHistoryChangedFired = false; + _traceChangeManager.TracedObjectHistoryChanged += delegate { - // Arrange - var cuesheet1 = new Cuesheet(); - var cuesheet2 = new Cuesheet() - { - CDTextfile = new("CD Testfile.cdt"), - Title = "Test Title Cuesheet 2" - }; - _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.CDTextfile)))); - _traceChangeManager.AddChange(new(cuesheet2, new(null, nameof(Cuesheet.Title)))); - var tracedObjectHistoryChangedFired = false; - _traceChangeManager.TracedObjectHistoryChanged += delegate - { - tracedObjectHistoryChangedFired = true; - }; - // Act - _traceChangeManager.RemoveTracedChanges([cuesheet1]); - // Assert - Assert.IsTrue(tracedObjectHistoryChangedFired); - Assert.IsTrue(_traceChangeManager.CanUndo); - _traceChangeManager.Undo(); - _traceChangeManager.Undo(); - Assert.IsFalse(_traceChangeManager.CanUndo); - Assert.IsNull(cuesheet2.CDTextfile); - Assert.IsNull(cuesheet2.Title); - } + tracedObjectHistoryChangedFired = true; + }; + // Act + _traceChangeManager.RemoveTracedChanges([cuesheet1]); + // Assert + Assert.IsTrue(tracedObjectHistoryChangedFired); + Assert.IsTrue(_traceChangeManager.CanUndo); + _traceChangeManager.Undo(); + _traceChangeManager.Undo(); + Assert.IsFalse(_traceChangeManager.CanUndo); + Assert.IsNull(cuesheet2.CDTextfile); + Assert.IsNull(cuesheet2.Title); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Utility/TestHelper.cs b/AudioCuesheetEditor.Tests/Utility/TestHelper.cs index b1900bb0..f4efd3f2 100644 --- a/AudioCuesheetEditor.Tests/Utility/TestHelper.cs +++ b/AudioCuesheetEditor.Tests/Utility/TestHelper.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,19 +18,18 @@ using Microsoft.Extensions.Logging; using System; -namespace AudioCuesheetEditor.Tests.Utility +namespace AudioCuesheetEditor.Tests.Utility; + +class TestHelper { - internal class TestHelper + public ApplicationOptions ApplicationOptions { get; private set; } = new(); + public static ILogger<T> CreateLogger<T>() { - public ApplicationOptions ApplicationOptions { get; private set; } = new(); - public static ILogger<T> CreateLogger<T>() - { - var serviceProvider = new ServiceCollection() - .AddLogging() - .BuildServiceProvider(); + var serviceProvider = new ServiceCollection() + .AddLogging() + .BuildServiceProvider(); - var factory = serviceProvider.GetService<ILoggerFactory>() ?? throw new NullReferenceException(); - return factory.CreateLogger<T>(); - } + var factory = serviceProvider.GetService<ILoggerFactory>() ?? throw new NullReferenceException(); + return factory.CreateLogger<T>(); } } diff --git a/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs b/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs index 941943fc..e71f74a3 100644 --- a/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs +++ b/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs @@ -17,29 +17,28 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Extensions +namespace AudioCuesheetEditor.Extensions; + +public class FlagJsonConverter : JsonConverter<Flag> { - public class FlagJsonConverter : JsonConverter<Flag> + public override Flag? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - public override Flag? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + var json = reader.GetString(); + if (string.IsNullOrEmpty(json) == false) + { + return Flag.AvailableFlags.Single(x => x.CuesheetLabel.Equals(json)); + } + else { - var json = reader.GetString(); - if (string.IsNullOrEmpty(json) == false) - { - return Flag.AvailableFlags.Single(x => x.CuesheetLabel.Equals(json)); - } - else - { - return null; - } + return null; } + } - public override void Write(Utf8JsonWriter writer, Flag value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, Flag value, JsonSerializerOptions options) + { + if ((value != null) && (String.IsNullOrEmpty(value.CuesheetLabel) == false)) { - if ((value != null) && (String.IsNullOrEmpty(value.CuesheetLabel) == false)) - { - writer.WriteStringValue(value.CuesheetLabel); - } + writer.WriteStringValue(value.CuesheetLabel); } } } diff --git a/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs b/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs index 6cc603bf..f6930603 100644 --- a/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs +++ b/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs @@ -16,20 +16,19 @@ using AudioCuesheetEditor.Services.UI; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -namespace AudioCuesheetEditor.Extensions +namespace AudioCuesheetEditor.Extensions; + +public static class WebAssemblyHostExtension { - public static class WebAssemblyHostExtension + public async static Task SetCultureFromConfigurationAsync(this WebAssemblyHost host) { - public async static Task SetCultureFromConfigurationAsync(this WebAssemblyHost host) - { - var localizationService = host.Services.GetRequiredService<LocalizationService>(); - await localizationService.SetCultureFromConfigurationAsync(); - } + var localizationService = host.Services.GetRequiredService<LocalizationService>(); + await localizationService.SetCultureFromConfigurationAsync(); + } - public async static Task InitializeSessionStateContainer(this WebAssemblyHost host) - { - var sessionStateContainer = host.Services.GetRequiredService<ISessionStateContainer>(); - await sessionStateContainer.InitializeAsync(); - } + public async static Task InitializeSessionStateContainer(this WebAssemblyHost host) + { + var sessionStateContainer = host.Services.GetRequiredService<ISessionStateContainer>(); + await sessionStateContainer.InitializeAsync(); } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs index 38994110..4091bf80 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs @@ -15,35 +15,34 @@ //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Model.IO; -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public class CDTextfile { - public class CDTextfile + string name; + public CDTextfile(String name) { - private string name; - public CDTextfile(String name) + if (String.IsNullOrEmpty(name)) { - if (String.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(nameof(name)); - } - this.name = name; + throw new ArgumentNullException(nameof(name)); } - public String Name + this.name = name; + } + public String Name + { + get => name; + set { - get => name; - set + if (String.IsNullOrEmpty(value)) + { + throw new ArgumentNullException(nameof(value)); + } + var extension = Path.GetExtension(value); + if (extension.Equals(FileExtensions.CDTextfile, StringComparison.CurrentCultureIgnoreCase) == false) { - if (String.IsNullOrEmpty(value)) - { - throw new ArgumentNullException(nameof(value)); - } - var extension = Path.GetExtension(value); - if (extension.Equals(FileExtensions.CDTextfile, StringComparison.CurrentCultureIgnoreCase) == false) - { - value = $"{value}{FileExtensions.CDTextfile}"; - } - name = value; + value = $"{value}{FileExtensions.CDTextfile}"; } + name = value; } } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs index ee8fc393..73f2c69e 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs @@ -17,74 +17,73 @@ using AudioCuesheetEditor.Model.IO.Audio; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public class Cuesheet() : Validateable, ICuesheet { - public class Cuesheet() : Validateable, ICuesheet - { - public String? Artist { get; set; } - - public String? Title { get; set; } + public String? Artist { get; set; } + + public String? Title { get; set; } - public IList<Audiofile> Audiofiles { get; set; } = []; + public IList<Audiofile> Audiofiles { get; set; } = []; - public CDTextfile? CDTextfile { get; set; } + public CDTextfile? CDTextfile { get; set; } - public String? Cataloguenumber { get; set; } + public String? Cataloguenumber { get; set; } - [JsonIgnore] - public bool IsRecording => RecordingStart.HasValue; - - [JsonIgnore] - public DateTime? RecordingStart { get; set; } + [JsonIgnore] + public bool IsRecording => RecordingStart.HasValue; + + [JsonIgnore] + public DateTime? RecordingStart { get; set; } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(Audiofiles): - validationStatus = ValidationStatus.Success; - if (Audiofiles.Count == 0) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Audiofiles), 0)); - } - break; - case nameof(Artist): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Artist)) + case nameof(Audiofiles): + validationStatus = ValidationStatus.Success; + if (Audiofiles.Count == 0) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Audiofiles), 0)); + } + break; + case nameof(Artist): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Artist)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Artist))); + } + break; + case nameof(Title): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Title)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Title))); + } + break; + case nameof(Cataloguenumber): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Cataloguenumber) == false) + { + if (Cataloguenumber.All(Char.IsDigit) == false) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Artist))); + validationMessages.Add(new ValidationMessage("{0} must only contain numbers!", nameof(Cataloguenumber))); } - break; - case nameof(Title): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Title)) + if (Cataloguenumber.Length != 13) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Title))); - } - break; - case nameof(Cataloguenumber): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Cataloguenumber) == false) - { - if (Cataloguenumber.All(Char.IsDigit) == false) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must only contain numbers!", nameof(Cataloguenumber))); - } - if (Cataloguenumber.Length != 13) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has an invalid length. Allowed length is {1}!", nameof(Cataloguenumber), 13)); - } + validationMessages.Add(new ValidationMessage("{0} has an invalid length. Allowed length is {1}!", nameof(Cataloguenumber), 13)); } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs index f0121747..f571a397 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs @@ -13,25 +13,24 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public class CuesheetConstants { - public class CuesheetConstants - { - public static readonly String CuesheetArtist = "PERFORMER"; - public static readonly String CuesheetTitle = "TITLE"; - public static readonly String CuesheetFileName = "FILE"; - public static readonly String CuesheetTrack = "TRACK"; - public static readonly String CuesheetTrackAudio = "AUDIO"; - public static readonly String TrackArtist = "PERFORMER"; - public static readonly String TrackTitle = "TITLE"; - public static readonly String TrackIndex01 = "INDEX 01"; - public static readonly String TrackFlags = "FLAGS"; - public static readonly String TrackPreGap = "PREGAP"; - public static readonly String TrackPostGap = "POSTGAP"; - public static readonly String Tab = "\t"; - public static readonly String CuesheetCDTextfile = "CDTEXTFILE"; - public static readonly String CuesheetCatalogueNumber = "CATALOG"; - public static readonly String MarkHTMLStart = "<Mark>"; - public static readonly String RecognizedMarkHTML = MarkHTMLStart + "{0}" + "</Mark>"; - } + public static readonly String CuesheetArtist = "PERFORMER"; + public static readonly String CuesheetTitle = "TITLE"; + public static readonly String CuesheetFileName = "FILE"; + public static readonly String CuesheetTrack = "TRACK"; + public static readonly String CuesheetTrackAudio = "AUDIO"; + public static readonly String TrackArtist = "PERFORMER"; + public static readonly String TrackTitle = "TITLE"; + public static readonly String TrackIndex01 = "INDEX 01"; + public static readonly String TrackFlags = "FLAGS"; + public static readonly String TrackPreGap = "PREGAP"; + public static readonly String TrackPostGap = "POSTGAP"; + public static readonly String Tab = "\t"; + public static readonly String CuesheetCDTextfile = "CDTEXTFILE"; + public static readonly String CuesheetCatalogueNumber = "CATALOG"; + public static readonly String MarkHTMLStart = "<Mark>"; + public static readonly String RecognizedMarkHTML = MarkHTMLStart + "{0}" + "</Mark>"; } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs index 5bb24da0..3e4db379 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs @@ -16,55 +16,54 @@ using AudioCuesheetEditor.Extensions; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +[JsonConverter(typeof(FlagJsonConverter))] +public class Flag { - [JsonConverter(typeof(FlagJsonConverter))] - public class Flag + /// <summary> + /// 4CH (Four channel audio) + /// </summary> + public static readonly Flag FourCH = new("4 channel audio (4CH)", "4CH"); + /// <summary> + /// DCP (Digital copy permitted) + /// </summary> + public static readonly Flag DCP = new("Digital copy permitted (DCP)", "DCP"); + /// <summary> + /// PRE (Pre-emphasis enabled) + /// </summary> + public static readonly Flag PRE = new("Pre-emphasis enabled (PRE)", "PRE"); + /// <summary> + /// SCMS (Serial copy management system) + /// </summary> + public static readonly Flag SCMS = new("Serial copy management system (SCMS)", "SCMS"); + + public static readonly IReadOnlyCollection<Flag> AvailableFlags; + static Flag() { - /// <summary> - /// 4CH (Four channel audio) - /// </summary> - public static readonly Flag FourCH = new("4 channel audio (4CH)", "4CH"); - /// <summary> - /// DCP (Digital copy permitted) - /// </summary> - public static readonly Flag DCP = new("Digital copy permitted (DCP)", "DCP"); - /// <summary> - /// PRE (Pre-emphasis enabled) - /// </summary> - public static readonly Flag PRE = new("Pre-emphasis enabled (PRE)", "PRE"); - /// <summary> - /// SCMS (Serial copy management system) - /// </summary> - public static readonly Flag SCMS = new("Serial copy management system (SCMS)", "SCMS"); + var list = new List<Flag> + { + FourCH, + DCP, + PRE, + SCMS + }; + AvailableFlags = list.AsReadOnly(); + } - public static readonly IReadOnlyCollection<Flag> AvailableFlags; - static Flag() + public String Name { get; private set; } + public String CuesheetLabel { get; private set; } + Flag(String name, String cuesheetLabel) + { + if (String.IsNullOrEmpty(name) == true) { - var list = new List<Flag> - { - FourCH, - DCP, - PRE, - SCMS - }; - AvailableFlags = list.AsReadOnly(); + throw new ArgumentNullException(nameof(name)); } - - public String Name { get; private set; } - public String CuesheetLabel { get; private set; } - private Flag(String name, String cuesheetLabel) + if (String.IsNullOrEmpty(cuesheetLabel) == true) { - if (String.IsNullOrEmpty(name) == true) - { - throw new ArgumentNullException(nameof(name)); - } - if (String.IsNullOrEmpty(cuesheetLabel) == true) - { - throw new ArgumentNullException(nameof(cuesheetLabel)); - } - Name = name; - CuesheetLabel = cuesheetLabel; + throw new ArgumentNullException(nameof(cuesheetLabel)); } + Name = name; + CuesheetLabel = cuesheetLabel; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs index 0efa34b0..e9e736be 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs @@ -13,10 +13,9 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public interface IAudiofile { - public interface IAudiofile - { - String? Name { get; set; } - } + String? Name { get; set; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/ICuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/ICuesheet.cs index 8cdc8c4d..c43e1412 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/ICuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/ICuesheet.cs @@ -14,12 +14,11 @@ //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public interface ICuesheet { - public interface ICuesheet - { - string? Artist { get; set; } - string? Title { get; set; } - string? Cataloguenumber { get; set; } - } + string? Artist { get; set; } + string? Title { get; set; } + string? Cataloguenumber { get; set; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs b/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs index 36c36a28..30f4e3d6 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs @@ -13,19 +13,18 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public interface ITrack { - public interface ITrack - { - string? Artist { get; set; } - string? Title { get; set; } - ushort? Position { get; set; } - TimeSpan? Begin { get; set; } - TimeSpan? End { get; set; } - TimeSpan? Length { get; set; } - IEnumerable<Flag> Flags { get; set; } - TimeSpan? PreGap { get; set; } - TimeSpan? PostGap { get; set; } - bool IsLinkedToPreviousTrack { get; set; } - } + string? Artist { get; set; } + string? Title { get; set; } + ushort? Position { get; set; } + TimeSpan? Begin { get; set; } + TimeSpan? End { get; set; } + TimeSpan? Length { get; set; } + IEnumerable<Flag> Flags { get; set; } + TimeSpan? PreGap { get; set; } + TimeSpan? PostGap { get; set; } + bool IsLinkedToPreviousTrack { get; set; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs index c158067d..e46775ca 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs @@ -1,8 +1,7 @@ -namespace AudioCuesheetEditor.Model.AudioCuesheet.Import +namespace AudioCuesheetEditor.Model.AudioCuesheet.Import; + +public class ImportAudiofile : IAudiofile { - public class ImportAudiofile : IAudiofile - { - public String? Name { get; set; } - public IList<ImportTrack> Tracks { get; } = []; - } + public String? Name { get; set; } + public IList<ImportTrack> Tracks { get; } = []; } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportCuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportCuesheet.cs index 47f401e0..553f9f9c 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportCuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportCuesheet.cs @@ -15,15 +15,14 @@ //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.AudioCuesheet.Import +namespace AudioCuesheetEditor.Model.AudioCuesheet.Import; + +public class ImportCuesheet : ICuesheet { - public class ImportCuesheet : ICuesheet - { - public string? Artist { get; set; } - public string? Title { get; set; } - public IList<ImportAudiofile> Audiofiles { get; set; } = []; - /// <inheritdoc/> - public string? CDTextfile { get; set; } - public string? Cataloguenumber { get; set; } - } + public string? Artist { get; set; } + public string? Title { get; set; } + public IList<ImportAudiofile> Audiofiles { get; set; } = []; + /// <inheritdoc/> + public string? CDTextfile { get; set; } + public string? Cataloguenumber { get; set; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs index 213453d0..e0a6fb08 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs @@ -14,20 +14,19 @@ //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.AudioCuesheet.Import +namespace AudioCuesheetEditor.Model.AudioCuesheet.Import; + +public class ImportTrack : ITrack { - public class ImportTrack : ITrack - { - public string? Artist { get; set; } - public string? Title { get; set; } - public ushort? Position { get; set; } - public TimeSpan? Begin { get; set; } - public TimeSpan? End { get; set; } - public TimeSpan? Length { get; set; } - public IEnumerable<Flag> Flags { get; set; } = []; - public TimeSpan? PreGap { get; set; } - public TimeSpan? PostGap { get; set; } - public DateTime? StartDateTime { get; set; } - public bool IsLinkedToPreviousTrack { get; set; } - } + public string? Artist { get; set; } + public string? Title { get; set; } + public ushort? Position { get; set; } + public TimeSpan? Begin { get; set; } + public TimeSpan? End { get; set; } + public TimeSpan? Length { get; set; } + public IEnumerable<Flag> Flags { get; set; } = []; + public TimeSpan? PreGap { get; set; } + public TimeSpan? PostGap { get; set; } + public DateTime? StartDateTime { get; set; } + public bool IsLinkedToPreviousTrack { get; set; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs index bd86d17c..495aa21c 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs @@ -17,157 +17,156 @@ using AudioCuesheetEditor.Model.IO.Audio; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.AudioCuesheet +namespace AudioCuesheetEditor.Model.AudioCuesheet; + +public class Track : Validateable, ITrack { - public class Track : Validateable, ITrack + public ushort? Position { get; set; } + public String? Artist { get; set; } + public String? Title { get; set; } + public TimeSpan? Begin { get; set; } + public TimeSpan? End { get; set; } + [JsonIgnore] + public TimeSpan? Length { - public ushort? Position { get; set; } - public String? Artist { get; set; } - public String? Title { get; set; } - public TimeSpan? Begin { get; set; } - public TimeSpan? End { get; set; } - [JsonIgnore] - public TimeSpan? Length + get { - get + if ((Begin.HasValue == true) && (End.HasValue == true) && (Begin.Value <= End.Value)) { - if ((Begin.HasValue == true) && (End.HasValue == true) && (Begin.Value <= End.Value)) - { - return End - Begin; - } - else - { - return null; - } + return End - Begin; + } + else + { + return null; } - set + } + set + { + if ((Begin.HasValue == false) && (End.HasValue == false)) { - if ((Begin.HasValue == false) && (End.HasValue == false)) + End = value; + } + else + { + if ((Begin.HasValue == true) && (End.HasValue == true)) { - End = value; + End = Begin.Value + value; } else { - if ((Begin.HasValue == true) && (End.HasValue == true)) + if ((End.HasValue == false) && (Begin.HasValue)) { End = Begin.Value + value; } - else + if ((Begin.HasValue == false) && (End.HasValue)) { - if ((End.HasValue == false) && (Begin.HasValue)) - { - End = Begin.Value + value; - } - if ((Begin.HasValue == false) && (End.HasValue)) - { - Begin = End.Value - value; - } + Begin = End.Value - value; } } } } - [JsonIgnore] - public Cuesheet? Cuesheet { get; set; } - [JsonInclude] - public IEnumerable<Flag> Flags { get; set; } = []; - /// <inheritdoc/> - public TimeSpan? PreGap { get; set; } - /// <inheritdoc/> - public TimeSpan? PostGap { get; set; } - /// <summary> - /// Set that this track is linked to the previous track in cuesheet - /// </summary> - public Boolean IsLinkedToPreviousTrack { get; set; } - [JsonIgnore] - public Audiofile? Audiofile { get; set; } + } + [JsonIgnore] + public Cuesheet? Cuesheet { get; set; } + [JsonInclude] + public IEnumerable<Flag> Flags { get; set; } = []; + /// <inheritdoc/> + public TimeSpan? PreGap { get; set; } + /// <inheritdoc/> + public TimeSpan? PostGap { get; set; } + /// <summary> + /// Set that this track is linked to the previous track in cuesheet + /// </summary> + public Boolean IsLinkedToPreviousTrack { get; set; } + [JsonIgnore] + public Audiofile? Audiofile { get; set; } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(Position): - validationStatus = ValidationStatus.Success; - if (Position == null) + case nameof(Position): + validationStatus = ValidationStatus.Success; + if (Position == null) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Position))); + } + else + { + if (Position == 0) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Position))); + validationMessages.Add(new ValidationMessage("{0} may not be 0!", nameof(Position))); } else { - if (Position == 0) + // Check correct track position + if (Cuesheet != null) { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} may not be 0!", nameof(Position))); - } - else - { - // Check correct track position - if (Cuesheet != null) + var positionTrackShouldHave = Cuesheet.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin ?? TimeSpan.MaxValue).ThenBy(x => x.Position).ToList().IndexOf(this) + 1; + if (positionTrackShouldHave != Position) { - var positionTrackShouldHave = Cuesheet.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin ?? TimeSpan.MaxValue).ThenBy(x => x.Position).ToList().IndexOf(this) + 1; - if (positionTrackShouldHave != Position) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? String.Empty, Title ?? String.Empty, Begin != null ? Begin : String.Empty, End != null ? End : String.Empty, positionTrackShouldHave)); - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? String.Empty, Title ?? String.Empty, Begin != null ? Begin : String.Empty, End != null ? End : String.Empty, positionTrackShouldHave)); } } } - break; - case nameof(Begin): - validationStatus = ValidationStatus.Success; - if (Begin == null) + } + break; + case nameof(Begin): + validationStatus = ValidationStatus.Success; + if (Begin == null) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Begin))); + } + else + { + if (Begin < TimeSpan.Zero) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Begin))); + validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(Begin))); } - else - { - if (Begin < TimeSpan.Zero) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(Begin))); - } - if (Begin > End) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} should be less than or equal '{1}'!", nameof(Begin), nameof(End))); - } - } - break; - case nameof(End): - validationStatus = ValidationStatus.Success; - if (End == null) + if (Begin > End) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(End))); + validationMessages.Add(new ValidationMessage("{0} should be less than or equal '{1}'!", nameof(Begin), nameof(End))); } - else + } + break; + case nameof(End): + validationStatus = ValidationStatus.Success; + if (End == null) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(End))); + } + else + { + if (End < TimeSpan.Zero) { - if (End < TimeSpan.Zero) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(End))); - } - if (End < Begin) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} should be greater than or equal '{1}'!", nameof(End), nameof(Begin))); - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(End))); } - break; - case nameof(Length): - validationStatus = ValidationStatus.Success; - if (Length == null) + if (End < Begin) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Length))); + validationMessages.Add(new ValidationMessage("{0} should be greater than or equal '{1}'!", nameof(End), nameof(Begin))); } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + } + break; + case nameof(Length): + validationStatus = ValidationStatus.Success; + if (Length == null) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Length))); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); } } diff --git a/AudioCuesheetEditor/Model/Entity/IValidateable.cs b/AudioCuesheetEditor/Model/Entity/IValidateable.cs index 8a848945..e030b442 100644 --- a/AudioCuesheetEditor/Model/Entity/IValidateable.cs +++ b/AudioCuesheetEditor/Model/Entity/IValidateable.cs @@ -13,53 +13,52 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.Entity +namespace AudioCuesheetEditor.Model.Entity; + +public interface IValidateable { - public interface IValidateable - { - /// <summary> - /// Validate all properties and return the result of validation. - /// </summary> - /// <returns>Validation result.</returns> - ValidationResult Validate(); - /// <summary> - /// Validates the property and return the result of validation. - /// </summary> - /// <param name="property"></param> - /// <returns></returns> - ValidationResult Validate(String property); - } - public enum ValidationStatus - { - NoValidation, - Success, - Error - } - public class ValidationResult - { - private List<ValidationMessage> validationMessages = []; + /// <summary> + /// Validate all properties and return the result of validation. + /// </summary> + /// <returns>Validation result.</returns> + ValidationResult Validate(); + /// <summary> + /// Validates the property and return the result of validation. + /// </summary> + /// <param name="property"></param> + /// <returns></returns> + ValidationResult Validate(String property); +} +public enum ValidationStatus +{ + NoValidation, + Success, + Error +} +public class ValidationResult +{ + List<ValidationMessage> validationMessages = []; - public static ValidationResult Create(ValidationStatus validationStatus, IEnumerable<ValidationMessage>? validationMessages = null) + public static ValidationResult Create(ValidationStatus validationStatus, IEnumerable<ValidationMessage>? validationMessages = null) + { + var result = new ValidationResult() { Status = validationStatus }; + if (validationMessages != null) { - var result = new ValidationResult() { Status = validationStatus }; - if (validationMessages != null) - { - result.ValidationMessages = [.. validationMessages]; - } - return result; + result.ValidationMessages = [.. validationMessages]; } + return result; + } - public ValidationStatus Status { get; set; } - public ICollection<ValidationMessage> ValidationMessages + public ValidationStatus Status { get; set; } + public ICollection<ValidationMessage> ValidationMessages + { + get => validationMessages; + set { - get => validationMessages; - set + validationMessages = [.. value]; + if (validationMessages.Count > 0) { - validationMessages = [.. value]; - if (validationMessages.Count > 0) - { - Status = ValidationStatus.Error; - } + Status = ValidationStatus.Error; } } } diff --git a/AudioCuesheetEditor/Model/Entity/Validateable.cs b/AudioCuesheetEditor/Model/Entity/Validateable.cs index 5d48e438..69d46d28 100644 --- a/AudioCuesheetEditor/Model/Entity/Validateable.cs +++ b/AudioCuesheetEditor/Model/Entity/Validateable.cs @@ -15,46 +15,45 @@ //<http: //www.gnu.org/licenses />. using System.Reflection; -namespace AudioCuesheetEditor.Model.Entity +namespace AudioCuesheetEditor.Model.Entity; + +public abstract class Validateable : IValidateable { - public abstract class Validateable : IValidateable - { - public event EventHandler<String>? ValidateablePropertyChanged; + public event EventHandler<String>? ValidateablePropertyChanged; - public ValidationResult Validate() + public ValidationResult Validate() + { + ValidationResult validationResult = new() { Status = ValidationStatus.NoValidation }; + List<ValidationMessage> validationMessages = []; + foreach (var property in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { - ValidationResult validationResult = new() { Status = ValidationStatus.NoValidation }; - List<ValidationMessage> validationMessages = []; - foreach (var property in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + var result = Validate(property.Name); + validationMessages.AddRange(result.ValidationMessages); + switch (validationResult.Status) { - var result = Validate(property.Name); - validationMessages.AddRange(result.ValidationMessages); - switch (validationResult.Status) - { - case ValidationStatus.NoValidation: - case ValidationStatus.Success: - switch (result.Status) - { - case ValidationStatus.Success: - case ValidationStatus.Error: - validationResult.Status = result.Status; - break; - } - break; - case ValidationStatus.Error: - //If there was an error, we don't delete it! - break; - } + case ValidationStatus.NoValidation: + case ValidationStatus.Success: + switch (result.Status) + { + case ValidationStatus.Success: + case ValidationStatus.Error: + validationResult.Status = result.Status; + break; + } + break; + case ValidationStatus.Error: + //If there was an error, we don't delete it! + break; } - validationResult.ValidationMessages = validationMessages; - return validationResult; } + validationResult.ValidationMessages = validationMessages; + return validationResult; + } - public abstract ValidationResult Validate(String property); + public abstract ValidationResult Validate(String property); - protected void OnValidateablePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") - { - ValidateablePropertyChanged?.Invoke(this, propertyName); - } + protected void OnValidateablePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") + { + ValidateablePropertyChanged?.Invoke(this, propertyName); } } diff --git a/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs b/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs index 06694604..7ecc9937 100644 --- a/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs +++ b/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs @@ -15,42 +15,41 @@ //<http: //www.gnu.org/licenses />. using Microsoft.Extensions.Localization; -namespace AudioCuesheetEditor.Model.Entity +namespace AudioCuesheetEditor.Model.Entity; + +public class ValidationMessage { - public class ValidationMessage + public ValidationMessage(String message, params object[]? args) { - public ValidationMessage(String message, params object[]? args) + if (String.IsNullOrEmpty(message) == true) { - if (String.IsNullOrEmpty(message) == true) - { - throw new ArgumentNullException(nameof(message)); - } - Message = message; - Parameter = args; + throw new ArgumentNullException(nameof(message)); } - public String Message { get; private set; } - public object[]? Parameter { get; private set; } + Message = message; + Parameter = args; + } + public String Message { get; private set; } + public object[]? Parameter { get; private set; } - public String GetMessageLocalized(IStringLocalizer<ValidationMessage> localizer) + public String GetMessageLocalized(IStringLocalizer<ValidationMessage> localizer) + { + object[]? arguments = null; + if (Parameter != null) { - object[]? arguments = null; - if (Parameter != null) - { - arguments = new object[Parameter.Length]; - Parameter.CopyTo(arguments, 0); - } - if (arguments != null) + arguments = new object[Parameter.Length]; + Parameter.CopyTo(arguments, 0); + } + if (arguments != null) + { + for (int i = 0; i < arguments.Length; i++) { - for (int i = 0; i < arguments.Length; i++) + if ((arguments[i] != null) && (arguments[i].GetType() == typeof(String))) { - if ((arguments[i] != null) && (arguments[i].GetType() == typeof(String))) - { - arguments[i] = localizer[(String)arguments[i]]; - } + arguments[i] = localizer[(String)arguments[i]]; } - return localizer[Message, arguments]; } - return localizer[Message]; + return localizer[Message, arguments]; } + return localizer[Message]; } } diff --git a/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs b/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs index 00785d02..4440f5a9 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs @@ -14,31 +14,30 @@ //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.IO.Audio +namespace AudioCuesheetEditor.Model.IO.Audio; + +public class AudioCodec { - public class AudioCodec + public String MimeType { get; private set; } + public String FileExtension { get; private set; } + public String Name { get; private set; } + + public AudioCodec(String mimeType, String fileExtension, String name) { - public String MimeType { get; private set; } - public String FileExtension { get; private set; } - public String Name { get; private set; } - - public AudioCodec(String mimeType, String fileExtension, String name) + if (String.IsNullOrEmpty(mimeType)) + { + throw new ArgumentNullException(nameof(mimeType)); + } + if (String.IsNullOrEmpty(fileExtension)) + { + throw new ArgumentNullException(nameof(fileExtension)); + } + if (String.IsNullOrEmpty(name)) { - if (String.IsNullOrEmpty(mimeType)) - { - throw new ArgumentNullException(nameof(mimeType)); - } - if (String.IsNullOrEmpty(fileExtension)) - { - throw new ArgumentNullException(nameof(fileExtension)); - } - if (String.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(nameof(name)); - } - MimeType = mimeType; - FileExtension = fileExtension; - Name = name; + throw new ArgumentNullException(nameof(name)); } + MimeType = mimeType; + FileExtension = fileExtension; + Name = name; } } diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index c8330b68..a0b55130 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -17,137 +17,136 @@ using AudioCuesheetEditor.Model.Entity; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.IO.Audio +namespace AudioCuesheetEditor.Model.IO.Audio; + +public class Audiofile() : Validateable, IAudiofile { - public class Audiofile() : Validateable, IAudiofile - { - public static readonly AudioCodec AudioCodecWEBM = new("audio/webm", ".webm", "AudioCodec WEBM"); + public static readonly AudioCodec AudioCodecWEBM = new("audio/webm", ".webm", "AudioCodec WEBM"); - public static readonly List<AudioCodec> AudioCodecs = - [ - AudioCodecWEBM, - new AudioCodec("audio/mpeg", ".mp3", "AudioCodec MP3"), - new AudioCodec("audio/ogg", ".oga", "AudioCodec OGA"), - new AudioCodec("audio/ogg", ".ogg", "AudioCodec OGG"), - new AudioCodec("audio/ogg; codecs=opus", ".opus", "AudioCodec OPUS"), - new AudioCodec("audio/wav", ".wav", "AudioCodec WAV"), - new AudioCodec("audio/wav", ".wave", "AudioCodec WAVE"), - new AudioCodec("audio/flac", ".flac", "AudioCodec FLAC") - ]; + public static readonly List<AudioCodec> AudioCodecs = + [ + AudioCodecWEBM, + new AudioCodec("audio/mpeg", ".mp3", "AudioCodec MP3"), + new AudioCodec("audio/ogg", ".oga", "AudioCodec OGA"), + new AudioCodec("audio/ogg", ".ogg", "AudioCodec OGG"), + new AudioCodec("audio/ogg; codecs=opus", ".opus", "AudioCodec OPUS"), + new AudioCodec("audio/wav", ".wav", "AudioCodec WAV"), + new AudioCodec("audio/wav", ".wave", "AudioCodec WAVE"), + new AudioCodec("audio/flac", ".flac", "AudioCodec FLAC") + ]; - private AudioCodec? _audioCodec; - private String? _name; - - public Audiofile(String? name, String? objectURL, AudioCodec? audioCodec, TimeSpan? duration = null) : this() - { - Name = name; - ObjectURL = objectURL; - AudioCodec = audioCodec; - Duration = duration; - } + AudioCodec? _audioCodec; + String? _name; + + public Audiofile(String? name, String? objectURL, AudioCodec? audioCodec, TimeSpan? duration = null) : this() + { + Name = name; + ObjectURL = objectURL; + AudioCodec = audioCodec; + Duration = duration; + } - public String? Name + public String? Name + { + get => _name; + set { - get => _name; - set + var extension = Path.GetExtension(value); + if (extension?.Equals(_audioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) { - var extension = Path.GetExtension(value); - if (extension?.Equals(_audioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) - { - value = $"{value}{_audioCodec?.FileExtension}"; - } - _name = value; + value = $"{value}{_audioCodec?.FileExtension}"; } + _name = value; } + } - [JsonIgnore] - public String? ObjectURL { get; set; } + [JsonIgnore] + public String? ObjectURL { get; set; } - /// <summary> - /// Duration of the audio file - /// </summary> - public TimeSpan? Duration { get; set; } + /// <summary> + /// Duration of the audio file + /// </summary> + public TimeSpan? Duration { get; set; } - public AudioCodec? AudioCodec + public AudioCodec? AudioCodec + { + get { return _audioCodec; } + set { - get { return _audioCodec; } - set + _audioCodec = value; + if ((_audioCodec != null) && (Name?.EndsWith(_audioCodec.FileExtension) == false)) { - _audioCodec = value; - if ((_audioCodec != null) && (Name?.EndsWith(_audioCodec.FileExtension) == false)) - { - //Replace file ending - Name = String.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), _audioCodec.FileExtension); - } + //Replace file ending + Name = String.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), _audioCodec.FileExtension); } } + } - public ICollection<Track> Tracks { get; set; } = []; + public ICollection<Track> Tracks { get; set; } = []; - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(Tracks): - validationStatus = ValidationStatus.Success; - if (Tracks.Count == 0) + case nameof(Tracks): + validationStatus = ValidationStatus.Success; + if (Tracks.Count == 0) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Tracks), 0)); + } + else + { + //Check track overlapping + var tracksWithSamePosition = Tracks + .GroupBy(x => x.Position) + .Where(grp => grp.Count() > 1); + if (tracksWithSamePosition.Any()) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has invalid count ({1})!", nameof(Tracks), 0)); - } - else - { - //Check track overlapping - var tracksWithSamePosition = Tracks - .GroupBy(x => x.Position) - .Where(grp => grp.Count() > 1); - if (tracksWithSamePosition.Any()) + foreach (var track in tracksWithSamePosition) { - validationMessages ??= []; - foreach (var track in tracksWithSamePosition) + foreach (var trackWithSamePosition in track) { - foreach (var trackWithSamePosition in track) - { - validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : String.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : String.Empty, trackWithSamePosition.Artist ?? String.Empty, trackWithSamePosition.Title ?? String.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : String.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : String.Empty)); - } + validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : String.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : String.Empty, trackWithSamePosition.Artist ?? String.Empty, trackWithSamePosition.Title ?? String.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : String.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : String.Empty)); } } - foreach (var track in Tracks.OrderBy(x => x.Position)) + } + foreach (var track in Tracks.OrderBy(x => x.Position)) + { + var tracksBetween = Tracks.Where(x => ((track.Begin >= x.Begin && track.Begin < x.End) + || (x.Begin < track.End && track.End <= x.End)) + && (x.Equals(track) == false)); + if (tracksBetween.Any()) { - var tracksBetween = Tracks.Where(x => ((track.Begin >= x.Begin && track.Begin < x.End) - || (x.Begin < track.End && track.End <= x.End)) - && (x.Equals(track) == false)); - if (tracksBetween.Any()) + validationMessages ??= []; + foreach (var trackBetween in tracksBetween) { - validationMessages ??= []; - foreach (var trackBetween in tracksBetween) - { - validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : String.Empty, track.Artist ?? String.Empty, track.Title ?? String.Empty, track.Begin != null ? track.Begin : String.Empty, track.End != null ? track.End : String.Empty, trackBetween.Position != null ? trackBetween.Position : String.Empty, trackBetween.Artist ?? String.Empty, trackBetween.Title ?? String.Empty, trackBetween.Begin != null ? trackBetween.Begin : String.Empty, trackBetween.End != null ? trackBetween.End : String.Empty)); - } + validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : String.Empty, track.Artist ?? String.Empty, track.Title ?? String.Empty, track.Begin != null ? track.Begin : String.Empty, track.End != null ? track.End : String.Empty, trackBetween.Position != null ? trackBetween.Position : String.Empty, trackBetween.Artist ?? String.Empty, trackBetween.Title ?? String.Empty, trackBetween.Begin != null ? trackBetween.Begin : String.Empty, trackBetween.End != null ? trackBetween.End : String.Empty)); } } } - break; - case nameof(Name): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Name)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Name))); - } - break; - case nameof(AudioCodec): - validationStatus = ValidationStatus.Success; - if (AudioCodec == null) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(AudioCodec))); - } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + } + break; + case nameof(Name): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Name)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Name))); + } + break; + case nameof(AudioCodec): + validationStatus = ValidationStatus.Success; + if (AudioCodec == null) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(AudioCodec))); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); } } diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs index c056e572..42cb6370 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs @@ -14,12 +14,11 @@ //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.IO.Export +namespace AudioCuesheetEditor.Model.IO.Export; + +public class Exportfile { - public class Exportfile - { - public static readonly string DefaultCuesheetFilename = "Cuesheet.cue"; - public string Name { get; set; } = String.Empty; - public string? Content { get; set; } - } + public static readonly string DefaultCuesheetFilename = "Cuesheet.cue"; + public string Name { get; set; } = String.Empty; + public string? Content { get; set; } } diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs index 7fc829da..f7eb9ee3 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs @@ -17,167 +17,166 @@ using AudioCuesheetEditor.Model.Entity; using AudioCuesheetEditor.Model.IO.Audio; -namespace AudioCuesheetEditor.Model.IO.Export +namespace AudioCuesheetEditor.Model.IO.Export; + +public class Exportprofile : Validateable { - public class Exportprofile : Validateable - { - public static readonly String DefaultFileName = "Export.txt"; + public static readonly String DefaultFileName = "Export.txt"; - public static readonly String SchemeCuesheetArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Artist), SchemeCharacter); - public static readonly String SchemeCuesheetTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Title), SchemeCharacter); - public static readonly String SchemeAudiofileName = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Audiofile), nameof(Audiofile.Name), SchemeCharacter); - public static readonly String SchemeCuesheetCDTextfile = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.CDTextfile), SchemeCharacter); - public static readonly String SchemeCuesheetCatalogueNumber = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Cataloguenumber), SchemeCharacter); - public static readonly String SchemeTrackArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Artist), SchemeCharacter); - public static readonly String SchemeTrackTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Title), SchemeCharacter); - public static readonly String SchemeTrackBegin = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Begin), SchemeCharacter); - public static readonly String SchemeTrackEnd = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.End), SchemeCharacter); - public static readonly String SchemeTrackLength = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Length), SchemeCharacter); - public static readonly String SchemeTrackPosition = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Position), SchemeCharacter); - public static readonly String SchemeTrackFlags = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Flags), SchemeCharacter); - public static readonly String SchemeTrackPreGap = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PreGap), SchemeCharacter); - public static readonly String SchemeTrackPostGap = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PostGap), SchemeCharacter); - public static readonly String SchemeDate = String.Format("{0}Date{1}", SchemeCharacter, SchemeCharacter); - public static readonly String SchemeDateTime = String.Format("{0}DateTime{1}", SchemeCharacter, SchemeCharacter); - public static readonly String SchemeTime = String.Format("{0}Time{1}", SchemeCharacter, SchemeCharacter); + public static readonly String SchemeCuesheetArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Artist), SchemeCharacter); + public static readonly String SchemeCuesheetTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Title), SchemeCharacter); + public static readonly String SchemeAudiofileName = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Audiofile), nameof(Audiofile.Name), SchemeCharacter); + public static readonly String SchemeCuesheetCDTextfile = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.CDTextfile), SchemeCharacter); + public static readonly String SchemeCuesheetCatalogueNumber = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Cataloguenumber), SchemeCharacter); + public static readonly String SchemeTrackArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Artist), SchemeCharacter); + public static readonly String SchemeTrackTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Title), SchemeCharacter); + public static readonly String SchemeTrackBegin = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Begin), SchemeCharacter); + public static readonly String SchemeTrackEnd = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.End), SchemeCharacter); + public static readonly String SchemeTrackLength = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Length), SchemeCharacter); + public static readonly String SchemeTrackPosition = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Position), SchemeCharacter); + public static readonly String SchemeTrackFlags = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Flags), SchemeCharacter); + public static readonly String SchemeTrackPreGap = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PreGap), SchemeCharacter); + public static readonly String SchemeTrackPostGap = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PostGap), SchemeCharacter); + public static readonly String SchemeDate = String.Format("{0}Date{1}", SchemeCharacter, SchemeCharacter); + public static readonly String SchemeDateTime = String.Format("{0}DateTime{1}", SchemeCharacter, SchemeCharacter); + public static readonly String SchemeTime = String.Format("{0}Time{1}", SchemeCharacter, SchemeCharacter); - public static readonly Dictionary<String, String> AvailableCuesheetSchemes = new() - { - { nameof(Cuesheet.Artist), SchemeCuesheetArtist }, - { nameof(Cuesheet.Title), SchemeCuesheetTitle }, - { nameof(Cuesheet.CDTextfile), SchemeCuesheetCDTextfile }, - { nameof(Cuesheet.Cataloguenumber), SchemeCuesheetCatalogueNumber }, - { "Date", SchemeDate }, - { "DateTime", SchemeDateTime }, - { "Time", SchemeTime } - }; - public static readonly Dictionary<String, String> AvailableAudiofileSchemes = new() - { - { nameof(Audiofile.Name), SchemeAudiofileName } - }; - public static readonly Dictionary<String, String> AvailableTrackSchemes = new() - { - { nameof(Track.Position), SchemeTrackPosition }, - { nameof(Track.Artist), SchemeTrackArtist }, - { nameof(Track.Title), SchemeTrackTitle }, - { nameof(Track.Begin), SchemeTrackBegin }, - { nameof(Track.End), SchemeTrackEnd }, - { nameof(Track.Length), SchemeTrackLength }, - { nameof(Track.Flags), SchemeTrackFlags }, - { nameof(Track.PreGap), SchemeTrackPreGap }, - { nameof(Track.PostGap), SchemeTrackPostGap } - }; + public static readonly Dictionary<String, String> AvailableCuesheetSchemes = new() + { + { nameof(Cuesheet.Artist), SchemeCuesheetArtist }, + { nameof(Cuesheet.Title), SchemeCuesheetTitle }, + { nameof(Cuesheet.CDTextfile), SchemeCuesheetCDTextfile }, + { nameof(Cuesheet.Cataloguenumber), SchemeCuesheetCatalogueNumber }, + { "Date", SchemeDate }, + { "DateTime", SchemeDateTime }, + { "Time", SchemeTime } + }; + public static readonly Dictionary<String, String> AvailableAudiofileSchemes = new() + { + { nameof(Audiofile.Name), SchemeAudiofileName } + }; + public static readonly Dictionary<String, String> AvailableTrackSchemes = new() + { + { nameof(Track.Position), SchemeTrackPosition }, + { nameof(Track.Artist), SchemeTrackArtist }, + { nameof(Track.Title), SchemeTrackTitle }, + { nameof(Track.Begin), SchemeTrackBegin }, + { nameof(Track.End), SchemeTrackEnd }, + { nameof(Track.Length), SchemeTrackLength }, + { nameof(Track.Flags), SchemeTrackFlags }, + { nameof(Track.PreGap), SchemeTrackPreGap }, + { nameof(Track.PostGap), SchemeTrackPostGap } + }; - public const String SchemeCharacter = "%"; + public const String SchemeCharacter = "%"; - private String _schemeHead; - private String _schemeAudiofiles; - private String _schemeTracks; - private String _schemeFooter; - private String _filename; - private String _name; + String _schemeHead; + String _schemeAudiofiles; + String _schemeTracks; + String _schemeFooter; + String _filename; + String _name; - public Exportprofile() - { - Id = Guid.NewGuid(); - _schemeHead = String.Empty; - _schemeTracks = String.Empty; - _schemeAudiofiles = String.Empty; - _schemeFooter = String.Empty; - _filename = DefaultFileName; - var random = new Random(); - _name = String.Format("{0}_{1}", nameof(Exportprofile), random.Next(1, 100)); - } - public Guid Id { get; init; } - public String Name - { - get => _name; - set { _name = value; OnValidateablePropertyChanged(); } - } - public String SchemeHead - { - get => _schemeHead; - set { _schemeHead = value; OnValidateablePropertyChanged(); } - } - public String SchemeTracks - { - get => _schemeTracks; - set { _schemeTracks = value; OnValidateablePropertyChanged(); } - } - public String SchemeAudiofiles - { - get => _schemeAudiofiles; - set { _schemeAudiofiles = value; OnValidateablePropertyChanged(); } - } - public String SchemeFooter - { - get => _schemeFooter; - set { _schemeFooter = value; OnValidateablePropertyChanged(); } - } - public String Filename - { - get => _filename; - set { _filename = value; OnValidateablePropertyChanged(); } - } + public Exportprofile() + { + Id = Guid.NewGuid(); + _schemeHead = String.Empty; + _schemeTracks = String.Empty; + _schemeAudiofiles = String.Empty; + _schemeFooter = String.Empty; + _filename = DefaultFileName; + var random = new Random(); + _name = String.Format("{0}_{1}", nameof(Exportprofile), random.Next(1, 100)); + } + public Guid Id { get; init; } + public String Name + { + get => _name; + set { _name = value; OnValidateablePropertyChanged(); } + } + public String SchemeHead + { + get => _schemeHead; + set { _schemeHead = value; OnValidateablePropertyChanged(); } + } + public String SchemeTracks + { + get => _schemeTracks; + set { _schemeTracks = value; OnValidateablePropertyChanged(); } + } + public String SchemeAudiofiles + { + get => _schemeAudiofiles; + set { _schemeAudiofiles = value; OnValidateablePropertyChanged(); } + } + public String SchemeFooter + { + get => _schemeFooter; + set { _schemeFooter = value; OnValidateablePropertyChanged(); } + } + public String Filename + { + get => _filename; + set { _filename = value; OnValidateablePropertyChanged(); } + } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(SchemeHead): - validationStatus = ValidationStatus.Success; - validationMessages = CheckForUnresolvablePlaceholders(SchemeHead, nameof(SchemeHead), [AvailableTrackSchemes, AvailableAudiofileSchemes]); - break; - case nameof(SchemeTracks): - validationStatus = ValidationStatus.Success; - validationMessages = CheckForUnresolvablePlaceholders(SchemeTracks, nameof(SchemeTracks), [AvailableCuesheetSchemes, AvailableAudiofileSchemes]); - break; - case nameof(SchemeAudiofiles): - validationStatus = ValidationStatus.Success; - validationMessages = CheckForUnresolvablePlaceholders(SchemeAudiofiles, nameof(SchemeAudiofiles), [AvailableTrackSchemes, AvailableCuesheetSchemes]); - break; - case nameof(SchemeFooter): - validationStatus = ValidationStatus.Success; - validationMessages = CheckForUnresolvablePlaceholders(SchemeFooter, nameof(SchemeFooter), [AvailableTrackSchemes, AvailableAudiofileSchemes]); - break; - case nameof(Filename): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Filename)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Filename))); - } - break; - case nameof(Name): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Name)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Name))); - } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + case nameof(SchemeHead): + validationStatus = ValidationStatus.Success; + validationMessages = CheckForUnresolvablePlaceholders(SchemeHead, nameof(SchemeHead), [AvailableTrackSchemes, AvailableAudiofileSchemes]); + break; + case nameof(SchemeTracks): + validationStatus = ValidationStatus.Success; + validationMessages = CheckForUnresolvablePlaceholders(SchemeTracks, nameof(SchemeTracks), [AvailableCuesheetSchemes, AvailableAudiofileSchemes]); + break; + case nameof(SchemeAudiofiles): + validationStatus = ValidationStatus.Success; + validationMessages = CheckForUnresolvablePlaceholders(SchemeAudiofiles, nameof(SchemeAudiofiles), [AvailableTrackSchemes, AvailableCuesheetSchemes]); + break; + case nameof(SchemeFooter): + validationStatus = ValidationStatus.Success; + validationMessages = CheckForUnresolvablePlaceholders(SchemeFooter, nameof(SchemeFooter), [AvailableTrackSchemes, AvailableAudiofileSchemes]); + break; + case nameof(Filename): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Filename)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Filename))); + } + break; + case nameof(Name): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Name)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Name))); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); + } - static List<ValidationMessage>? CheckForUnresolvablePlaceholders(String scheme, string schemeName, List<Dictionary<String, String>> schemesToCheck) + static List<ValidationMessage>? CheckForUnresolvablePlaceholders(String scheme, string schemeName, List<Dictionary<String, String>> schemesToCheck) + { + List<ValidationMessage>? validationMessages = null; + foreach (var schemeToCheck in schemesToCheck) { - List<ValidationMessage>? validationMessages = null; - foreach (var schemeToCheck in schemesToCheck) + foreach (var availableScheme in schemeToCheck) { - foreach (var availableScheme in schemeToCheck) + if (scheme.Contains(availableScheme.Value) == true) { - if (scheme.Contains(availableScheme.Value) == true) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} contains placeholder '{1}' that can not be resolved!", schemeName, availableScheme.Value)); - break; - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} contains placeholder '{1}' that can not be resolved!", schemeName, availableScheme.Value)); + break; } } - return validationMessages; } + return validationMessages; } } diff --git a/AudioCuesheetEditor/Model/IO/FileExtensions.cs b/AudioCuesheetEditor/Model/IO/FileExtensions.cs index 980f574d..a3c5cfe8 100644 --- a/AudioCuesheetEditor/Model/IO/FileExtensions.cs +++ b/AudioCuesheetEditor/Model/IO/FileExtensions.cs @@ -13,14 +13,13 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.IO +namespace AudioCuesheetEditor.Model.IO; + +public class FileExtensions { - public class FileExtensions - { - public const string Text = ".txt"; - public const string Projectfile = ".ace"; - public const string Cuesheet = ".cue"; - public const string CDTextfile = ".cdt"; - public const string HTML = ".html"; - } + public const string Text = ".txt"; + public const string Projectfile = ".ace"; + public const string Cuesheet = ".cue"; + public const string CDTextfile = ".cdt"; + public const string HTML = ".html"; } diff --git a/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs b/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs index 37483831..386d0eac 100644 --- a/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs +++ b/AudioCuesheetEditor/Model/IO/FileMimeTypes.cs @@ -13,13 +13,12 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.IO +namespace AudioCuesheetEditor.Model.IO; + +public static class FileMimeTypes { - public static class FileMimeTypes - { - public const string TextPlain = "text/plain"; - public const string Projectfile = "application/x-ace"; - public const string Cuesheet = "application/x-cue"; - public const string Text = "text/*"; - } + public const string TextPlain = "text/plain"; + public const string Projectfile = "application/x-ace"; + public const string Cuesheet = "application/x-cue"; + public const string Text = "text/*"; } diff --git a/AudioCuesheetEditor/Model/IO/FileUpload.cs b/AudioCuesheetEditor/Model/IO/FileUpload.cs index a8df1ee7..ca711fa9 100644 --- a/AudioCuesheetEditor/Model/IO/FileUpload.cs +++ b/AudioCuesheetEditor/Model/IO/FileUpload.cs @@ -13,13 +13,12 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.IO +namespace AudioCuesheetEditor.Model.IO; + +public class FileUpload(string name, string contentType, string? content = null, string? objectUrl = null) { - public class FileUpload(string name, string contentType, string? content = null, string? objectUrl = null) - { - public string Name { get; set; } = name; - public string ContentType { get; set; } = contentType; - public string? Content { get; set; } = content; - public string? ObjectUrl { get; set; } = objectUrl; - } + public string Name { get; set; } = name; + public string ContentType { get; set; } = contentType; + public string? Content { get; set; } = content; + public string? ObjectUrl { get; set; } = objectUrl; } diff --git a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs index 5ad6f513..deb93a79 100644 --- a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs @@ -16,29 +16,28 @@ using AudioCuesheetEditor.Model.AudioCuesheet.Import; using AudioCuesheetEditor.Services.IO; -namespace AudioCuesheetEditor.Model.IO.Import +namespace AudioCuesheetEditor.Model.IO.Import; + +public interface IImportfile { - public interface IImportfile - { - /// <summary> - /// File content - /// </summary> - String? FileContent { get; set; } - /// <summary> - /// File content with marking which passages has been recognized by scheme - /// </summary> - String? FileContentRecognized { get; set; } - /// <summary> - /// Exception that has been thrown while reading out the file - /// </summary> - Exception? AnalyseException { get; set; } - /// <summary> - /// The cue sheet which was created during analyzing the <see cref="FileContent"/> - /// </summary> - ImportCuesheet? AnalyzedCuesheet { get; set; } - /// <summary> - /// Type of file (text, cuesheet, project, etc.) - /// </summary> - ImportFileType FileType { get; set; } - } + /// <summary> + /// File content + /// </summary> + String? FileContent { get; set; } + /// <summary> + /// File content with marking which passages has been recognized by scheme + /// </summary> + String? FileContentRecognized { get; set; } + /// <summary> + /// Exception that has been thrown while reading out the file + /// </summary> + Exception? AnalyseException { get; set; } + /// <summary> + /// The cue sheet which was created during analyzing the <see cref="FileContent"/> + /// </summary> + ImportCuesheet? AnalyzedCuesheet { get; set; } + /// <summary> + /// Type of file (text, cuesheet, project, etc.) + /// </summary> + ImportFileType FileType { get; set; } } diff --git a/AudioCuesheetEditor/Model/IO/Import/Importfile.cs b/AudioCuesheetEditor/Model/IO/Import/Importfile.cs index eafbb129..da62b57c 100644 --- a/AudioCuesheetEditor/Model/IO/Import/Importfile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/Importfile.cs @@ -16,18 +16,17 @@ using AudioCuesheetEditor.Model.AudioCuesheet.Import; using AudioCuesheetEditor.Services.IO; -namespace AudioCuesheetEditor.Model.IO.Import +namespace AudioCuesheetEditor.Model.IO.Import; + +public class Importfile : IImportfile { - public class Importfile : IImportfile - { - /// <inheritdoc /> - public Exception? AnalyseException { get; set; } - /// <inheritdoc /> - public ImportCuesheet? AnalyzedCuesheet { get; set; } - public ImportFileType FileType { get; set; } - /// <inheritdoc /> - public string? FileContentRecognized { get; set; } - /// <inheritdoc /> - public string? FileContent { get; set; } - } + /// <inheritdoc /> + public Exception? AnalyseException { get; set; } + /// <inheritdoc /> + public ImportCuesheet? AnalyzedCuesheet { get; set; } + public ImportFileType FileType { get; set; } + /// <inheritdoc /> + public string? FileContentRecognized { get; set; } + /// <inheritdoc /> + public string? FileContent { get; set; } } diff --git a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs index 822d1a4e..89033df7 100644 --- a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs @@ -17,91 +17,90 @@ using AudioCuesheetEditor.Model.Entity; using AudioCuesheetEditor.Model.Utility; -namespace AudioCuesheetEditor.Model.IO.Import +namespace AudioCuesheetEditor.Model.IO.Import; + +public class Importprofile : Validateable { - public class Importprofile : Validateable - { - public static readonly IEnumerable<String> AvailableSchemeCuesheet = [nameof(ImportCuesheet.Artist), nameof(ImportCuesheet.Title), nameof(ImportCuesheet.CDTextfile), nameof(ImportCuesheet.Cataloguenumber)]; + public static readonly IEnumerable<String> AvailableSchemeCuesheet = [nameof(ImportCuesheet.Artist), nameof(ImportCuesheet.Title), nameof(ImportCuesheet.CDTextfile), nameof(ImportCuesheet.Cataloguenumber)]; - public static readonly IEnumerable<String> AvailableSchemeAudiofiles = [nameof(ImportAudiofile.Name)]; + public static readonly IEnumerable<String> AvailableSchemeAudiofiles = [nameof(ImportAudiofile.Name)]; - public static readonly IEnumerable<String> AvailableSchemesTrack = [nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), nameof(ImportTrack.End), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), nameof(ImportTrack.PreGap), nameof(ImportTrack.PostGap), nameof(ImportTrack.StartDateTime)]; + public static readonly IEnumerable<String> AvailableSchemesTrack = [nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), nameof(ImportTrack.End), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), nameof(ImportTrack.PreGap), nameof(ImportTrack.PostGap), nameof(ImportTrack.StartDateTime)]; - public Guid Id { get; init; } = Guid.NewGuid(); - public String? Name { get; set; } - public Boolean UseRegularExpression { get; set; } - public String? SchemeCuesheet { get; set; } - public String? SchemeAudiofiles { get; set; } - public String? SchemeTracks { get; set; } - public TimeSpanFormat? TimeSpanFormat { get; set; } - public override ValidationResult Validate(string property) + public Guid Id { get; init; } = Guid.NewGuid(); + public String? Name { get; set; } + public Boolean UseRegularExpression { get; set; } + public String? SchemeCuesheet { get; set; } + public String? SchemeAudiofiles { get; set; } + public String? SchemeTracks { get; set; } + public TimeSpanFormat? TimeSpanFormat { get; set; } + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(SchemeCuesheet): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(SchemeCuesheet) == false) + case nameof(SchemeCuesheet): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(SchemeCuesheet) == false) + { + var containsPlaceHolder = false; + var enumerator = AvailableSchemeCuesheet.GetEnumerator(); + if (enumerator.MoveNext()) { - var containsPlaceHolder = false; - var enumerator = AvailableSchemeCuesheet.GetEnumerator(); - if (enumerator.MoveNext()) + do { - do - { - containsPlaceHolder = SchemeCuesheet?.Contains(enumerator.Current) == true; - } while ((containsPlaceHolder == false) && enumerator.MoveNext()); - } - if (containsPlaceHolder == false) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(SchemeCuesheet))); - } + containsPlaceHolder = SchemeCuesheet?.Contains(enumerator.Current) == true; + } while ((containsPlaceHolder == false) && enumerator.MoveNext()); } - break; - case nameof(SchemeAudiofiles): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(SchemeAudiofiles) == false) + if (containsPlaceHolder == false) { - var containsPlaceHolder = false; - var enumerator = AvailableSchemeAudiofiles.GetEnumerator(); - if (enumerator.MoveNext()) - { - do - { - containsPlaceHolder = SchemeAudiofiles?.Contains(enumerator.Current) == true; - } while ((containsPlaceHolder == false) && enumerator.MoveNext()); - } - if (containsPlaceHolder == false) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(SchemeAudiofiles))); - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(SchemeCuesheet))); } - break; - case nameof(SchemeTracks): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(SchemeTracks) == false) + } + break; + case nameof(SchemeAudiofiles): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(SchemeAudiofiles) == false) + { + var containsPlaceHolder = false; + var enumerator = AvailableSchemeAudiofiles.GetEnumerator(); + if (enumerator.MoveNext()) { - var containsPlaceHolder = false; - var enumerator = AvailableSchemesTrack.GetEnumerator(); - if (enumerator.MoveNext()) + do { - do - { - containsPlaceHolder = SchemeTracks?.Contains(enumerator.Current) == true; - } while ((containsPlaceHolder == false) && enumerator.MoveNext()); - } - if (containsPlaceHolder == false) + containsPlaceHolder = SchemeAudiofiles?.Contains(enumerator.Current) == true; + } while ((containsPlaceHolder == false) && enumerator.MoveNext()); + } + if (containsPlaceHolder == false) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(SchemeAudiofiles))); + } + } + break; + case nameof(SchemeTracks): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(SchemeTracks) == false) + { + var containsPlaceHolder = false; + var enumerator = AvailableSchemesTrack.GetEnumerator(); + if (enumerator.MoveNext()) + { + do { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(SchemeTracks))); - } + containsPlaceHolder = SchemeTracks?.Contains(enumerator.Current) == true; + } while ((containsPlaceHolder == false) && enumerator.MoveNext()); + } + if (containsPlaceHolder == false) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(SchemeTracks))); } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); } } diff --git a/AudioCuesheetEditor/Model/IO/Projectfile.cs b/AudioCuesheetEditor/Model/IO/Projectfile.cs index 767de0fc..06dcab28 100644 --- a/AudioCuesheetEditor/Model/IO/Projectfile.cs +++ b/AudioCuesheetEditor/Model/IO/Projectfile.cs @@ -18,49 +18,48 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.IO +namespace AudioCuesheetEditor.Model.IO; + +public class Projectfile(Cuesheet cuesheet) { - public class Projectfile(Cuesheet cuesheet) - { - public static readonly String DefaultFilename = "Project.ace"; + public static readonly String DefaultFilename = "Project.ace"; - public static readonly JsonSerializerOptions Options = new() + public static readonly JsonSerializerOptions Options = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + Converters = { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - ReferenceHandler = ReferenceHandler.IgnoreCycles, - Converters = - { - new JsonStringEnumConverter() - } - }; + new JsonStringEnumConverter() + } + }; - public static Cuesheet? ImportFile(string fileContent) + public static Cuesheet? ImportFile(string fileContent) + { + var cuesheet = JsonSerializer.Deserialize<Cuesheet>(fileContent, Options); + if (cuesheet != null) { - var cuesheet = JsonSerializer.Deserialize<Cuesheet>(fileContent, Options); - if (cuesheet != null) + foreach (var audiofile in cuesheet.Audiofiles) { - foreach (var audiofile in cuesheet.Audiofiles) + foreach (var track in audiofile.Tracks) { - foreach (var track in audiofile.Tracks) - { - track.Audiofile = audiofile; - track.Cuesheet = cuesheet; - } + track.Audiofile = audiofile; + track.Cuesheet = cuesheet; } } - return cuesheet; } + return cuesheet; + } - public Cuesheet Cuesheet { get; private set; } = cuesheet; + public Cuesheet Cuesheet { get; private set; } = cuesheet; - /// <summary> - /// Generate a ProjectFile - /// </summary> - /// <returns>Byte array with project file content</returns> - public byte[] GenerateFile() - { - var json = JsonSerializer.Serialize(Cuesheet, Options); - return Encoding.UTF8.GetBytes(json); - } + /// <summary> + /// Generate a ProjectFile + /// </summary> + /// <returns>Byte array with project file content</returns> + public byte[] GenerateFile() + { + var json = JsonSerializer.Serialize(Cuesheet, Options); + return Encoding.UTF8.GetBytes(json); } } diff --git a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs index 06ef0b15..e34f6901 100644 --- a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs @@ -18,30 +18,29 @@ using System.Globalization; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public class ApplicationOptions : IOptions { - public class ApplicationOptions : IOptions + public const LogLevel DefaultLogLevel = LogLevel.Information; + public String? CultureName { get; set; } = LocalizationService.DefaultCulture; + [JsonIgnore] + public CultureInfo Culture { - public const LogLevel DefaultLogLevel = LogLevel.Information; - public String? CultureName { get; set; } = LocalizationService.DefaultCulture; - [JsonIgnore] - public CultureInfo Culture + get { - get + if (String.IsNullOrEmpty(CultureName) == false) + { + return new CultureInfo(CultureName); + } + else { - if (String.IsNullOrEmpty(CultureName) == false) - { - return new CultureInfo(CultureName); - } - else - { - return CultureInfo.CurrentCulture; - } + return CultureInfo.CurrentCulture; } } - public TimeSpanFormat? TimeSpanFormat { get; set; } - public Boolean DefaultIsLinkedToPreviousTrack { get; set; } = true; - public String? DisplayTimeSpanFormat { get; set; } - public LogLevel MinimumLogLevel { get; set; } = DefaultLogLevel; } + public TimeSpanFormat? TimeSpanFormat { get; set; } + public Boolean DefaultIsLinkedToPreviousTrack { get; set; } = true; + public String? DisplayTimeSpanFormat { get; set; } + public LogLevel MinimumLogLevel { get; set; } = DefaultLogLevel; } diff --git a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs index b74e136c..fd164cb8 100644 --- a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs +++ b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs @@ -17,98 +17,97 @@ using AudioCuesheetEditor.Model.IO; using AudioCuesheetEditor.Model.IO.Export; -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public class DownloadOptions : Validateable, IOptions { - public class DownloadOptions : Validateable, IOptions + string? projectFilename = Projectfile.DefaultFilename; + string? cuesheetFilename = Exportfile.DefaultCuesheetFilename; + public String? CuesheetFilename { - private string? projectFilename = Projectfile.DefaultFilename; - private string? cuesheetFilename = Exportfile.DefaultCuesheetFilename; - public String? CuesheetFilename + get => cuesheetFilename; + set { - get => cuesheetFilename; - set + if (String.IsNullOrEmpty(value) == false) { - if (String.IsNullOrEmpty(value) == false) + var extension = Path.GetExtension(value); + if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) { - var extension = Path.GetExtension(value); - if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) - { - value = $"{value}{FileExtensions.Cuesheet}"; - } + value = $"{value}{FileExtensions.Cuesheet}"; } - cuesheetFilename = value; } + cuesheetFilename = value; } - public String? ProjectFilename + } + public String? ProjectFilename + { + get => projectFilename; + set { - get => projectFilename; - set + if (String.IsNullOrEmpty(value) == false) { - if (String.IsNullOrEmpty(value) == false) + var extension = Path.GetExtension(value); + if (extension?.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false) { - var extension = Path.GetExtension(value); - if (extension?.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false) - { - value = $"{value}{FileExtensions.Projectfile}"; - } + value = $"{value}{FileExtensions.Projectfile}"; } - projectFilename = value; } + projectFilename = value; } - public override ValidationResult Validate(string property) + } + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(CuesheetFilename): - validationStatus = ValidationStatus.Success; - if (string.IsNullOrEmpty(CuesheetFilename)) + case nameof(CuesheetFilename): + validationStatus = ValidationStatus.Success; + if (string.IsNullOrEmpty(CuesheetFilename)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(CuesheetFilename))); + } + else + { + var extension = Path.GetExtension(CuesheetFilename); + if (extension.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(CuesheetFilename))); + validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(CuesheetFilename), FileExtensions.Cuesheet)); } - else + var filenameWithoutExtension = Path.GetFileNameWithoutExtension(CuesheetFilename); + if (string.IsNullOrEmpty(filenameWithoutExtension)) { - var extension = Path.GetExtension(CuesheetFilename); - if (extension.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(CuesheetFilename), FileExtensions.Cuesheet)); - } - var filenameWithoutExtension = Path.GetFileNameWithoutExtension(CuesheetFilename); - if (string.IsNullOrEmpty(filenameWithoutExtension)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(CuesheetFilename))); - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(CuesheetFilename))); } - break; - case nameof(ProjectFilename): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(ProjectFilename)) + } + break; + case nameof(ProjectFilename): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(ProjectFilename)) + { + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(ProjectFilename))); + } + else + { + var extension = Path.GetExtension(ProjectFilename); + if (extension.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(ProjectFilename))); + validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(ProjectFilename), FileExtensions.Projectfile)); } - else + var filename = Path.GetFileNameWithoutExtension(ProjectFilename); + if (String.IsNullOrEmpty(filename)) { - var extension = Path.GetExtension(ProjectFilename); - if (extension.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(ProjectFilename), FileExtensions.Projectfile)); - } - var filename = Path.GetFileNameWithoutExtension(ProjectFilename); - if (String.IsNullOrEmpty(filename)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(ProjectFilename))); - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(ProjectFilename))); } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); } } diff --git a/AudioCuesheetEditor/Model/Options/ExportOptions.cs b/AudioCuesheetEditor/Model/Options/ExportOptions.cs index 3f8457ac..c328db5e 100644 --- a/AudioCuesheetEditor/Model/Options/ExportOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ExportOptions.cs @@ -16,69 +16,68 @@ using AudioCuesheetEditor.Model.IO.Export; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public class ExportOptions : IOptions { - public class ExportOptions : IOptions + public static readonly Exportprofile DefaultSelectedExportProfile = new() { - public static readonly Exportprofile DefaultSelectedExportProfile = new() + Filename = "YouTube.txt", + Name = "YouTube", + SchemeHead = "%Cuesheet.Artist% - %Cuesheet.Title%", + SchemeTracks = "%Track.Artist% - %Track.Title% %Track.Begin%" + }; + public static readonly ICollection<Exportprofile> DefaultExportProfiles = + [ + DefaultSelectedExportProfile, + new Exportprofile() { - Filename = "YouTube.txt", - Name = "YouTube", - SchemeHead = "%Cuesheet.Artist% - %Cuesheet.Title%", + Filename = "Mixcloud.txt", + Name = "Mixcloud", SchemeTracks = "%Track.Artist% - %Track.Title% %Track.Begin%" - }; - public static readonly ICollection<Exportprofile> DefaultExportProfiles = - [ - DefaultSelectedExportProfile, - new Exportprofile() - { - Filename = "Mixcloud.txt", - Name = "Mixcloud", - SchemeTracks = "%Track.Artist% - %Track.Title% %Track.Begin%" - }, - new Exportprofile() - { - Filename = "Export.csv", - Name = "CSV Export", - SchemeHead = "%Cuesheet.Artist%;%Cuesheet.Title%;", - SchemeTracks = "%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%", - SchemeFooter = "Exported at %DateTime% using AudioCuesheetEditor (https://neocodermatrix86.github.io/AudioCuesheetEditor/)" - }, - new Exportprofile() - { - Filename = "Tracks.txt", - Name = "Tracks only", - SchemeTracks = "%Track.Position% - %Track.Artist% - %Track.Title% - %Track.Begin% - %Track.End% - %Track.Length%", - } - ]; - public ExportOptions() + }, + new Exportprofile() { - ExportProfiles = DefaultExportProfiles; - SelectedProfileId = DefaultSelectedExportProfile.Id; - } - [JsonConstructor] - public ExportOptions(ICollection<Exportprofile> exportProfiles, Guid? selectedProfileId = null) + Filename = "Export.csv", + Name = "CSV Export", + SchemeHead = "%Cuesheet.Artist%;%Cuesheet.Title%;", + SchemeTracks = "%Track.Position%;%Track.Artist%;%Track.Title%;%Track.Begin%;%Track.End%;%Track.Length%", + SchemeFooter = "Exported at %DateTime% using AudioCuesheetEditor (https://neocodermatrix86.github.io/AudioCuesheetEditor/)" + }, + new Exportprofile() { - ExportProfiles = exportProfiles; - SelectedProfileId = selectedProfileId ?? ExportProfiles.FirstOrDefault()?.Id; + Filename = "Tracks.txt", + Name = "Tracks only", + SchemeTracks = "%Track.Position% - %Track.Artist% - %Track.Title% - %Track.Begin% - %Track.End% - %Track.Length%", } - public ICollection<Exportprofile> ExportProfiles { get; set; } - [JsonIgnore] - public Exportprofile? SelectedExportProfile + ]; + public ExportOptions() + { + ExportProfiles = DefaultExportProfiles; + SelectedProfileId = DefaultSelectedExportProfile.Id; + } + [JsonConstructor] + public ExportOptions(ICollection<Exportprofile> exportProfiles, Guid? selectedProfileId = null) + { + ExportProfiles = exportProfiles; + SelectedProfileId = selectedProfileId ?? ExportProfiles.FirstOrDefault()?.Id; + } + public ICollection<Exportprofile> ExportProfiles { get; set; } + [JsonIgnore] + public Exportprofile? SelectedExportProfile + { + get => SelectedProfileId.HasValue ? ExportProfiles.FirstOrDefault(x => x.Id == SelectedProfileId) : null; + set { - get => SelectedProfileId.HasValue ? ExportProfiles.FirstOrDefault(x => x.Id == SelectedProfileId) : null; - set + if (ExportProfiles.Any(x => x.Id == value?.Id) == false) { - if (ExportProfiles.Any(x => x.Id == value?.Id) == false) + if (value != null) { - if (value != null) - { - ExportProfiles.Add(value); - } + ExportProfiles.Add(value); } - SelectedProfileId = value?.Id; } + SelectedProfileId = value?.Id; } - public Guid? SelectedProfileId { get; private set; } } + public Guid? SelectedProfileId { get; private set; } } diff --git a/AudioCuesheetEditor/Model/Options/IOptions.cs b/AudioCuesheetEditor/Model/Options/IOptions.cs index d7cb1a26..131bf175 100644 --- a/AudioCuesheetEditor/Model/Options/IOptions.cs +++ b/AudioCuesheetEditor/Model/Options/IOptions.cs @@ -13,10 +13,9 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public interface IOptions { - public interface IOptions - { - - } + } diff --git a/AudioCuesheetEditor/Model/Options/ImportOptions.cs b/AudioCuesheetEditor/Model/Options/ImportOptions.cs index 533c0771..3e289c24 100644 --- a/AudioCuesheetEditor/Model/Options/ImportOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ImportOptions.cs @@ -17,60 +17,59 @@ using AudioCuesheetEditor.Model.IO.Import; using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public class ImportOptions : IOptions { - public class ImportOptions : IOptions + public static readonly Importprofile DefaultSelectedImportprofile = new() { - public static readonly Importprofile DefaultSelectedImportprofile = new() + Name = "Textfile (common data in first line)", + UseRegularExpression = false, + SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}", + SchemeAudiofiles = $"- {nameof(ImportAudiofile.Name)}", + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + }; + + public static readonly ICollection<Importprofile> DefaultImportprofiles = + [ + DefaultSelectedImportprofile, + new() { - Name = "Textfile (common data in first line)", + Name = "Textfile (just track data)", UseRegularExpression = false, - SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}", - SchemeAudiofiles = $"- {nameof(ImportAudiofile.Name)}", SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" - }; - - public static readonly ICollection<Importprofile> DefaultImportprofiles = - [ - DefaultSelectedImportprofile, - new() - { - Name = "Textfile (just track data)", - UseRegularExpression = false, - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" - }, - new() - { - Name = "Textfile (track data seperated by ~)", - UseRegularExpression = false, - SchemeTracks = $"{nameof(ImportTrack.Artist)}~{nameof(ImportTrack.Title)}~{nameof(ImportTrack.StartDateTime)}" - }, - new() - { - Name = "Traktor history", - UseRegularExpression = true, - SchemeTracks = @$"<tr>\s*<td>(?<{nameof(ImportTrack.Position)}>\d+)</td>\s*<td>(?<{nameof(ImportTrack.Artist)}>.*?)</td>\s*<td>(?<{nameof(ImportTrack.Title)}>.*?)</td>\s*<td>(?<{nameof(ImportTrack.StartDateTime)}>.*?)</td>\s*</tr>" - } - ]; + }, + new() + { + Name = "Textfile (track data seperated by ~)", + UseRegularExpression = false, + SchemeTracks = $"{nameof(ImportTrack.Artist)}~{nameof(ImportTrack.Title)}~{nameof(ImportTrack.StartDateTime)}" + }, + new() + { + Name = "Traktor history", + UseRegularExpression = true, + SchemeTracks = @$"<tr>\s*<td>(?<{nameof(ImportTrack.Position)}>\d+)</td>\s*<td>(?<{nameof(ImportTrack.Artist)}>.*?)</td>\s*<td>(?<{nameof(ImportTrack.Title)}>.*?)</td>\s*<td>(?<{nameof(ImportTrack.StartDateTime)}>.*?)</td>\s*</tr>" + } + ]; - [JsonInclude] - public Guid? SelectedImportProfileId { get; private set; } = DefaultSelectedImportprofile.Id; - public ICollection<Importprofile> ImportProfiles { get; set; } = DefaultImportprofiles; - [JsonIgnore] - public Importprofile? SelectedImportProfile + [JsonInclude] + public Guid? SelectedImportProfileId { get; private set; } = DefaultSelectedImportprofile.Id; + public ICollection<Importprofile> ImportProfiles { get; set; } = DefaultImportprofiles; + [JsonIgnore] + public Importprofile? SelectedImportProfile + { + get => SelectedImportProfileId.HasValue ? ImportProfiles.FirstOrDefault(x => x.Id == SelectedImportProfileId) : null; + set { - get => SelectedImportProfileId.HasValue ? ImportProfiles.FirstOrDefault(x => x.Id == SelectedImportProfileId) : null; - set + if (ImportProfiles.Any(x => x.Id == value?.Id) == false) { - if (ImportProfiles.Any(x => x.Id == value?.Id) == false) + if (value != null) { - if (value != null) - { - ImportProfiles.Add(value); - } + ImportProfiles.Add(value); } - SelectedImportProfileId = value?.Id; } + SelectedImportProfileId = value?.Id; } } } diff --git a/AudioCuesheetEditor/Model/Options/RecordOptions.cs b/AudioCuesheetEditor/Model/Options/RecordOptions.cs index ab47a448..d61887c0 100644 --- a/AudioCuesheetEditor/Model/Options/RecordOptions.cs +++ b/AudioCuesheetEditor/Model/Options/RecordOptions.cs @@ -13,10 +13,9 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public class RecordOptions : IOptions { - public class RecordOptions : IOptions - { - public uint RecordCountdownTimer { get; set; } = 5; - } + public uint RecordCountdownTimer { get; set; } = 5; } diff --git a/AudioCuesheetEditor/Model/Options/ViewOptions.cs b/AudioCuesheetEditor/Model/Options/ViewOptions.cs index 3c1389e4..ee54d730 100644 --- a/AudioCuesheetEditor/Model/Options/ViewOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ViewOptions.cs @@ -15,31 +15,30 @@ //<http: //www.gnu.org/licenses />. using System.Text.Json.Serialization; -namespace AudioCuesheetEditor.Model.Options +namespace AudioCuesheetEditor.Model.Options; + +public enum ViewMode { - public enum ViewMode - { - DetailView = 0, - RecordView = 1, - ImportView = 2 - } - public class ViewOptions : IOptions + DetailView = 0, + RecordView = 1, + ImportView = 2 +} +public class ViewOptions : IOptions +{ + [JsonIgnore] + public ViewMode ActiveTab { get; set; } + public String? ActiveTabName { - [JsonIgnore] - public ViewMode ActiveTab { get; set; } - public String? ActiveTabName + get => Enum.GetName(ActiveTab); + set { - get => Enum.GetName(ActiveTab); - set + if (value != null) + { + ActiveTab = Enum.Parse<ViewMode>(value); + } + else { - if (value != null) - { - ActiveTab = Enum.Parse<ViewMode>(value); - } - else - { - throw new ArgumentNullException(nameof(value)); - } + throw new ArgumentNullException(nameof(value)); } } } diff --git a/AudioCuesheetEditor/Model/UI/EditMultipleTracksModalResult.cs b/AudioCuesheetEditor/Model/UI/EditMultipleTracksModalResult.cs index 3aefd35e..5a17e4e2 100644 --- a/AudioCuesheetEditor/Model/UI/EditMultipleTracksModalResult.cs +++ b/AudioCuesheetEditor/Model/UI/EditMultipleTracksModalResult.cs @@ -15,26 +15,25 @@ //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Model.AudioCuesheet; -namespace AudioCuesheetEditor.Model.UI +namespace AudioCuesheetEditor.Model.UI; + +public enum DynamicEditValue +{ + DoNotChange = 0, + EnteredValueEquals = 1, + EnteredValueAdd = 2, + EnteredValueSubstract = 3 +} +public class EditMultipleTracksModalResult(Track editedTrack, DynamicEditValue isLinkedToPreviousTrackChanged, DynamicEditValue artistEditMode, DynamicEditValue titleEditMode, DynamicEditValue beginEditMode, DynamicEditValue endEditMode, DynamicEditValue lengthEditMode, DynamicEditValue flagsEditMode, DynamicEditValue pregapEditMode, DynamicEditValue postgapEditMode) { - public enum DynamicEditValue - { - DoNotChange = 0, - EnteredValueEquals = 1, - EnteredValueAdd = 2, - EnteredValueSubstract = 3 - } - public class EditMultipleTracksModalResult(Track editedTrack, DynamicEditValue isLinkedToPreviousTrackChanged, DynamicEditValue artistEditMode, DynamicEditValue titleEditMode, DynamicEditValue beginEditMode, DynamicEditValue endEditMode, DynamicEditValue lengthEditMode, DynamicEditValue flagsEditMode, DynamicEditValue pregapEditMode, DynamicEditValue postgapEditMode) - { - public Track EditedTrack { get; } = editedTrack; - public DynamicEditValue IsLinkedToPreviousTrackEditMode { get; } = isLinkedToPreviousTrackChanged; - public DynamicEditValue ArtistEditMode { get; } = artistEditMode; - public DynamicEditValue TitleEditMode { get; } = titleEditMode; - public DynamicEditValue BeginEditMode { get; } = beginEditMode; - public DynamicEditValue EndEditMode { get; } = endEditMode; - public DynamicEditValue LengthEditMode { get; } = lengthEditMode; - public DynamicEditValue FlagsEditMode { get; } = flagsEditMode; - public DynamicEditValue PregapEditMode { get; } = pregapEditMode; - public DynamicEditValue PostgapEditMode { get; } = postgapEditMode; - } + public Track EditedTrack { get; } = editedTrack; + public DynamicEditValue IsLinkedToPreviousTrackEditMode { get; } = isLinkedToPreviousTrackChanged; + public DynamicEditValue ArtistEditMode { get; } = artistEditMode; + public DynamicEditValue TitleEditMode { get; } = titleEditMode; + public DynamicEditValue BeginEditMode { get; } = beginEditMode; + public DynamicEditValue EndEditMode { get; } = endEditMode; + public DynamicEditValue LengthEditMode { get; } = lengthEditMode; + public DynamicEditValue FlagsEditMode { get; } = flagsEditMode; + public DynamicEditValue PregapEditMode { get; } = pregapEditMode; + public DynamicEditValue PostgapEditMode { get; } = postgapEditMode; } diff --git a/AudioCuesheetEditor/Model/UI/TraceableChange.cs b/AudioCuesheetEditor/Model/UI/TraceableChange.cs index e5dfa0ba..875e5ce8 100644 --- a/AudioCuesheetEditor/Model/UI/TraceableChange.cs +++ b/AudioCuesheetEditor/Model/UI/TraceableChange.cs @@ -13,21 +13,20 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.UI +namespace AudioCuesheetEditor.Model.UI; + +public class TraceableChange { - public class TraceableChange + public TraceableChange(object? previousValue, string propertyName) { - public TraceableChange(object? previousValue, string propertyName) + if (String.IsNullOrEmpty(propertyName)) { - if (String.IsNullOrEmpty(propertyName)) - { - throw new ArgumentNullException(nameof(propertyName)); - } - PreviousValue = previousValue; - PropertyName = propertyName; + throw new ArgumentNullException(nameof(propertyName)); } - - public object? PreviousValue { get; } - public string PropertyName { get; } + PreviousValue = previousValue; + PropertyName = propertyName; } + + public object? PreviousValue { get; } + public string PropertyName { get; } } diff --git a/AudioCuesheetEditor/Model/UI/TracedChange.cs b/AudioCuesheetEditor/Model/UI/TracedChange.cs index fb4eb9a9..44581801 100644 --- a/AudioCuesheetEditor/Model/UI/TracedChange.cs +++ b/AudioCuesheetEditor/Model/UI/TracedChange.cs @@ -13,27 +13,26 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.UI +namespace AudioCuesheetEditor.Model.UI; + +/// <summary> +/// Class for tracing changes on an object +/// </summary> +public class TracedChange(object traceableObject, TraceableChange traceableChange) { - /// <summary> - /// Class for tracing changes on an object - /// </summary> - public class TracedChange(object traceableObject, TraceableChange traceableChange) - { - private readonly WeakReference<object> _tracedObject = new(traceableObject, false); + readonly WeakReference<object> _tracedObject = new(traceableObject, false); - public object? TraceableObject + public object? TraceableObject + { + get { - get + if (_tracedObject.TryGetTarget(out var traceable)) { - if (_tracedObject.TryGetTarget(out var traceable)) - { - return traceable; - } - return null; + return traceable; } + return null; } - - public TraceableChange TraceableChange { get; } = traceableChange; } + + public TraceableChange TraceableChange { get; } = traceableChange; } diff --git a/AudioCuesheetEditor/Model/UI/TracedChanges.cs b/AudioCuesheetEditor/Model/UI/TracedChanges.cs index 00ce7c1d..300e3399 100644 --- a/AudioCuesheetEditor/Model/UI/TracedChanges.cs +++ b/AudioCuesheetEditor/Model/UI/TracedChanges.cs @@ -13,11 +13,10 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.UI +namespace AudioCuesheetEditor.Model.UI; + +public class TracedChanges(IEnumerable<TracedChange> changes) { - public class TracedChanges(IEnumerable<TracedChange> changes) - { - public List<TracedChange> Changes { get; } = [.. changes]; - public bool HasTraceableObject { get { return Changes.Any(x => x.TraceableObject != null); } } - } + public List<TracedChange> Changes { get; } = [.. changes]; + public bool HasTraceableObject { get { return Changes.Any(x => x.TraceableObject != null); } } } diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs index 6661e82c..2129e0dd 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs @@ -16,112 +16,111 @@ using AudioCuesheetEditor.Model.Entity; using System.Text.RegularExpressions; -namespace AudioCuesheetEditor.Model.Utility +namespace AudioCuesheetEditor.Model.Utility; + +public class TimeSpanFormat : Validateable { - public class TimeSpanFormat : Validateable - { - public const String Days = "Days"; - public const String Hours = "Hours"; - public const String Minutes = "Minutes"; - public const String Seconds = "Seconds"; - public const String Milliseconds = "Milliseconds"; + public const String Days = "Days"; + public const String Hours = "Hours"; + public const String Minutes = "Minutes"; + public const String Seconds = "Seconds"; + public const String Milliseconds = "Milliseconds"; - public static readonly IEnumerable<String> AvailableTimespanScheme; + public static readonly IEnumerable<String> AvailableTimespanScheme; - static TimeSpanFormat() - { - AvailableTimespanScheme = [Days, Hours, Minutes, Seconds, Milliseconds]; - } + static TimeSpanFormat() + { + AvailableTimespanScheme = [Days, Hours, Minutes, Seconds, Milliseconds]; + } - public event EventHandler? SchemeChanged; + public event EventHandler? SchemeChanged; - private string? scheme; + string? scheme; - public String? Scheme + public String? Scheme + { + get => scheme; + set { - get => scheme; - set - { - scheme = value; - SchemeChanged?.Invoke(this, EventArgs.Empty); - OnValidateablePropertyChanged(); - } + scheme = value; + SchemeChanged?.Invoke(this, EventArgs.Empty); + OnValidateablePropertyChanged(); } + } - public TimeSpan? ParseTimeSpan(String input) + public TimeSpan? ParseTimeSpan(String input) + { + TimeSpan? timespan = null; + if ((String.IsNullOrEmpty(Scheme) == false) && (String.IsNullOrEmpty(input) == false)) { - TimeSpan? timespan = null; - if ((String.IsNullOrEmpty(Scheme) == false) && (String.IsNullOrEmpty(input) == false)) + var pattern = CreateFlexibleRegexPattern(Scheme); + var match = Regex.Match(input, pattern); + if (match.Success) { - var pattern = CreateFlexibleRegexPattern(Scheme); - var match = Regex.Match(input, pattern); - if (match.Success) + int days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0; + foreach (var groupName in match.Groups.Keys) { - int days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0; - foreach (var groupName in match.Groups.Keys) + switch (groupName) { - switch (groupName) - { - case nameof(Days): - days = Convert.ToInt32(match.Groups[groupName].Value); - break; - case nameof(Hours): - hours = Convert.ToInt32(match.Groups[groupName].Value); - break; - case nameof(Minutes): - minutes = Convert.ToInt32(match.Groups[groupName].Value); - break; - case nameof(Seconds): - seconds = Convert.ToInt32(match.Groups[groupName].Value); - break; - case nameof(Milliseconds): - milliseconds = Convert.ToInt32(match.Groups[groupName].Value); - break; - } + case nameof(Days): + days = Convert.ToInt32(match.Groups[groupName].Value); + break; + case nameof(Hours): + hours = Convert.ToInt32(match.Groups[groupName].Value); + break; + case nameof(Minutes): + minutes = Convert.ToInt32(match.Groups[groupName].Value); + break; + case nameof(Seconds): + seconds = Convert.ToInt32(match.Groups[groupName].Value); + break; + case nameof(Milliseconds): + milliseconds = Convert.ToInt32(match.Groups[groupName].Value); + break; } - timespan = new TimeSpan(days, hours, minutes, seconds, milliseconds); } + timespan = new TimeSpan(days, hours, minutes, seconds, milliseconds); } - return timespan; } + return timespan; + } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string property) + { + ValidationStatus validationStatus = ValidationStatus.NoValidation; + List<ValidationMessage>? validationMessages = null; + switch (property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; - List<ValidationMessage>? validationMessages = null; - switch (property) - { - case nameof(Scheme): - validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Scheme) == false) + case nameof(Scheme): + validationStatus = ValidationStatus.Success; + if (String.IsNullOrEmpty(Scheme) == false) + { + if ((Scheme.Contains(Days) == false) + && (Scheme.Contains(Hours) == false) + && (Scheme.Contains(Minutes) == false) + && (Scheme.Contains(Seconds) == false) + && (Scheme.Contains(Milliseconds) == false)) { - if ((Scheme.Contains(Days) == false) - && (Scheme.Contains(Hours) == false) - && (Scheme.Contains(Minutes) == false) - && (Scheme.Contains(Seconds) == false) - && (Scheme.Contains(Milliseconds) == false)) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(Scheme))); - } + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("{0} contains no placeholder!", nameof(Scheme))); } - break; - } - return ValidationResult.Create(validationStatus, validationMessages); + } + break; } + return ValidationResult.Create(validationStatus, validationMessages); + } - private static string CreateFlexibleRegexPattern(string scheme) - { - var regex = Regex.Escape(scheme); + static string CreateFlexibleRegexPattern(string scheme) + { + var regex = Regex.Escape(scheme); - regex = regex.Replace(Days, $"(?<{nameof(Days)}>\\d+)"); - regex = regex.Replace(Hours, $"(?<{nameof(Hours)}>\\d+)"); - regex = regex.Replace(Minutes, $"(?<{nameof(Minutes)}>\\d+)"); - regex = regex.Replace(Seconds, $"(?<{nameof(Seconds)}>\\d+)"); - regex = regex.Replace(Milliseconds, $"(?<{nameof(Milliseconds)}>\\d+)"); - regex = regex.Replace(@"\\:", @"[\s|:.,-]?"); + regex = regex.Replace(Days, $"(?<{nameof(Days)}>\\d+)"); + regex = regex.Replace(Hours, $"(?<{nameof(Hours)}>\\d+)"); + regex = regex.Replace(Minutes, $"(?<{nameof(Minutes)}>\\d+)"); + regex = regex.Replace(Seconds, $"(?<{nameof(Seconds)}>\\d+)"); + regex = regex.Replace(Milliseconds, $"(?<{nameof(Milliseconds)}>\\d+)"); + regex = regex.Replace(@"\\:", @"[\s|:.,-]?"); - return $"^{regex}$"; - } + return $"^{regex}$"; } } diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs index 7ca259e8..3e07bdd9 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs @@ -13,28 +13,27 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Model.Utility +namespace AudioCuesheetEditor.Model.Utility; + +public class TimeSpanUtility { - public class TimeSpanUtility + public static TimeSpan? ParseTimeSpan(String input, TimeSpanFormat? timeSpanFormat = null) { - public static TimeSpan? ParseTimeSpan(String input, TimeSpanFormat? timeSpanFormat = null) + TimeSpan? result = null; + if (String.IsNullOrEmpty(input) == false) { - TimeSpan? result = null; - if (String.IsNullOrEmpty(input) == false) + if (String.IsNullOrEmpty(timeSpanFormat?.Scheme)) { - if (String.IsNullOrEmpty(timeSpanFormat?.Scheme)) - { - if (TimeSpan.TryParse(input, out var parsed)) - { - result = parsed; - } - } - else + if (TimeSpan.TryParse(input, out var parsed)) { - result = timeSpanFormat.ParseTimeSpan(input); + result = parsed; } } - return result; + else + { + result = timeSpanFormat.ParseTimeSpan(input); + } } + return result; } } diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index c27c0c2c..5cff89f4 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -19,218 +19,212 @@ using AudioCuesheetEditor.Services.UI; using Microsoft.JSInterop; -namespace AudioCuesheetEditor.Services.Audio +namespace AudioCuesheetEditor.Services.Audio; + +public class PlaybackService(IJSRuntime jsRuntime, ISessionStateContainer sessionStateContainer, IAudiofileManager audiofileManager) : IAsyncDisposable { - public class PlaybackService(IJSRuntime jsRuntime, ISessionStateContainer sessionStateContainer, IAudiofileManager audiofileManager) : IAsyncDisposable - { - private readonly IJSRuntime _jsRuntime = jsRuntime; - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private readonly IAudiofileManager _audiofileManager = audiofileManager; + readonly IJSRuntime _jsRuntime = jsRuntime; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly IAudiofileManager _audiofileManager = audiofileManager; - private Audiofile? _currentlyPlayingAudiofile; - private Timer? _updateTimer; - private readonly Lock _timerLock = new(); - private TimeSpan? _currentPosition; - private DotNetObjectReference<PlaybackService>? _dotNetObjectReference; - private TimeSpan _durationBeforeCurrentlyPlayingAudiofile; + Audiofile? _currentlyPlayingAudiofile; + Timer? _updateTimer; + readonly Lock _timerLock = new(); + TimeSpan? _currentPosition; + DotNetObjectReference<PlaybackService>? _dotNetObjectReference; + TimeSpan _durationBeforeCurrentlyPlayingAudiofile; - public event Action? CurrentPositionChanged; + public event Action? CurrentPositionChanged; - public TimeSpan? CurrentPosition + public TimeSpan? CurrentPosition + { + get => _currentPosition; + private set { - get => _currentPosition; - private set + if (_currentPosition != value) { - if (_currentPosition != value) - { - _currentPosition = value; - CurrentPositionChanged?.Invoke(); - } + _currentPosition = value; + CurrentPositionChanged?.Invoke(); } } - public Track? CurrentlyPlayingTrack => _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).SingleOrDefault(x => x.Begin.HasValue == true && x.End.HasValue == true && x.Begin <= CurrentPosition && x.End > CurrentPosition); - public TimeSpan? TotalTime + } + public Track? CurrentlyPlayingTrack => _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).SingleOrDefault(x => x.Begin.HasValue == true && x.End.HasValue == true && x.Begin <= CurrentPosition && x.End > CurrentPosition); + public TimeSpan? TotalTime + { + get { - get + var durations = _sessionStateContainer.Cuesheet.Audiofiles.Where(a => a.Duration.HasValue).Select(x => x.Duration); + if (durations.Any()) { - var durations = _sessionStateContainer.Cuesheet.Audiofiles.Where(a => a.Duration.HasValue).Select(x => x.Duration); - if (durations.Any()) - { - return durations.Aggregate((sum, a) => sum + a); - } - return null; + return durations.Aggregate((sum, a) => sum + a); } + return null; } - public Boolean IsPaused { get; private set; } = false; - public Boolean IsPlaybackPossible => _sessionStateContainer.Cuesheet.Audiofiles.Any(x => string.IsNullOrEmpty(x.ObjectURL) == false); - public Boolean IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; - public Boolean IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; - public Boolean IsPlaying => _currentlyPlayingAudiofile != null; + } + public Boolean IsPaused { get; private set; } = false; + public Boolean IsPlaybackPossible => _sessionStateContainer.Cuesheet.Audiofiles.Any(x => string.IsNullOrEmpty(x.ObjectURL) == false); + public Boolean IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; + public Boolean IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; + public Boolean IsPlaying => _currentlyPlayingAudiofile != null; - public async Task InitializeAsync() + public async Task InitializeAsync() + { + if (_dotNetObjectReference == null) { - if (_dotNetObjectReference == null) - { - _dotNetObjectReference = DotNetObjectReference.Create(this); - await _jsRuntime.InvokeVoidAsync("audioInterop.register", _dotNetObjectReference); - } - _audiofileManager.AudiofileChanged += AudiofileManager_AudiofileChanged; - _sessionStateContainer.CuesheetChanged += SessionStateContainer_CuesheetChanged; + _dotNetObjectReference = DotNetObjectReference.Create(this); + await _jsRuntime.InvokeVoidAsync("audioInterop.register", _dotNetObjectReference); } + _audiofileManager.AudiofileChanged += AudiofileManager_AudiofileChanged; + _sessionStateContainer.CuesheetChanged += SessionStateContainer_CuesheetChanged; + } - void AudiofileManager_AudiofileChanged(object? sender, Audiofile audiofile) + void AudiofileManager_AudiofileChanged(object? sender, Audiofile audiofile) + { + if (audiofile == _currentlyPlayingAudiofile) { - if (audiofile == _currentlyPlayingAudiofile) + if (string.IsNullOrEmpty(audiofile.ObjectURL)) { - if (string.IsNullOrEmpty(audiofile.ObjectURL)) - { - _ = StopAsync(); - } + _ = StopAsync(); } } + } - void SessionStateContainer_CuesheetChanged(object? sender, EventArgs e) - { - _ = StopAsync(); - CurrentPositionChanged?.Invoke(); - } + void SessionStateContainer_CuesheetChanged(object? sender, EventArgs e) + { + _ = StopAsync(); + CurrentPositionChanged?.Invoke(); + } - public async Task PlayOrPauseAsync() + public async Task PlayOrPauseAsync() + { + if (_currentlyPlayingAudiofile != null) { - if (_currentlyPlayingAudiofile != null) + if (IsPaused == false) { - if (IsPaused == false) - { - await _jsRuntime.InvokeVoidAsync("audioInterop.pauseAudio"); - } - else - { - await _jsRuntime.InvokeVoidAsync("audioInterop.playAudio"); - } + await _jsRuntime.InvokeVoidAsync("audioInterop.pauseAudio"); } else { - var audiofileToPlay = _sessionStateContainer.Cuesheet.Audiofiles.FirstOrDefault(x => string.IsNullOrEmpty(x.ObjectURL) == false); - if (audiofileToPlay != null) - { - await PlayAsync(audiofileToPlay); - } + await _jsRuntime.InvokeVoidAsync("audioInterop.playAudio"); } } - - public async Task PlayAsync(Track trackToPlay) + else { - if (trackToPlay?.Begin.HasValue == true) + var audiofileToPlay = _sessionStateContainer.Cuesheet.Audiofiles.FirstOrDefault(x => string.IsNullOrEmpty(x.ObjectURL) == false); + if (audiofileToPlay != null) { - await SeekAsync(trackToPlay.Begin.Value); + await PlayAsync(audiofileToPlay); } } + } - public async Task StopAsync() + public async Task PlayAsync(Track trackToPlay) + { + if (trackToPlay?.Begin.HasValue == true) { - Reset(); - await _jsRuntime.InvokeVoidAsync("audioInterop.stopAudio"); + await SeekAsync(trackToPlay.Begin.Value); } + } - public async Task PlayNextTrackAsync() + public async Task StopAsync() + { + Reset(); + await _jsRuntime.InvokeVoidAsync("audioInterop.stopAudio"); + } + + public async Task PlayNextTrackAsync() + { + if (CurrentlyPlayingTrack != null) { - if (CurrentlyPlayingTrack != null) + var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End); + if (trackToPlay != null) { - var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End); - if (trackToPlay != null) - { - await PlayAsync(trackToPlay); - } + await PlayAsync(trackToPlay); } } + } - public async Task PlayPreviousTrackAsync() + public async Task PlayPreviousTrackAsync() + { + if (CurrentlyPlayingTrack != null) { - if (CurrentlyPlayingTrack != null) + var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin); + if (trackToPlay != null) { - var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin); - if (trackToPlay != null) - { - await PlayAsync(trackToPlay); - } + await PlayAsync(trackToPlay); } } + } - public async Task SeekAsync(TimeSpan time) - { - TimeSpan cumulativeDuration = TimeSpan.Zero; - Audiofile? targetAudiofile = null; - TimeSpan targetPositionInAudiofile = TimeSpan.Zero; + public async Task SeekAsync(TimeSpan time) + { + TimeSpan cumulativeDuration = TimeSpan.Zero; + Audiofile? targetAudiofile = null; + TimeSpan targetPositionInAudiofile = TimeSpan.Zero; - foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) + foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) + { + if (string.IsNullOrEmpty(audiofile.ObjectURL)) { - if (string.IsNullOrEmpty(audiofile.ObjectURL)) - { - continue; - } - - if (audiofile.Duration.HasValue) - { - TimeSpan nextCumulativeDuration = cumulativeDuration + audiofile.Duration.Value; - - if (time >= cumulativeDuration && time < nextCumulativeDuration) - { - targetAudiofile = audiofile; - targetPositionInAudiofile = time - cumulativeDuration; - break; - } - - cumulativeDuration = nextCumulativeDuration; - } + continue; } - if (targetAudiofile == null) + if (audiofile.Duration.HasValue) { - targetAudiofile = _sessionStateContainer.Cuesheet.Audiofiles.FirstOrDefault(x => string.IsNullOrEmpty(x.ObjectURL) == false); + TimeSpan nextCumulativeDuration = cumulativeDuration + audiofile.Duration.Value; - if (targetAudiofile == null) + if (time >= cumulativeDuration && time < nextCumulativeDuration) { - return; + targetAudiofile = audiofile; + targetPositionInAudiofile = time - cumulativeDuration; + break; } - } - if (_currentlyPlayingAudiofile != targetAudiofile) - { - await PlayAsync(targetAudiofile); + cumulativeDuration = nextCumulativeDuration; } + } + + if (targetAudiofile == null) + { + targetAudiofile = _sessionStateContainer.Cuesheet.Audiofiles.FirstOrDefault(x => string.IsNullOrEmpty(x.ObjectURL) == false); - if (IsPaused) + if (targetAudiofile == null) { - await PlayOrPauseAsync(); + return; } + } - await _jsRuntime.InvokeVoidAsync("audioInterop.seekAudio", targetPositionInAudiofile.TotalSeconds); + if (_currentlyPlayingAudiofile != targetAudiofile) + { + await PlayAsync(targetAudiofile); } - [JSInvokable] - public void OnPlaybackStarted() + if (IsPaused) { - IsPaused = false; - StartTimer(); + await PlayOrPauseAsync(); } - [JSInvokable] - public void OnPlaybackEnded(string objectUrlEnded) + await _jsRuntime.InvokeVoidAsync("audioInterop.seekAudio", targetPositionInAudiofile.TotalSeconds); + } + + [JSInvokable] + public void OnPlaybackStarted() + { + IsPaused = false; + StartTimer(); + } + + [JSInvokable] + public void OnPlaybackEnded(string objectUrlEnded) + { + var audioFileEnded = _sessionStateContainer.Cuesheet.Audiofiles.Single(x => x.ObjectURL == objectUrlEnded); + var index = _sessionStateContainer.Cuesheet.Audiofiles.IndexOf(audioFileEnded); + if (index < _sessionStateContainer.Cuesheet.Audiofiles.Count - 1) { - var audioFileEnded = _sessionStateContainer.Cuesheet.Audiofiles.Single(x => x.ObjectURL == objectUrlEnded); - var index = _sessionStateContainer.Cuesheet.Audiofiles.IndexOf(audioFileEnded); - if (index < _sessionStateContainer.Cuesheet.Audiofiles.Count - 1) + var nextAudioFile = _sessionStateContainer.Cuesheet.Audiofiles.Where(x => string.IsNullOrEmpty(x.ObjectURL) == false).Skip(index + 1).FirstOrDefault(); + if (nextAudioFile != null) { - var nextAudioFile = _sessionStateContainer.Cuesheet.Audiofiles.Where(x => string.IsNullOrEmpty(x.ObjectURL) == false).Skip(index + 1).FirstOrDefault(); - if (nextAudioFile != null) - { - _ = PlayAsync(nextAudioFile); - } - else - { - // No more audio files to play, we stop playback - Reset(); - } + _ = PlayAsync(nextAudioFile); } else { @@ -238,88 +232,93 @@ public void OnPlaybackEnded(string objectUrlEnded) Reset(); } } - - [JSInvokable] - public void OnPlaybackPaused() + else { - IsPaused = true; - StopTimer(); - UpdateCurrentPosition(); + // No more audio files to play, we stop playback + Reset(); } + } - public async ValueTask DisposeAsync() - { - GC.SuppressFinalize(this); - _audiofileManager.AudiofileChanged -= AudiofileManager_AudiofileChanged; - _sessionStateContainer.CuesheetChanged -= SessionStateContainer_CuesheetChanged; - await _jsRuntime.InvokeVoidAsync("audioInterop.unregister"); - _dotNetObjectReference?.Dispose(); - } + [JSInvokable] + public void OnPlaybackPaused() + { + IsPaused = true; + StopTimer(); + UpdateCurrentPosition(); + } - async Task PlayAsync(Audiofile audiofileToPlay) - { - await _jsRuntime.InvokeVoidAsync("audioInterop.setAudioSource", audiofileToPlay.ObjectURL); - await _jsRuntime.InvokeVoidAsync("audioInterop.playAudio"); - _currentlyPlayingAudiofile = audiofileToPlay; - _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; - } + public async ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + _audiofileManager.AudiofileChanged -= AudiofileManager_AudiofileChanged; + _sessionStateContainer.CuesheetChanged -= SessionStateContainer_CuesheetChanged; + await _jsRuntime.InvokeVoidAsync("audioInterop.unregister"); + _dotNetObjectReference?.Dispose(); + } - void Reset() - { - StopTimer(); - _currentlyPlayingAudiofile = null; - _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; - CurrentPosition = null; - IsPaused = false; - } + async Task PlayAsync(Audiofile audiofileToPlay) + { + await _jsRuntime.InvokeVoidAsync("audioInterop.setAudioSource", audiofileToPlay.ObjectURL); + await _jsRuntime.InvokeVoidAsync("audioInterop.playAudio"); + _currentlyPlayingAudiofile = audiofileToPlay; + _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; + } - void StartTimer() - { - _updateTimer ??= new Timer(UpdateCurrentPosition, null, 0, 500); - } + void Reset() + { + StopTimer(); + _currentlyPlayingAudiofile = null; + _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; + CurrentPosition = null; + IsPaused = false; + } - void StopTimer() - { - _updateTimer?.Dispose(); - _updateTimer = null; - } + void StartTimer() + { + _updateTimer ??= new Timer(UpdateCurrentPosition, null, 0, 500); + } - async void UpdateCurrentPosition(object? state = null) + void StopTimer() + { + _updateTimer?.Dispose(); + _updateTimer = null; + } + + async void UpdateCurrentPosition(object? state = null) + { + lock (_timerLock) { - lock (_timerLock) + if (IsPlaying == false) { - if (IsPlaying == false) - { - Reset(); - return; - } - else - { - SetDurationBeforeCurrentlyPlayingAudiofile(); - } + Reset(); + return; } - if (IsPlaying) + else { - var currentSecondsInCurrentlyPlayingAudiofile = await _jsRuntime.InvokeAsync<double>("audioInterop.getAudioCurrentTime"); - CurrentPosition = _durationBeforeCurrentlyPlayingAudiofile + TimeSpan.FromSeconds(currentSecondsInCurrentlyPlayingAudiofile); + SetDurationBeforeCurrentlyPlayingAudiofile(); } } + if (IsPlaying) + { + var currentSecondsInCurrentlyPlayingAudiofile = await _jsRuntime.InvokeAsync<double>("audioInterop.getAudioCurrentTime"); + CurrentPosition = _durationBeforeCurrentlyPlayingAudiofile + TimeSpan.FromSeconds(currentSecondsInCurrentlyPlayingAudiofile); + } + } - void SetDurationBeforeCurrentlyPlayingAudiofile() + void SetDurationBeforeCurrentlyPlayingAudiofile() + { + if (_currentlyPlayingAudiofile == null) { - if (_currentlyPlayingAudiofile == null) - { - return; - } - _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; - var index = _sessionStateContainer.Cuesheet.Audiofiles.IndexOf(_currentlyPlayingAudiofile); - for (int i = 0; i < index; i++) + return; + } + _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; + var index = _sessionStateContainer.Cuesheet.Audiofiles.IndexOf(_currentlyPlayingAudiofile); + for (int i = 0; i < index; i++) + { + var audiofile = _sessionStateContainer.Cuesheet.Audiofiles[i]; + if (audiofile.Duration.HasValue) { - var audiofile = _sessionStateContainer.Cuesheet.Audiofiles[i]; - if (audiofile.Duration.HasValue) - { - _durationBeforeCurrentlyPlayingAudiofile += audiofile.Duration.Value; - } + _durationBeforeCurrentlyPlayingAudiofile += audiofile.Duration.Value; } } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index 37acac4d..550f4647 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -22,238 +22,237 @@ using System.Linq.Expressions; using System.Reflection; -namespace AudioCuesheetEditor.Services.AudioCuesheet +namespace AudioCuesheetEditor.Services.AudioCuesheet; + +public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeManager traceChangeManager, IJSRuntime jsRuntime, ITrackManager trackManager, ISessionStateContainer sessionStateContainer) : IAudiofileManager { - public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeManager traceChangeManager, IJSRuntime jsRuntime, ITrackManager trackManager, ISessionStateContainer sessionStateContainer) : IAudiofileManager + readonly IFileInputManager _fileInputManager = fileInputManager; + readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + readonly IJSRuntime _jsRuntime = jsRuntime; + readonly ITrackManager _trackManager = trackManager; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + + /// <inheritdoc/> + public event EventHandler<Audiofile>? AudiofileChanged; + + /// <inheritdoc/> + public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile) { - private readonly IFileInputManager _fileInputManager = fileInputManager; - private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; - private readonly IJSRuntime _jsRuntime = jsRuntime; - private readonly ITrackManager _trackManager = trackManager; - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - - /// <inheritdoc/> - public event EventHandler<Audiofile>? AudiofileChanged; + _traceChangeManager.BulkEdit = true; + if (String.IsNullOrEmpty(audiofile.ObjectURL) == false) + { + await ClearPropertiesAsync(audiofile, false); + } + var codec = _fileInputManager.GetAudioCodec(browserFile.Name, browserFile.ContentType); + var objectUrl = await _fileInputManager.GetObjectUrlAsync(browserFile); + TimeSpan? duration = null; + if (String.IsNullOrEmpty(objectUrl) == false) + { + var durationSeconds = await _jsRuntime.InvokeAsync<double>("getAudioDurationFromFile", objectUrl); + duration = TimeSpan.FromSeconds(durationSeconds); + } + var codecChanged = SetValue(audiofile, x => x.AudioCodec, codec); + var nameChanged = SetValue(audiofile, x => x.Name, browserFile.Name); + var objectUrlChanged = SetValue(audiofile, x => x.ObjectURL, objectUrl); + var durationChanged = SetValue(audiofile, x => x.Duration, duration); + SetLastTrackEnd(audiofile); + _traceChangeManager.BulkEdit = false; + if (codecChanged || nameChanged || objectUrlChanged || durationChanged) + { + AudiofileChanged?.Invoke(this, audiofile); + } + } - /// <inheritdoc/> - public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile) + /// <inheritdoc/> + public async Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true) + { + if (setTracing) { _traceChangeManager.BulkEdit = true; - if (String.IsNullOrEmpty(audiofile.ObjectURL) == false) - { - await ClearPropertiesAsync(audiofile, false); - } - var codec = _fileInputManager.GetAudioCodec(browserFile.Name, browserFile.ContentType); - var objectUrl = await _fileInputManager.GetObjectUrlAsync(browserFile); - TimeSpan? duration = null; - if (String.IsNullOrEmpty(objectUrl) == false) - { - var durationSeconds = await _jsRuntime.InvokeAsync<double>("getAudioDurationFromFile", objectUrl); - duration = TimeSpan.FromSeconds(durationSeconds); - } - var codecChanged = SetValue(audiofile, x => x.AudioCodec, codec); - var nameChanged = SetValue(audiofile, x => x.Name, browserFile.Name); - var objectUrlChanged = SetValue(audiofile, x => x.ObjectURL, objectUrl); - var durationChanged = SetValue(audiofile, x => x.Duration, duration); - SetLastTrackEnd(audiofile); + } + if (string.IsNullOrEmpty(audiofile.ObjectURL) == false) + { + await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); + } + var codecChanged = SetValue(audiofile, x => x.AudioCodec, null); + var nameChanged = SetValue(audiofile, x => x.Name, null); + var objectUrlChanged = SetValue(audiofile, x => x.ObjectURL, null); + var durationChanged = SetValue(audiofile, x => x.Duration, null); + if (setTracing) + { _traceChangeManager.BulkEdit = false; if (codecChanged || nameChanged || objectUrlChanged || durationChanged) { AudiofileChanged?.Invoke(this, audiofile); } } + } - /// <inheritdoc/> - public async Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true) + /// <inheritdoc/> + public void SetProperty<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value) + { + var changed = SetValue(audiofile, propertyExpression, value); + SetLastTrackEnd(audiofile); + if (changed) { - if (setTracing) - { - _traceChangeManager.BulkEdit = true; - } - if (string.IsNullOrEmpty(audiofile.ObjectURL) == false) - { - await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); - } - var codecChanged = SetValue(audiofile, x => x.AudioCodec, null); - var nameChanged = SetValue(audiofile, x => x.Name, null); - var objectUrlChanged = SetValue(audiofile, x => x.ObjectURL, null); - var durationChanged = SetValue(audiofile, x => x.Duration, null); - if (setTracing) - { - _traceChangeManager.BulkEdit = false; - if (codecChanged || nameChanged || objectUrlChanged || durationChanged) - { - AudiofileChanged?.Invoke(this, audiofile); - } - } + AudiofileChanged?.Invoke(this, audiofile); } + } - /// <inheritdoc/> - public void SetProperty<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value) + /// <inheritdoc/> + public void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true) + { + if (setTracing) { - var changed = SetValue(audiofile, propertyExpression, value); - SetLastTrackEnd(audiofile); - if (changed) - { - AudiofileChanged?.Invoke(this, audiofile); - } + _traceChangeManager.BulkEdit = true; + } + var cuesheet = _sessionStateContainer.ActiveCuesheet; + track.Cuesheet = cuesheet; + track.Audiofile = audiofile; + if ((cuesheet?.IsRecording == true) && cuesheet.Audiofiles.SelectMany(x => x.Tracks).Any(x => x.Position >= 1)) + { + _trackManager.SetProperty(track, x => x.Begin, DateTime.UtcNow - cuesheet.RecordingStart); + } + var lastTrack = GetLastTrack(audiofile); + if ((audiofile.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == audiofile.Duration)) + { + _trackManager.SetProperty(lastTrack, x => x.End, null); + } + var newValue = new List<Track>(audiofile.Tracks) + { + track + }; + var changed = SetValue(audiofile, x => x.Tracks, newValue); + RecalculateTrackProperties(cuesheet!); + if (setTracing) + { + _traceChangeManager.BulkEdit = false; + } + if (changed) + { + AudiofileChanged?.Invoke(this, audiofile); } + } - /// <inheritdoc/> - public void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true) + /// <inheritdoc/> + public void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, Boolean setTracing = true) + { + var cuesheet = _sessionStateContainer.ActiveCuesheet; + var intersection = audiofile.Tracks.Intersect(tracksToRemove); + foreach (var track in intersection) { - if (setTracing) - { - _traceChangeManager.BulkEdit = true; - } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - track.Cuesheet = cuesheet; - track.Audiofile = audiofile; - if ((cuesheet?.IsRecording == true) && cuesheet.Audiofiles.SelectMany(x => x.Tracks).Any(x => x.Position >= 1)) - { - _trackManager.SetProperty(track, x => x.Begin, DateTime.UtcNow - cuesheet.RecordingStart); - } - var lastTrack = GetLastTrack(audiofile); - if ((audiofile.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == audiofile.Duration)) - { - _trackManager.SetProperty(lastTrack, x => x.End, null); - } - var newValue = new List<Track>(audiofile.Tracks) - { - track - }; - var changed = SetValue(audiofile, x => x.Tracks, newValue); - RecalculateTrackProperties(cuesheet!); - if (setTracing) - { - _traceChangeManager.BulkEdit = false; - } - if (changed) - { - AudiofileChanged?.Invoke(this, audiofile); - } + track.Audiofile = null; } + ICollection<Track> newValue = [.. audiofile.Tracks.Except(intersection)]; + if (setTracing) + { + _traceChangeManager.BulkEdit = true; + } + var changed = SetValue(audiofile, x => x.Tracks, newValue); + RecalculateTrackProperties(cuesheet!); + if (setTracing) + { + _traceChangeManager.BulkEdit = false; + } + if (changed) + { + AudiofileChanged?.Invoke(this, audiofile); + } + } - /// <inheritdoc/> - public void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, Boolean setTracing = true) + Boolean SetValue<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value) + { + if (propertyExpression.Body is not MemberExpression memberExpression) { - var cuesheet = _sessionStateContainer.ActiveCuesheet; - var intersection = audiofile.Tracks.Intersect(tracksToRemove); - foreach (var track in intersection) - { - track.Audiofile = null; - } - ICollection<Track> newValue = [.. audiofile.Tracks.Except(intersection)]; - if (setTracing) - { - _traceChangeManager.BulkEdit = true; - } - var changed = SetValue(audiofile, x => x.Tracks, newValue); - RecalculateTrackProperties(cuesheet!); - if (setTracing) - { - _traceChangeManager.BulkEdit = false; - } - if (changed) - { - AudiofileChanged?.Invoke(this, audiofile); - } + throw new ArgumentException("Expression must be a property"); } - Boolean SetValue<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value) + if (memberExpression.Member is not PropertyInfo propertyInfo) { - if (propertyExpression.Body is not MemberExpression memberExpression) - { - throw new ArgumentException("Expression must be a property"); - } + throw new ArgumentException("Member is not a property"); + } - if (memberExpression.Member is not PropertyInfo propertyInfo) - { - throw new ArgumentException("Member is not a property"); - } + var previousValue = (TProperty?)propertyInfo.GetValue(audiofile); + if (Equals(previousValue, value)) + { + return false; + } - var previousValue = (TProperty?)propertyInfo.GetValue(audiofile); - if (Equals(previousValue, value)) - { - return false; - } + propertyInfo.SetValue(audiofile, value); + _traceChangeManager.AddChange(new(audiofile, new(previousValue, propertyInfo.Name))); + return true; + } - propertyInfo.SetValue(audiofile, value); - _traceChangeManager.AddChange(new(audiofile, new(previousValue, propertyInfo.Name))); - return true; + void RecalculateTrackProperties(Cuesheet cuesheet) + { + // Unset first track begin + var firstTrack = GetFirstTrack(cuesheet); + if (firstTrack?.Begin == TimeSpan.Zero) + { + _trackManager.SetProperty(firstTrack, x => x.Begin, null); } - - void RecalculateTrackProperties(Cuesheet cuesheet) + // Recalculate position, begin and end ascending + ushort position = 1; + foreach (var audiofile in cuesheet.Audiofiles) { - // Unset first track begin - var firstTrack = GetFirstTrack(cuesheet); - if (firstTrack?.Begin == TimeSpan.Zero) - { - _trackManager.SetProperty(firstTrack, x => x.Begin, null); - } - // Recalculate position, begin and end ascending - ushort position = 1; - foreach (var audiofile in cuesheet.Audiofiles) + foreach (var track in audiofile.Tracks) { - foreach (var track in audiofile.Tracks) + if (track.Position != position) { - if (track.Position != position) - { - _trackManager.SetProperty(track, x => x.Position, position); - } - var previousTrack = _trackManager.GetPreviousLinkedTrack(track); - if (previousTrack?.End.HasValue == true) - { - _trackManager.SetProperty(track, x => x.Begin, previousTrack.End); - } - else + _trackManager.SetProperty(track, x => x.Position, position); + } + var previousTrack = _trackManager.GetPreviousLinkedTrack(track); + if (previousTrack?.End.HasValue == true) + { + _trackManager.SetProperty(track, x => x.Begin, previousTrack.End); + } + else + { + if (previousTrack != null) { - if (previousTrack != null) - { - _trackManager.SetProperty(previousTrack, x => x.End, track.Begin); - } + _trackManager.SetProperty(previousTrack, x => x.End, track.Begin); } - position++; } - } - // Set first track begin - firstTrack = GetFirstTrack(cuesheet); - if (firstTrack?.Begin.HasValue == false) - { - _trackManager.SetProperty(firstTrack, x => x.Begin, TimeSpan.Zero); - } - // Set track ends based on audiofile duration - foreach (var audiofile in cuesheet.Audiofiles) - { - SetLastTrackEnd(audiofile); + position++; } } - - static Track? GetLastTrack(Audiofile audiofile) + // Set first track begin + firstTrack = GetFirstTrack(cuesheet); + if (firstTrack?.Begin.HasValue == false) { - return audiofile.Tracks.OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) - .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) - .LastOrDefault(); + _trackManager.SetProperty(firstTrack, x => x.Begin, TimeSpan.Zero); } - - void SetLastTrackEnd(Audiofile audiofile) + // Set track ends based on audiofile duration + foreach (var audiofile in cuesheet.Audiofiles) { - var lastTrack = GetLastTrack(audiofile); - if ((lastTrack?.End.HasValue == false) && (audiofile.Duration.HasValue == true)) - { - _trackManager.SetProperty(lastTrack, x => x.End, audiofile.Duration); - } + SetLastTrackEnd(audiofile); } + } - static Track? GetFirstTrack(Cuesheet cuesheet) + static Track? GetLastTrack(Audiofile audiofile) + { + return audiofile.Tracks.OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) + .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) + .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .LastOrDefault(); + } + + void SetLastTrackEnd(Audiofile audiofile) + { + var lastTrack = GetLastTrack(audiofile); + if ((lastTrack?.End.HasValue == false) && (audiofile.Duration.HasValue == true)) { - return cuesheet.Audiofiles.SelectMany(x => x.Tracks) - .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) - .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) - .FirstOrDefault(); + _trackManager.SetProperty(lastTrack, x => x.End, audiofile.Duration); } + } + static Track? GetFirstTrack(Cuesheet cuesheet) + { + return cuesheet.Audiofiles.SelectMany(x => x.Tracks) + .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) + .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) + .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .FirstOrDefault(); } + } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs index 6333479a..8acfcd7f 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs @@ -20,358 +20,357 @@ using System.Linq.Expressions; using System.Reflection; -namespace AudioCuesheetEditor.Services.AudioCuesheet +namespace AudioCuesheetEditor.Services.AudioCuesheet; + +/// <inheritdoc/> +public class CuesheetManager(ITraceChangeManager traceChangeManager, ISessionStateContainer sessionStateContainer, ITrackManager trackManager, IAudiofileManager audiofileManager, IJSRuntime jsRuntime) : ICuesheetManager { + readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly ITrackManager _trackManager = trackManager; + readonly IAudiofileManager _audiofileManager = audiofileManager; + readonly IJSRuntime _jsRuntime = jsRuntime; + + public event EventHandler? IsRecordingChanged; + /// <inheritdoc/> - public class CuesheetManager(ITraceChangeManager traceChangeManager, ISessionStateContainer sessionStateContainer, ITrackManager trackManager, IAudiofileManager audiofileManager, IJSRuntime jsRuntime) : ICuesheetManager + public void SetProperty<TProperty>(Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value) { - private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private readonly ITrackManager _trackManager = trackManager; - private readonly IAudiofileManager _audiofileManager = audiofileManager; - private readonly IJSRuntime _jsRuntime = jsRuntime; - - public event EventHandler? IsRecordingChanged; + var workingOnCuesheet = _sessionStateContainer.ActiveCuesheet == _sessionStateContainer.Cuesheet; + if (workingOnCuesheet) + { + _traceChangeManager.BulkEdit = true; + } + var cuesheet = _sessionStateContainer.ActiveCuesheet; + SetValue(cuesheet!, propertyExpression, value, workingOnCuesheet); + if (workingOnCuesheet) + { + _traceChangeManager.BulkEdit = false; + } + } - /// <inheritdoc/> - public void SetProperty<TProperty>(Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value) + /// <inheritdoc/> + public Result IsRecordingPossible + { + get { - var workingOnCuesheet = _sessionStateContainer.ActiveCuesheet == _sessionStateContainer.Cuesheet; - if (workingOnCuesheet) + if (_sessionStateContainer.Cuesheet.IsRecording == true) { - _traceChangeManager.BulkEdit = true; + return Result.Failure(new Error(ErrorType.NotPossible, "Record is already running!")); } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - SetValue(cuesheet!, propertyExpression, value, workingOnCuesheet); - if (workingOnCuesheet) + if (_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Any()) { - _traceChangeManager.BulkEdit = false; + return Result.Failure(new Error(ErrorType.NotPossible, "Cuesheet already contains tracks!")); } + return Result.Success(); } + } - /// <inheritdoc/> - public Result IsRecordingPossible + /// <inheritdoc/> + public Result StartRecording() + { + var isRecordingPossibleResult = IsRecordingPossible; + if (isRecordingPossibleResult.IsSuccess) { - get + var cuesheet = _sessionStateContainer.Cuesheet; + if (cuesheet.IsRecording == true) { - if (_sessionStateContainer.Cuesheet.IsRecording == true) - { - return Result.Failure(new Error(ErrorType.NotPossible, "Record is already running!")); - } - if (_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Any()) - { - return Result.Failure(new Error(ErrorType.NotPossible, "Cuesheet already contains tracks!")); - } - return Result.Success(); + return Result.Failure(new Error(ErrorType.NotPossible, "Record is already running!")); } - } - - /// <inheritdoc/> - public Result StartRecording() - { - var isRecordingPossibleResult = IsRecordingPossible; - if (isRecordingPossibleResult.IsSuccess) + cuesheet.RecordingStart = DateTime.UtcNow; + if (cuesheet.Audiofiles.Count == 0) { - var cuesheet = _sessionStateContainer.Cuesheet; - if (cuesheet.IsRecording == true) - { - return Result.Failure(new Error(ErrorType.NotPossible, "Record is already running!")); - } - cuesheet.RecordingStart = DateTime.UtcNow; - if (cuesheet.Audiofiles.Count == 0) - { - cuesheet.Audiofiles.Add(new Audiofile()); - } - IsRecordingChanged?.Invoke(this, EventArgs.Empty); - return Result.Success(); + cuesheet.Audiofiles.Add(new Audiofile()); } - return isRecordingPossibleResult; + IsRecordingChanged?.Invoke(this, EventArgs.Empty); + return Result.Success(); } + return isRecordingPossibleResult; + } - /// <inheritdoc/> - public void StopRecording() + /// <inheritdoc/> + public void StopRecording() + { + var cuesheet = _sessionStateContainer.Cuesheet; + if (cuesheet.IsRecording == true) { - var cuesheet = _sessionStateContainer.Cuesheet; - if (cuesheet.IsRecording == true) + var lastTrack = GetLastTrack(cuesheet); + if ((lastTrack != null) && cuesheet.RecordingStart.HasValue) { - var lastTrack = GetLastTrack(cuesheet); - if ((lastTrack != null) && cuesheet.RecordingStart.HasValue) - { - lastTrack.End = DateTime.UtcNow - cuesheet.RecordingStart.Value; - } - cuesheet.RecordingStart = null; - IsRecordingChanged?.Invoke(this, EventArgs.Empty); + lastTrack.End = DateTime.UtcNow - cuesheet.RecordingStart.Value; } + cuesheet.RecordingStart = null; + IsRecordingChanged?.Invoke(this, EventArgs.Empty); } + } - /// <inheritdoc/> - public bool IsMoveUpPossible(HashSet<Track> selectedTracks) => selectedTracks.Count > 0 && selectedTracks.Min(x => x.Position) >= 2; + /// <inheritdoc/> + public bool IsMoveUpPossible(HashSet<Track> selectedTracks) => selectedTracks.Count > 0 && selectedTracks.Min(x => x.Position) >= 2; - /// <inheritdoc/> - public bool IsMoveUpPossible(HashSet<Audiofile> selectedAudiofiles) + /// <inheritdoc/> + public bool IsMoveUpPossible(HashSet<Audiofile> selectedAudiofiles) + { + if (selectedAudiofiles.Count == 0) { - if (selectedAudiofiles.Count == 0) - { - return false; - } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - if (cuesheet?.Audiofiles.Count > 0) - { - return !selectedAudiofiles.Contains(cuesheet.Audiofiles.First()); - } return false; } + var cuesheet = _sessionStateContainer.ActiveCuesheet; + if (cuesheet?.Audiofiles.Count > 0) + { + return !selectedAudiofiles.Contains(cuesheet.Audiofiles.First()); + } + return false; + } - /// <inheritdoc/> - public bool IsMoveDownPossible(HashSet<Track> selectedTracks) => selectedTracks.Count > 0 && selectedTracks.Max(x => x.Position) < _sessionStateContainer.ActiveCuesheet?.Audiofiles.SelectMany(x => x.Tracks).Max(x => x.Position); + /// <inheritdoc/> + public bool IsMoveDownPossible(HashSet<Track> selectedTracks) => selectedTracks.Count > 0 && selectedTracks.Max(x => x.Position) < _sessionStateContainer.ActiveCuesheet?.Audiofiles.SelectMany(x => x.Tracks).Max(x => x.Position); - /// <inheritdoc/> - public bool IsMoveDownPossible(HashSet<Audiofile> selectedAudiofiles) + /// <inheritdoc/> + public bool IsMoveDownPossible(HashSet<Audiofile> selectedAudiofiles) + { + if (selectedAudiofiles.Count == 0) { - if (selectedAudiofiles.Count == 0) - { - return false; - } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - if (cuesheet?.Audiofiles.Count > 0) - { - return !selectedAudiofiles.Contains(cuesheet.Audiofiles.Last()); - } return false; } + var cuesheet = _sessionStateContainer.ActiveCuesheet; + if (cuesheet?.Audiofiles.Count > 0) + { + return !selectedAudiofiles.Contains(cuesheet.Audiofiles.Last()); + } + return false; + } - /// <inheritdoc/> - public Result MoveUp(HashSet<Track> selectedTracks, uint positions = 1) + /// <inheritdoc/> + public Result MoveUp(HashSet<Track> selectedTracks, uint positions = 1) + { + if (IsMoveUpPossible(selectedTracks) == false) + { + return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks up is not possible!")); + } + _traceChangeManager.BulkEdit = true; + while (positions > 0) { if (IsMoveUpPossible(selectedTracks) == false) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks up is not possible!")); + positions = 0; + break; } - _traceChangeManager.BulkEdit = true; - while (positions > 0) + var cuesheet = _sessionStateContainer.ActiveCuesheet; + foreach (var selectedTrack in selectedTracks.OrderBy(x => x.Position)) { - if (IsMoveUpPossible(selectedTracks) == false) + var previousTrack = cuesheet?.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Position == selectedTrack.Position - 1); + if (previousTrack?.Audiofile != null && previousTrack.Audiofile != selectedTrack.Audiofile) { - positions = 0; - break; + SwitchAudiofile(selectedTrack, previousTrack.Audiofile); } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - foreach (var selectedTrack in selectedTracks.OrderBy(x => x.Position)) + else { - var previousTrack = cuesheet?.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Position == selectedTrack.Position - 1); - if (previousTrack?.Audiofile != null && previousTrack.Audiofile != selectedTrack.Audiofile) + var newBegin = previousTrack?.Begin; + var newEnd = previousTrack?.End; + if (previousTrack != null) { - SwitchAudiofile(selectedTrack, previousTrack.Audiofile); + _trackManager.SetProperty(previousTrack, x => x.Position, selectedTrack.Position); + _trackManager.SetProperty(previousTrack, x => x.Begin, selectedTrack.Begin); + _trackManager.SetProperty(previousTrack, x => x.End, selectedTrack.End); } - else - { - var newBegin = previousTrack?.Begin; - var newEnd = previousTrack?.End; - if (previousTrack != null) - { - _trackManager.SetProperty(previousTrack, x => x.Position, selectedTrack.Position); - _trackManager.SetProperty(previousTrack, x => x.Begin, selectedTrack.Begin); - _trackManager.SetProperty(previousTrack, x => x.End, selectedTrack.End); - } - _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position - 1)); - _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); - _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); - } - - } - foreach (var audiofile in cuesheet!.Audiofiles) - { - var orderedTracks = audiofile.Tracks.OrderBy(x => x.Position).ToList(); - _audiofileManager.SetProperty(audiofile, x => x.Tracks, orderedTracks); + _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position - 1)); + _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); + _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); } - positions--; + } - _traceChangeManager.BulkEdit = false; - return Result.Success(); + foreach (var audiofile in cuesheet!.Audiofiles) + { + var orderedTracks = audiofile.Tracks.OrderBy(x => x.Position).ToList(); + _audiofileManager.SetProperty(audiofile, x => x.Tracks, orderedTracks); + } + positions--; } + _traceChangeManager.BulkEdit = false; + return Result.Success(); + } - /// <inheritdoc/> - public Result MoveUp(HashSet<Audiofile> selectedAudiofiles) + /// <inheritdoc/> + public Result MoveUp(HashSet<Audiofile> selectedAudiofiles) + { + if (IsMoveUpPossible(selectedAudiofiles) == false) + { + return Result.Failure(new Error(ErrorType.NotPossible, "Moving audiofiles up is not possible!")); + } + var cuesheet = _sessionStateContainer.ActiveCuesheet; + _traceChangeManager.BulkEdit = true; + var newAudiofiles = new List<Audiofile>(cuesheet!.Audiofiles); + foreach (var audiofile in selectedAudiofiles) { - if (IsMoveUpPossible(selectedAudiofiles) == false) + var index = newAudiofiles.IndexOf(audiofile); + var previousAudiofile = newAudiofiles[index - 1]; + newAudiofiles[index] = previousAudiofile; + newAudiofiles[index - 1] = audiofile; + var previousAudiofileTracks = previousAudiofile.Tracks; + var audiofileTracks = audiofile.Tracks; + _audiofileManager.RemoveTracks(previousAudiofile, previousAudiofileTracks, false); + _audiofileManager.RemoveTracks(audiofile, audiofileTracks, false); + foreach (var track in previousAudiofileTracks) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving audiofiles up is not possible!")); + _audiofileManager.AddTrack(audiofile, track, false); } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - _traceChangeManager.BulkEdit = true; - var newAudiofiles = new List<Audiofile>(cuesheet!.Audiofiles); - foreach (var audiofile in selectedAudiofiles) + foreach (var track in audiofileTracks) { - var index = newAudiofiles.IndexOf(audiofile); - var previousAudiofile = newAudiofiles[index - 1]; - newAudiofiles[index] = previousAudiofile; - newAudiofiles[index - 1] = audiofile; - var previousAudiofileTracks = previousAudiofile.Tracks; - var audiofileTracks = audiofile.Tracks; - _audiofileManager.RemoveTracks(previousAudiofile, previousAudiofileTracks, false); - _audiofileManager.RemoveTracks(audiofile, audiofileTracks, false); - foreach (var track in previousAudiofileTracks) - { - _audiofileManager.AddTrack(audiofile, track, false); - } - foreach (var track in audiofileTracks) - { - _audiofileManager.AddTrack(previousAudiofile, track, false); - } + _audiofileManager.AddTrack(previousAudiofile, track, false); } - SetValue(cuesheet, x => x.Audiofiles, newAudiofiles); - _traceChangeManager.BulkEdit = false; - return Result.Success(); } + SetValue(cuesheet, x => x.Audiofiles, newAudiofiles); + _traceChangeManager.BulkEdit = false; + return Result.Success(); + } - /// <inheritdoc/> - public Result MoveDown(HashSet<Track> selectedTracks, uint positions = 1) + /// <inheritdoc/> + public Result MoveDown(HashSet<Track> selectedTracks, uint positions = 1) + { + if (IsMoveDownPossible(selectedTracks) == false) + { + return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks down is not possible!")); + } + _traceChangeManager.BulkEdit = true; + while (positions > 0) { if (IsMoveDownPossible(selectedTracks) == false) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks down is not possible!")); + positions = 0; + break; } - _traceChangeManager.BulkEdit = true; - while (positions > 0) + var cuesheet = _sessionStateContainer.ActiveCuesheet; + foreach (var selectedTrack in selectedTracks.OrderByDescending(x => x.Position)) { - if (IsMoveDownPossible(selectedTracks) == false) + var nextTrack = cuesheet?.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Position == selectedTrack.Position + 1); + if (nextTrack?.Audiofile != null && nextTrack.Audiofile != selectedTrack.Audiofile) { - positions = 0; - break; + SwitchAudiofile(selectedTrack, nextTrack.Audiofile); } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - foreach (var selectedTrack in selectedTracks.OrderByDescending(x => x.Position)) + else { - var nextTrack = cuesheet?.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Position == selectedTrack.Position + 1); - if (nextTrack?.Audiofile != null && nextTrack.Audiofile != selectedTrack.Audiofile) - { - SwitchAudiofile(selectedTrack, nextTrack.Audiofile); - } - else + var newBegin = nextTrack?.Begin; + var newEnd = nextTrack?.End; + if (nextTrack != null) { - var newBegin = nextTrack?.Begin; - var newEnd = nextTrack?.End; - if (nextTrack != null) - { - _trackManager.SetProperty(nextTrack, x => x.Position, selectedTrack.Position); - _trackManager.SetProperty(nextTrack, x => x.Begin, selectedTrack.Begin); - _trackManager.SetProperty(nextTrack, x => x.End, selectedTrack.End); - } - _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position + 1)); - _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); - _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); + _trackManager.SetProperty(nextTrack, x => x.Position, selectedTrack.Position); + _trackManager.SetProperty(nextTrack, x => x.Begin, selectedTrack.Begin); + _trackManager.SetProperty(nextTrack, x => x.End, selectedTrack.End); } + _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position + 1)); + _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); + _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); } - foreach (var audiofile in cuesheet!.Audiofiles) - { - var orderedTracks = audiofile.Tracks.OrderBy(x => x.Position).ToList(); - _audiofileManager.SetProperty(audiofile, x => x.Tracks, orderedTracks); - } - positions--; } - _traceChangeManager.BulkEdit = false; - return Result.Success(); + foreach (var audiofile in cuesheet!.Audiofiles) + { + var orderedTracks = audiofile.Tracks.OrderBy(x => x.Position).ToList(); + _audiofileManager.SetProperty(audiofile, x => x.Tracks, orderedTracks); + } + positions--; } + _traceChangeManager.BulkEdit = false; + return Result.Success(); + } - /// <inheritdoc/> - public Result MoveDown(HashSet<Audiofile> selectedAudiofiles) + /// <inheritdoc/> + public Result MoveDown(HashSet<Audiofile> selectedAudiofiles) + { + if (IsMoveDownPossible(selectedAudiofiles) == false) { - if (IsMoveDownPossible(selectedAudiofiles) == false) + return Result.Failure(new Error(ErrorType.NotPossible, "Moving audiofiles down is not possible!")); + } + var cuesheet = _sessionStateContainer.ActiveCuesheet; + _traceChangeManager.BulkEdit = true; + var newAudiofiles = new List<Audiofile>(cuesheet!.Audiofiles); + foreach (var audiofile in selectedAudiofiles) + { + var index = newAudiofiles.IndexOf(audiofile); + var nextAudiofile = newAudiofiles[index + 1]; + newAudiofiles[index] = nextAudiofile; + newAudiofiles[index + 1] = audiofile; + var nextAudiofileTracks = nextAudiofile.Tracks; + var audiofileTracks = audiofile.Tracks; + _audiofileManager.RemoveTracks(nextAudiofile, nextAudiofileTracks, false); + _audiofileManager.RemoveTracks(audiofile, audiofileTracks, false); + foreach (var track in nextAudiofileTracks) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving audiofiles down is not possible!")); + _audiofileManager.AddTrack(audiofile, track, false); } - var cuesheet = _sessionStateContainer.ActiveCuesheet; - _traceChangeManager.BulkEdit = true; - var newAudiofiles = new List<Audiofile>(cuesheet!.Audiofiles); - foreach (var audiofile in selectedAudiofiles) + foreach (var track in audiofileTracks) { - var index = newAudiofiles.IndexOf(audiofile); - var nextAudiofile = newAudiofiles[index + 1]; - newAudiofiles[index] = nextAudiofile; - newAudiofiles[index + 1] = audiofile; - var nextAudiofileTracks = nextAudiofile.Tracks; - var audiofileTracks = audiofile.Tracks; - _audiofileManager.RemoveTracks(nextAudiofile, nextAudiofileTracks, false); - _audiofileManager.RemoveTracks(audiofile, audiofileTracks, false); - foreach (var track in nextAudiofileTracks) - { - _audiofileManager.AddTrack(audiofile, track, false); - } - foreach (var track in audiofileTracks) - { - _audiofileManager.AddTrack(nextAudiofile, track, false); - } + _audiofileManager.AddTrack(nextAudiofile, track, false); } - SetValue(cuesheet, x => x.Audiofiles, newAudiofiles); - _traceChangeManager.BulkEdit = false; - return Result.Success(); } + SetValue(cuesheet, x => x.Audiofiles, newAudiofiles); + _traceChangeManager.BulkEdit = false; + return Result.Success(); + } - void SetValue<TProperty>(Cuesheet cuesheet, Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value, Boolean traceChanges = true) + void SetValue<TProperty>(Cuesheet cuesheet, Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value, Boolean traceChanges = true) + { + if (propertyExpression.Body is not MemberExpression memberExpression) { - if (propertyExpression.Body is not MemberExpression memberExpression) - { - throw new ArgumentException("Expression must be a property"); - } + throw new ArgumentException("Expression must be a property"); + } - if (memberExpression.Member is not PropertyInfo propertyInfo) - { - throw new ArgumentException("Member is not a property"); - } + if (memberExpression.Member is not PropertyInfo propertyInfo) + { + throw new ArgumentException("Member is not a property"); + } - var previousValue = (TProperty?)propertyInfo.GetValue(cuesheet); - if (Equals(previousValue, value)) - { - return; - } + var previousValue = (TProperty?)propertyInfo.GetValue(cuesheet); + if (Equals(previousValue, value)) + { + return; + } - propertyInfo.SetValue(cuesheet, value); - if (traceChanges) - { - _traceChangeManager.AddChange(new(cuesheet, new(previousValue, propertyInfo.Name))); - } - _ = RevokeObjectUrlOfRemovedAudiofilesAsync(cuesheet, propertyInfo, previousValue); + propertyInfo.SetValue(cuesheet, value); + if (traceChanges) + { + _traceChangeManager.AddChange(new(cuesheet, new(previousValue, propertyInfo.Name))); } + _ = RevokeObjectUrlOfRemovedAudiofilesAsync(cuesheet, propertyInfo, previousValue); + } - async Task RevokeObjectUrlOfRemovedAudiofilesAsync(Cuesheet cuesheet, PropertyInfo propertyInfo, object? previousValue) + async Task RevokeObjectUrlOfRemovedAudiofilesAsync(Cuesheet cuesheet, PropertyInfo propertyInfo, object? previousValue) + { + if (propertyInfo.Name == nameof(Cuesheet.Audiofiles)) { - if (propertyInfo.Name == nameof(Cuesheet.Audiofiles)) + var deletedAudiofiles = ((IList<Audiofile>)previousValue!).Except(cuesheet.Audiofiles); + foreach (var deletedAudiofile in deletedAudiofiles) { - var deletedAudiofiles = ((IList<Audiofile>)previousValue!).Except(cuesheet.Audiofiles); - foreach (var deletedAudiofile in deletedAudiofiles) + if (!string.IsNullOrEmpty(deletedAudiofile.ObjectURL)) { - if (!string.IsNullOrEmpty(deletedAudiofile.ObjectURL)) - { - await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", deletedAudiofile.ObjectURL); - } + await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", deletedAudiofile.ObjectURL); } } } + } - void SwitchAudiofile(Track trackToMove, Audiofile audiofileToMoveTo) + void SwitchAudiofile(Track trackToMove, Audiofile audiofileToMoveTo) + { + var currentTrackPositionAudiofile = trackToMove.Audiofile; + //Switch audiofiles without audiofilemanager since methods there capsulate much logic + var currentTrackPositionAudiofileTracks = new List<Track>(currentTrackPositionAudiofile!.Tracks); + currentTrackPositionAudiofileTracks.Remove(trackToMove); + _traceChangeManager.AddChange(new(currentTrackPositionAudiofile, new(currentTrackPositionAudiofile.Tracks, nameof(Audiofile.Tracks)))); + currentTrackPositionAudiofile.Tracks = currentTrackPositionAudiofileTracks; + var audiofileToMoveToTracks = new List<Track>(audiofileToMoveTo.Tracks) { - var currentTrackPositionAudiofile = trackToMove.Audiofile; - //Switch audiofiles without audiofilemanager since methods there capsulate much logic - var currentTrackPositionAudiofileTracks = new List<Track>(currentTrackPositionAudiofile!.Tracks); - currentTrackPositionAudiofileTracks.Remove(trackToMove); - _traceChangeManager.AddChange(new(currentTrackPositionAudiofile, new(currentTrackPositionAudiofile.Tracks, nameof(Audiofile.Tracks)))); - currentTrackPositionAudiofile.Tracks = currentTrackPositionAudiofileTracks; - var audiofileToMoveToTracks = new List<Track>(audiofileToMoveTo.Tracks) - { - trackToMove - }; - trackToMove.Audiofile = audiofileToMoveTo; - _traceChangeManager.AddChange(new(audiofileToMoveTo, new(audiofileToMoveTo.Tracks, nameof(Audiofile.Tracks)))); - audiofileToMoveTo.Tracks = audiofileToMoveToTracks; - } + trackToMove + }; + trackToMove.Audiofile = audiofileToMoveTo; + _traceChangeManager.AddChange(new(audiofileToMoveTo, new(audiofileToMoveTo.Tracks, nameof(Audiofile.Tracks)))); + audiofileToMoveTo.Tracks = audiofileToMoveToTracks; + } - static Track? GetLastTrack(Cuesheet cuesheet) - { - return cuesheet.Audiofiles.SelectMany(x => x.Tracks) - .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) - .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) - .LastOrDefault(); - } + static Track? GetLastTrack(Cuesheet cuesheet) + { + return cuesheet.Audiofiles.SelectMany(x => x.Tracks) + .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) + .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) + .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .LastOrDefault(); } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs index 6cf526cb..af6a0b1e 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs @@ -18,48 +18,47 @@ using Microsoft.AspNetCore.Components.Forms; using System.Linq.Expressions; -namespace AudioCuesheetEditor.Services.AudioCuesheet +namespace AudioCuesheetEditor.Services.AudioCuesheet; + +public interface IAudiofileManager { - public interface IAudiofileManager - { - /// <summary> - /// Event triggered when an audiofile is changed - /// </summary> - public event EventHandler<Audiofile>? AudiofileChanged; - /// <summary> - /// Set properties from a file upload - /// </summary> - /// <param name="audiofile"></param> - /// <param name="browserFile"></param> - Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile); - /// <summary> - /// Clear properties of an audiofile - /// </summary> - /// <param name="audiofile"></param> - /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> - /// <returns></returns> - Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true); - /// <summary> - /// Set property for an audio file - /// </summary> - /// <typeparam name="TProperty"></typeparam> - /// <param name="audiofile"></param> - /// <param name="propertyExpression"></param> - /// <param name="value"></param> - void SetProperty<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value); - /// <summary> - /// Adds a track to the audiofile - /// </summary> - /// <param name="audiofile"></param> - /// <param name="track"></param> - /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> - void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true); - /// <summary> - /// Remove tracks from the audiofile - /// </summary> - /// <param name="audiofile"></param> - /// <param name="tracksToRemove"></param> - /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> - void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, Boolean setTracing = true); - } + /// <summary> + /// Event triggered when an audiofile is changed + /// </summary> + event EventHandler<Audiofile>? AudiofileChanged; + /// <summary> + /// Set properties from a file upload + /// </summary> + /// <param name="audiofile"></param> + /// <param name="browserFile"></param> + Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile); + /// <summary> + /// Clear properties of an audiofile + /// </summary> + /// <param name="audiofile"></param> + /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> + /// <returns></returns> + Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true); + /// <summary> + /// Set property for an audio file + /// </summary> + /// <typeparam name="TProperty"></typeparam> + /// <param name="audiofile"></param> + /// <param name="propertyExpression"></param> + /// <param name="value"></param> + void SetProperty<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value); + /// <summary> + /// Adds a track to the audiofile + /// </summary> + /// <param name="audiofile"></param> + /// <param name="track"></param> + /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> + void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true); + /// <summary> + /// Remove tracks from the audiofile + /// </summary> + /// <param name="audiofile"></param> + /// <param name="tracksToRemove"></param> + /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> + void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, Boolean setTracing = true); } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs index 66631da8..0ddf534f 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs @@ -17,88 +17,87 @@ using AudioCuesheetEditor.Model.IO.Audio; using System.Linq.Expressions; -namespace AudioCuesheetEditor.Services.AudioCuesheet +namespace AudioCuesheetEditor.Services.AudioCuesheet; + +/// <summary> +/// Manager for cuesheet interactions +/// </summary> +public interface ICuesheetManager { /// <summary> - /// Manager for cuesheet interactions + /// Event propagated when recording on a cuesheet changes + /// </summary> + event EventHandler? IsRecordingChanged; + /// <summary> + /// Set property for cuesheet + /// </summary> + /// <typeparam name="TProperty"></typeparam> + /// <param name="propertyExpression"></param> + /// <param name="value"></param> + void SetProperty<TProperty>(Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value); + /// <summary> + /// Checks if recording for the cuesheet is possible + /// </summary> + /// <returns></returns> + Result IsRecordingPossible { get; } + /// <summary> + /// Starts recording on cuesheet + /// </summary> + /// <returns></returns> + Result StartRecording(); + /// <summary> + /// Stop recording on cuesheet + /// </summary> + /// <returns></returns> + void StopRecording(); + /// <summary> + /// Determines if moving tracks up is possible + /// </summary> + /// <param name="selectedTracks"></param> + /// <returns></returns> + Boolean IsMoveUpPossible(HashSet<Track> selectedTracks); + /// <summary> + /// Determines if moving audiofiles up is possible + /// </summary> + /// <param name="selectedAudiofiles"></param> + /// <returns></returns> + Boolean IsMoveUpPossible(HashSet<Audiofile> selectedAudiofiles); + /// <summary> + /// Determines if moving tracks down is possible + /// </summary> + /// <param name="selectedTracks"></param> + /// <returns></returns> + Boolean IsMoveDownPossible(HashSet<Track> selectedTracks); + /// <summary> + /// Determines if moving audiofiles down is possible + /// </summary> + /// <param name="selectedTracks"></param> + /// <returns></returns> + Boolean IsMoveDownPossible(HashSet<Audiofile> selectedAudiofiles); + /// <summary> + /// Moves selected tracks up + /// </summary> + /// <param name="selectedTracks"></param> + /// <param name="positions"></param> + /// <returns></returns> + Result MoveUp(HashSet<Track> selectedTracks, uint positions = 1); + /// <summary> + /// Moves selected audiofiles up + /// </summary> + /// <param name="selectedAudiofiles"></param> + /// <returns></returns> + Result MoveUp(HashSet<Audiofile> selectedAudiofiles); + /// <summary> + /// Moves selected tracks down + /// </summary> + /// <param name="selectedTracks"></param> + /// <param name="positions"></param> + /// <returns></returns> + Result MoveDown(HashSet<Track> selectedTracks, uint positions = 1); + /// <summary> + /// Moves selected audiofiles down /// </summary> - public interface ICuesheetManager - { - /// <summary> - /// Event propagated when recording on a cuesheet changes - /// </summary> - public event EventHandler? IsRecordingChanged; - /// <summary> - /// Set property for cuesheet - /// </summary> - /// <typeparam name="TProperty"></typeparam> - /// <param name="propertyExpression"></param> - /// <param name="value"></param> - void SetProperty<TProperty>(Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value); - /// <summary> - /// Checks if recording for the cuesheet is possible - /// </summary> - /// <returns></returns> - Result IsRecordingPossible { get; } - /// <summary> - /// Starts recording on cuesheet - /// </summary> - /// <returns></returns> - Result StartRecording(); - /// <summary> - /// Stop recording on cuesheet - /// </summary> - /// <returns></returns> - void StopRecording(); - /// <summary> - /// Determines if moving tracks up is possible - /// </summary> - /// <param name="selectedTracks"></param> - /// <returns></returns> - Boolean IsMoveUpPossible(HashSet<Track> selectedTracks); - /// <summary> - /// Determines if moving audiofiles up is possible - /// </summary> - /// <param name="selectedAudiofiles"></param> - /// <returns></returns> - Boolean IsMoveUpPossible(HashSet<Audiofile> selectedAudiofiles); - /// <summary> - /// Determines if moving tracks down is possible - /// </summary> - /// <param name="selectedTracks"></param> - /// <returns></returns> - Boolean IsMoveDownPossible(HashSet<Track> selectedTracks); - /// <summary> - /// Determines if moving audiofiles down is possible - /// </summary> - /// <param name="selectedTracks"></param> - /// <returns></returns> - Boolean IsMoveDownPossible(HashSet<Audiofile> selectedAudiofiles); - /// <summary> - /// Moves selected tracks up - /// </summary> - /// <param name="selectedTracks"></param> - /// <param name="positions"></param> - /// <returns></returns> - Result MoveUp(HashSet<Track> selectedTracks, uint positions = 1); - /// <summary> - /// Moves selected audiofiles up - /// </summary> - /// <param name="selectedAudiofiles"></param> - /// <returns></returns> - Result MoveUp(HashSet<Audiofile> selectedAudiofiles); - /// <summary> - /// Moves selected tracks down - /// </summary> - /// <param name="selectedTracks"></param> - /// <param name="positions"></param> - /// <returns></returns> - Result MoveDown(HashSet<Track> selectedTracks, uint positions = 1); - /// <summary> - /// Moves selected audiofiles down - /// </summary> - /// <param name="selectedAudiofiles"></param> - /// <returns></returns> - Result MoveDown(HashSet<Audiofile> selectedAudiofiles); - } + /// <param name="selectedAudiofiles"></param> + /// <returns></returns> + Result MoveDown(HashSet<Audiofile> selectedAudiofiles); } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs index fc631edd..d495030b 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs @@ -16,59 +16,58 @@ using AudioCuesheetEditor.Model.AudioCuesheet; using System.Linq.Expressions; -namespace AudioCuesheetEditor.Services.AudioCuesheet +namespace AudioCuesheetEditor.Services.AudioCuesheet; + +/// <summary> +/// Manages track interactions +/// </summary> +public interface ITrackManager { /// <summary> - /// Manages track interactions + /// Set property value for track + /// </summary> + /// <typeparam name="TProperty"></typeparam> + /// <param name="track"></param> + /// <param name="propertyExpression"></param> + /// <param name="value"></param> + void SetProperty<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value); + /// <summary> + /// Copies values from a track to another + /// </summary> + /// <param name="source"></param> + /// <param name="target"></param> + /// <param name="setIsLinkedToPreviousTrack"></param> + /// <param name="setPosition"></param> + /// <param name="setArtist"></param> + /// <param name="setTitle"></param> + /// <param name="setBegin"></param> + /// <param name="setEnd"></param> + /// <param name="setLength"></param> + /// <param name="setFlags"></param> + /// <param name="setPreGap"></param> + /// <param name="setPostGap"></param> + void CopyValues(ITrack source, Track target, Boolean setIsLinkedToPreviousTrack = true, Boolean setPosition = true, Boolean setArtist = true, Boolean setTitle = true, Boolean setBegin = true, Boolean setEnd = true, Boolean setLength = true, Boolean setFlags = true, Boolean setPreGap = true, Boolean setPostGap = true); + /// <summary> + /// Create a clone of a track + /// </summary> + /// <param name="track"></param> + /// <returns></returns> + Track Clone(ITrack track); + /// <summary> + /// Get the previous linked track of a track object + /// </summary> + /// <param name="track">Track object to get the previous link to</param> + /// <returns>Previous linked track or null (if not linked)</returns> + Track? GetPreviousLinkedTrack(Track track); + /// <summary> + /// Get next linked track that is linked to the parameter track + /// </summary> + /// <param name="track"></param> + /// <returns></returns> + Track? GetNextLinkedTrack(Track track); + /// <summary> + /// Recalculates properties of linked tracks (previous and next track) /// </summary> - public interface ITrackManager - { - /// <summary> - /// Set property value for track - /// </summary> - /// <typeparam name="TProperty"></typeparam> - /// <param name="track"></param> - /// <param name="propertyExpression"></param> - /// <param name="value"></param> - void SetProperty<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value); - /// <summary> - /// Copies values from a track to another - /// </summary> - /// <param name="source"></param> - /// <param name="target"></param> - /// <param name="setIsLinkedToPreviousTrack"></param> - /// <param name="setPosition"></param> - /// <param name="setArtist"></param> - /// <param name="setTitle"></param> - /// <param name="setBegin"></param> - /// <param name="setEnd"></param> - /// <param name="setLength"></param> - /// <param name="setFlags"></param> - /// <param name="setPreGap"></param> - /// <param name="setPostGap"></param> - void CopyValues(ITrack source, Track target, Boolean setIsLinkedToPreviousTrack = true, Boolean setPosition = true, Boolean setArtist = true, Boolean setTitle = true, Boolean setBegin = true, Boolean setEnd = true, Boolean setLength = true, Boolean setFlags = true, Boolean setPreGap = true, Boolean setPostGap = true); - /// <summary> - /// Create a clone of a track - /// </summary> - /// <param name="track"></param> - /// <returns></returns> - Track Clone(ITrack track); - /// <summary> - /// Get the previous linked track of a track object - /// </summary> - /// <param name="track">Track object to get the previous link to</param> - /// <returns>Previous linked track or null (if not linked)</returns> - Track? GetPreviousLinkedTrack(Track track); - /// <summary> - /// Get next linked track that is linked to the parameter track - /// </summary> - /// <param name="track"></param> - /// <returns></returns> - Track? GetNextLinkedTrack(Track track); - /// <summary> - /// Recalculates properties of linked tracks (previous and next track) - /// </summary> - /// <param name="track"></param> - void RecalculateLinkedTracksProperties(Track track); - } + /// <param name="track"></param> + void RecalculateLinkedTracksProperties(Track track); } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs index 9bcf0463..e7fe1aa3 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs @@ -19,182 +19,181 @@ using System.Linq.Expressions; using System.Reflection; -namespace AudioCuesheetEditor.Services.AudioCuesheet +namespace AudioCuesheetEditor.Services.AudioCuesheet; + +/// <inheritdoc/> +public class TrackManager(ITraceChangeManager traceChangeManager) : ITrackManager { + readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + /// <inheritdoc/> - public class TrackManager(ITraceChangeManager traceChangeManager) : ITrackManager + public void SetProperty<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value) { - private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + SetValue(track, propertyExpression, value); + } - /// <inheritdoc/> - public void SetProperty<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value) + /// <inheritdoc/> + public Track Clone(ITrack track) + { + Boolean setLength = true; + if (track.Begin.HasValue && track.End.HasValue) { - SetValue(track, propertyExpression, value); + setLength = false; } - - /// <inheritdoc/> - public Track Clone(ITrack track) + Audiofile? audiofile = null; + if (track is Track trackReference) { - Boolean setLength = true; - if (track.Begin.HasValue && track.End.HasValue) - { - setLength = false; - } - Audiofile? audiofile = null; - if (track is Track trackReference) - { - audiofile = trackReference.Audiofile; - } - var clone = new Track() - { - Audiofile = audiofile, - IsLinkedToPreviousTrack = track.IsLinkedToPreviousTrack, - Position = track.Position, - Artist = track.Artist, - Title = track.Title, - Begin = track.Begin, - End = track.End, - Flags = track.Flags, - PreGap = track.PreGap, - PostGap = track.PostGap - }; - if (setLength) - { - clone.Length = track.Length; - } - return clone; + audiofile = trackReference.Audiofile; } + var clone = new Track() + { + Audiofile = audiofile, + IsLinkedToPreviousTrack = track.IsLinkedToPreviousTrack, + Position = track.Position, + Artist = track.Artist, + Title = track.Title, + Begin = track.Begin, + End = track.End, + Flags = track.Flags, + PreGap = track.PreGap, + PostGap = track.PostGap + }; + if (setLength) + { + clone.Length = track.Length; + } + return clone; + } - /// <inheritdoc/> - public void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTrack = true, bool setPosition = true, bool setArtist = true, bool setTitle = true, bool setBegin = true, bool setEnd = true, bool setLength = true, bool setFlags = true, bool setPreGap = true, bool setPostGap = true) + /// <inheritdoc/> + public void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTrack = true, bool setPosition = true, bool setArtist = true, bool setTitle = true, bool setBegin = true, bool setEnd = true, bool setLength = true, bool setFlags = true, bool setPreGap = true, bool setPostGap = true) + { + if (setIsLinkedToPreviousTrack) { - if (setIsLinkedToPreviousTrack) - { - SetValue(target, x => x.IsLinkedToPreviousTrack, source.IsLinkedToPreviousTrack); - } - if (setPosition) - { - SetValue(target, x => x.Position, source.Position); - } - if (setArtist) - { - SetValue(target, x => x.Artist, source.Artist); - } - if (setTitle) - { - SetValue(target, x => x.Title, source.Title); - } - if (setBegin) - { - SetValue(target, x => x.Begin, source.Begin ); - } - if (setEnd) - { - SetValue(target, x => x.End, source.End); - } - if (setLength) - { - SetValue(target, x => x.Length, source.Length); - } - if (setFlags) - { - SetValue(target, x => x.Flags, source.Flags); - } - if (setPreGap) - { - SetValue(target, x => x.PreGap, source.PreGap); - } - if (setPostGap) - { - SetValue(target, x=> x.PostGap, source.PostGap); - } + SetValue(target, x => x.IsLinkedToPreviousTrack, source.IsLinkedToPreviousTrack); } + if (setPosition) + { + SetValue(target, x => x.Position, source.Position); + } + if (setArtist) + { + SetValue(target, x => x.Artist, source.Artist); + } + if (setTitle) + { + SetValue(target, x => x.Title, source.Title); + } + if (setBegin) + { + SetValue(target, x => x.Begin, source.Begin ); + } + if (setEnd) + { + SetValue(target, x => x.End, source.End); + } + if (setLength) + { + SetValue(target, x => x.Length, source.Length); + } + if (setFlags) + { + SetValue(target, x => x.Flags, source.Flags); + } + if (setPreGap) + { + SetValue(target, x => x.PreGap, source.PreGap); + } + if (setPostGap) + { + SetValue(target, x=> x.PostGap, source.PostGap); + } + } - /// <inheritdoc/> - public Track? GetPreviousLinkedTrack(Track track) + /// <inheritdoc/> + public Track? GetPreviousLinkedTrack(Track track) + { + if (track.IsLinkedToPreviousTrack == false) { - if (track.IsLinkedToPreviousTrack == false) - { - return null; - } - if (track.Position.HasValue && (track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Position.HasValue) == true)) - { - return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.Position == track.Position - 1 && Equals(x, track) == false); - } - if (track.Begin.HasValue) - { - return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); - } return null; } + if (track.Position.HasValue && (track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Position.HasValue) == true)) + { + return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.Position == track.Position - 1 && Equals(x, track) == false); + } + if (track.Begin.HasValue) + { + return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); + } + return null; + } - /// <inheritdoc/> - public Track? GetNextLinkedTrack(Track track) + /// <inheritdoc/> + public Track? GetNextLinkedTrack(Track track) + { + if (track.Position.HasValue && (track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Position.HasValue) == true)) { - if (track.Position.HasValue && (track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).All(x => x.Position.HasValue) == true)) - { - return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).FirstOrDefault(x => x.Position >= track.Position.Value + 1 && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); - } - if (track.End.HasValue) - { - return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).LastOrDefault(x => x.Begin <= track.End && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); - } - return null; + return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).FirstOrDefault(x => x.Position >= track.Position.Value + 1 && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); } + if (track.End.HasValue) + { + return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).LastOrDefault(x => x.Begin <= track.End && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); + } + return null; + } - /// <inheritdoc/> - public void RecalculateLinkedTracksProperties(Track track) + /// <inheritdoc/> + public void RecalculateLinkedTracksProperties(Track track) + { + if (track.Cuesheet != null) { - if (track.Cuesheet != null) + var previousTrack = GetPreviousLinkedTrack(track); + if (previousTrack != null) { - var previousTrack = GetPreviousLinkedTrack(track); - if (previousTrack != null) + if (track.Position.HasValue == false && previousTrack.Position.HasValue && (track.Position != previousTrack.Position.Value + 1)) + { + SetValue(track, x => x.Position, (ushort?)(previousTrack.Position + 1)); + } + if (previousTrack.End.HasValue && (track.Begin != previousTrack.End)) { - if (track.Position.HasValue == false && previousTrack.Position.HasValue && (track.Position != previousTrack.Position.Value + 1)) - { - SetValue(track, x => x.Position, (ushort?)(previousTrack.Position + 1)); - } - if (previousTrack.End.HasValue && (track.Begin != previousTrack.End)) - { - SetValue(track, x => x.Begin, previousTrack.End); - } - if ((previousTrack.End.HasValue == false) && track.Begin.HasValue) - { - SetValue(previousTrack, x => x.End, track.Begin); - } + SetValue(track, x => x.Begin, previousTrack.End); } - var nextTrack = GetNextLinkedTrack(track); - if (nextTrack != null) + if ((previousTrack.End.HasValue == false) && track.Begin.HasValue) { - if (track.Position.HasValue) - { - SetValue(nextTrack, x => x.Position, (ushort?)(track.Position + 1)); - } - SetValue(nextTrack, x => x.Begin, track.End); + SetValue(previousTrack, x => x.End, track.Begin); } } - } - - void SetValue<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value) - { - if (propertyExpression.Body is not MemberExpression memberExpression) + var nextTrack = GetNextLinkedTrack(track); + if (nextTrack != null) { - throw new ArgumentException("Expression must be a property"); + if (track.Position.HasValue) + { + SetValue(nextTrack, x => x.Position, (ushort?)(track.Position + 1)); + } + SetValue(nextTrack, x => x.Begin, track.End); } + } + } - if (memberExpression.Member is not PropertyInfo propertyInfo) - { - throw new ArgumentException("Member is not a property"); - } + void SetValue<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value) + { + if (propertyExpression.Body is not MemberExpression memberExpression) + { + throw new ArgumentException("Expression must be a property"); + } - var previousValue = (TProperty?)propertyInfo.GetValue(track); - if (Equals(previousValue, value)) - { - return; - } + if (memberExpression.Member is not PropertyInfo propertyInfo) + { + throw new ArgumentException("Member is not a property"); + } - propertyInfo.SetValue(track, value); - _traceChangeManager.AddChange(new(track, new(previousValue, propertyInfo.Name))); + var previousValue = (TProperty?)propertyInfo.GetValue(track); + if (Equals(previousValue, value)) + { + return; } + + propertyInfo.SetValue(track, value); + _traceChangeManager.AddChange(new(track, new(previousValue, propertyInfo.Name))); } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index bf44fb64..22475201 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -18,74 +18,73 @@ using AudioCuesheetEditor.Services.UI; using MudBlazor; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +/// <inheritdoc/> +public class AudioImportService(IDialogManager dialogManager, ISessionStateContainer sessionStateContainer, ICuesheetManager cuesheetManager) : IAudioImportService { + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly IDialogManager _dialogManager = dialogManager; + readonly ICuesheetManager _cuesheetManager = cuesheetManager; + /// <inheritdoc/> - public class AudioImportService(IDialogManager dialogManager, ISessionStateContainer sessionStateContainer, ICuesheetManager cuesheetManager) : IAudioImportService + public async Task<Boolean> MapAudioImportAsync() { - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private readonly IDialogManager _dialogManager = dialogManager; - private readonly ICuesheetManager _cuesheetManager = cuesheetManager; - - /// <inheritdoc/> - public async Task<Boolean> MapAudioImportAsync() + // Just run an import if there are audiofiles to import, otherwise this service has nothing to do + if (_sessionStateContainer.ImportAudiofiles.Count == 0) { - // Just run an import if there are audiofiles to import, otherwise this service has nothing to do - if (_sessionStateContainer.ImportAudiofiles.Count == 0) - { - return true; - } - var mappingRequired = MapImportfiles(); - var cancel = false; - if (mappingRequired) - { - cancel = await _dialogManager.ShowImportAudiofilesDialogAsync(); - } - if (cancel == false) + return true; + } + var mappingRequired = MapImportfiles(); + var cancel = false; + if (mappingRequired) + { + cancel = await _dialogManager.ShowImportAudiofilesDialogAsync(); + } + if (cancel == false) + { + var files = new List<Audiofile>(_sessionStateContainer.ActiveCuesheet!.Audiofiles); + foreach (var mapping in _sessionStateContainer.ImportAudiofileMapping.Where(x => x.Value != null)) { - var files = new List<Audiofile>(_sessionStateContainer.ActiveCuesheet!.Audiofiles); - foreach (var mapping in _sessionStateContainer.ImportAudiofileMapping.Where(x => x.Value != null)) + var audiofile = files.FirstOrDefault(x => x.Equals(mapping.Key)); + if (audiofile == null) { - var audiofile = files.FirstOrDefault(x => x.Equals(mapping.Key)); - if (audiofile == null) - { - audiofile = mapping.Key; - files.Add(audiofile); - } - audiofile.ObjectURL = mapping.Value!.ObjectURL; - audiofile.AudioCodec = mapping.Value!.AudioCodec; - audiofile.Duration = mapping.Value!.Duration; - audiofile.Name = mapping.Value!.Name; + audiofile = mapping.Key; + files.Add(audiofile); } - _cuesheetManager.SetProperty(x => x.Audiofiles, files); + audiofile.ObjectURL = mapping.Value!.ObjectURL; + audiofile.AudioCodec = mapping.Value!.AudioCodec; + audiofile.Duration = mapping.Value!.Duration; + audiofile.Name = mapping.Value!.Name; } - else - { - await _sessionStateContainer.ResetAudioImportAsync(cancel); - } - return cancel == false; + _cuesheetManager.SetProperty(x => x.Audiofiles, files); + } + else + { + await _sessionStateContainer.ResetAudioImportAsync(cancel); } + return cancel == false; + } - Boolean MapImportfiles() + Boolean MapImportfiles() + { + _sessionStateContainer.ImportAudiofileMapping.Clear(); + foreach (var audiofile in _sessionStateContainer.ActiveCuesheet!.Audiofiles) { - _sessionStateContainer.ImportAudiofileMapping.Clear(); - foreach (var audiofile in _sessionStateContainer.ActiveCuesheet!.Audiofiles) + var importAudiofile = _sessionStateContainer.ImportAudiofiles.FirstOrDefault(); + if (string.IsNullOrEmpty(audiofile.Name) || audiofile.Name == importAudiofile?.Name) { - var importAudiofile = _sessionStateContainer.ImportAudiofiles.FirstOrDefault(); - if (string.IsNullOrEmpty(audiofile.Name) || audiofile.Name == importAudiofile?.Name) + if (importAudiofile != null) { - if (importAudiofile != null) - { - _sessionStateContainer.ImportAudiofiles.Remove(importAudiofile); - _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, importAudiofile); - } - } - else - { - _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, null); + _sessionStateContainer.ImportAudiofiles.Remove(importAudiofile); + _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, importAudiofile); } } - return _sessionStateContainer.ImportAudiofiles.Count > 0; + else + { + _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, null); + } } + return _sessionStateContainer.ImportAudiofiles.Count > 0; } } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index 2879a7aa..ed42b51e 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -21,87 +21,86 @@ using Microsoft.Extensions.Localization; using System.Text; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public class CuesheetExportService(ISessionStateContainer sessionStateContainer, IStringLocalizer<ValidationMessage> localizer) { - public class CuesheetExportService(ISessionStateContainer sessionStateContainer, IStringLocalizer<ValidationMessage> localizer) - { - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private readonly IStringLocalizer<ValidationMessage> _localizer = localizer; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly IStringLocalizer<ValidationMessage> _localizer = localizer; - public Result CanGenerateExportfile(string? filename) + public Result CanGenerateExportfile(string? filename) + { + List<ValidationMessage> validationMessages = []; + var extension = Path.GetExtension(filename); + if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) { - List<ValidationMessage> validationMessages = []; - var extension = Path.GetExtension(filename); - if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) - { - validationMessages ??= []; - validationMessages.Add(new ValidationMessage("File extension is not '{0}'", FileExtensions.Cuesheet)); - } - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Validate().ValidationMessages); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); - if (validationMessages.Count != 0) - { - return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); - } - return Result.Success(); + validationMessages ??= []; + validationMessages.Add(new ValidationMessage("File extension is not '{0}'", FileExtensions.Cuesheet)); + } + validationMessages.AddRange(_sessionStateContainer.Cuesheet.Validate().ValidationMessages); + validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); + validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); + if (validationMessages.Count != 0) + { + return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); } + return Result.Success(); + } - public Result<Exportfile> GenerateExportfile(string? filename) + public Result<Exportfile> GenerateExportfile(string? filename) + { + var validationResult = CanGenerateExportfile(filename); + if (validationResult.IsSuccess == false) { - var validationResult = CanGenerateExportfile(filename); - if (validationResult.IsSuccess == false) - { - return Result<Exportfile>.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); - } - return Result<Exportfile>.Success(new Exportfile() { Name = filename!, Content = WriteCuesheet() }); + return Result<Exportfile>.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); } + return Result<Exportfile>.Success(new Exportfile() { Name = filename!, Content = WriteCuesheet() }); + } - string WriteCuesheet() + string WriteCuesheet() + { + var builder = new StringBuilder(); + if (string.IsNullOrEmpty(_sessionStateContainer.Cuesheet.Cataloguenumber) == false) { - var builder = new StringBuilder(); - if (string.IsNullOrEmpty(_sessionStateContainer.Cuesheet.Cataloguenumber) == false) - { - builder.AppendLine(string.Format("{0} {1}", CuesheetConstants.CuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber)); - } - if (_sessionStateContainer.Cuesheet.CDTextfile != null) - { - builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile.Name)); - } - builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, _sessionStateContainer.Cuesheet.Title)); - builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); - foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) + builder.AppendLine(string.Format("{0} {1}", CuesheetConstants.CuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber)); + } + if (_sessionStateContainer.Cuesheet.CDTextfile != null) + { + builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile.Name)); + } + builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, _sessionStateContainer.Cuesheet.Title)); + builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); + foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) + { + builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".",string.Empty).ToUpper())); + foreach(var track in audiofile.Tracks) { - builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".",string.Empty).ToUpper())); - foreach(var track in audiofile.Tracks) + builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position, CuesheetConstants.CuesheetTrackAudio)); + builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); + builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); + if (track.Flags.Any()) + { + builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); + } + if (track.PreGap.HasValue) + { + builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); + } + if (track.Begin.HasValue) + { + var begin = track.Begin.Value; + builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); + } + else + { + throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); + } + if (track.PostGap.HasValue) { - builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position, CuesheetConstants.CuesheetTrackAudio)); - builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); - builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); - if (track.Flags.Any()) - { - builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); - } - if (track.PreGap.HasValue) - { - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); - } - if (track.Begin.HasValue) - { - var begin = track.Begin.Value; - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); - } - else - { - throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); - } - if (track.PostGap.HasValue) - { - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); - } + builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); } } - return builder.ToString(); } + return builder.ToString(); } } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs index 8d900df1..860de309 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs @@ -19,269 +19,268 @@ using System.Text; using System.Text.RegularExpressions; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public class CuesheetImportService { - public class CuesheetImportService + public static IImportfile Analyse(string fileContent) { - public static IImportfile Analyse(string fileContent) + Importfile importfile = new() { - Importfile importfile = new() - { - FileContent = fileContent, - FileType = ImportFileType.Cuesheet - }; - try + FileContent = fileContent, + FileType = ImportFileType.Cuesheet + }; + try + { + importfile.AnalyzedCuesheet = new(); + var cuesheetArtistGroupName = "CuesheetArtist"; + var cuesheetTitleGroupName = "CuesheetTitle"; + var cuesheetFileNameGroupName = "CuesheetFileName"; + var cuesheetCDTextfileGroupName = "CuesheetCDTextfile"; + var cuesheetCatalogueNumberGroupName = "CuesheetCatalogueNumber"; + var trackArtistGroupName = "TrackArtist"; + var trackTitleGroupName = "TrackTitle"; + var trackFlagsGroupName = "TrackFlags"; + var trackPreGapGroupName = "TrackPostGap"; + var trackPostGapGroupName = "TrackPostGap"; + var trackIndex01GroupName = "TrackIndex01"; + var regexCuesheetArtist = new Regex("^" + CuesheetConstants.CuesheetArtist + " \"(?'" + cuesheetArtistGroupName + "'.{0,})\""); + var regexCuesheetTitle = new Regex("^" + CuesheetConstants.CuesheetTitle + " \"(?'" + cuesheetTitleGroupName + "'.{0,})\""); + var regexCuesheetFile = new Regex("^" + CuesheetConstants.CuesheetFileName + " \"(?'" + cuesheetFileNameGroupName + "'.{0,})\" \\w{1,}"); + var regexTrackBegin = new Regex(CuesheetConstants.CuesheetTrack + " [0-9]{1,} " + CuesheetConstants.CuesheetTrackAudio); + var regexTrackArtist = new Regex(CuesheetConstants.TrackArtist + " \"(?'" + trackArtistGroupName + "'.{0,})\""); + var regexTrackTitle = new Regex(CuesheetConstants.TrackTitle + " \"(?'" + trackTitleGroupName + "'.{0,})\""); + var regexTrackIndex = new Regex(CuesheetConstants.TrackIndex01 + "(?'" + trackIndex01GroupName + "'.{0,})"); + var regexTrackFlags = new Regex(CuesheetConstants.TrackFlags + "(?'" + trackFlagsGroupName + "'.{0,})"); + var regexTrackPreGap = new Regex(CuesheetConstants.TrackPreGap + "(?'" + trackPreGapGroupName + "'.{0,})"); + var regexTrackPostGap = new Regex(CuesheetConstants.TrackPostGap + "(?'" + trackPostGapGroupName + "'.{0,})"); + var regexCDTextfile = new Regex("^" + CuesheetConstants.CuesheetCDTextfile + " \"(?'" + cuesheetCDTextfileGroupName + "'.{0,})\""); + var regexCatalogueNumber = new Regex("^" + CuesheetConstants.CuesheetCatalogueNumber + " (?'" + cuesheetCatalogueNumberGroupName + "'.{0,})"); + ImportTrack? track = null; + ImportAudiofile? audiofile = null; + StringBuilder recognizedContent = new(); + foreach (var line in fileContent.Split(Environment.NewLine)) { - importfile.AnalyzedCuesheet = new(); - var cuesheetArtistGroupName = "CuesheetArtist"; - var cuesheetTitleGroupName = "CuesheetTitle"; - var cuesheetFileNameGroupName = "CuesheetFileName"; - var cuesheetCDTextfileGroupName = "CuesheetCDTextfile"; - var cuesheetCatalogueNumberGroupName = "CuesheetCatalogueNumber"; - var trackArtistGroupName = "TrackArtist"; - var trackTitleGroupName = "TrackTitle"; - var trackFlagsGroupName = "TrackFlags"; - var trackPreGapGroupName = "TrackPostGap"; - var trackPostGapGroupName = "TrackPostGap"; - var trackIndex01GroupName = "TrackIndex01"; - var regexCuesheetArtist = new Regex("^" + CuesheetConstants.CuesheetArtist + " \"(?'" + cuesheetArtistGroupName + "'.{0,})\""); - var regexCuesheetTitle = new Regex("^" + CuesheetConstants.CuesheetTitle + " \"(?'" + cuesheetTitleGroupName + "'.{0,})\""); - var regexCuesheetFile = new Regex("^" + CuesheetConstants.CuesheetFileName + " \"(?'" + cuesheetFileNameGroupName + "'.{0,})\" \\w{1,}"); - var regexTrackBegin = new Regex(CuesheetConstants.CuesheetTrack + " [0-9]{1,} " + CuesheetConstants.CuesheetTrackAudio); - var regexTrackArtist = new Regex(CuesheetConstants.TrackArtist + " \"(?'" + trackArtistGroupName + "'.{0,})\""); - var regexTrackTitle = new Regex(CuesheetConstants.TrackTitle + " \"(?'" + trackTitleGroupName + "'.{0,})\""); - var regexTrackIndex = new Regex(CuesheetConstants.TrackIndex01 + "(?'" + trackIndex01GroupName + "'.{0,})"); - var regexTrackFlags = new Regex(CuesheetConstants.TrackFlags + "(?'" + trackFlagsGroupName + "'.{0,})"); - var regexTrackPreGap = new Regex(CuesheetConstants.TrackPreGap + "(?'" + trackPreGapGroupName + "'.{0,})"); - var regexTrackPostGap = new Regex(CuesheetConstants.TrackPostGap + "(?'" + trackPostGapGroupName + "'.{0,})"); - var regexCDTextfile = new Regex("^" + CuesheetConstants.CuesheetCDTextfile + " \"(?'" + cuesheetCDTextfileGroupName + "'.{0,})\""); - var regexCatalogueNumber = new Regex("^" + CuesheetConstants.CuesheetCatalogueNumber + " (?'" + cuesheetCatalogueNumberGroupName + "'.{0,})"); - ImportTrack? track = null; - ImportAudiofile? audiofile = null; - StringBuilder recognizedContent = new(); - foreach (var line in fileContent.Split(Environment.NewLine)) + String? recognizedLine = line; + if (String.IsNullOrEmpty(line) == false) { - String? recognizedLine = line; - if (String.IsNullOrEmpty(line) == false) + if ((regexCuesheetArtist.IsMatch(line) == true) && (track == null)) { - if ((regexCuesheetArtist.IsMatch(line) == true) && (track == null)) + var match = regexCuesheetArtist.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(cuesheetArtistGroupName); + if (matchGroup != null) { - var match = regexCuesheetArtist.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(cuesheetArtistGroupName); - if (matchGroup != null) - { - var artist = matchGroup.Value; - importfile.AnalyzedCuesheet.Artist = artist; - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetArtistGroupName)); - } + var artist = matchGroup.Value; + importfile.AnalyzedCuesheet.Artist = artist; } - if ((regexCuesheetTitle.IsMatch(line) == true) && (track == null)) + else { - var match = regexCuesheetTitle.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(cuesheetTitleGroupName); - if (matchGroup != null) - { - var title = matchGroup.Value; - importfile.AnalyzedCuesheet.Title = title; - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetTitleGroupName)); - } + throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetArtistGroupName)); } - if (regexCuesheetFile.IsMatch(line) == true) + } + if ((regexCuesheetTitle.IsMatch(line) == true) && (track == null)) + { + var match = regexCuesheetTitle.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(cuesheetTitleGroupName); + if (matchGroup != null) { - var match = regexCuesheetFile.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(cuesheetFileNameGroupName); - if (matchGroup != null) - { - audiofile = new() { Name = matchGroup.Value }; - importfile.AnalyzedCuesheet.Audiofiles.Add(audiofile); - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetFileNameGroupName)); - } + var title = matchGroup.Value; + importfile.AnalyzedCuesheet.Title = title; } - if (regexCDTextfile.IsMatch(line) == true) + else { - var match = regexCDTextfile.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(cuesheetCDTextfileGroupName); - if (matchGroup != null) - { - var cdTextfile = matchGroup.Value; - importfile.AnalyzedCuesheet.CDTextfile = cdTextfile; - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetCDTextfileGroupName)); - } + throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetTitleGroupName)); } - if (regexCatalogueNumber.IsMatch(line) == true) + } + if (regexCuesheetFile.IsMatch(line) == true) + { + var match = regexCuesheetFile.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(cuesheetFileNameGroupName); + if (matchGroup != null) { - var match = regexCatalogueNumber.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(cuesheetCatalogueNumberGroupName); - if (matchGroup != null) - { - var catalogueNumber = matchGroup.Value; - importfile.AnalyzedCuesheet.Cataloguenumber = catalogueNumber; - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetCatalogueNumberGroupName)); - } + audiofile = new() { Name = matchGroup.Value }; + importfile.AnalyzedCuesheet.Audiofiles.Add(audiofile); } - if (regexTrackBegin.IsMatch(line) == true) + else { - track = new ImportTrack(); - recognizedLine = String.Format(CuesheetConstants.RecognizedMarkHTML, line); + throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetFileNameGroupName)); } - if ((regexTrackArtist.IsMatch(line) == true) && (track != null)) + } + if (regexCDTextfile.IsMatch(line) == true) + { + var match = regexCDTextfile.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(cuesheetCDTextfileGroupName); + if (matchGroup != null) { - var match = regexTrackArtist.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(trackArtistGroupName); - if (matchGroup != null) - { - var artist = matchGroup.Value; - track.Artist = artist; - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackArtistGroupName)); - } + var cdTextfile = matchGroup.Value; + importfile.AnalyzedCuesheet.CDTextfile = cdTextfile; } - if ((regexTrackTitle.IsMatch(line) == true) && (track != null)) + else { - var match = regexTrackTitle.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(trackTitleGroupName); - if (matchGroup != null) - { - var title = matchGroup.Value; - track.Title = title; - } - else - { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackTitleGroupName)); - } + throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetCDTextfileGroupName)); + } + } + if (regexCatalogueNumber.IsMatch(line) == true) + { + var match = regexCatalogueNumber.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(cuesheetCatalogueNumberGroupName); + if (matchGroup != null) + { + var catalogueNumber = matchGroup.Value; + importfile.AnalyzedCuesheet.Cataloguenumber = catalogueNumber; + } + else + { + throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetCatalogueNumberGroupName)); + } + } + if (regexTrackBegin.IsMatch(line) == true) + { + track = new ImportTrack(); + recognizedLine = String.Format(CuesheetConstants.RecognizedMarkHTML, line); + } + if ((regexTrackArtist.IsMatch(line) == true) && (track != null)) + { + var match = regexTrackArtist.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(trackArtistGroupName); + if (matchGroup != null) + { + var artist = matchGroup.Value; + track.Artist = artist; + } + else + { + throw new ArgumentException(String.Format("Group '{0}' was null!", trackArtistGroupName)); + } + } + if ((regexTrackTitle.IsMatch(line) == true) && (track != null)) + { + var match = regexTrackTitle.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(trackTitleGroupName); + if (matchGroup != null) + { + var title = matchGroup.Value; + track.Title = title; + } + else + { + throw new ArgumentException(String.Format("Group '{0}' was null!", trackTitleGroupName)); } - if (regexTrackFlags.IsMatch(line) == true) + } + if (regexTrackFlags.IsMatch(line) == true) + { + var match = regexTrackFlags.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(trackFlagsGroupName); + if (matchGroup != null) { - var match = regexTrackFlags.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(trackFlagsGroupName); - if (matchGroup != null) + var flags = matchGroup.Value; + var flagList = Flag.AvailableFlags.Where(x => flags.Contains(x.CuesheetLabel)); + if (track != null) { - var flags = matchGroup.Value; - var flagList = Flag.AvailableFlags.Where(x => flags.Contains(x.CuesheetLabel)); - if (track != null) - { - track.Flags = flagList; - } - else - { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); - } + track.Flags = flagList; } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackFlagsGroupName)); + throw new NullReferenceException(String.Format("Track was null during input {0}", line)); } } - if (regexTrackPreGap.IsMatch(line) == true) + else { - var match = regexTrackPreGap.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(trackPreGapGroupName); - if (matchGroup != null) + throw new ArgumentException(String.Format("Group '{0}' was null!", trackFlagsGroupName)); + } + } + if (regexTrackPreGap.IsMatch(line) == true) + { + var match = regexTrackPreGap.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(trackPreGapGroupName); + if (matchGroup != null) + { + var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); + var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); + var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); + if (track != null) { - var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); - var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); - var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); - if (track != null) - { - track.PreGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); - } - else - { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); - } + track.PreGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackPreGapGroupName)); + throw new NullReferenceException(String.Format("Track was null during input {0}", line)); } } - if (regexTrackIndex.IsMatch(line) == true) + else + { + throw new ArgumentException(String.Format("Group '{0}' was null!", trackPreGapGroupName)); + } + } + if (regexTrackIndex.IsMatch(line) == true) + { + var match = regexTrackIndex.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(trackIndex01GroupName); + if (matchGroup != null) { - var match = regexTrackIndex.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(trackIndex01GroupName); - if (matchGroup != null) + var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); + var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); + var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); + if (track != null) { - var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); - var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); - var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); - if (track != null) - { - track.Begin = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); - } - else - { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); - } + track.Begin = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackIndex01GroupName)); + throw new NullReferenceException(String.Format("Track was null during input {0}", line)); } - audiofile?.Tracks.Add(track); } - if (regexTrackPostGap.IsMatch(line) == true) + else { - var match = regexTrackPostGap.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); - var matchGroup = match.Groups.GetValueOrDefault(trackPostGapGroupName); - if (matchGroup != null) + throw new ArgumentException(String.Format("Group '{0}' was null!", trackIndex01GroupName)); + } + audiofile?.Tracks.Add(track); + } + if (regexTrackPostGap.IsMatch(line) == true) + { + var match = regexTrackPostGap.Match(line); + recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + var matchGroup = match.Groups.GetValueOrDefault(trackPostGapGroupName); + if (matchGroup != null) + { + var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); + var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); + var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); + if (track != null) { - var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); - var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); - var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); - if (track != null) - { - track.PostGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); - } - else - { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); - } + track.PostGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackPostGapGroupName)); + throw new NullReferenceException(String.Format("Track was null during input {0}", line)); } } + else + { + throw new ArgumentException(String.Format("Group '{0}' was null!", trackPostGapGroupName)); + } } - recognizedContent.AppendLine(recognizedLine); } - importfile.FileContentRecognized = recognizedContent.ToString().TrimEnd(Environment.NewLine.ToCharArray()); - } - catch (Exception ex) - { - importfile.AnalyseException = ex; - importfile.AnalyzedCuesheet = null; - importfile.FileContentRecognized = fileContent; + recognizedContent.AppendLine(recognizedLine); } - return importfile; + importfile.FileContentRecognized = recognizedContent.ToString().TrimEnd(Environment.NewLine.ToCharArray()); + } + catch (Exception ex) + { + importfile.AnalyseException = ex; + importfile.AnalyzedCuesheet = null; + importfile.FileContentRecognized = fileContent; } + return importfile; } } diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index 2b7a570b..be18b5ae 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -21,90 +21,89 @@ using System.Data; using System.Text; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public class ExportfileGenerator(ISessionStateContainer sessionStateContainer, IStringLocalizer<ValidationMessage> localizer) { - public class ExportfileGenerator(ISessionStateContainer sessionStateContainer, IStringLocalizer<ValidationMessage> localizer) - { - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private readonly IStringLocalizer<ValidationMessage> _localizer = localizer; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly IStringLocalizer<ValidationMessage> _localizer = localizer; - public Result CanGenerateExportfile(Exportprofile exportprofile) + public Result CanGenerateExportfile(Exportprofile exportprofile) + { + List<ValidationMessage> validationMessages = []; + validationMessages.AddRange(exportprofile.Validate().ValidationMessages); + validationMessages.AddRange(_sessionStateContainer.Cuesheet.Validate().ValidationMessages); + validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); + validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); + if (validationMessages.Count != 0) { - List<ValidationMessage> validationMessages = []; - validationMessages.AddRange(exportprofile.Validate().ValidationMessages); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Validate().ValidationMessages); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); - validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); - if (validationMessages.Count != 0) - { - return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); - } - return Result.Success(); + return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); } + return Result.Success(); + } - public Result<Exportfile> GenerateExportfile(Exportprofile exportprofile) + public Result<Exportfile> GenerateExportfile(Exportprofile exportprofile) + { + var validationResult = CanGenerateExportfile(exportprofile); + if (validationResult.IsSuccess == false) { - var validationResult = CanGenerateExportfile(exportprofile); - if (validationResult.IsSuccess == false) - { - return Result<Exportfile>.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); - } - return Result<Exportfile>.Success(new Exportfile() { Name = exportprofile.Filename, Content = WriteExport(exportprofile) }); + return Result<Exportfile>.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); } + return Result<Exportfile>.Success(new Exportfile() { Name = exportprofile.Filename, Content = WriteExport(exportprofile) }); + } - private string WriteExport(Exportprofile exportprofile) + string WriteExport(Exportprofile exportprofile) + { + var builder = new StringBuilder(); + if (exportprofile != null) { - var builder = new StringBuilder(); - if (exportprofile != null) + var header = exportprofile.SchemeHead + .Replace(Exportprofile.SchemeCuesheetArtist, _sessionStateContainer.Cuesheet.Artist) + .Replace(Exportprofile.SchemeCuesheetTitle, _sessionStateContainer.Cuesheet.Title) + .Replace(Exportprofile.SchemeCuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile?.Name) + .Replace(Exportprofile.SchemeCuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber) + .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) + .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); + builder.AppendLine(header); + foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) { - var header = exportprofile.SchemeHead - .Replace(Exportprofile.SchemeCuesheetArtist, _sessionStateContainer.Cuesheet.Artist) - .Replace(Exportprofile.SchemeCuesheetTitle, _sessionStateContainer.Cuesheet.Title) - .Replace(Exportprofile.SchemeCuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile?.Name) - .Replace(Exportprofile.SchemeCuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber) - .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) - .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(header); - foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) + var audiofileLine = exportprofile.SchemeAudiofiles + .Replace(Exportprofile.SchemeAudiofileName, audiofile.Name); + builder.AppendLine(audiofileLine); + IEnumerable<Track> tracks = audiofile.Tracks.OrderBy(x => x.Position); + if (tracks.Any()) { - var audiofileLine = exportprofile.SchemeAudiofiles - .Replace(Exportprofile.SchemeAudiofileName, audiofile.Name); - builder.AppendLine(audiofileLine); - IEnumerable<Track> tracks = audiofile.Tracks.OrderBy(x => x.Position); - if (tracks.Any()) + foreach (var track in tracks) { - foreach (var track in tracks) - { - var trackLine = exportprofile.SchemeTracks - .Replace(Exportprofile.SchemeTrackArtist, track.Artist) - .Replace(Exportprofile.SchemeTrackTitle, track.Title) - .Replace(Exportprofile.SchemeTrackPosition, track.Position.ToString()) - .Replace(Exportprofile.SchemeTrackBegin, track.Begin.ToString()) - .Replace(Exportprofile.SchemeTrackEnd, track.End.ToString()) - .Replace(Exportprofile.SchemeTrackLength, track.Length.ToString()) - .Replace(Exportprofile.SchemeTrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))) - .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty) - .Replace(Exportprofile.SchemeTrackPostGap, track.PostGap != null ? track.PostGap.Value.ToString() : string.Empty) - .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) - .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(trackLine); - } + var trackLine = exportprofile.SchemeTracks + .Replace(Exportprofile.SchemeTrackArtist, track.Artist) + .Replace(Exportprofile.SchemeTrackTitle, track.Title) + .Replace(Exportprofile.SchemeTrackPosition, track.Position.ToString()) + .Replace(Exportprofile.SchemeTrackBegin, track.Begin.ToString()) + .Replace(Exportprofile.SchemeTrackEnd, track.End.ToString()) + .Replace(Exportprofile.SchemeTrackLength, track.Length.ToString()) + .Replace(Exportprofile.SchemeTrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))) + .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty) + .Replace(Exportprofile.SchemeTrackPostGap, track.PostGap != null ? track.PostGap.Value.ToString() : string.Empty) + .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) + .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); + builder.AppendLine(trackLine); } } - - var footer = exportprofile.SchemeFooter - .Replace(Exportprofile.SchemeCuesheetArtist, _sessionStateContainer.Cuesheet.Artist) - .Replace(Exportprofile.SchemeCuesheetTitle, _sessionStateContainer.Cuesheet.Title) - .Replace(Exportprofile.SchemeCuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile?.Name) - .Replace(Exportprofile.SchemeCuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber) - .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) - .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(footer); } - return builder.ToString(); + + var footer = exportprofile.SchemeFooter + .Replace(Exportprofile.SchemeCuesheetArtist, _sessionStateContainer.Cuesheet.Artist) + .Replace(Exportprofile.SchemeCuesheetTitle, _sessionStateContainer.Cuesheet.Title) + .Replace(Exportprofile.SchemeCuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile?.Name) + .Replace(Exportprofile.SchemeCuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber) + .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) + .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); + builder.AppendLine(footer); } + return builder.ToString(); } } diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 1ba191ab..a9f22d7e 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -19,148 +19,147 @@ using Microsoft.AspNetCore.Components.Forms; using Microsoft.JSInterop; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public class FileInputManager(IJSRuntime jsRuntime, ILogger<FileInputManager> logger) : IFileInputManager { - public class FileInputManager(IJSRuntime jsRuntime, ILogger<FileInputManager> logger) : IFileInputManager - { - private readonly IJSRuntime _jsRuntime = jsRuntime; - private readonly ILogger<FileInputManager> _logger = logger; + readonly IJSRuntime _jsRuntime = jsRuntime; + readonly ILogger<FileInputManager> _logger = logger; - public AudioCodec? GetAudioCodec(string fileName, string? fileContentType = null) + public AudioCodec? GetAudioCodec(string fileName, string? fileContentType = null) + { + AudioCodec? foundAudioCodec = null; + var extension = Path.GetExtension(fileName); + // First search with mime type and file extension + var audioCodecsFound = Audiofile.AudioCodecs.Where(x => x.MimeType.Equals(fileContentType, StringComparison.OrdinalIgnoreCase) && x.FileExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)); + if (audioCodecsFound.Count() <= 1) { - AudioCodec? foundAudioCodec = null; - var extension = Path.GetExtension(fileName); - // First search with mime type and file extension - var audioCodecsFound = Audiofile.AudioCodecs.Where(x => x.MimeType.Equals(fileContentType, StringComparison.OrdinalIgnoreCase) && x.FileExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)); - if (audioCodecsFound.Count() <= 1) - { - foundAudioCodec = audioCodecsFound.FirstOrDefault(); - } - if (foundAudioCodec == null) - { - // Second search with mime type or file extension - audioCodecsFound = Audiofile.AudioCodecs.Where(x => x.MimeType.Equals(fileContentType, StringComparison.OrdinalIgnoreCase) || x.FileExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)); - foundAudioCodec = audioCodecsFound.FirstOrDefault(); - } - return foundAudioCodec; + foundAudioCodec = audioCodecsFound.FirstOrDefault(); } - - /// <inheritdoc/> - public async Task<String> GetObjectUrlAsync(IBrowserFile browserFile) + if (foundAudioCodec == null) { - return await _jsRuntime.InvokeAsync<String>("getObjectURLFromMudFileUpload", browserFile.Name, browserFile.Size, browserFile.ContentType, browserFile.LastModified.ToUnixTimeMilliseconds()); + // Second search with mime type or file extension + audioCodecsFound = Audiofile.AudioCodecs.Where(x => x.MimeType.Equals(fileContentType, StringComparison.OrdinalIgnoreCase) || x.FileExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)); + foundAudioCodec = audioCodecsFound.FirstOrDefault(); } + return foundAudioCodec; + } + + /// <inheritdoc/> + public async Task<String> GetObjectUrlAsync(IBrowserFile browserFile) + { + return await _jsRuntime.InvokeAsync<String>("getObjectURLFromMudFileUpload", browserFile.Name, browserFile.Size, browserFile.ContentType, browserFile.LastModified.ToUnixTimeMilliseconds()); + } - public bool IsValidAudiofile(string fileName, string? fileContentType = null) + public bool IsValidAudiofile(string fileName, string? fileContentType = null) + { + return GetAudioCodec(fileName, fileContentType) != null; + } + + public bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable<string> fileExtensions) + { + if (_logger.IsEnabled(LogLevel.Debug)) { - return GetAudioCodec(fileName, fileContentType) != null; + _logger.LogDebug("CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtensions: '{fileExtensions}'", fileName, fileContentType, mimeType, fileExtensions); } - - public bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable<string> fileExtensions) + Boolean fileMimeTypeMatches = false; + if (String.IsNullOrEmpty(mimeType) == false) { - if (_logger.IsEnabled(LogLevel.Debug)) + if (String.IsNullOrEmpty(fileContentType) == false) { - _logger.LogDebug("CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtensions: '{fileExtensions}'", fileName, fileContentType, mimeType, fileExtensions); - } - Boolean fileMimeTypeMatches = false; - if (String.IsNullOrEmpty(mimeType) == false) - { - if (String.IsNullOrEmpty(fileContentType) == false) + if (mimeType.EndsWith("/*")) { - if (mimeType.EndsWith("/*")) - { - var mainType = mimeType[..^1]; - fileMimeTypeMatches = fileContentType.StartsWith(mainType, StringComparison.CurrentCultureIgnoreCase); - } - else - { - fileMimeTypeMatches = fileContentType.Equals(mimeType, StringComparison.CurrentCultureIgnoreCase); - } + var mainType = mimeType[..^1]; + fileMimeTypeMatches = fileContentType.StartsWith(mainType, StringComparison.CurrentCultureIgnoreCase); } - if ((fileMimeTypeMatches == false) && fileExtensions.Any()) + else { - //Try to find by file extension - var extension = Path.GetExtension(fileName); - fileMimeTypeMatches = fileExtensions.Any(x => x.Equals(extension, StringComparison.CurrentCultureIgnoreCase)); + fileMimeTypeMatches = fileContentType.Equals(mimeType, StringComparison.CurrentCultureIgnoreCase); } } - return fileMimeTypeMatches; - } - - public async Task<Audiofile?> CreateAudiofileAsync(FileUpload fileUpload) - { - // Check file mime type - var codec = GetAudioCodec(fileUpload.Name, fileUpload.ContentType); - Audiofile? audiofile; - if (codec != null) + if ((fileMimeTypeMatches == false) && fileExtensions.Any()) { - TimeSpan? duration = null; - if (String.IsNullOrEmpty(fileUpload.ObjectUrl) == false) - { - var durationSeconds = await _jsRuntime.InvokeAsync<double>("getAudioDurationFromFile", fileUpload.ObjectUrl); - duration = TimeSpan.FromSeconds(durationSeconds); - } - audiofile = new Audiofile(fileUpload.Name, fileUpload.ObjectUrl, codec, duration); - } - else - { - throw new ArgumentException("The audiofile provided is not of a valid type."); + //Try to find by file extension + var extension = Path.GetExtension(fileName); + fileMimeTypeMatches = fileExtensions.Any(x => x.Equals(extension, StringComparison.CurrentCultureIgnoreCase)); } - return audiofile; } + return fileMimeTypeMatches; + } - public CDTextfile? CreateCDTextfile(string? fileContentType, string fileName) + public async Task<Audiofile?> CreateAudiofileAsync(FileUpload fileUpload) + { + // Check file mime type + var codec = GetAudioCodec(fileUpload.Name, fileUpload.ContentType); + Audiofile? audiofile; + if (codec != null) { - CDTextfile? cdTextfile; - if (CheckFileMimeType(fileContentType, fileName, FileMimeTypes.Text, [FileExtensions.CDTextfile])) + TimeSpan? duration = null; + if (String.IsNullOrEmpty(fileUpload.ObjectUrl) == false) { - cdTextfile = new CDTextfile(fileName); + var durationSeconds = await _jsRuntime.InvokeAsync<double>("getAudioDurationFromFile", fileUpload.ObjectUrl); + duration = TimeSpan.FromSeconds(durationSeconds); } - else - { - throw new ArgumentException("The cdtextfile provided is not of a valid type."); - } - return cdTextfile; + audiofile = new Audiofile(fileUpload.Name, fileUpload.ObjectUrl, codec, duration); } - - /// <inheritdoc/> - public bool IsValidForImportView(string? fileContentType, string fileName) + else { - return CheckFileMimeType(fileContentType, fileName, FileMimeTypes.Text, [FileExtensions.Text, FileExtensions.HTML]); + throw new ArgumentException("The audiofile provided is not of a valid type."); } + return audiofile; + } - /// <inheritdoc/> - public async Task<string> ReadFileContentAsync(IBrowserFile browserFile) + public CDTextfile? CreateCDTextfile(string? fileContentType, string fileName) + { + CDTextfile? cdTextfile; + if (CheckFileMimeType(fileContentType, fileName, FileMimeTypes.Text, [FileExtensions.CDTextfile])) + { + cdTextfile = new CDTextfile(fileName); + } + else { - var fileContent = new StreamContent(browserFile.OpenReadStream()); - return await fileContent.ReadAsStringAsync(); + throw new ArgumentException("The cdtextfile provided is not of a valid type."); } + return cdTextfile; + } + + /// <inheritdoc/> + public bool IsValidForImportView(string? fileContentType, string fileName) + { + return CheckFileMimeType(fileContentType, fileName, FileMimeTypes.Text, [FileExtensions.Text, FileExtensions.HTML]); + } - /// <inheritdoc/> - public async Task<IEnumerable<FileUpload>> CreateFileUploadsAsync(IReadOnlyList<IBrowserFile> browserFiles) + /// <inheritdoc/> + public async Task<string> ReadFileContentAsync(IBrowserFile browserFile) + { + var fileContent = new StreamContent(browserFile.OpenReadStream()); + return await fileContent.ReadAsStringAsync(); + } + + /// <inheritdoc/> + public async Task<IEnumerable<FileUpload>> CreateFileUploadsAsync(IReadOnlyList<IBrowserFile> browserFiles) + { + List<FileUpload> fileUploads = []; + foreach (var file in browserFiles) { - List<FileUpload> fileUploads = []; - foreach (var file in browserFiles) + if (CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) + || CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) + || IsValidForImportView(file.ContentType, file.Name) + || IsValidAudiofile(file.Name, file.ContentType)) { - if (CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) - || CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) - || IsValidForImportView(file.ContentType, file.Name) - || IsValidAudiofile(file.Name, file.ContentType)) + string? content = null; + string? objectUrl = null; + if (IsValidAudiofile(file.Name, file.ContentType)) + { + objectUrl = await GetObjectUrlAsync(file); + } + else { - string? content = null; - string? objectUrl = null; - if (IsValidAudiofile(file.Name, file.ContentType)) - { - objectUrl = await GetObjectUrlAsync(file); - } - else - { - content = await ReadFileContentAsync(file); - } - fileUploads.Add(new(file.Name, file.ContentType, content, objectUrl)); + content = await ReadFileContentAsync(file); } + fileUploads.Add(new(file.Name, file.ContentType, content, objectUrl)); } - return fileUploads; } + return fileUploads; } } diff --git a/AudioCuesheetEditor/Services/IO/IAudioImportService.cs b/AudioCuesheetEditor/Services/IO/IAudioImportService.cs index f01d34b6..7f13cf45 100644 --- a/AudioCuesheetEditor/Services/IO/IAudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/IAudioImportService.cs @@ -13,17 +13,16 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +/// <summary> +/// Service for importing audio files and matching them to the cuesheet. +/// </summary> +public interface IAudioImportService { /// <summary> - /// Service for importing audio files and matching them to the cuesheet. + /// Maps the import audio from session state to the active cuesheet. If mapping is not possible automatically the user gets a dialog. /// </summary> - public interface IAudioImportService - { - /// <summary> - /// Maps the import audio from session state to the active cuesheet. If mapping is not possible automatically the user gets a dialog. - /// </summary> - /// <returns></returns> - Task<Boolean> MapAudioImportAsync(); - } + /// <returns></returns> + Task<Boolean> MapAudioImportAsync(); } diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs index 95383d55..de31b2af 100644 --- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs @@ -19,46 +19,45 @@ using AudioCuesheetEditor.Model.IO.Audio; using Microsoft.AspNetCore.Components.Forms; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public interface IFileInputManager { - public interface IFileInputManager - { - bool IsValidAudiofile(string fileName, string? fileContentType = null); - AudioCodec? GetAudioCodec(string fileName, string? fileContentType = null); - /// <summary> - /// Get object url for an IBrowserFile. - /// </summary> - /// <param name="browserFile"></param> - /// <returns></returns> - Task<String> GetObjectUrlAsync(IBrowserFile browserFile); - /// <summary> - /// Checks if a file content type and name matches given parameters - /// </summary> - /// <param name="fileContentType"></param> - /// <param name="fileName"></param> - /// <param name="mimeType"></param> - /// <param name="fileExtensions"></param> - /// <returns></returns> - bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable<string> fileExtensions); - Task<Audiofile?> CreateAudiofileAsync(FileUpload fileUpload); - CDTextfile? CreateCDTextfile(string? fileContentType, string fileName); - /// <summary> - /// Checks if the file can be used for the import view - /// </summary> - /// <param name="browserFile"></param> - /// <returns></returns> - bool IsValidForImportView(string? fileContentType, string fileName); - /// <summary> - /// Reads the browser file and gets the file content as string - /// </summary> - /// <param name="browserFile"></param> - /// <returns></returns> - Task<string> ReadFileContentAsync(IBrowserFile browserFile); - /// <summary> - /// Generates file upload references for files - /// </summary> - /// <param name="browserFiles"></param> - /// <returns></returns> - Task<IEnumerable<FileUpload>> CreateFileUploadsAsync(IReadOnlyList<IBrowserFile> browserFiles); - } + bool IsValidAudiofile(string fileName, string? fileContentType = null); + AudioCodec? GetAudioCodec(string fileName, string? fileContentType = null); + /// <summary> + /// Get object url for an IBrowserFile. + /// </summary> + /// <param name="browserFile"></param> + /// <returns></returns> + Task<String> GetObjectUrlAsync(IBrowserFile browserFile); + /// <summary> + /// Checks if a file content type and name matches given parameters + /// </summary> + /// <param name="fileContentType"></param> + /// <param name="fileName"></param> + /// <param name="mimeType"></param> + /// <param name="fileExtensions"></param> + /// <returns></returns> + bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable<string> fileExtensions); + Task<Audiofile?> CreateAudiofileAsync(FileUpload fileUpload); + CDTextfile? CreateCDTextfile(string? fileContentType, string fileName); + /// <summary> + /// Checks if the file can be used for the import view + /// </summary> + /// <param name="browserFile"></param> + /// <returns></returns> + bool IsValidForImportView(string? fileContentType, string fileName); + /// <summary> + /// Reads the browser file and gets the file content as string + /// </summary> + /// <param name="browserFile"></param> + /// <returns></returns> + Task<string> ReadFileContentAsync(IBrowserFile browserFile); + /// <summary> + /// Generates file upload references for files + /// </summary> + /// <param name="browserFiles"></param> + /// <returns></returns> + Task<IEnumerable<FileUpload>> CreateFileUploadsAsync(IReadOnlyList<IBrowserFile> browserFiles); } \ No newline at end of file diff --git a/AudioCuesheetEditor/Services/IO/ITextImportService.cs b/AudioCuesheetEditor/Services/IO/ITextImportService.cs index 3f4f31a6..5f8f4a10 100644 --- a/AudioCuesheetEditor/Services/IO/ITextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/ITextImportService.cs @@ -16,10 +16,9 @@ using AudioCuesheetEditor.Model.IO.Import; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public interface ITextImportService { - public interface ITextImportService - { - Task<IImportfile> AnalyseAsync(string fileContent); - } + Task<IImportfile> AnalyseAsync(string fileContent); } \ No newline at end of file diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 8294d69c..c8dbd9bb 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -23,298 +23,297 @@ using AudioCuesheetEditor.Services.UI; using System.Diagnostics; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public enum ImportFileType +{ + Unknown, + ProjectFile, + Cuesheet, + Textfile, + Audiofile +} +public class ImportManager(ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager, ITextImportService textImportService, ITrackManager trackManager, IAudioImportService audioImportService, ILogger<ImportManager> logger) { - public enum ImportFileType + public event EventHandler<IEnumerable<string>>? UploadFilesFinished; + + readonly ILogger<ImportManager> _logger = logger; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + readonly IFileInputManager _fileInputManager = fileInputManager; + readonly ITextImportService _textImportService = textImportService; + readonly ITrackManager _trackManager = trackManager; + readonly IAudioImportService _audioImportService = audioImportService; + + public void ImportData(String? data) { - Unknown, - ProjectFile, - Cuesheet, - Textfile, - Audiofile + var stopwatch = Stopwatch.StartNew(); + _sessionStateContainer.Importfile = new Importfile() + { + FileContent = data, + FileContentRecognized = data, + FileType = ImportFileType.Textfile + }; + stopwatch.Stop(); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("ImportData duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + } } - public class ImportManager(ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager, ITextImportService textImportService, ITrackManager trackManager, IAudioImportService audioImportService, ILogger<ImportManager> logger) + + public async Task<Boolean> AnalyseImportfile() { - public event EventHandler<IEnumerable<string>>? UploadFilesFinished; - - private readonly ILogger<ImportManager> _logger = logger; - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; - private readonly IFileInputManager _fileInputManager = fileInputManager; - private readonly ITextImportService _textImportService = textImportService; - private readonly ITrackManager _trackManager = trackManager; - private readonly IAudioImportService _audioImportService = audioImportService; - - public void ImportData(String? data) + ResetTracing(); + var stopwatch = Stopwatch.StartNew(); + var fileContent = _sessionStateContainer.Importfile?.FileContent; + if (String.IsNullOrEmpty(fileContent) == false) { - var stopwatch = Stopwatch.StartNew(); - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = data, - FileContentRecognized = data, - FileType = ImportFileType.Textfile - }; - stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) + switch (_sessionStateContainer.Importfile?.FileType) { - _logger.LogDebug("ImportData duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + case ImportFileType.ProjectFile: + var importedCuesheet = Projectfile.ImportFile(fileContent); + var previousValue = _sessionStateContainer.Cuesheet; + _sessionStateContainer.Cuesheet = importedCuesheet!; + _traceChangeManager.AddChange(new TracedChange(_sessionStateContainer, new(previousValue, nameof(SessionStateContainer.Cuesheet)))); + break; + case ImportFileType.Textfile: + _sessionStateContainer.Importfile = await _textImportService.AnalyseAsync(fileContent); + break; + case ImportFileType.Cuesheet: + _sessionStateContainer.Importfile = CuesheetImportService.Analyse(fileContent); + break; } } - - public async Task<Boolean> AnalyseImportfile() + if (_sessionStateContainer.Importfile?.AnalyzedCuesheet != null) { - ResetTracing(); - var stopwatch = Stopwatch.StartNew(); - var fileContent = _sessionStateContainer.Importfile?.FileContent; - if (String.IsNullOrEmpty(fileContent) == false) + switch (_sessionStateContainer.Importfile?.FileType) { - switch (_sessionStateContainer.Importfile?.FileType) - { - case ImportFileType.ProjectFile: - var importedCuesheet = Projectfile.ImportFile(fileContent); - var previousValue = _sessionStateContainer.Cuesheet; - _sessionStateContainer.Cuesheet = importedCuesheet!; - _traceChangeManager.AddChange(new TracedChange(_sessionStateContainer, new(previousValue, nameof(SessionStateContainer.Cuesheet)))); - break; - case ImportFileType.Textfile: - _sessionStateContainer.Importfile = await _textImportService.AnalyseAsync(fileContent); - break; - case ImportFileType.Cuesheet: - _sessionStateContainer.Importfile = CuesheetImportService.Analyse(fileContent); - break; - } + case ImportFileType.Cuesheet: + case ImportFileType.Textfile: + var importCuesheet = new Cuesheet(); + CopyCuesheet(importCuesheet, _sessionStateContainer.Importfile.AnalyzedCuesheet); + _sessionStateContainer.ImportCuesheet = importCuesheet; + break; } - if (_sessionStateContainer.Importfile?.AnalyzedCuesheet != null) - { - switch (_sessionStateContainer.Importfile?.FileType) - { - case ImportFileType.Cuesheet: - case ImportFileType.Textfile: - var importCuesheet = new Cuesheet(); - CopyCuesheet(importCuesheet, _sessionStateContainer.Importfile.AnalyzedCuesheet); - _sessionStateContainer.ImportCuesheet = importCuesheet; - break; - } - } - var cancelImport = await _audioImportService.MapAudioImportAsync(); - stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("AnalyseImportfile duration: {stopwatch.Elapsed}", stopwatch.Elapsed); - } - return cancelImport; } - - public async Task ImportCuesheetAsync() + var cancelImport = await _audioImportService.MapAudioImportAsync(); + stopwatch.Stop(); + if (_logger.IsEnabled(LogLevel.Debug)) { - var stopwatch = Stopwatch.StartNew(); - ResetTracing(); - if (_sessionStateContainer.ImportCuesheet != null) - { - var newCuesheet = new Cuesheet(); - CopyCuesheet(newCuesheet, _sessionStateContainer.ImportCuesheet); - var previousValue = _sessionStateContainer.Cuesheet; - _sessionStateContainer.Cuesheet = newCuesheet; - _traceChangeManager.AddChange(new TracedChange(_sessionStateContainer, new(previousValue, nameof(SessionStateContainer.Cuesheet)))); - } - await _sessionStateContainer.ResetImportAsync(false); - stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("ImportCuesheet duration: {stopwatch.Elapsed}", stopwatch.Elapsed); - } + _logger.LogDebug("AnalyseImportfile duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + } + return cancelImport; + } + + public async Task ImportCuesheetAsync() + { + var stopwatch = Stopwatch.StartNew(); + ResetTracing(); + if (_sessionStateContainer.ImportCuesheet != null) + { + var newCuesheet = new Cuesheet(); + CopyCuesheet(newCuesheet, _sessionStateContainer.ImportCuesheet); + var previousValue = _sessionStateContainer.Cuesheet; + _sessionStateContainer.Cuesheet = newCuesheet; + _traceChangeManager.AddChange(new TracedChange(_sessionStateContainer, new(previousValue, nameof(SessionStateContainer.Cuesheet)))); } + await _sessionStateContainer.ResetImportAsync(false); + stopwatch.Stop(); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("ImportCuesheet duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + } + } - public async Task UploadFilesAsync(IEnumerable<FileUpload> files) + public async Task UploadFilesAsync(IEnumerable<FileUpload> files) + { + var stopwatch = Stopwatch.StartNew(); + var invalidFiles = new List<string>(); + foreach (var file in files) { - var stopwatch = Stopwatch.StartNew(); - var invalidFiles = new List<string>(); - foreach (var file in files) + if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) + || _fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) + || _fileInputManager.IsValidForImportView(file.ContentType, file.Name) + || _fileInputManager.IsValidAudiofile(file.Name, file.ContentType)) { - if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) - || _fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) - || _fileInputManager.IsValidForImportView(file.ContentType, file.Name) - || _fileInputManager.IsValidAudiofile(file.Name, file.ContentType)) + if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile])) { - if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile])) + _sessionStateContainer.Importfile = new Importfile() { - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = file.Content, - FileContentRecognized = file.Content, - FileType = ImportFileType.ProjectFile - }; - } - if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet])) - { - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = file.Content, - FileContentRecognized = file.Content, - FileType = ImportFileType.Cuesheet - }; - } - if (_fileInputManager.IsValidForImportView(file.ContentType, file.Name)) + FileContent = file.Content, + FileContentRecognized = file.Content, + FileType = ImportFileType.ProjectFile + }; + } + if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet])) + { + _sessionStateContainer.Importfile = new Importfile() { - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = file.Content, - FileContentRecognized = file.Content, - FileType = ImportFileType.Textfile - }; - } - if (_fileInputManager.IsValidAudiofile(file.Name, file.ContentType)) + FileContent = file.Content, + FileContentRecognized = file.Content, + FileType = ImportFileType.Cuesheet + }; + } + if (_fileInputManager.IsValidForImportView(file.ContentType, file.Name)) + { + _sessionStateContainer.Importfile = new Importfile() { - var audioFile = await _fileInputManager.CreateAudiofileAsync(file); - if (audioFile != null) - { - _sessionStateContainer.ImportAudiofiles.Add(audioFile); - } - } + FileContent = file.Content, + FileContentRecognized = file.Content, + FileType = ImportFileType.Textfile + }; } - else + if (_fileInputManager.IsValidAudiofile(file.Name, file.ContentType)) { - invalidFiles.Add(file.Name); + var audioFile = await _fileInputManager.CreateAudiofileAsync(file); + if (audioFile != null) + { + _sessionStateContainer.ImportAudiofiles.Add(audioFile); + } } } - UploadFilesFinished?.Invoke(this, invalidFiles); - stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) + else { - _logger.LogDebug("UploadFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + invalidFiles.Add(file.Name); } } + UploadFilesFinished?.Invoke(this, invalidFiles); + stopwatch.Stop(); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("UploadFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + } + } - void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) + void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) + { + target.Artist = cuesheetToCopy.Artist; + target.Title = cuesheetToCopy.Title; + target.Cataloguenumber = cuesheetToCopy.Cataloguenumber; + IEnumerable<IAudiofile> audiofiles = []; + if (cuesheetToCopy is Cuesheet originCuesheet) { - target.Artist = cuesheetToCopy.Artist; - target.Title = cuesheetToCopy.Title; - target.Cataloguenumber = cuesheetToCopy.Cataloguenumber; - IEnumerable<IAudiofile> audiofiles = []; - if (cuesheetToCopy is Cuesheet originCuesheet) - { - target.CDTextfile = originCuesheet.CDTextfile; - audiofiles = originCuesheet.Audiofiles; - } - if (cuesheetToCopy is ImportCuesheet importCuesheet) + target.CDTextfile = originCuesheet.CDTextfile; + audiofiles = originCuesheet.Audiofiles; + } + if (cuesheetToCopy is ImportCuesheet importCuesheet) + { + if (String.IsNullOrEmpty(importCuesheet.CDTextfile) == false) { - if (String.IsNullOrEmpty(importCuesheet.CDTextfile) == false) - { - target.CDTextfile = new CDTextfile(importCuesheet.CDTextfile); - } - audiofiles = importCuesheet.Audiofiles; + target.CDTextfile = new CDTextfile(importCuesheet.CDTextfile); } - AttachClonedAudiofiles(target, audiofiles); + audiofiles = importCuesheet.Audiofiles; } + AttachClonedAudiofiles(target, audiofiles); + } - void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) + void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) + { + foreach (var audiofile in audiofiles) { - foreach (var audiofile in audiofiles) + Audiofile? targetAudiofile = null; + IEnumerable<ITrack>? tracks = null; + // Map uploaded import audiofiles by name + var importAudiofileFound = _sessionStateContainer.ImportAudiofiles.FirstOrDefault(x => x.Name == audiofile.Name); + if (importAudiofileFound != null) { - Audiofile? targetAudiofile = null; - IEnumerable<ITrack>? tracks = null; - // Map uploaded import audiofiles by name - var importAudiofileFound = _sessionStateContainer.ImportAudiofiles.FirstOrDefault(x => x.Name == audiofile.Name); - if (importAudiofileFound != null) - { - targetAudiofile = new Audiofile(importAudiofileFound.Name, importAudiofileFound.ObjectURL, importAudiofileFound.AudioCodec, importAudiofileFound.Duration); - } - if (audiofile is ImportAudiofile importAudiofile) - { - targetAudiofile ??= new Audiofile() - { - Name = importAudiofile.Name, - AudioCodec = String.IsNullOrEmpty(importAudiofile.Name) == false ? _fileInputManager.GetAudioCodec(importAudiofile.Name) : null - }; - tracks = importAudiofile.Tracks; - } - if (audiofile is Audiofile sourceAudiofile) - { - targetAudiofile ??= new Audiofile(sourceAudiofile.Name, sourceAudiofile.ObjectURL, sourceAudiofile.AudioCodec, sourceAudiofile.Duration); - tracks = sourceAudiofile.Tracks; - } - if (targetAudiofile == null || tracks == null) - { - throw new NullReferenceException(); - } - IOrderedEnumerable<ITrack> sortedTracks; - if (tracks.All(x => x.Position.HasValue)) - { - sortedTracks = tracks.OrderBy(x => x.Position); - } - else - { - sortedTracks = tracks.OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position); - } - if (sortedTracks.All(x => x.Begin.HasValue)) + targetAudiofile = new Audiofile(importAudiofileFound.Name, importAudiofileFound.ObjectURL, importAudiofileFound.AudioCodec, importAudiofileFound.Duration); + } + if (audiofile is ImportAudiofile importAudiofile) + { + targetAudiofile ??= new Audiofile() { - sortedTracks = sortedTracks.ThenBy(x => x.Begin); - } - else + Name = importAudiofile.Name, + AudioCodec = String.IsNullOrEmpty(importAudiofile.Name) == false ? _fileInputManager.GetAudioCodec(importAudiofile.Name) : null + }; + tracks = importAudiofile.Tracks; + } + if (audiofile is Audiofile sourceAudiofile) + { + targetAudiofile ??= new Audiofile(sourceAudiofile.Name, sourceAudiofile.ObjectURL, sourceAudiofile.AudioCodec, sourceAudiofile.Duration); + tracks = sourceAudiofile.Tracks; + } + if (targetAudiofile == null || tracks == null) + { + throw new NullReferenceException(); + } + IOrderedEnumerable<ITrack> sortedTracks; + if (tracks.All(x => x.Position.HasValue)) + { + sortedTracks = tracks.OrderBy(x => x.Position); + } + else + { + sortedTracks = tracks.OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position); + } + if (sortedTracks.All(x => x.Begin.HasValue)) + { + sortedTracks = sortedTracks.ThenBy(x => x.Begin); + } + else + { + sortedTracks = sortedTracks.ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin); + } + if (sortedTracks.All(x => x.End.HasValue)) + { + sortedTracks = sortedTracks.ThenBy(x => x.End); + } + else + { + sortedTracks = sortedTracks.ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End); + } + TimeSpan? begin = TimeSpan.Zero; + ushort position = 1; + for (int i = 0; i < sortedTracks.Count(); i++) + { + var track = sortedTracks.ElementAt(i); + ITrack? nextTrack = null; + if (i < sortedTracks.Count() - 1) { - sortedTracks = sortedTracks.ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin); + nextTrack = sortedTracks.ElementAt(i + 1); } - if (sortedTracks.All(x => x.End.HasValue)) + var clone = _trackManager.Clone(track); + clone.Cuesheet = target; + clone.Audiofile = targetAudiofile; + // Special treatment for StartDateTime of ImportTrack + if (track is ImportTrack importTrack && importTrack.StartDateTime != null && nextTrack is ImportTrack nextImportTrack) { - sortedTracks = sortedTracks.ThenBy(x => x.End); + var length = nextImportTrack.StartDateTime - importTrack.StartDateTime; + clone.Begin = begin; + clone.End = begin + length; } - else + // Calculate properties + if (clone.Position.HasValue == false) { - sortedTracks = sortedTracks.ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End); + clone.Position = position; } - TimeSpan? begin = TimeSpan.Zero; - ushort position = 1; - for (int i = 0; i < sortedTracks.Count(); i++) + if (clone.Begin.HasValue == false) { - var track = sortedTracks.ElementAt(i); - ITrack? nextTrack = null; - if (i < sortedTracks.Count() - 1) - { - nextTrack = sortedTracks.ElementAt(i + 1); - } - var clone = _trackManager.Clone(track); - clone.Cuesheet = target; - clone.Audiofile = targetAudiofile; - // Special treatment for StartDateTime of ImportTrack - if (track is ImportTrack importTrack && importTrack.StartDateTime != null && nextTrack is ImportTrack nextImportTrack) - { - var length = nextImportTrack.StartDateTime - importTrack.StartDateTime; - clone.Begin = begin; - clone.End = begin + length; - } - // Calculate properties - if (clone.Position.HasValue == false) - { - clone.Position = position; - } - if (clone.Begin.HasValue == false) - { - clone.Begin = begin; - } - if ((clone.End.HasValue == false) && (nextTrack?.Begin.HasValue == true)) - { - clone.End = nextTrack.Begin; - } - begin = clone.End; - position++; - targetAudiofile.Tracks.Add(clone); + clone.Begin = begin; } - //Set last track end - var lastTrack = targetAudiofile.Tracks.LastOrDefault(); - if ((lastTrack?.End.HasValue == false) && (targetAudiofile.Duration.HasValue == true)) + if ((clone.End.HasValue == false) && (nextTrack?.Begin.HasValue == true)) { - _trackManager.SetProperty(lastTrack, x => x.End, targetAudiofile.Duration); + clone.End = nextTrack.Begin; } - target.Audiofiles.Add(targetAudiofile); + begin = clone.End; + position++; + targetAudiofile.Tracks.Add(clone); } + //Set last track end + var lastTrack = targetAudiofile.Tracks.LastOrDefault(); + if ((lastTrack?.End.HasValue == false) && (targetAudiofile.Duration.HasValue == true)) + { + _trackManager.SetProperty(lastTrack, x => x.End, targetAudiofile.Duration); + } + target.Audiofiles.Add(targetAudiofile); } + } - void ResetTracing() + void ResetTracing() + { + if (_sessionStateContainer.ImportCuesheet != null) { - if (_sessionStateContainer.ImportCuesheet != null) - { - _traceChangeManager.RemoveTracedChanges([_sessionStateContainer.ImportCuesheet, .. _sessionStateContainer.ImportCuesheet.Audiofiles, .. _sessionStateContainer.ImportCuesheet.Audiofiles.SelectMany(x => x.Tracks)]); - } + _traceChangeManager.RemoveTracedChanges([_sessionStateContainer.ImportCuesheet, .. _sessionStateContainer.ImportCuesheet.Audiofiles, .. _sessionStateContainer.ImportCuesheet.Audiofiles.SelectMany(x => x.Tracks)]); } } } diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index 39bca6d0..61e4efc2 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -25,334 +25,333 @@ using System.Text; using System.Text.RegularExpressions; -namespace AudioCuesheetEditor.Services.IO +namespace AudioCuesheetEditor.Services.IO; + +public class TextImportService(ILocalStorageOptionsProvider localStorageOptionsProvider) : ITextImportService { - public class TextImportService(ILocalStorageOptionsProvider localStorageOptionsProvider) : ITextImportService - { - private readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider; + readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider; - private readonly Dictionary<ImportAudiofile, int> _audiofileStartIndices = []; + readonly Dictionary<ImportAudiofile, int> _audiofileStartIndices = []; - public async Task<IImportfile> AnalyseAsync(string fileContent) + public async Task<IImportfile> AnalyseAsync(string fileContent) + { + Importfile importFile = new() { - Importfile importFile = new() - { - FileContent = fileContent, - FileContentRecognized = fileContent, - FileType = ImportFileType.Textfile - }; - try - { - var importOptions = await _localStorageOptionsProvider.GetOptionsAsync<ImportOptions>(); - var applicationOptions = await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); - var importProfile = importOptions.SelectedImportProfile ?? throw new InvalidOperationException("Selected import profiles is not set!"); - SearchForCuesheetData(ref importFile, fileContent, importProfile); - SearchForAudiofileData(ref importFile, fileContent, importProfile); - SearchForTrackData(ref importFile, fileContent, importProfile, applicationOptions.DefaultIsLinkedToPreviousTrack); - } - catch (Exception ex) - { - importFile.FileContentRecognized = fileContent; - importFile.AnalyseException = ex; - importFile.AnalyzedCuesheet = null; - } - return importFile; + FileContent = fileContent, + FileContentRecognized = fileContent, + FileType = ImportFileType.Textfile + }; + try + { + var importOptions = await _localStorageOptionsProvider.GetOptionsAsync<ImportOptions>(); + var applicationOptions = await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); + var importProfile = importOptions.SelectedImportProfile ?? throw new InvalidOperationException("Selected import profiles is not set!"); + SearchForCuesheetData(ref importFile, fileContent, importProfile); + SearchForAudiofileData(ref importFile, fileContent, importProfile); + SearchForTrackData(ref importFile, fileContent, importProfile, applicationOptions.DefaultIsLinkedToPreviousTrack); + } + catch (Exception ex) + { + importFile.FileContentRecognized = fileContent; + importFile.AnalyseException = ex; + importFile.AnalyzedCuesheet = null; } + return importFile; + } - static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, TimeSpanFormat? timeSpanFormat) + static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, TimeSpanFormat? timeSpanFormat) + { + return regex.Replace(input, match => { - return regex.Replace(input, match => + string result = match.Value; + var groupInfos = new List<(int RelIndex, int Length, string Value, string Key)>(); + for (int matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++) { - string result = match.Value; - var groupInfos = new List<(int RelIndex, int Length, string Value, string Key)>(); - for (int matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++) + var group = match.Groups[matchCounter]; + var key = regex.GroupNameFromNumber(matchCounter); + if (!string.IsNullOrEmpty(key) && key != matchCounter.ToString()) { - var group = match.Groups[matchCounter]; - var key = regex.GroupNameFromNumber(matchCounter); - if (!string.IsNullOrEmpty(key) && key != matchCounter.ToString()) + var property = entity.GetType().GetProperty(key, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (property != null) { - var property = entity.GetType().GetProperty(key, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - if (property != null) - { - SetValue(entity, property, group.Value, timeSpanFormat); - } - int relIndex = group.Index - match.Index; - groupInfos.Add((relIndex, group.Length, group.Value, key)); + SetValue(entity, property, group.Value, timeSpanFormat); } + int relIndex = group.Index - match.Index; + groupInfos.Add((relIndex, group.Length, group.Value, key)); } - if (groupInfos.Count == 0) - { - return result; - } - groupInfos.Sort((a, b) => b.RelIndex.CompareTo(a.RelIndex)); - var sb = new StringBuilder(result); - foreach (var (RelIndex, Length, Value, Key) in groupInfos) - { - sb.Remove(RelIndex, Length); - sb.Insert(RelIndex, string.Format(CuesheetConstants.RecognizedMarkHTML, Value)); - } - return sb.ToString(); - }); - } + } + if (groupInfos.Count == 0) + { + return result; + } + groupInfos.Sort((a, b) => b.RelIndex.CompareTo(a.RelIndex)); + var sb = new StringBuilder(result); + foreach (var (RelIndex, Length, Value, Key) in groupInfos) + { + sb.Remove(RelIndex, Length); + sb.Insert(RelIndex, string.Format(CuesheetConstants.RecognizedMarkHTML, Value)); + } + return sb.ToString(); + }); + } - static void SearchForCuesheetData(ref Importfile importFile, string fileContent, Importprofile importProfile) + static void SearchForCuesheetData(ref Importfile importFile, string fileContent, Importprofile importProfile) + { + var cuesheet = new ImportCuesheet(); + if (string.IsNullOrWhiteSpace(importProfile.SchemeCuesheet) == false) { - var cuesheet = new ImportCuesheet(); - if (string.IsNullOrWhiteSpace(importProfile.SchemeCuesheet) == false) + importFile.FileContentRecognized ??= fileContent; + if (importProfile.UseRegularExpression) { - importFile.FileContentRecognized ??= fileContent; - if (importProfile.UseRegularExpression) - { - var regex = new Regex(importProfile.SchemeCuesheet); - importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, - match => - { - string marked = ApplyRegexAndMarkGroups(cuesheet, regex, match.Value, importProfile.TimeSpanFormat); - return marked; - } - ); - importFile.FileContentRecognized = ApplyRegexAndMarkGroups(cuesheet, regex, fileContent, importProfile.TimeSpanFormat); - } - else - { - var regex = CreateRegexPattern(importProfile.SchemeCuesheet, [ - nameof(ImportCuesheet.Artist), - nameof(ImportCuesheet.Title), - nameof(ImportCuesheet.CDTextfile), - nameof(ImportCuesheet.Cataloguenumber) - ]); - importFile.FileContentRecognized = SearchLineByLineForEntry(importFile.FileContentRecognized, () => new ImportCuesheet(), (position, entity) => + var regex = new Regex(importProfile.SchemeCuesheet); + importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, + match => { - cuesheet = (ImportCuesheet)entity; - return true; - }, regex, importProfile); - } + string marked = ApplyRegexAndMarkGroups(cuesheet, regex, match.Value, importProfile.TimeSpanFormat); + return marked; + } + ); + importFile.FileContentRecognized = ApplyRegexAndMarkGroups(cuesheet, regex, fileContent, importProfile.TimeSpanFormat); + } + else + { + var regex = CreateRegexPattern(importProfile.SchemeCuesheet, [ + nameof(ImportCuesheet.Artist), + nameof(ImportCuesheet.Title), + nameof(ImportCuesheet.CDTextfile), + nameof(ImportCuesheet.Cataloguenumber) + ]); + importFile.FileContentRecognized = SearchLineByLineForEntry(importFile.FileContentRecognized, () => new ImportCuesheet(), (position, entity) => + { + cuesheet = (ImportCuesheet)entity; + return true; + }, regex, importProfile); } - importFile.AnalyzedCuesheet = cuesheet; } + importFile.AnalyzedCuesheet = cuesheet; + } - void SearchForAudiofileData(ref Importfile importFile, string fileContent, Importprofile importProfile) + void SearchForAudiofileData(ref Importfile importFile, string fileContent, Importprofile importProfile) + { + _audiofileStartIndices.Clear(); + var cuesheet = importFile.AnalyzedCuesheet; + if (string.IsNullOrWhiteSpace(importProfile.SchemeAudiofiles) == false) { - _audiofileStartIndices.Clear(); - var cuesheet = importFile.AnalyzedCuesheet; - if (string.IsNullOrWhiteSpace(importProfile.SchemeAudiofiles) == false) + importFile.FileContentRecognized ??= fileContent; + if (importProfile.UseRegularExpression) { - importFile.FileContentRecognized ??= fileContent; - if (importProfile.UseRegularExpression) - { - var regex = new Regex(importProfile.SchemeAudiofiles); - importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, - match => - { - var audiofile = new ImportAudiofile(); - string marked = ApplyRegexAndMarkGroups(audiofile, regex, match.Value, importProfile.TimeSpanFormat); - cuesheet!.Audiofiles.Add(audiofile); - _audiofileStartIndices.Add(audiofile, match.Index); - return marked; - } - ); - } - else - { - var regex = CreateRegexPattern(importProfile.SchemeAudiofiles, [nameof(ImportAudiofile.Name)]); - importFile.FileContentRecognized = SearchLineByLineForEntry(importFile.FileContentRecognized, () => new ImportAudiofile(), (position, entity) => + var regex = new Regex(importProfile.SchemeAudiofiles); + importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, + match => { - var audiofile = (ImportAudiofile)entity; + var audiofile = new ImportAudiofile(); + string marked = ApplyRegexAndMarkGroups(audiofile, regex, match.Value, importProfile.TimeSpanFormat); cuesheet!.Audiofiles.Add(audiofile); - _audiofileStartIndices.Add(audiofile, position); - return false; - }, regex, importProfile); - } + _audiofileStartIndices.Add(audiofile, match.Index); + return marked; + } + ); } else { - //Add an empty audiofile to the cuesheet if no scheme is provided, so that tracks can be added to it - var audiofile = new ImportAudiofile(); - _audiofileStartIndices.Add(audiofile, 0); - cuesheet!.Audiofiles.Add(audiofile); + var regex = CreateRegexPattern(importProfile.SchemeAudiofiles, [nameof(ImportAudiofile.Name)]); + importFile.FileContentRecognized = SearchLineByLineForEntry(importFile.FileContentRecognized, () => new ImportAudiofile(), (position, entity) => + { + var audiofile = (ImportAudiofile)entity; + cuesheet!.Audiofiles.Add(audiofile); + _audiofileStartIndices.Add(audiofile, position); + return false; + }, regex, importProfile); } } + else + { + //Add an empty audiofile to the cuesheet if no scheme is provided, so that tracks can be added to it + var audiofile = new ImportAudiofile(); + _audiofileStartIndices.Add(audiofile, 0); + cuesheet!.Audiofiles.Add(audiofile); + } + } - void SearchForTrackData(ref Importfile importFile, string fileContent, Importprofile importProfile, bool defaultIsLinkedToPreviousTrack) + void SearchForTrackData(ref Importfile importFile, string fileContent, Importprofile importProfile, bool defaultIsLinkedToPreviousTrack) + { + if (string.IsNullOrWhiteSpace(importProfile.SchemeTracks) == false) { - if (string.IsNullOrWhiteSpace(importProfile.SchemeTracks) == false) + var cuesheet = importFile.AnalyzedCuesheet; + importFile.FileContentRecognized ??= fileContent; + if (importProfile.UseRegularExpression) { - var cuesheet = importFile.AnalyzedCuesheet; - importFile.FileContentRecognized ??= fileContent; - if (importProfile.UseRegularExpression) - { - var regex = new Regex(importProfile.SchemeTracks); - importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, - match => + var regex = new Regex(importProfile.SchemeTracks); + importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, + match => + { + var track = new ImportTrack() { IsLinkedToPreviousTrack = defaultIsLinkedToPreviousTrack }; + var audiofile = _audiofileStartIndices + .Where(kv => kv.Value <= match.Index) + .OrderBy(kv => kv.Value) + .Select(kv => kv.Key) + .LastOrDefault(); + if (audiofile != null) { - var track = new ImportTrack() { IsLinkedToPreviousTrack = defaultIsLinkedToPreviousTrack }; - var audiofile = _audiofileStartIndices - .Where(kv => kv.Value <= match.Index) - .OrderBy(kv => kv.Value) - .Select(kv => kv.Key) - .LastOrDefault(); - if (audiofile != null) - { - audiofile.Tracks.Add(track); - return ApplyRegexAndMarkGroups(track, regex, match.Value, importProfile.TimeSpanFormat); - } - return match.Value; + audiofile.Tracks.Add(track); + return ApplyRegexAndMarkGroups(track, regex, match.Value, importProfile.TimeSpanFormat); } - ); - } - else + return match.Value; + } + ); + } + else + { + var regex = CreateRegexPattern(importProfile.SchemeTracks, + [ + nameof(ImportTrack.Artist), + nameof(ImportTrack.Title), + nameof(ImportTrack.Begin), + nameof(ImportTrack.End), + nameof(ImportTrack.Length), + nameof(ImportTrack.Position), + nameof(ImportTrack.Flags), + nameof(ImportTrack.PreGap), + nameof(ImportTrack.PostGap), + nameof(ImportTrack.StartDateTime) + ]); + if (_audiofileStartIndices.Count > 0) { - var regex = CreateRegexPattern(importProfile.SchemeTracks, - [ - nameof(ImportTrack.Artist), - nameof(ImportTrack.Title), - nameof(ImportTrack.Begin), - nameof(ImportTrack.End), - nameof(ImportTrack.Length), - nameof(ImportTrack.Position), - nameof(ImportTrack.Flags), - nameof(ImportTrack.PreGap), - nameof(ImportTrack.PostGap), - nameof(ImportTrack.StartDateTime) - ]); - if (_audiofileStartIndices.Count > 0) + importFile.FileContentRecognized = SearchLineByLineForEntry(importFile.FileContentRecognized, () => new ImportTrack() { IsLinkedToPreviousTrack = defaultIsLinkedToPreviousTrack }, (position, entity) => { - importFile.FileContentRecognized = SearchLineByLineForEntry(importFile.FileContentRecognized, () => new ImportTrack() { IsLinkedToPreviousTrack = defaultIsLinkedToPreviousTrack }, (position, entity) => - { - var audiofile = _audiofileStartIndices - .Where(kv => kv.Value <= position) - .OrderBy(kv => kv.Value) - .Select(kv => kv.Key) - .LastOrDefault(); - audiofile?.Tracks.Add((ImportTrack)entity); - return false; - }, regex, importProfile); - } + var audiofile = _audiofileStartIndices + .Where(kv => kv.Value <= position) + .OrderBy(kv => kv.Value) + .Select(kv => kv.Key) + .LastOrDefault(); + audiofile?.Tracks.Add((ImportTrack)entity); + return false; + }, regex, importProfile); } } } + } - static string SearchLineByLineForEntry(string fileContent, Func<object> entityCreation, Func<int, object, bool> ifEntityFound, Regex regex, Importprofile importProfile) + static string SearchLineByLineForEntry(string fileContent, Func<object> entityCreation, Func<int, object, bool> ifEntityFound, Regex regex, Importprofile importProfile) + { + var sb = new StringBuilder(); + using (var reader = new StringReader(fileContent)) { - var sb = new StringBuilder(); - using (var reader = new StringReader(fileContent)) + string? line; + int pos = 0; + while ((line = reader.ReadLine()) != null) { - string? line; - int pos = 0; - while ((line = reader.ReadLine()) != null) + Boolean stopSearch = false; + // Check if this line is already analyzed + if (line.Contains(CuesheetConstants.MarkHTMLStart) == false) { - Boolean stopSearch = false; - // Check if this line is already analyzed - if (line.Contains(CuesheetConstants.MarkHTMLStart) == false) + var entity = entityCreation.Invoke(); + var markedLine = ApplyRegexAndMarkGroups(entity, regex, line, importProfile.TimeSpanFormat); + if (!string.Equals(markedLine, line)) { - var entity = entityCreation.Invoke(); - var markedLine = ApplyRegexAndMarkGroups(entity, regex, line, importProfile.TimeSpanFormat); - if (!string.Equals(markedLine, line)) - { - stopSearch = ifEntityFound.Invoke(pos, entity); - } - sb.AppendLine(markedLine); - if (stopSearch) - { - sb.Append(reader.ReadToEnd()); - break; - } + stopSearch = ifEntityFound.Invoke(pos, entity); } - else + sb.AppendLine(markedLine); + if (stopSearch) { - sb.AppendLine(line); + sb.Append(reader.ReadToEnd()); + break; } - pos += line.Length + Environment.NewLine.Length; } + else + { + sb.AppendLine(line); + } + pos += line.Length + Environment.NewLine.Length; } - return sb.ToString().TrimEnd(Environment.NewLine.ToCharArray()); } + return sb.ToString().TrimEnd(Environment.NewLine.ToCharArray()); + } - static void SetValue(object entity, PropertyInfo property, string value, TimeSpanFormat? timeSpanFormat) + static void SetValue(object entity, PropertyInfo property, string value, TimeSpanFormat? timeSpanFormat) + { + if (property.PropertyType == typeof(TimeSpan?)) { - if (property.PropertyType == typeof(TimeSpan?)) - { - property.SetValue(entity, TimeSpanUtility.ParseTimeSpan(value, timeSpanFormat)); - } - if (property.PropertyType == typeof(ushort?)) - { - property.SetValue(entity, Convert.ToUInt16(value)); - } - if (property.PropertyType == typeof(String)) - { - property.SetValue(entity, value); - } - if (property.PropertyType == typeof(IEnumerable<Flag>)) + property.SetValue(entity, TimeSpanUtility.ParseTimeSpan(value, timeSpanFormat)); + } + if (property.PropertyType == typeof(ushort?)) + { + property.SetValue(entity, Convert.ToUInt16(value)); + } + if (property.PropertyType == typeof(String)) + { + property.SetValue(entity, value); + } + if (property.PropertyType == typeof(IEnumerable<Flag>)) + { + ((ITrack)entity).Flags = Flag.AvailableFlags.Where(x => value.Contains(x.CuesheetLabel)); + } + if (property.PropertyType == typeof(Audiofile)) + { + property.SetValue(entity, new Audiofile() { Name = value }); + } + if (property.PropertyType == typeof(DateTime?)) + { + if (DateTime.TryParse(value, out var date)) { - ((ITrack)entity).Flags = Flag.AvailableFlags.Where(x => value.Contains(x.CuesheetLabel)); + property.SetValue(entity, date); } - if (property.PropertyType == typeof(Audiofile)) + } + } + + static Regex CreateRegexPattern(string scheme, string[] fieldNames) + { + var parts = new List<string>(); + int idx = 0; + while (idx < scheme.Length) + { + var field = fieldNames.FirstOrDefault(fn => scheme.IndexOf(fn, idx, StringComparison.Ordinal) == idx); + if (field != null) { - property.SetValue(entity, new Audiofile() { Name = value }); + parts.Add(field); + idx += field.Length; } - if (property.PropertyType == typeof(DateTime?)) + else { - if (DateTime.TryParse(value, out var date)) + int nextFieldIdx = scheme.Length; + foreach (var fn in fieldNames) { - property.SetValue(entity, date); + int pos = scheme.IndexOf(fn, idx, StringComparison.Ordinal); + if (pos >= 0 && pos < nextFieldIdx) + { + nextFieldIdx = pos; + } } + string separator = scheme[idx..nextFieldIdx]; + parts.Add(separator); + idx = nextFieldIdx; } } - static Regex CreateRegexPattern(string scheme, string[] fieldNames) + var regexBuilder = new StringBuilder("^"); + for (int i = 0; i < parts.Count; i++) { - var parts = new List<string>(); - int idx = 0; - while (idx < scheme.Length) + var part = parts[i]; + if (fieldNames.Contains(part)) { - var field = fieldNames.FirstOrDefault(fn => scheme.IndexOf(fn, idx, StringComparison.Ordinal) == idx); - if (field != null) + bool isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p)); + if (isLast) { - parts.Add(field); - idx += field.Length; + regexBuilder.Append($@"(?<{part}>.+)"); } else { - int nextFieldIdx = scheme.Length; - foreach (var fn in fieldNames) - { - int pos = scheme.IndexOf(fn, idx, StringComparison.Ordinal); - if (pos >= 0 && pos < nextFieldIdx) - { - nextFieldIdx = pos; - } - } - string separator = scheme[idx..nextFieldIdx]; - parts.Add(separator); - idx = nextFieldIdx; + regexBuilder.Append($@"(?<{part}>.+?)"); } } - - var regexBuilder = new StringBuilder("^"); - for (int i = 0; i < parts.Count; i++) + else { - var part = parts[i]; - if (fieldNames.Contains(part)) - { - bool isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p)); - if (isLast) - { - regexBuilder.Append($@"(?<{part}>.+)"); - } - else - { - regexBuilder.Append($@"(?<{part}>.+?)"); - } - } - else - { - string sep = Regex.Escape(part).Replace("\\t", @"\t{1,}"); - regexBuilder.Append(sep); - } + string sep = Regex.Escape(part).Replace("\\t", @"\t{1,}"); + regexBuilder.Append(sep); } - regexBuilder.Append('$'); - - return new Regex(regexBuilder.ToString()); } + regexBuilder.Append('$'); + + return new Regex(regexBuilder.ToString()); } } diff --git a/AudioCuesheetEditor/Services/Options/ILocalStorageOptionsProvider.cs b/AudioCuesheetEditor/Services/Options/ILocalStorageOptionsProvider.cs index db629e4b..ffa40bda 100644 --- a/AudioCuesheetEditor/Services/Options/ILocalStorageOptionsProvider.cs +++ b/AudioCuesheetEditor/Services/Options/ILocalStorageOptionsProvider.cs @@ -16,14 +16,13 @@ using AudioCuesheetEditor.Model.Options; using System.Linq.Expressions; -namespace AudioCuesheetEditor.Services.Options +namespace AudioCuesheetEditor.Services.Options; + +public interface ILocalStorageOptionsProvider { - public interface ILocalStorageOptionsProvider - { - event EventHandler<IOptions>? OptionSaved; - Task<T> GetOptionsAsync<T>() where T : IOptions; - Task<Result> SaveOptionsAsync(IOptions options); - Task<Result> SaveOptionsValueAsync<T>(Expression<Func<T, object?>> propertyExpression, object? value) where T : class, IOptions, new(); - Task SaveNestedOptionValueAsync<T, TNested, TValue>(Expression<Func<T, TNested>> nestedPropertyExpression, Expression<Func<TNested, TValue>> valuePropertyExpression, TValue value) where T : class, IOptions, new(); - } + event EventHandler<IOptions>? OptionSaved; + Task<T> GetOptionsAsync<T>() where T : IOptions; + Task<Result> SaveOptionsAsync(IOptions options); + Task<Result> SaveOptionsValueAsync<T>(Expression<Func<T, object?>> propertyExpression, object? value) where T : class, IOptions, new(); + Task SaveNestedOptionValueAsync<T, TNested, TValue>(Expression<Func<T, TNested>> nestedPropertyExpression, Expression<Func<TNested, TValue>> valuePropertyExpression, TValue value) where T : class, IOptions, new(); } diff --git a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs index aa46c044..51b9959c 100644 --- a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs +++ b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs @@ -21,143 +21,142 @@ using System.Reflection; using System.Text.Json; -namespace AudioCuesheetEditor.Services.Options +namespace AudioCuesheetEditor.Services.Options; + +public class LocalStorageOptionsProvider(IJSRuntime jsRuntime, IStringLocalizer<ValidationMessage> localizer) : ILocalStorageOptionsProvider { - public class LocalStorageOptionsProvider(IJSRuntime jsRuntime, IStringLocalizer<ValidationMessage> localizer) : ILocalStorageOptionsProvider - { - public event EventHandler<IOptions>? OptionSaved; + public event EventHandler<IOptions>? OptionSaved; - private readonly IJSRuntime _jsRuntime = jsRuntime; - private readonly IStringLocalizer<ValidationMessage> _localizer = localizer; - private readonly JsonSerializerOptions _serializerOptions = new() - { - DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull - }; + readonly IJSRuntime _jsRuntime = jsRuntime; + readonly IStringLocalizer<ValidationMessage> _localizer = localizer; + readonly JsonSerializerOptions _serializerOptions = new() + { + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull + }; - public async Task<T> GetOptionsAsync<T>() where T : IOptions + public async Task<T> GetOptionsAsync<T>() where T : IOptions + { + var type = typeof(T); + IOptions? options = (IOptions?)Activator.CreateInstance(type); + String optionsJson = await _jsRuntime.InvokeAsync<String>("AppSettings.get", type.Name); + if (String.IsNullOrEmpty(optionsJson) == false) { - var type = typeof(T); - IOptions? options = (IOptions?)Activator.CreateInstance(type); - String optionsJson = await _jsRuntime.InvokeAsync<String>("AppSettings.get", type.Name); - if (String.IsNullOrEmpty(optionsJson) == false) - { - try - { - options = JsonSerializer.Deserialize<T>(optionsJson); - options ??= Activator.CreateInstance<T>(); - } - catch (JsonException) - { - //nothing to do, we can not deserialize - options = Activator.CreateInstance<T>(); - } - } - if (options != null) + try { - return (T)options; + options = JsonSerializer.Deserialize<T>(optionsJson); + options ??= Activator.CreateInstance<T>(); } - else + catch (JsonException) { - return default!; + //nothing to do, we can not deserialize + options = Activator.CreateInstance<T>(); } } + if (options != null) + { + return (T)options; + } + else + { + return default!; + } + } - public async Task<Result> SaveOptionsAsync(IOptions options) + public async Task<Result> SaveOptionsAsync(IOptions options) + { + if (options is IValidateable validateable) { - if (options is IValidateable validateable) + var validationResult = validateable.Validate(); + if (validationResult.Status == ValidationStatus.Error) { - var validationResult = validateable.Validate(); - if (validationResult.Status == ValidationStatus.Error) - { - return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationResult.ValidationMessages.Select(x => x.GetMessageLocalized(_localizer))))); - } + return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationResult.ValidationMessages.Select(x => x.GetMessageLocalized(_localizer))))); } - await WriteOptionsAsync(options); - return Result.Success(); } + await WriteOptionsAsync(options); + return Result.Success(); + } - public async Task<Result> SaveOptionsValueAsync<T>(Expression<Func<T, object?>> propertyExpression, object? value) where T : class, IOptions, new() - { - var options = await GetOptionsAsync<T>(); - PropertyInfo? propertyInfo = null; - object? targetObject = options; + public async Task<Result> SaveOptionsValueAsync<T>(Expression<Func<T, object?>> propertyExpression, object? value) where T : class, IOptions, new() + { + var options = await GetOptionsAsync<T>(); + PropertyInfo? propertyInfo = null; + object? targetObject = options; - if (propertyExpression.Body is MemberExpression memberExpression) - { - propertyInfo = ResolveNestedProperty(memberExpression, ref targetObject); - } - else if (propertyExpression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression unaryMemberExpression) - { - propertyInfo = ResolveNestedProperty(unaryMemberExpression, ref targetObject); - } + if (propertyExpression.Body is MemberExpression memberExpression) + { + propertyInfo = ResolveNestedProperty(memberExpression, ref targetObject); + } + else if (propertyExpression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression unaryMemberExpression) + { + propertyInfo = ResolveNestedProperty(unaryMemberExpression, ref targetObject); + } - if (propertyInfo != null && targetObject != null) - { - propertyInfo.SetValue(targetObject, Convert.ChangeType(value, propertyInfo.PropertyType)); - } - else - { - throw new ArgumentException("The provided expression does not reference a valid property."); - } - return await SaveOptionsAsync(options); + if (propertyInfo != null && targetObject != null) + { + propertyInfo.SetValue(targetObject, Convert.ChangeType(value, propertyInfo.PropertyType)); + } + else + { + throw new ArgumentException("The provided expression does not reference a valid property."); } + return await SaveOptionsAsync(options); + } - public async Task SaveNestedOptionValueAsync<T, TNested, TValue>(Expression<Func<T, TNested>> nestedPropertyExpression, Expression<Func<TNested, TValue>> valuePropertyExpression, TValue value) where T : class, IOptions, new() + public async Task SaveNestedOptionValueAsync<T, TNested, TValue>(Expression<Func<T, TNested>> nestedPropertyExpression, Expression<Func<TNested, TValue>> valuePropertyExpression, TValue value) where T : class, IOptions, new() + { + var options = await GetOptionsAsync<T>(); + + if (nestedPropertyExpression.Body is not MemberExpression memberExpression) { - var options = await GetOptionsAsync<T>(); + throw new ArgumentException("The provided nested property expression does not reference a member!"); + } - if (nestedPropertyExpression.Body is not MemberExpression memberExpression) - { - throw new ArgumentException("The provided nested property expression does not reference a member!"); - } + var nestedProperty = typeof(T).GetProperty(memberExpression.Member.Name) ?? throw new ArgumentException("The provided nested property expression does not reference a valid property."); + var nestedInstance = nestedProperty.GetValue(options) ?? throw new InvalidOperationException("The nested property is null."); + var valueProperty = ResolveNestedProperty(valuePropertyExpression.Body as MemberExpression, ref nestedInstance) ?? throw new ArgumentException("The provided value property expression does not reference a valid property."); + valueProperty.SetValue(nestedInstance, Convert.ChangeType(value, valueProperty.PropertyType)); - var nestedProperty = typeof(T).GetProperty(memberExpression.Member.Name) ?? throw new ArgumentException("The provided nested property expression does not reference a valid property."); - var nestedInstance = nestedProperty.GetValue(options) ?? throw new InvalidOperationException("The nested property is null."); - var valueProperty = ResolveNestedProperty(valuePropertyExpression.Body as MemberExpression, ref nestedInstance) ?? throw new ArgumentException("The provided value property expression does not reference a valid property."); - valueProperty.SetValue(nestedInstance, Convert.ChangeType(value, valueProperty.PropertyType)); + await SaveOptionsAsync(options); + } - await SaveOptionsAsync(options); - } + static PropertyInfo? ResolveNestedProperty(MemberExpression? memberExpression, ref object? targetObject) + { + PropertyInfo? propertyInfo = null; + var members = new Stack<MemberExpression>(); - private static PropertyInfo? ResolveNestedProperty(MemberExpression? memberExpression, ref object? targetObject) + while (memberExpression != null) { - PropertyInfo? propertyInfo = null; - var members = new Stack<MemberExpression>(); - - while (memberExpression != null) + members.Push(memberExpression); + if (memberExpression.Expression is MemberExpression parentMember) { - members.Push(memberExpression); - if (memberExpression.Expression is MemberExpression parentMember) - { - memberExpression = parentMember; - } - else - { - memberExpression = null; - } + memberExpression = parentMember; + } + else + { + memberExpression = null; } + } - while (members.Count > 0 && targetObject != null) + while (members.Count > 0 && targetObject != null) + { + memberExpression = members.Pop(); + propertyInfo = targetObject.GetType().GetProperty(memberExpression.Member.Name); + if (propertyInfo != null) { - memberExpression = members.Pop(); - propertyInfo = targetObject.GetType().GetProperty(memberExpression.Member.Name); - if (propertyInfo != null) + if (members.Count > 0) { - if (members.Count > 0) - { - targetObject = propertyInfo.GetValue(targetObject); - } + targetObject = propertyInfo.GetValue(targetObject); } } - - return propertyInfo; } - async Task WriteOptionsAsync(IOptions options) - { - var optionsJson = JsonSerializer.Serialize<object>(options, _serializerOptions); - await _jsRuntime.InvokeVoidAsync("AppSettings.set", options.GetType().Name, optionsJson); - OptionSaved?.Invoke(this, options); - } + return propertyInfo; + } + + async Task WriteOptionsAsync(IOptions options) + { + var optionsJson = JsonSerializer.Serialize<object>(options, _serializerOptions); + await _jsRuntime.InvokeVoidAsync("AppSettings.set", options.GetType().Name, optionsJson); + OptionSaved?.Invoke(this, options); } } diff --git a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs index 440cd292..db86cd4d 100644 --- a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs +++ b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs @@ -18,113 +18,112 @@ using MetaBrainz.MusicBrainz.Interfaces.Searches; using System.Reflection; -namespace AudioCuesheetEditor.Services.Provider +namespace AudioCuesheetEditor.Services.Provider; + +public class MusicBrainzArtist { - public class MusicBrainzArtist - { - public Guid? Id { get; init; } - public String? Name { get; init; } - public String? Disambiguation { get; init; } - } - public class MusicBrainzTrack - { - public Guid? Id { get; init; } - public String? Artist { get; init; } - public String? Title { get; init; } - public TimeSpan? Length { get; init; } - public String? Disambiguation { get; init; } - } - public class MusicBrainzDataProvider(ILogger<MusicBrainzDataProvider> logger) - { - private readonly ILogger<MusicBrainzDataProvider> _logger = logger; + public Guid? Id { get; init; } + public String? Name { get; init; } + public String? Disambiguation { get; init; } +} +public class MusicBrainzTrack +{ + public Guid? Id { get; init; } + public String? Artist { get; init; } + public String? Title { get; init; } + public TimeSpan? Length { get; init; } + public String? Disambiguation { get; init; } +} +public class MusicBrainzDataProvider(ILogger<MusicBrainzDataProvider> logger) +{ + readonly ILogger<MusicBrainzDataProvider> _logger = logger; - public const String Application = "AudioCuesheetEditor"; - public const String ProjectUrl = "https://github.com/NeoCoderMatrix86/AudioCuesheetEditor"; + public const String Application = "AudioCuesheetEditor"; + public const String ProjectUrl = "https://github.com/NeoCoderMatrix86/AudioCuesheetEditor"; - private String? applicationVersion = null; + String? applicationVersion = null; - public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(String? searchString, CancellationToken token) + public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(String? searchString, CancellationToken token) + { + List<MusicBrainzArtist> artistSearchResult = []; + try { - List<MusicBrainzArtist> artistSearchResult = []; - try - { - if (String.IsNullOrEmpty(searchString) == false) - { - using var query = new Query(Application, ApplicationVersion, ProjectUrl); - var findArtistsResult = await query.FindArtistsAsync(searchString, simple: true, cancellationToken: token); - artistSearchResult = findArtistsResult.Results.ToList().ConvertAll(x => new MusicBrainzArtist() { Id = x.Item.Id, Name = x.Item.Name, Disambiguation = x.Item.Disambiguation }); - } - } - catch (HttpRequestException hre) + if (String.IsNullOrEmpty(searchString) == false) { - _logger.LogError(hre, "Error getting response from MusicBrainz"); + using var query = new Query(Application, ApplicationVersion, ProjectUrl); + var findArtistsResult = await query.FindArtistsAsync(searchString, simple: true, cancellationToken: token); + artistSearchResult = findArtistsResult.Results.ToList().ConvertAll(x => new MusicBrainzArtist() { Id = x.Item.Id, Name = x.Item.Name, Disambiguation = x.Item.Disambiguation }); } - return artistSearchResult.AsReadOnly(); } + catch (HttpRequestException hre) + { + _logger.LogError(hre, "Error getting response from MusicBrainz"); + } + return artistSearchResult.AsReadOnly(); + } - public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(String? searchString, String? artist, CancellationToken token) + public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(String? searchString, String? artist, CancellationToken token) + { + List<MusicBrainzTrack> titleSearchResult = []; + try { - List<MusicBrainzTrack> titleSearchResult = []; - try + if (String.IsNullOrEmpty(searchString) == false) { - if (String.IsNullOrEmpty(searchString) == false) + using var query = new Query(Application, ApplicationVersion, ProjectUrl); + ISearchResults<ISearchResult<IRecording>> findRecordingsResult; + if (String.IsNullOrEmpty(artist)) { - using var query = new Query(Application, ApplicationVersion, ProjectUrl); - ISearchResults<ISearchResult<IRecording>> findRecordingsResult; - if (String.IsNullOrEmpty(artist)) - { - findRecordingsResult = await query.FindRecordingsAsync(searchString, simple: true, cancellationToken: token); - } - else - { - findRecordingsResult = await query.FindRecordingsAsync(String.Format("{0} AND artistname:{1}", searchString, artist), cancellationToken: token); - } - foreach (var result in findRecordingsResult.Results) + findRecordingsResult = await query.FindRecordingsAsync(searchString, simple: true, cancellationToken: token); + } + else + { + findRecordingsResult = await query.FindRecordingsAsync(String.Format("{0} AND artistname:{1}", searchString, artist), cancellationToken: token); + } + foreach (var result in findRecordingsResult.Results) + { + String artistString = String.Empty; + if (result.Item.ArtistCredit != null) { - String artistString = String.Empty; - if (result.Item.ArtistCredit != null) + foreach (var artistCredit in result.Item.ArtistCredit) { - foreach (var artistCredit in result.Item.ArtistCredit) + artistString += artistCredit.Name; + if (String.IsNullOrEmpty(artistCredit.JoinPhrase) == false) { - artistString += artistCredit.Name; - if (String.IsNullOrEmpty(artistCredit.JoinPhrase) == false) - { - artistString += artistCredit.JoinPhrase; - } + artistString += artistCredit.JoinPhrase; } } - titleSearchResult.Add(new MusicBrainzTrack() - { - Id = result.Item.Id, - Artist = artistString, - Title = result.Item.Title, - Length = result.Item.Length, - Disambiguation = result.Item.Disambiguation - }); } + titleSearchResult.Add(new MusicBrainzTrack() + { + Id = result.Item.Id, + Artist = artistString, + Title = result.Item.Title, + Length = result.Item.Length, + Disambiguation = result.Item.Disambiguation + }); } } - catch (HttpRequestException hre) - { - _logger.LogError(hre, "Error getting response from MusicBrainz"); - } - return titleSearchResult.AsReadOnly(); } + catch (HttpRequestException hre) + { + _logger.LogError(hre, "Error getting response from MusicBrainz"); + } + return titleSearchResult.AsReadOnly(); + } - private String? ApplicationVersion + String? ApplicationVersion + { + get { - get + if (applicationVersion == null) { - if (applicationVersion == null) + var versionAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>(); + if (versionAttribute != null) { - var versionAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>(); - if (versionAttribute != null) - { - applicationVersion = versionAttribute.InformationalVersion; - } + applicationVersion = versionAttribute.InformationalVersion; } - return applicationVersion; } + return applicationVersion; } } } diff --git a/AudioCuesheetEditor/Services/Result.cs b/AudioCuesheetEditor/Services/Result.cs index 565b1fe0..df1b9b3e 100644 --- a/AudioCuesheetEditor/Services/Result.cs +++ b/AudioCuesheetEditor/Services/Result.cs @@ -13,117 +13,116 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. -namespace AudioCuesheetEditor.Services +namespace AudioCuesheetEditor.Services; + +/// <summary> +/// Defines types of errors +/// </summary> +public enum ErrorType { /// <summary> - /// Defines types of errors + /// Validation failed with error /// </summary> - public enum ErrorType - { - /// <summary> - /// Validation failed with error - /// </summary> - ValidationFailed, - /// <summary> - /// Resource already exists - /// </summary> - AlreadyDone, - /// <summary> - /// Current action is not possible - /// </summary> - NotPossible, - /// <summary> - /// Action was aborted - /// </summary> - Aborted, - } - + ValidationFailed, /// <summary> - /// Represents an error of an service + /// Resource already exists /// </summary> - public class Error(ErrorType type, string message) - { - /// <summary> - /// Type of error - /// </summary> - public ErrorType Type { get; } = type; - /// <summary> - /// The error message - /// </summary> - public string Message { get; } = message; - } + AlreadyDone, + /// <summary> + /// Current action is not possible + /// </summary> + NotPossible, + /// <summary> + /// Action was aborted + /// </summary> + Aborted, +} +/// <summary> +/// Represents an error of an service +/// </summary> +public class Error(ErrorType type, string message) +{ /// <summary> - /// Indicates a service result + /// Type of error /// </summary> - public class Result - { - /// <summary> - /// Indicates if the result was successful - /// </summary> - public bool IsSuccess { get; } - /// <summary> - /// The error if one occurred - /// </summary> - public Error? Error { get; } + public ErrorType Type { get; } = type; + /// <summary> + /// The error message + /// </summary> + public string Message { get; } = message; +} - /// <summary> - /// Private constructor - /// </summary> - protected Result() - { - IsSuccess = true; - } +/// <summary> +/// Indicates a service result +/// </summary> +public class Result +{ + /// <summary> + /// Indicates if the result was successful + /// </summary> + public bool IsSuccess { get; } + /// <summary> + /// The error if one occurred + /// </summary> + public Error? Error { get; } - /// <summary> - /// Private constructor - /// </summary> - protected Result(Error error) - { - IsSuccess = false; - Error = error; - } - /// <summary> - /// Creates a success result - /// </summary> - /// <returns></returns> - public static Result Success() => new(); - /// <summary> - /// Creates a failure result - /// </summary> - /// <param name="error"></param> - /// <returns></returns> - public static Result Failure(Error error) => new(error); + /// <summary> + /// Private constructor + /// </summary> + protected Result() + { + IsSuccess = true; } /// <summary> - /// Represent the result of a service + /// Private constructor /// </summary> - /// <typeparam name="T"></typeparam> - public class Result<T> : Result + protected Result(Error error) { - /// <summary> - /// The result value - /// </summary> - public T? Value { get; } + IsSuccess = false; + Error = error; + } + /// <summary> + /// Creates a success result + /// </summary> + /// <returns></returns> + public static Result Success() => new(); + /// <summary> + /// Creates a failure result + /// </summary> + /// <param name="error"></param> + /// <returns></returns> + public static Result Failure(Error error) => new(error); +} - private Result(T value) : base() - { - Value = value; - } +/// <summary> +/// Represent the result of a service +/// </summary> +/// <typeparam name="T"></typeparam> +public class Result<T> : Result +{ + /// <summary> + /// The result value + /// </summary> + public T? Value { get; } - private Result(Error error) : base(error) { } - /// <summary> - /// Creates a success result - /// </summary> - /// <param name="value"></param> - /// <returns></returns> - public static Result<T> Success(T value) => new(value); - /// <summary> - /// Creates a failure result - /// </summary> - /// <param name="error"></param> - /// <returns></returns> - public static new Result<T> Failure(Error error) => new(error); + Result(T value) : base() + { + Value = value; } + + Result(Error error) : base(error) { } + /// <summary> + /// Creates a success result + /// </summary> + /// <param name="value"></param> + /// <returns></returns> + public static Result<T> Success(T value) => new(value); + /// <summary> + /// Creates a failure result + /// </summary> + /// <param name="error"></param> + /// <returns></returns> + public static new Result<T> Failure(Error error) => new(error); } diff --git a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs index 9a80bd15..684f365d 100644 --- a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs +++ b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs @@ -19,99 +19,98 @@ using System.Linq.Expressions; using System.Reflection; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public class ApplicationOptionsTimeSpanParser { - public class ApplicationOptionsTimeSpanParser - { - private readonly ILocalStorageOptionsProvider _localStorageOptionsProvider; + readonly ILocalStorageOptionsProvider _localStorageOptionsProvider; - private ApplicationOptions? applicationOptions; - private readonly Task? _initTask; - private bool disposedValue; + ApplicationOptions? applicationOptions; + readonly Task? _initTask; + bool disposedValue; - public ApplicationOptionsTimeSpanParser(ILocalStorageOptionsProvider localStorageOptionsProvider) - { - _localStorageOptionsProvider = localStorageOptionsProvider; - _localStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved; - _initTask = InitAsync(); - } + public ApplicationOptionsTimeSpanParser(ILocalStorageOptionsProvider localStorageOptionsProvider) + { + _localStorageOptionsProvider = localStorageOptionsProvider; + _localStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved; + _initTask = InitAsync(); + } - public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, TProperty>> expression, String value) + public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, TProperty>> expression, String value) + { + if (expression.Body is not MemberExpression memberExpression) { - if (expression.Body is not MemberExpression memberExpression) - { - throw new ArgumentException("'expression' should be a member expression"); - } - await EnsureInitializedAsync(); - TimeSpan? result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); - switch (memberExpression.Member.MemberType) - { - case MemberTypes.Property: - ((PropertyInfo)memberExpression.Member).SetValue(entity, result); - break; - default: - throw new NotImplementedException(); - } + throw new ArgumentException("'expression' should be a member expression"); } - - public async Task<TimeSpan?> GetTimespanAsync(String value) + await EnsureInitializedAsync(); + TimeSpan? result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); + switch (memberExpression.Member.MemberType) { - await EnsureInitializedAsync(); - TimeSpan? result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); - return result; + case MemberTypes.Property: + ((PropertyInfo)memberExpression.Member).SetValue(entity, result); + break; + default: + throw new NotImplementedException(); } + } - public string? GetTimespanFormatted(TimeSpan? timeSpan) + public async Task<TimeSpan?> GetTimespanAsync(String value) + { + await EnsureInitializedAsync(); + TimeSpan? result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); + return result; + } + + public string? GetTimespanFormatted(TimeSpan? timeSpan) + { + string? formatted = null; + EnsureInitializedAsync().GetAwaiter().GetResult(); + if (timeSpan.HasValue) { - string? formatted = null; - EnsureInitializedAsync().GetAwaiter().GetResult(); - if (timeSpan.HasValue) + try { - try - { - formatted = timeSpan.Value.ToString(applicationOptions?.DisplayTimeSpanFormat); - } - catch (FormatException) - { - formatted = timeSpan.Value.ToString(); - } + formatted = timeSpan.Value.ToString(applicationOptions?.DisplayTimeSpanFormat); + } + catch (FormatException) + { + formatted = timeSpan.Value.ToString(); } - return formatted; } + return formatted; + } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) { - if (!disposedValue) + if (disposing) { - if (disposing) - { - // Verwalteten Zustand (verwaltete Objekte) bereinigen - _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; - } - - disposedValue = true; + // Verwalteten Zustand (verwaltete Objekte) bereinigen + _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; } - } - private async Task InitAsync() - { - applicationOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); + disposedValue = true; } + } - private async Task EnsureInitializedAsync() + async Task InitAsync() + { + applicationOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); + } + + async Task EnsureInitializedAsync() + { + if (_initTask != null) { - if (_initTask != null) - { - await _initTask; - } + await _initTask; } + } - private void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions options) + void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions options) + { + if (options is ApplicationOptions applicationOption) { - if (options is ApplicationOptions applicationOption) - { - applicationOptions = applicationOption; - } + applicationOptions = applicationOption; } } } diff --git a/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs b/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs index df9b58a7..26347c5c 100644 --- a/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs +++ b/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs @@ -15,44 +15,43 @@ //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Services.Provider; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public class AutocompleteManager(MusicBrainzDataProvider musicBrainzDataProvider) { - public class AutocompleteManager(MusicBrainzDataProvider musicBrainzDataProvider) - { - private readonly MusicBrainzDataProvider _musicBrainzDataProvider = musicBrainzDataProvider; + readonly MusicBrainzDataProvider _musicBrainzDataProvider = musicBrainzDataProvider; - public async Task<IEnumerable<MusicBrainzArtist>> SearchArtistsAsync(String? searchString, CancellationToken cancellationToken) + public async Task<IEnumerable<MusicBrainzArtist>> SearchArtistsAsync(String? searchString, CancellationToken cancellationToken) + { + try + { + var artists = await _musicBrainzDataProvider.SearchArtistAsync(searchString, cancellationToken); + return artists; + } + catch (TaskCanceledException) + { + return []; + } + catch (OperationCanceledException) { - try - { - var artists = await _musicBrainzDataProvider.SearchArtistAsync(searchString, cancellationToken); - return artists; - } - catch (TaskCanceledException) - { - return []; - } - catch (OperationCanceledException) - { - return []; - } + return []; } + } - public async Task<IEnumerable<MusicBrainzTrack>> SearchTitlesAsync(String? searchString, String? artist, CancellationToken cancellationToken) + public async Task<IEnumerable<MusicBrainzTrack>> SearchTitlesAsync(String? searchString, String? artist, CancellationToken cancellationToken) + { + try + { + var tracks = await _musicBrainzDataProvider.SearchTitleAsync(searchString, artist, cancellationToken); + return tracks; + } + catch (TaskCanceledException) + { + return []; + } + catch (OperationCanceledException) { - try - { - var tracks = await _musicBrainzDataProvider.SearchTitleAsync(searchString, artist, cancellationToken); - return tracks; - } - catch (TaskCanceledException) - { - return []; - } - catch (OperationCanceledException) - { - return []; - } + return []; } } } diff --git a/AudioCuesheetEditor/Services/UI/DialogManager.cs b/AudioCuesheetEditor/Services/UI/DialogManager.cs index f8712578..5ca11e27 100644 --- a/AudioCuesheetEditor/Services/UI/DialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/DialogManager.cs @@ -20,237 +20,236 @@ using AudioCuesheetEditor.Shared.Dialogs; using MudBlazor; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public class DialogManager(IDialogService dialogService, ITraceChangeManager traceChangeManager, ITrackManager trackManager, ISessionStateContainer sessionStateContainer) : IDialogManager { - public class DialogManager(IDialogService dialogService, ITraceChangeManager traceChangeManager, ITrackManager trackManager, ISessionStateContainer sessionStateContainer) : IDialogManager - { - private readonly IDialogService _dialogService = dialogService; - private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; - private readonly ITrackManager _trackManager = trackManager; - private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + readonly IDialogService _dialogService = dialogService; + readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + readonly ITrackManager _trackManager = trackManager; + readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; - private IDialogReference? _loadingDialog; + IDialogReference? _loadingDialog; - public async Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks) + public async Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks) + { + _traceChangeManager.BulkEdit = true; + if (tracks.Count() == 1) { - _traceChangeManager.BulkEdit = true; - if (tracks.Count() == 1) + var parameters = new DialogParameters<EditTrackModal> { { x => x.EditedTrack, _trackManager.Clone(tracks.First()) } }; + var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; + var dialog = await _dialogService.ShowAsync<EditTrackModal>(null, parameters, options); + var result = await dialog.Result; + if ((result?.Canceled == false) && (result.Data is Track editedTrack)) { - var parameters = new DialogParameters<EditTrackModal> { { x => x.EditedTrack, _trackManager.Clone(tracks.First()) } }; - var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; - var dialog = await _dialogService.ShowAsync<EditTrackModal>(null, parameters, options); - var result = await dialog.Result; - if ((result?.Canceled == false) && (result.Data is Track editedTrack)) - { - _trackManager.CopyValues(editedTrack, tracks.First()); - _trackManager.RecalculateLinkedTracksProperties(tracks.First()); - } + _trackManager.CopyValues(editedTrack, tracks.First()); + _trackManager.RecalculateLinkedTracksProperties(tracks.First()); } - if (tracks.Count() > 1) + } + if (tracks.Count() > 1) + { + var parameters = new DialogParameters<EditMultipleTracksModal> { { x => x.EditedTrack, new() } }; + var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; + var dialog = await _dialogService.ShowAsync<EditMultipleTracksModal>(null, parameters, options); + var result = await dialog.Result; + if ((result?.Canceled == false) && (result.Data is EditMultipleTracksModalResult editMultipleTracksModalResult)) { - var parameters = new DialogParameters<EditMultipleTracksModal> { { x => x.EditedTrack, new() } }; - var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; - var dialog = await _dialogService.ShowAsync<EditMultipleTracksModal>(null, parameters, options); - var result = await dialog.Result; - if ((result?.Canceled == false) && (result.Data is EditMultipleTracksModalResult editMultipleTracksModalResult)) + foreach (var track in tracks) { - foreach (var track in tracks) + var position = editMultipleTracksModalResult.EditedTrack.Position; + var begin = editMultipleTracksModalResult.EditedTrack.Begin; + var end = editMultipleTracksModalResult.EditedTrack.End; + var length = editMultipleTracksModalResult.EditedTrack.Length; + var preGap = editMultipleTracksModalResult.EditedTrack.PreGap; + var postGap = editMultipleTracksModalResult.EditedTrack.PostGap; + Boolean copyIsLinkedToPreviousTrack = editMultipleTracksModalResult.IsLinkedToPreviousTrackEditMode == DynamicEditValue.EnteredValueEquals; + Boolean copyTrackArtist = editMultipleTracksModalResult.ArtistEditMode == DynamicEditValue.EnteredValueEquals; + Boolean copyTrackTitle = editMultipleTracksModalResult.TitleEditMode == DynamicEditValue.EnteredValueEquals; + Boolean copyTrackBegin = true; + Boolean copyTrackEnd = true; + Boolean copyTrackLength = true; + Boolean copyTrackFlags = editMultipleTracksModalResult.FlagsEditMode == DynamicEditValue.EnteredValueEquals; + Boolean copyTrackPreGap = true; + Boolean copyTrackPostGap = true; + //First process dynamic edit, because we need to increase each value separately + switch (editMultipleTracksModalResult.BeginEditMode) { - var position = editMultipleTracksModalResult.EditedTrack.Position; - var begin = editMultipleTracksModalResult.EditedTrack.Begin; - var end = editMultipleTracksModalResult.EditedTrack.End; - var length = editMultipleTracksModalResult.EditedTrack.Length; - var preGap = editMultipleTracksModalResult.EditedTrack.PreGap; - var postGap = editMultipleTracksModalResult.EditedTrack.PostGap; - Boolean copyIsLinkedToPreviousTrack = editMultipleTracksModalResult.IsLinkedToPreviousTrackEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackArtist = editMultipleTracksModalResult.ArtistEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackTitle = editMultipleTracksModalResult.TitleEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackBegin = true; - Boolean copyTrackEnd = true; - Boolean copyTrackLength = true; - Boolean copyTrackFlags = editMultipleTracksModalResult.FlagsEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackPreGap = true; - Boolean copyTrackPostGap = true; - //First process dynamic edit, because we need to increase each value separately - switch (editMultipleTracksModalResult.BeginEditMode) - { - case DynamicEditValue.DoNotChange: - copyTrackBegin = false; - break; - case DynamicEditValue.EnteredValueEquals: - copyTrackBegin = true; - break; - case DynamicEditValue.EnteredValueAdd: - var newValue = editMultipleTracksModalResult.EditedTrack.Begin + track.Begin; - editMultipleTracksModalResult.EditedTrack.Begin = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: copyTrackBegin, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); - copyTrackBegin = false; - break; - case DynamicEditValue.EnteredValueSubstract: - newValue = track.Begin - editMultipleTracksModalResult.EditedTrack.Begin; - editMultipleTracksModalResult.EditedTrack.Begin = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: copyTrackBegin, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); - copyTrackBegin = false; - break; - } - switch (editMultipleTracksModalResult.EndEditMode) - { - case DynamicEditValue.DoNotChange: - copyTrackEnd = false; - break; - case DynamicEditValue.EnteredValueEquals: - copyTrackEnd = true; - break; - case DynamicEditValue.EnteredValueAdd: - var newValue = editMultipleTracksModalResult.EditedTrack.End + track.End; - editMultipleTracksModalResult.EditedTrack.End = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: copyTrackEnd, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); - copyTrackEnd = false; - break; - case DynamicEditValue.EnteredValueSubstract: - newValue = track.End - editMultipleTracksModalResult.EditedTrack.End; - editMultipleTracksModalResult.EditedTrack.End = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: copyTrackEnd, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); - copyTrackEnd = false; - break; - } - switch (editMultipleTracksModalResult.LengthEditMode) - { - case DynamicEditValue.DoNotChange: - copyTrackLength = false; - break; - case DynamicEditValue.EnteredValueEquals: - copyTrackLength = true; - break; - case DynamicEditValue.EnteredValueAdd: - var newValue = editMultipleTracksModalResult.EditedTrack.Length + track.Length; - editMultipleTracksModalResult.EditedTrack.Length = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: copyTrackLength, setFlags: false, setPreGap: false, setPostGap: false); - copyTrackLength = false; - break; - case DynamicEditValue.EnteredValueSubstract: - newValue = track.Length - editMultipleTracksModalResult.EditedTrack.Length; - editMultipleTracksModalResult.EditedTrack.Length = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: copyTrackLength, setFlags: false, setPreGap: false, setPostGap: false); - copyTrackLength = false; - break; - } - switch (editMultipleTracksModalResult.PregapEditMode) - { - case DynamicEditValue.DoNotChange: - copyTrackPreGap = false; - break; - case DynamicEditValue.EnteredValueEquals: - copyTrackPreGap = true; - break; - case DynamicEditValue.EnteredValueAdd: - var newValue = editMultipleTracksModalResult.EditedTrack.PreGap + track.PreGap; - editMultipleTracksModalResult.EditedTrack.PreGap = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: copyTrackPreGap, setPostGap: false); - copyTrackPreGap = false; - break; - case DynamicEditValue.EnteredValueSubstract: - newValue = track.PreGap - editMultipleTracksModalResult.EditedTrack.PreGap; - editMultipleTracksModalResult.EditedTrack.PreGap = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: copyTrackPreGap, setPostGap: false); - copyTrackPreGap = false; - break; - } - switch (editMultipleTracksModalResult.PostgapEditMode) - { - case DynamicEditValue.DoNotChange: - copyTrackPostGap = false; - break; - case DynamicEditValue.EnteredValueEquals: - copyTrackPostGap = true; - break; - case DynamicEditValue.EnteredValueAdd: - var newValue = editMultipleTracksModalResult.EditedTrack.PostGap + track.PostGap; - editMultipleTracksModalResult.EditedTrack.PostGap = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: copyTrackPostGap); - copyTrackPostGap = false; - break; - case DynamicEditValue.EnteredValueSubstract: - newValue = track.PostGap - editMultipleTracksModalResult.EditedTrack.PostGap; - editMultipleTracksModalResult.EditedTrack.PostGap = newValue; - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: copyTrackPostGap); - copyTrackPostGap = false; - break; - } - editMultipleTracksModalResult.EditedTrack.Position = position; - editMultipleTracksModalResult.EditedTrack.Begin = begin; - editMultipleTracksModalResult.EditedTrack.End = end; - editMultipleTracksModalResult.EditedTrack.Length = length; - editMultipleTracksModalResult.EditedTrack.PreGap = preGap; - editMultipleTracksModalResult.EditedTrack.PostGap = postGap; - //Now copy all values - _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: copyIsLinkedToPreviousTrack, setPosition: false, setArtist: copyTrackArtist, setTitle: copyTrackTitle, setBegin: copyTrackBegin, setEnd: copyTrackEnd, setLength: copyTrackLength, setFlags: copyTrackFlags, setPreGap: copyTrackPreGap, setPostGap: copyTrackPostGap); + case DynamicEditValue.DoNotChange: + copyTrackBegin = false; + break; + case DynamicEditValue.EnteredValueEquals: + copyTrackBegin = true; + break; + case DynamicEditValue.EnteredValueAdd: + var newValue = editMultipleTracksModalResult.EditedTrack.Begin + track.Begin; + editMultipleTracksModalResult.EditedTrack.Begin = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: copyTrackBegin, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); + copyTrackBegin = false; + break; + case DynamicEditValue.EnteredValueSubstract: + newValue = track.Begin - editMultipleTracksModalResult.EditedTrack.Begin; + editMultipleTracksModalResult.EditedTrack.Begin = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: copyTrackBegin, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); + copyTrackBegin = false; + break; } + switch (editMultipleTracksModalResult.EndEditMode) + { + case DynamicEditValue.DoNotChange: + copyTrackEnd = false; + break; + case DynamicEditValue.EnteredValueEquals: + copyTrackEnd = true; + break; + case DynamicEditValue.EnteredValueAdd: + var newValue = editMultipleTracksModalResult.EditedTrack.End + track.End; + editMultipleTracksModalResult.EditedTrack.End = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: copyTrackEnd, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); + copyTrackEnd = false; + break; + case DynamicEditValue.EnteredValueSubstract: + newValue = track.End - editMultipleTracksModalResult.EditedTrack.End; + editMultipleTracksModalResult.EditedTrack.End = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: copyTrackEnd, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); + copyTrackEnd = false; + break; + } + switch (editMultipleTracksModalResult.LengthEditMode) + { + case DynamicEditValue.DoNotChange: + copyTrackLength = false; + break; + case DynamicEditValue.EnteredValueEquals: + copyTrackLength = true; + break; + case DynamicEditValue.EnteredValueAdd: + var newValue = editMultipleTracksModalResult.EditedTrack.Length + track.Length; + editMultipleTracksModalResult.EditedTrack.Length = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: copyTrackLength, setFlags: false, setPreGap: false, setPostGap: false); + copyTrackLength = false; + break; + case DynamicEditValue.EnteredValueSubstract: + newValue = track.Length - editMultipleTracksModalResult.EditedTrack.Length; + editMultipleTracksModalResult.EditedTrack.Length = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: copyTrackLength, setFlags: false, setPreGap: false, setPostGap: false); + copyTrackLength = false; + break; + } + switch (editMultipleTracksModalResult.PregapEditMode) + { + case DynamicEditValue.DoNotChange: + copyTrackPreGap = false; + break; + case DynamicEditValue.EnteredValueEquals: + copyTrackPreGap = true; + break; + case DynamicEditValue.EnteredValueAdd: + var newValue = editMultipleTracksModalResult.EditedTrack.PreGap + track.PreGap; + editMultipleTracksModalResult.EditedTrack.PreGap = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: copyTrackPreGap, setPostGap: false); + copyTrackPreGap = false; + break; + case DynamicEditValue.EnteredValueSubstract: + newValue = track.PreGap - editMultipleTracksModalResult.EditedTrack.PreGap; + editMultipleTracksModalResult.EditedTrack.PreGap = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: copyTrackPreGap, setPostGap: false); + copyTrackPreGap = false; + break; + } + switch (editMultipleTracksModalResult.PostgapEditMode) + { + case DynamicEditValue.DoNotChange: + copyTrackPostGap = false; + break; + case DynamicEditValue.EnteredValueEquals: + copyTrackPostGap = true; + break; + case DynamicEditValue.EnteredValueAdd: + var newValue = editMultipleTracksModalResult.EditedTrack.PostGap + track.PostGap; + editMultipleTracksModalResult.EditedTrack.PostGap = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: copyTrackPostGap); + copyTrackPostGap = false; + break; + case DynamicEditValue.EnteredValueSubstract: + newValue = track.PostGap - editMultipleTracksModalResult.EditedTrack.PostGap; + editMultipleTracksModalResult.EditedTrack.PostGap = newValue; + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: false, setLength: false, setFlags: false, setPreGap: false, setPostGap: copyTrackPostGap); + copyTrackPostGap = false; + break; + } + editMultipleTracksModalResult.EditedTrack.Position = position; + editMultipleTracksModalResult.EditedTrack.Begin = begin; + editMultipleTracksModalResult.EditedTrack.End = end; + editMultipleTracksModalResult.EditedTrack.Length = length; + editMultipleTracksModalResult.EditedTrack.PreGap = preGap; + editMultipleTracksModalResult.EditedTrack.PostGap = postGap; + //Now copy all values + _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: copyIsLinkedToPreviousTrack, setPosition: false, setArtist: copyTrackArtist, setTitle: copyTrackTitle, setBegin: copyTrackBegin, setEnd: copyTrackEnd, setLength: copyTrackLength, setFlags: copyTrackFlags, setPreGap: copyTrackPreGap, setPostGap: copyTrackPostGap); } } - _traceChangeManager.BulkEdit = false; } + _traceChangeManager.BulkEdit = false; + } - public async Task ShowLoadingDialogAsync() + public async Task ShowLoadingDialogAsync() + { + if (_loadingDialog == null) { - if (_loadingDialog == null) - { - var options = new DialogOptions() { BackdropClick = false, FullWidth = true, MaxWidth = MaxWidth.ExtraSmall, NoHeader = true }; - _loadingDialog = await _dialogService.ShowAsync<LoadingDialog>(options); - await Task.Delay(1); - } + var options = new DialogOptions() { BackdropClick = false, FullWidth = true, MaxWidth = MaxWidth.ExtraSmall, NoHeader = true }; + _loadingDialog = await _dialogService.ShowAsync<LoadingDialog>(options); + await Task.Delay(1); } + } - public void HideLoadingDialog() - { - _loadingDialog?.Close(); - _loadingDialog = null; - } + public void HideLoadingDialog() + { + _loadingDialog?.Close(); + _loadingDialog = null; + } - public async Task<Boolean> ShowImportAudiofilesDialogAsync() + public async Task<Boolean> ShowImportAudiofilesDialogAsync() + { + var parameters = new DialogParameters<ImportAudiofilesDialog> { - var parameters = new DialogParameters<ImportAudiofilesDialog> - { - { x => x.MappedAudiofiles, _sessionStateContainer.ImportAudiofileMapping }, - { x => x.ImportAudiofiles, _sessionStateContainer.ImportAudiofiles } - }; - var options = new DialogOptions() { BackdropClick = false, FullWidth = true }; - var dialog = await _dialogService.ShowAsync<ImportAudiofilesDialog>(null, parameters, options); - var result = await dialog.Result; - var canceled = result?.Canceled ?? true; - if (canceled == false) + { x => x.MappedAudiofiles, _sessionStateContainer.ImportAudiofileMapping }, + { x => x.ImportAudiofiles, _sessionStateContainer.ImportAudiofiles } + }; + var options = new DialogOptions() { BackdropClick = false, FullWidth = true }; + var dialog = await _dialogService.ShowAsync<ImportAudiofilesDialog>(null, parameters, options); + var result = await dialog.Result; + var canceled = result?.Canceled ?? true; + if (canceled == false) + { + if (result?.Data is Dictionary<Audiofile, Audiofile?> audiofileMapping) { - if (result?.Data is Dictionary<Audiofile, Audiofile?> audiofileMapping) - { - _sessionStateContainer.ImportAudiofileMapping = audiofileMapping; - } + _sessionStateContainer.ImportAudiofileMapping = audiofileMapping; } - return canceled; } + return canceled; + } - /// <inheritdoc/> - public async Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? OkText = "Ok", string? OkButtonStartIcon = null) + /// <inheritdoc/> + public async Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? OkText = "Ok", string? OkButtonStartIcon = null) + { + var parameters = new DialogParameters<InputDialog<T>> { - var parameters = new DialogParameters<InputDialog<T>> - { - { x => x.Placeholder, placeholder }, - { x => x.Label, label }, - { x => x.InitialValue, initialValue }, - { x => x.OkText, OkText }, - { x => x.OkButtonStartIcon, OkButtonStartIcon } - }; - var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; - var dialog = await _dialogService.ShowAsync<InputDialog<T>>(title, parameters, options); - var result = await dialog.Result; - if (result?.Canceled == false) - { - var value = (T)result.Data!; - return Result<T>.Success(value); - } - else - { - return Result<T>.Failure(new Error(ErrorType.Aborted, "User canceled the input dialog.")); - } + { x => x.Placeholder, placeholder }, + { x => x.Label, label }, + { x => x.InitialValue, initialValue }, + { x => x.OkText, OkText }, + { x => x.OkButtonStartIcon, OkButtonStartIcon } + }; + var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; + var dialog = await _dialogService.ShowAsync<InputDialog<T>>(title, parameters, options); + var result = await dialog.Result; + if (result?.Canceled == false) + { + var value = (T)result.Data!; + return Result<T>.Success(value); + } + else + { + return Result<T>.Failure(new Error(ErrorType.Aborted, "User canceled the input dialog.")); } } } diff --git a/AudioCuesheetEditor/Services/UI/IDialogManager.cs b/AudioCuesheetEditor/Services/UI/IDialogManager.cs index 1394af97..cc9109cf 100644 --- a/AudioCuesheetEditor/Services/UI/IDialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/IDialogManager.cs @@ -16,25 +16,24 @@ using AudioCuesheetEditor.Model.AudioCuesheet; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public interface IDialogManager { - public interface IDialogManager - { - void HideLoadingDialog(); - Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks); - Task<bool> ShowImportAudiofilesDialogAsync(); - Task ShowLoadingDialogAsync(); - /// <summary> - /// Show input dialog and wait for user input. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="title"></param> - /// <param name="placeholder"></param> - /// <param name="label"></param> - /// <param name="initialValue"></param> - /// <param name="OkText"></param> - /// <param name="OkButtonStartIcon"></param> - /// <returns></returns> - Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? OkText = "Ok", string? OkButtonStartIcon = null); - } + void HideLoadingDialog(); + Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks); + Task<bool> ShowImportAudiofilesDialogAsync(); + Task ShowLoadingDialogAsync(); + /// <summary> + /// Show input dialog and wait for user input. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="title"></param> + /// <param name="placeholder"></param> + /// <param name="label"></param> + /// <param name="initialValue"></param> + /// <param name="OkText"></param> + /// <param name="OkButtonStartIcon"></param> + /// <returns></returns> + Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? OkText = "Ok", string? OkButtonStartIcon = null); } \ No newline at end of file diff --git a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs index 8267e2ed..3e149312 100644 --- a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs @@ -17,28 +17,27 @@ using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Model.IO.Import; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public interface ISessionStateContainer { - public interface ISessionStateContainer - { - public event EventHandler? CuesheetChanged; - public event EventHandler? ActiveCuesheetChanged; - public Cuesheet Cuesheet { get; set; } - public Cuesheet? ImportCuesheet { get; set; } - public IList<Audiofile> ImportAudiofiles { get; set; } - public Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } - public IImportfile? Importfile { get; set; } - public Boolean ImportIsAnalyzed { get; set; } - public Task ResetImportAsync(Boolean revokeObjectURLs); - public Task ResetAudioImportAsync(Boolean revokeObjectURLs); - /// <summary> - /// Initialize this class - /// </summary> - /// <returns></returns> - Task InitializeAsync(); - /// <summary> - /// Get current cuesheet based on current view - /// </summary> - public Cuesheet? ActiveCuesheet { get; } - } + event EventHandler? CuesheetChanged; + event EventHandler? ActiveCuesheetChanged; + Cuesheet Cuesheet { get; set; } + Cuesheet? ImportCuesheet { get; set; } + IList<Audiofile> ImportAudiofiles { get; set; } + Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } + IImportfile? Importfile { get; set; } + Boolean ImportIsAnalyzed { get; set; } + Task ResetImportAsync(Boolean revokeObjectURLs); + Task ResetAudioImportAsync(Boolean revokeObjectURLs); + /// <summary> + /// Initialize this class + /// </summary> + /// <returns></returns> + Task InitializeAsync(); + /// <summary> + /// Get current cuesheet based on current view + /// </summary> + Cuesheet? ActiveCuesheet { get; } } diff --git a/AudioCuesheetEditor/Services/UI/ITraceChangeManager.cs b/AudioCuesheetEditor/Services/UI/ITraceChangeManager.cs index 4aec1c11..db98d384 100644 --- a/AudioCuesheetEditor/Services/UI/ITraceChangeManager.cs +++ b/AudioCuesheetEditor/Services/UI/ITraceChangeManager.cs @@ -15,33 +15,32 @@ //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Model.UI; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +/// <summary> +/// Manager for Undo and Redo operations on objects. +/// </summary> +public interface ITraceChangeManager { + event EventHandler? TracedObjectHistoryChanged; + event EventHandler? UndoDone; + event EventHandler? RedoDone; + /// <summary> + /// Is Undo() currently possible (are there any changes)? + /// </summary> + bool CanUndo { get; } + /// <summary> + /// Is Redo() currently possible (are there any changes)? + /// </summary> + bool CanRedo { get; } + bool BulkEdit { get; set; } /// <summary> - /// Manager for Undo and Redo operations on objects. + /// Adds a change of a property /// </summary> - public interface ITraceChangeManager - { - public event EventHandler? TracedObjectHistoryChanged; - public event EventHandler? UndoDone; - public event EventHandler? RedoDone; - /// <summary> - /// Is Undo() currently possible (are there any changes)? - /// </summary> - public bool CanUndo { get; } - /// <summary> - /// Is Redo() currently possible (are there any changes)? - /// </summary> - public bool CanRedo { get; } - public bool BulkEdit { get; set; } - /// <summary> - /// Adds a change of a property - /// </summary> - /// <param name="tracedChange"></param> - void AddChange(TracedChange tracedChange); - public void Reset(); - public void Undo(); - public void Redo(); - public void RemoveTracedChanges(IEnumerable<object> traceables); - } + /// <param name="tracedChange"></param> + void AddChange(TracedChange tracedChange); + void Reset(); + void Undo(); + void Redo(); + void RemoveTracedChanges(IEnumerable<object> traceables); } diff --git a/AudioCuesheetEditor/Services/UI/LocalizationService.cs b/AudioCuesheetEditor/Services/UI/LocalizationService.cs index 1aeb8b2e..7de8e115 100644 --- a/AudioCuesheetEditor/Services/UI/LocalizationService.cs +++ b/AudioCuesheetEditor/Services/UI/LocalizationService.cs @@ -19,57 +19,56 @@ using Microsoft.JSInterop; using System.Globalization; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public class LocalizationService(ILocalStorageOptionsProvider localStorageOptionsProvider, NavigationManager navigationManager, IJSRuntime jsRuntime) { - public class LocalizationService(ILocalStorageOptionsProvider localStorageOptionsProvider, NavigationManager navigationManager, IJSRuntime jsRuntime) - { - private readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider; - private readonly NavigationManager _navigationManager = navigationManager; - private readonly IJSRuntime _jsRuntime = jsRuntime; + readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider; + readonly NavigationManager _navigationManager = navigationManager; + readonly IJSRuntime _jsRuntime = jsRuntime; - public const String DefaultCulture = "en-US"; + public const String DefaultCulture = "en-US"; - public static IReadOnlyCollection<CultureInfo> AvailableCultures + public static IReadOnlyCollection<CultureInfo> AvailableCultures + { + get { - get + var cultures = new List<CultureInfo> { - var cultures = new List<CultureInfo> - { - new(DefaultCulture), - new("de-DE") - }; - return cultures.AsReadOnly(); - } + new(DefaultCulture), + new("de-DE") + }; + return cultures.AsReadOnly(); } + } - public static CultureInfo SelectedCulture => CultureInfo.DefaultThreadCurrentUICulture ?? CultureInfo.CurrentUICulture; + public static CultureInfo SelectedCulture => CultureInfo.DefaultThreadCurrentUICulture ?? CultureInfo.CurrentUICulture; - public async Task SetCultureFromConfigurationAsync() - { - var options = await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); + public async Task SetCultureFromConfigurationAsync() + { + var options = await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); - ChangeLanguage(options.Culture); - } + ChangeLanguage(options.Culture); + } - public async Task ChangeLanguageAsync(CultureInfo culture) + public async Task ChangeLanguageAsync(CultureInfo culture) + { + if (ChangeLanguage(culture)) { - if (ChangeLanguage(culture)) - { - await _localStorageOptionsProvider.SaveOptionsValueAsync<ApplicationOptions>(x => x.CultureName!, culture.Name); - await _jsRuntime.InvokeVoidAsync("removeBeforeunload"); - _navigationManager.NavigateTo(_navigationManager.Uri, true); - } + await _localStorageOptionsProvider.SaveOptionsValueAsync<ApplicationOptions>(x => x.CultureName!, culture.Name); + await _jsRuntime.InvokeVoidAsync("removeBeforeunload"); + _navigationManager.NavigateTo(_navigationManager.Uri, true); } + } - private static Boolean ChangeLanguage(CultureInfo newCulture) + static Boolean ChangeLanguage(CultureInfo newCulture) + { + var contains = AvailableCultures.Contains(newCulture); + if (contains) { - var contains = AvailableCultures.Contains(newCulture); - if (contains) - { - CultureInfo.DefaultThreadCurrentUICulture = newCulture; - CultureInfo.DefaultThreadCurrentCulture = newCulture; - } - return contains; + CultureInfo.DefaultThreadCurrentUICulture = newCulture; + CultureInfo.DefaultThreadCurrentCulture = newCulture; } + return contains; } } diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index 3a8caa84..c8b143e5 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -20,144 +20,143 @@ using AudioCuesheetEditor.Services.Options; using Microsoft.JSInterop; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +public class SessionStateContainer : ISessionStateContainer, IDisposable { - public class SessionStateContainer : ISessionStateContainer, IDisposable - { - private readonly ILocalStorageOptionsProvider _localStorageOptionsProvider; - private readonly IJSRuntime _jsRuntime; + readonly ILocalStorageOptionsProvider _localStorageOptionsProvider; + readonly IJSRuntime _jsRuntime; - private Cuesheet _cuesheet = new(); - private Cuesheet? _importCuesheet; - private Cuesheet? _activeCuesheet; - private ViewOptions? _viewOptions; - private bool disposedValue; + Cuesheet _cuesheet = new(); + Cuesheet? _importCuesheet; + Cuesheet? _activeCuesheet; + ViewOptions? _viewOptions; + bool disposedValue; - public event EventHandler? CuesheetChanged; - public event EventHandler? ActiveCuesheetChanged; + public event EventHandler? CuesheetChanged; + public event EventHandler? ActiveCuesheetChanged; - public SessionStateContainer(ILocalStorageOptionsProvider localStorageOptionsProvider, IJSRuntime jsRuntime) - { - _localStorageOptionsProvider = localStorageOptionsProvider; - _localStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved; - _jsRuntime = jsRuntime; - } + public SessionStateContainer(ILocalStorageOptionsProvider localStorageOptionsProvider, IJSRuntime jsRuntime) + { + _localStorageOptionsProvider = localStorageOptionsProvider; + _localStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved; + _jsRuntime = jsRuntime; + } - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } - public Cuesheet Cuesheet - { - get => _cuesheet; - set - { - _cuesheet = value; - SetActiveCuesheet(); - CuesheetChanged?.Invoke(this, EventArgs.Empty); - } - } - public Cuesheet? ImportCuesheet + public Cuesheet Cuesheet + { + get => _cuesheet; + set { - get => _importCuesheet; - set - { - _importCuesheet = value; - SetActiveCuesheet(); - } + _cuesheet = value; + SetActiveCuesheet(); + CuesheetChanged?.Invoke(this, EventArgs.Empty); } - public IList<Audiofile> ImportAudiofiles { get; set; } = []; - public Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } = []; - public IImportfile? Importfile { get; set; } - public Boolean ImportIsAnalyzed { get; set; } = false; - - /// <inheritdoc/> - public async Task InitializeAsync() + } + public Cuesheet? ImportCuesheet + { + get => _importCuesheet; + set { - _viewOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ViewOptions>(); + _importCuesheet = value; SetActiveCuesheet(); } + } + public IList<Audiofile> ImportAudiofiles { get; set; } = []; + public Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } = []; + public IImportfile? Importfile { get; set; } + public Boolean ImportIsAnalyzed { get; set; } = false; - public async Task ResetImportAsync(Boolean revokeObjectURLs) - { - Importfile = null; - await ResetAudioImportAsync(revokeObjectURLs); - ImportCuesheet = null; - ImportIsAnalyzed = false; - } + /// <inheritdoc/> + public async Task InitializeAsync() + { + _viewOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ViewOptions>(); + SetActiveCuesheet(); + } - public async Task ResetAudioImportAsync(bool revokeObjectURLs) + public async Task ResetImportAsync(Boolean revokeObjectURLs) + { + Importfile = null; + await ResetAudioImportAsync(revokeObjectURLs); + ImportCuesheet = null; + ImportIsAnalyzed = false; + } + + public async Task ResetAudioImportAsync(bool revokeObjectURLs) + { + if (revokeObjectURLs) { - if (revokeObjectURLs) + foreach (var audiofile in ImportAudiofiles) { - foreach (var audiofile in ImportAudiofiles) + if (!string.IsNullOrEmpty(audiofile.ObjectURL)) { - if (!string.IsNullOrEmpty(audiofile.ObjectURL)) - { - await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); - } + await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); } - foreach (var audiofile in ImportAudiofileMapping.Values.Where(x => x != null)) + } + foreach (var audiofile in ImportAudiofileMapping.Values.Where(x => x != null)) + { + if (!string.IsNullOrEmpty(audiofile!.ObjectURL)) { - if (!string.IsNullOrEmpty(audiofile!.ObjectURL)) - { - await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); - } + await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); } } - ImportAudiofileMapping = []; - ImportAudiofiles = []; } + ImportAudiofileMapping = []; + ImportAudiofiles = []; + } - /// <inheritdoc/> - public Cuesheet? ActiveCuesheet => _activeCuesheet; + /// <inheritdoc/> + public Cuesheet? ActiveCuesheet => _activeCuesheet; - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) { - if (!disposedValue) + if (disposing) { - if (disposing) - { - _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; - } - disposedValue = true; + _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; } + disposedValue = true; } + } - void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions options) + void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions options) + { + if (options is ViewOptions viewOptions) { - if (options is ViewOptions viewOptions) - { - _viewOptions = viewOptions; - SetActiveCuesheet(); - } + _viewOptions = viewOptions; + SetActiveCuesheet(); } + } - void SetActiveCuesheet() + void SetActiveCuesheet() + { + if (_viewOptions == null) { - if (_viewOptions == null) - { - throw new InvalidOperationException("Not initialized!"); - } - if (_viewOptions.ActiveTab == ViewMode.ImportView) + throw new InvalidOperationException("Not initialized!"); + } + if (_viewOptions.ActiveTab == ViewMode.ImportView) + { + if (_activeCuesheet != ImportCuesheet) { - if (_activeCuesheet != ImportCuesheet) - { - _activeCuesheet = ImportCuesheet; - ActiveCuesheetChanged?.Invoke(this, EventArgs.Empty); - } + _activeCuesheet = ImportCuesheet; + ActiveCuesheetChanged?.Invoke(this, EventArgs.Empty); } - else + } + else + { + if (_activeCuesheet != Cuesheet) { - if (_activeCuesheet != Cuesheet) - { - _activeCuesheet = Cuesheet; - ActiveCuesheetChanged?.Invoke(this, EventArgs.Empty); - } + _activeCuesheet = Cuesheet; + ActiveCuesheetChanged?.Invoke(this, EventArgs.Empty); } } - } + } diff --git a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs index 192c3866..87818879 100644 --- a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs +++ b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs @@ -15,201 +15,200 @@ //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Model.UI; -namespace AudioCuesheetEditor.Services.UI +namespace AudioCuesheetEditor.Services.UI; + +/// <inheritdoc /> +public class TraceChangeManager(ILogger<TraceChangeManager> logger) : ITraceChangeManager { - /// <inheritdoc /> - public class TraceChangeManager(ILogger<TraceChangeManager> logger) : ITraceChangeManager - { - private readonly ILogger<TraceChangeManager> _logger = logger; + readonly ILogger<TraceChangeManager> _logger = logger; - private readonly List<TracedChanges> _undoStack = []; - private readonly List<TracedChanges> _redoStack = []; + readonly List<TracedChanges> _undoStack = []; + readonly List<TracedChanges> _redoStack = []; - private List<TracedChange>? _bulkEditTracedChanges; + List<TracedChange>? _bulkEditTracedChanges; - public event EventHandler? TracedObjectHistoryChanged; - public event EventHandler? UndoDone; - public event EventHandler? RedoDone; + public event EventHandler? TracedObjectHistoryChanged; + public event EventHandler? UndoDone; + public event EventHandler? RedoDone; - /// <inheritdoc /> - public bool CanUndo => _undoStack.Count > 0; + /// <inheritdoc /> + public bool CanUndo => _undoStack.Count > 0; - /// <inheritdoc /> - public bool CanRedo => _redoStack.Count > 0; + /// <inheritdoc /> + public bool CanRedo => _redoStack.Count > 0; - public void Reset() - { - _redoStack.Clear(); - _undoStack.Clear(); - } + public void Reset() + { + _redoStack.Clear(); + _undoStack.Clear(); + } - public void Undo() + public void Undo() + { + _logger.LogDebug("Undo called"); + if (CanUndo) { - _logger.LogDebug("Undo called"); - if (CanUndo) + TracedChanges? changes = null; + while (_undoStack.Count > 0 && changes == null) { - TracedChanges? changes = null; - while (_undoStack.Count > 0 && changes == null) + changes = _undoStack[^1]; + _undoStack.Remove(changes); + if (changes.HasTraceableObject == false) { - changes = _undoStack[^1]; - _undoStack.Remove(changes); - if (changes.HasTraceableObject == false) - { - changes = null; - } + changes = null; } - if (changes != null && changes.HasTraceableObject) + } + if (changes != null && changes.HasTraceableObject) + { + var redoChanges = new List<TracedChange>(); + for (int i = changes.Changes.Count - 1; i >= 0; i--) { - var redoChanges = new List<TracedChange>(); - for (int i = changes.Changes.Count - 1; i >= 0; i--) + var change = changes.Changes.ElementAt(i); + var tracedObject = change?.TraceableObject; + var traceAbleChange = change?.TraceableChange; + if (_logger.IsEnabled(LogLevel.Debug)) { - var change = changes.Changes.ElementAt(i); - var tracedObject = change?.TraceableObject; - var traceAbleChange = change?.TraceableChange; - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}", tracedObject, traceAbleChange); - } - if (tracedObject != null && traceAbleChange != null) + _logger.LogDebug("tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}", tracedObject, traceAbleChange); + } + if (tracedObject != null && traceAbleChange != null) + { + var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); + if (propertyInfo != null) { - var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); - if (propertyInfo != null) + var currentValue = propertyInfo.GetValue(tracedObject); + redoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); + if (_logger.IsEnabled(LogLevel.Debug)) { - var currentValue = propertyInfo.GetValue(tracedObject); - redoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}", traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); - } - propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); - } - else - { - throw new NullReferenceException(string.Format("Property {0} could not be found!", traceAbleChange.PropertyName)); + _logger.LogDebug("Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}", traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); } + propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); } - if (change != null) + else { - changes.Changes.Remove(change); + throw new NullReferenceException(string.Format("Property {0} could not be found!", traceAbleChange.PropertyName)); } } - //Push the old value to redo stack - _redoStack.Add(new TracedChanges(redoChanges)); + if (change != null) + { + changes.Changes.Remove(change); + } } - UndoDone?.Invoke(this, EventArgs.Empty); + //Push the old value to redo stack + _redoStack.Add(new TracedChanges(redoChanges)); } + UndoDone?.Invoke(this, EventArgs.Empty); } + } - public void Redo() + public void Redo() + { + _logger.LogDebug("Redo called"); + if (CanRedo) { - _logger.LogDebug("Redo called"); - if (CanRedo) + TracedChanges? changes = null; + while (_redoStack.Count > 0 && changes == null) { - TracedChanges? changes = null; - while (_redoStack.Count > 0 && changes == null) + changes = _redoStack[^1]; + _redoStack.Remove(changes); + if (changes.HasTraceableObject == false) { - changes = _redoStack[^1]; - _redoStack.Remove(changes); - if (changes.HasTraceableObject == false) - { - changes = null; - } + changes = null; } - if (changes != null && changes.HasTraceableObject) + } + if (changes != null && changes.HasTraceableObject) + { + var undoChanges = new List<TracedChange>(); + for (int i = changes.Changes.Count - 1;i >= 0; i--) { - var undoChanges = new List<TracedChange>(); - for (int i = changes.Changes.Count - 1;i >= 0; i--) + var change = changes.Changes.ElementAt(i); + var tracedObject = change?.TraceableObject; + var traceAbleChange = change?.TraceableChange; + if (_logger.IsEnabled(LogLevel.Debug)) { - var change = changes.Changes.ElementAt(i); - var tracedObject = change?.TraceableObject; - var traceAbleChange = change?.TraceableChange; - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}", tracedObject, traceAbleChange); - } - if (tracedObject != null && traceAbleChange != null) + _logger.LogDebug("tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}", tracedObject, traceAbleChange); + } + if (tracedObject != null && traceAbleChange != null) + { + var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); + if (propertyInfo != null) { - var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); - if (propertyInfo != null) - { - var currentValue = propertyInfo.GetValue(tracedObject); - undoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}", traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); - } - propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); - } - else + var currentValue = propertyInfo.GetValue(tracedObject); + undoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); + if (_logger.IsEnabled(LogLevel.Debug)) { - throw new NullReferenceException(string.Format("Property {0} could not be found!", traceAbleChange.PropertyName)); + _logger.LogDebug("Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}", traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); } + propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); } - if (change != null) + else { - changes.Changes.Remove(change); + throw new NullReferenceException(string.Format("Property {0} could not be found!", traceAbleChange.PropertyName)); } } - //Push the old value to redo stack - _undoStack.Add(new TracedChanges(undoChanges)); - } - RedoDone?.Invoke(this, EventArgs.Empty); - } - } - - public bool BulkEdit - { - get => _bulkEditTracedChanges != null; - set - { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Set BulkEdit called with {value}", value); - } - if (value) - { - _bulkEditTracedChanges ??= []; - } - else - { - if (_bulkEditTracedChanges?.Count > 0) + if (change != null) { - _undoStack.Add(new TracedChanges(_bulkEditTracedChanges)); - _redoStack.Clear(); - TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); + changes.Changes.Remove(change); } - _bulkEditTracedChanges = null; } + //Push the old value to redo stack + _undoStack.Add(new TracedChanges(undoChanges)); } + RedoDone?.Invoke(this, EventArgs.Empty); } + } - public void AddChange(TracedChange tracedChange) + public bool BulkEdit + { + get => _bulkEditTracedChanges != null; + set { if (_logger.IsEnabled(LogLevel.Debug)) { - _logger.LogDebug("AddChange: {tracedChange.TraceableObject}, {tracedChange.TraceableChange.PropertyName}, {tracedChange.TraceableChange.PreviousValue}", tracedChange.TraceableObject, tracedChange.TraceableChange.PropertyName, tracedChange.TraceableChange.PreviousValue); + _logger.LogDebug("Set BulkEdit called with {value}", value); } - if (BulkEdit == false) + if (value) { - //Single change - _undoStack.Add(new([tracedChange])); - _redoStack.Clear(); - TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); + _bulkEditTracedChanges ??= []; } else { - //We are tracing multiple changes - _bulkEditTracedChanges?.Add(tracedChange); + if (_bulkEditTracedChanges?.Count > 0) + { + _undoStack.Add(new TracedChanges(_bulkEditTracedChanges)); + _redoStack.Clear(); + TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); + } + _bulkEditTracedChanges = null; } } + } - public void RemoveTracedChanges(IEnumerable<object> traceables) + public void AddChange(TracedChange tracedChange) + { + if (_logger.IsEnabled(LogLevel.Debug)) { - _undoStack.RemoveAll(x => x.HasTraceableObject == false); - _undoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); - _redoStack.RemoveAll(x => x.HasTraceableObject == false); - _redoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); + _logger.LogDebug("AddChange: {tracedChange.TraceableObject}, {tracedChange.TraceableChange.PropertyName}, {tracedChange.TraceableChange.PreviousValue}", tracedChange.TraceableObject, tracedChange.TraceableChange.PropertyName, tracedChange.TraceableChange.PreviousValue); + } + if (BulkEdit == false) + { + //Single change + _undoStack.Add(new([tracedChange])); + _redoStack.Clear(); TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); } + else + { + //We are tracing multiple changes + _bulkEditTracedChanges?.Add(tracedChange); + } + } + + public void RemoveTracedChanges(IEnumerable<object> traceables) + { + _undoStack.RemoveAll(x => x.HasTraceableObject == false); + _undoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); + _redoStack.RemoveAll(x => x.HasTraceableObject == false); + _redoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); + TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); } } diff --git a/AudioCuesheetEditor/Services/Validation/ValidationService.cs b/AudioCuesheetEditor/Services/Validation/ValidationService.cs index 1857efbd..864de8e1 100644 --- a/AudioCuesheetEditor/Services/Validation/ValidationService.cs +++ b/AudioCuesheetEditor/Services/Validation/ValidationService.cs @@ -16,42 +16,41 @@ using AudioCuesheetEditor.Model.Entity; using Microsoft.Extensions.Localization; -namespace AudioCuesheetEditor.Services.Validation +namespace AudioCuesheetEditor.Services.Validation; + +public class ValidationService(IStringLocalizer<ValidationMessage> localizer) { - public class ValidationService(IStringLocalizer<ValidationMessage> localizer) - { - private readonly IStringLocalizer<ValidationMessage> _localizer = localizer; - public Func<object, string, Task<IEnumerable<string>>> ValidateProperty => (model, propertyName) => Task.FromResult(Validate(model, propertyName)); + readonly IStringLocalizer<ValidationMessage> _localizer = localizer; + public Func<object, string, Task<IEnumerable<string>>> ValidateProperty => (model, propertyName) => Task.FromResult(Validate(model, propertyName)); - public IEnumerable<string> Validate(object? model, string propertyName) + public IEnumerable<string> Validate(object? model, string propertyName) + { + IEnumerable<string> errors = []; + if (model != null) { - IEnumerable<string> errors = []; - if (model != null) + if (model is IValidateable validateable) { - if (model is IValidateable validateable) - { - var validationResult = validateable.Validate(propertyName); - switch (validationResult?.Status) - { - case ValidationStatus.NoValidation: - case ValidationStatus.Success: - // Nothing to do - break; - - case ValidationStatus.Error: - errors = [.. validationResult.ValidationMessages.Select(x => x.GetMessageLocalized(_localizer))]; - break; - - default: - throw new InvalidOperationException("Unknown validation status."); - } - } - else + var validationResult = validateable.Validate(propertyName); + switch (validationResult?.Status) { - throw new NotSupportedException(string.Format("Model was not of supposed type '{0}'", nameof(IValidateable))); + case ValidationStatus.NoValidation: + case ValidationStatus.Success: + // Nothing to do + break; + + case ValidationStatus.Error: + errors = [.. validationResult.ValidationMessages.Select(x => x.GetMessageLocalized(_localizer))]; + break; + + default: + throw new InvalidOperationException("Unknown validation status."); } } - return errors; + else + { + throw new NotSupportedException(string.Format("Model was not of supposed type '{0}'", nameof(IValidateable))); + } } + return errors; } } diff --git a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs b/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs index 17077ea4..5b7068bd 100644 --- a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs +++ b/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs @@ -17,62 +17,61 @@ using AudioCuesheetEditor.Services.UI; using Microsoft.AspNetCore.Components; -namespace AudioCuesheetEditor.Shared +namespace AudioCuesheetEditor.Shared; + +public abstract class BaseLocalizedComponent : ComponentBase, IDisposable { - public abstract class BaseLocalizedComponent : ComponentBase, IDisposable - { - private bool disposedValue; + bool disposedValue; - [Inject] - protected LocalizationService LocalizationService { get; set; } = default!; - [Inject] - protected ITraceChangeManager TraceChangeManager { get; set; } = default!; - [Inject] - protected ILocalStorageOptionsProvider LocalStorageOptionsProvider { get; set; } = default!; + [Inject] + protected LocalizationService LocalizationService { get; set; } = default!; + [Inject] + protected ITraceChangeManager TraceChangeManager { get; set; } = default!; + [Inject] + protected ILocalStorageOptionsProvider LocalStorageOptionsProvider { get; set; } = default!; - protected override void OnInitialized() - { - base.OnInitialized(); - TraceChangeManager.TracedObjectHistoryChanged += TraceChangeManager_TracedObjectHistoryChanged; - TraceChangeManager.UndoDone += TraceChangeManager_UndoDone; - TraceChangeManager.RedoDone += TraceChangeManager_RedoDone; - } + protected override void OnInitialized() + { + base.OnInitialized(); + TraceChangeManager.TracedObjectHistoryChanged += TraceChangeManager_TracedObjectHistoryChanged; + TraceChangeManager.UndoDone += TraceChangeManager_UndoDone; + TraceChangeManager.RedoDone += TraceChangeManager_RedoDone; + } - void TraceChangeManager_RedoDone(object? sender, EventArgs e) - { - StateHasChanged(); - } + void TraceChangeManager_RedoDone(object? sender, EventArgs e) + { + StateHasChanged(); + } - void TraceChangeManager_UndoDone(object? sender, EventArgs e) - { - StateHasChanged(); - } + void TraceChangeManager_UndoDone(object? sender, EventArgs e) + { + StateHasChanged(); + } - void TraceChangeManager_TracedObjectHistoryChanged(object? sender, EventArgs e) - { - StateHasChanged(); - } + void TraceChangeManager_TracedObjectHistoryChanged(object? sender, EventArgs e) + { + StateHasChanged(); + } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) { - if (!disposedValue) + if (disposing) { - if (disposing) - { - TraceChangeManager.TracedObjectHistoryChanged -= TraceChangeManager_TracedObjectHistoryChanged; - TraceChangeManager.UndoDone -= TraceChangeManager_UndoDone; - TraceChangeManager.RedoDone -= TraceChangeManager_RedoDone; - } - - disposedValue = true; + TraceChangeManager.TracedObjectHistoryChanged -= TraceChangeManager_TracedObjectHistoryChanged; + TraceChangeManager.UndoDone -= TraceChangeManager_UndoDone; + TraceChangeManager.RedoDone -= TraceChangeManager_RedoDone; } - } - public void Dispose() - { - // Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(bool disposing)" ein. - Dispose(disposing: true); - GC.SuppressFinalize(this); + disposedValue = true; } } + + public void Dispose() + { + // Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(bool disposing)" ein. + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } \ No newline at end of file From 443f1fc4e565ff3d7f39f282a994ee2424ccc5ea Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:59:32 +0200 Subject: [PATCH 04/20] fix most CAs --- .editorconfig | 16 +++ .../Models/About.cs | 4 +- .../Models/AppBar.cs | 12 +-- .../Models/DetailView.cs | 31 ++---- .../Models/ExportDialog.cs | 5 +- .../Models/ImportView.cs | 36 ++----- .../Models/RecordView.cs | 14 +-- .../Tests/Desktop/ImportTest.cs | 2 +- .../Tests/Smartphone/ImportTest.cs | 2 +- .../Model/Entity/ValidateableTests.cs | 2 +- .../Model/IO/ProjectfileTests.cs | 2 +- .../Model/Utility/TimeSpanUtilityTests.cs | 20 ++-- .../AudioCuesheet/AudiofileManagerTests.cs | 46 ++++----- .../AudioCuesheet/CuesheetManagerTests.cs | 74 +++++++------- .../Services/IO/AudioImportServiceTests.cs | 30 +++--- .../Services/IO/CuesheetExportServiceTests.cs | 32 +++--- .../Services/IO/ExportfileGeneratorTests.cs | 6 +- .../Services/IO/FileInputManagerTests.cs | 10 +- .../Services/IO/ImportManagerTests.cs | 98 +++++++++---------- .../Services/IO/TextImportServiceTests.cs | 96 +++++++++--------- .../LocalStorageOptionsProviderTests.cs | 6 +- .../ApplicationOptionsTimeSpanParserTests.cs | 14 +-- .../Services/UI/SessionStateContainerTests.cs | 58 +++++------ .../Extensions/FlagJsonConverter.cs | 2 +- .../Extensions/WebAssemblyHostExtension.cs | 4 +- .../Model/AudioCuesheet/CDTextfile.cs | 8 +- .../Model/AudioCuesheet/Cuesheet.cs | 16 +-- .../Model/AudioCuesheet/CuesheetConstants.cs | 32 +++--- .../Model/AudioCuesheet/Flag.cs | 10 +- .../Model/AudioCuesheet/IAudiofile.cs | 2 +- .../AudioCuesheet/Import/ImportAudiofile.cs | 2 +- .../Model/AudioCuesheet/Track.cs | 10 +- .../Model/Entity/IValidateable.cs | 2 +- .../Model/Entity/Validateable.cs | 11 +-- .../Model/Entity/ValidationMessage.cs | 14 +-- .../Model/IO/Audio/AudioCodec.cs | 14 +-- .../Model/IO/Audio/Audiofile.cs | 21 ++-- .../Model/IO/Export/Exportfile.cs | 2 +- .../Model/IO/Export/Exportprofile.cs | 86 ++++++++-------- .../Model/IO/Import/IImportfile.cs | 4 +- .../Model/IO/Import/Importprofile.cs | 24 ++--- AudioCuesheetEditor/Model/IO/Projectfile.cs | 2 +- .../Model/Options/ApplicationOptions.cs | 8 +- .../Model/Options/DownloadOptions.cs | 14 +-- .../Model/Options/ViewOptions.cs | 2 +- .../Model/UI/TraceableChange.cs | 2 +- AudioCuesheetEditor/Model/UI/TracedChanges.cs | 2 +- .../Model/Utility/TimeSpanFormat.cs | 22 ++--- .../Model/Utility/TimeSpanUtility.cs | 6 +- AudioCuesheetEditor/Program.cs | 5 +- .../Services/Audio/PlaybackService.cs | 23 ++--- .../AudioCuesheet/AudiofileManager.cs | 12 +-- .../Services/AudioCuesheet/CuesheetManager.cs | 4 +- .../AudioCuesheet/IAudiofileManager.cs | 6 +- .../AudioCuesheet/ICuesheetManager.cs | 8 +- .../Services/AudioCuesheet/ITrackManager.cs | 2 +- .../Services/AudioCuesheet/TrackManager.cs | 7 +- .../Services/IO/AudioImportService.cs | 6 +- .../Services/IO/CuesheetExportService.cs | 24 ++--- .../Services/IO/CuesheetImportService.cs | 60 ++++++------ .../Services/IO/ExportfileGenerator.cs | 8 +- .../Services/IO/FileInputManager.cs | 23 ++--- .../Services/IO/IAudioImportService.cs | 2 +- .../Services/IO/IFileInputManager.cs | 2 +- .../Services/IO/ImportManager.cs | 12 +-- .../Services/IO/TextImportService.cs | 48 ++++----- .../Options/LocalStorageOptionsProvider.cs | 8 +- .../Provider/MusicBrainzDataProvider.cs | 34 +++---- .../UI/ApplicationOptionsTimeSpanParser.cs | 13 +-- .../Services/UI/AutocompleteManager.cs | 4 +- .../Services/UI/DialogManager.cs | 20 ++-- .../Services/UI/ISessionStateContainer.cs | 6 +- .../Services/UI/LocalizationService.cs | 8 +- .../Services/UI/SessionStateContainer.cs | 4 +- .../Services/UI/TraceChangeManager.cs | 20 ++-- .../Shared/BaseLocalizedComponent.cs | 15 +-- 76 files changed, 626 insertions(+), 696 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6008f9ad..ee79b17d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,22 @@ indent_size = 2 indent_size = 4 tab_width = 4 +#TODO: Enable all of these +dotnet_diagnostic.CA1000.severity = suggestion +dotnet_diagnostic.CA1051.severity = suggestion +dotnet_diagnostic.CA1304.severity = suggestion +dotnet_diagnostic.CA1305.severity = suggestion +dotnet_diagnostic.CA1309.severity = suggestion +dotnet_diagnostic.CA1310.severity = suggestion +dotnet_diagnostic.CA1311.severity = suggestion +dotnet_diagnostic.CA1716.severity = suggestion +dotnet_diagnostic.CA1727.severity = suggestion +dotnet_diagnostic.CA1805.severity = suggestion +dotnet_diagnostic.CA1848.severity = suggestion +dotnet_diagnostic.CA1852.severity = suggestion +dotnet_diagnostic.CA1863.severity = suggestion +dotnet_diagnostic.CA2201.severity = suggestion + # Organize usings dotnet_separate_import_directive_groups = false dotnet_sort_system_directives_first = true diff --git a/AudioCuesheetEditor.End2EndTests/Models/About.cs b/AudioCuesheetEditor.End2EndTests/Models/About.cs index 2ac1d0af..5a015b46 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/About.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/About.cs @@ -27,9 +27,9 @@ class About(IPage page) internal async Task GotoAsync() { - await _page.GotoAsync(BaseUrl); + _ = await _page.GotoAsync(BaseUrl); await _page.WaitForURLAsync(BaseUrl); await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + _ = await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); } } diff --git a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs index bab19e64..93d1a0c5 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs @@ -39,18 +39,12 @@ internal async Task ChangeLanguageAsync(string language) await _page.GetByRole(AriaRole.Button, new() { Name = "Change language" }).ClickAsync(); await _page.GetByText(language).ClickAsync(); await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + _ = await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); } - internal async Task UndoAsync() - { - await UndoButton.ClickAsync(); - } + internal async Task UndoAsync() => await UndoButton.ClickAsync(); - internal async Task RedoAsync() - { - await RedoButton.ClickAsync(); - } + internal async Task RedoAsync() => await RedoButton.ClickAsync(); internal async Task OpenFileAsync(string file) { diff --git a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs index 8bc4d4a3..9a3de96d 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs @@ -31,26 +31,17 @@ class DetailView(IPage page) internal async Task GotoAsync() { - await _page.GotoAsync(BaseUrl); + _ = await _page.GotoAsync(BaseUrl); await _page.WaitForURLAsync(BaseUrl); await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + _ = await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); } - internal async Task AddAudiofileAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Add file" }).ClickAsync(); - } + internal async Task AddAudiofileAsync() => await _page.GetByRole(AriaRole.Button, new() { Name = "Add file" }).ClickAsync(); - internal async Task SetAudiofileInputFileAsync(int audiofileIndex, string file) - { - await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "No file uploaded!" }).Nth(audiofileIndex).Locator("input[type=\"file\"]").SetInputFilesAsync(file); - } + internal async Task SetAudiofileInputFileAsync(int audiofileIndex, string file) => await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "No file uploaded!" }).Nth(audiofileIndex).Locator("input[type=\"file\"]").SetInputFilesAsync(file); - internal async Task AddTrackAsync(int audiofileIndex) - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Add new track" }).Nth(audiofileIndex).ClickAsync(); - } + internal async Task AddTrackAsync(int audiofileIndex) => await _page.GetByRole(AriaRole.Button, new() { Name = "Add new track" }).Nth(audiofileIndex).ClickAsync(); internal async Task EditTrackAsync(string? artist = null, string? title = null, TimeSpan? begin = null, TimeSpan? end = null, int trackPosition = 1) { @@ -72,7 +63,7 @@ internal async Task EditTrackAsync(string? artist = null, string? title = null, } } - internal async Task SelectTracksAsync(IEnumerable<int> trackTablePositions, Boolean uncheck = false) + internal async Task SelectTracksAsync(IEnumerable<int> trackTablePositions, bool uncheck = false) { foreach (var trackTablePosition in trackTablePositions) { @@ -87,10 +78,7 @@ internal async Task SelectTracksAsync(IEnumerable<int> trackTablePositions, Bool } } - internal async Task EditSelectedTracksModalAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); - } + internal async Task EditSelectedTracksModalAsync() => await _page.GetByRole(AriaRole.Button, new() { Name = "Edit selected tracks" }).ClickAsync(); internal async Task EditTracksModalAsync(string artist, string title, string end, IEnumerable<string> flagsToSelect) { @@ -114,10 +102,7 @@ internal async Task RenameAudiofileAsync(int audiofileIndex, string filename) await _page.GetByRole(AriaRole.Button, new() { Name = "Ok" }).ClickAsync(); } - internal async Task OpenRenameAudiofileDialogAsync(int audiofileIndex) - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Rename file" }).Nth(audiofileIndex).ClickAsync(); - } + internal async Task OpenRenameAudiofileDialogAsync(int audiofileIndex) => await _page.GetByRole(AriaRole.Button, new() { Name = "Rename file" }).Nth(audiofileIndex).ClickAsync(); async Task EditTrackFieldAsync(int trackPosition, string dataLabel, string value) { diff --git a/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs b/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs index 14e15895..40d2a194 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs @@ -22,8 +22,5 @@ class ExportDialog(IPage page) { readonly IPage _page = page; - internal async Task OpenSchemeMenuAsync(string schemeHeadMenuName = "Scheme head") - { - await _page.Locator("div").Filter(new() { HasTextRegex = new Regex($"^{schemeHeadMenuName}$") }).GetByRole(AriaRole.Button).Nth(1).ClickAsync(); - } + internal async Task OpenSchemeMenuAsync(string schemeHeadMenuName = "Scheme head") => await _page.Locator("div").Filter(new() { HasTextRegex = new Regex($"^{schemeHeadMenuName}$") }).GetByRole(AriaRole.Button).Nth(1).ClickAsync(); } diff --git a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs index 3106e556..4b353ff1 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs @@ -39,27 +39,18 @@ partial class ImportView(IPage page, bool mobile) internal async Task GotoAsync() { - await _page.GotoAsync(BaseUrl); + _ = await _page.GotoAsync(BaseUrl); await _page.WaitForURLAsync(BaseUrl); await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + _ = await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); await _page.GetByText("Import view").ClickAsync(); } - internal async Task ImportFileAsync(string filepath) - { - await _page.GetByLabel("TextField file upload").SetInputFilesAsync(filepath); - } + internal async Task ImportFileAsync(string filepath) => await _page.GetByLabel("TextField file upload").SetInputFilesAsync(filepath); - internal async Task ImportTextAsync(string text) - { - await _page.GetByRole(AriaRole.Textbox, new() { Name = "Please enter text or upload a" }).FillAsync(text); - } + internal async Task ImportTextAsync(string text) => await _page.GetByRole(AriaRole.Textbox, new() { Name = "Please enter text or upload a" }).FillAsync(text); - internal async Task Analyze() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Analyze" }).ClickAsync(); - } + internal async Task Analyze() => await _page.GetByRole(AriaRole.Button, new() { Name = "Analyze" }).ClickAsync(); internal async Task CompleteImportAsync() { @@ -74,7 +65,7 @@ internal async Task CompleteImportAsync() } } - internal async Task SelectTracksAsync(IEnumerable<int> trackTablePositions, Boolean uncheck = false) + internal async Task SelectTracksAsync(IEnumerable<int> trackTablePositions, bool uncheck = false) { foreach (var trackTablePosition in trackTablePositions) { @@ -103,20 +94,11 @@ internal async Task SwitchImportProfileAsync(string profile) await _page.GetByText(profile).ClickAsync(); } - internal async Task ClearSchemeCommonDataAsync() - { - await _page.Locator("div").Filter(new() { HasTextRegex = SchemeCommonData() }).GetByLabel("Clear").ClickAsync(); - } + internal async Task ClearSchemeCommonDataAsync() => await _page.Locator("div").Filter(new() { HasTextRegex = SchemeCommonData() }).GetByLabel("Clear").ClickAsync(); - internal async Task ClearSchemeAudiofilesAsync() - { - await _page.Locator("div").Filter(new() { HasTextRegex = SchemeAudiofiles() }).GetByLabel("Clear").ClickAsync(); - } + internal async Task ClearSchemeAudiofilesAsync() => await _page.Locator("div").Filter(new() { HasTextRegex = SchemeAudiofiles() }).GetByLabel("Clear").ClickAsync(); - internal async Task SetSchemeCommonDataAsync(string schemeCommonData) - { - await _page.GetByRole(AriaRole.Textbox, new() { Name = "Scheme common data" }).FillAsync(schemeCommonData); - } + internal async Task SetSchemeCommonDataAsync(string schemeCommonData) => await _page.GetByRole(AriaRole.Textbox, new() { Name = "Scheme common data" }).FillAsync(schemeCommonData); internal async Task SelectSchemeCommonDataPlaceholderAsync(string placeholder) { diff --git a/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs b/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs index e7b2a148..6ac46056 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs @@ -25,22 +25,16 @@ class RecordView(IPage page) internal async Task GotoAsync() { - await _page.GotoAsync(BaseUrl); + _ = await _page.GotoAsync(BaseUrl); await _page.WaitForURLAsync(BaseUrl); await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); + _ = await _page.WaitForFunctionAsync(@"() => window.Blazor !== undefined"); await _page.GetByText("Record view").ClickAsync(); } - internal async Task StartRecordingAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Start recording" }).ClickAsync(); - } + internal async Task StartRecordingAsync() => await _page.GetByRole(AriaRole.Button, new() { Name = "Start recording" }).ClickAsync(); - internal async Task StopRecordingAsync() - { - await _page.GetByRole(AriaRole.Button, new() { Name = "Stop recording" }).ClickAsync(); - } + internal async Task StopRecordingAsync() => await _page.GetByRole(AriaRole.Button, new() { Name = "Stop recording" }).ClickAsync(); internal async Task AddRecordingTrackAsync(string artist, string title) { diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs index c982b351..85a4c8ba 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs @@ -2635,7 +2635,7 @@ public async Task Import_ShouldImportTracks_WhenUsingText() { var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); - var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); + var text = string.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); await importView.ImportTextAsync(text); await importView.Analyze(); await importView.CompleteImportAsync(); diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs index b3355e54..ab00590f 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs @@ -3222,7 +3222,7 @@ public async Task Import_ShouldImportTracks_WhenUsingText() { var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); - var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); + var text = string.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); await importView.ImportTextAsync(text); await importView.Analyze(); await importView.CompleteImportAsync(); diff --git a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs index 1585fe73..495ac126 100644 --- a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs @@ -44,7 +44,7 @@ public int? TestProperty2 } public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { diff --git a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs index 92742382..03a04757 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs @@ -56,7 +56,7 @@ public void GenerateFile_WithoutSections_GeneratesOneFile() var rand = new Random(); var flagsToAdd = rand.Next(1, 3); var flags = new List<Flag>(); - for (int x = 0; x < flagsToAdd; x++) + for (var x = 0; x < flagsToAdd; x++) { flags.Add(Flag.AvailableFlags.ElementAt(x)); } diff --git a/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs b/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs index 9bb47bb8..ce07964c 100644 --- a/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Utility/TimeSpanUtilityTests.cs @@ -26,7 +26,7 @@ public class TimeSpanUtilityTests public void ParseTimeSpan_Valid_HoursMinutesSeconds() { // Arrange - string input = "01:23:45"; + var input = "01:23:45"; // Act var timespan = TimeSpanUtility.ParseTimeSpan(input); @@ -40,7 +40,7 @@ public void ParseTimeSpan_Valid_HoursMinutesSeconds() public void ParseTimeSpan_Valid_MinutesSeconds() { // Arrange - string input = "3:12"; + var input = "3:12"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; // Act @@ -55,7 +55,7 @@ public void ParseTimeSpan_Valid_MinutesSeconds() public void ParseTimeSpan_Valid_OverflowMinutes() { // Arrange - string input = "63:12"; + var input = "63:12"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; // Act @@ -70,7 +70,7 @@ public void ParseTimeSpan_Valid_OverflowMinutes() public void ParseTimeSpan_Valid_HoursMinutes() { // Arrange - string input = "23:12"; + var input = "23:12"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}" }; // Act @@ -85,7 +85,7 @@ public void ParseTimeSpan_Valid_HoursMinutes() public void ParseTimeSpan_Valid_FullFormat() { // Arrange - string input = "23:45:56"; + var input = "23:45:56"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; // Act @@ -100,7 +100,7 @@ public void ParseTimeSpan_Valid_FullFormat() public void ParseTimeSpan_Valid_WithDays() { // Arrange - string input = "2.23:45:56"; + var input = "2.23:45:56"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Days}.{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}" }; // Act @@ -115,7 +115,7 @@ public void ParseTimeSpan_Valid_WithDays() public void ParseTimeSpan_Valid_WithMilliseconds() { // Arrange - string input = "23:45:56.599"; + var input = "23:45:56.599"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; // Act @@ -130,7 +130,7 @@ public void ParseTimeSpan_Valid_WithMilliseconds() public void ParseTimeSpan_Invalid_Format() { // Arrange - string input = "1.2e:45:87.h3a"; + var input = "1.2e:45:87.h3a"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; @@ -145,7 +145,7 @@ public void ParseTimeSpan_Invalid_Format() public void ParseTimeSpan_Invalid_Text() { // Arrange - string input = "Test"; + var input = "Test"; var format = new TimeSpanFormat() { Scheme = $"{TimeSpanFormat.Hours}:{TimeSpanFormat.Minutes}:{TimeSpanFormat.Seconds}.{TimeSpanFormat.Milliseconds}" }; // Act @@ -159,7 +159,7 @@ public void ParseTimeSpan_Invalid_Text() public void ParseTimeSpan_Invalid_Scheme() { // Arrange - string input = "Test"; + var input = "Test"; var format = new TimeSpanFormat() { Scheme = "this is a test" }; // Act diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs index f0e8e649..caa85eaa 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs @@ -48,7 +48,7 @@ public AudiofileManagerTests() _traceChangeManager = new Mock<ITraceChangeManager>(); _jsRuntime = new Mock<IJSRuntime>(); _trackManager = new Mock<ITrackManager>(); - _trackManager.Setup(x => x.SetProperty(It.IsAny<Track>(), It.IsAny<Expression<Func<Track, It.IsAnyType>>>(), It.IsAny<It.IsAnyType>())) + _ = _trackManager.Setup(x => x.SetProperty(It.IsAny<Track>(), It.IsAny<Expression<Func<Track, It.IsAnyType>>>(), It.IsAny<It.IsAnyType>())) .Callback((Track track, LambdaExpression propExpr, object value) => { var memberExpression = propExpr.Body as MemberExpression; @@ -57,7 +57,7 @@ public AudiofileManagerTests() propertyInfo.SetValue(track, value); } }); - _trackManager.Setup(x => x.GetPreviousLinkedTrack(It.IsAny<Track>())).Returns(delegate (Track track) + _ = _trackManager.Setup(x => x.GetPreviousLinkedTrack(It.IsAny<Track>())).Returns(delegate (Track track) { if (track.IsLinkedToPreviousTrack == false) { @@ -117,13 +117,13 @@ public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() var objectUrl = "blob:123"; var filename = "song.mp3"; var browserFile = new Mock<IBrowserFile>(); - browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); - browserFile.SetupGet(b => b.Name).Returns(filename); + _ = browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + _ = browserFile.SetupGet(b => b.Name).Returns(filename); var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); - _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); - _jsRuntime.Setup(js => js.InvokeAsync<double>("getAudioDurationFromFile", It.IsAny<object?[]>())).Returns(new ValueTask<double>(90.0)); + _ = _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); + _ = _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); + _ = _jsRuntime.Setup(js => js.InvokeAsync<double>("getAudioDurationFromFile", It.IsAny<object?[]>())).Returns(new ValueTask<double>(90.0)); var audiofile = new Audiofile(); var audiofileChangedFired = 0; @@ -156,13 +156,13 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() var objectUrl = "blob:123"; var filename = "song.mp3"; var browserFile = new Mock<IBrowserFile>(); - browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); - browserFile.SetupGet(b => b.Name).Returns(filename); + _ = browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + _ = browserFile.SetupGet(b => b.Name).Returns(filename); var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); - _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); - _jsRuntime.Setup(js => js.InvokeAsync<double>("getAudioDurationFromFile", It.IsAny<object?[]>())).Returns(new ValueTask<double>(90.0)); + _ = _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); + _ = _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); + _ = _jsRuntime.Setup(js => js.InvokeAsync<double>("getAudioDurationFromFile", It.IsAny<object?[]>())).Returns(new ValueTask<double>(90.0)); var track1 = new Track() { Position = 1, @@ -208,13 +208,13 @@ public async Task SetPropertiesAsync_PreviouslySetAudiofile_ShouldClearFirstAndS var objectUrl = "blob:123"; var filename = "song.mp3"; var browserFile = new Mock<IBrowserFile>(); - browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); - browserFile.SetupGet(b => b.Name).Returns(filename); + _ = browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + _ = browserFile.SetupGet(b => b.Name).Returns(filename); var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); - _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); - _jsRuntime.Setup(js => js.InvokeAsync<double>("getAudioDurationFromFile", It.IsAny<object?[]>())).Returns(new ValueTask<double>(90.0)); + _ = _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); + _ = _fileInputManager.Setup(f => f.GetObjectUrlAsync(browserFile.Object)).ReturnsAsync(objectUrl); + _ = _jsRuntime.Setup(js => js.InvokeAsync<double>("getAudioDurationFromFile", It.IsAny<object?[]>())).Returns(new ValueTask<double>(90.0)); var audiofile = new Audiofile { @@ -372,7 +372,7 @@ public void AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties() { Audiofiles = [audiofile] }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { @@ -417,7 +417,7 @@ public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackPropertie { Audiofiles = [audiofile] }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); var track = new Track() { IsLinkedToPreviousTrack = true @@ -467,7 +467,7 @@ public void AddTrack_DuringRecording_AddsNewTrackWithCalulatedTrackProperties() RecordingStart = DateTime.UtcNow, Audiofiles = [audiofile] }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); var track = new Track() { IsLinkedToPreviousTrack = true @@ -506,7 +506,7 @@ public void AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackPropertie { Audiofiles = [audiofile] }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); var track = new Track(); var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) @@ -585,7 +585,7 @@ public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainin track3.Cuesheet = cuesheet; track4.Cuesheet = cuesheet; track5.Cuesheet = cuesheet; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { @@ -672,7 +672,7 @@ public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrack track3.Audiofile = audiofile; track4.Audiofile = audiofile; track5.Audiofile = audiofile; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs index 53754066..a10b8784 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs @@ -47,7 +47,7 @@ public CuesheetManagerTests() _audiofileManager = new(); _trackManager = new(); _jsRuntime = new Mock<IJSRuntime>(); - _trackManager.Setup(x => x.SetProperty(It.IsAny<Track>(),It.IsAny<Expression<Func<Track, It.IsAnyType>>>(),It.IsAny<It.IsAnyType>())) + _ = _trackManager.Setup(x => x.SetProperty(It.IsAny<Track>(), It.IsAny<Expression<Func<Track, It.IsAnyType>>>(), It.IsAny<It.IsAnyType>())) .Callback((Track track, LambdaExpression propExpr, object value) => { var memberExpression = propExpr.Body as MemberExpression; @@ -64,8 +64,8 @@ public void SetProperty_NewValue_ChangesPropertyAndSetsTracedChange() { // Arrange var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act _cuesheetManager.SetProperty(x => x.Artist, "Artist"); // Assert @@ -81,7 +81,7 @@ public void SetProperty_EqualValue_DoesntChangeProperty() { Artist = "Artist" }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act _cuesheetManager.SetProperty(x => x.Artist, cuesheet.Artist); // Assert @@ -108,9 +108,9 @@ public void SetProperty_DeletedAudiofile_RevokesObjectURLs() { Audiofiles = [audiofile1, audiofile2] }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); var files = new List<Audiofile>(cuesheet.Audiofiles); - files.Remove(audiofile2); + _ = files.Remove(audiofile2); // Act _cuesheetManager.SetProperty(x => x.Audiofiles, files); // Assert @@ -123,9 +123,9 @@ public void SetProperty_OnImportCuesheet_DoesNotTraceChanges() // Arrange var importCuesheet = new Cuesheet(); var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(importCuesheet); - _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(importCuesheet); + _ = _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(importCuesheet); + _ = _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(cuesheet); + _ = _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(importCuesheet); // Act _cuesheetManager.SetProperty(x => x.Artist, nameof(SetProperty_OnImportCuesheet_DoesNotTraceChanges)); // Assert @@ -137,7 +137,7 @@ public void IsRecordingPossible_WithoutTracks_ReturnsSuccess() { // Arrange var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetManager.IsRecordingPossible; // Assert @@ -158,7 +158,7 @@ public void IsRecordingPossible_WithTracks_ReturnsFailure() } ] }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetManager.IsRecordingPossible; // Assert @@ -178,7 +178,7 @@ public void IsRecordingPossible_RecordingAlreadyRunning_ReturnsFailure() ], RecordingStart = DateTime.UtcNow }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetManager.IsRecordingPossible; // Assert @@ -191,7 +191,7 @@ public void StartRecording_RecordingPossible_ReturnsSuccess() { // Arrange var cuesheet = new Cuesheet(); - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); var isRecordingChanged = false; _cuesheetManager.IsRecordingChanged += delegate { @@ -214,7 +214,7 @@ public void StartRecording_RecordingNotPossible_ReturnsFailure() { RecordingStart = DateTime.UtcNow.AddDays(-1) }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); var isRecordingChanged = false; _cuesheetManager.IsRecordingChanged += delegate { @@ -251,7 +251,7 @@ public void StopRecording_WithActiveRecording_StopsRecordAndSetsTrackDetails() } ] }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); var isRecordingChanged = false; _cuesheetManager.IsRecordingChanged += delegate { @@ -288,7 +288,7 @@ public void StopRecording_WithoutActiveRecording_ChangesNothing() } ] }; - _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); var isRecordingChanged = false; _cuesheetManager.IsRecordingChanged += delegate { @@ -406,7 +406,7 @@ public void IsMoveUpPossible_AudiofilesAbove_ReturnsTrue() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.IsMoveUpPossible([file2, file3]); // Assert @@ -424,7 +424,7 @@ public void IsMoveUpPossible_NoAudiofilesAbove_ReturnsFalse() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.IsMoveUpPossible([file1, file2]); // Assert @@ -477,7 +477,7 @@ public void IsMoveDownPossible_TracksBelow_ReturnsTrue() track1.Cuesheet = cuesheet; track2.Cuesheet = cuesheet; track3.Cuesheet = cuesheet; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.IsMoveDownPossible([track2, track1]); // Assert @@ -547,7 +547,7 @@ public void IsMoveDownPossible_AudiofilesBelow_ReturnsTrue() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.IsMoveDownPossible([file2, file1]); // Assert @@ -565,7 +565,7 @@ public void IsMoveDownPossible_NoAudiofilesBelow_ReturnsFalse() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.IsMoveDownPossible([file3, file2]); // Assert @@ -626,7 +626,7 @@ public void MoveUp_TracksSwitchingAudiofile_ReturnsSuccess() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.Last(); track3.Audiofile = cuesheet.Audiofiles.Last(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp([track2, track3]); // Assert @@ -688,7 +688,7 @@ public void MoveUp_TracksAbove_ReturnsSuccess() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp([track2, track3]); // Assert @@ -757,7 +757,7 @@ public void MoveUp_Move2Positions_ReturnsSuccess() track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); track4.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp([track2, track3], 2); // Assert @@ -816,7 +816,7 @@ public void MoveUp_NoTracksAbove_ReturnsFailure() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp([track2, track1]); // Assert @@ -876,7 +876,7 @@ public void MoveUp_NoTracksSelected_ReturnsFailure() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp(new HashSet<Track>()); // Assert @@ -935,7 +935,7 @@ public void MoveUp_AudiofilesAbove_ReturnsSuccess() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); track1.Cuesheet = cuesheet; track2.Cuesheet = cuesheet; track3.Cuesheet = cuesheet; @@ -974,7 +974,7 @@ public void MoveUp_NoAudiofilesAbove_ReturnsFailure() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp([file1, file2]); // Assert @@ -995,7 +995,7 @@ public void MoveUp_NoAudiofilesSelected_ReturnsFailure() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveUp(new HashSet<Audiofile>()); // Assert @@ -1049,7 +1049,7 @@ public void MoveDown_TracksSwitchingAudiofile_ReturnsSuccess() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.Last(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown([track2, track1]); // Assert @@ -1111,7 +1111,7 @@ public void MoveDown_TracksBelow_ReturnsSuccess() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown([track2, track1]); // Assert @@ -1180,7 +1180,7 @@ public void MoveDown_Move2Positions_ReturnsSuccess() track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); track4.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown([track2, track1], 2); // Assert @@ -1242,7 +1242,7 @@ public void MoveDown_NoTracksBelow_ReturnsFailure() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown([track2, track3]); // Assert @@ -1302,7 +1302,7 @@ public void MoveDown_NoTracksSelected_ReturnsFailure() track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); track3.Audiofile = cuesheet.Audiofiles.First(); - _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.Cuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown(new HashSet<Track>()); // Assert @@ -1361,7 +1361,7 @@ public void MoveDown_AudiofilesBelow_ReturnsSuccess() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); track1.Cuesheet = cuesheet; track2.Cuesheet = cuesheet; track3.Cuesheet = cuesheet; @@ -1399,7 +1399,7 @@ public void MoveDown_NoAudiofilesBelow_ReturnsFailure() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown([file2, file3]); // Assert @@ -1420,7 +1420,7 @@ public void MoveDown_NoAudiofilesSelected_ReturnsFailure() { Audiofiles = [file1, file2, file3], }; - _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = _cuesheetManager.MoveDown(new HashSet<Audiofile>()); // Assert diff --git a/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs index 5bca1388..aef16472 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/AudioImportServiceTests.cs @@ -47,11 +47,11 @@ public async Task MapAudioImportAsync_WhenMappingIsNotRequired_ReturnsTrueAsync( // Arrange var cuesheet = new Cuesheet(); var importAudiofileMapping = new Dictionary<Audiofile, Audiofile?>(); - _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); - _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); - _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny<Dictionary<Audiofile, Audiofile?>>()).Callback<Dictionary<Audiofile, Audiofile?>>(cs => importAudiofileMapping = cs); - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns([]); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); + _ = _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny<Dictionary<Audiofile, Audiofile?>>()).Callback<Dictionary<Audiofile, Audiofile?>>(cs => importAudiofileMapping = cs); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns([]); + _ = _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = await _service.MapAudioImportAsync(); // Assert @@ -76,11 +76,11 @@ public async Task MapAudioImportAsync_WhenMappingIsRequiredAndDoneAutomatically_ { new() }; - _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); - _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); - _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny<Dictionary<Audiofile, Audiofile?>>()).Callback<Dictionary<Audiofile, Audiofile?>>(cs => importAudiofileMapping = cs); - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(true); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); + _ = _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny<Dictionary<Audiofile, Audiofile?>>()).Callback<Dictionary<Audiofile, Audiofile?>>(cs => importAudiofileMapping = cs); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); + _ = _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = await _service.MapAudioImportAsync(); // Assert @@ -106,11 +106,11 @@ public async Task MapAudioImportAsync_WhenMappingIsRequiredAndCannotBeDoneAutoma new(), new() }; var dialogResultAborted = true; - _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(dialogResultAborted); - _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); - _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny<Dictionary<Audiofile, Audiofile?>>()).Callback<Dictionary<Audiofile, Audiofile?>>(cs => importAudiofileMapping = cs); - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); - _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); + _ = _dialogManager.Setup(x => x.ShowImportAudiofilesDialogAsync()).ReturnsAsync(dialogResultAborted); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofileMapping).Returns(importAudiofileMapping); + _ = _sessionStateContainer.SetupSet(x => x.ImportAudiofileMapping = It.IsAny<Dictionary<Audiofile, Audiofile?>>()).Callback<Dictionary<Audiofile, Audiofile?>>(cs => importAudiofileMapping = cs); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(importAudioFiles); + _ = _sessionStateContainer.SetupGet(x => x.ActiveCuesheet).Returns(cuesheet); // Act var result = await _service.MapAudioImportAsync(); // Assert diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs index 5c48c554..ac3d6f39 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs @@ -44,9 +44,9 @@ public CuesheetExportServiceTests() public void CanGenerateExportfile_InvalidExtension_ReturnsValidationMessage() { // Arrange - string invalidFilename = "test.txt"; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); - _localizerMock.Setup(x => x["File extension is not '{0}'", It.IsAny<object[]>()]).Returns(new LocalizedString("File extension is not '{0}'", "File extension is not '{0}'")); + var invalidFilename = "test.txt"; + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); + _ = _localizerMock.Setup(x => x["File extension is not '{0}'", It.IsAny<object[]>()]).Returns(new LocalizedString("File extension is not '{0}'", "File extension is not '{0}'")); // Act var result = _cuesheetExportService.CanGenerateExportfile(invalidFilename); @@ -60,12 +60,12 @@ public void CanGenerateExportfile_InvalidExtension_ReturnsValidationMessage() public void CanGenerateExportfile_InvalidAudiofileName_ReturnsValidationMessage() { // Arrange - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet() + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet() { Audiofiles = [new()] }); - _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); - _localizerMock.Setup(x => x[nameof(Audiofile.Name)]).Returns(new LocalizedString(nameof(Audiofile.Name), nameof(Audiofile.Name))); + _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _ = _localizerMock.Setup(x => x[nameof(Audiofile.Name)]).Returns(new LocalizedString(nameof(Audiofile.Name), nameof(Audiofile.Name))); // Act var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); @@ -79,9 +79,9 @@ public void CanGenerateExportfile_InvalidAudiofileName_ReturnsValidationMessage( public void CanGenerateExportfile_InvalidCuesheeetTitle_ReturnsValidationMessage() { // Arrange - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); - _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); - _localizerMock.Setup(x => x[nameof(Cuesheet.Title)]).Returns(new LocalizedString(nameof(Cuesheet.Title), nameof(Cuesheet.Title))); + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); + _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _ = _localizerMock.Setup(x => x[nameof(Cuesheet.Title)]).Returns(new LocalizedString(nameof(Cuesheet.Title), nameof(Cuesheet.Title))); // Act var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); @@ -116,9 +116,9 @@ public void CanGenerateExportfile_InvalidTrackEnd_ReturnsValidationMessage() ], }; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); - _localizerMock.Setup(x => x[nameof(Track.End)]).Returns(new LocalizedString(nameof(Track.End), nameof(Track.End))); + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _ = _localizerMock.Setup(x => x[nameof(Track.End)]).Returns(new LocalizedString(nameof(Track.End), nameof(Track.End))); // Act var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); @@ -155,7 +155,7 @@ public void CanGenerateExportfiles_ValidExtension_ReturnsSuccess() ], }; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); @@ -201,7 +201,7 @@ public void GenerateExportfiles_SingleAudiofile_ReturnsExportFile() }; track1.Cuesheet = cuesheet; track2.Cuesheet = cuesheet; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetExportService.GenerateExportfile(filename); @@ -286,7 +286,7 @@ public void GenerateExportfiles_MultipleAudiofiles_ReturnsExportFile() track2.Cuesheet = cuesheet; track3.Cuesheet = cuesheet; track4.Cuesheet = cuesheet; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetExportService.GenerateExportfile(filename); @@ -347,7 +347,7 @@ public void GenerateExportfiles_WithInvalidTracks_ReturnsFailure() } ] }; - _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _cuesheetExportService.GenerateExportfile("test.cue"); diff --git a/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs index 6a480c66..02fbd9f7 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs @@ -91,7 +91,7 @@ public void GenerateExportFile_SeveralAudiofiles_ReturnsSuccess() track2.Cuesheet = cuesheet; track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.Last(); - _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _exportfileGenerator.GenerateExportfile(exportProfile); @@ -147,7 +147,7 @@ public void GenerateExportFile_EmptyExportprofile_ReturnsSuccess() track2.Cuesheet = cuesheet; track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); - _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _exportfileGenerator.GenerateExportfile(exportProfile); @@ -199,7 +199,7 @@ public void GenerateExportFile_ReturnsEmpty_WithInvalidTracks() track2.Cuesheet = cuesheet; track1.Audiofile = cuesheet.Audiofiles.First(); track2.Audiofile = cuesheet.Audiofiles.First(); - _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); + _ = _mockSessionStateContainer.SetupProperty(x => x.Cuesheet, cuesheet); // Act var result = _exportfileGenerator.GenerateExportfile(exportProfile); diff --git a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs index 9604c3b2..25a1bc3b 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs @@ -237,7 +237,7 @@ public async Task CreateFileUploadsAsync_ReturnsFileUploads_WhenFileHasTextConte secondFile ]; var objectUrl = "Some object url!"; - _jsRuntimeMock.Setup(js => js.InvokeAsync<String>(It.IsAny<string>(), It.IsAny<object[]>())).ReturnsAsync(objectUrl); + _ = _jsRuntimeMock.Setup(js => js.InvokeAsync<string>(It.IsAny<string>(), It.IsAny<object[]>())).ReturnsAsync(objectUrl); // Act var result = await _service.CreateFileUploadsAsync(browserfiles); // Assert @@ -270,11 +270,11 @@ public async Task CreateFileUploadsAsync_ReturnsEmpty_WhenFilesHaveInvalidMimeTy static IBrowserFile CreateBrowserFile(string name, string contentType, string? content = null) { var fileMock = new Mock<IBrowserFile>(); - fileMock.Setup(f => f.Name).Returns(name); - fileMock.Setup(f => f.ContentType).Returns(contentType); + _ = fileMock.Setup(f => f.Name).Returns(name); + _ = fileMock.Setup(f => f.ContentType).Returns(contentType); if (content != null) - { - fileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(Encoding.UTF8.GetBytes(content))); + { + _ = fileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(Encoding.UTF8.GetBytes(content))); } return fileMock.Object; } diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index 07ac8825..44b0268c 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -51,7 +51,7 @@ public ImportManagerTests() _fileInputManager = new(); _textImportService = new(); _trackManager = new(); - _trackManager.Setup(x => x.SetProperty(It.IsAny<Track>(), It.IsAny<Expression<Func<Track, It.IsAnyType>>>(), It.IsAny<It.IsAnyType>())) + _ = _trackManager.Setup(x => x.SetProperty(It.IsAny<Track>(), It.IsAny<Expression<Func<Track, It.IsAnyType>>>(), It.IsAny<It.IsAnyType>())) .Callback((Track track, LambdaExpression propExpr, object value) => { var memberExpression = propExpr.Body as MemberExpression; @@ -60,7 +60,7 @@ public ImportManagerTests() propertyInfo.SetValue(track, value); } }); - _trackManager.Setup(x => x.CopyValues(It.IsAny<ITrack>(), It.IsAny<Track>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>())) + _ = _trackManager.Setup(x => x.CopyValues(It.IsAny<ITrack>(), It.IsAny<Track>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>())) .Callback<ITrack, Track, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool>((source, target, setIsLinkedToPreviousTrack, setPosition, setArtist, setTitle, setBegin, setEnd, setLength, setFlags, setPreGap, setPostGap) => { if (setIsLinkedToPreviousTrack) @@ -104,10 +104,10 @@ public ImportManagerTests() TrackManager_SetValue(target, x => x.PostGap, source.PostGap, false); } }); - _trackManager.Setup(x => x.Clone(It.IsAny<ITrack>())).Returns<ITrack>(track => + _ = _trackManager.Setup(x => x.Clone(It.IsAny<ITrack>())).Returns<ITrack>(track => { var clone = new Track(); - Boolean setLength = true; + var setLength = true; if (track.Begin.HasValue && track.End.HasValue) { setLength = false; @@ -120,7 +120,7 @@ public ImportManagerTests() _service = new ImportManager(_sessionStateContainer.Object, _traceChangeManager.Object, _fileInputManager.Object, _textImportService.Object, _trackManager.Object, _audioImportService.Object, loggerMock.Object); } - void TrackManager_SetValue<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value, Boolean signalTraceChangeManager = true) + void TrackManager_SetValue<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value, bool signalTraceChangeManager = true) { if (propertyExpression.Body is not MemberExpression memberExpression) { @@ -179,17 +179,17 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() FileType = ImportFileType.Textfile, AnalyzedCuesheet = importCuesheet }; - _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); - _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); + _ = _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); + _ = _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); IList<Audiofile>? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); Cuesheet? sessionStateContainerImportCuesheet = null; - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cs => sessionStateContainerImportCuesheet = cs); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); + _ = _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cs => sessionStateContainerImportCuesheet = cs); + _ = _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); // Act - await _service.AnalyseImportfile(); + _ = await _service.AnalyseImportfile(); // Assert Assert.AreEqual(importFile, sessionStateContainerImportfile); Assert.IsNotNull(sessionStateContainerImportCuesheet); @@ -220,14 +220,14 @@ public async Task AnalyseImportfile_WithoutAnalysedCuesheet_DoesNothing() FileContent = fileContent, FileType = ImportFileType.Textfile, }; - _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); - _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); + _ = _textImportService.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importFile); + _ = _sessionStateContainer.SetupGet(x => x.Importfile).Returns(importFile); Cuesheet? sessionStateContainerImportCuesheet = null; - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cs => sessionStateContainerImportCuesheet = cs); + _ = _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cs => sessionStateContainerImportCuesheet = cs); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); // Act - await _service.AnalyseImportfile(); + _ = await _service.AnalyseImportfile(); // Assert Assert.AreEqual(importFile, sessionStateContainerImportfile); Assert.IsNull(sessionStateContainerImportCuesheet); @@ -279,15 +279,15 @@ TRACK 08 AUDIO FileType = ImportFileType.Cuesheet }; IList<Audiofile>? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); - _sessionStateContainer.SetupGet(x => x.Importfile).Returns(() => sessionStateContainerImportFile); - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(importfile => sessionStateContainerImportFile = importfile); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + _ = _sessionStateContainer.SetupGet(x => x.Importfile).Returns(() => sessionStateContainerImportFile); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(importfile => sessionStateContainerImportFile = importfile); Cuesheet? sessionStateContainerImportCuesheet = null; - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cuesheet => sessionStateContainerImportCuesheet = cuesheet); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); + _ = _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cuesheet => sessionStateContainerImportCuesheet = cuesheet); + _ = _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(() => sessionStateContainerImportCuesheet); // Act - await _service.AnalyseImportfile(); + _ = await _service.AnalyseImportfile(); // Assert Assert.IsNotNull(sessionStateContainerImportCuesheet); Assert.AreEqual("Sample CD Artist", sessionStateContainerImportCuesheet.Artist); @@ -308,12 +308,12 @@ public async Task UploadFilesAsync_ProjectFile_ImportsCorrectly() // Arrange var fileContent = "This is the content"; var file = new FileUpload("test.projectfile", "text/plain", fileContent); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(true); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(false); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(true); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(false); + _ = _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); // Act await _service.UploadFilesAsync([file]); @@ -331,12 +331,12 @@ public async Task UploadFilesAsync_CuesheetFile_ImportsCorrectly() var fileContent = "Cuesheet file content"; var file = new FileUpload("test.cue", "text/plain", fileContent); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(false); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(true); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(false); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(true); + _ = _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); // Act await _service.UploadFilesAsync([file]); @@ -354,12 +354,12 @@ public async Task UploadFilesAsync_TextFile_ImportsCorrectly() var fileContent = "TextFileContent"; var file = new FileUpload("test.txt", "text/plain", fileContent); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(false); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(false); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(true); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(false); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(false); + _ = _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(true); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); // Act await _service.UploadFilesAsync([file]); @@ -376,17 +376,17 @@ public async Task UploadFilesAsync_WithAudiofile_ImportsCorrectly() // Arrange var file = new FileUpload("test.mp3", "audio/mpeg"); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(false); - _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(false); - _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); - _fileInputManager.Setup(f => f.IsValidAudiofile(file.Name, file.ContentType)).Returns(true); - _fileInputManager.Setup(f => f.CreateAudiofileAsync(It.IsAny<FileUpload>())).ReturnsAsync(new Audiofile() { Name = file.Name }); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny<IEnumerable<string>>())).Returns(false); + _ = _fileInputManager.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny<IEnumerable<string>>())).Returns(false); + _ = _fileInputManager.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); + _ = _fileInputManager.Setup(f => f.IsValidAudiofile(file.Name, file.ContentType)).Returns(true); + _ = _fileInputManager.Setup(f => f.CreateAudiofileAsync(It.IsAny<FileUpload>())).ReturnsAsync(new Audiofile() { Name = file.Name }); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); IList<Audiofile>? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); - _sessionStateContainer.SetupSet(x => x.ImportAudiofiles = It.IsAny<IList<Audiofile>>()).Callback<IList<Audiofile>>(x => sessionStateContainerImportAudiofiles = x); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + _ = _sessionStateContainer.SetupSet(x => x.ImportAudiofiles = It.IsAny<IList<Audiofile>>()).Callback<IList<Audiofile>>(x => sessionStateContainerImportAudiofiles = x); // Act await _service.UploadFilesAsync([file]); @@ -429,13 +429,13 @@ public async Task ImportCuesheetAsync_WithImportCuesheetAvailable_ImportsCueshee track2.Cuesheet = sessionStateContainerImportCuesheet; track1.Audiofile = sessionStateContainerImportCuesheet.Audiofiles.First(); track2.Audiofile = sessionStateContainerImportCuesheet.Audiofiles.First(); - _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(sessionStateContainerImportCuesheet); - _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cuesheet => sessionStateContainerImportCuesheet = cuesheet); + _ = _sessionStateContainer.SetupGet(x => x.ImportCuesheet).Returns(sessionStateContainerImportCuesheet); + _ = _sessionStateContainer.SetupSet(x => x.ImportCuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cuesheet => sessionStateContainerImportCuesheet = cuesheet); Cuesheet sessionStateContainerCuesheet = new(); - _sessionStateContainer.SetupSet(x => x.Cuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cuesheet => sessionStateContainerCuesheet = cuesheet); - _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(() => sessionStateContainerCuesheet); + _ = _sessionStateContainer.SetupSet(x => x.Cuesheet = It.IsAny<Cuesheet>()).Callback<Cuesheet>(cuesheet => sessionStateContainerCuesheet = cuesheet); + _ = _sessionStateContainer.SetupGet(x => x.Cuesheet).Returns(() => sessionStateContainerCuesheet); IList<Audiofile>? sessionStateContainerImportAudiofiles = []; - _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); + _ = _sessionStateContainer.SetupGet(x => x.ImportAudiofiles).Returns(() => sessionStateContainerImportAudiofiles); // Act await _service.ImportCuesheetAsync(); // Assert @@ -460,7 +460,7 @@ public void ImportData_ValidData_SetsImportfile() // Arrange var importData = nameof(ImportData_ValidData_SetsImportfile); IImportfile? sessionStateContainerImportfile = null; - _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); + _ = _sessionStateContainer.SetupSet(x => x.Importfile = It.IsAny<IImportfile>()).Callback<IImportfile>(x => sessionStateContainerImportfile = x); // Act _service.ImportData(importData); // Assert diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs index 2ba0c515..796a3eb5 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs @@ -60,12 +60,12 @@ public async Task AnalyseAsync_SampleCuesheet_CreatesValidCuesheetAsync() { SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(importOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(importOptions); var applicationOptions = new ApplicationOptions() { DefaultIsLinkedToPreviousTrack = true }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -100,12 +100,12 @@ public async Task AnalyseAsync_InvalidAudiofileSchemeWithMatchingTrackScheme_Doe { SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(importOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(importOptions); var applicationOptions = new ApplicationOptions() { DefaultIsLinkedToPreviousTrack = true }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -144,7 +144,7 @@ public async Task AnalyseAsync_InvalidSchemeTracks_CreatesAnalyseExceptionAsync( { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); // Act var importfile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -174,9 +174,9 @@ public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetA { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importfile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -215,9 +215,9 @@ public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCueshee { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -266,9 +266,9 @@ public async Task AnalyseAsync_InvalidScheme_CreatesAnalyseExceptionAsync() { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -307,9 +307,9 @@ public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesVal { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -348,9 +348,9 @@ public async Task AnalyseAsync_CuesheetTracksOnly_CreatesValidCuesheetAsync() { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -377,9 +377,9 @@ public async Task AnalyseAsync_CuesheetBug213_CreatesValidCuesheetAsync() { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -411,9 +411,9 @@ public async Task AnalyseAsync_CuesheetWithFlags_CreatesValidCuesheetAsync() { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -455,9 +455,9 @@ public async Task AnalyseAsync_CuesheetWithPreGapAndPostGap_CreatesValidCuesheet { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -505,9 +505,9 @@ public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOn { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -556,9 +556,9 @@ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentReco { SelectedImportProfile = importProfile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -590,9 +590,9 @@ public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedA { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -620,9 +620,9 @@ public async Task AnalyseAsync_WithRegularExpression_ReturnsCuesheetAsync() { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -640,8 +640,8 @@ public async Task AnalyseAsync_WithRegularExpression_ReturnsCuesheetAsync() Assert.AreEqual("Andale (MONTA (TN) Remix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); Assert.AreEqual(new DateTime(2025, 1, 29, 22, 30, 3), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().StartDateTime); Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sasha Fashion"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "2025/1/29 21:48:55"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Sasha Fashion"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "2025/1/29 21:48:55"), importFile.FileContentRecognized); } [TestMethod()] @@ -659,9 +659,9 @@ public async Task AnalyseAsync_WithoutRegularExpression_ReturnsCuesheetAsync() { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -678,13 +678,13 @@ public async Task AnalyseAsync_WithoutRegularExpression_ReturnsCuesheetAsync() Assert.AreEqual("Chasing the Sun (Original Mix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); Assert.IsNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Begin); Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "DJFreezeT"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Rabbit Hole Mix"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "0123456789123"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Nikolay Kirov"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Chasing the Sun (Original Mix)"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "SHDW & Obscure Shape"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Wächter der Nacht (Original Mix)"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "DJFreezeT"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Rabbit Hole Mix"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "0123456789123"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Nikolay Kirov"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Chasing the Sun (Original Mix)"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "SHDW & Obscure Shape"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Wächter der Nacht (Original Mix)"), importFile.FileContentRecognized); } [TestMethod()] @@ -731,9 +731,9 @@ public async Task AnalyseAsync_TextfileWithStartDateTime_CreatesValidCuesheetAsy { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -768,9 +768,9 @@ public async Task AnalyseAsync_WithCommonDataMatchingMultipleLines_SetsCommonDat { SelectedImportProfile = profile }; - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ImportOptions>()).ReturnsAsync(options); var applicationOptions = new ApplicationOptions(); - _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); + _ = _localStorageOptionsProviderMock.Setup(x => x.GetOptionsAsync<ApplicationOptions>()).ReturnsAsync(applicationOptions); // Act var importFile = await _textImportService.AnalyseAsync(fileContent); // Assert @@ -782,9 +782,9 @@ public async Task AnalyseAsync_WithCommonDataMatchingMultipleLines_SetsCommonDat Assert.AreEqual("c:\\AudioFile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\AudioFile.mp3"), importFile.FileContentRecognized); - Assert.Contains(String.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\AudioFile.mp3"), importFile.FileContentRecognized); + Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), importFile.FileContentRecognized); } } \ No newline at end of file diff --git a/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs b/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs index c49a0f45..5d5a4495 100644 --- a/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs +++ b/AudioCuesheetEditor.Tests/Services/Options/LocalStorageOptionsProviderTests.cs @@ -47,7 +47,7 @@ public async Task SaveOptionsAsync_NonValidatableOptions_ReturnsSuccessAsync() { // Arrange var options = new ExportOptions(); - Boolean eventRaised = false; + var eventRaised = false; _service.OptionSaved += delegate { eventRaised = true; @@ -68,7 +68,7 @@ public async Task SaveOptionsAsync_ValidOptions_ReturnsSuccessAsync() ProjectFilename = "Test.ace", CuesheetFilename = "Test.cue" }; - Boolean eventRaised = false; + var eventRaised = false; _service.OptionSaved += delegate { eventRaised = true; @@ -89,7 +89,7 @@ public async Task SaveOptionsAsync_InvalidOptions_ReturnsFailureAsync() CuesheetFilename = null, ProjectFilename = null }; - Boolean eventRaised = false; + var eventRaised = false; _service.OptionSaved += delegate { eventRaised = true; diff --git a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs index 1ef18686..241b4840 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs @@ -40,7 +40,7 @@ public async Task TimespanTextChanged_ValidInput_SetsPropertyCorrectly() } }; var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); @@ -62,7 +62,7 @@ public async Task TimespanTextChanged_InvalidInput_SetsNull() } }; var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); @@ -82,7 +82,7 @@ public void GetTimespanFormatted_ValidFormat_ReturnsCorrectString() DisplayTimeSpanFormat = @"hh\:mm\:ss" }; var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); @@ -101,7 +101,7 @@ public void GetTimespanFormatted_InvalidFormat_FallbackToDefault() DisplayTimeSpanFormat = "INVALID_FORMAT" }; var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); @@ -123,7 +123,7 @@ public async Task GetTimespanAsync_CustomValidFormat_ReturnsTimeSpanAsync() } }; var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); @@ -146,7 +146,7 @@ public async Task GetTimespanAsync_CustomInvalidFormat_ReturnsNullAsync() } }; var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); @@ -162,7 +162,7 @@ public async Task GetTimespanAsync_DefaultFormat_ReturnsTimeSpanAsync() // Arrange var options = new ApplicationOptions(); var mockOptionsProvider = new Mock<ILocalStorageOptionsProvider>(); - mockOptionsProvider + _ = mockOptionsProvider .Setup(p => p.GetOptionsAsync<ApplicationOptions>()) .ReturnsAsync(options); var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); diff --git a/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs b/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs index 962e647a..de5dbbab 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/SessionStateContainerTests.cs @@ -65,10 +65,10 @@ public async Task Cuesheet_SetNewValueInDetailView_ShouldTriggerActiveCuesheetCh // Arrange var newCuesheet = new Cuesheet(); var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); - bool activeCuesheetChangedEvent = false; - bool cuesheetChangedEvent = false; + var activeCuesheetChangedEvent = false; + var cuesheetChangedEvent = false; _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => activeCuesheetChangedEvent = true; _sessionStateContainer.CuesheetChanged += (sender, args) => cuesheetChangedEvent = true; @@ -89,10 +89,10 @@ public async Task Cuesheet_SetNewValueInImportView_ShouldNotTriggerActiveCueshee { ActiveTab = ViewMode.ImportView }; - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); - bool eventTriggered = false; - bool cuesheetChangedEvent = false; + var eventTriggered = false; + var cuesheetChangedEvent = false; _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; _sessionStateContainer.CuesheetChanged += (sender, args) => cuesheetChangedEvent = true; // Act @@ -112,9 +112,9 @@ public async Task ImportCuesheet_SetNewValueInImportView_ShouldTriggerActiveCues { ActiveTab = ViewMode.ImportView }; - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); - bool eventTriggered = false; + var eventTriggered = false; _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; // Act @@ -130,9 +130,9 @@ public async Task ImportCuesheet_SetNewValueInDetailView_ShouldTriggerActiveCues // Arrange var newImportCuesheet = new Cuesheet(); var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); - bool eventTriggered = false; + var eventTriggered = false; _sessionStateContainer.ActiveCuesheetChanged += (sender, args) => eventTriggered = true; // Act @@ -147,7 +147,7 @@ public async Task ResetImportAsync_RevokeObjectUrls_ShouldClearPropertiesAsync() { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); _sessionStateContainer.Importfile = Mock.Of<IImportfile>(); _sessionStateContainer.ImportCuesheet = new Cuesheet(); @@ -193,7 +193,7 @@ public async Task ResetImportAsync_RevokeObjectUrlsNotSet_ShouldClearPropertiesA { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); _sessionStateContainer.Importfile = Mock.Of<IImportfile>(); _sessionStateContainer.ImportCuesheet = new Cuesheet(); @@ -239,7 +239,7 @@ public async Task InitializeAsync_NotInitialized_ShouldInitializeAsync() { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); // Act await _sessionStateContainer.InitializeAsync(); // Assert @@ -251,7 +251,7 @@ public async Task InitializeAsync_Initialized_ShouldNotInitializeAsync() { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); // Act await _sessionStateContainer.InitializeAsync(); @@ -264,7 +264,7 @@ public async Task ActiveCuesheet_Initialized_ReturnsDetailViewCuesheet() { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); // Act var cuesheet = _sessionStateContainer.ActiveCuesheet; @@ -277,16 +277,13 @@ public async Task ActiveCuesheet_SwitchViewSignalesUpdate_ReturnsImportViewCuesh { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); viewOptions.ActiveTab = ViewMode.ImportView; - _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => - { - _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions); - }); - - Boolean activeCuesheetChangedEventTriggered = false; + _ = _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions)); + + var activeCuesheetChangedEventTriggered = false; _sessionStateContainer.ActiveCuesheetChanged += delegate { activeCuesheetChangedEventTriggered = true; @@ -296,7 +293,7 @@ public async Task ActiveCuesheet_SwitchViewSignalesUpdate_ReturnsImportViewCuesh { Title = "ImportCuesheet" }; - await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); + _ = await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); // Act var cuesheet = _sessionStateContainer.ActiveCuesheet; // Assert @@ -309,25 +306,22 @@ public async Task ActiveCuesheet_SaveOptionsSetsActiveCuesheetOnce_ReturnsDetail { // Arrange var viewOptions = new ViewOptions(); - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); - _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => - { - _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions); - }); + _ = _localStorageOptionsProvider.Setup(x => x.SaveOptionsAsync(viewOptions)).Callback(() => _localStorageOptionsProvider.Raise(x => x.OptionSaved += null, _localStorageOptionsProvider.Object, viewOptions)); _sessionStateContainer.Cuesheet.Title = "Cuesheet"; _sessionStateContainer.ImportCuesheet = new() { Title = "ImportCuesheet" }; viewOptions.ActiveTab = ViewMode.ImportView; - await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); - Boolean activeCuesheetChangedEventTriggered = false; + _ = await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); + var activeCuesheetChangedEventTriggered = false; _sessionStateContainer.ActiveCuesheetChanged += delegate { activeCuesheetChangedEventTriggered = true; }; - await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); + _ = await _localStorageOptionsProvider.Object.SaveOptionsAsync(viewOptions); // Act var cuesheet = _sessionStateContainer.ActiveCuesheet; // Assert @@ -343,7 +337,7 @@ public async Task ActiveCuesheet_InitializedWithImportView_ReturnsDetailViewCues { ActiveTab = ViewMode.ImportView }; - _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); + _ = _localStorageOptionsProvider.Setup(x => x.GetOptionsAsync<ViewOptions>()).ReturnsAsync(viewOptions); await _sessionStateContainer.InitializeAsync(); // Act var result = _sessionStateContainer.ActiveCuesheet; diff --git a/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs b/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs index e71f74a3..447c3bc5 100644 --- a/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs +++ b/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs @@ -36,7 +36,7 @@ public class FlagJsonConverter : JsonConverter<Flag> public override void Write(Utf8JsonWriter writer, Flag value, JsonSerializerOptions options) { - if ((value != null) && (String.IsNullOrEmpty(value.CuesheetLabel) == false)) + if ((value != null) && (string.IsNullOrEmpty(value.CuesheetLabel) == false)) { writer.WriteStringValue(value.CuesheetLabel); } diff --git a/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs b/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs index f6930603..88373c4f 100644 --- a/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs +++ b/AudioCuesheetEditor/Extensions/WebAssemblyHostExtension.cs @@ -20,13 +20,13 @@ namespace AudioCuesheetEditor.Extensions; public static class WebAssemblyHostExtension { - public async static Task SetCultureFromConfigurationAsync(this WebAssemblyHost host) + public static async Task SetCultureFromConfigurationAsync(this WebAssemblyHost host) { var localizationService = host.Services.GetRequiredService<LocalizationService>(); await localizationService.SetCultureFromConfigurationAsync(); } - public async static Task InitializeSessionStateContainer(this WebAssemblyHost host) + public static async Task InitializeSessionStateContainer(this WebAssemblyHost host) { var sessionStateContainer = host.Services.GetRequiredService<ISessionStateContainer>(); await sessionStateContainer.InitializeAsync(); diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs index 4091bf80..abf3eba7 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs @@ -20,20 +20,20 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet; public class CDTextfile { string name; - public CDTextfile(String name) + public CDTextfile(string name) { - if (String.IsNullOrEmpty(name)) + if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } this.name = name; } - public String Name + public string Name { get => name; set { - if (String.IsNullOrEmpty(value)) + if (string.IsNullOrEmpty(value)) { throw new ArgumentNullException(nameof(value)); } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs index 73f2c69e..5c49c273 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs @@ -21,15 +21,15 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet; public class Cuesheet() : Validateable, ICuesheet { - public String? Artist { get; set; } + public string? Artist { get; set; } - public String? Title { get; set; } + public string? Title { get; set; } public IList<Audiofile> Audiofiles { get; set; } = []; public CDTextfile? CDTextfile { get; set; } - public String? Cataloguenumber { get; set; } + public string? Cataloguenumber { get; set; } [JsonIgnore] public bool IsRecording => RecordingStart.HasValue; @@ -39,7 +39,7 @@ public class Cuesheet() : Validateable, ICuesheet public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { @@ -53,7 +53,7 @@ public override ValidationResult Validate(string property) break; case nameof(Artist): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Artist)) + if (string.IsNullOrEmpty(Artist)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Artist))); @@ -61,7 +61,7 @@ public override ValidationResult Validate(string property) break; case nameof(Title): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Title)) + if (string.IsNullOrEmpty(Title)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Title))); @@ -69,9 +69,9 @@ public override ValidationResult Validate(string property) break; case nameof(Cataloguenumber): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Cataloguenumber) == false) + if (string.IsNullOrEmpty(Cataloguenumber) == false) { - if (Cataloguenumber.All(Char.IsDigit) == false) + if (Cataloguenumber.All(char.IsDigit) == false) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} must only contain numbers!", nameof(Cataloguenumber))); diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs index f571a397..00f106dc 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs @@ -17,20 +17,20 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet; public class CuesheetConstants { - public static readonly String CuesheetArtist = "PERFORMER"; - public static readonly String CuesheetTitle = "TITLE"; - public static readonly String CuesheetFileName = "FILE"; - public static readonly String CuesheetTrack = "TRACK"; - public static readonly String CuesheetTrackAudio = "AUDIO"; - public static readonly String TrackArtist = "PERFORMER"; - public static readonly String TrackTitle = "TITLE"; - public static readonly String TrackIndex01 = "INDEX 01"; - public static readonly String TrackFlags = "FLAGS"; - public static readonly String TrackPreGap = "PREGAP"; - public static readonly String TrackPostGap = "POSTGAP"; - public static readonly String Tab = "\t"; - public static readonly String CuesheetCDTextfile = "CDTEXTFILE"; - public static readonly String CuesheetCatalogueNumber = "CATALOG"; - public static readonly String MarkHTMLStart = "<Mark>"; - public static readonly String RecognizedMarkHTML = MarkHTMLStart + "{0}" + "</Mark>"; + public static readonly string CuesheetArtist = "PERFORMER"; + public static readonly string CuesheetTitle = "TITLE"; + public static readonly string CuesheetFileName = "FILE"; + public static readonly string CuesheetTrack = "TRACK"; + public static readonly string CuesheetTrackAudio = "AUDIO"; + public static readonly string TrackArtist = "PERFORMER"; + public static readonly string TrackTitle = "TITLE"; + public static readonly string TrackIndex01 = "INDEX 01"; + public static readonly string TrackFlags = "FLAGS"; + public static readonly string TrackPreGap = "PREGAP"; + public static readonly string TrackPostGap = "POSTGAP"; + public static readonly string Tab = "\t"; + public static readonly string CuesheetCDTextfile = "CDTEXTFILE"; + public static readonly string CuesheetCatalogueNumber = "CATALOG"; + public static readonly string MarkHTMLStart = "<Mark>"; + public static readonly string RecognizedMarkHTML = MarkHTMLStart + "{0}" + "</Mark>"; } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs index 3e4db379..60e9b53b 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Flag.cs @@ -51,15 +51,15 @@ static Flag() AvailableFlags = list.AsReadOnly(); } - public String Name { get; private set; } - public String CuesheetLabel { get; private set; } - Flag(String name, String cuesheetLabel) + public string Name { get; private set; } + public string CuesheetLabel { get; private set; } + Flag(string name, string cuesheetLabel) { - if (String.IsNullOrEmpty(name) == true) + if (string.IsNullOrEmpty(name) == true) { throw new ArgumentNullException(nameof(name)); } - if (String.IsNullOrEmpty(cuesheetLabel) == true) + if (string.IsNullOrEmpty(cuesheetLabel) == true) { throw new ArgumentNullException(nameof(cuesheetLabel)); } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs index e9e736be..f0364683 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/IAudiofile.cs @@ -17,5 +17,5 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet; public interface IAudiofile { - String? Name { get; set; } + string? Name { get; set; } } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs index e46775ca..03a04834 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportAudiofile.cs @@ -2,6 +2,6 @@ public class ImportAudiofile : IAudiofile { - public String? Name { get; set; } + public string? Name { get; set; } public IList<ImportTrack> Tracks { get; } = []; } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs index 495aa21c..efd43ec2 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs @@ -22,8 +22,8 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet; public class Track : Validateable, ITrack { public ushort? Position { get; set; } - public String? Artist { get; set; } - public String? Title { get; set; } + public string? Artist { get; set; } + public string? Title { get; set; } public TimeSpan? Begin { get; set; } public TimeSpan? End { get; set; } [JsonIgnore] @@ -77,13 +77,13 @@ public TimeSpan? Length /// <summary> /// Set that this track is linked to the previous track in cuesheet /// </summary> - public Boolean IsLinkedToPreviousTrack { get; set; } + public bool IsLinkedToPreviousTrack { get; set; } [JsonIgnore] public Audiofile? Audiofile { get; set; } public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { @@ -110,7 +110,7 @@ public override ValidationResult Validate(string property) if (positionTrackShouldHave != Position) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? String.Empty, Title ?? String.Empty, Begin != null ? Begin : String.Empty, End != null ? End : String.Empty, positionTrackShouldHave)); + validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? string.Empty, Title ?? string.Empty, Begin != null ? Begin : string.Empty, End != null ? End : string.Empty, positionTrackShouldHave)); } } } diff --git a/AudioCuesheetEditor/Model/Entity/IValidateable.cs b/AudioCuesheetEditor/Model/Entity/IValidateable.cs index e030b442..54bea1e2 100644 --- a/AudioCuesheetEditor/Model/Entity/IValidateable.cs +++ b/AudioCuesheetEditor/Model/Entity/IValidateable.cs @@ -27,7 +27,7 @@ public interface IValidateable /// </summary> /// <param name="property"></param> /// <returns></returns> - ValidationResult Validate(String property); + ValidationResult Validate(string property); } public enum ValidationStatus { diff --git a/AudioCuesheetEditor/Model/Entity/Validateable.cs b/AudioCuesheetEditor/Model/Entity/Validateable.cs index 69d46d28..d79d74e7 100644 --- a/AudioCuesheetEditor/Model/Entity/Validateable.cs +++ b/AudioCuesheetEditor/Model/Entity/Validateable.cs @@ -19,13 +19,13 @@ namespace AudioCuesheetEditor.Model.Entity; public abstract class Validateable : IValidateable { - public event EventHandler<String>? ValidateablePropertyChanged; + public event EventHandler<string>? ValidateablePropertyChanged; public ValidationResult Validate() { ValidationResult validationResult = new() { Status = ValidationStatus.NoValidation }; List<ValidationMessage> validationMessages = []; - foreach (var property in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + foreach (var property in GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { var result = Validate(property.Name); validationMessages.AddRange(result.ValidationMessages); @@ -50,10 +50,7 @@ public ValidationResult Validate() return validationResult; } - public abstract ValidationResult Validate(String property); + public abstract ValidationResult Validate(string property); - protected void OnValidateablePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") - { - ValidateablePropertyChanged?.Invoke(this, propertyName); - } + protected void OnValidateablePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") => ValidateablePropertyChanged?.Invoke(this, propertyName); } diff --git a/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs b/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs index 7ecc9937..59f70bbb 100644 --- a/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs +++ b/AudioCuesheetEditor/Model/Entity/ValidationMessage.cs @@ -19,19 +19,19 @@ namespace AudioCuesheetEditor.Model.Entity; public class ValidationMessage { - public ValidationMessage(String message, params object[]? args) + public ValidationMessage(string message, params object[]? args) { - if (String.IsNullOrEmpty(message) == true) + if (string.IsNullOrEmpty(message) == true) { throw new ArgumentNullException(nameof(message)); } Message = message; Parameter = args; } - public String Message { get; private set; } + public string Message { get; private set; } public object[]? Parameter { get; private set; } - public String GetMessageLocalized(IStringLocalizer<ValidationMessage> localizer) + public string GetMessageLocalized(IStringLocalizer<ValidationMessage> localizer) { object[]? arguments = null; if (Parameter != null) @@ -41,11 +41,11 @@ public String GetMessageLocalized(IStringLocalizer<ValidationMessage> localizer) } if (arguments != null) { - for (int i = 0; i < arguments.Length; i++) + for (var i = 0; i < arguments.Length; i++) { - if ((arguments[i] != null) && (arguments[i].GetType() == typeof(String))) + if ((arguments[i] != null) && (arguments[i].GetType() == typeof(string))) { - arguments[i] = localizer[(String)arguments[i]]; + arguments[i] = localizer[(string)arguments[i]]; } } return localizer[Message, arguments]; diff --git a/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs b/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs index 4440f5a9..480656a1 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/AudioCodec.cs @@ -18,21 +18,21 @@ namespace AudioCuesheetEditor.Model.IO.Audio; public class AudioCodec { - public String MimeType { get; private set; } - public String FileExtension { get; private set; } - public String Name { get; private set; } + public string MimeType { get; private set; } + public string FileExtension { get; private set; } + public string Name { get; private set; } - public AudioCodec(String mimeType, String fileExtension, String name) + public AudioCodec(string mimeType, string fileExtension, string name) { - if (String.IsNullOrEmpty(mimeType)) + if (string.IsNullOrEmpty(mimeType)) { throw new ArgumentNullException(nameof(mimeType)); } - if (String.IsNullOrEmpty(fileExtension)) + if (string.IsNullOrEmpty(fileExtension)) { throw new ArgumentNullException(nameof(fileExtension)); } - if (String.IsNullOrEmpty(name)) + if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index a0b55130..bbb27371 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -35,10 +35,11 @@ public class Audiofile() : Validateable, IAudiofile new AudioCodec("audio/flac", ".flac", "AudioCodec FLAC") ]; + //TODO AudioCodec? _audioCodec; - String? _name; + string? _name; - public Audiofile(String? name, String? objectURL, AudioCodec? audioCodec, TimeSpan? duration = null) : this() + public Audiofile(string? name, string? objectURL, AudioCodec? audioCodec, TimeSpan? duration = null) : this() { Name = name; ObjectURL = objectURL; @@ -46,7 +47,7 @@ public Audiofile(String? name, String? objectURL, AudioCodec? audioCodec, TimeSp Duration = duration; } - public String? Name + public string? Name { get => _name; set @@ -61,7 +62,7 @@ public String? Name } [JsonIgnore] - public String? ObjectURL { get; set; } + public string? ObjectURL { get; set; } /// <summary> /// Duration of the audio file @@ -70,14 +71,14 @@ public String? Name public AudioCodec? AudioCodec { - get { return _audioCodec; } + get => _audioCodec; set { _audioCodec = value; if ((_audioCodec != null) && (Name?.EndsWith(_audioCodec.FileExtension) == false)) { //Replace file ending - Name = String.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), _audioCodec.FileExtension); + Name = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), _audioCodec.FileExtension); } } } @@ -86,7 +87,7 @@ public AudioCodec? AudioCodec public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { @@ -110,7 +111,7 @@ public override ValidationResult Validate(string property) { foreach (var trackWithSamePosition in track) { - validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : String.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : String.Empty, trackWithSamePosition.Artist ?? String.Empty, trackWithSamePosition.Title ?? String.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : String.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : String.Empty)); + validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : string.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : string.Empty, trackWithSamePosition.Artist ?? string.Empty, trackWithSamePosition.Title ?? string.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : string.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : string.Empty)); } } } @@ -124,7 +125,7 @@ public override ValidationResult Validate(string property) validationMessages ??= []; foreach (var trackBetween in tracksBetween) { - validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : String.Empty, track.Artist ?? String.Empty, track.Title ?? String.Empty, track.Begin != null ? track.Begin : String.Empty, track.End != null ? track.End : String.Empty, trackBetween.Position != null ? trackBetween.Position : String.Empty, trackBetween.Artist ?? String.Empty, trackBetween.Title ?? String.Empty, trackBetween.Begin != null ? trackBetween.Begin : String.Empty, trackBetween.End != null ? trackBetween.End : String.Empty)); + validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : string.Empty, track.Artist ?? string.Empty, track.Title ?? string.Empty, track.Begin != null ? track.Begin : string.Empty, track.End != null ? track.End : string.Empty, trackBetween.Position != null ? trackBetween.Position : string.Empty, trackBetween.Artist ?? string.Empty, trackBetween.Title ?? string.Empty, trackBetween.Begin != null ? trackBetween.Begin : string.Empty, trackBetween.End != null ? trackBetween.End : string.Empty)); } } } @@ -132,7 +133,7 @@ public override ValidationResult Validate(string property) break; case nameof(Name): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Name)) + if (string.IsNullOrEmpty(Name)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Name))); diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs index 42cb6370..54e8bdee 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportfile.cs @@ -19,6 +19,6 @@ namespace AudioCuesheetEditor.Model.IO.Export; public class Exportfile { public static readonly string DefaultCuesheetFilename = "Cuesheet.cue"; - public string Name { get; set; } = String.Empty; + public string Name { get; set; } = string.Empty; public string? Content { get; set; } } diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs index f7eb9ee3..b23017d3 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs @@ -21,27 +21,27 @@ namespace AudioCuesheetEditor.Model.IO.Export; public class Exportprofile : Validateable { - public static readonly String DefaultFileName = "Export.txt"; + public static readonly string DefaultFileName = "Export.txt"; - public static readonly String SchemeCuesheetArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Artist), SchemeCharacter); - public static readonly String SchemeCuesheetTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Title), SchemeCharacter); - public static readonly String SchemeAudiofileName = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Audiofile), nameof(Audiofile.Name), SchemeCharacter); - public static readonly String SchemeCuesheetCDTextfile = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.CDTextfile), SchemeCharacter); - public static readonly String SchemeCuesheetCatalogueNumber = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Cataloguenumber), SchemeCharacter); - public static readonly String SchemeTrackArtist = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Artist), SchemeCharacter); - public static readonly String SchemeTrackTitle = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Title), SchemeCharacter); - public static readonly String SchemeTrackBegin = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Begin), SchemeCharacter); - public static readonly String SchemeTrackEnd = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.End), SchemeCharacter); - public static readonly String SchemeTrackLength = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Length), SchemeCharacter); - public static readonly String SchemeTrackPosition = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Position), SchemeCharacter); - public static readonly String SchemeTrackFlags = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Flags), SchemeCharacter); - public static readonly String SchemeTrackPreGap = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PreGap), SchemeCharacter); - public static readonly String SchemeTrackPostGap = String.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PostGap), SchemeCharacter); - public static readonly String SchemeDate = String.Format("{0}Date{1}", SchemeCharacter, SchemeCharacter); - public static readonly String SchemeDateTime = String.Format("{0}DateTime{1}", SchemeCharacter, SchemeCharacter); - public static readonly String SchemeTime = String.Format("{0}Time{1}", SchemeCharacter, SchemeCharacter); + public static readonly string SchemeCuesheetArtist = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Artist), SchemeCharacter); + public static readonly string SchemeCuesheetTitle = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Title), SchemeCharacter); + public static readonly string SchemeAudiofileName = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Audiofile), nameof(Audiofile.Name), SchemeCharacter); + public static readonly string SchemeCuesheetCDTextfile = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.CDTextfile), SchemeCharacter); + public static readonly string SchemeCuesheetCatalogueNumber = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Cataloguenumber), SchemeCharacter); + public static readonly string SchemeTrackArtist = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Artist), SchemeCharacter); + public static readonly string SchemeTrackTitle = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Title), SchemeCharacter); + public static readonly string SchemeTrackBegin = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Begin), SchemeCharacter); + public static readonly string SchemeTrackEnd = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.End), SchemeCharacter); + public static readonly string SchemeTrackLength = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Length), SchemeCharacter); + public static readonly string SchemeTrackPosition = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Position), SchemeCharacter); + public static readonly string SchemeTrackFlags = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Flags), SchemeCharacter); + public static readonly string SchemeTrackPreGap = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PreGap), SchemeCharacter); + public static readonly string SchemeTrackPostGap = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PostGap), SchemeCharacter); + public static readonly string SchemeDate = string.Format("{0}Date{1}", SchemeCharacter, SchemeCharacter); + public static readonly string SchemeDateTime = string.Format("{0}DateTime{1}", SchemeCharacter, SchemeCharacter); + public static readonly string SchemeTime = string.Format("{0}Time{1}", SchemeCharacter, SchemeCharacter); - public static readonly Dictionary<String, String> AvailableCuesheetSchemes = new() + public static readonly Dictionary<string, string> AvailableCuesheetSchemes = new() { { nameof(Cuesheet.Artist), SchemeCuesheetArtist }, { nameof(Cuesheet.Title), SchemeCuesheetTitle }, @@ -51,11 +51,11 @@ public class Exportprofile : Validateable { "DateTime", SchemeDateTime }, { "Time", SchemeTime } }; - public static readonly Dictionary<String, String> AvailableAudiofileSchemes = new() + public static readonly Dictionary<string, string> AvailableAudiofileSchemes = new() { { nameof(Audiofile.Name), SchemeAudiofileName } }; - public static readonly Dictionary<String, String> AvailableTrackSchemes = new() + public static readonly Dictionary<string, string> AvailableTrackSchemes = new() { { nameof(Track.Position), SchemeTrackPosition }, { nameof(Track.Artist), SchemeTrackArtist }, @@ -68,53 +68,53 @@ public class Exportprofile : Validateable { nameof(Track.PostGap), SchemeTrackPostGap } }; - public const String SchemeCharacter = "%"; + public const string SchemeCharacter = "%"; - String _schemeHead; - String _schemeAudiofiles; - String _schemeTracks; - String _schemeFooter; - String _filename; - String _name; + string _schemeHead; + string _schemeAudiofiles; + string _schemeTracks; + string _schemeFooter; + string _filename; + string _name; public Exportprofile() { Id = Guid.NewGuid(); - _schemeHead = String.Empty; - _schemeTracks = String.Empty; - _schemeAudiofiles = String.Empty; - _schemeFooter = String.Empty; + _schemeHead = string.Empty; + _schemeTracks = string.Empty; + _schemeAudiofiles = string.Empty; + _schemeFooter = string.Empty; _filename = DefaultFileName; var random = new Random(); - _name = String.Format("{0}_{1}", nameof(Exportprofile), random.Next(1, 100)); + _name = string.Format("{0}_{1}", nameof(Exportprofile), random.Next(1, 100)); } public Guid Id { get; init; } - public String Name + public string Name { get => _name; set { _name = value; OnValidateablePropertyChanged(); } } - public String SchemeHead + public string SchemeHead { get => _schemeHead; set { _schemeHead = value; OnValidateablePropertyChanged(); } } - public String SchemeTracks + public string SchemeTracks { get => _schemeTracks; set { _schemeTracks = value; OnValidateablePropertyChanged(); } } - public String SchemeAudiofiles + public string SchemeAudiofiles { get => _schemeAudiofiles; set { _schemeAudiofiles = value; OnValidateablePropertyChanged(); } } - public String SchemeFooter + public string SchemeFooter { get => _schemeFooter; set { _schemeFooter = value; OnValidateablePropertyChanged(); } } - public String Filename + public string Filename { get => _filename; set { _filename = value; OnValidateablePropertyChanged(); } @@ -122,7 +122,7 @@ public String Filename public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { @@ -144,7 +144,7 @@ public override ValidationResult Validate(string property) break; case nameof(Filename): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Filename)) + if (string.IsNullOrEmpty(Filename)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Filename))); @@ -152,7 +152,7 @@ public override ValidationResult Validate(string property) break; case nameof(Name): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Name)) + if (string.IsNullOrEmpty(Name)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Name))); @@ -162,7 +162,7 @@ public override ValidationResult Validate(string property) return ValidationResult.Create(validationStatus, validationMessages); } - static List<ValidationMessage>? CheckForUnresolvablePlaceholders(String scheme, string schemeName, List<Dictionary<String, String>> schemesToCheck) + static List<ValidationMessage>? CheckForUnresolvablePlaceholders(string scheme, string schemeName, List<Dictionary<string, string>> schemesToCheck) { List<ValidationMessage>? validationMessages = null; foreach (var schemeToCheck in schemesToCheck) diff --git a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs index deb93a79..309c96da 100644 --- a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs @@ -23,11 +23,11 @@ public interface IImportfile /// <summary> /// File content /// </summary> - String? FileContent { get; set; } + string? FileContent { get; set; } /// <summary> /// File content with marking which passages has been recognized by scheme /// </summary> - String? FileContentRecognized { get; set; } + string? FileContentRecognized { get; set; } /// <summary> /// Exception that has been thrown while reading out the file /// </summary> diff --git a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs index 89033df7..41834f7e 100644 --- a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs @@ -21,28 +21,28 @@ namespace AudioCuesheetEditor.Model.IO.Import; public class Importprofile : Validateable { - public static readonly IEnumerable<String> AvailableSchemeCuesheet = [nameof(ImportCuesheet.Artist), nameof(ImportCuesheet.Title), nameof(ImportCuesheet.CDTextfile), nameof(ImportCuesheet.Cataloguenumber)]; + public static readonly IEnumerable<string> AvailableSchemeCuesheet = [nameof(ImportCuesheet.Artist), nameof(ImportCuesheet.Title), nameof(ImportCuesheet.CDTextfile), nameof(ImportCuesheet.Cataloguenumber)]; - public static readonly IEnumerable<String> AvailableSchemeAudiofiles = [nameof(ImportAudiofile.Name)]; + public static readonly IEnumerable<string> AvailableSchemeAudiofiles = [nameof(ImportAudiofile.Name)]; - public static readonly IEnumerable<String> AvailableSchemesTrack = [nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), nameof(ImportTrack.End), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), nameof(ImportTrack.PreGap), nameof(ImportTrack.PostGap), nameof(ImportTrack.StartDateTime)]; + public static readonly IEnumerable<string> AvailableSchemesTrack = [nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), nameof(ImportTrack.End), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), nameof(ImportTrack.PreGap), nameof(ImportTrack.PostGap), nameof(ImportTrack.StartDateTime)]; public Guid Id { get; init; } = Guid.NewGuid(); - public String? Name { get; set; } - public Boolean UseRegularExpression { get; set; } - public String? SchemeCuesheet { get; set; } - public String? SchemeAudiofiles { get; set; } - public String? SchemeTracks { get; set; } + public string? Name { get; set; } + public bool UseRegularExpression { get; set; } + public string? SchemeCuesheet { get; set; } + public string? SchemeAudiofiles { get; set; } + public string? SchemeTracks { get; set; } public TimeSpanFormat? TimeSpanFormat { get; set; } public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { case nameof(SchemeCuesheet): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(SchemeCuesheet) == false) + if (string.IsNullOrEmpty(SchemeCuesheet) == false) { var containsPlaceHolder = false; var enumerator = AvailableSchemeCuesheet.GetEnumerator(); @@ -62,7 +62,7 @@ public override ValidationResult Validate(string property) break; case nameof(SchemeAudiofiles): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(SchemeAudiofiles) == false) + if (string.IsNullOrEmpty(SchemeAudiofiles) == false) { var containsPlaceHolder = false; var enumerator = AvailableSchemeAudiofiles.GetEnumerator(); @@ -82,7 +82,7 @@ public override ValidationResult Validate(string property) break; case nameof(SchemeTracks): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(SchemeTracks) == false) + if (string.IsNullOrEmpty(SchemeTracks) == false) { var containsPlaceHolder = false; var enumerator = AvailableSchemesTrack.GetEnumerator(); diff --git a/AudioCuesheetEditor/Model/IO/Projectfile.cs b/AudioCuesheetEditor/Model/IO/Projectfile.cs index 06dcab28..00baa5b8 100644 --- a/AudioCuesheetEditor/Model/IO/Projectfile.cs +++ b/AudioCuesheetEditor/Model/IO/Projectfile.cs @@ -22,7 +22,7 @@ namespace AudioCuesheetEditor.Model.IO; public class Projectfile(Cuesheet cuesheet) { - public static readonly String DefaultFilename = "Project.ace"; + public static readonly string DefaultFilename = "Project.ace"; public static readonly JsonSerializerOptions Options = new() { diff --git a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs index e34f6901..55c7360d 100644 --- a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs @@ -23,13 +23,13 @@ namespace AudioCuesheetEditor.Model.Options; public class ApplicationOptions : IOptions { public const LogLevel DefaultLogLevel = LogLevel.Information; - public String? CultureName { get; set; } = LocalizationService.DefaultCulture; + public string? CultureName { get; set; } = LocalizationService.DefaultCulture; [JsonIgnore] public CultureInfo Culture { get { - if (String.IsNullOrEmpty(CultureName) == false) + if (string.IsNullOrEmpty(CultureName) == false) { return new CultureInfo(CultureName); } @@ -40,7 +40,7 @@ public CultureInfo Culture } } public TimeSpanFormat? TimeSpanFormat { get; set; } - public Boolean DefaultIsLinkedToPreviousTrack { get; set; } = true; - public String? DisplayTimeSpanFormat { get; set; } + public bool DefaultIsLinkedToPreviousTrack { get; set; } = true; + public string? DisplayTimeSpanFormat { get; set; } public LogLevel MinimumLogLevel { get; set; } = DefaultLogLevel; } diff --git a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs index fd164cb8..70173d47 100644 --- a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs +++ b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs @@ -23,12 +23,12 @@ public class DownloadOptions : Validateable, IOptions { string? projectFilename = Projectfile.DefaultFilename; string? cuesheetFilename = Exportfile.DefaultCuesheetFilename; - public String? CuesheetFilename + public string? CuesheetFilename { get => cuesheetFilename; set { - if (String.IsNullOrEmpty(value) == false) + if (string.IsNullOrEmpty(value) == false) { var extension = Path.GetExtension(value); if (extension?.Equals(FileExtensions.Cuesheet, StringComparison.OrdinalIgnoreCase) == false) @@ -39,12 +39,12 @@ public String? CuesheetFilename cuesheetFilename = value; } } - public String? ProjectFilename + public string? ProjectFilename { get => projectFilename; set { - if (String.IsNullOrEmpty(value) == false) + if (string.IsNullOrEmpty(value) == false) { var extension = Path.GetExtension(value); if (extension?.Equals(FileExtensions.Projectfile, StringComparison.OrdinalIgnoreCase) == false) @@ -57,7 +57,7 @@ public String? ProjectFilename } public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { @@ -86,7 +86,7 @@ public override ValidationResult Validate(string property) break; case nameof(ProjectFilename): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(ProjectFilename)) + if (string.IsNullOrEmpty(ProjectFilename)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(ProjectFilename))); @@ -100,7 +100,7 @@ public override ValidationResult Validate(string property) validationMessages.Add(new ValidationMessage("{0} must end with '{1}'!", nameof(ProjectFilename), FileExtensions.Projectfile)); } var filename = Path.GetFileNameWithoutExtension(ProjectFilename); - if (String.IsNullOrEmpty(filename)) + if (string.IsNullOrEmpty(filename)) { validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} must have a filename!", nameof(ProjectFilename))); diff --git a/AudioCuesheetEditor/Model/Options/ViewOptions.cs b/AudioCuesheetEditor/Model/Options/ViewOptions.cs index ee54d730..e581d499 100644 --- a/AudioCuesheetEditor/Model/Options/ViewOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ViewOptions.cs @@ -27,7 +27,7 @@ public class ViewOptions : IOptions { [JsonIgnore] public ViewMode ActiveTab { get; set; } - public String? ActiveTabName + public string? ActiveTabName { get => Enum.GetName(ActiveTab); set diff --git a/AudioCuesheetEditor/Model/UI/TraceableChange.cs b/AudioCuesheetEditor/Model/UI/TraceableChange.cs index 875e5ce8..34954823 100644 --- a/AudioCuesheetEditor/Model/UI/TraceableChange.cs +++ b/AudioCuesheetEditor/Model/UI/TraceableChange.cs @@ -19,7 +19,7 @@ public class TraceableChange { public TraceableChange(object? previousValue, string propertyName) { - if (String.IsNullOrEmpty(propertyName)) + if (string.IsNullOrEmpty(propertyName)) { throw new ArgumentNullException(nameof(propertyName)); } diff --git a/AudioCuesheetEditor/Model/UI/TracedChanges.cs b/AudioCuesheetEditor/Model/UI/TracedChanges.cs index 300e3399..a7883a12 100644 --- a/AudioCuesheetEditor/Model/UI/TracedChanges.cs +++ b/AudioCuesheetEditor/Model/UI/TracedChanges.cs @@ -18,5 +18,5 @@ namespace AudioCuesheetEditor.Model.UI; public class TracedChanges(IEnumerable<TracedChange> changes) { public List<TracedChange> Changes { get; } = [.. changes]; - public bool HasTraceableObject { get { return Changes.Any(x => x.TraceableObject != null); } } + public bool HasTraceableObject => Changes.Any(x => x.TraceableObject != null); } diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs index 2129e0dd..2476c4d8 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs @@ -20,13 +20,13 @@ namespace AudioCuesheetEditor.Model.Utility; public class TimeSpanFormat : Validateable { - public const String Days = "Days"; - public const String Hours = "Hours"; - public const String Minutes = "Minutes"; - public const String Seconds = "Seconds"; - public const String Milliseconds = "Milliseconds"; + public const string Days = "Days"; + public const string Hours = "Hours"; + public const string Minutes = "Minutes"; + public const string Seconds = "Seconds"; + public const string Milliseconds = "Milliseconds"; - public static readonly IEnumerable<String> AvailableTimespanScheme; + public static readonly IEnumerable<string> AvailableTimespanScheme; static TimeSpanFormat() { @@ -37,7 +37,7 @@ static TimeSpanFormat() string? scheme; - public String? Scheme + public string? Scheme { get => scheme; set @@ -48,10 +48,10 @@ public String? Scheme } } - public TimeSpan? ParseTimeSpan(String input) + public TimeSpan? ParseTimeSpan(string input) { TimeSpan? timespan = null; - if ((String.IsNullOrEmpty(Scheme) == false) && (String.IsNullOrEmpty(input) == false)) + if ((string.IsNullOrEmpty(Scheme) == false) && (string.IsNullOrEmpty(input) == false)) { var pattern = CreateFlexibleRegexPattern(Scheme); var match = Regex.Match(input, pattern); @@ -87,13 +87,13 @@ public String? Scheme public override ValidationResult Validate(string property) { - ValidationStatus validationStatus = ValidationStatus.NoValidation; + var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; switch (property) { case nameof(Scheme): validationStatus = ValidationStatus.Success; - if (String.IsNullOrEmpty(Scheme) == false) + if (string.IsNullOrEmpty(Scheme) == false) { if ((Scheme.Contains(Days) == false) && (Scheme.Contains(Hours) == false) diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs index 3e07bdd9..7c8ad968 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanUtility.cs @@ -17,12 +17,12 @@ namespace AudioCuesheetEditor.Model.Utility; public class TimeSpanUtility { - public static TimeSpan? ParseTimeSpan(String input, TimeSpanFormat? timeSpanFormat = null) + public static TimeSpan? ParseTimeSpan(string input, TimeSpanFormat? timeSpanFormat = null) { TimeSpan? result = null; - if (String.IsNullOrEmpty(input) == false) + if (string.IsNullOrEmpty(input) == false) { - if (String.IsNullOrEmpty(timeSpanFormat?.Scheme)) + if (string.IsNullOrEmpty(timeSpanFormat?.Scheme)) { if (TimeSpan.TryParse(input, out var parsed)) { diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs index 38b84b89..d9ee4a8f 100644 --- a/AudioCuesheetEditor/Program.cs +++ b/AudioCuesheetEditor/Program.cs @@ -35,10 +35,7 @@ builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddLocalization(); -builder.Services.AddMudServices(config => -{ - config.PopoverOptions.OverflowPadding = 0; -}); +builder.Services.AddMudServices(config => config.PopoverOptions.OverflowPadding = 0); builder.Services.AddBlazorDownloadFile(); diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index 5cff89f4..b03e9b72 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -61,11 +61,11 @@ public TimeSpan? TotalTime return null; } } - public Boolean IsPaused { get; private set; } = false; - public Boolean IsPlaybackPossible => _sessionStateContainer.Cuesheet.Audiofiles.Any(x => string.IsNullOrEmpty(x.ObjectURL) == false); - public Boolean IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; - public Boolean IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; - public Boolean IsPlaying => _currentlyPlayingAudiofile != null; + public bool IsPaused { get; private set; } = false; + public bool IsPlaybackPossible => _sessionStateContainer.Cuesheet.Audiofiles.Any(x => string.IsNullOrEmpty(x.ObjectURL) == false); + public bool IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; + public bool IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; + public bool IsPlaying => _currentlyPlayingAudiofile != null; public async Task InitializeAsync() { @@ -158,9 +158,9 @@ public async Task PlayPreviousTrackAsync() public async Task SeekAsync(TimeSpan time) { - TimeSpan cumulativeDuration = TimeSpan.Zero; + var cumulativeDuration = TimeSpan.Zero; Audiofile? targetAudiofile = null; - TimeSpan targetPositionInAudiofile = TimeSpan.Zero; + var targetPositionInAudiofile = TimeSpan.Zero; foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) { @@ -171,7 +171,7 @@ public async Task SeekAsync(TimeSpan time) if (audiofile.Duration.HasValue) { - TimeSpan nextCumulativeDuration = cumulativeDuration + audiofile.Duration.Value; + var nextCumulativeDuration = cumulativeDuration + audiofile.Duration.Value; if (time >= cumulativeDuration && time < nextCumulativeDuration) { @@ -273,10 +273,7 @@ void Reset() IsPaused = false; } - void StartTimer() - { - _updateTimer ??= new Timer(UpdateCurrentPosition, null, 0, 500); - } + void StartTimer() => _updateTimer ??= new Timer(UpdateCurrentPosition, null, 0, 500); void StopTimer() { @@ -313,7 +310,7 @@ void SetDurationBeforeCurrentlyPlayingAudiofile() } _durationBeforeCurrentlyPlayingAudiofile = TimeSpan.Zero; var index = _sessionStateContainer.Cuesheet.Audiofiles.IndexOf(_currentlyPlayingAudiofile); - for (int i = 0; i < index; i++) + for (var i = 0; i < index; i++) { var audiofile = _sessionStateContainer.Cuesheet.Audiofiles[i]; if (audiofile.Duration.HasValue) diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index 550f4647..a9ae433d 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -39,14 +39,14 @@ public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeMa public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile) { _traceChangeManager.BulkEdit = true; - if (String.IsNullOrEmpty(audiofile.ObjectURL) == false) + if (string.IsNullOrEmpty(audiofile.ObjectURL) == false) { await ClearPropertiesAsync(audiofile, false); } var codec = _fileInputManager.GetAudioCodec(browserFile.Name, browserFile.ContentType); var objectUrl = await _fileInputManager.GetObjectUrlAsync(browserFile); TimeSpan? duration = null; - if (String.IsNullOrEmpty(objectUrl) == false) + if (string.IsNullOrEmpty(objectUrl) == false) { var durationSeconds = await _jsRuntime.InvokeAsync<double>("getAudioDurationFromFile", objectUrl); duration = TimeSpan.FromSeconds(durationSeconds); @@ -64,7 +64,7 @@ public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFi } /// <inheritdoc/> - public async Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true) + public async Task ClearPropertiesAsync(Audiofile audiofile, bool setTracing = true) { if (setTracing) { @@ -100,7 +100,7 @@ public void SetProperty<TProperty>(Audiofile audiofile, Expression<Func<Audiofil } /// <inheritdoc/> - public void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true) + public void AddTrack(Audiofile audiofile, Track track, bool setTracing = true) { if (setTracing) { @@ -135,7 +135,7 @@ public void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true } /// <inheritdoc/> - public void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, Boolean setTracing = true) + public void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, bool setTracing = true) { var cuesheet = _sessionStateContainer.ActiveCuesheet; var intersection = audiofile.Tracks.Intersect(tracksToRemove); @@ -160,7 +160,7 @@ public void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, } } - Boolean SetValue<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value) + bool SetValue<TProperty>(Audiofile audiofile, Expression<Func<Audiofile, TProperty>> propertyExpression, TProperty value) { if (propertyExpression.Body is not MemberExpression memberExpression) { diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs index 8acfcd7f..0bb7cd4e 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs @@ -307,7 +307,7 @@ public Result MoveDown(HashSet<Audiofile> selectedAudiofiles) return Result.Success(); } - void SetValue<TProperty>(Cuesheet cuesheet, Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value, Boolean traceChanges = true) + void SetValue<TProperty>(Cuesheet cuesheet, Expression<Func<Cuesheet, TProperty>> propertyExpression, TProperty value, bool traceChanges = true) { if (propertyExpression.Body is not MemberExpression memberExpression) { @@ -353,7 +353,7 @@ void SwitchAudiofile(Track trackToMove, Audiofile audiofileToMoveTo) var currentTrackPositionAudiofile = trackToMove.Audiofile; //Switch audiofiles without audiofilemanager since methods there capsulate much logic var currentTrackPositionAudiofileTracks = new List<Track>(currentTrackPositionAudiofile!.Tracks); - currentTrackPositionAudiofileTracks.Remove(trackToMove); + _ = currentTrackPositionAudiofileTracks.Remove(trackToMove); _traceChangeManager.AddChange(new(currentTrackPositionAudiofile, new(currentTrackPositionAudiofile.Tracks, nameof(Audiofile.Tracks)))); currentTrackPositionAudiofile.Tracks = currentTrackPositionAudiofileTracks; var audiofileToMoveToTracks = new List<Track>(audiofileToMoveTo.Tracks) diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs index af6a0b1e..ec1f4082 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs @@ -38,7 +38,7 @@ public interface IAudiofileManager /// <param name="audiofile"></param> /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> /// <returns></returns> - Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true); + Task ClearPropertiesAsync(Audiofile audiofile, bool setTracing = true); /// <summary> /// Set property for an audio file /// </summary> @@ -53,12 +53,12 @@ public interface IAudiofileManager /// <param name="audiofile"></param> /// <param name="track"></param> /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> - void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true); + void AddTrack(Audiofile audiofile, Track track, bool setTracing = true); /// <summary> /// Remove tracks from the audiofile /// </summary> /// <param name="audiofile"></param> /// <param name="tracksToRemove"></param> /// <param name="setTracing">Parameter controlling if tracing should be handled by this service or by calling services</param> - void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, Boolean setTracing = true); + void RemoveTracks(Audiofile audiofile, IEnumerable<Track> tracksToRemove, bool setTracing = true); } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs index 0ddf534f..cc30747a 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/ICuesheetManager.cs @@ -55,25 +55,25 @@ public interface ICuesheetManager /// </summary> /// <param name="selectedTracks"></param> /// <returns></returns> - Boolean IsMoveUpPossible(HashSet<Track> selectedTracks); + bool IsMoveUpPossible(HashSet<Track> selectedTracks); /// <summary> /// Determines if moving audiofiles up is possible /// </summary> /// <param name="selectedAudiofiles"></param> /// <returns></returns> - Boolean IsMoveUpPossible(HashSet<Audiofile> selectedAudiofiles); + bool IsMoveUpPossible(HashSet<Audiofile> selectedAudiofiles); /// <summary> /// Determines if moving tracks down is possible /// </summary> /// <param name="selectedTracks"></param> /// <returns></returns> - Boolean IsMoveDownPossible(HashSet<Track> selectedTracks); + bool IsMoveDownPossible(HashSet<Track> selectedTracks); /// <summary> /// Determines if moving audiofiles down is possible /// </summary> /// <param name="selectedTracks"></param> /// <returns></returns> - Boolean IsMoveDownPossible(HashSet<Audiofile> selectedAudiofiles); + bool IsMoveDownPossible(HashSet<Audiofile> selectedAudiofiles); /// <summary> /// Moves selected tracks up /// </summary> diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs index d495030b..9671c785 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/ITrackManager.cs @@ -46,7 +46,7 @@ public interface ITrackManager /// <param name="setFlags"></param> /// <param name="setPreGap"></param> /// <param name="setPostGap"></param> - void CopyValues(ITrack source, Track target, Boolean setIsLinkedToPreviousTrack = true, Boolean setPosition = true, Boolean setArtist = true, Boolean setTitle = true, Boolean setBegin = true, Boolean setEnd = true, Boolean setLength = true, Boolean setFlags = true, Boolean setPreGap = true, Boolean setPostGap = true); + void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTrack = true, bool setPosition = true, bool setArtist = true, bool setTitle = true, bool setBegin = true, bool setEnd = true, bool setLength = true, bool setFlags = true, bool setPreGap = true, bool setPostGap = true); /// <summary> /// Create a clone of a track /// </summary> diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs index e7fe1aa3..3998435c 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs @@ -27,15 +27,12 @@ public class TrackManager(ITraceChangeManager traceChangeManager) : ITrackManage readonly ITraceChangeManager _traceChangeManager = traceChangeManager; /// <inheritdoc/> - public void SetProperty<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value) - { - SetValue(track, propertyExpression, value); - } + public void SetProperty<TProperty>(Track track, Expression<Func<Track, TProperty>> propertyExpression, TProperty value) => SetValue(track, propertyExpression, value); /// <inheritdoc/> public Track Clone(ITrack track) { - Boolean setLength = true; + var setLength = true; if (track.Begin.HasValue && track.End.HasValue) { setLength = false; diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index 22475201..24dd1204 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -28,7 +28,7 @@ public class AudioImportService(IDialogManager dialogManager, ISessionStateConta readonly ICuesheetManager _cuesheetManager = cuesheetManager; /// <inheritdoc/> - public async Task<Boolean> MapAudioImportAsync() + public async Task<bool> MapAudioImportAsync() { // Just run an import if there are audiofiles to import, otherwise this service has nothing to do if (_sessionStateContainer.ImportAudiofiles.Count == 0) @@ -66,7 +66,7 @@ public async Task<Boolean> MapAudioImportAsync() return cancel == false; } - Boolean MapImportfiles() + bool MapImportfiles() { _sessionStateContainer.ImportAudiofileMapping.Clear(); foreach (var audiofile in _sessionStateContainer.ActiveCuesheet!.Audiofiles) @@ -76,7 +76,7 @@ Boolean MapImportfiles() { if (importAudiofile != null) { - _sessionStateContainer.ImportAudiofiles.Remove(importAudiofile); + _ = _sessionStateContainer.ImportAudiofiles.Remove(importAudiofile); _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, importAudiofile); } } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index ed42b51e..926b07d5 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -62,34 +62,34 @@ string WriteCuesheet() var builder = new StringBuilder(); if (string.IsNullOrEmpty(_sessionStateContainer.Cuesheet.Cataloguenumber) == false) { - builder.AppendLine(string.Format("{0} {1}", CuesheetConstants.CuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber)); + _ = builder.AppendLine(string.Format("{0} {1}", CuesheetConstants.CuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber)); } if (_sessionStateContainer.Cuesheet.CDTextfile != null) { - builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile.Name)); + _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile.Name)); } - builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, _sessionStateContainer.Cuesheet.Title)); - builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); + _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, _sessionStateContainer.Cuesheet.Title)); + _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) { - builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".",string.Empty).ToUpper())); + _ = builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".", string.Empty).ToUpper())); foreach(var track in audiofile.Tracks) { - builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position, CuesheetConstants.CuesheetTrackAudio)); - builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); - builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); + _ = builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position, CuesheetConstants.CuesheetTrackAudio)); + _ = builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); + _ = builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); if (track.Flags.Any()) { - builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); + _ = builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); } if (track.PreGap.HasValue) { - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); + _ = builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); } if (track.Begin.HasValue) { var begin = track.Begin.Value; - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); + _ = builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); } else { @@ -97,7 +97,7 @@ string WriteCuesheet() } if (track.PostGap.HasValue) { - builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); + _ = builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); } } } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs index 860de309..bb747361 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs @@ -61,13 +61,13 @@ public static IImportfile Analyse(string fileContent) StringBuilder recognizedContent = new(); foreach (var line in fileContent.Split(Environment.NewLine)) { - String? recognizedLine = line; - if (String.IsNullOrEmpty(line) == false) + var recognizedLine = line; + if (string.IsNullOrEmpty(line) == false) { if ((regexCuesheetArtist.IsMatch(line) == true) && (track == null)) { var match = regexCuesheetArtist.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetArtistGroupName); if (matchGroup != null) { @@ -76,13 +76,13 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetArtistGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetArtistGroupName)); } } if ((regexCuesheetTitle.IsMatch(line) == true) && (track == null)) { var match = regexCuesheetTitle.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetTitleGroupName); if (matchGroup != null) { @@ -91,13 +91,13 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetTitleGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetTitleGroupName)); } } if (regexCuesheetFile.IsMatch(line) == true) { var match = regexCuesheetFile.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetFileNameGroupName); if (matchGroup != null) { @@ -106,13 +106,13 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetFileNameGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetFileNameGroupName)); } } if (regexCDTextfile.IsMatch(line) == true) { var match = regexCDTextfile.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetCDTextfileGroupName); if (matchGroup != null) { @@ -121,13 +121,13 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetCDTextfileGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetCDTextfileGroupName)); } } if (regexCatalogueNumber.IsMatch(line) == true) { var match = regexCatalogueNumber.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetCatalogueNumberGroupName); if (matchGroup != null) { @@ -136,18 +136,18 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", cuesheetCatalogueNumberGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetCatalogueNumberGroupName)); } } if (regexTrackBegin.IsMatch(line) == true) { track = new ImportTrack(); - recognizedLine = String.Format(CuesheetConstants.RecognizedMarkHTML, line); + recognizedLine = string.Format(CuesheetConstants.RecognizedMarkHTML, line); } if ((regexTrackArtist.IsMatch(line) == true) && (track != null)) { var match = regexTrackArtist.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackArtistGroupName); if (matchGroup != null) { @@ -156,13 +156,13 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackArtistGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", trackArtistGroupName)); } } if ((regexTrackTitle.IsMatch(line) == true) && (track != null)) { var match = regexTrackTitle.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackTitleGroupName); if (matchGroup != null) { @@ -171,13 +171,13 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackTitleGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", trackTitleGroupName)); } } if (regexTrackFlags.IsMatch(line) == true) { var match = regexTrackFlags.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackFlagsGroupName); if (matchGroup != null) { @@ -189,18 +189,18 @@ public static IImportfile Analyse(string fileContent) } else { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); + throw new NullReferenceException(string.Format("Track was null during input {0}", line)); } } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackFlagsGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", trackFlagsGroupName)); } } if (regexTrackPreGap.IsMatch(line) == true) { var match = regexTrackPreGap.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackPreGapGroupName); if (matchGroup != null) { @@ -213,18 +213,18 @@ public static IImportfile Analyse(string fileContent) } else { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); + throw new NullReferenceException(string.Format("Track was null during input {0}", line)); } } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackPreGapGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", trackPreGapGroupName)); } } if (regexTrackIndex.IsMatch(line) == true) { var match = regexTrackIndex.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackIndex01GroupName); if (matchGroup != null) { @@ -237,19 +237,19 @@ public static IImportfile Analyse(string fileContent) } else { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); + throw new NullReferenceException(string.Format("Track was null during input {0}", line)); } } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackIndex01GroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", trackIndex01GroupName)); } audiofile?.Tracks.Add(track); } if (regexTrackPostGap.IsMatch(line) == true) { var match = regexTrackPostGap.Match(line); - recognizedLine = line.Replace(match.Value, String.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackPostGapGroupName); if (matchGroup != null) { @@ -262,16 +262,16 @@ public static IImportfile Analyse(string fileContent) } else { - throw new NullReferenceException(String.Format("Track was null during input {0}", line)); + throw new NullReferenceException(string.Format("Track was null during input {0}", line)); } } else { - throw new ArgumentException(String.Format("Group '{0}' was null!", trackPostGapGroupName)); + throw new ArgumentException(string.Format("Group '{0}' was null!", trackPostGapGroupName)); } } } - recognizedContent.AppendLine(recognizedLine); + _ = recognizedContent.AppendLine(recognizedLine); } importfile.FileContentRecognized = recognizedContent.ToString().TrimEnd(Environment.NewLine.ToCharArray()); } diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index be18b5ae..464ef487 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -65,12 +65,12 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(header); + _ = builder.AppendLine(header); foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) { var audiofileLine = exportprofile.SchemeAudiofiles .Replace(Exportprofile.SchemeAudiofileName, audiofile.Name); - builder.AppendLine(audiofileLine); + _ = builder.AppendLine(audiofileLine); IEnumerable<Track> tracks = audiofile.Tracks.OrderBy(x => x.Position); if (tracks.Any()) { @@ -89,7 +89,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(trackLine); + _ = builder.AppendLine(trackLine); } } } @@ -102,7 +102,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); - builder.AppendLine(footer); + _ = builder.AppendLine(footer); } return builder.ToString(); } diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index a9f22d7e..4363505b 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -46,15 +46,9 @@ public class FileInputManager(IJSRuntime jsRuntime, ILogger<FileInputManager> lo } /// <inheritdoc/> - public async Task<String> GetObjectUrlAsync(IBrowserFile browserFile) - { - return await _jsRuntime.InvokeAsync<String>("getObjectURLFromMudFileUpload", browserFile.Name, browserFile.Size, browserFile.ContentType, browserFile.LastModified.ToUnixTimeMilliseconds()); - } + public async Task<string> GetObjectUrlAsync(IBrowserFile browserFile) => await _jsRuntime.InvokeAsync<string>("getObjectURLFromMudFileUpload", browserFile.Name, browserFile.Size, browserFile.ContentType, browserFile.LastModified.ToUnixTimeMilliseconds()); - public bool IsValidAudiofile(string fileName, string? fileContentType = null) - { - return GetAudioCodec(fileName, fileContentType) != null; - } + public bool IsValidAudiofile(string fileName, string? fileContentType = null) => GetAudioCodec(fileName, fileContentType) != null; public bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable<string> fileExtensions) { @@ -62,10 +56,10 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m { _logger.LogDebug("CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtensions: '{fileExtensions}'", fileName, fileContentType, mimeType, fileExtensions); } - Boolean fileMimeTypeMatches = false; - if (String.IsNullOrEmpty(mimeType) == false) + var fileMimeTypeMatches = false; + if (string.IsNullOrEmpty(mimeType) == false) { - if (String.IsNullOrEmpty(fileContentType) == false) + if (string.IsNullOrEmpty(fileContentType) == false) { if (mimeType.EndsWith("/*")) { @@ -95,7 +89,7 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m if (codec != null) { TimeSpan? duration = null; - if (String.IsNullOrEmpty(fileUpload.ObjectUrl) == false) + if (string.IsNullOrEmpty(fileUpload.ObjectUrl) == false) { var durationSeconds = await _jsRuntime.InvokeAsync<double>("getAudioDurationFromFile", fileUpload.ObjectUrl); duration = TimeSpan.FromSeconds(durationSeconds); @@ -124,10 +118,7 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m } /// <inheritdoc/> - public bool IsValidForImportView(string? fileContentType, string fileName) - { - return CheckFileMimeType(fileContentType, fileName, FileMimeTypes.Text, [FileExtensions.Text, FileExtensions.HTML]); - } + public bool IsValidForImportView(string? fileContentType, string fileName) => CheckFileMimeType(fileContentType, fileName, FileMimeTypes.Text, [FileExtensions.Text, FileExtensions.HTML]); /// <inheritdoc/> public async Task<string> ReadFileContentAsync(IBrowserFile browserFile) diff --git a/AudioCuesheetEditor/Services/IO/IAudioImportService.cs b/AudioCuesheetEditor/Services/IO/IAudioImportService.cs index 7f13cf45..dc594db1 100644 --- a/AudioCuesheetEditor/Services/IO/IAudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/IAudioImportService.cs @@ -24,5 +24,5 @@ public interface IAudioImportService /// Maps the import audio from session state to the active cuesheet. If mapping is not possible automatically the user gets a dialog. /// </summary> /// <returns></returns> - Task<Boolean> MapAudioImportAsync(); + Task<bool> MapAudioImportAsync(); } diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs index de31b2af..70fb24e0 100644 --- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs @@ -30,7 +30,7 @@ public interface IFileInputManager /// </summary> /// <param name="browserFile"></param> /// <returns></returns> - Task<String> GetObjectUrlAsync(IBrowserFile browserFile); + Task<string> GetObjectUrlAsync(IBrowserFile browserFile); /// <summary> /// Checks if a file content type and name matches given parameters /// </summary> diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index c8dbd9bb..8ba880d7 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -45,7 +45,7 @@ public class ImportManager(ISessionStateContainer sessionStateContainer, ITraceC readonly ITrackManager _trackManager = trackManager; readonly IAudioImportService _audioImportService = audioImportService; - public void ImportData(String? data) + public void ImportData(string? data) { var stopwatch = Stopwatch.StartNew(); _sessionStateContainer.Importfile = new Importfile() @@ -61,12 +61,12 @@ public void ImportData(String? data) } } - public async Task<Boolean> AnalyseImportfile() + public async Task<bool> AnalyseImportfile() { ResetTracing(); var stopwatch = Stopwatch.StartNew(); var fileContent = _sessionStateContainer.Importfile?.FileContent; - if (String.IsNullOrEmpty(fileContent) == false) + if (string.IsNullOrEmpty(fileContent) == false) { switch (_sessionStateContainer.Importfile?.FileType) { @@ -198,7 +198,7 @@ void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) } if (cuesheetToCopy is ImportCuesheet importCuesheet) { - if (String.IsNullOrEmpty(importCuesheet.CDTextfile) == false) + if (string.IsNullOrEmpty(importCuesheet.CDTextfile) == false) { target.CDTextfile = new CDTextfile(importCuesheet.CDTextfile); } @@ -224,7 +224,7 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) targetAudiofile ??= new Audiofile() { Name = importAudiofile.Name, - AudioCodec = String.IsNullOrEmpty(importAudiofile.Name) == false ? _fileInputManager.GetAudioCodec(importAudiofile.Name) : null + AudioCodec = string.IsNullOrEmpty(importAudiofile.Name) == false ? _fileInputManager.GetAudioCodec(importAudiofile.Name) : null }; tracks = importAudiofile.Tracks; } @@ -264,7 +264,7 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) } TimeSpan? begin = TimeSpan.Zero; ushort position = 1; - for (int i = 0; i < sortedTracks.Count(); i++) + for (var i = 0; i < sortedTracks.Count(); i++) { var track = sortedTracks.ElementAt(i); ITrack? nextTrack = null; diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index 61e4efc2..b6381174 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -63,9 +63,9 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, { return regex.Replace(input, match => { - string result = match.Value; + var result = match.Value; var groupInfos = new List<(int RelIndex, int Length, string Value, string Key)>(); - for (int matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++) + for (var matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++) { var group = match.Groups[matchCounter]; var key = regex.GroupNameFromNumber(matchCounter); @@ -76,7 +76,7 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, { SetValue(entity, property, group.Value, timeSpanFormat); } - int relIndex = group.Index - match.Index; + var relIndex = group.Index - match.Index; groupInfos.Add((relIndex, group.Length, group.Value, key)); } } @@ -88,8 +88,8 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, var sb = new StringBuilder(result); foreach (var (RelIndex, Length, Value, Key) in groupInfos) { - sb.Remove(RelIndex, Length); - sb.Insert(RelIndex, string.Format(CuesheetConstants.RecognizedMarkHTML, Value)); + _ = sb.Remove(RelIndex, Length); + _ = sb.Insert(RelIndex, string.Format(CuesheetConstants.RecognizedMarkHTML, Value)); } return sb.ToString(); }); @@ -107,7 +107,7 @@ static void SearchForCuesheetData(ref Importfile importFile, string fileContent, importFile.FileContentRecognized = regex.Replace(importFile.FileContentRecognized, match => { - string marked = ApplyRegexAndMarkGroups(cuesheet, regex, match.Value, importProfile.TimeSpanFormat); + var marked = ApplyRegexAndMarkGroups(cuesheet, regex, match.Value, importProfile.TimeSpanFormat); return marked; } ); @@ -145,7 +145,7 @@ void SearchForAudiofileData(ref Importfile importFile, string fileContent, Impor match => { var audiofile = new ImportAudiofile(); - string marked = ApplyRegexAndMarkGroups(audiofile, regex, match.Value, importProfile.TimeSpanFormat); + var marked = ApplyRegexAndMarkGroups(audiofile, regex, match.Value, importProfile.TimeSpanFormat); cuesheet!.Audiofiles.Add(audiofile); _audiofileStartIndices.Add(audiofile, match.Index); return marked; @@ -238,10 +238,10 @@ static string SearchLineByLineForEntry(string fileContent, Func<object> entityCr using (var reader = new StringReader(fileContent)) { string? line; - int pos = 0; + var pos = 0; while ((line = reader.ReadLine()) != null) { - Boolean stopSearch = false; + var stopSearch = false; // Check if this line is already analyzed if (line.Contains(CuesheetConstants.MarkHTMLStart) == false) { @@ -251,16 +251,16 @@ static string SearchLineByLineForEntry(string fileContent, Func<object> entityCr { stopSearch = ifEntityFound.Invoke(pos, entity); } - sb.AppendLine(markedLine); + _ = sb.AppendLine(markedLine); if (stopSearch) { - sb.Append(reader.ReadToEnd()); + _ = sb.Append(reader.ReadToEnd()); break; } } else { - sb.AppendLine(line); + _ = sb.AppendLine(line); } pos += line.Length + Environment.NewLine.Length; } @@ -278,7 +278,7 @@ static void SetValue(object entity, PropertyInfo property, string value, TimeSpa { property.SetValue(entity, Convert.ToUInt16(value)); } - if (property.PropertyType == typeof(String)) + if (property.PropertyType == typeof(string)) { property.SetValue(entity, value); } @@ -302,7 +302,7 @@ static void SetValue(object entity, PropertyInfo property, string value, TimeSpa static Regex CreateRegexPattern(string scheme, string[] fieldNames) { var parts = new List<string>(); - int idx = 0; + var idx = 0; while (idx < scheme.Length) { var field = fieldNames.FirstOrDefault(fn => scheme.IndexOf(fn, idx, StringComparison.Ordinal) == idx); @@ -313,44 +313,44 @@ static Regex CreateRegexPattern(string scheme, string[] fieldNames) } else { - int nextFieldIdx = scheme.Length; + var nextFieldIdx = scheme.Length; foreach (var fn in fieldNames) { - int pos = scheme.IndexOf(fn, idx, StringComparison.Ordinal); + var pos = scheme.IndexOf(fn, idx, StringComparison.Ordinal); if (pos >= 0 && pos < nextFieldIdx) { nextFieldIdx = pos; } } - string separator = scheme[idx..nextFieldIdx]; + var separator = scheme[idx..nextFieldIdx]; parts.Add(separator); idx = nextFieldIdx; } } var regexBuilder = new StringBuilder("^"); - for (int i = 0; i < parts.Count; i++) + for (var i = 0; i < parts.Count; i++) { var part = parts[i]; if (fieldNames.Contains(part)) { - bool isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p)); + var isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p)); if (isLast) { - regexBuilder.Append($@"(?<{part}>.+)"); + _ = regexBuilder.Append($@"(?<{part}>.+)"); } else { - regexBuilder.Append($@"(?<{part}>.+?)"); + _ = regexBuilder.Append($@"(?<{part}>.+?)"); } } else { - string sep = Regex.Escape(part).Replace("\\t", @"\t{1,}"); - regexBuilder.Append(sep); + var sep = Regex.Escape(part).Replace("\\t", @"\t{1,}"); + _ = regexBuilder.Append(sep); } } - regexBuilder.Append('$'); + _ = regexBuilder.Append('$'); return new Regex(regexBuilder.ToString()); } diff --git a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs index 51b9959c..393b1662 100644 --- a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs +++ b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs @@ -37,9 +37,9 @@ public class LocalStorageOptionsProvider(IJSRuntime jsRuntime, IStringLocalizer< public async Task<T> GetOptionsAsync<T>() where T : IOptions { var type = typeof(T); - IOptions? options = (IOptions?)Activator.CreateInstance(type); - String optionsJson = await _jsRuntime.InvokeAsync<String>("AppSettings.get", type.Name); - if (String.IsNullOrEmpty(optionsJson) == false) + var options = (IOptions?)Activator.CreateInstance(type); + var optionsJson = await _jsRuntime.InvokeAsync<string>("AppSettings.get", type.Name); + if (string.IsNullOrEmpty(optionsJson) == false) { try { @@ -116,7 +116,7 @@ public async Task<Result> SaveOptionsAsync(IOptions options) var valueProperty = ResolveNestedProperty(valuePropertyExpression.Body as MemberExpression, ref nestedInstance) ?? throw new ArgumentException("The provided value property expression does not reference a valid property."); valueProperty.SetValue(nestedInstance, Convert.ChangeType(value, valueProperty.PropertyType)); - await SaveOptionsAsync(options); + _ = await SaveOptionsAsync(options); } static PropertyInfo? ResolveNestedProperty(MemberExpression? memberExpression, ref object? targetObject) diff --git a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs index db86cd4d..5844d12f 100644 --- a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs +++ b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs @@ -23,32 +23,32 @@ namespace AudioCuesheetEditor.Services.Provider; public class MusicBrainzArtist { public Guid? Id { get; init; } - public String? Name { get; init; } - public String? Disambiguation { get; init; } + public string? Name { get; init; } + public string? Disambiguation { get; init; } } public class MusicBrainzTrack { public Guid? Id { get; init; } - public String? Artist { get; init; } - public String? Title { get; init; } + public string? Artist { get; init; } + public string? Title { get; init; } public TimeSpan? Length { get; init; } - public String? Disambiguation { get; init; } + public string? Disambiguation { get; init; } } public class MusicBrainzDataProvider(ILogger<MusicBrainzDataProvider> logger) { readonly ILogger<MusicBrainzDataProvider> _logger = logger; - public const String Application = "AudioCuesheetEditor"; - public const String ProjectUrl = "https://github.com/NeoCoderMatrix86/AudioCuesheetEditor"; + public const string Application = "AudioCuesheetEditor"; + public const string ProjectUrl = "https://github.com/NeoCoderMatrix86/AudioCuesheetEditor"; - String? applicationVersion = null; + string? applicationVersion = null; - public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(String? searchString, CancellationToken token) + public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(string? searchString, CancellationToken token) { List<MusicBrainzArtist> artistSearchResult = []; try { - if (String.IsNullOrEmpty(searchString) == false) + if (string.IsNullOrEmpty(searchString) == false) { using var query = new Query(Application, ApplicationVersion, ProjectUrl); var findArtistsResult = await query.FindArtistsAsync(searchString, simple: true, cancellationToken: token); @@ -62,32 +62,32 @@ public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(Stri return artistSearchResult.AsReadOnly(); } - public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(String? searchString, String? artist, CancellationToken token) + public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(string? searchString, string? artist, CancellationToken token) { List<MusicBrainzTrack> titleSearchResult = []; try { - if (String.IsNullOrEmpty(searchString) == false) + if (string.IsNullOrEmpty(searchString) == false) { using var query = new Query(Application, ApplicationVersion, ProjectUrl); ISearchResults<ISearchResult<IRecording>> findRecordingsResult; - if (String.IsNullOrEmpty(artist)) + if (string.IsNullOrEmpty(artist)) { findRecordingsResult = await query.FindRecordingsAsync(searchString, simple: true, cancellationToken: token); } else { - findRecordingsResult = await query.FindRecordingsAsync(String.Format("{0} AND artistname:{1}", searchString, artist), cancellationToken: token); + findRecordingsResult = await query.FindRecordingsAsync(string.Format("{0} AND artistname:{1}", searchString, artist), cancellationToken: token); } foreach (var result in findRecordingsResult.Results) { - String artistString = String.Empty; + var artistString = string.Empty; if (result.Item.ArtistCredit != null) { foreach (var artistCredit in result.Item.ArtistCredit) { artistString += artistCredit.Name; - if (String.IsNullOrEmpty(artistCredit.JoinPhrase) == false) + if (string.IsNullOrEmpty(artistCredit.JoinPhrase) == false) { artistString += artistCredit.JoinPhrase; } @@ -111,7 +111,7 @@ public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(String return titleSearchResult.AsReadOnly(); } - String? ApplicationVersion + string? ApplicationVersion { get { diff --git a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs index 684f365d..7e840065 100644 --- a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs +++ b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs @@ -36,14 +36,14 @@ public ApplicationOptionsTimeSpanParser(ILocalStorageOptionsProvider localStorag _initTask = InitAsync(); } - public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, TProperty>> expression, String value) + public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, TProperty>> expression, string value) { if (expression.Body is not MemberExpression memberExpression) { throw new ArgumentException("'expression' should be a member expression"); } await EnsureInitializedAsync(); - TimeSpan? result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); + var result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); switch (memberExpression.Member.MemberType) { case MemberTypes.Property: @@ -54,10 +54,10 @@ public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, } } - public async Task<TimeSpan?> GetTimespanAsync(String value) + public async Task<TimeSpan?> GetTimespanAsync(string value) { await EnsureInitializedAsync(); - TimeSpan? result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); + var result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); return result; } @@ -93,10 +93,7 @@ protected virtual void Dispose(bool disposing) } } - async Task InitAsync() - { - applicationOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); - } + async Task InitAsync() => applicationOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); async Task EnsureInitializedAsync() { diff --git a/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs b/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs index 26347c5c..95d4ffba 100644 --- a/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs +++ b/AudioCuesheetEditor/Services/UI/AutocompleteManager.cs @@ -21,7 +21,7 @@ public class AutocompleteManager(MusicBrainzDataProvider musicBrainzDataProvider { readonly MusicBrainzDataProvider _musicBrainzDataProvider = musicBrainzDataProvider; - public async Task<IEnumerable<MusicBrainzArtist>> SearchArtistsAsync(String? searchString, CancellationToken cancellationToken) + public async Task<IEnumerable<MusicBrainzArtist>> SearchArtistsAsync(string? searchString, CancellationToken cancellationToken) { try { @@ -38,7 +38,7 @@ public async Task<IEnumerable<MusicBrainzArtist>> SearchArtistsAsync(String? sea } } - public async Task<IEnumerable<MusicBrainzTrack>> SearchTitlesAsync(String? searchString, String? artist, CancellationToken cancellationToken) + public async Task<IEnumerable<MusicBrainzTrack>> SearchTitlesAsync(string? searchString, string? artist, CancellationToken cancellationToken) { try { diff --git a/AudioCuesheetEditor/Services/UI/DialogManager.cs b/AudioCuesheetEditor/Services/UI/DialogManager.cs index 5ca11e27..93f4f451 100644 --- a/AudioCuesheetEditor/Services/UI/DialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/DialogManager.cs @@ -62,15 +62,15 @@ public async Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks) var length = editMultipleTracksModalResult.EditedTrack.Length; var preGap = editMultipleTracksModalResult.EditedTrack.PreGap; var postGap = editMultipleTracksModalResult.EditedTrack.PostGap; - Boolean copyIsLinkedToPreviousTrack = editMultipleTracksModalResult.IsLinkedToPreviousTrackEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackArtist = editMultipleTracksModalResult.ArtistEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackTitle = editMultipleTracksModalResult.TitleEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackBegin = true; - Boolean copyTrackEnd = true; - Boolean copyTrackLength = true; - Boolean copyTrackFlags = editMultipleTracksModalResult.FlagsEditMode == DynamicEditValue.EnteredValueEquals; - Boolean copyTrackPreGap = true; - Boolean copyTrackPostGap = true; + var copyIsLinkedToPreviousTrack = editMultipleTracksModalResult.IsLinkedToPreviousTrackEditMode == DynamicEditValue.EnteredValueEquals; + var copyTrackArtist = editMultipleTracksModalResult.ArtistEditMode == DynamicEditValue.EnteredValueEquals; + var copyTrackTitle = editMultipleTracksModalResult.TitleEditMode == DynamicEditValue.EnteredValueEquals; + var copyTrackBegin = true; + var copyTrackEnd = true; + var copyTrackLength = true; + var copyTrackFlags = editMultipleTracksModalResult.FlagsEditMode == DynamicEditValue.EnteredValueEquals; + var copyTrackPreGap = true; + var copyTrackPostGap = true; //First process dynamic edit, because we need to increase each value separately switch (editMultipleTracksModalResult.BeginEditMode) { @@ -207,7 +207,7 @@ public void HideLoadingDialog() _loadingDialog = null; } - public async Task<Boolean> ShowImportAudiofilesDialogAsync() + public async Task<bool> ShowImportAudiofilesDialogAsync() { var parameters = new DialogParameters<ImportAudiofilesDialog> { diff --git a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs index 3e149312..b8a88deb 100644 --- a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs @@ -28,9 +28,9 @@ public interface ISessionStateContainer IList<Audiofile> ImportAudiofiles { get; set; } Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } IImportfile? Importfile { get; set; } - Boolean ImportIsAnalyzed { get; set; } - Task ResetImportAsync(Boolean revokeObjectURLs); - Task ResetAudioImportAsync(Boolean revokeObjectURLs); + bool ImportIsAnalyzed { get; set; } + Task ResetImportAsync(bool revokeObjectURLs); + Task ResetAudioImportAsync(bool revokeObjectURLs); /// <summary> /// Initialize this class /// </summary> diff --git a/AudioCuesheetEditor/Services/UI/LocalizationService.cs b/AudioCuesheetEditor/Services/UI/LocalizationService.cs index 7de8e115..96b3d63e 100644 --- a/AudioCuesheetEditor/Services/UI/LocalizationService.cs +++ b/AudioCuesheetEditor/Services/UI/LocalizationService.cs @@ -27,7 +27,7 @@ public class LocalizationService(ILocalStorageOptionsProvider localStorageOption readonly NavigationManager _navigationManager = navigationManager; readonly IJSRuntime _jsRuntime = jsRuntime; - public const String DefaultCulture = "en-US"; + public const string DefaultCulture = "en-US"; public static IReadOnlyCollection<CultureInfo> AvailableCultures { @@ -48,20 +48,20 @@ public async Task SetCultureFromConfigurationAsync() { var options = await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); - ChangeLanguage(options.Culture); + _ = ChangeLanguage(options.Culture); } public async Task ChangeLanguageAsync(CultureInfo culture) { if (ChangeLanguage(culture)) { - await _localStorageOptionsProvider.SaveOptionsValueAsync<ApplicationOptions>(x => x.CultureName!, culture.Name); + _ = await _localStorageOptionsProvider.SaveOptionsValueAsync<ApplicationOptions>(x => x.CultureName!, culture.Name); await _jsRuntime.InvokeVoidAsync("removeBeforeunload"); _navigationManager.NavigateTo(_navigationManager.Uri, true); } } - static Boolean ChangeLanguage(CultureInfo newCulture) + static bool ChangeLanguage(CultureInfo newCulture) { var contains = AvailableCultures.Contains(newCulture); if (contains) diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index c8b143e5..1d21e8be 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -71,7 +71,7 @@ public Cuesheet? ImportCuesheet public IList<Audiofile> ImportAudiofiles { get; set; } = []; public Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } = []; public IImportfile? Importfile { get; set; } - public Boolean ImportIsAnalyzed { get; set; } = false; + public bool ImportIsAnalyzed { get; set; } = false; /// <inheritdoc/> public async Task InitializeAsync() @@ -80,7 +80,7 @@ public async Task InitializeAsync() SetActiveCuesheet(); } - public async Task ResetImportAsync(Boolean revokeObjectURLs) + public async Task ResetImportAsync(bool revokeObjectURLs) { Importfile = null; await ResetAudioImportAsync(revokeObjectURLs); diff --git a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs index 87818879..a1747bcb 100644 --- a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs +++ b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs @@ -52,7 +52,7 @@ public void Undo() while (_undoStack.Count > 0 && changes == null) { changes = _undoStack[^1]; - _undoStack.Remove(changes); + _ = _undoStack.Remove(changes); if (changes.HasTraceableObject == false) { changes = null; @@ -61,7 +61,7 @@ public void Undo() if (changes != null && changes.HasTraceableObject) { var redoChanges = new List<TracedChange>(); - for (int i = changes.Changes.Count - 1; i >= 0; i--) + for (var i = changes.Changes.Count - 1; i >= 0; i--) { var change = changes.Changes.ElementAt(i); var tracedObject = change?.TraceableObject; @@ -90,7 +90,7 @@ public void Undo() } if (change != null) { - changes.Changes.Remove(change); + _ = changes.Changes.Remove(change); } } //Push the old value to redo stack @@ -109,7 +109,7 @@ public void Redo() while (_redoStack.Count > 0 && changes == null) { changes = _redoStack[^1]; - _redoStack.Remove(changes); + _ = _redoStack.Remove(changes); if (changes.HasTraceableObject == false) { changes = null; @@ -118,7 +118,7 @@ public void Redo() if (changes != null && changes.HasTraceableObject) { var undoChanges = new List<TracedChange>(); - for (int i = changes.Changes.Count - 1;i >= 0; i--) + for (var i = changes.Changes.Count - 1;i >= 0; i--) { var change = changes.Changes.ElementAt(i); var tracedObject = change?.TraceableObject; @@ -147,7 +147,7 @@ public void Redo() } if (change != null) { - changes.Changes.Remove(change); + _ = changes.Changes.Remove(change); } } //Push the old value to redo stack @@ -205,10 +205,10 @@ public void AddChange(TracedChange tracedChange) public void RemoveTracedChanges(IEnumerable<object> traceables) { - _undoStack.RemoveAll(x => x.HasTraceableObject == false); - _undoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); - _redoStack.RemoveAll(x => x.HasTraceableObject == false); - _redoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); + _ = _undoStack.RemoveAll(x => x.HasTraceableObject == false); + _ = _undoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); + _ = _redoStack.RemoveAll(x => x.HasTraceableObject == false); + _ = _redoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); } } diff --git a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs b/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs index 5b7068bd..3991f2e4 100644 --- a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs +++ b/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs @@ -38,20 +38,11 @@ protected override void OnInitialized() TraceChangeManager.RedoDone += TraceChangeManager_RedoDone; } - void TraceChangeManager_RedoDone(object? sender, EventArgs e) - { - StateHasChanged(); - } + void TraceChangeManager_RedoDone(object? sender, EventArgs e) => StateHasChanged(); - void TraceChangeManager_UndoDone(object? sender, EventArgs e) - { - StateHasChanged(); - } + void TraceChangeManager_UndoDone(object? sender, EventArgs e) => StateHasChanged(); - void TraceChangeManager_TracedObjectHistoryChanged(object? sender, EventArgs e) - { - StateHasChanged(); - } + void TraceChangeManager_TracedObjectHistoryChanged(object? sender, EventArgs e) => StateHasChanged(); protected virtual void Dispose(bool disposing) { From 876e6ef0410a93d4cd78629a628d3f37a4cabead Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:04:27 +0200 Subject: [PATCH 05/20] fix most CAs --- .../Model/Entity/ValidateableTests.cs | 15 ++++------ .../Model/IO/Audio/Audiofile.cs | 20 +++++-------- .../Model/Options/DownloadOptions.cs | 12 ++++---- .../Model/Utility/TimeSpanFormat.cs | 6 ++-- .../Services/Audio/PlaybackService.cs | 7 ++--- .../Provider/MusicBrainzDataProvider.cs | 8 ++--- .../UI/ApplicationOptionsTimeSpanParser.cs | 18 +++++------ .../Services/UI/SessionStateContainer.cs | 30 ++++++++----------- .../Shared/BaseLocalizedComponent.cs | 6 ++-- 9 files changed, 51 insertions(+), 71 deletions(-) diff --git a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs index 495ac126..ab4a253e 100644 --- a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs @@ -14,31 +14,26 @@ //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Model.Entity; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections.Generic; namespace AudioCuesheetEditor.Tests.Model.Entity; public class ValidateableTestClass : Validateable { - string? testProperty; - int? testProperty2; - public string? TestProperty { - get => testProperty; + get; set { - testProperty = value; + field = value; OnValidateablePropertyChanged(); } } public int? TestProperty2 { - get => testProperty2; + get; set { - testProperty2 = value; + field = value; OnValidateablePropertyChanged(); } } @@ -76,4 +71,4 @@ public void ValidateTest() testObject.TestProperty = "Test"; Assert.AreEqual(ValidationStatus.Success, testObject.Validate().Status); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index bbb27371..14166864 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -35,10 +35,6 @@ public class Audiofile() : Validateable, IAudiofile new AudioCodec("audio/flac", ".flac", "AudioCodec FLAC") ]; - //TODO - AudioCodec? _audioCodec; - string? _name; - public Audiofile(string? name, string? objectURL, AudioCodec? audioCodec, TimeSpan? duration = null) : this() { Name = name; @@ -49,15 +45,15 @@ public Audiofile(string? name, string? objectURL, AudioCodec? audioCodec, TimeSp public string? Name { - get => _name; + get; set { var extension = Path.GetExtension(value); - if (extension?.Equals(_audioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) + if (extension?.Equals(AudioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) { - value = $"{value}{_audioCodec?.FileExtension}"; + value = $"{value}{AudioCodec?.FileExtension}"; } - _name = value; + field = value; } } @@ -71,14 +67,14 @@ public string? Name public AudioCodec? AudioCodec { - get => _audioCodec; + get; set { - _audioCodec = value; - if ((_audioCodec != null) && (Name?.EndsWith(_audioCodec.FileExtension) == false)) + field = value; + if ((field != null) && (Name?.EndsWith(field.FileExtension) == false)) { //Replace file ending - Name = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), _audioCodec.FileExtension); + Name = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), field.FileExtension); } } } diff --git a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs index 70173d47..6b3a8390 100644 --- a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs +++ b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs @@ -21,11 +21,9 @@ namespace AudioCuesheetEditor.Model.Options; public class DownloadOptions : Validateable, IOptions { - string? projectFilename = Projectfile.DefaultFilename; - string? cuesheetFilename = Exportfile.DefaultCuesheetFilename; public string? CuesheetFilename { - get => cuesheetFilename; + get; set { if (string.IsNullOrEmpty(value) == false) @@ -36,12 +34,12 @@ public string? CuesheetFilename value = $"{value}{FileExtensions.Cuesheet}"; } } - cuesheetFilename = value; + field = value; } - } + } = Exportfile.DefaultCuesheetFilename; public string? ProjectFilename { - get => projectFilename; + get; set { if (string.IsNullOrEmpty(value) == false) @@ -52,7 +50,7 @@ public string? ProjectFilename value = $"{value}{FileExtensions.Projectfile}"; } } - projectFilename = value; + field = value; } } public override ValidationResult Validate(string property) diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs index 2476c4d8..89399ed8 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs @@ -35,14 +35,12 @@ static TimeSpanFormat() public event EventHandler? SchemeChanged; - string? scheme; - public string? Scheme { - get => scheme; + get; set { - scheme = value; + field = value; SchemeChanged?.Invoke(this, EventArgs.Empty); OnValidateablePropertyChanged(); } diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index b03e9b72..c524af5d 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -30,7 +30,6 @@ public class PlaybackService(IJSRuntime jsRuntime, ISessionStateContainer sessio Audiofile? _currentlyPlayingAudiofile; Timer? _updateTimer; readonly Lock _timerLock = new(); - TimeSpan? _currentPosition; DotNetObjectReference<PlaybackService>? _dotNetObjectReference; TimeSpan _durationBeforeCurrentlyPlayingAudiofile; @@ -38,12 +37,12 @@ public class PlaybackService(IJSRuntime jsRuntime, ISessionStateContainer sessio public TimeSpan? CurrentPosition { - get => _currentPosition; + get; private set { - if (_currentPosition != value) + if (field != value) { - _currentPosition = value; + field = value; CurrentPositionChanged?.Invoke(); } } diff --git a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs index 5844d12f..a0b45ef0 100644 --- a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs +++ b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs @@ -41,8 +41,6 @@ public class MusicBrainzDataProvider(ILogger<MusicBrainzDataProvider> logger) public const string Application = "AudioCuesheetEditor"; public const string ProjectUrl = "https://github.com/NeoCoderMatrix86/AudioCuesheetEditor"; - string? applicationVersion = null; - public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(string? searchString, CancellationToken token) { List<MusicBrainzArtist> artistSearchResult = []; @@ -115,15 +113,15 @@ public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(string { get { - if (applicationVersion == null) + if (field == null) { var versionAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>(); if (versionAttribute != null) { - applicationVersion = versionAttribute.InformationalVersion; + field = versionAttribute.InformationalVersion; } } - return applicationVersion; + return field; } } } diff --git a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs index 7e840065..12d6f976 100644 --- a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs +++ b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs @@ -25,9 +25,9 @@ public class ApplicationOptionsTimeSpanParser { readonly ILocalStorageOptionsProvider _localStorageOptionsProvider; - ApplicationOptions? applicationOptions; + ApplicationOptions? _applicationOptions; readonly Task? _initTask; - bool disposedValue; + bool _disposedValue; public ApplicationOptionsTimeSpanParser(ILocalStorageOptionsProvider localStorageOptionsProvider) { @@ -43,7 +43,7 @@ public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, throw new ArgumentException("'expression' should be a member expression"); } await EnsureInitializedAsync(); - var result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); + var result = TimeSpanUtility.ParseTimeSpan(value, _applicationOptions?.TimeSpanFormat); switch (memberExpression.Member.MemberType) { case MemberTypes.Property: @@ -57,7 +57,7 @@ public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, public async Task<TimeSpan?> GetTimespanAsync(string value) { await EnsureInitializedAsync(); - var result = TimeSpanUtility.ParseTimeSpan(value, applicationOptions?.TimeSpanFormat); + var result = TimeSpanUtility.ParseTimeSpan(value, _applicationOptions?.TimeSpanFormat); return result; } @@ -69,7 +69,7 @@ public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, { try { - formatted = timeSpan.Value.ToString(applicationOptions?.DisplayTimeSpanFormat); + formatted = timeSpan.Value.ToString(_applicationOptions?.DisplayTimeSpanFormat); } catch (FormatException) { @@ -81,7 +81,7 @@ public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, protected virtual void Dispose(bool disposing) { - if (!disposedValue) + if (!_disposedValue) { if (disposing) { @@ -89,11 +89,11 @@ protected virtual void Dispose(bool disposing) _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; } - disposedValue = true; + _disposedValue = true; } } - async Task InitAsync() => applicationOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); + async Task InitAsync() => _applicationOptions ??= await _localStorageOptionsProvider.GetOptionsAsync<ApplicationOptions>(); async Task EnsureInitializedAsync() { @@ -107,7 +107,7 @@ void LocalStorageOptionsProvider_OptionSaved(object? sender, IOptions options) { if (options is ApplicationOptions applicationOption) { - applicationOptions = applicationOption; + _applicationOptions = applicationOption; } } } diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index 1d21e8be..b910506b 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -26,12 +26,8 @@ public class SessionStateContainer : ISessionStateContainer, IDisposable { readonly ILocalStorageOptionsProvider _localStorageOptionsProvider; readonly IJSRuntime _jsRuntime; - - Cuesheet _cuesheet = new(); - Cuesheet? _importCuesheet; - Cuesheet? _activeCuesheet; ViewOptions? _viewOptions; - bool disposedValue; + bool _disposedValue; public event EventHandler? CuesheetChanged; public event EventHandler? ActiveCuesheetChanged; @@ -51,20 +47,20 @@ public void Dispose() public Cuesheet Cuesheet { - get => _cuesheet; + get; set { - _cuesheet = value; + field = value; SetActiveCuesheet(); CuesheetChanged?.Invoke(this, EventArgs.Empty); } - } + } = new(); public Cuesheet? ImportCuesheet { - get => _importCuesheet; + get; set { - _importCuesheet = value; + field = value; SetActiveCuesheet(); } } @@ -112,17 +108,17 @@ public async Task ResetAudioImportAsync(bool revokeObjectURLs) } /// <inheritdoc/> - public Cuesheet? ActiveCuesheet => _activeCuesheet; + public Cuesheet? ActiveCuesheet { get; private set; } protected virtual void Dispose(bool disposing) { - if (!disposedValue) + if (!_disposedValue) { if (disposing) { _localStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; } - disposedValue = true; + _disposedValue = true; } } @@ -143,17 +139,17 @@ void SetActiveCuesheet() } if (_viewOptions.ActiveTab == ViewMode.ImportView) { - if (_activeCuesheet != ImportCuesheet) + if (ActiveCuesheet != ImportCuesheet) { - _activeCuesheet = ImportCuesheet; + ActiveCuesheet = ImportCuesheet; ActiveCuesheetChanged?.Invoke(this, EventArgs.Empty); } } else { - if (_activeCuesheet != Cuesheet) + if (ActiveCuesheet != Cuesheet) { - _activeCuesheet = Cuesheet; + ActiveCuesheet = Cuesheet; ActiveCuesheetChanged?.Invoke(this, EventArgs.Empty); } } diff --git a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs b/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs index 3991f2e4..458eb27a 100644 --- a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs +++ b/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs @@ -21,7 +21,7 @@ namespace AudioCuesheetEditor.Shared; public abstract class BaseLocalizedComponent : ComponentBase, IDisposable { - bool disposedValue; + bool _disposedValue; [Inject] protected LocalizationService LocalizationService { get; set; } = default!; @@ -46,7 +46,7 @@ protected override void OnInitialized() protected virtual void Dispose(bool disposing) { - if (!disposedValue) + if (!_disposedValue) { if (disposing) { @@ -55,7 +55,7 @@ protected virtual void Dispose(bool disposing) TraceChangeManager.RedoDone -= TraceChangeManager_RedoDone; } - disposedValue = true; + _disposedValue = true; } } From 59d7c6f76ba09e02ac09d9bb7877546a130ba65a Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 16 Oct 2026 16:17:55 +0200 Subject: [PATCH 06/20] fix CA1304 and CA1309 --- .editorconfig | 2 -- .../Services/IO/ImportManagerTests.cs | 4 ++-- AudioCuesheetEditor/Extensions/FlagJsonConverter.cs | 2 +- AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs | 9 ++++----- AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs | 2 +- AudioCuesheetEditor/Services/IO/CuesheetExportService.cs | 3 ++- AudioCuesheetEditor/Services/IO/FileInputManager.cs | 4 ++-- AudioCuesheetEditor/Services/IO/TextImportService.cs | 3 ++- 8 files changed, 14 insertions(+), 15 deletions(-) diff --git a/.editorconfig b/.editorconfig index ee79b17d..e3fd2f79 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,9 +18,7 @@ tab_width = 4 #TODO: Enable all of these dotnet_diagnostic.CA1000.severity = suggestion dotnet_diagnostic.CA1051.severity = suggestion -dotnet_diagnostic.CA1304.severity = suggestion dotnet_diagnostic.CA1305.severity = suggestion -dotnet_diagnostic.CA1309.severity = suggestion dotnet_diagnostic.CA1310.severity = suggestion dotnet_diagnostic.CA1311.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index 44b0268c..be2a03ac 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -199,7 +199,7 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() Assert.AreEqual(importAudiofile.Name, sessionStateContainerImportCuesheet.Audiofiles.First().Name); Assert.AreEqual(importCuesheet.Cataloguenumber, sessionStateContainerImportCuesheet.Cataloguenumber); Assert.IsNotNull(sessionStateContainerImportCuesheet.CDTextfile); - Assert.AreEqual(importCuesheet.CDTextfile, sessionStateContainerImportCuesheet.CDTextfile.Name); + Assert.AreEqual($"{importCuesheet.CDTextfile}{FileExtensions.CDTextfile}", sessionStateContainerImportCuesheet.CDTextfile.Name); Assert.AreEqual(importAudiofile.Tracks.First().Artist, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Artist); Assert.AreEqual(importAudiofile.Tracks.First().Title, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); Assert.AreEqual(importAudiofile.Tracks.First().Begin, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); @@ -469,4 +469,4 @@ public void ImportData_ValidData_SetsImportfile() Assert.AreEqual(importData, sessionStateContainerImportfile.FileContentRecognized); Assert.AreEqual(ImportFileType.Textfile, sessionStateContainerImportfile.FileType); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs b/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs index 447c3bc5..c4c62122 100644 --- a/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs +++ b/AudioCuesheetEditor/Extensions/FlagJsonConverter.cs @@ -26,7 +26,7 @@ public class FlagJsonConverter : JsonConverter<Flag> var json = reader.GetString(); if (string.IsNullOrEmpty(json) == false) { - return Flag.AvailableFlags.Single(x => x.CuesheetLabel.Equals(json)); + return Flag.AvailableFlags.Single(x => x.CuesheetLabel.Equals(json, StringComparison.Ordinal)); } else { diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs index abf3eba7..95d6f736 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs @@ -19,18 +19,17 @@ namespace AudioCuesheetEditor.Model.AudioCuesheet; public class CDTextfile { - string name; public CDTextfile(string name) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } - this.name = name; + Name = name; } public string Name { - get => name; + get; set { if (string.IsNullOrEmpty(value)) @@ -38,11 +37,11 @@ public string Name throw new ArgumentNullException(nameof(value)); } var extension = Path.GetExtension(value); - if (extension.Equals(FileExtensions.CDTextfile, StringComparison.CurrentCultureIgnoreCase) == false) + if (extension.Equals(FileExtensions.CDTextfile, StringComparison.OrdinalIgnoreCase) == false) { value = $"{value}{FileExtensions.CDTextfile}"; } - name = value; + field = value; } } } diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index 14166864..9a815557 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -49,7 +49,7 @@ public string? Name set { var extension = Path.GetExtension(value); - if (extension?.Equals(AudioCodec?.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false) + if (extension?.Equals(AudioCodec?.FileExtension, StringComparison.OrdinalIgnoreCase) == false) { value = $"{value}{AudioCodec?.FileExtension}"; } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index 926b07d5..16bf61a1 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -19,6 +19,7 @@ using AudioCuesheetEditor.Model.IO.Export; using AudioCuesheetEditor.Services.UI; using Microsoft.Extensions.Localization; +using System.Globalization; using System.Text; namespace AudioCuesheetEditor.Services.IO; @@ -72,7 +73,7 @@ string WriteCuesheet() _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) { - _ = builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".", string.Empty).ToUpper())); + _ = builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".", string.Empty).ToUpper(CultureInfo.InvariantCulture))); foreach(var track in audiofile.Tracks) { _ = builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position, CuesheetConstants.CuesheetTrackAudio)); diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 4363505b..4047c4ff 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -68,14 +68,14 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m } else { - fileMimeTypeMatches = fileContentType.Equals(mimeType, StringComparison.CurrentCultureIgnoreCase); + fileMimeTypeMatches = fileContentType.Equals(mimeType, StringComparison.OrdinalIgnoreCase); } } if ((fileMimeTypeMatches == false) && fileExtensions.Any()) { //Try to find by file extension var extension = Path.GetExtension(fileName); - fileMimeTypeMatches = fileExtensions.Any(x => x.Equals(extension, StringComparison.CurrentCultureIgnoreCase)); + fileMimeTypeMatches = fileExtensions.Any(x => x.Equals(extension, StringComparison.OrdinalIgnoreCase)); } } return fileMimeTypeMatches; diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index b6381174..7da3696d 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -64,6 +64,7 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, return regex.Replace(input, match => { var result = match.Value; + //TODO: Consider using a more efficient data structure to store group information var groupInfos = new List<(int RelIndex, int Length, string Value, string Key)>(); for (var matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++) { @@ -247,7 +248,7 @@ static string SearchLineByLineForEntry(string fileContent, Func<object> entityCr { var entity = entityCreation.Invoke(); var markedLine = ApplyRegexAndMarkGroups(entity, regex, line, importProfile.TimeSpanFormat); - if (!string.Equals(markedLine, line)) + if (!string.Equals(markedLine, line, StringComparison.Ordinal)) { stopSearch = ifEntityFound.Invoke(pos, entity); } From c37158b69bdf8914bf8494787acb80a03ab3dedf Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 19 Oct 2026 16:50:55 +0200 Subject: [PATCH 07/20] fix CA1805 --- .editorconfig | 3 --- AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs | 2 +- AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs | 2 +- AudioCuesheetEditor/Services/Audio/PlaybackService.cs | 4 ++-- AudioCuesheetEditor/Services/IO/FileInputManager.cs | 6 +++--- AudioCuesheetEditor/Services/UI/SessionStateContainer.cs | 4 ++-- 6 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.editorconfig b/.editorconfig index e3fd2f79..6af6c75c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,11 +19,8 @@ tab_width = 4 dotnet_diagnostic.CA1000.severity = suggestion dotnet_diagnostic.CA1051.severity = suggestion dotnet_diagnostic.CA1305.severity = suggestion -dotnet_diagnostic.CA1310.severity = suggestion -dotnet_diagnostic.CA1311.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion dotnet_diagnostic.CA1727.severity = suggestion -dotnet_diagnostic.CA1805.severity = suggestion dotnet_diagnostic.CA1848.severity = suggestion dotnet_diagnostic.CA1852.severity = suggestion dotnet_diagnostic.CA1863.severity = suggestion diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs index 95d6f736..7698844e 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CDTextfile.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index 9a815557..1c465b10 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -71,7 +71,7 @@ public AudioCodec? AudioCodec set { field = value; - if ((field != null) && (Name?.EndsWith(field.FileExtension) == false)) + if ((field != null) && (Name?.EndsWith(field.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false)) { //Replace file ending Name = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), field.FileExtension); diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index c524af5d..8e930df2 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ public TimeSpan? TotalTime return null; } } - public bool IsPaused { get; private set; } = false; + public bool IsPaused { get; private set; } public bool IsPlaybackPossible => _sessionStateContainer.Cuesheet.Audiofiles.Any(x => string.IsNullOrEmpty(x.ObjectURL) == false); public bool IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; public bool IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 4047c4ff..2889dc07 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -61,10 +61,10 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m { if (string.IsNullOrEmpty(fileContentType) == false) { - if (mimeType.EndsWith("/*")) + if (mimeType.EndsWith("/*", StringComparison.OrdinalIgnoreCase)) { var mainType = mimeType[..^1]; - fileMimeTypeMatches = fileContentType.StartsWith(mainType, StringComparison.CurrentCultureIgnoreCase); + fileMimeTypeMatches = fileContentType.StartsWith(mainType, StringComparison.OrdinalIgnoreCase); } else { diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index b910506b..6baaf214 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ public Cuesheet? ImportCuesheet public IList<Audiofile> ImportAudiofiles { get; set; } = []; public Dictionary<Audiofile, Audiofile?> ImportAudiofileMapping { get; set; } = []; public IImportfile? Importfile { get; set; } - public bool ImportIsAnalyzed { get; set; } = false; + public bool ImportIsAnalyzed { get; set; } /// <inheritdoc/> public async Task InitializeAsync() From a1b0715d126d28a446f7231bca37c83099faab1f Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 19 Oct 2026 16:55:01 +0200 Subject: [PATCH 08/20] fix CA1852 --- .editorconfig | 1 - AudioCuesheetEditor.Tests/Utility/TestHelper.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6af6c75c..ca01c873 100644 --- a/.editorconfig +++ b/.editorconfig @@ -22,7 +22,6 @@ dotnet_diagnostic.CA1305.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion dotnet_diagnostic.CA1727.severity = suggestion dotnet_diagnostic.CA1848.severity = suggestion -dotnet_diagnostic.CA1852.severity = suggestion dotnet_diagnostic.CA1863.severity = suggestion dotnet_diagnostic.CA2201.severity = suggestion diff --git a/AudioCuesheetEditor.Tests/Utility/TestHelper.cs b/AudioCuesheetEditor.Tests/Utility/TestHelper.cs index f4efd3f2..2abc8390 100644 --- a/AudioCuesheetEditor.Tests/Utility/TestHelper.cs +++ b/AudioCuesheetEditor.Tests/Utility/TestHelper.cs @@ -16,11 +16,10 @@ using AudioCuesheetEditor.Model.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using System; namespace AudioCuesheetEditor.Tests.Utility; -class TestHelper +sealed class TestHelper { public ApplicationOptions ApplicationOptions { get; private set; } = new(); public static ILogger<T> CreateLogger<T>() From 4bd46122ff5781c3887266698da0468c3ebe3544 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:00:32 +0200 Subject: [PATCH 09/20] fix CA1848 --- .editorconfig | 1 - .../Services/IO/FileInputManager.cs | 10 ++-- .../Services/IO/ImportManager.cs | 33 +++++------ .../Provider/MusicBrainzDataProvider.cs | 11 ++-- .../Services/UI/TraceChangeManager.cs | 56 +++++++++---------- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/.editorconfig b/.editorconfig index ca01c873..64d75027 100644 --- a/.editorconfig +++ b/.editorconfig @@ -21,7 +21,6 @@ dotnet_diagnostic.CA1051.severity = suggestion dotnet_diagnostic.CA1305.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion dotnet_diagnostic.CA1727.severity = suggestion -dotnet_diagnostic.CA1848.severity = suggestion dotnet_diagnostic.CA1863.severity = suggestion dotnet_diagnostic.CA2201.severity = suggestion diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 2889dc07..89d48ae6 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -21,7 +21,7 @@ namespace AudioCuesheetEditor.Services.IO; -public class FileInputManager(IJSRuntime jsRuntime, ILogger<FileInputManager> logger) : IFileInputManager +public partial class FileInputManager(IJSRuntime jsRuntime, ILogger<FileInputManager> logger) : IFileInputManager { readonly IJSRuntime _jsRuntime = jsRuntime; readonly ILogger<FileInputManager> _logger = logger; @@ -52,10 +52,7 @@ public class FileInputManager(IJSRuntime jsRuntime, ILogger<FileInputManager> lo public bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable<string> fileExtensions) { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtensions: '{fileExtensions}'", fileName, fileContentType, mimeType, fileExtensions); - } + LogCheckFileMimeTypeCalled(fileContentType, fileName, mimeType, fileExtensions); var fileMimeTypeMatches = false; if (string.IsNullOrEmpty(mimeType) == false) { @@ -153,4 +150,7 @@ public async Task<IEnumerable<FileUpload>> CreateFileUploadsAsync(IReadOnlyList< } return fileUploads; } + + [LoggerMessage(Level = LogLevel.Debug, Message = "CheckFileMimeType called with file: file.Name: '{FileName}', file.ContentType: '{ContentType}', mimeType: '{MimeType}', fileExtensions: '{fileExtensions}'")] + partial void LogCheckFileMimeTypeCalled(string? contentType, string fileName, string mimeType, IEnumerable<string> fileExtensions); } diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 8ba880d7..f67fb28a 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ public enum ImportFileType Textfile, Audiofile } -public class ImportManager(ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager, ITextImportService textImportService, ITrackManager trackManager, IAudioImportService audioImportService, ILogger<ImportManager> logger) +public partial class ImportManager(ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager, ITextImportService textImportService, ITrackManager trackManager, IAudioImportService audioImportService, ILogger<ImportManager> logger) { public event EventHandler<IEnumerable<string>>? UploadFilesFinished; @@ -55,10 +55,7 @@ public void ImportData(string? data) FileType = ImportFileType.Textfile }; stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("ImportData duration: {stopwatch.Elapsed}", stopwatch.Elapsed); - } + LogImportDataFinished(stopwatch.Elapsed); } public async Task<bool> AnalyseImportfile() @@ -98,10 +95,7 @@ public async Task<bool> AnalyseImportfile() } var cancelImport = await _audioImportService.MapAudioImportAsync(); stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("AnalyseImportfile duration: {stopwatch.Elapsed}", stopwatch.Elapsed); - } + LogAnalyseImportfileFinished(stopwatch.Elapsed); return cancelImport; } @@ -119,10 +113,7 @@ public async Task ImportCuesheetAsync() } await _sessionStateContainer.ResetImportAsync(false); stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("ImportCuesheet duration: {stopwatch.Elapsed}", stopwatch.Elapsed); - } + LogImportCuesheetFinished(stopwatch.Elapsed); } public async Task UploadFilesAsync(IEnumerable<FileUpload> files) @@ -179,10 +170,7 @@ public async Task UploadFilesAsync(IEnumerable<FileUpload> files) } UploadFilesFinished?.Invoke(this, invalidFiles); stopwatch.Stop(); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("UploadFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed); - } + LogImportCuesheetFinished(stopwatch.Elapsed); } void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) @@ -316,4 +304,13 @@ void ResetTracing() _traceChangeManager.RemoveTracedChanges([_sessionStateContainer.ImportCuesheet, .. _sessionStateContainer.ImportCuesheet.Audiofiles, .. _sessionStateContainer.ImportCuesheet.Audiofiles.SelectMany(x => x.Tracks)]); } } + + [LoggerMessage(Level = LogLevel.Debug, Message = "ImportData duration: {Duration}")] + partial void LogImportDataFinished(TimeSpan duration); + + [LoggerMessage(Level = LogLevel.Debug, Message = "AnalyseImportfile duration: {Duration}")] + partial void LogAnalyseImportfileFinished(TimeSpan duration); + + [LoggerMessage(Level = LogLevel.Debug, Message = "ImportCuesheet duration: {Duration}")] + partial void LogImportCuesheetFinished(TimeSpan duration); } diff --git a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs index a0b45ef0..261b8a40 100644 --- a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs +++ b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ public class MusicBrainzTrack public TimeSpan? Length { get; init; } public string? Disambiguation { get; init; } } -public class MusicBrainzDataProvider(ILogger<MusicBrainzDataProvider> logger) +public partial class MusicBrainzDataProvider(ILogger<MusicBrainzDataProvider> logger) { readonly ILogger<MusicBrainzDataProvider> _logger = logger; @@ -55,7 +55,7 @@ public async Task<IReadOnlyCollection<MusicBrainzArtist>> SearchArtistAsync(stri } catch (HttpRequestException hre) { - _logger.LogError(hre, "Error getting response from MusicBrainz"); + LogErrorGettingResponseFromMusicBrainz(hre); } return artistSearchResult.AsReadOnly(); } @@ -104,7 +104,7 @@ public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(string } catch (HttpRequestException hre) { - _logger.LogError(hre, "Error getting response from MusicBrainz"); + LogErrorGettingResponseFromMusicBrainz(hre); } return titleSearchResult.AsReadOnly(); } @@ -124,4 +124,7 @@ public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(string return field; } } + + [LoggerMessage(Level = LogLevel.Error, Message = "Error getting response from MusicBrainz")] + partial void LogErrorGettingResponseFromMusicBrainz(HttpRequestException hre); } diff --git a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs index a1747bcb..933b0572 100644 --- a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs +++ b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ namespace AudioCuesheetEditor.Services.UI; /// <inheritdoc /> -public class TraceChangeManager(ILogger<TraceChangeManager> logger) : ITraceChangeManager +public partial class TraceChangeManager(ILogger<TraceChangeManager> logger) : ITraceChangeManager { readonly ILogger<TraceChangeManager> _logger = logger; @@ -45,7 +45,7 @@ public void Reset() public void Undo() { - _logger.LogDebug("Undo called"); + LogUndoCalled(); if (CanUndo) { TracedChanges? changes = null; @@ -66,10 +66,7 @@ public void Undo() var change = changes.Changes.ElementAt(i); var tracedObject = change?.TraceableObject; var traceAbleChange = change?.TraceableChange; - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}", tracedObject, traceAbleChange); - } + LogTracedObjectAndTracableChange(tracedObject, traceAbleChange); if (tracedObject != null && traceAbleChange != null) { var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); @@ -77,10 +74,7 @@ public void Undo() { var currentValue = propertyInfo.GetValue(tracedObject); redoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}", traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); - } + LogSettingProperty(traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); } else @@ -102,7 +96,7 @@ public void Undo() public void Redo() { - _logger.LogDebug("Redo called"); + LogRedoCalled(); if (CanRedo) { TracedChanges? changes = null; @@ -123,10 +117,7 @@ public void Redo() var change = changes.Changes.ElementAt(i); var tracedObject = change?.TraceableObject; var traceAbleChange = change?.TraceableChange; - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}", tracedObject, traceAbleChange); - } + LogTracedObjectAndTracableChange(tracedObject, traceAbleChange); if (tracedObject != null && traceAbleChange != null) { var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); @@ -134,10 +125,7 @@ public void Redo() { var currentValue = propertyInfo.GetValue(tracedObject); undoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}", traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); - } + LogSettingProperty(traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); } else @@ -162,10 +150,7 @@ public bool BulkEdit get => _bulkEditTracedChanges != null; set { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Set BulkEdit called with {value}", value); - } + LogSetBulkEdit(value); if (value) { _bulkEditTracedChanges ??= []; @@ -185,10 +170,7 @@ public bool BulkEdit public void AddChange(TracedChange tracedChange) { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("AddChange: {tracedChange.TraceableObject}, {tracedChange.TraceableChange.PropertyName}, {tracedChange.TraceableChange.PreviousValue}", tracedChange.TraceableObject, tracedChange.TraceableChange.PropertyName, tracedChange.TraceableChange.PreviousValue); - } + LogAddChange(tracedChange.TraceableObject, tracedChange.TraceableChange.PropertyName, tracedChange.TraceableChange.PreviousValue); if (BulkEdit == false) { //Single change @@ -211,4 +193,22 @@ public void RemoveTracedChanges(IEnumerable<object> traceables) _ = _redoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject))); TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty); } + + [LoggerMessage(Level = LogLevel.Debug, Message = "Undo called")] + partial void LogUndoCalled(); + + [LoggerMessage(Level = LogLevel.Debug, Message = "Redo called")] + partial void LogRedoCalled(); + + [LoggerMessage(Level = LogLevel.Debug, Message = "tracedObject = {tracedObject}, traceAbleChange = {traceAbleChange}")] + partial void LogTracedObjectAndTracableChange(object? tracedObject, object? traceAbleChange); + + [LoggerMessage(Level = LogLevel.Debug, Message = "Setting {PropertyName} on {tracedObject} from {currentValue} to {PreviousValue}")] + partial void LogSettingProperty(string propertyName, object? tracedObject, object? currentValue, object? previousValue); + + [LoggerMessage(Level = LogLevel.Debug, Message = "Set BulkEdit called with {value}")] + partial void LogSetBulkEdit(bool value); + + [LoggerMessage(Level = LogLevel.Debug, Message = "AddChange: {TraceableObject}, {PropertyName}, {PreviousValue}")] + partial void LogAddChange(object? traceableObject, string? propertyName, object? previousValue); } From ab7263e743c75e1707244e79f15fde9a7cc3ead5 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:04:28 +0200 Subject: [PATCH 10/20] fix CA1863 --- .editorconfig | 1 - .../Services/IO/CuesheetImportServiceTests.cs | 24 +++++----- .../Services/IO/TextImportServiceTests.cs | 48 +++++++++---------- .../Model/AudioCuesheet/CuesheetConstants.cs | 7 +-- .../Services/IO/CuesheetImportService.cs | 26 +++++----- .../Services/IO/TextImportService.cs | 6 +-- 6 files changed, 56 insertions(+), 56 deletions(-) diff --git a/.editorconfig b/.editorconfig index 64d75027..6d476d7c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -21,7 +21,6 @@ dotnet_diagnostic.CA1051.severity = suggestion dotnet_diagnostic.CA1305.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion dotnet_diagnostic.CA1727.severity = suggestion -dotnet_diagnostic.CA1863.severity = suggestion dotnet_diagnostic.CA2201.severity = suggestion # Organize usings diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs index 6654cd35..ae24247c 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs @@ -76,15 +76,15 @@ TRACK 08 AUDIO Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample CD Artist\""), lines.ElementAt(0)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample CD Title\""), lines.ElementAt(1)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "FILE \"AC DC - TNT.mp3\" MP3"), lines.ElementAt(2)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CDTEXTFILE \"Testfile.cdt\""), lines.ElementAt(3)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "CATALOG 0123456789012"), lines.ElementAt(4)); - Assert.AreEqual(string.Format(CuesheetConstants.RecognizedMarkHTML, "TRACK 01 AUDIO"), lines.ElementAt(5)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PERFORMER \"Sample Artist 1\"")), lines.ElementAt(6)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "TITLE \"Sample Title 1\"")), lines.ElementAt(7)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "INDEX 01 00:00:00")), lines.ElementAt(8)); + Assert.AreEqual(CuesheetConstants.GetMarkedText("PERFORMER \"Sample CD Artist\""), lines.ElementAt(0)); + Assert.AreEqual(CuesheetConstants.GetMarkedText("TITLE \"Sample CD Title\""), lines.ElementAt(1)); + Assert.AreEqual(CuesheetConstants.GetMarkedText("FILE \"AC DC - TNT.mp3\" MP3"), lines.ElementAt(2)); + Assert.AreEqual(CuesheetConstants.GetMarkedText("CDTEXTFILE \"Testfile.cdt\""), lines.ElementAt(3)); + Assert.AreEqual(CuesheetConstants.GetMarkedText("CATALOG 0123456789012"), lines.ElementAt(4)); + Assert.AreEqual(CuesheetConstants.GetMarkedText("TRACK 01 AUDIO"), lines.ElementAt(5)); + Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("PERFORMER \"Sample Artist 1\"")), lines.ElementAt(6)); + Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("TITLE \"Sample Title 1\"")), lines.ElementAt(7)); + Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("INDEX 01 00:00:00")), lines.ElementAt(8)); } [TestMethod()] @@ -182,8 +182,8 @@ TRACK 08 AUDIO Assert.IsNotNull(importFile.AnalyzedCuesheet); Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "FLAGS 4CH DCP PRE SCMS")), lines.ElementAt(8)); - Assert.AreEqual(string.Format(" {0}", string.Format(CuesheetConstants.RecognizedMarkHTML, "PREGAP 00:04:00")), lines.ElementAt(36)); + Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("FLAGS 4CH DCP PRE SCMS")), lines.ElementAt(8)); + Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("PREGAP 00:04:00")), lines.ElementAt(36)); Assert.HasCount(2, importFile.AnalyzedCuesheet.Audiofiles); Assert.AreEqual("Sample Audiofile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); Assert.AreEqual("Sample Input.wav", importFile.AnalyzedCuesheet.Audiofiles.Last().Name); @@ -196,4 +196,4 @@ TRACK 08 AUDIO Assert.AreEqual(new TimeSpan(0, 0, 2), importFile.AnalyzedCuesheet.Audiofiles.Last().Tracks.ElementAt(0).PostGap); Assert.AreEqual(new TimeSpan(0, 0, 4), importFile.AnalyzedCuesheet.Audiofiles.Last().Tracks.ElementAt(2).PreGap); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs index 796a3eb5..1c2de679 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs @@ -116,8 +116,8 @@ public async Task AnalyseAsync_InvalidAudiofileSchemeWithMatchingTrackScheme_Doe Assert.IsEmpty(importFile.AnalyzedCuesheet.Audiofiles); var lines = importFile.FileContentRecognized!.Split(Environment.NewLine); Assert.AreEqual(string.Format("{0} - {1}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3")), lines.First()); + CuesheetConstants.GetMarkedText("CuesheetArtist"), + CuesheetConstants.GetMarkedText("CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3")), lines.First()); Assert.AreEqual("Sample Artist 8 - Sample Title 8\t\t\t\t01:15:54", lines.Last()); } @@ -516,8 +516,8 @@ public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOn Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); Assert.AreEqual(string.Format("{0} - {1}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle")), lines.First()); + CuesheetConstants.GetMarkedText("CuesheetArtist"), + CuesheetConstants.GetMarkedText("CuesheetTitle")), lines.First()); Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); Assert.HasCount(0, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); @@ -572,9 +572,9 @@ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentReco Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); Assert.AreEqual(string.Format("{0} - {1} {2}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Title 8"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "01:15:54")), lines.Last()); + CuesheetConstants.GetMarkedText("Sample Artist 8"), + CuesheetConstants.GetMarkedText("Sample Title 8"), + CuesheetConstants.GetMarkedText("01:15:54")), lines.Last()); } [TestMethod()] @@ -601,9 +601,9 @@ public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedA Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); Assert.AreEqual(string.Format("{0} - {1}\t\t\t\t\t\t\t\t{2}", - string.Format(CuesheetConstants.RecognizedMarkHTML, "Age Of Love"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)"), - string.Format(CuesheetConstants.RecognizedMarkHTML, "04:29:28")), lines.ElementAt(53)); + CuesheetConstants.GetMarkedText("Age Of Love"), + CuesheetConstants.GetMarkedText("The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)"), + CuesheetConstants.GetMarkedText("04:29:28")), lines.ElementAt(53)); } [TestMethod()] @@ -640,8 +640,8 @@ public async Task AnalyseAsync_WithRegularExpression_ReturnsCuesheetAsync() Assert.AreEqual("Andale (MONTA (TN) Remix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); Assert.AreEqual(new DateTime(2025, 1, 29, 22, 30, 3), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().StartDateTime); Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Sasha Fashion"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "2025/1/29 21:48:55"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("Sasha Fashion"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("2025/1/29 21:48:55"), importFile.FileContentRecognized); } [TestMethod()] @@ -678,13 +678,13 @@ public async Task AnalyseAsync_WithoutRegularExpression_ReturnsCuesheetAsync() Assert.AreEqual("Chasing the Sun (Original Mix)", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Title); Assert.IsNull(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.Last().Begin); Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "DJFreezeT"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Rabbit Hole Mix"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "0123456789123"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Nikolay Kirov"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Chasing the Sun (Original Mix)"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "SHDW & Obscure Shape"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Wächter der Nacht (Original Mix)"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("DJFreezeT"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("Rabbit Hole Mix"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("0123456789123"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("Nikolay Kirov"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("Chasing the Sun (Original Mix)"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("SHDW & Obscure Shape"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("Wächter der Nacht (Original Mix)"), importFile.FileContentRecognized); } [TestMethod()] @@ -782,9 +782,9 @@ public async Task AnalyseAsync_WithCommonDataMatchingMultipleLines_SetsCommonDat Assert.AreEqual("c:\\AudioFile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.IsNotNull(importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetArtist"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "CuesheetTitle"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "c:\\AudioFile.mp3"), importFile.FileContentRecognized); - Assert.Contains(string.Format(CuesheetConstants.RecognizedMarkHTML, "Sample Artist 8"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("CuesheetArtist"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("CuesheetTitle"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("c:\\AudioFile.mp3"), importFile.FileContentRecognized); + Assert.Contains(CuesheetConstants.GetMarkedText("Sample Artist 8"), importFile.FileContentRecognized); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs index 00f106dc..198fe799 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/CuesheetConstants.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -31,6 +31,7 @@ public class CuesheetConstants public static readonly string Tab = "\t"; public static readonly string CuesheetCDTextfile = "CDTEXTFILE"; public static readonly string CuesheetCatalogueNumber = "CATALOG"; - public static readonly string MarkHTMLStart = "<Mark>"; - public static readonly string RecognizedMarkHTML = MarkHTMLStart + "{0}" + "</Mark>"; + public static readonly string MarkStart = "<Mark>"; + + public static string GetMarkedText(string text) => $"{MarkStart}{text}</Mark>"; } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs index bb747361..d6d4baf4 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ public static IImportfile Analyse(string fileContent) if ((regexCuesheetArtist.IsMatch(line) == true) && (track == null)) { var match = regexCuesheetArtist.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetArtistGroupName); if (matchGroup != null) { @@ -82,7 +82,7 @@ public static IImportfile Analyse(string fileContent) if ((regexCuesheetTitle.IsMatch(line) == true) && (track == null)) { var match = regexCuesheetTitle.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetTitleGroupName); if (matchGroup != null) { @@ -97,7 +97,7 @@ public static IImportfile Analyse(string fileContent) if (regexCuesheetFile.IsMatch(line) == true) { var match = regexCuesheetFile.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetFileNameGroupName); if (matchGroup != null) { @@ -112,7 +112,7 @@ public static IImportfile Analyse(string fileContent) if (regexCDTextfile.IsMatch(line) == true) { var match = regexCDTextfile.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetCDTextfileGroupName); if (matchGroup != null) { @@ -127,7 +127,7 @@ public static IImportfile Analyse(string fileContent) if (regexCatalogueNumber.IsMatch(line) == true) { var match = regexCatalogueNumber.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(cuesheetCatalogueNumberGroupName); if (matchGroup != null) { @@ -142,12 +142,12 @@ public static IImportfile Analyse(string fileContent) if (regexTrackBegin.IsMatch(line) == true) { track = new ImportTrack(); - recognizedLine = string.Format(CuesheetConstants.RecognizedMarkHTML, line); + recognizedLine = CuesheetConstants.GetMarkedText(line); } if ((regexTrackArtist.IsMatch(line) == true) && (track != null)) { var match = regexTrackArtist.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackArtistGroupName); if (matchGroup != null) { @@ -162,7 +162,7 @@ public static IImportfile Analyse(string fileContent) if ((regexTrackTitle.IsMatch(line) == true) && (track != null)) { var match = regexTrackTitle.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackTitleGroupName); if (matchGroup != null) { @@ -177,7 +177,7 @@ public static IImportfile Analyse(string fileContent) if (regexTrackFlags.IsMatch(line) == true) { var match = regexTrackFlags.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackFlagsGroupName); if (matchGroup != null) { @@ -200,7 +200,7 @@ public static IImportfile Analyse(string fileContent) if (regexTrackPreGap.IsMatch(line) == true) { var match = regexTrackPreGap.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackPreGapGroupName); if (matchGroup != null) { @@ -224,7 +224,7 @@ public static IImportfile Analyse(string fileContent) if (regexTrackIndex.IsMatch(line) == true) { var match = regexTrackIndex.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackIndex01GroupName); if (matchGroup != null) { @@ -249,7 +249,7 @@ public static IImportfile Analyse(string fileContent) if (regexTrackPostGap.IsMatch(line) == true) { var match = regexTrackPostGap.Match(line); - recognizedLine = line.Replace(match.Value, string.Format(CuesheetConstants.RecognizedMarkHTML, match.Value)); + recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); var matchGroup = match.Groups.GetValueOrDefault(trackPostGapGroupName); if (matchGroup != null) { diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index 7da3696d..bdd6c5f2 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -90,7 +90,7 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, foreach (var (RelIndex, Length, Value, Key) in groupInfos) { _ = sb.Remove(RelIndex, Length); - _ = sb.Insert(RelIndex, string.Format(CuesheetConstants.RecognizedMarkHTML, Value)); + _ = sb.Insert(RelIndex, CuesheetConstants.GetMarkedText(Value)); } return sb.ToString(); }); @@ -244,7 +244,7 @@ static string SearchLineByLineForEntry(string fileContent, Func<object> entityCr { var stopSearch = false; // Check if this line is already analyzed - if (line.Contains(CuesheetConstants.MarkHTMLStart) == false) + if (line.Contains(CuesheetConstants.MarkStart) == false) { var entity = entityCreation.Invoke(); var markedLine = ApplyRegexAndMarkGroups(entity, regex, line, importProfile.TimeSpanFormat); From 6a79f5ee2416cf7c211ad94097a98bd9d44683de Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:33:31 +0200 Subject: [PATCH 11/20] Update TextImportService.cs --- .../Services/IO/TextImportService.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index bdd6c5f2..3385e148 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -27,6 +27,8 @@ namespace AudioCuesheetEditor.Services.IO; +readonly record struct CapturedText(string Name, int Index,int Length, string Value); + public class TextImportService(ILocalStorageOptionsProvider localStorageOptionsProvider) : ITextImportService { readonly ILocalStorageOptionsProvider _localStorageOptionsProvider = localStorageOptionsProvider; @@ -64,33 +66,32 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, return regex.Replace(input, match => { var result = match.Value; - //TODO: Consider using a more efficient data structure to store group information - var groupInfos = new List<(int RelIndex, int Length, string Value, string Key)>(); + var capturedTexts = new List<CapturedText>(); for (var matchCounter = 1; matchCounter < match.Groups.Count; matchCounter++) { var group = match.Groups[matchCounter]; - var key = regex.GroupNameFromNumber(matchCounter); - if (!string.IsNullOrEmpty(key) && key != matchCounter.ToString()) + var groupName = regex.GroupNameFromNumber(matchCounter); + if (!string.IsNullOrEmpty(groupName) && groupName != matchCounter.ToString()) { - var property = entity.GetType().GetProperty(key, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + var property = entity.GetType().GetProperty(groupName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (property != null) { SetValue(entity, property, group.Value, timeSpanFormat); } - var relIndex = group.Index - match.Index; - groupInfos.Add((relIndex, group.Length, group.Value, key)); + var relativeIndex = group.Index - match.Index; + capturedTexts.Add(new CapturedText(groupName, relativeIndex, group.Length, group.Value)); } } - if (groupInfos.Count == 0) + if (capturedTexts.Count == 0) { return result; } - groupInfos.Sort((a, b) => b.RelIndex.CompareTo(a.RelIndex)); + capturedTexts.Sort((a, b) => b.Index.CompareTo(a.Index)); var sb = new StringBuilder(result); - foreach (var (RelIndex, Length, Value, Key) in groupInfos) + foreach (var capturedText in capturedTexts) { - _ = sb.Remove(RelIndex, Length); - _ = sb.Insert(RelIndex, CuesheetConstants.GetMarkedText(Value)); + _ = sb.Remove(capturedText.Index, capturedText.Length); + _ = sb.Insert(capturedText.Index, CuesheetConstants.GetMarkedText(capturedText.Value)); } return sb.ToString(); }); From 92bde65c9cc9f808144f4acfe317de6788e70607 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:59:06 +0200 Subject: [PATCH 12/20] fix CA1305 --- .editorconfig | 1 - .../Model/IO/ProjectfileTests.cs | 6 +-- .../Services/IO/CuesheetExportServiceTests.cs | 9 ++-- .../Services/IO/CuesheetImportServiceTests.cs | 10 ++-- .../Services/IO/TextImportServiceTests.cs | 20 ++------ .../Model/IO/Audio/Audiofile.cs | 2 +- .../Model/IO/Export/Exportprofile.cs | 41 ++++++++-------- .../Model/Utility/TimeSpanFormat.cs | 11 +++-- .../Services/IO/CuesheetExportService.cs | 28 +++++------ .../Services/IO/CuesheetImportService.cs | 49 ++++++++++--------- .../Services/IO/ExportfileGenerator.cs | 11 +++-- .../Services/IO/TextImportService.cs | 9 ++-- .../Options/LocalStorageOptionsProvider.cs | 7 +-- .../Provider/MusicBrainzDataProvider.cs | 2 +- .../UI/ApplicationOptionsTimeSpanParser.cs | 5 +- .../Services/UI/TraceChangeManager.cs | 4 +- .../Services/Validation/ValidationService.cs | 4 +- 17 files changed, 107 insertions(+), 112 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6d476d7c..9a32c6ab 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,7 +18,6 @@ tab_width = 4 #TODO: Enable all of these dotnet_diagnostic.CA1000.severity = suggestion dotnet_diagnostic.CA1051.severity = suggestion -dotnet_diagnostic.CA1305.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion dotnet_diagnostic.CA1727.severity = suggestion dotnet_diagnostic.CA2201.severity = suggestion diff --git a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs index 03a04757..6b262d4e 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs @@ -49,8 +49,8 @@ public void GenerateFile_WithoutSections_GeneratesOneFile() var track = new Track { Position = i, - Artist = string.Format("Artist {0}", i), - Title = string.Format("Title {0}", i), + Artist = $"Artist {i}", + Title = $"Title {i}", Begin = begin }; var rand = new Random(); @@ -107,4 +107,4 @@ public void ImportFile_ValidProjectfile_ShouldImportFile() Assert.AreEqual(new TimeSpan(0, 55, 55), cuesheet.Audiofiles.Last().Tracks.Last().End); Assert.AreEqual((ushort)10, cuesheet.Audiofiles.Last().Tracks.Last().Position); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs index ac3d6f39..3c4796c4 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs @@ -22,6 +22,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System; +using System.Globalization; using System.Linq; namespace AudioCuesheetEditor.Tests.Services.IO; @@ -64,7 +65,7 @@ public void CanGenerateExportfile_InvalidAudiofileName_ReturnsValidationMessage( { Audiofiles = [new()] }); - _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(CultureInfo.CurrentCulture, format, args))); _ = _localizerMock.Setup(x => x[nameof(Audiofile.Name)]).Returns(new LocalizedString(nameof(Audiofile.Name), nameof(Audiofile.Name))); // Act @@ -80,7 +81,7 @@ public void CanGenerateExportfile_InvalidCuesheeetTitle_ReturnsValidationMessage { // Arrange _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, new Cuesheet()); - _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(CultureInfo.CurrentCulture, format, args))); _ = _localizerMock.Setup(x => x[nameof(Cuesheet.Title)]).Returns(new LocalizedString(nameof(Cuesheet.Title), nameof(Cuesheet.Title))); // Act @@ -117,7 +118,7 @@ public void CanGenerateExportfile_InvalidTrackEnd_ReturnsValidationMessage() }; _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); - _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(format, args))); + _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(CultureInfo.CurrentCulture, format, args))); _ = _localizerMock.Setup(x => x[nameof(Track.End)]).Returns(new LocalizedString(nameof(Track.End), nameof(Track.End))); // Act @@ -355,4 +356,4 @@ public void GenerateExportfiles_WithInvalidTracks_ReturnsFailure() // Assert Assert.IsFalse(result.IsSuccess); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs index ae24247c..0e150217 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetImportServiceTests.cs @@ -82,9 +82,9 @@ TRACK 08 AUDIO Assert.AreEqual(CuesheetConstants.GetMarkedText("CDTEXTFILE \"Testfile.cdt\""), lines.ElementAt(3)); Assert.AreEqual(CuesheetConstants.GetMarkedText("CATALOG 0123456789012"), lines.ElementAt(4)); Assert.AreEqual(CuesheetConstants.GetMarkedText("TRACK 01 AUDIO"), lines.ElementAt(5)); - Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("PERFORMER \"Sample Artist 1\"")), lines.ElementAt(6)); - Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("TITLE \"Sample Title 1\"")), lines.ElementAt(7)); - Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("INDEX 01 00:00:00")), lines.ElementAt(8)); + Assert.AreEqual($" {CuesheetConstants.GetMarkedText("PERFORMER \"Sample Artist 1\"")}", lines.ElementAt(6)); + Assert.AreEqual($" {CuesheetConstants.GetMarkedText("TITLE \"Sample Title 1\"")}", lines.ElementAt(7)); + Assert.AreEqual($" {CuesheetConstants.GetMarkedText("INDEX 01 00:00:00")}", lines.ElementAt(8)); } [TestMethod()] @@ -182,8 +182,8 @@ TRACK 08 AUDIO Assert.IsNotNull(importFile.AnalyzedCuesheet); Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("FLAGS 4CH DCP PRE SCMS")), lines.ElementAt(8)); - Assert.AreEqual(string.Format(" {0}", CuesheetConstants.GetMarkedText("PREGAP 00:04:00")), lines.ElementAt(36)); + Assert.AreEqual($" {CuesheetConstants.GetMarkedText("FLAGS 4CH DCP PRE SCMS")}", lines.ElementAt(8)); + Assert.AreEqual($" {CuesheetConstants.GetMarkedText("PREGAP 00:04:00")}", lines.ElementAt(36)); Assert.HasCount(2, importFile.AnalyzedCuesheet.Audiofiles); Assert.AreEqual("Sample Audiofile.mp3", importFile.AnalyzedCuesheet.Audiofiles.First().Name); Assert.AreEqual("Sample Input.wav", importFile.AnalyzedCuesheet.Audiofiles.Last().Name); diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs index 1c2de679..83c5eefc 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs @@ -115,9 +115,7 @@ public async Task AnalyseAsync_InvalidAudiofileSchemeWithMatchingTrackScheme_Doe Assert.AreEqual("CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3", importFile.AnalyzedCuesheet.Title); Assert.IsEmpty(importFile.AnalyzedCuesheet.Audiofiles); var lines = importFile.FileContentRecognized!.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1}", - CuesheetConstants.GetMarkedText("CuesheetArtist"), - CuesheetConstants.GetMarkedText("CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3")), lines.First()); + Assert.AreEqual($"{CuesheetConstants.GetMarkedText("CuesheetArtist")} - {CuesheetConstants.GetMarkedText("CuesheetTitle\t\t\t\tc:\\tmp\\Testfile.mp3")}", lines.First()); Assert.AreEqual("Sample Artist 8 - Sample Title 8\t\t\t\t01:15:54", lines.Last()); } @@ -515,12 +513,10 @@ public async Task AnalyseAsync_SchemeCuesheetOnly_CreatesFileContentRecognizedOn Assert.IsNotNull(importFile.AnalyzedCuesheet); Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1}", - CuesheetConstants.GetMarkedText("CuesheetArtist"), - CuesheetConstants.GetMarkedText("CuesheetTitle")), lines.First()); + Assert.AreEqual($"{CuesheetConstants.GetMarkedText("CuesheetArtist")} - {CuesheetConstants.GetMarkedText("CuesheetTitle")}", lines.First()); Assert.AreEqual("CuesheetArtist", importFile.AnalyzedCuesheet.Artist); Assert.AreEqual("CuesheetTitle", importFile.AnalyzedCuesheet.Title); - Assert.HasCount(0, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); + Assert.IsEmpty(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.AreEqual("- c:\\tmp\\Testfile.mp3", lines.ElementAt(1)); Assert.AreEqual("Sample Artist 1 - Sample Title 1 00:05:00", lines.ElementAt(2)); Assert.AreEqual("Sample Artist 2 - Sample Title 2 00:09:23", lines.ElementAt(3)); @@ -571,10 +567,7 @@ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentReco Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1} {2}", - CuesheetConstants.GetMarkedText("Sample Artist 8"), - CuesheetConstants.GetMarkedText("Sample Title 8"), - CuesheetConstants.GetMarkedText("01:15:54")), lines.Last()); + Assert.AreEqual($"{CuesheetConstants.GetMarkedText("Sample Artist 8")} - {CuesheetConstants.GetMarkedText("Sample Title 8")} {CuesheetConstants.GetMarkedText("01:15:54")}", lines.Last()); } [TestMethod()] @@ -600,10 +593,7 @@ public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedA Assert.IsNotNull(importFile.AnalyzedCuesheet); Assert.IsNotNull(importFile.FileContentRecognized); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); - Assert.AreEqual(string.Format("{0} - {1}\t\t\t\t\t\t\t\t{2}", - CuesheetConstants.GetMarkedText("Age Of Love"), - CuesheetConstants.GetMarkedText("The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)"), - CuesheetConstants.GetMarkedText("04:29:28")), lines.ElementAt(53)); + Assert.AreEqual($"{CuesheetConstants.GetMarkedText("Age Of Love")} - {CuesheetConstants.GetMarkedText("The Age Of Love (Charlotte De Witte & Enrico Sangiuliano Remix)")}\t\t\t\t\t\t\t\t{CuesheetConstants.GetMarkedText("04:29:28")}", lines.ElementAt(53)); } [TestMethod()] diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index 1c465b10..6bb18e52 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -74,7 +74,7 @@ public AudioCodec? AudioCodec if ((field != null) && (Name?.EndsWith(field.FileExtension, StringComparison.CurrentCultureIgnoreCase) == false)) { //Replace file ending - Name = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(Name), field.FileExtension); + Name = $"{Path.GetFileNameWithoutExtension(Name)}{field.FileExtension}"; } } } diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs index b23017d3..730499ab 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs @@ -23,23 +23,23 @@ public class Exportprofile : Validateable { public static readonly string DefaultFileName = "Export.txt"; - public static readonly string SchemeCuesheetArtist = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Artist), SchemeCharacter); - public static readonly string SchemeCuesheetTitle = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Title), SchemeCharacter); - public static readonly string SchemeAudiofileName = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Audiofile), nameof(Audiofile.Name), SchemeCharacter); - public static readonly string SchemeCuesheetCDTextfile = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.CDTextfile), SchemeCharacter); - public static readonly string SchemeCuesheetCatalogueNumber = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Cuesheet), nameof(Cuesheet.Cataloguenumber), SchemeCharacter); - public static readonly string SchemeTrackArtist = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Artist), SchemeCharacter); - public static readonly string SchemeTrackTitle = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Title), SchemeCharacter); - public static readonly string SchemeTrackBegin = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Begin), SchemeCharacter); - public static readonly string SchemeTrackEnd = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.End), SchemeCharacter); - public static readonly string SchemeTrackLength = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Length), SchemeCharacter); - public static readonly string SchemeTrackPosition = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Position), SchemeCharacter); - public static readonly string SchemeTrackFlags = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.Flags), SchemeCharacter); - public static readonly string SchemeTrackPreGap = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PreGap), SchemeCharacter); - public static readonly string SchemeTrackPostGap = string.Format("{0}{1}.{2}{3}", SchemeCharacter, nameof(Track), nameof(Track.PostGap), SchemeCharacter); - public static readonly string SchemeDate = string.Format("{0}Date{1}", SchemeCharacter, SchemeCharacter); - public static readonly string SchemeDateTime = string.Format("{0}DateTime{1}", SchemeCharacter, SchemeCharacter); - public static readonly string SchemeTime = string.Format("{0}Time{1}", SchemeCharacter, SchemeCharacter); + public static readonly string SchemeCuesheetArtist = $"{SchemeCharacter}{nameof(Cuesheet)}.{nameof(Cuesheet.Artist)}{SchemeCharacter}"; + public static readonly string SchemeCuesheetTitle = $"{SchemeCharacter}{nameof(Cuesheet)}.{nameof(Cuesheet.Title)}{SchemeCharacter}"; + public static readonly string SchemeAudiofileName = $"{SchemeCharacter}{nameof(Audiofile)}.{nameof(Audiofile.Name)}{SchemeCharacter}"; + public static readonly string SchemeCuesheetCDTextfile = $"{SchemeCharacter}{nameof(Cuesheet)}.{nameof(Cuesheet.CDTextfile)}{SchemeCharacter}"; + public static readonly string SchemeCuesheetCatalogueNumber = $"{SchemeCharacter}{nameof(Cuesheet)}.{nameof(Cuesheet.Cataloguenumber)}{SchemeCharacter}"; + public static readonly string SchemeTrackArtist = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Artist)}{SchemeCharacter}"; + public static readonly string SchemeTrackTitle = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Title)}{SchemeCharacter}"; + public static readonly string SchemeTrackBegin = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Begin)}{SchemeCharacter}"; + public static readonly string SchemeTrackEnd = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.End)}{SchemeCharacter}"; + public static readonly string SchemeTrackLength = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Length)}{SchemeCharacter}"; + public static readonly string SchemeTrackPosition = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Position)}{SchemeCharacter}"; + public static readonly string SchemeTrackFlags = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Flags)}{SchemeCharacter}"; + public static readonly string SchemeTrackPreGap = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.PreGap)}{SchemeCharacter}"; + public static readonly string SchemeTrackPostGap = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.PostGap)}{SchemeCharacter}"; + public static readonly string SchemeDate = $"{SchemeCharacter}Date{SchemeCharacter}"; + public static readonly string SchemeDateTime = $"{SchemeCharacter}DateTime{SchemeCharacter}"; + public static readonly string SchemeTime = $"{SchemeCharacter}Time{SchemeCharacter}"; public static readonly Dictionary<string, string> AvailableCuesheetSchemes = new() { @@ -75,7 +75,6 @@ public class Exportprofile : Validateable string _schemeTracks; string _schemeFooter; string _filename; - string _name; public Exportprofile() { @@ -86,13 +85,13 @@ public Exportprofile() _schemeFooter = string.Empty; _filename = DefaultFileName; var random = new Random(); - _name = string.Format("{0}_{1}", nameof(Exportprofile), random.Next(1, 100)); + Name = $"{nameof(Exportprofile)}_{random.Next(1, 100)}"; } public Guid Id { get; init; } public string Name { - get => _name; - set { _name = value; OnValidateablePropertyChanged(); } + get; + set { field = value; OnValidateablePropertyChanged(); } } public string SchemeHead { diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs index 89399ed8..b94f8847 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs @@ -14,6 +14,7 @@ //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. using AudioCuesheetEditor.Model.Entity; +using System.Globalization; using System.Text.RegularExpressions; namespace AudioCuesheetEditor.Model.Utility; @@ -61,19 +62,19 @@ public string? Scheme switch (groupName) { case nameof(Days): - days = Convert.ToInt32(match.Groups[groupName].Value); + days = Convert.ToInt32(match.Groups[groupName].Value, CultureInfo.CurrentCulture); break; case nameof(Hours): - hours = Convert.ToInt32(match.Groups[groupName].Value); + hours = Convert.ToInt32(match.Groups[groupName].Value, CultureInfo.CurrentCulture); break; case nameof(Minutes): - minutes = Convert.ToInt32(match.Groups[groupName].Value); + minutes = Convert.ToInt32(match.Groups[groupName].Value, CultureInfo.CurrentCulture); break; case nameof(Seconds): - seconds = Convert.ToInt32(match.Groups[groupName].Value); + seconds = Convert.ToInt32(match.Groups[groupName].Value, CultureInfo.CurrentCulture); break; case nameof(Milliseconds): - milliseconds = Convert.ToInt32(match.Groups[groupName].Value); + milliseconds = Convert.ToInt32(match.Groups[groupName].Value, CultureInfo.CurrentCulture); break; } } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index 16bf61a1..f4e92bee 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -63,42 +63,42 @@ string WriteCuesheet() var builder = new StringBuilder(); if (string.IsNullOrEmpty(_sessionStateContainer.Cuesheet.Cataloguenumber) == false) { - _ = builder.AppendLine(string.Format("{0} {1}", CuesheetConstants.CuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.CuesheetCatalogueNumber} {_sessionStateContainer.Cuesheet.Cataloguenumber}"); } if (_sessionStateContainer.Cuesheet.CDTextfile != null) { - _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile.Name)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.CuesheetCDTextfile} \"{_sessionStateContainer.Cuesheet.CDTextfile.Name}\""); } - _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetTitle, _sessionStateContainer.Cuesheet.Title)); - _ = builder.AppendLine(string.Format("{0} \"{1}\"", CuesheetConstants.CuesheetArtist, _sessionStateContainer.Cuesheet.Artist)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.CuesheetTitle} \"{_sessionStateContainer.Cuesheet.Title}\""); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.CuesheetArtist} \"{_sessionStateContainer.Cuesheet.Artist}\""); foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) { - _ = builder.AppendLine(string.Format("{0} \"{1}\" {2}", CuesheetConstants.CuesheetFileName, audiofile.Name, audiofile.AudioCodec?.FileExtension.Replace(".", string.Empty).ToUpper(CultureInfo.InvariantCulture))); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.CuesheetFileName} \"{audiofile.Name}\" {audiofile.AudioCodec?.FileExtension.Replace(".", string.Empty).ToUpper(CultureInfo.InvariantCulture)}"); foreach(var track in audiofile.Tracks) { - _ = builder.AppendLine(string.Format("{0}{1} {2:00} {3}", CuesheetConstants.Tab, CuesheetConstants.CuesheetTrack, track.Position, CuesheetConstants.CuesheetTrackAudio)); - _ = builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackTitle, track.Title)); - _ = builder.AppendLine(string.Format("{0}{1}{2} \"{3}\"", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackArtist, track.Artist)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.CuesheetTrack} {track.Position:00} {CuesheetConstants.CuesheetTrackAudio}"); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackTitle} \"{track.Title}\""); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackArtist} \"{track.Artist}\""); if (track.Flags.Any()) { - _ = builder.AppendLine(string.Format("{0}{1}{2} {3}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel)))); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackFlags} {string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))}"); } if (track.PreGap.HasValue) { - _ = builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPreGap, Math.Floor(track.PreGap.Value.TotalMinutes), track.PreGap.Value.Seconds, track.PreGap.Value.Milliseconds * 75 / 1000)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackPreGap} {Math.Floor(track.PreGap.Value.TotalMinutes):00}:{track.PreGap.Value.Seconds:00}:{track.PreGap.Value.Milliseconds * 75 / 1000:00}"); } if (track.Begin.HasValue) { var begin = track.Begin.Value; - _ = builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackIndex01, Math.Floor(begin.TotalMinutes), begin.Seconds, begin.Milliseconds * 75 / 1000)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackIndex01} {Math.Floor(begin.TotalMinutes):00}:{begin.Seconds:00}:{begin.Milliseconds * 75 / 1000:00}"); } else { - throw new NullReferenceException(string.Format("{0} may not be null!", nameof(Track.Begin))); + throw new NullReferenceException($"{nameof(Track.Begin)} may not be null!"); } if (track.PostGap.HasValue) { - _ = builder.AppendLine(string.Format("{0}{1}{2} {3:00}:{4:00}:{5:00}", CuesheetConstants.Tab, CuesheetConstants.Tab, CuesheetConstants.TrackPostGap, Math.Floor(track.PostGap.Value.TotalMinutes), track.PostGap.Value.Seconds, track.PostGap.Value.Milliseconds * 75 / 1000)); + _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackPostGap} {Math.Floor(track.PostGap.Value.TotalMinutes):00}:{track.PostGap.Value.Seconds:00}:{track.PostGap.Value.Milliseconds * 75 / 1000:00}"); } } } diff --git a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs index d6d4baf4..bb2fbbc9 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs @@ -16,6 +16,7 @@ using AudioCuesheetEditor.Model.AudioCuesheet; using AudioCuesheetEditor.Model.AudioCuesheet.Import; using AudioCuesheetEditor.Model.IO.Import; +using System.Globalization; using System.Text; using System.Text.RegularExpressions; @@ -76,7 +77,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetArtistGroupName)); + throw new ArgumentException($"Group '{cuesheetArtistGroupName}' was null!"); } } if ((regexCuesheetTitle.IsMatch(line) == true) && (track == null)) @@ -91,7 +92,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetTitleGroupName)); + throw new ArgumentException($"Group '{cuesheetTitleGroupName}' was null!"); } } if (regexCuesheetFile.IsMatch(line) == true) @@ -106,7 +107,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetFileNameGroupName)); + throw new ArgumentException($"Group '{cuesheetFileNameGroupName}' was null!"); } } if (regexCDTextfile.IsMatch(line) == true) @@ -121,7 +122,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetCDTextfileGroupName)); + throw new ArgumentException($"Group '{cuesheetCDTextfileGroupName}' was null!"); } } if (regexCatalogueNumber.IsMatch(line) == true) @@ -136,7 +137,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", cuesheetCatalogueNumberGroupName)); + throw new ArgumentException($"Group '{cuesheetCatalogueNumberGroupName}' was null!"); } } if (regexTrackBegin.IsMatch(line) == true) @@ -156,7 +157,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", trackArtistGroupName)); + throw new ArgumentException($"Group '{trackArtistGroupName}' was null!"); } } if ((regexTrackTitle.IsMatch(line) == true) && (track != null)) @@ -171,7 +172,7 @@ public static IImportfile Analyse(string fileContent) } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", trackTitleGroupName)); + throw new ArgumentException($"Group '{trackTitleGroupName}' was null!"); } } if (regexTrackFlags.IsMatch(line) == true) @@ -189,12 +190,12 @@ public static IImportfile Analyse(string fileContent) } else { - throw new NullReferenceException(string.Format("Track was null during input {0}", line)); + throw new NullReferenceException($"Track was null during input {line}"); } } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", trackFlagsGroupName)); + throw new ArgumentException($"Group '{trackFlagsGroupName}' was null!"); } } if (regexTrackPreGap.IsMatch(line) == true) @@ -204,21 +205,21 @@ public static IImportfile Analyse(string fileContent) var matchGroup = match.Groups.GetValueOrDefault(trackPreGapGroupName); if (matchGroup != null) { - var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); - var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); - var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); + var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')], CultureInfo.CurrentCulture); + var seconds = int.Parse(matchGroup.Value.AsSpan(matchGroup.Value.IndexOf(':') + 1, 2), CultureInfo.CurrentCulture); + var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..], CultureInfo.CurrentCulture); if (track != null) { track.PreGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { - throw new NullReferenceException(string.Format("Track was null during input {0}", line)); + throw new NullReferenceException($"Track was null during input {line}"); } } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", trackPreGapGroupName)); + throw new ArgumentException($"Group '{trackPreGapGroupName}' was null!"); } } if (regexTrackIndex.IsMatch(line) == true) @@ -228,21 +229,21 @@ public static IImportfile Analyse(string fileContent) var matchGroup = match.Groups.GetValueOrDefault(trackIndex01GroupName); if (matchGroup != null) { - var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); - var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); - var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); + var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')], CultureInfo.CurrentCulture); + var seconds = int.Parse(matchGroup.Value.AsSpan(matchGroup.Value.IndexOf(':') + 1, 2), CultureInfo.CurrentCulture); + var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..], CultureInfo.CurrentCulture); if (track != null) { track.Begin = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { - throw new NullReferenceException(string.Format("Track was null during input {0}", line)); + throw new NullReferenceException($"Track was null during input {line}"); } } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", trackIndex01GroupName)); + throw new ArgumentException($"Group '{trackIndex01GroupName}' was null!"); } audiofile?.Tracks.Add(track); } @@ -253,21 +254,21 @@ public static IImportfile Analyse(string fileContent) var matchGroup = match.Groups.GetValueOrDefault(trackPostGapGroupName); if (matchGroup != null) { - var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')]); - var seconds = int.Parse(matchGroup.Value.Substring(matchGroup.Value.IndexOf(':') + 1, 2)); - var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..]); + var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')], CultureInfo.CurrentCulture); + var seconds = int.Parse(matchGroup.Value.AsSpan(matchGroup.Value.IndexOf(':') + 1, 2), CultureInfo.CurrentCulture); + var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..], CultureInfo.CurrentCulture); if (track != null) { track.PostGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { - throw new NullReferenceException(string.Format("Track was null during input {0}", line)); + throw new NullReferenceException($"Track was null during input {line}"); } } else { - throw new ArgumentException(string.Format("Group '{0}' was null!", trackPostGapGroupName)); + throw new ArgumentException($"Group '{trackPostGapGroupName}' was null!"); } } } diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index 464ef487..59f90c68 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ using AudioCuesheetEditor.Services.UI; using Microsoft.Extensions.Localization; using System.Data; +using System.Globalization; using System.Text; namespace AudioCuesheetEditor.Services.IO; @@ -63,7 +64,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeCuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile?.Name) .Replace(Exportprofile.SchemeCuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber) .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString(CultureInfo.CurrentCulture)) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); _ = builder.AppendLine(header); foreach (var audiofile in _sessionStateContainer.Cuesheet.Audiofiles) @@ -79,7 +80,7 @@ string WriteExport(Exportprofile exportprofile) var trackLine = exportprofile.SchemeTracks .Replace(Exportprofile.SchemeTrackArtist, track.Artist) .Replace(Exportprofile.SchemeTrackTitle, track.Title) - .Replace(Exportprofile.SchemeTrackPosition, track.Position.ToString()) + .Replace(Exportprofile.SchemeTrackPosition, track.Position?.ToString(CultureInfo.CurrentCulture)) .Replace(Exportprofile.SchemeTrackBegin, track.Begin.ToString()) .Replace(Exportprofile.SchemeTrackEnd, track.End.ToString()) .Replace(Exportprofile.SchemeTrackLength, track.Length.ToString()) @@ -87,7 +88,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty) .Replace(Exportprofile.SchemeTrackPostGap, track.PostGap != null ? track.PostGap.Value.ToString() : string.Empty) .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString(CultureInfo.CurrentCulture)) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); _ = builder.AppendLine(trackLine); } @@ -100,7 +101,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeCuesheetCDTextfile, _sessionStateContainer.Cuesheet.CDTextfile?.Name) .Replace(Exportprofile.SchemeCuesheetCatalogueNumber, _sessionStateContainer.Cuesheet.Cataloguenumber) .Replace(Exportprofile.SchemeDate, DateTime.Now.ToShortDateString()) - .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString()) + .Replace(Exportprofile.SchemeDateTime, DateTime.Now.ToString(CultureInfo.CurrentCulture)) .Replace(Exportprofile.SchemeTime, DateTime.Now.ToLongTimeString()); _ = builder.AppendLine(footer); } diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index 3385e148..6531121f 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -21,6 +21,7 @@ using AudioCuesheetEditor.Model.Options; using AudioCuesheetEditor.Model.Utility; using AudioCuesheetEditor.Services.Options; +using System.Globalization; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -71,7 +72,7 @@ static string ApplyRegexAndMarkGroups(object entity, Regex regex, string input, { var group = match.Groups[matchCounter]; var groupName = regex.GroupNameFromNumber(matchCounter); - if (!string.IsNullOrEmpty(groupName) && groupName != matchCounter.ToString()) + if (!string.IsNullOrEmpty(groupName) && groupName != matchCounter.ToString(CultureInfo.InvariantCulture)) { var property = entity.GetType().GetProperty(groupName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (property != null) @@ -278,7 +279,7 @@ static void SetValue(object entity, PropertyInfo property, string value, TimeSpa } if (property.PropertyType == typeof(ushort?)) { - property.SetValue(entity, Convert.ToUInt16(value)); + property.SetValue(entity, Convert.ToUInt16(value, CultureInfo.CurrentCulture)); } if (property.PropertyType == typeof(string)) { @@ -339,11 +340,11 @@ static Regex CreateRegexPattern(string scheme, string[] fieldNames) var isLast = i == parts.Count - 1 || parts.Skip(i + 1).All(p => !fieldNames.Contains(p)); if (isLast) { - _ = regexBuilder.Append($@"(?<{part}>.+)"); + _ = regexBuilder.Append(CultureInfo.CurrentCulture, $@"(?<{part}>.+)"); } else { - _ = regexBuilder.Append($@"(?<{part}>.+?)"); + _ = regexBuilder.Append(CultureInfo.CurrentCulture, $@"(?<{part}>.+?)"); } } else diff --git a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs index 393b1662..cb13e840 100644 --- a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs +++ b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ using AudioCuesheetEditor.Model.Options; using Microsoft.Extensions.Localization; using Microsoft.JSInterop; +using System.Globalization; using System.Linq.Expressions; using System.Reflection; using System.Text.Json; @@ -93,7 +94,7 @@ public async Task<Result> SaveOptionsAsync(IOptions options) if (propertyInfo != null && targetObject != null) { - propertyInfo.SetValue(targetObject, Convert.ChangeType(value, propertyInfo.PropertyType)); + propertyInfo.SetValue(targetObject, Convert.ChangeType(value, propertyInfo.PropertyType, CultureInfo.CurrentCulture)); } else { @@ -114,7 +115,7 @@ public async Task<Result> SaveOptionsAsync(IOptions options) var nestedProperty = typeof(T).GetProperty(memberExpression.Member.Name) ?? throw new ArgumentException("The provided nested property expression does not reference a valid property."); var nestedInstance = nestedProperty.GetValue(options) ?? throw new InvalidOperationException("The nested property is null."); var valueProperty = ResolveNestedProperty(valuePropertyExpression.Body as MemberExpression, ref nestedInstance) ?? throw new ArgumentException("The provided value property expression does not reference a valid property."); - valueProperty.SetValue(nestedInstance, Convert.ChangeType(value, valueProperty.PropertyType)); + valueProperty.SetValue(nestedInstance, Convert.ChangeType(value, valueProperty.PropertyType, CultureInfo.CurrentCulture)); _ = await SaveOptionsAsync(options); } diff --git a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs index 261b8a40..d1a2951c 100644 --- a/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs +++ b/AudioCuesheetEditor/Services/Provider/MusicBrainzDataProvider.cs @@ -75,7 +75,7 @@ public async Task<IReadOnlyCollection<MusicBrainzTrack>> SearchTitleAsync(string } else { - findRecordingsResult = await query.FindRecordingsAsync(string.Format("{0} AND artistname:{1}", searchString, artist), cancellationToken: token); + findRecordingsResult = await query.FindRecordingsAsync($"{searchString} AND artistname:{artist}", cancellationToken: token); } foreach (var result in findRecordingsResult.Results) { diff --git a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs index 12d6f976..b71c5c8a 100644 --- a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs +++ b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ using AudioCuesheetEditor.Model.Options; using AudioCuesheetEditor.Model.Utility; using AudioCuesheetEditor.Services.Options; +using System.Globalization; using System.Linq.Expressions; using System.Reflection; @@ -69,7 +70,7 @@ public async Task TimespanTextChanged<T, TProperty>(T entity, Expression<Func<T, { try { - formatted = timeSpan.Value.ToString(_applicationOptions?.DisplayTimeSpanFormat); + formatted = timeSpan.Value.ToString(_applicationOptions?.DisplayTimeSpanFormat, CultureInfo.CurrentCulture); } catch (FormatException) { diff --git a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs index 933b0572..83c0c2d5 100644 --- a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs +++ b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs @@ -79,7 +79,7 @@ public void Undo() } else { - throw new NullReferenceException(string.Format("Property {0} could not be found!", traceAbleChange.PropertyName)); + throw new NullReferenceException($"Property {traceAbleChange.PropertyName} could not be found!"); } } if (change != null) @@ -130,7 +130,7 @@ public void Redo() } else { - throw new NullReferenceException(string.Format("Property {0} could not be found!", traceAbleChange.PropertyName)); + throw new NullReferenceException($"Property {traceAbleChange.PropertyName} could not be found!"); } } if (change != null) diff --git a/AudioCuesheetEditor/Services/Validation/ValidationService.cs b/AudioCuesheetEditor/Services/Validation/ValidationService.cs index 864de8e1..b11f97bd 100644 --- a/AudioCuesheetEditor/Services/Validation/ValidationService.cs +++ b/AudioCuesheetEditor/Services/Validation/ValidationService.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -48,7 +48,7 @@ public IEnumerable<string> Validate(object? model, string propertyName) } else { - throw new NotSupportedException(string.Format("Model was not of supposed type '{0}'", nameof(IValidateable))); + throw new NotSupportedException($"Model was not of supposed type '{nameof(IValidateable)}'"); } } return errors; From 5ed655c6041e1e5c8b653f4696fa73ba079952b7 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:48:35 +0200 Subject: [PATCH 13/20] fix CA1000 --- .editorconfig | 2 - .../AudioCuesheet/CuesheetManagerTests.cs | 26 +++---- .../Services/IO/CuesheetExportServiceTests.cs | 8 +- .../Services/IO/ImportManagerTests.cs | 2 +- .../Services/AudioCuesheet/CuesheetManager.cs | 16 ++-- .../Services/IO/CuesheetExportService.cs | 6 +- .../Services/IO/ExportfileGenerator.cs | 6 +- .../Options/LocalStorageOptionsProvider.cs | 2 +- AudioCuesheetEditor/Services/Result.cs | 75 +++++++++++-------- .../Services/UI/DialogManager.cs | 12 +-- .../Services/UI/IDialogManager.cs | 10 +-- .../Dialogs/GenerateCuesheetDialog.razor | 8 +- .../Shared/Dialogs/GenerateExportDialog.razor | 4 +- .../Shared/Record/ControlRecording.razor | 8 +- 14 files changed, 97 insertions(+), 88 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9a32c6ab..f238a3e1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,10 +16,8 @@ indent_size = 4 tab_width = 4 #TODO: Enable all of these -dotnet_diagnostic.CA1000.severity = suggestion dotnet_diagnostic.CA1051.severity = suggestion dotnet_diagnostic.CA1716.severity = suggestion -dotnet_diagnostic.CA1727.severity = suggestion dotnet_diagnostic.CA2201.severity = suggestion # Organize usings diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs index a10b8784..0d6bd244 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs @@ -163,7 +163,7 @@ public void IsRecordingPossible_WithTracks_ReturnsFailure() var result = _cuesheetManager.IsRecordingPossible; // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual("Cuesheet already contains tracks!", result.Error!.Message); + Assert.AreEqual("Cuesheet already contains tracks!", result.FailureDetails!.Message); } [TestMethod] @@ -183,7 +183,7 @@ public void IsRecordingPossible_RecordingAlreadyRunning_ReturnsFailure() var result = _cuesheetManager.IsRecordingPossible; // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual("Record is already running!", result.Error!.Message); + Assert.AreEqual("Record is already running!", result.FailureDetails!.Message); } [TestMethod] @@ -225,7 +225,7 @@ public void StartRecording_RecordingNotPossible_ReturnsFailure() // Assert Assert.IsFalse(result.IsSuccess); Assert.IsFalse(isRecordingChanged); - Assert.AreEqual("Record is already running!", result.Error!.Message); + Assert.AreEqual("Record is already running!", result.FailureDetails!.Message); } [TestMethod] @@ -821,7 +821,7 @@ public void MoveUp_NoTracksAbove_ReturnsFailure() var result = _cuesheetManager.MoveUp([track2, track1]); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); Assert.AreEqual(track1End, track1.End); @@ -881,7 +881,7 @@ public void MoveUp_NoTracksSelected_ReturnsFailure() var result = _cuesheetManager.MoveUp(new HashSet<Track>()); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); Assert.AreEqual(track1End, track1.End); @@ -979,7 +979,7 @@ public void MoveUp_NoAudiofilesAbove_ReturnsFailure() var result = _cuesheetManager.MoveUp([file1, file2]); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); } @@ -997,10 +997,10 @@ public void MoveUp_NoAudiofilesSelected_ReturnsFailure() }; _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act - var result = _cuesheetManager.MoveUp(new HashSet<Audiofile>()); + var result = _cuesheetManager.MoveUp([]); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); } @@ -1247,7 +1247,7 @@ public void MoveDown_NoTracksBelow_ReturnsFailure() var result = _cuesheetManager.MoveDown([track2, track3]); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); Assert.AreEqual(track1End, track1.End); @@ -1307,7 +1307,7 @@ public void MoveDown_NoTracksSelected_ReturnsFailure() var result = _cuesheetManager.MoveDown(new HashSet<Track>()); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); Assert.AreEqual(track1End, track1.End); @@ -1404,7 +1404,7 @@ public void MoveDown_NoAudiofilesBelow_ReturnsFailure() var result = _cuesheetManager.MoveDown([file2, file3]); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); } @@ -1422,10 +1422,10 @@ public void MoveDown_NoAudiofilesSelected_ReturnsFailure() }; _ = _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); // Act - var result = _cuesheetManager.MoveDown(new HashSet<Audiofile>()); + var result = _cuesheetManager.MoveDown([]); // Assert Assert.IsFalse(result.IsSuccess); - Assert.AreEqual(ErrorType.NotPossible, result.Error!.Type); + Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); _traceChangeManager.VerifySet(x => x.BulkEdit = true, Times.Never); _traceChangeManager.VerifySet(x => x.BulkEdit = false, Times.Never); } diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs index 3c4796c4..0b2d5e34 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs @@ -54,7 +54,7 @@ public void CanGenerateExportfile_InvalidExtension_ReturnsValidationMessage() // Assert Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains("File extension is not")); + Assert.IsTrue(result.FailureDetails?.Message.Contains("File extension is not")); } [TestMethod] @@ -73,7 +73,7 @@ public void CanGenerateExportfile_InvalidAudiofileName_ReturnsValidationMessage( // Assert Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Audiofile.Name)} has no value!")); + Assert.IsTrue(result.FailureDetails?.Message.Contains($"{nameof(Audiofile.Name)} has no value!")); } [TestMethod] @@ -89,7 +89,7 @@ public void CanGenerateExportfile_InvalidCuesheeetTitle_ReturnsValidationMessage // Assert Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Cuesheet.Title)} has no value!")); + Assert.IsTrue(result.FailureDetails?.Message.Contains($"{nameof(Cuesheet.Title)} has no value!")); } [TestMethod] @@ -126,7 +126,7 @@ public void CanGenerateExportfile_InvalidTrackEnd_ReturnsValidationMessage() // Assert Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.Error?.Message.Contains($"{nameof(Track.End)} has no value!")); + Assert.IsTrue(result.FailureDetails?.Message.Contains($"{nameof(Track.End)} has no value!")); } [TestMethod] diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index be2a03ac..b2546c04 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -204,7 +204,7 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() Assert.AreEqual(importAudiofile.Tracks.First().Title, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); Assert.AreEqual(importAudiofile.Tracks.First().Begin, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); Assert.AreEqual(importAudiofile.Tracks.First().End, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().End); - Assert.AreSequenceEqual([.. importAudiofile.Tracks.First().Flags], sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Flags.ToList(), Microsoft.VisualStudio.TestTools.UnitTesting.SequenceOrder.InAnyOrder); + Assert.AreSequenceEqual([.. importAudiofile.Tracks.First().Flags], sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Flags.ToList(), SequenceOrder.InAnyOrder); Assert.AreEqual(importAudiofile.Tracks.First().Position, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Position); Assert.AreEqual(importAudiofile.Tracks.First().PreGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PreGap); Assert.AreEqual(importAudiofile.Tracks.First().PostGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PostGap); diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs index 0bb7cd4e..461abae8 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -56,11 +56,11 @@ public Result IsRecordingPossible { if (_sessionStateContainer.Cuesheet.IsRecording == true) { - return Result.Failure(new Error(ErrorType.NotPossible, "Record is already running!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Record is already running!")); } if (_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Any()) { - return Result.Failure(new Error(ErrorType.NotPossible, "Cuesheet already contains tracks!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Cuesheet already contains tracks!")); } return Result.Success(); } @@ -75,7 +75,7 @@ public Result StartRecording() var cuesheet = _sessionStateContainer.Cuesheet; if (cuesheet.IsRecording == true) { - return Result.Failure(new Error(ErrorType.NotPossible, "Record is already running!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Record is already running!")); } cuesheet.RecordingStart = DateTime.UtcNow; if (cuesheet.Audiofiles.Count == 0) @@ -145,7 +145,7 @@ public Result MoveUp(HashSet<Track> selectedTracks, uint positions = 1) { if (IsMoveUpPossible(selectedTracks) == false) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks up is not possible!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Moving tracks up is not possible!")); } _traceChangeManager.BulkEdit = true; while (positions > 0) @@ -195,7 +195,7 @@ public Result MoveUp(HashSet<Audiofile> selectedAudiofiles) { if (IsMoveUpPossible(selectedAudiofiles) == false) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving audiofiles up is not possible!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Moving audiofiles up is not possible!")); } var cuesheet = _sessionStateContainer.ActiveCuesheet; _traceChangeManager.BulkEdit = true; @@ -229,7 +229,7 @@ public Result MoveDown(HashSet<Track> selectedTracks, uint positions = 1) { if (IsMoveDownPossible(selectedTracks) == false) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving tracks down is not possible!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Moving tracks down is not possible!")); } _traceChangeManager.BulkEdit = true; while (positions > 0) @@ -278,7 +278,7 @@ public Result MoveDown(HashSet<Audiofile> selectedAudiofiles) { if (IsMoveDownPossible(selectedAudiofiles) == false) { - return Result.Failure(new Error(ErrorType.NotPossible, "Moving audiofiles down is not possible!")); + return Result.Failure(new FailureDetails(ErrorType.NotPossible, "Moving audiofiles down is not possible!")); } var cuesheet = _sessionStateContainer.ActiveCuesheet; _traceChangeManager.BulkEdit = true; diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index f4e92bee..a3edb892 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -43,7 +43,7 @@ public Result CanGenerateExportfile(string? filename) validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); if (validationMessages.Count != 0) { - return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); + return Result.Failure(new FailureDetails(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); } return Result.Success(); } @@ -53,9 +53,9 @@ public Result<Exportfile> GenerateExportfile(string? filename) var validationResult = CanGenerateExportfile(filename); if (validationResult.IsSuccess == false) { - return Result<Exportfile>.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); + return Result.Failure(new FailureDetails(ErrorType.ValidationFailed, validationResult.FailureDetails!.Message)); } - return Result<Exportfile>.Success(new Exportfile() { Name = filename!, Content = WriteCuesheet() }); + return Result.Success(new Exportfile() { Name = filename!, Content = WriteCuesheet() }); } string WriteCuesheet() diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index 59f90c68..ddc5318b 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -38,7 +38,7 @@ public Result CanGenerateExportfile(Exportprofile exportprofile) validationMessages.AddRange(_sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).Select(x => x.Validate()).SelectMany(x => x.ValidationMessages)); if (validationMessages.Count != 0) { - return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); + return Result.Failure(new FailureDetails(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationMessages.Select(x => x.GetMessageLocalized(_localizer))))); } return Result.Success(); } @@ -48,9 +48,9 @@ public Result<Exportfile> GenerateExportfile(Exportprofile exportprofile) var validationResult = CanGenerateExportfile(exportprofile); if (validationResult.IsSuccess == false) { - return Result<Exportfile>.Failure(new Error(ErrorType.ValidationFailed, validationResult.Error!.Message)); + return Result.Failure(new FailureDetails(ErrorType.ValidationFailed, validationResult.FailureDetails!.Message)); } - return Result<Exportfile>.Success(new Exportfile() { Name = exportprofile.Filename, Content = WriteExport(exportprofile) }); + return Result.Success(new Exportfile() { Name = exportprofile.Filename, Content = WriteExport(exportprofile) }); } string WriteExport(Exportprofile exportprofile) diff --git a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs index cb13e840..69444436 100644 --- a/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs +++ b/AudioCuesheetEditor/Services/Options/LocalStorageOptionsProvider.cs @@ -70,7 +70,7 @@ public async Task<Result> SaveOptionsAsync(IOptions options) var validationResult = validateable.Validate(); if (validationResult.Status == ValidationStatus.Error) { - return Result.Failure(new Error(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationResult.ValidationMessages.Select(x => x.GetMessageLocalized(_localizer))))); + return Result.Failure(new FailureDetails(ErrorType.ValidationFailed, string.Join(Environment.NewLine, validationResult.ValidationMessages.Select(x => x.GetMessageLocalized(_localizer))))); } } await WriteOptionsAsync(options); diff --git a/AudioCuesheetEditor/Services/Result.cs b/AudioCuesheetEditor/Services/Result.cs index df1b9b3e..64014f82 100644 --- a/AudioCuesheetEditor/Services/Result.cs +++ b/AudioCuesheetEditor/Services/Result.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -39,9 +39,9 @@ public enum ErrorType } /// <summary> -/// Represents an error of an service +/// Represents failure of a service /// </summary> -public class Error(ErrorType type, string message) +public class FailureDetails(ErrorType type, string message) { /// <summary> /// Type of error @@ -53,22 +53,24 @@ public class Error(ErrorType type, string message) public string Message { get; } = message; } + /// <summary> -/// Indicates a service result +/// Indicates a service result. /// </summary> public class Result { /// <summary> - /// Indicates if the result was successful + /// Indicates whether the operation was successful. /// </summary> public bool IsSuccess { get; } + /// <summary> - /// The error if one occurred + /// Contains the failure details if the operation failed. /// </summary> - public Error? Error { get; } + public FailureDetails? FailureDetails { get; } /// <summary> - /// Private constructor + /// Initializes a new instance of the <see cref="Result"/> class. /// </summary> protected Result() { @@ -76,53 +78,62 @@ protected Result() } /// <summary> - /// Private constructor + /// Initializes a new instance of the <see cref="Result"/> class with an error. /// </summary> - protected Result(Error error) + /// <param name="failureDetails"></param> + protected Result(FailureDetails failureDetails) { IsSuccess = false; - Error = error; + FailureDetails = failureDetails; } + /// <summary> - /// Creates a success result + /// Creates a successful result without a value. /// </summary> - /// <returns></returns> public static Result Success() => new(); + /// <summary> - /// Creates a failure result + /// Creates a successful result containing a value. /// </summary> - /// <param name="error"></param> - /// <returns></returns> - public static Result Failure(Error error) => new(error); + public static Result<T> Success<T>(T value) => new(value); + + /// <summary> + /// Creates a failed result. + /// </summary> + public static FailureResult Failure(FailureDetails error) => new(error); } /// <summary> -/// Represent the result of a service +/// Represents a failed result before conversion to a specific result type. /// </summary> -/// <typeparam name="T"></typeparam> +public sealed class FailureResult : Result +{ + internal FailureResult(FailureDetails error) : base(error) { } +} + +/// <summary> +/// Represents a service result containing a value. +/// </summary> +/// <typeparam name="T">The type of the result value.</typeparam> public class Result<T> : Result { /// <summary> - /// The result value + /// Gets the result value. /// </summary> public T? Value { get; } - Result(T value) : base() + internal Result(T value) { Value = value; } - Result(Error error) : base(error) { } - /// <summary> - /// Creates a success result - /// </summary> - /// <param name="value"></param> - /// <returns></returns> - public static Result<T> Success(T value) => new(value); + Result(FailureDetails error) : base(error) { } + /// <summary> - /// Creates a failure result + /// Converts a failed result to a typed failed result. /// </summary> - /// <param name="error"></param> - /// <returns></returns> - public static new Result<T> Failure(Error error) => new(error); + public static implicit operator Result<T>(FailureResult failure) + { + return new Result<T>(failure.FailureDetails ?? throw new InvalidOperationException("A failed result requires failure details.")); + } } diff --git a/AudioCuesheetEditor/Services/UI/DialogManager.cs b/AudioCuesheetEditor/Services/UI/DialogManager.cs index 93f4f451..1e4fb582 100644 --- a/AudioCuesheetEditor/Services/UI/DialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/DialogManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -229,15 +229,15 @@ public async Task<bool> ShowImportAudiofilesDialogAsync() } /// <inheritdoc/> - public async Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? OkText = "Ok", string? OkButtonStartIcon = null) + public async Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? okText = "Ok", string? okButtonStartIcon = null) { var parameters = new DialogParameters<InputDialog<T>> { { x => x.Placeholder, placeholder }, { x => x.Label, label }, { x => x.InitialValue, initialValue }, - { x => x.OkText, OkText }, - { x => x.OkButtonStartIcon, OkButtonStartIcon } + { x => x.OkText, okText }, + { x => x.OkButtonStartIcon, okButtonStartIcon } }; var options = new DialogOptions() { CloseOnEscapeKey = true, BackdropClick = false, FullWidth = true, CloseButton = true }; var dialog = await _dialogService.ShowAsync<InputDialog<T>>(title, parameters, options); @@ -245,11 +245,11 @@ public async Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? plac if (result?.Canceled == false) { var value = (T)result.Data!; - return Result<T>.Success(value); + return Result.Success(value); } else { - return Result<T>.Failure(new Error(ErrorType.Aborted, "User canceled the input dialog.")); + return Result.Failure(new FailureDetails(ErrorType.Aborted, "User canceled the input dialog.")); } } } diff --git a/AudioCuesheetEditor/Services/UI/IDialogManager.cs b/AudioCuesheetEditor/Services/UI/IDialogManager.cs index cc9109cf..5478d56d 100644 --- a/AudioCuesheetEditor/Services/UI/IDialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/IDialogManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -32,8 +32,8 @@ public interface IDialogManager /// <param name="placeholder"></param> /// <param name="label"></param> /// <param name="initialValue"></param> - /// <param name="OkText"></param> - /// <param name="OkButtonStartIcon"></param> + /// <param name="okText"></param> + /// <param name="okButtonStartIcon"></param> /// <returns></returns> - Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? OkText = "Ok", string? OkButtonStartIcon = null); -} \ No newline at end of file + Task<Result<T>> ShowInputDialogAsync<T>(string? title, string? placeholder, string? label, T initialValue, string? okText = "Ok", string? okButtonStartIcon = null); +} diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.razor index 85ca96bb..6a47a43c 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.razor @@ -1,4 +1,4 @@ -<!-- +<!-- This file is part of AudioCuesheetEditor. AudioCuesheetEditor is free software: you can redistribute it and/or modify @@ -67,7 +67,7 @@ along with Foobar. If not, see var generateExportResult = _cuesheetExportService.GenerateExportfile(_options!.CuesheetFilename); if (generateExportResult.IsSuccess == false) { - throw new InvalidOperationException($"Could not generate export file: {generateExportResult.Error?.Message}"); + throw new InvalidOperationException($"Could not generate export file: {generateExportResult.FailureDetails?.Message}"); } var exportfile = generateExportResult.Value!; await _blazorDownloadFileService.DownloadFileFromText(exportfile.Name, exportfile.Content, System.Text.Encoding.Default, "text/plain"); @@ -79,7 +79,7 @@ along with Foobar. If not, see var result = _cuesheetExportService.CanGenerateExportfile(_options?.CuesheetFilename); if (result.IsSuccess == false) { - _validationErrorMessage = result.Error?.Message.Replace(Environment.NewLine, "<br />"); + _validationErrorMessage = result.FailureDetails?.Message.Replace(Environment.NewLine, "<br />"); } SetFileNameValidationError(); } @@ -99,7 +99,7 @@ along with Foobar. If not, see var result = await LocalStorageOptionsProvider.SaveOptionsValueAsync<DownloadOptions>(x => x.CuesheetFilename, newFilename); if (result.IsSuccess == false) { - _fileNameValidationErrorMessage = result.Error?.Message; + _fileNameValidationErrorMessage = result.FailureDetails?.Message; } } diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.razor index c7c8cf09..afd4f1c2 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.razor @@ -1,4 +1,4 @@ -<!-- +<!-- This file is part of AudioCuesheetEditor. AudioCuesheetEditor is free software: you can redistribute it and/or modify @@ -88,7 +88,7 @@ along with Foobar. If not, see var result = _exportfileGenerator.CanGenerateExportfile(selectedExportProfile); if (result.IsSuccess == false) { - _validationErrorMessage = result.Error?.Message.Replace(Environment.NewLine, "<br />"); + _validationErrorMessage = result.FailureDetails?.Message.Replace(Environment.NewLine, "<br />"); } } else diff --git a/AudioCuesheetEditor/Shared/Record/ControlRecording.razor b/AudioCuesheetEditor/Shared/Record/ControlRecording.razor index e98af628..c528e095 100644 --- a/AudioCuesheetEditor/Shared/Record/ControlRecording.razor +++ b/AudioCuesheetEditor/Shared/Record/ControlRecording.razor @@ -1,4 +1,4 @@ -<!-- +<!-- This file is part of AudioCuesheetEditor. AudioCuesheetEditor is free software: you can redistribute it and/or modify @@ -100,7 +100,7 @@ along with Foobar. If not, see var result = _cuesheetManager.IsRecordingPossible; if (result.IsSuccess == false) { - _errorMessage = result.Error!.Message; + _errorMessage = result.FailureDetails!.Message; } } @@ -135,7 +135,7 @@ along with Foobar. If not, see } else { - _errorMessage = result.Error!.Message; + _errorMessage = result.FailureDetails!.Message; } } @@ -169,7 +169,7 @@ along with Foobar. If not, see var result = _cuesheetManager.IsRecordingPossible; if (result.IsSuccess == false) { - _errorMessage = result.Error!.Message; + _errorMessage = result.FailureDetails!.Message; } } } From 57ecd3d5e05ace013f44fcc58df5ce35ca28cb6c Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:10:39 +0200 Subject: [PATCH 14/20] fix CA1051 --- .editorconfig | 2 - .../Tests/PlaywrightTestBase.cs | 7 +- .../Model/AudioCuesheet/AudiofileTests.cs | 4 +- .../Model/AudioCuesheet/TrackTests.cs | 6 +- .../Model/Entity/ValidateableTests.cs | 4 +- .../Model/IO/ProjectfileTests.cs | 4 +- .../AudioCuesheet/AudiofileManagerTests.cs | 54 +++--- .../AudioCuesheet/CuesheetManagerTests.cs | 158 +++++++++--------- .../AudioCuesheet/TrackManagerTests.cs | 60 +++---- .../Services/IO/CuesheetExportServiceTests.cs | 26 +-- .../Services/IO/ExportfileGeneratorTests.cs | 12 +- .../Services/IO/ImportManagerTests.cs | 16 +- .../Services/IO/TextImportServiceTests.cs | 22 +-- .../ApplicationOptionsTimeSpanParserTests.cs | 4 +- .../Services/UI/TraceChangeManagerTests.cs | 4 +- .../AudioCuesheetEditor.csproj | 4 + .../{Shared => Components}/AppBar.de.resx | 0 .../{Shared => Components}/AppBar.razor | 0 .../{Shared => Components}/AppBar.resx | 0 .../Audio/AudioPlayer.de.resx | 0 .../Audio/AudioPlayer.razor | 0 .../Audio/AudioPlayer.resx | 0 .../BaseLocalizedComponent.cs | 6 +- .../Cuesheet/Audiofiles.de.resx | 0 .../Cuesheet/Audiofiles.razor | 0 .../Cuesheet/Audiofiles.resx | 0 .../Cuesheet/CuesheetData.de.resx | 0 .../Cuesheet/CuesheetData.razor | 0 .../Cuesheet/CuesheetData.resx | 0 .../Dialogs/ConfirmationDialog.de.resx | 0 .../Dialogs/ConfirmationDialog.razor | 0 .../Dialogs/ConfirmationDialog.resx | 0 .../Dialogs/DisplayHotkeysDialog.de.resx | 0 .../Dialogs/DisplayHotkeysDialog.razor | 0 .../Dialogs/DisplayHotkeysDialog.resx | 0 .../Dialogs/DownloadProjectfileDialog.de.resx | 0 .../Dialogs/DownloadProjectfileDialog.razor | 0 .../Dialogs/DownloadProjectfileDialog.resx | 0 .../Dialogs/EditMultipleTracksModal.de.resx | 0 .../Dialogs/EditMultipleTracksModal.razor | 8 +- .../Dialogs/EditMultipleTracksModal.resx | 0 .../Dialogs/EditTrackModal.de.resx | 0 .../Dialogs/EditTrackModal.razor | 6 +- .../Dialogs/EditTrackModal.resx | 0 .../Dialogs/GenerateCuesheetDialog.de.resx | 0 .../Dialogs/GenerateCuesheetDialog.razor | 0 .../Dialogs/GenerateCuesheetDialog.resx | 0 .../Dialogs/GenerateExportDialog.de.resx | 0 .../Dialogs/GenerateExportDialog.razor | 0 .../Dialogs/GenerateExportDialog.resx | 0 .../Dialogs/ImportAudiofilesDialog.de.resx | 0 .../Dialogs/ImportAudiofilesDialog.razor | 0 .../Dialogs/ImportAudiofilesDialog.resx | 0 .../Dialogs/InputDialog.de.resx | 0 .../Dialogs/InputDialog.razor | 0 .../Dialogs/InputDialog.resx | 0 .../Dialogs/LoadingDialog.de.resx | 0 .../Dialogs/LoadingDialog.razor | 0 .../Dialogs/LoadingDialog.resx | 0 .../Dialogs/SettingsDialog.de.resx | 0 .../Dialogs/SettingsDialog.razor | 0 .../Dialogs/SettingsDialog.resx | 0 .../Export/DisplayExportfileContent.de.resx | 0 .../Export/DisplayExportfileContent.razor | 0 .../Export/DisplayExportfileContent.resx | 0 .../Export/EditExportProfile.de.resx | 0 .../Export/EditExportProfile.razor | 0 .../Export/EditExportProfile.resx | 0 .../Export/SelectExportProfile.de.resx | 0 .../Export/SelectExportProfile.razor | 0 .../Export/SelectExportProfile.resx | 0 .../Import/DisplayAnalyzedResult.de.resx | 0 .../Import/DisplayAnalyzedResult.razor | 0 .../Import/DisplayAnalyzedResult.resx | 0 .../Import/Importprofiles.de.resx | 0 .../Import/Importprofiles.razor | 0 .../Import/Importprofiles.resx | 0 .../Inputs/FileDropOverlay.de.resx | 0 .../Inputs/FileDropOverlay.razor | 0 .../Inputs/FileDropOverlay.resx | 0 .../Inputs/FileInput.de.resx | 0 .../Inputs/FileInput.razor | 0 .../Inputs/FileInput.resx | 0 .../Inputs/TextField.de.resx | 0 .../Inputs/TextField.razor | 0 .../Inputs/TextField.resx | 0 .../Layouts/MainLayout.de.resx | 0 .../Layouts/MainLayout.razor | 0 .../Layouts/MainLayout.resx | 0 .../Layouts/MainLayoutWithoutMenu.de.resx | 0 .../Layouts/MainLayoutWithoutMenu.razor | 0 .../Layouts/MainLayoutWithoutMenu.resx | 0 .../Record/AddTrack.de.resx | 0 .../Record/AddTrack.razor | 0 .../Record/AddTrack.resx | 0 .../Record/ControlRecording.de.resx | 0 .../Record/ControlRecording.razor | 0 .../Record/ControlRecording.resx | 0 .../TrackList/ArtistColumn.razor | 0 .../TrackList/TitleColumn.razor | 0 .../TrackList/TrackList.de.resx | 0 .../TrackList/TrackList.razor | 14 +- .../TrackList/TrackList.resx | 0 .../TrackList/TrackListControlButtons.de.resx | 0 .../TrackList/TrackListControlButtons.razor | 0 .../TrackList/TrackListControlButtons.resx | 0 .../Validation/Alert.razor | 0 .../ViewModes/ViewModeFull.de.resx | 0 .../ViewModes/ViewModeFull.razor | 0 .../ViewModes/ViewModeFull.resx | 0 .../ViewModes/ViewModeImport.de.resx | 0 .../ViewModes/ViewModeImport.razor | 0 .../ViewModes/ViewModeImport.resx | 0 .../ViewModes/ViewModeRecord.de.resx | 0 .../ViewModes/ViewModeRecord.razor | 0 .../ViewModes/ViewModeRecord.resx | 0 .../Model/AudioCuesheet/Cuesheet.cs | 6 +- .../Model/AudioCuesheet/ITrack.cs | 4 +- .../Model/AudioCuesheet/Import/ImportTrack.cs | 4 +- .../Model/AudioCuesheet/Track.cs | 48 +++--- .../Model/Entity/IValidateable.cs | 14 +- .../Model/Entity/Validateable.cs | 4 +- .../Model/IO/Audio/Audiofile.cs | 12 +- .../Model/IO/Export/Exportprofile.cs | 8 +- .../Model/IO/Import/Importprofile.cs | 8 +- .../Model/Options/DownloadOptions.cs | 6 +- .../Model/Options/ImportOptions.cs | 6 +- .../Model/Utility/TimeSpanFormat.cs | 4 +- .../Services/Audio/PlaybackService.cs | 10 +- .../AudioCuesheet/AudiofileManager.cs | 20 +-- .../Services/AudioCuesheet/CuesheetManager.cs | 16 +- .../Services/AudioCuesheet/TrackManager.cs | 24 +-- .../Services/IO/ExportfileGenerator.cs | 2 +- .../Services/IO/ImportManager.cs | 18 +- .../Services/IO/TextImportService.cs | 2 +- .../Services/UI/DialogManager.cs | 14 +- AudioCuesheetEditor/_Imports.razor | 28 ++-- 137 files changed, 341 insertions(+), 338 deletions(-) rename AudioCuesheetEditor/{Shared => Components}/AppBar.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/AppBar.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/AppBar.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Audio/AudioPlayer.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Audio/AudioPlayer.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Audio/AudioPlayer.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/BaseLocalizedComponent.cs (96%) rename AudioCuesheetEditor/{Shared => Components}/Cuesheet/Audiofiles.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Cuesheet/Audiofiles.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Cuesheet/Audiofiles.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Cuesheet/CuesheetData.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Cuesheet/CuesheetData.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Cuesheet/CuesheetData.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/ConfirmationDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/ConfirmationDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/ConfirmationDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/DisplayHotkeysDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/DisplayHotkeysDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/DisplayHotkeysDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/DownloadProjectfileDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/DownloadProjectfileDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/DownloadProjectfileDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/EditMultipleTracksModal.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/EditMultipleTracksModal.razor (98%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/EditMultipleTracksModal.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/EditTrackModal.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/EditTrackModal.razor (96%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/EditTrackModal.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/GenerateCuesheetDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/GenerateCuesheetDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/GenerateCuesheetDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/GenerateExportDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/GenerateExportDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/GenerateExportDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/ImportAudiofilesDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/ImportAudiofilesDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/ImportAudiofilesDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/InputDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/InputDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/InputDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/LoadingDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/LoadingDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/LoadingDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/SettingsDialog.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/SettingsDialog.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Dialogs/SettingsDialog.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/DisplayExportfileContent.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/DisplayExportfileContent.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/DisplayExportfileContent.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/EditExportProfile.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/EditExportProfile.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/EditExportProfile.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/SelectExportProfile.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/SelectExportProfile.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Export/SelectExportProfile.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Import/DisplayAnalyzedResult.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Import/DisplayAnalyzedResult.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Import/DisplayAnalyzedResult.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Import/Importprofiles.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Import/Importprofiles.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Import/Importprofiles.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/FileDropOverlay.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/FileDropOverlay.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/FileDropOverlay.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/FileInput.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/FileInput.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/FileInput.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/TextField.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/TextField.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Inputs/TextField.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Layouts/MainLayout.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Layouts/MainLayout.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Layouts/MainLayout.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Layouts/MainLayoutWithoutMenu.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Layouts/MainLayoutWithoutMenu.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Layouts/MainLayoutWithoutMenu.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Record/AddTrack.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Record/AddTrack.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Record/AddTrack.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Record/ControlRecording.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Record/ControlRecording.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/Record/ControlRecording.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/ArtistColumn.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TitleColumn.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TrackList.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TrackList.razor (96%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TrackList.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TrackListControlButtons.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TrackListControlButtons.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/TrackList/TrackListControlButtons.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/Validation/Alert.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeFull.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeFull.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeFull.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeImport.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeImport.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeImport.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeRecord.de.resx (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeRecord.razor (100%) rename AudioCuesheetEditor/{Shared => Components}/ViewModes/ViewModeRecord.resx (100%) diff --git a/.editorconfig b/.editorconfig index f238a3e1..0dc31054 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,8 +16,6 @@ indent_size = 4 tab_width = 4 #TODO: Enable all of these -dotnet_diagnostic.CA1051.severity = suggestion -dotnet_diagnostic.CA1716.severity = suggestion dotnet_diagnostic.CA2201.severity = suggestion # Organize usings diff --git a/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs b/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs index 836b8c96..95eb0794 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/PlaywrightTestBase.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -21,10 +21,11 @@ namespace AudioCuesheetEditor.End2EndTests.Tests; public abstract class PlaywrightTestBase : PageTest { IBrowserContext _testContextInstance = null!; - protected IPage TestPage = null!; protected virtual string? DeviceName => null; + protected IPage TestPage { get; private set; } = default!; + [TestInitialize] public async Task TestInitializeAsync() { @@ -71,4 +72,4 @@ await _testContextInstance.Tracing.StopAsync(new() }); await _testContextInstance.CloseAsync(); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs index 477976a2..f84fd62d 100644 --- a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/AudiofileTests.cs @@ -80,13 +80,13 @@ public void Validate_TracksOverlapping_ReturnsValidationStatusError() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 45) + Finish = new TimeSpan(0, 3, 45) }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 42), - End = new TimeSpan(0, 6, 32) + Finish = new TimeSpan(0, 6, 32) }; var audiofile = new Audiofile() { diff --git a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs index 410b6976..947251fc 100644 --- a/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs +++ b/AudioCuesheetEditor.Tests/Model/AudioCuesheet/TrackTests.cs @@ -76,10 +76,10 @@ public void Validate_InvalidEnd_ReturnsValidationStatusError() var track = new Track { Begin = new TimeSpan(0, 2, 32), - End = new TimeSpan(0, 1, 15) + Finish = new TimeSpan(0, 1, 15) }; // Act - var endValidationResult = track.Validate(nameof(Track.End)); + var endValidationResult = track.Validate(nameof(Track.Finish)); // Assert Assert.AreEqual(ValidationStatus.Error, endValidationResult.Status); } @@ -91,7 +91,7 @@ public void Validate_InvalidBegin_ReturnsValidationStatusError() var track = new Track { Begin = new TimeSpan(0, 4, 53), - End = new TimeSpan(0, 3, 15) + Finish = new TimeSpan(0, 3, 15) }; // Act var endValidationResult = track.Validate(nameof(Track.Begin)); diff --git a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs index ab4a253e..d02098cc 100644 --- a/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs +++ b/AudioCuesheetEditor.Tests/Model/Entity/ValidateableTests.cs @@ -37,11 +37,11 @@ public int? TestProperty2 OnValidateablePropertyChanged(); } } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(TestProperty): validationStatus = ValidationStatus.Success; diff --git a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs index 6b262d4e..0c4fb921 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs @@ -62,7 +62,7 @@ public void GenerateFile_WithoutSections_GeneratesOneFile() } track.Flags = flags; begin = begin.Add(new TimeSpan(0, i, i)); - track.End = begin; + track.Finish = begin; track.Cuesheet = cuesheet; tracks.Add(track); } @@ -104,7 +104,7 @@ public void ImportFile_ValidProjectfile_ShouldImportFile() Assert.Contains(Flag.DCP, cuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); Assert.Contains(Flag.FourCH, cuesheet.Audiofiles.First().Tracks.ElementAt(3).Flags); Assert.AreEqual("Artist 10", cuesheet.Audiofiles.Last().Tracks.Last().Artist); - Assert.AreEqual(new TimeSpan(0, 55, 55), cuesheet.Audiofiles.Last().Tracks.Last().End); + Assert.AreEqual(new TimeSpan(0, 55, 55), cuesheet.Audiofiles.Last().Tracks.Last().Finish); Assert.AreEqual((ushort)10, cuesheet.Audiofiles.Last().Tracks.Last().Position); } } diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs index caa85eaa..6cc0c06c 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs @@ -69,7 +69,7 @@ public AudiofileManagerTests() } if (track.Begin.HasValue) { - return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); + return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Finish).LastOrDefault(x => x.Finish <= track.Begin && Equals(x, track) == false); } return null; }); @@ -167,12 +167,12 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() { Position = 1, Begin = TimeSpan.FromSeconds(0), - End = TimeSpan.FromSeconds(30) + Finish = TimeSpan.FromSeconds(30) }; var track2 = new Track() { Position = 2, - Begin = track1.End + Begin = track1.Finish }; var audiofile = new Audiofile() { @@ -194,7 +194,7 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() Assert.AreEqual(filename, audiofile.Name); Assert.AreEqual(objectUrl, audiofile.ObjectURL); Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); - Assert.AreEqual(TimeSpan.FromSeconds(90), track2.End); + Assert.AreEqual(TimeSpan.FromSeconds(90), track2.Finish); Assert.AreEqual(1, audiofileChangedFired); _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); _fileInputManager.Verify(f => f.GetObjectUrlAsync(browserFile.Object), Times.Once); @@ -332,12 +332,12 @@ public void SetProperty_DurationChanged_SetsLastTrackEndAlso() { Position = 1, Begin = TimeSpan.FromSeconds(0), - End = TimeSpan.FromSeconds(30) + Finish = TimeSpan.FromSeconds(30) }; var track2 = new Track() { Position = 2, - Begin = track1.End + Begin = track1.Finish }; var audiofile = new Audiofile { @@ -358,7 +358,7 @@ public void SetProperty_DurationChanged_SetsLastTrackEndAlso() // Assert Assert.AreEqual(duration, audiofile.Duration); - Assert.AreEqual(duration, track2.End); + Assert.AreEqual(duration, track2.Finish); Assert.AreEqual(1, audiofileChangedFired); } @@ -390,7 +390,7 @@ public void AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties() Assert.AreEqual(1, audiofileChangedFired); Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); - Assert.AreEqual(duration, audiofile.Tracks.First().End); + Assert.AreEqual(duration, audiofile.Tracks.First().Finish); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == audiofile && ((ICollection<Track>)y.TraceableChange.PreviousValue!).Count == 0 && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); } @@ -405,7 +405,7 @@ public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackPropertie { Position = 1, Begin = TimeSpan.Zero, - End = duration, + Finish = duration, IsLinkedToPreviousTrack = true } }; @@ -435,8 +435,8 @@ public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackPropertie // Assert Assert.HasCount(2, audiofile.Tracks); Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); - Assert.IsFalse(audiofile.Tracks.First().End.HasValue); - Assert.AreEqual(duration, audiofile.Tracks.Last().End); + Assert.IsFalse(audiofile.Tracks.First().Finish.HasValue); + Assert.AreEqual(duration, audiofile.Tracks.Last().Finish); Assert.AreEqual(cuesheet, track.Cuesheet); Assert.AreEqual(audiofile, track.Audiofile); Assert.AreEqual(1, audiofileChangedFired); @@ -487,7 +487,7 @@ public void AddTrack_DuringRecording_AddsNewTrackWithCalulatedTrackProperties() Assert.AreEqual(1, audiofileChangedFired); Assert.HasCount(2, audiofile.Tracks); Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); - Assert.IsNotNull(audiofile.Tracks.First().End); + Assert.IsNotNull(audiofile.Tracks.First().Finish); Assert.IsNotNull(audiofile.Tracks.Last().Begin); Assert.AreEqual(cuesheet, track.Cuesheet); Assert.AreEqual(audiofile, track.Audiofile); @@ -524,7 +524,7 @@ public void AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackPropertie Assert.HasCount(1, audiofile.Tracks); Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); - Assert.AreEqual(duration, audiofile.Tracks.First().End); + Assert.AreEqual(duration, audiofile.Tracks.First().Finish); Assert.AreEqual(importCuesheet, track.Cuesheet); Assert.AreEqual(audiofile, track.Audiofile); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == audiofile && ((ICollection<Track>) y.TraceableChange.PreviousValue!).Count == 0 && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); @@ -540,28 +540,28 @@ public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainin { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), + Finish = new TimeSpan(0, 3, 12), IsLinkedToPreviousTrack = true }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), + Finish = new TimeSpan(0, 7, 34), IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var track4 = new Track() { Position = 4, Begin = new TimeSpan(0, 10, 4), - End = new TimeSpan(0, 14, 54), + Finish = new TimeSpan(0, 14, 54), IsLinkedToPreviousTrack = true }; var track5 = new Track() @@ -604,11 +604,11 @@ public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainin Assert.AreEqual(1, audiofileChangedFired); Assert.AreEqual((ushort)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1.End, track3.Begin); + Assert.AreEqual(track1.Finish, track3.Begin); Assert.AreEqual((ushort)2, track3.Position); - Assert.AreEqual(track5.Begin, track3.End); + Assert.AreEqual(track5.Begin, track3.Finish); Assert.AreEqual((ushort)3, track5.Position); - Assert.AreEqual(duration, track5.End); + Assert.AreEqual(duration, track5.Finish); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); @@ -622,28 +622,28 @@ public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrack { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), + Finish = new TimeSpan(0, 3, 12), IsLinkedToPreviousTrack = true }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), + Finish = new TimeSpan(0, 7, 34), IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var track4 = new Track() { Position = 4, Begin = new TimeSpan(0, 10, 4), - End = new TimeSpan(0, 14, 54), + Finish = new TimeSpan(0, 14, 54), IsLinkedToPreviousTrack = true }; var track5 = new Track() @@ -690,12 +690,12 @@ public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrack Assert.Contains(track5, audiofile.Tracks); Assert.AreEqual((ushort)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1.End, track3.Begin); + Assert.AreEqual(track1.Finish, track3.Begin); Assert.AreEqual((ushort)2, track3.Position); - Assert.AreEqual(track5.Begin, track3.End); + Assert.AreEqual(track5.Begin, track3.Finish); Assert.AreEqual((ushort)3, track5.Position); Assert.AreEqual(1, audiofileChangedFired); - Assert.AreEqual(duration, track5.End); + Assert.AreEqual(duration, track5.Finish); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs index 0d6bd244..ca766042 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/CuesheetManagerTests.cs @@ -241,7 +241,7 @@ public void StopRecording_WithActiveRecording_StopsRecordAndSetsTrackDetails() new() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }, new() { Position = 2, @@ -263,7 +263,7 @@ public void StopRecording_WithActiveRecording_StopsRecordAndSetsTrackDetails() Assert.IsFalse(cuesheet.IsRecording); Assert.IsNull(cuesheet.RecordingStart); Assert.IsTrue(isRecordingChanged); - Assert.IsNotNull(cuesheet.Audiofiles.First().Tracks.Last().End); + Assert.IsNotNull(cuesheet.Audiofiles.First().Tracks.Last().Finish); } [TestMethod] @@ -278,7 +278,7 @@ public void StopRecording_WithoutActiveRecording_ChangesNothing() new() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }, new() { Position = 2, @@ -298,7 +298,7 @@ public void StopRecording_WithoutActiveRecording_ChangesNothing() _cuesheetManager.StopRecording(); // Assert Assert.IsFalse(isRecordingChanged); - Assert.IsNull(cuesheet.Audiofiles.First().Tracks.Last().End); + Assert.IsNull(cuesheet.Audiofiles.First().Tracks.Last().Finish); } [TestMethod] @@ -309,21 +309,21 @@ public void IsMoveUpPossible_TracksAbove_ReturnsTrue() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), + Finish = new TimeSpan(0, 3, 12), IsLinkedToPreviousTrack = true }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), + Finish = new TimeSpan(0, 7, 34), IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -351,21 +351,21 @@ public void IsMoveUpPossible_NoTracksAbove_ReturnsFalse() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), + Finish = new TimeSpan(0, 3, 12), IsLinkedToPreviousTrack = true }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), + Finish = new TimeSpan(0, 7, 34), IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -449,21 +449,21 @@ public void IsMoveDownPossible_TracksBelow_ReturnsTrue() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), + Finish = new TimeSpan(0, 3, 12), IsLinkedToPreviousTrack = true }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), + Finish = new TimeSpan(0, 7, 34), IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -492,21 +492,21 @@ public void IsMoveDownPossible_NoTracksBelow_ReturnsFalse() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12), + Finish = new TimeSpan(0, 3, 12), IsLinkedToPreviousTrack = true }; var track2 = new Track() { Position = 2, Begin = new TimeSpan(0, 3, 12), - End = new TimeSpan(0, 7, 34), + Finish = new TimeSpan(0, 7, 34), IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = new TimeSpan(0, 7, 34), - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -591,7 +591,7 @@ public void MoveUp_TracksSwitchingAudiofile_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -599,14 +599,14 @@ public void MoveUp_TracksSwitchingAudiofile_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -633,12 +633,12 @@ public void MoveUp_TracksSwitchingAudiofile_ReturnsSuccess() Assert.IsTrue(result.IsSuccess); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual(cuesheet.Audiofiles.First(), track1.Audiofile); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); Assert.AreEqual(cuesheet.Audiofiles.First(), track2.Audiofile); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); Assert.AreEqual(cuesheet.Audiofiles.First(), track3.Audiofile); @@ -656,7 +656,7 @@ public void MoveUp_TracksAbove_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -664,14 +664,14 @@ public void MoveUp_TracksAbove_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -695,10 +695,10 @@ public void MoveUp_TracksAbove_ReturnsSuccess() Assert.IsTrue(result.IsSuccess); Assert.AreEqual((ushort?)1, track2.Position); Assert.AreEqual(TimeSpan.Zero, track2.Begin); - Assert.AreEqual(track1End, track2.End); + Assert.AreEqual(track1End, track2.Finish); Assert.AreEqual((ushort?)2, track3.Position); Assert.AreEqual(track1End, track3.Begin); - Assert.AreEqual(track2End, track3.End); + Assert.AreEqual(track2End, track3.Finish); Assert.AreEqual((ushort?)3, track1.Position); Assert.AreEqual(track2End, track1.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -715,7 +715,7 @@ public void MoveUp_Move2Positions_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -723,7 +723,7 @@ public void MoveUp_Move2Positions_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3End = new TimeSpan(0, 10, 4); @@ -731,14 +731,14 @@ public void MoveUp_Move2Positions_ReturnsSuccess() { Position = 3, Begin = track2End, - End = track3End, + Finish = track3End, IsLinkedToPreviousTrack = true }; var track4 = new Track() { Position = 4, Begin = track3End, - End = new TimeSpan(0, 13, 45), + Finish = new TimeSpan(0, 13, 45), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -764,10 +764,10 @@ public void MoveUp_Move2Positions_ReturnsSuccess() Assert.IsTrue(result.IsSuccess); Assert.AreEqual((ushort?)1, track2.Position); Assert.AreEqual(TimeSpan.Zero, track2.Begin); - Assert.AreEqual(track1End, track2.End); + Assert.AreEqual(track1End, track2.Finish); Assert.AreEqual((ushort?)2, track3.Position); Assert.AreEqual(track1End, track3.Begin); - Assert.AreEqual(track2End, track3.End); + Assert.AreEqual(track2End, track3.Finish); Assert.AreEqual((ushort?)3, track1.Position); Assert.AreEqual(track2End, track1.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -784,7 +784,7 @@ public void MoveUp_NoTracksAbove_ReturnsFailure() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -792,14 +792,14 @@ public void MoveUp_NoTracksAbove_ReturnsFailure() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -824,10 +824,10 @@ public void MoveUp_NoTracksAbove_ReturnsFailure() Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -844,7 +844,7 @@ public void MoveUp_NoTracksSelected_ReturnsFailure() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -852,14 +852,14 @@ public void MoveUp_NoTracksSelected_ReturnsFailure() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -884,10 +884,10 @@ public void MoveUp_NoTracksSelected_ReturnsFailure() Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -904,7 +904,7 @@ public void MoveUp_AudiofilesAbove_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -912,14 +912,14 @@ public void MoveUp_AudiofilesAbove_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var file1 = new Audiofile("Audiofile 1", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM); @@ -950,11 +950,11 @@ public void MoveUp_AudiofilesAbove_ReturnsSuccess() Assert.IsEmpty(file1.Tracks); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual(file2, track1.Audiofile); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual(file2, track2.Audiofile); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); @@ -1014,7 +1014,7 @@ public void MoveDown_TracksSwitchingAudiofile_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -1022,14 +1022,14 @@ public void MoveDown_TracksSwitchingAudiofile_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -1056,11 +1056,11 @@ public void MoveDown_TracksSwitchingAudiofile_ReturnsSuccess() Assert.IsTrue(result.IsSuccess); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual(cuesheet.Audiofiles.Last(), track1.Audiofile); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual(cuesheet.Audiofiles.Last(), track2.Audiofile); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); @@ -1079,7 +1079,7 @@ public void MoveDown_TracksBelow_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -1087,14 +1087,14 @@ public void MoveDown_TracksBelow_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -1118,10 +1118,10 @@ public void MoveDown_TracksBelow_ReturnsSuccess() Assert.IsTrue(result.IsSuccess); Assert.AreEqual((ushort?)1, track3.Position); Assert.AreEqual(TimeSpan.Zero, track3.Begin); - Assert.AreEqual(track1End, track3.End); + Assert.AreEqual(track1End, track3.Finish); Assert.AreEqual((ushort?)2, track1.Position); Assert.AreEqual(track1End, track1.Begin); - Assert.AreEqual(track2End, track1.End); + Assert.AreEqual(track2End, track1.Finish); Assert.AreEqual((ushort?)3, track2.Position); Assert.AreEqual(track2End, track2.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -1138,7 +1138,7 @@ public void MoveDown_Move2Positions_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -1146,7 +1146,7 @@ public void MoveDown_Move2Positions_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3End = new TimeSpan(0, 10, 4); @@ -1154,14 +1154,14 @@ public void MoveDown_Move2Positions_ReturnsSuccess() { Position = 3, Begin = track2End, - End = track3End, + Finish = track3End, IsLinkedToPreviousTrack = true }; var track4 = new Track() { Position = 4, Begin = track3End, - End = new TimeSpan(0, 13, 45), + Finish = new TimeSpan(0, 13, 45), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -1187,13 +1187,13 @@ public void MoveDown_Move2Positions_ReturnsSuccess() Assert.IsTrue(result.IsSuccess); Assert.AreEqual((ushort?)1, track3.Position); Assert.AreEqual(TimeSpan.Zero, track3.Begin); - Assert.AreEqual(track1End, track3.End); + Assert.AreEqual(track1End, track3.Finish); Assert.AreEqual((ushort?)2, track4.Position); Assert.AreEqual(track1End, track4.Begin); - Assert.AreEqual(track2End, track4.End); + Assert.AreEqual(track2End, track4.Finish); Assert.AreEqual((ushort?)3, track1.Position); Assert.AreEqual(track2End, track1.Begin); - Assert.AreEqual(track3End, track1.End); + Assert.AreEqual(track3End, track1.Finish); Assert.AreEqual((ushort?)4, track2.Position); Assert.AreEqual(track3End, track2.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -1210,7 +1210,7 @@ public void MoveDown_NoTracksBelow_ReturnsFailure() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -1218,14 +1218,14 @@ public void MoveDown_NoTracksBelow_ReturnsFailure() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -1250,10 +1250,10 @@ public void MoveDown_NoTracksBelow_ReturnsFailure() Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles.First() && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -1270,7 +1270,7 @@ public void MoveDown_NoTracksSelected_ReturnsFailure() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -1278,14 +1278,14 @@ public void MoveDown_NoTracksSelected_ReturnsFailure() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -1310,10 +1310,10 @@ public void MoveDown_NoTracksSelected_ReturnsFailure() Assert.AreEqual(ErrorType.NotPossible, result.FailureDetails!.Type); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == cuesheet.Audiofiles && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Never); @@ -1330,7 +1330,7 @@ public void MoveDown_AudiofilesBelow_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = track1End, + Finish = track1End, IsLinkedToPreviousTrack = true }; var track2End = new TimeSpan(0, 7, 34); @@ -1338,14 +1338,14 @@ public void MoveDown_AudiofilesBelow_ReturnsSuccess() { Position = 2, Begin = track1End, - End = track2End, + Finish = track2End, IsLinkedToPreviousTrack = true }; var track3 = new Track() { Position = 3, Begin = track2End, - End = new TimeSpan(0, 10, 4), + Finish = new TimeSpan(0, 10, 4), IsLinkedToPreviousTrack = true }; var file1 = new Audiofile("Audiofile 1", $"{Guid.NewGuid()}", Audiofile.AudioCodecWEBM); @@ -1375,11 +1375,11 @@ public void MoveDown_AudiofilesBelow_ReturnsSuccess() Assert.AreSequenceEqual(new List<Audiofile>([file3, file1, file2]), cuesheet.Audiofiles); Assert.AreEqual((ushort?)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); - Assert.AreEqual(track1End, track1.End); + Assert.AreEqual(track1End, track1.Finish); Assert.AreEqual(file2, track1.Audiofile); Assert.AreEqual((ushort?)2, track2.Position); Assert.AreEqual(track1End, track2.Begin); - Assert.AreEqual(track2End, track2.End); + Assert.AreEqual(track2End, track2.Finish); Assert.AreEqual(file2, track2.Audiofile); Assert.AreEqual((ushort?)3, track3.Position); Assert.AreEqual(track2End, track3.Begin); diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs index 46064005..829bd2a4 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/TrackManagerTests.cs @@ -74,7 +74,7 @@ public void Clone_ImportTrack_ReturnsTrackClone() Artist = "Artist 1", Title = "Title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 2, 54), + Finish = new TimeSpan(0, 2, 54), IsLinkedToPreviousTrack = true, Position = 1, PostGap = new TimeSpan(0, 0, 2), @@ -88,7 +88,7 @@ public void Clone_ImportTrack_ReturnsTrackClone() Assert.AreEqual(importTrack.Artist, track.Artist); Assert.AreEqual(importTrack.Title, track.Title); Assert.AreEqual(importTrack.Begin, track.Begin); - Assert.AreEqual(importTrack.End, track.End); + Assert.AreEqual(importTrack.Finish, track.Finish); Assert.AreEqual(importTrack.IsLinkedToPreviousTrack, track.IsLinkedToPreviousTrack); Assert.AreEqual(importTrack.Position, track.Position); Assert.AreEqual(importTrack.PostGap, track.PostGap); @@ -120,7 +120,7 @@ public void Clone_ImportTrackWithLength_ReturnsTrackCloneWithLengthSet() Assert.AreEqual(importTrack.Artist, track.Artist); Assert.AreEqual(importTrack.Title, track.Title); Assert.AreEqual(importTrack.Begin, track.Begin); - Assert.AreEqual(importTrack.Length, track.End); + Assert.AreEqual(importTrack.Length, track.Finish); Assert.AreEqual(importTrack.IsLinkedToPreviousTrack, track.IsLinkedToPreviousTrack); Assert.AreEqual(importTrack.Position, track.Position); Assert.AreEqual(importTrack.PostGap, track.PostGap); @@ -138,7 +138,7 @@ public void CopyValues_AllDefaultValues_CopiesAllValues() Artist = "Artist 1", Title = "Title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 2, 54), + Finish = new TimeSpan(0, 2, 54), IsLinkedToPreviousTrack = true, Position = 1, PostGap = new TimeSpan(0, 0, 2), @@ -152,7 +152,7 @@ public void CopyValues_AllDefaultValues_CopiesAllValues() Assert.AreEqual(source.Artist, target.Artist); Assert.AreEqual(source.Title, target.Title); Assert.AreEqual(source.Begin, target.Begin); - Assert.AreEqual(source.End, target.End); + Assert.AreEqual(source.Finish, target.Finish); Assert.AreEqual(source.IsLinkedToPreviousTrack, target.IsLinkedToPreviousTrack); Assert.AreEqual(source.Position, target.Position); Assert.AreEqual(source.PostGap, target.PostGap); @@ -171,7 +171,7 @@ public void CopyValues_ValuesSet_CopiesOnlySetValues() Artist = "Artist 1", Title = "Title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 2, 54), + Finish = new TimeSpan(0, 2, 54), IsLinkedToPreviousTrack = true, Position = 1, PostGap = new TimeSpan(0, 0, 2), @@ -185,7 +185,7 @@ public void CopyValues_ValuesSet_CopiesOnlySetValues() Assert.AreEqual(source.Artist, target.Artist); Assert.AreEqual(source.Title, target.Title); Assert.AreNotEqual(source.Begin, target.Begin); - Assert.AreEqual(source.End, target.End); + Assert.AreEqual(source.Finish, target.Finish); Assert.AreEqual(source.IsLinkedToPreviousTrack, target.IsLinkedToPreviousTrack); Assert.AreEqual(source.Position, target.Position); Assert.AreNotEqual(source.PostGap, target.PostGap); @@ -295,12 +295,12 @@ public void GetPreviousLinkedTrack_WithBegin_ReturnsTrack() IsLinkedToPreviousTrack = true, Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 6, 37) + Finish = new TimeSpan(0, 6, 37) }; var track2 = new Track() { IsLinkedToPreviousTrack = true, - Begin = track1.End + Begin = track1.Finish }; var cuesheet = new Cuesheet() { @@ -419,14 +419,14 @@ public void GetNextLinkedTrack_WithBegin_ReturnsTrack() { IsLinkedToPreviousTrack = true, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 8, 32) + Finish = new TimeSpan(0, 8, 32) }; var track2 = new Track() { IsLinkedToPreviousTrack = true, Position = 2, - Begin = track1.End, - End = new TimeSpan(0, 13, 54) + Begin = track1.Finish, + Finish = new TimeSpan(0, 13, 54) }; var cuesheet = new Cuesheet() { @@ -454,7 +454,7 @@ public void GetNextLinkedTrack_OnlyOneTrack_ReturnsNull() { IsLinkedToPreviousTrack = true, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 8, 32) + Finish = new TimeSpan(0, 8, 32) }; var cuesheet = new Cuesheet(); track1.Cuesheet = cuesheet; @@ -473,21 +473,21 @@ public void GetNextLinkedTrack_MultiplePositions_ReturnsTrack() Position = 1, IsLinkedToPreviousTrack = true, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 8, 32) + Finish = new TimeSpan(0, 8, 32) }; var track2 = new Track() { IsLinkedToPreviousTrack = true, Position = 2, - Begin = track1.End, - End = new TimeSpan(0, 13, 54) + Begin = track1.Finish, + Finish = new TimeSpan(0, 13, 54) }; var track3 = new Track() { IsLinkedToPreviousTrack = true, Position = 2, - Begin = track2.End, - End = new TimeSpan(0, 17, 32) + Begin = track2.Finish, + Finish = new TimeSpan(0, 17, 32) }; var cuesheet = new Cuesheet() { @@ -516,11 +516,11 @@ public void GetNextLinkedTrack_WithPosition_ReturnsTrack() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }; var track2 = new Track() { - Begin = track1.End, + Begin = track1.Finish, IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -549,7 +549,7 @@ public void RecalculateLinkedTracksProperties_TrackHasNoBegin_SetsBegin() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }; var track2 = new Track() { @@ -570,7 +570,7 @@ public void RecalculateLinkedTracksProperties_TrackHasNoBegin_SetsBegin() // Act _trackManager.RecalculateLinkedTracksProperties(track2); // Assert - Assert.AreEqual(track1.End, track2.Begin); + Assert.AreEqual(track1.Finish, track2.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Begin))), Times.Once); } @@ -582,12 +582,12 @@ public void RecalculateLinkedTracksProperties_TrackHasNoPosition_SetsPosition() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }; var track2 = new Track() { IsLinkedToPreviousTrack = true, - Begin = track1.End + Begin = track1.Finish }; var cuesheet = new Cuesheet() { @@ -636,8 +636,8 @@ public void RecalculateLinkedTracksProperties_PreviousTrackHasNoEnd_SetsEnd() // Act _trackManager.RecalculateLinkedTracksProperties(track2); // Assert - Assert.AreEqual(track2.Begin, track1.End); - _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == track1 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.End))), Times.Once); + Assert.AreEqual(track2.Begin, track1.Finish); + _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == track1 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Finish))), Times.Once); } [TestMethod] @@ -648,11 +648,11 @@ public void RecalculateLinkedTracksProperties_NextTrackNoPosition_SetsPosition() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }; var track2 = new Track() { - Begin = track1.End, + Begin = track1.Finish, IsLinkedToPreviousTrack = true }; var cuesheet = new Cuesheet() @@ -681,7 +681,7 @@ public void RecalculateLinkedTracksProperties_NextTrackNoBegin_SetsBegin() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 12) + Finish = new TimeSpan(0, 3, 12) }; var track2 = new Track() { @@ -702,7 +702,7 @@ public void RecalculateLinkedTracksProperties_NextTrackNoBegin_SetsBegin() // Act _trackManager.RecalculateLinkedTracksProperties(track1); // Assert - Assert.AreEqual(track1.End, track2.Begin); + Assert.AreEqual(track1.Finish, track2.Begin); _traceChangeManager.Verify(x => x.AddChange(It.Is<TracedChange>(y => y.TraceableObject == track2 && y.TraceableChange.PreviousValue == null && y.TraceableChange.PropertyName == nameof(Track.Begin))), Times.Once); } } diff --git a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs index 0b2d5e34..aedcce11 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/CuesheetExportServiceTests.cs @@ -119,14 +119,14 @@ public void CanGenerateExportfile_InvalidTrackEnd_ReturnsValidationMessage() }; _ = _sessionStateContainerMock.SetupProperty(x => x.Cuesheet, cuesheet); _ = _localizerMock.Setup(x => x["{0} has no value!", It.IsAny<object[]>()]).Returns((string format, object[] args) => new LocalizedString(format, string.Format(CultureInfo.CurrentCulture, format, args))); - _ = _localizerMock.Setup(x => x[nameof(Track.End)]).Returns(new LocalizedString(nameof(Track.End), nameof(Track.End))); + _ = _localizerMock.Setup(x => x[nameof(Track.Finish)]).Returns(new LocalizedString(nameof(Track.Finish), nameof(Track.Finish))); // Act var result = _cuesheetExportService.CanGenerateExportfile("test.cue"); // Assert Assert.IsFalse(result.IsSuccess); - Assert.IsTrue(result.FailureDetails?.Message.Contains($"{nameof(Track.End)} has no value!")); + Assert.IsTrue(result.FailureDetails?.Message.Contains($"{nameof(Track.Finish)} has no value!")); } [TestMethod] @@ -149,7 +149,7 @@ public void CanGenerateExportfiles_ValidExtension_ReturnsSuccess() { Position = 1, Begin = TimeSpan.Zero, - End = new TimeSpan(0, 3, 43) + Finish = new TimeSpan(0, 3, 43) } ] } @@ -175,15 +175,15 @@ public void GenerateExportfiles_SingleAudiofile_ReturnsExportFile() Artist = "Test artist 1", Title = "Test title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), + Finish = new TimeSpan(0, 4, 12), Position = 1 }; var track2 = new Track() { Artist = "Test artist 2", Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), + Begin = track1.Finish, + Finish = new TimeSpan(0, 8, 32), Position = 2 }; var cuesheet = new Cuesheet() @@ -236,31 +236,31 @@ public void GenerateExportfiles_MultipleAudiofiles_ReturnsExportFile() Artist = "Test artist 1", Title = "Test title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), + Finish = new TimeSpan(0, 4, 12), Position = 1 }; var track2 = new Track() { Artist = "Test artist 2", Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), + Begin = track1.Finish, + Finish = new TimeSpan(0, 8, 32), Position = 2 }; var track3 = new Track() { Artist = "Test artist 3", Title = "Test title 3", - Begin = track2.End, - End = new TimeSpan(0, 12, 43), + Begin = track2.Finish, + Finish = new TimeSpan(0, 12, 43), Position = 3 }; var track4 = new Track() { Artist = "Test artist 4", Title = "Test title 4", - Begin = track3.End, - End = new TimeSpan(0, 15, 54), + Begin = track3.Finish, + Finish = new TimeSpan(0, 15, 54), Position = 4 }; var cuesheet = new Cuesheet() diff --git a/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs index 02fbd9f7..70981d20 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ExportfileGeneratorTests.cs @@ -57,15 +57,15 @@ public void GenerateExportFile_SeveralAudiofiles_ReturnsSuccess() Artist = "Test artist 1", Title = "Test title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), + Finish = new TimeSpan(0, 4, 12), Position = 1 }; var track2 = new Track() { Artist = "Test artist 2", Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), + Begin = track1.Finish, + Finish = new TimeSpan(0, 8, 32), Position = 2 }; var cuesheet = new Cuesheet() @@ -119,15 +119,15 @@ public void GenerateExportFile_EmptyExportprofile_ReturnsSuccess() Artist = "Test artist 1", Title = "Test title 1", Begin = TimeSpan.Zero, - End = new TimeSpan(0, 4, 12), + Finish = new TimeSpan(0, 4, 12), Position = 1 }; var track2 = new Track() { Artist = "Test artist 2", Title = "Test title 2", - Begin = track1.End, - End = new TimeSpan(0, 8, 32), + Begin = track1.Finish, + Finish = new TimeSpan(0, 8, 32), Position = 2 }; var cuesheet = new Cuesheet() diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index b2546c04..a103b0f4 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -85,7 +85,7 @@ public ImportManagerTests() } if (setEnd) { - TrackManager_SetValue(target, x => x.End, source.End, false); + TrackManager_SetValue(target, x => x.Finish, source.Finish, false); } if (setLength) { @@ -108,7 +108,7 @@ public ImportManagerTests() { var clone = new Track(); var setLength = true; - if (track.Begin.HasValue && track.End.HasValue) + if (track.Begin.HasValue && track.Finish.HasValue) { setLength = false; } @@ -167,7 +167,7 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() Artist = "Test Track Artist 1", Title = "Test Track Title 1", Begin = new TimeSpan(0, 3, 20), - End = new TimeSpan(0, 7, 43), + Finish = new TimeSpan(0, 7, 43), Flags = [Flag.DCP], Position = 1, PreGap = new TimeSpan(0, 0, 2), @@ -203,7 +203,7 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet() Assert.AreEqual(importAudiofile.Tracks.First().Artist, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Artist); Assert.AreEqual(importAudiofile.Tracks.First().Title, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Title); Assert.AreEqual(importAudiofile.Tracks.First().Begin, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Begin); - Assert.AreEqual(importAudiofile.Tracks.First().End, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().End); + Assert.AreEqual(importAudiofile.Tracks.First().Finish, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Finish); Assert.AreSequenceEqual([.. importAudiofile.Tracks.First().Flags], sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Flags.ToList(), SequenceOrder.InAnyOrder); Assert.AreEqual(importAudiofile.Tracks.First().Position, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().Position); Assert.AreEqual(importAudiofile.Tracks.First().PreGap, sessionStateContainerImportCuesheet.Audiofiles.First().Tracks.First().PreGap); @@ -403,7 +403,7 @@ public async Task ImportCuesheetAsync_WithImportCuesheetAvailable_ImportsCueshee { Artist = "Track Artist 1", Title = "Track Title 1", - End = new TimeSpan(0, 4, 23), + Finish = new TimeSpan(0, 4, 23), }; var track2 = new Track() { @@ -446,11 +446,11 @@ public async Task ImportCuesheetAsync_WithImportCuesheetAvailable_ImportsCueshee Assert.AreEqual(track1.Artist, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Artist); Assert.AreEqual(track1.Title, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Title); Assert.AreEqual(TimeSpan.Zero, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Begin); - Assert.AreEqual(track1.End, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().End); + Assert.AreEqual(track1.Finish, sessionStateContainerCuesheet.Audiofiles.First().Tracks.First().Finish); Assert.AreEqual(track2.Artist, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Artist); Assert.AreEqual(track2.Title, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Title); - Assert.AreEqual(track1.End, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Begin); - Assert.AreEqual(audiofileDuration, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().End); + Assert.AreEqual(track1.Finish, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Begin); + Assert.AreEqual(audiofileDuration, sessionStateContainerCuesheet.Audiofiles.First().Tracks.Last().Finish); _traceChangeManager.Verify(x => x.RemoveTracedChanges(It.IsAny<IEnumerable<object>>())); } diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs index 83c5eefc..c4e4dbdc 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs @@ -78,7 +78,7 @@ public async Task AnalyseAsync_SampleCuesheet_CreatesValidCuesheetAsync() Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Finish); Assert.IsTrue(importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).IsLinkedToPreviousTrack); } @@ -188,7 +188,7 @@ public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetA Assert.AreEqual((ushort)6, importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); Assert.AreEqual("Sample Artist 1", importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); Assert.AreEqual("Sample Title 1", importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + Assert.AreEqual(new TimeSpan(0, 5, 0), importfile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Finish); } [TestMethod()] @@ -229,7 +229,7 @@ public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCueshee Assert.AreEqual((ushort)6, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Finish); } [TestMethod()] @@ -322,7 +322,7 @@ public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesVal Assert.AreEqual((ushort)6, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(5).Position); Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Finish); } [TestMethod()] @@ -340,7 +340,7 @@ public async Task AnalyseAsync_CuesheetTracksOnly_CreatesValidCuesheetAsync() Sample Artist 9 - Sample Title 9 "; var profile = new Importprofile() { - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.Finish)}" }; var options = new ImportOptions { @@ -358,7 +358,7 @@ public async Task AnalyseAsync_CuesheetTracksOnly_CreatesValidCuesheetAsync() Assert.HasCount(9, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(1, 15, 54), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).End); + Assert.AreEqual(new TimeSpan(1, 15, 54), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(7).Finish); } [TestMethod()] @@ -368,7 +368,7 @@ public async Task AnalyseAsync_CuesheetBug213_CreatesValidCuesheetAsync() var fileContent = File.ReadAllText("Resources/Textimport_Bug_213.txt"); var profile = new Importprofile() { - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}", + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.Finish)}", TimeSpanFormat = new() { Scheme = $"{nameof(TimeSpanFormat.Minutes)}:{nameof(TimeSpanFormat.Seconds)}" } }; var options = new ImportOptions @@ -385,7 +385,7 @@ public async Task AnalyseAsync_CuesheetBug213_CreatesValidCuesheetAsync() Assert.IsNotNull(importFile.AnalyzedCuesheet); Assert.HasCount(1, importFile.AnalyzedCuesheet.Audiofiles); Assert.HasCount(4, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); - Assert.AreEqual(new TimeSpan(2, 3, 23), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).End); + Assert.AreEqual(new TimeSpan(2, 3, 23), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(3).Finish); } [TestMethod()] @@ -546,7 +546,7 @@ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentReco UseRegularExpression = true, SchemeCuesheet = @$"^(?<{nameof(ImportCuesheet.Artist)}>.+?)\s*-\s*(?<{nameof(ImportCuesheet.Title)}>.+?)\t+", SchemeAudiofiles = @$"\s+(?<{nameof(ImportAudiofile.Name)}>\S+.mp3)", - SchemeTracks = @$"(?<{nameof(ImportTrack.Artist)}>.+?)\s*-\s*(?<{nameof(ImportTrack.Title)}>.+?)\s+(?<{nameof(ImportTrack.End)}>\d{{2}}:\d{{2}}:\d{{2}})" + SchemeTracks = @$"(?<{nameof(ImportTrack.Artist)}>.+?)\s*-\s*(?<{nameof(ImportTrack.Title)}>.+?)\s+(?<{nameof(ImportTrack.Finish)}>\d{{2}}:\d{{2}}:\d{{2}})" }; var options = new ImportOptions { @@ -565,7 +565,7 @@ public async Task AnalyseAsync_CuesheetWithoutTracks_CreatesValidFileContentReco Assert.HasCount(8, importFile.AnalyzedCuesheet.Audiofiles.First().Tracks); Assert.AreEqual("Sample Artist 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Artist); Assert.AreEqual("Sample Title 1", importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Title); - Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).End); + Assert.AreEqual(new TimeSpan(0, 5, 0), importFile.AnalyzedCuesheet.Audiofiles.First().Tracks.ElementAt(0).Finish); var lines = importFile.FileContentRecognized.Split(Environment.NewLine); Assert.AreEqual($"{CuesheetConstants.GetMarkedText("Sample Artist 8")} - {CuesheetConstants.GetMarkedText("Sample Title 8")} {CuesheetConstants.GetMarkedText("01:15:54")}", lines.Last()); } @@ -576,7 +576,7 @@ public async Task AnalyseAsync_TextfileBug233_CreatesValidFileContentRecognizedA // Arrange var profile = new Importprofile() { - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.Finish)}" }; var fileContent = File.ReadAllText("Resources/Textimport_Bug_#233.txt"); var options = new ImportOptions diff --git a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs index 241b4840..fa93e55c 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs @@ -68,9 +68,9 @@ public async Task TimespanTextChanged_InvalidInput_SetsNull() var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); var track = new Track(); // Act - await parser.TimespanTextChanged(track, x => x.End, "not a time"); + await parser.TimespanTextChanged(track, x => x.Finish, "not a time"); // Assert - Assert.IsNull(track.End); + Assert.IsNull(track.Finish); } [TestMethod()] diff --git a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs index c610fe94..aea87b86 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs @@ -314,7 +314,7 @@ public void Reset_HasChanges_ResetsAllChanges() { Artist = "Track 1 Artist", Title = "Track 1 Title", - End = new TimeSpan(0, 2, 30) + Finish = new TimeSpan(0, 2, 30) }; var cuesheet = new Cuesheet() { @@ -325,7 +325,7 @@ public void Reset_HasChanges_ResetsAllChanges() ] }; _traceChangeManager.AddChange(new(cuesheet.Audiofiles.First(), new(Enumerable.Empty<Track>(), nameof(Audiofile.Tracks)))); - _traceChangeManager.AddChange(new(track, new(null, nameof(Track.End)))); + _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Finish)))); _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Title)))); _traceChangeManager.AddChange(new(track, new(null, nameof(Track.Artist)))); _traceChangeManager.Undo(); diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index 246c8e24..6a74a8bb 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -31,5 +31,9 @@ <ItemGroup> <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" /> </ItemGroup> + + <ItemGroup> + <Folder Include="Shared\" /> + </ItemGroup> </Project> diff --git a/AudioCuesheetEditor/Shared/AppBar.de.resx b/AudioCuesheetEditor/Components/AppBar.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/AppBar.de.resx rename to AudioCuesheetEditor/Components/AppBar.de.resx diff --git a/AudioCuesheetEditor/Shared/AppBar.razor b/AudioCuesheetEditor/Components/AppBar.razor similarity index 100% rename from AudioCuesheetEditor/Shared/AppBar.razor rename to AudioCuesheetEditor/Components/AppBar.razor diff --git a/AudioCuesheetEditor/Shared/AppBar.resx b/AudioCuesheetEditor/Components/AppBar.resx similarity index 100% rename from AudioCuesheetEditor/Shared/AppBar.resx rename to AudioCuesheetEditor/Components/AppBar.resx diff --git a/AudioCuesheetEditor/Shared/Audio/AudioPlayer.de.resx b/AudioCuesheetEditor/Components/Audio/AudioPlayer.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Audio/AudioPlayer.de.resx rename to AudioCuesheetEditor/Components/Audio/AudioPlayer.de.resx diff --git a/AudioCuesheetEditor/Shared/Audio/AudioPlayer.razor b/AudioCuesheetEditor/Components/Audio/AudioPlayer.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Audio/AudioPlayer.razor rename to AudioCuesheetEditor/Components/Audio/AudioPlayer.razor diff --git a/AudioCuesheetEditor/Shared/Audio/AudioPlayer.resx b/AudioCuesheetEditor/Components/Audio/AudioPlayer.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Audio/AudioPlayer.resx rename to AudioCuesheetEditor/Components/Audio/AudioPlayer.resx diff --git a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs b/AudioCuesheetEditor/Components/BaseLocalizedComponent.cs similarity index 96% rename from AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs rename to AudioCuesheetEditor/Components/BaseLocalizedComponent.cs index 458eb27a..be940f36 100644 --- a/AudioCuesheetEditor/Shared/BaseLocalizedComponent.cs +++ b/AudioCuesheetEditor/Components/BaseLocalizedComponent.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ using AudioCuesheetEditor.Services.UI; using Microsoft.AspNetCore.Components; -namespace AudioCuesheetEditor.Shared; +namespace AudioCuesheetEditor.Components; public abstract class BaseLocalizedComponent : ComponentBase, IDisposable { @@ -65,4 +65,4 @@ public void Dispose() Dispose(disposing: true); GC.SuppressFinalize(this); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx b/AudioCuesheetEditor/Components/Cuesheet/Audiofiles.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx rename to AudioCuesheetEditor/Components/Cuesheet/Audiofiles.de.resx diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Components/Cuesheet/Audiofiles.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor rename to AudioCuesheetEditor/Components/Cuesheet/Audiofiles.razor diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx b/AudioCuesheetEditor/Components/Cuesheet/Audiofiles.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx rename to AudioCuesheetEditor/Components/Cuesheet/Audiofiles.resx diff --git a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.de.resx b/AudioCuesheetEditor/Components/Cuesheet/CuesheetData.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.de.resx rename to AudioCuesheetEditor/Components/Cuesheet/CuesheetData.de.resx diff --git a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor b/AudioCuesheetEditor/Components/Cuesheet/CuesheetData.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.razor rename to AudioCuesheetEditor/Components/Cuesheet/CuesheetData.razor diff --git a/AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.resx b/AudioCuesheetEditor/Components/Cuesheet/CuesheetData.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Cuesheet/CuesheetData.resx rename to AudioCuesheetEditor/Components/Cuesheet/CuesheetData.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/ConfirmationDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/ConfirmationDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/ConfirmationDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/ConfirmationDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/ConfirmationDialog.razor b/AudioCuesheetEditor/Components/Dialogs/ConfirmationDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/ConfirmationDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/ConfirmationDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/ConfirmationDialog.resx b/AudioCuesheetEditor/Components/Dialogs/ConfirmationDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/ConfirmationDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/ConfirmationDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/DisplayHotkeysDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/DisplayHotkeysDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/DisplayHotkeysDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/DisplayHotkeysDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/DisplayHotkeysDialog.razor b/AudioCuesheetEditor/Components/Dialogs/DisplayHotkeysDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/DisplayHotkeysDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/DisplayHotkeysDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/DisplayHotkeysDialog.resx b/AudioCuesheetEditor/Components/Dialogs/DisplayHotkeysDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/DisplayHotkeysDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/DisplayHotkeysDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/DownloadProjectfileDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/DownloadProjectfileDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/DownloadProjectfileDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/DownloadProjectfileDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/DownloadProjectfileDialog.razor b/AudioCuesheetEditor/Components/Dialogs/DownloadProjectfileDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/DownloadProjectfileDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/DownloadProjectfileDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/DownloadProjectfileDialog.resx b/AudioCuesheetEditor/Components/Dialogs/DownloadProjectfileDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/DownloadProjectfileDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/DownloadProjectfileDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.de.resx b/AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.de.resx rename to AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.razor b/AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.razor similarity index 98% rename from AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.razor rename to AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.razor index 6995dc3e..986444f4 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.razor +++ b/AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.razor @@ -1,4 +1,4 @@ -<!-- +<!-- This file is part of AudioCuesheetEditor. AudioCuesheetEditor is free software: you can redistribute it and/or modify @@ -120,9 +120,9 @@ along with Foobar. If not, see </MudSelect> </MudItem> <MudItem xs="8" sm="9"> - <MudTextField Label="@_localizer["End"]" Variant="Variant.Outlined" Value="@EditedTrack.End.ToString()" ValueChanged="(string value) => _applicationOptionsTimeSpanParser.TimespanTextChanged<Track, TimeSpan?>(EditedTrack, x => x.End, value)" - Disabled="editModeTrackEnd == DynamicEditValue.DoNotChange" Error="!String.IsNullOrEmpty(GetValidationErrorMessage(editModeTrackEnd != DynamicEditValue.DoNotChange, EditedTrack, nameof(Track.End)))" - ErrorText="@GetValidationErrorMessage(editModeTrackEnd != DynamicEditValue.DoNotChange, EditedTrack, nameof(Track.End))" /> + <MudTextField Label="@_localizer["End"]" Variant="Variant.Outlined" Value="@EditedTrack.Finish.ToString()" ValueChanged="(string value) => _applicationOptionsTimeSpanParser.TimespanTextChanged<Track, TimeSpan?>(EditedTrack, x => x.Finish, value)" + Disabled="editModeTrackEnd == DynamicEditValue.DoNotChange" Error="!String.IsNullOrEmpty(GetValidationErrorMessage(editModeTrackEnd != DynamicEditValue.DoNotChange, EditedTrack, nameof(Track.Finish)))" + ErrorText="@GetValidationErrorMessage(editModeTrackEnd != DynamicEditValue.DoNotChange, EditedTrack, nameof(Track.Finish))" /> </MudItem> <MudFlexBreak /> <MudItem xs="4" sm="3"> diff --git a/AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.resx b/AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/EditMultipleTracksModal.resx rename to AudioCuesheetEditor/Components/Dialogs/EditMultipleTracksModal.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.de.resx b/AudioCuesheetEditor/Components/Dialogs/EditTrackModal.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.de.resx rename to AudioCuesheetEditor/Components/Dialogs/EditTrackModal.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.razor b/AudioCuesheetEditor/Components/Dialogs/EditTrackModal.razor similarity index 96% rename from AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.razor rename to AudioCuesheetEditor/Components/Dialogs/EditTrackModal.razor index e26e5b7c..edaf352b 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.razor +++ b/AudioCuesheetEditor/Components/Dialogs/EditTrackModal.razor @@ -1,4 +1,4 @@ -<!-- +<!-- This file is part of AudioCuesheetEditor. AudioCuesheetEditor is free software: you can redistribute it and/or modify @@ -71,8 +71,8 @@ along with Foobar. If not, see </MudAutocomplete> <MudTextField Label="@_localizer["Begin"]" Variant="Variant.Outlined" Value="@EditedTrack.Begin.ToString()" ValueChanged="(string value) => _applicationOptionsTimeSpanParser.TimespanTextChanged<Track, TimeSpan?>(EditedTrack, x => x.Begin, value)" Error="!String.IsNullOrEmpty(GetValidationErrorMessage(EditedTrack, nameof(Track.Begin)))" ErrorText="@GetValidationErrorMessage(EditedTrack, nameof(Track.Begin))" /> - <MudTextField Label="@_localizer["End"]" Variant="Variant.Outlined" Value="@EditedTrack.End.ToString()" ValueChanged="(string value) => _applicationOptionsTimeSpanParser.TimespanTextChanged<Track, TimeSpan?>(EditedTrack, x => x.End, value)" - Error="!String.IsNullOrEmpty(GetValidationErrorMessage(EditedTrack, nameof(Track.End)))" ErrorText="@GetValidationErrorMessage(EditedTrack, nameof(Track.End))" /> + <MudTextField Label="@_localizer["End"]" Variant="Variant.Outlined" Value="@EditedTrack.Finish.ToString()" ValueChanged="(string value) => _applicationOptionsTimeSpanParser.TimespanTextChanged<Track, TimeSpan?>(EditedTrack, x => x.Finish, value)" + Error="!String.IsNullOrEmpty(GetValidationErrorMessage(EditedTrack, nameof(Track.Finish)))" ErrorText="@GetValidationErrorMessage(EditedTrack, nameof(Track.Finish))" /> <MudTextField Label="@_localizer["Length"]" Variant="Variant.Outlined" Value="@EditedTrack.Length.ToString()" ValueChanged="(string value) => _applicationOptionsTimeSpanParser.TimespanTextChanged<Track, TimeSpan?>(EditedTrack, x => x.Length, value)" Error="!String.IsNullOrEmpty(GetValidationErrorMessage(EditedTrack, nameof(Track.Length)))" ErrorText="@GetValidationErrorMessage(EditedTrack, nameof(Track.Length))" /> <MudField Label="@_localizer["Flags"]" Variant="Variant.Outlined" Error="!String.IsNullOrEmpty(GetValidationErrorMessage(EditedTrack, nameof(Track.Flags)))" ErrorText="@GetValidationErrorMessage(EditedTrack, nameof(Track.Flags))"> diff --git a/AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.resx b/AudioCuesheetEditor/Components/Dialogs/EditTrackModal.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/EditTrackModal.resx rename to AudioCuesheetEditor/Components/Dialogs/EditTrackModal.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/GenerateCuesheetDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/GenerateCuesheetDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.razor b/AudioCuesheetEditor/Components/Dialogs/GenerateCuesheetDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/GenerateCuesheetDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.resx b/AudioCuesheetEditor/Components/Dialogs/GenerateCuesheetDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/GenerateCuesheetDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/GenerateCuesheetDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/GenerateExportDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/GenerateExportDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.razor b/AudioCuesheetEditor/Components/Dialogs/GenerateExportDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/GenerateExportDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.resx b/AudioCuesheetEditor/Components/Dialogs/GenerateExportDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/GenerateExportDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/GenerateExportDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/ImportAudiofilesDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/ImportAudiofilesDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Components/Dialogs/ImportAudiofilesDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/ImportAudiofilesDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx b/AudioCuesheetEditor/Components/Dialogs/ImportAudiofilesDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/ImportAudiofilesDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/InputDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/InputDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/InputDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/InputDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/InputDialog.razor b/AudioCuesheetEditor/Components/Dialogs/InputDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/InputDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/InputDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/InputDialog.resx b/AudioCuesheetEditor/Components/Dialogs/InputDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/InputDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/InputDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/LoadingDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/LoadingDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/LoadingDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/LoadingDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/LoadingDialog.razor b/AudioCuesheetEditor/Components/Dialogs/LoadingDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/LoadingDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/LoadingDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/LoadingDialog.resx b/AudioCuesheetEditor/Components/Dialogs/LoadingDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/LoadingDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/LoadingDialog.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/SettingsDialog.de.resx b/AudioCuesheetEditor/Components/Dialogs/SettingsDialog.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/SettingsDialog.de.resx rename to AudioCuesheetEditor/Components/Dialogs/SettingsDialog.de.resx diff --git a/AudioCuesheetEditor/Shared/Dialogs/SettingsDialog.razor b/AudioCuesheetEditor/Components/Dialogs/SettingsDialog.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/SettingsDialog.razor rename to AudioCuesheetEditor/Components/Dialogs/SettingsDialog.razor diff --git a/AudioCuesheetEditor/Shared/Dialogs/SettingsDialog.resx b/AudioCuesheetEditor/Components/Dialogs/SettingsDialog.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Dialogs/SettingsDialog.resx rename to AudioCuesheetEditor/Components/Dialogs/SettingsDialog.resx diff --git a/AudioCuesheetEditor/Shared/Export/DisplayExportfileContent.de.resx b/AudioCuesheetEditor/Components/Export/DisplayExportfileContent.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Export/DisplayExportfileContent.de.resx rename to AudioCuesheetEditor/Components/Export/DisplayExportfileContent.de.resx diff --git a/AudioCuesheetEditor/Shared/Export/DisplayExportfileContent.razor b/AudioCuesheetEditor/Components/Export/DisplayExportfileContent.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Export/DisplayExportfileContent.razor rename to AudioCuesheetEditor/Components/Export/DisplayExportfileContent.razor diff --git a/AudioCuesheetEditor/Shared/Export/DisplayExportfileContent.resx b/AudioCuesheetEditor/Components/Export/DisplayExportfileContent.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Export/DisplayExportfileContent.resx rename to AudioCuesheetEditor/Components/Export/DisplayExportfileContent.resx diff --git a/AudioCuesheetEditor/Shared/Export/EditExportProfile.de.resx b/AudioCuesheetEditor/Components/Export/EditExportProfile.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Export/EditExportProfile.de.resx rename to AudioCuesheetEditor/Components/Export/EditExportProfile.de.resx diff --git a/AudioCuesheetEditor/Shared/Export/EditExportProfile.razor b/AudioCuesheetEditor/Components/Export/EditExportProfile.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Export/EditExportProfile.razor rename to AudioCuesheetEditor/Components/Export/EditExportProfile.razor diff --git a/AudioCuesheetEditor/Shared/Export/EditExportProfile.resx b/AudioCuesheetEditor/Components/Export/EditExportProfile.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Export/EditExportProfile.resx rename to AudioCuesheetEditor/Components/Export/EditExportProfile.resx diff --git a/AudioCuesheetEditor/Shared/Export/SelectExportProfile.de.resx b/AudioCuesheetEditor/Components/Export/SelectExportProfile.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Export/SelectExportProfile.de.resx rename to AudioCuesheetEditor/Components/Export/SelectExportProfile.de.resx diff --git a/AudioCuesheetEditor/Shared/Export/SelectExportProfile.razor b/AudioCuesheetEditor/Components/Export/SelectExportProfile.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Export/SelectExportProfile.razor rename to AudioCuesheetEditor/Components/Export/SelectExportProfile.razor diff --git a/AudioCuesheetEditor/Shared/Export/SelectExportProfile.resx b/AudioCuesheetEditor/Components/Export/SelectExportProfile.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Export/SelectExportProfile.resx rename to AudioCuesheetEditor/Components/Export/SelectExportProfile.resx diff --git a/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.de.resx b/AudioCuesheetEditor/Components/Import/DisplayAnalyzedResult.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.de.resx rename to AudioCuesheetEditor/Components/Import/DisplayAnalyzedResult.de.resx diff --git a/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor b/AudioCuesheetEditor/Components/Import/DisplayAnalyzedResult.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor rename to AudioCuesheetEditor/Components/Import/DisplayAnalyzedResult.razor diff --git a/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.resx b/AudioCuesheetEditor/Components/Import/DisplayAnalyzedResult.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.resx rename to AudioCuesheetEditor/Components/Import/DisplayAnalyzedResult.resx diff --git a/AudioCuesheetEditor/Shared/Import/Importprofiles.de.resx b/AudioCuesheetEditor/Components/Import/Importprofiles.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Import/Importprofiles.de.resx rename to AudioCuesheetEditor/Components/Import/Importprofiles.de.resx diff --git a/AudioCuesheetEditor/Shared/Import/Importprofiles.razor b/AudioCuesheetEditor/Components/Import/Importprofiles.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Import/Importprofiles.razor rename to AudioCuesheetEditor/Components/Import/Importprofiles.razor diff --git a/AudioCuesheetEditor/Shared/Import/Importprofiles.resx b/AudioCuesheetEditor/Components/Import/Importprofiles.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Import/Importprofiles.resx rename to AudioCuesheetEditor/Components/Import/Importprofiles.resx diff --git a/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.de.resx b/AudioCuesheetEditor/Components/Inputs/FileDropOverlay.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.de.resx rename to AudioCuesheetEditor/Components/Inputs/FileDropOverlay.de.resx diff --git a/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor b/AudioCuesheetEditor/Components/Inputs/FileDropOverlay.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor rename to AudioCuesheetEditor/Components/Inputs/FileDropOverlay.razor diff --git a/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.resx b/AudioCuesheetEditor/Components/Inputs/FileDropOverlay.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.resx rename to AudioCuesheetEditor/Components/Inputs/FileDropOverlay.resx diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.de.resx b/AudioCuesheetEditor/Components/Inputs/FileInput.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/FileInput.de.resx rename to AudioCuesheetEditor/Components/Inputs/FileInput.de.resx diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor b/AudioCuesheetEditor/Components/Inputs/FileInput.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/FileInput.razor rename to AudioCuesheetEditor/Components/Inputs/FileInput.razor diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.resx b/AudioCuesheetEditor/Components/Inputs/FileInput.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/FileInput.resx rename to AudioCuesheetEditor/Components/Inputs/FileInput.resx diff --git a/AudioCuesheetEditor/Shared/Inputs/TextField.de.resx b/AudioCuesheetEditor/Components/Inputs/TextField.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/TextField.de.resx rename to AudioCuesheetEditor/Components/Inputs/TextField.de.resx diff --git a/AudioCuesheetEditor/Shared/Inputs/TextField.razor b/AudioCuesheetEditor/Components/Inputs/TextField.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/TextField.razor rename to AudioCuesheetEditor/Components/Inputs/TextField.razor diff --git a/AudioCuesheetEditor/Shared/Inputs/TextField.resx b/AudioCuesheetEditor/Components/Inputs/TextField.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Inputs/TextField.resx rename to AudioCuesheetEditor/Components/Inputs/TextField.resx diff --git a/AudioCuesheetEditor/Shared/Layouts/MainLayout.de.resx b/AudioCuesheetEditor/Components/Layouts/MainLayout.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Layouts/MainLayout.de.resx rename to AudioCuesheetEditor/Components/Layouts/MainLayout.de.resx diff --git a/AudioCuesheetEditor/Shared/Layouts/MainLayout.razor b/AudioCuesheetEditor/Components/Layouts/MainLayout.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Layouts/MainLayout.razor rename to AudioCuesheetEditor/Components/Layouts/MainLayout.razor diff --git a/AudioCuesheetEditor/Shared/Layouts/MainLayout.resx b/AudioCuesheetEditor/Components/Layouts/MainLayout.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Layouts/MainLayout.resx rename to AudioCuesheetEditor/Components/Layouts/MainLayout.resx diff --git a/AudioCuesheetEditor/Shared/Layouts/MainLayoutWithoutMenu.de.resx b/AudioCuesheetEditor/Components/Layouts/MainLayoutWithoutMenu.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Layouts/MainLayoutWithoutMenu.de.resx rename to AudioCuesheetEditor/Components/Layouts/MainLayoutWithoutMenu.de.resx diff --git a/AudioCuesheetEditor/Shared/Layouts/MainLayoutWithoutMenu.razor b/AudioCuesheetEditor/Components/Layouts/MainLayoutWithoutMenu.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Layouts/MainLayoutWithoutMenu.razor rename to AudioCuesheetEditor/Components/Layouts/MainLayoutWithoutMenu.razor diff --git a/AudioCuesheetEditor/Shared/Layouts/MainLayoutWithoutMenu.resx b/AudioCuesheetEditor/Components/Layouts/MainLayoutWithoutMenu.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Layouts/MainLayoutWithoutMenu.resx rename to AudioCuesheetEditor/Components/Layouts/MainLayoutWithoutMenu.resx diff --git a/AudioCuesheetEditor/Shared/Record/AddTrack.de.resx b/AudioCuesheetEditor/Components/Record/AddTrack.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Record/AddTrack.de.resx rename to AudioCuesheetEditor/Components/Record/AddTrack.de.resx diff --git a/AudioCuesheetEditor/Shared/Record/AddTrack.razor b/AudioCuesheetEditor/Components/Record/AddTrack.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Record/AddTrack.razor rename to AudioCuesheetEditor/Components/Record/AddTrack.razor diff --git a/AudioCuesheetEditor/Shared/Record/AddTrack.resx b/AudioCuesheetEditor/Components/Record/AddTrack.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Record/AddTrack.resx rename to AudioCuesheetEditor/Components/Record/AddTrack.resx diff --git a/AudioCuesheetEditor/Shared/Record/ControlRecording.de.resx b/AudioCuesheetEditor/Components/Record/ControlRecording.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Record/ControlRecording.de.resx rename to AudioCuesheetEditor/Components/Record/ControlRecording.de.resx diff --git a/AudioCuesheetEditor/Shared/Record/ControlRecording.razor b/AudioCuesheetEditor/Components/Record/ControlRecording.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Record/ControlRecording.razor rename to AudioCuesheetEditor/Components/Record/ControlRecording.razor diff --git a/AudioCuesheetEditor/Shared/Record/ControlRecording.resx b/AudioCuesheetEditor/Components/Record/ControlRecording.resx similarity index 100% rename from AudioCuesheetEditor/Shared/Record/ControlRecording.resx rename to AudioCuesheetEditor/Components/Record/ControlRecording.resx diff --git a/AudioCuesheetEditor/Shared/TrackList/ArtistColumn.razor b/AudioCuesheetEditor/Components/TrackList/ArtistColumn.razor similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/ArtistColumn.razor rename to AudioCuesheetEditor/Components/TrackList/ArtistColumn.razor diff --git a/AudioCuesheetEditor/Shared/TrackList/TitleColumn.razor b/AudioCuesheetEditor/Components/TrackList/TitleColumn.razor similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/TitleColumn.razor rename to AudioCuesheetEditor/Components/TrackList/TitleColumn.razor diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackList.de.resx b/AudioCuesheetEditor/Components/TrackList/TrackList.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/TrackList.de.resx rename to AudioCuesheetEditor/Components/TrackList/TrackList.de.resx diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor b/AudioCuesheetEditor/Components/TrackList/TrackList.razor similarity index 96% rename from AudioCuesheetEditor/Shared/TrackList/TrackList.razor rename to AudioCuesheetEditor/Components/TrackList/TrackList.razor index ea5c8c95..0dd751ed 100644 --- a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor +++ b/AudioCuesheetEditor/Components/TrackList/TrackList.razor @@ -1,4 +1,4 @@ -<!-- +<!-- This file is part of AudioCuesheetEditor. AudioCuesheetEditor is free software: you can redistribute it and/or modify @@ -79,13 +79,13 @@ along with Foobar. If not, see Validation="(string? newBegin) => _validationService.Validate(context.Item, nameof(Track.Begin))" Style="width: 55px;" /> </EditTemplate> </PropertyColumn> - <PropertyColumn Property="x => x.End" Title="@_localizer["End"]" Editable="CurrentViewMode != ViewMode.RecordView" HeaderStyle="width: 1px;"> + <PropertyColumn Property="x => x.Finish" Title="@_localizer["End"]" Editable="CurrentViewMode != ViewMode.RecordView" HeaderStyle="width: 1px;"> <CellTemplate> - @_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.End) + @_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.Finish) </CellTemplate> <EditTemplate> - <MudTextField Value="@_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.End)" ValueChanged="(string value) => TimespanChanged(context.Item, x => x.End, value)" - Validation="(string? newEnd) => _validationService.Validate(context.Item, nameof(Track.End))" Style="width: 55px;" /> + <MudTextField Value="@_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.Finish)" ValueChanged="(string value) => TimespanChanged(context.Item, x => x.Finish, value)" + Validation="(string? newEnd) => _validationService.Validate(context.Item, nameof(Track.Finish))" Style="width: 55px;" /> </EditTemplate> </PropertyColumn> <PropertyColumn Property="x => x.Length" Title="@_localizer["Length"]" Editable="CurrentViewMode != ViewMode.RecordView" HeaderStyle="width: 1px;"> @@ -213,8 +213,8 @@ along with Foobar. If not, see { var copy = _trackManager.Clone(trackThatWillBeCopied); copy.Position = (ushort?)(trackThatWillBeCopied.Position + 1); - copy.Begin = trackThatWillBeCopied.End; - copy.End = null; + copy.Begin = trackThatWillBeCopied.Finish; + copy.Finish = null; _audiofileManager.AddTrack(Audiofile, copy); await EditTrackModalClicked(copy); } diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackList.resx b/AudioCuesheetEditor/Components/TrackList/TrackList.resx similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/TrackList.resx rename to AudioCuesheetEditor/Components/TrackList/TrackList.resx diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackListControlButtons.de.resx b/AudioCuesheetEditor/Components/TrackList/TrackListControlButtons.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/TrackListControlButtons.de.resx rename to AudioCuesheetEditor/Components/TrackList/TrackListControlButtons.de.resx diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackListControlButtons.razor b/AudioCuesheetEditor/Components/TrackList/TrackListControlButtons.razor similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/TrackListControlButtons.razor rename to AudioCuesheetEditor/Components/TrackList/TrackListControlButtons.razor diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackListControlButtons.resx b/AudioCuesheetEditor/Components/TrackList/TrackListControlButtons.resx similarity index 100% rename from AudioCuesheetEditor/Shared/TrackList/TrackListControlButtons.resx rename to AudioCuesheetEditor/Components/TrackList/TrackListControlButtons.resx diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.razor b/AudioCuesheetEditor/Components/Validation/Alert.razor similarity index 100% rename from AudioCuesheetEditor/Shared/Validation/Alert.razor rename to AudioCuesheetEditor/Components/Validation/Alert.razor diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.de.resx b/AudioCuesheetEditor/Components/ViewModes/ViewModeFull.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.de.resx rename to AudioCuesheetEditor/Components/ViewModes/ViewModeFull.de.resx diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor b/AudioCuesheetEditor/Components/ViewModes/ViewModeFull.razor similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.razor rename to AudioCuesheetEditor/Components/ViewModes/ViewModeFull.razor diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.resx b/AudioCuesheetEditor/Components/ViewModes/ViewModeFull.resx similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeFull.resx rename to AudioCuesheetEditor/Components/ViewModes/ViewModeFull.resx diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.de.resx b/AudioCuesheetEditor/Components/ViewModes/ViewModeImport.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.de.resx rename to AudioCuesheetEditor/Components/ViewModes/ViewModeImport.de.resx diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor b/AudioCuesheetEditor/Components/ViewModes/ViewModeImport.razor similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor rename to AudioCuesheetEditor/Components/ViewModes/ViewModeImport.razor diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.resx b/AudioCuesheetEditor/Components/ViewModes/ViewModeImport.resx similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.resx rename to AudioCuesheetEditor/Components/ViewModes/ViewModeImport.resx diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.de.resx b/AudioCuesheetEditor/Components/ViewModes/ViewModeRecord.de.resx similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.de.resx rename to AudioCuesheetEditor/Components/ViewModes/ViewModeRecord.de.resx diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.razor b/AudioCuesheetEditor/Components/ViewModes/ViewModeRecord.razor similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.razor rename to AudioCuesheetEditor/Components/ViewModes/ViewModeRecord.razor diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.resx b/AudioCuesheetEditor/Components/ViewModes/ViewModeRecord.resx similarity index 100% rename from AudioCuesheetEditor/Shared/ViewModes/ViewModeRecord.resx rename to AudioCuesheetEditor/Components/ViewModes/ViewModeRecord.resx diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs index 5c49c273..8a30d469 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Cuesheet.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -37,11 +37,11 @@ public class Cuesheet() : Validateable, ICuesheet [JsonIgnore] public DateTime? RecordingStart { get; set; } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(Audiofiles): validationStatus = ValidationStatus.Success; diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs b/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs index 30f4e3d6..ef3f358a 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/ITrack.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ public interface ITrack string? Title { get; set; } ushort? Position { get; set; } TimeSpan? Begin { get; set; } - TimeSpan? End { get; set; } + TimeSpan? Finish { get; set; } TimeSpan? Length { get; set; } IEnumerable<Flag> Flags { get; set; } TimeSpan? PreGap { get; set; } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs index e0a6fb08..3c529c18 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Import/ImportTrack.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ public class ImportTrack : ITrack public string? Title { get; set; } public ushort? Position { get; set; } public TimeSpan? Begin { get; set; } - public TimeSpan? End { get; set; } + public TimeSpan? Finish { get; set; } public TimeSpan? Length { get; set; } public IEnumerable<Flag> Flags { get; set; } = []; public TimeSpan? PreGap { get; set; } diff --git a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs index efd43ec2..a49600b4 100644 --- a/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs +++ b/AudioCuesheetEditor/Model/AudioCuesheet/Track.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -25,15 +25,15 @@ public class Track : Validateable, ITrack public string? Artist { get; set; } public string? Title { get; set; } public TimeSpan? Begin { get; set; } - public TimeSpan? End { get; set; } + public TimeSpan? Finish { get; set; } [JsonIgnore] public TimeSpan? Length { get { - if ((Begin.HasValue == true) && (End.HasValue == true) && (Begin.Value <= End.Value)) + if ((Begin.HasValue == true) && (Finish.HasValue == true) && (Begin.Value <= Finish.Value)) { - return End - Begin; + return Finish - Begin; } else { @@ -42,25 +42,25 @@ public TimeSpan? Length } set { - if ((Begin.HasValue == false) && (End.HasValue == false)) + if ((Begin.HasValue == false) && (Finish.HasValue == false)) { - End = value; + Finish = value; } else { - if ((Begin.HasValue == true) && (End.HasValue == true)) + if ((Begin.HasValue == true) && (Finish.HasValue == true)) { - End = Begin.Value + value; + Finish = Begin.Value + value; } else { - if ((End.HasValue == false) && (Begin.HasValue)) + if ((Finish.HasValue == false) && (Begin.HasValue)) { - End = Begin.Value + value; + Finish = Begin.Value + value; } - if ((Begin.HasValue == false) && (End.HasValue)) + if ((Begin.HasValue == false) && (Finish.HasValue)) { - Begin = End.Value - value; + Begin = Finish.Value - value; } } } @@ -81,11 +81,11 @@ public TimeSpan? Length [JsonIgnore] public Audiofile? Audiofile { get; set; } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(Position): validationStatus = ValidationStatus.Success; @@ -110,7 +110,7 @@ public override ValidationResult Validate(string property) if (positionTrackShouldHave != Position) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? string.Empty, Title ?? string.Empty, Begin != null ? Begin : string.Empty, End != null ? End : string.Empty, positionTrackShouldHave)); + validationMessages.Add(new ValidationMessage("Track({0},{1},{2},{3},{4}) does not have the correct position '{5}'!", Position, Artist ?? string.Empty, Title ?? string.Empty, Begin != null ? Begin : string.Empty, Finish != null ? Finish : string.Empty, positionTrackShouldHave)); } } } @@ -130,31 +130,31 @@ public override ValidationResult Validate(string property) validationMessages ??= []; validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(Begin))); } - if (Begin > End) + if (Begin > Finish) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} should be less than or equal '{1}'!", nameof(Begin), nameof(End))); + validationMessages.Add(new ValidationMessage("{0} should be less than or equal '{1}'!", nameof(Begin), nameof(Finish))); } } break; - case nameof(End): + case nameof(Finish): validationStatus = ValidationStatus.Success; - if (End == null) + if (Finish == null) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(End))); + validationMessages.Add(new ValidationMessage("{0} has no value!", nameof(Finish))); } else { - if (End < TimeSpan.Zero) + if (Finish < TimeSpan.Zero) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(End))); + validationMessages.Add(new ValidationMessage("{0} must be equal or greater zero!", nameof(Finish))); } - if (End < Begin) + if (Finish < Begin) { validationMessages ??= []; - validationMessages.Add(new ValidationMessage("{0} should be greater than or equal '{1}'!", nameof(End), nameof(Begin))); + validationMessages.Add(new ValidationMessage("{0} should be greater than or equal '{1}'!", nameof(Finish), nameof(Begin))); } } break; diff --git a/AudioCuesheetEditor/Model/Entity/IValidateable.cs b/AudioCuesheetEditor/Model/Entity/IValidateable.cs index 54bea1e2..55daf630 100644 --- a/AudioCuesheetEditor/Model/Entity/IValidateable.cs +++ b/AudioCuesheetEditor/Model/Entity/IValidateable.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -25,9 +25,9 @@ public interface IValidateable /// <summary> /// Validates the property and return the result of validation. /// </summary> - /// <param name="property"></param> + /// <param name="propertyName"></param> /// <returns></returns> - ValidationResult Validate(string property); + ValidationResult Validate(string propertyName); } public enum ValidationStatus { @@ -37,7 +37,7 @@ public enum ValidationStatus } public class ValidationResult { - List<ValidationMessage> validationMessages = []; + List<ValidationMessage> _validationMessages = []; public static ValidationResult Create(ValidationStatus validationStatus, IEnumerable<ValidationMessage>? validationMessages = null) { @@ -52,11 +52,11 @@ public static ValidationResult Create(ValidationStatus validationStatus, IEnumer public ValidationStatus Status { get; set; } public ICollection<ValidationMessage> ValidationMessages { - get => validationMessages; + get => _validationMessages; set { - validationMessages = [.. value]; - if (validationMessages.Count > 0) + _validationMessages = [.. value]; + if (_validationMessages.Count > 0) { Status = ValidationStatus.Error; } diff --git a/AudioCuesheetEditor/Model/Entity/Validateable.cs b/AudioCuesheetEditor/Model/Entity/Validateable.cs index d79d74e7..a0e56183 100644 --- a/AudioCuesheetEditor/Model/Entity/Validateable.cs +++ b/AudioCuesheetEditor/Model/Entity/Validateable.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -50,7 +50,7 @@ public ValidationResult Validate() return validationResult; } - public abstract ValidationResult Validate(string property); + public abstract ValidationResult Validate(string propertyName); protected void OnValidateablePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") => ValidateablePropertyChanged?.Invoke(this, propertyName); } diff --git a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs index 6bb18e52..e7f95b00 100644 --- a/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs +++ b/AudioCuesheetEditor/Model/IO/Audio/Audiofile.cs @@ -81,11 +81,11 @@ public AudioCodec? AudioCodec public ICollection<Track> Tracks { get; set; } = []; - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(Tracks): validationStatus = ValidationStatus.Success; @@ -107,21 +107,21 @@ public override ValidationResult Validate(string property) { foreach (var trackWithSamePosition in track) { - validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : string.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : string.Empty, trackWithSamePosition.Artist ?? string.Empty, trackWithSamePosition.Title ?? string.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : string.Empty, trackWithSamePosition.End != null ? trackWithSamePosition.End : string.Empty)); + validationMessages.Add(new ValidationMessage("{0} {1} '{2}' is used also by {3}({4},{5},{6},{7},{8}). Positions must be unique!", nameof(Track), nameof(Track.Position), track.Key != null ? track.Key : string.Empty, nameof(Track), trackWithSamePosition.Position != null ? trackWithSamePosition.Position : string.Empty, trackWithSamePosition.Artist ?? string.Empty, trackWithSamePosition.Title ?? string.Empty, trackWithSamePosition.Begin != null ? trackWithSamePosition.Begin : string.Empty, trackWithSamePosition.Finish != null ? trackWithSamePosition.Finish : string.Empty)); } } } foreach (var track in Tracks.OrderBy(x => x.Position)) { - var tracksBetween = Tracks.Where(x => ((track.Begin >= x.Begin && track.Begin < x.End) - || (x.Begin < track.End && track.End <= x.End)) + var tracksBetween = Tracks.Where(x => ((track.Begin >= x.Begin && track.Begin < x.Finish) + || (x.Begin < track.Finish && track.Finish <= x.Finish)) && (x.Equals(track) == false)); if (tracksBetween.Any()) { validationMessages ??= []; foreach (var trackBetween in tracksBetween) { - validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : string.Empty, track.Artist ?? string.Empty, track.Title ?? string.Empty, track.Begin != null ? track.Begin : string.Empty, track.End != null ? track.End : string.Empty, trackBetween.Position != null ? trackBetween.Position : string.Empty, trackBetween.Artist ?? string.Empty, trackBetween.Title ?? string.Empty, trackBetween.Begin != null ? trackBetween.Begin : string.Empty, trackBetween.End != null ? trackBetween.End : string.Empty)); + validationMessages.Add(new ValidationMessage("{0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once!", nameof(Track), track.Position != null ? track.Position : string.Empty, track.Artist ?? string.Empty, track.Title ?? string.Empty, track.Begin != null ? track.Begin : string.Empty, track.Finish != null ? track.Finish : string.Empty, trackBetween.Position != null ? trackBetween.Position : string.Empty, trackBetween.Artist ?? string.Empty, trackBetween.Title ?? string.Empty, trackBetween.Begin != null ? trackBetween.Begin : string.Empty, trackBetween.Finish != null ? trackBetween.Finish : string.Empty)); } } } diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs index 730499ab..7dd68b49 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs @@ -31,7 +31,7 @@ public class Exportprofile : Validateable public static readonly string SchemeTrackArtist = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Artist)}{SchemeCharacter}"; public static readonly string SchemeTrackTitle = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Title)}{SchemeCharacter}"; public static readonly string SchemeTrackBegin = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Begin)}{SchemeCharacter}"; - public static readonly string SchemeTrackEnd = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.End)}{SchemeCharacter}"; + public static readonly string SchemeTrackEnd = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Finish)}{SchemeCharacter}"; public static readonly string SchemeTrackLength = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Length)}{SchemeCharacter}"; public static readonly string SchemeTrackPosition = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Position)}{SchemeCharacter}"; public static readonly string SchemeTrackFlags = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Flags)}{SchemeCharacter}"; @@ -61,7 +61,7 @@ public class Exportprofile : Validateable { nameof(Track.Artist), SchemeTrackArtist }, { nameof(Track.Title), SchemeTrackTitle }, { nameof(Track.Begin), SchemeTrackBegin }, - { nameof(Track.End), SchemeTrackEnd }, + { nameof(Track.Finish), SchemeTrackEnd }, { nameof(Track.Length), SchemeTrackLength }, { nameof(Track.Flags), SchemeTrackFlags }, { nameof(Track.PreGap), SchemeTrackPreGap }, @@ -119,11 +119,11 @@ public string Filename set { _filename = value; OnValidateablePropertyChanged(); } } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(SchemeHead): validationStatus = ValidationStatus.Success; diff --git a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs index 41834f7e..17d72caa 100644 --- a/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/Importprofile.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ public class Importprofile : Validateable public static readonly IEnumerable<string> AvailableSchemeAudiofiles = [nameof(ImportAudiofile.Name)]; - public static readonly IEnumerable<string> AvailableSchemesTrack = [nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), nameof(ImportTrack.End), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), nameof(ImportTrack.PreGap), nameof(ImportTrack.PostGap), nameof(ImportTrack.StartDateTime)]; + public static readonly IEnumerable<string> AvailableSchemesTrack = [nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), nameof(ImportTrack.Finish), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), nameof(ImportTrack.PreGap), nameof(ImportTrack.PostGap), nameof(ImportTrack.StartDateTime)]; public Guid Id { get; init; } = Guid.NewGuid(); public string? Name { get; set; } @@ -34,11 +34,11 @@ public class Importprofile : Validateable public string? SchemeAudiofiles { get; set; } public string? SchemeTracks { get; set; } public TimeSpanFormat? TimeSpanFormat { get; set; } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(SchemeCuesheet): validationStatus = ValidationStatus.Success; diff --git a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs index 6b3a8390..55f15f75 100644 --- a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs +++ b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -53,11 +53,11 @@ public string? ProjectFilename field = value; } } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(CuesheetFilename): validationStatus = ValidationStatus.Success; diff --git a/AudioCuesheetEditor/Model/Options/ImportOptions.cs b/AudioCuesheetEditor/Model/Options/ImportOptions.cs index 3e289c24..50ee1056 100644 --- a/AudioCuesheetEditor/Model/Options/ImportOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ImportOptions.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ public class ImportOptions : IOptions UseRegularExpression = false, SchemeCuesheet = $"{nameof(ImportCuesheet.Artist)} - {nameof(ImportCuesheet.Title)}", SchemeAudiofiles = $"- {nameof(ImportAudiofile.Name)}", - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.Finish)}" }; public static readonly ICollection<Importprofile> DefaultImportprofiles = @@ -37,7 +37,7 @@ public class ImportOptions : IOptions { Name = "Textfile (just track data)", UseRegularExpression = false, - SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.End)}" + SchemeTracks = $"{nameof(ImportTrack.Artist)} - {nameof(ImportTrack.Title)}\t{nameof(ImportTrack.Finish)}" }, new() { diff --git a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs index b94f8847..e4ef482f 100644 --- a/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs +++ b/AudioCuesheetEditor/Model/Utility/TimeSpanFormat.cs @@ -84,11 +84,11 @@ public string? Scheme return timespan; } - public override ValidationResult Validate(string property) + public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; List<ValidationMessage>? validationMessages = null; - switch (property) + switch (propertyName) { case nameof(Scheme): validationStatus = ValidationStatus.Success; diff --git a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs index 8e930df2..44c28a8c 100644 --- a/AudioCuesheetEditor/Services/Audio/PlaybackService.cs +++ b/AudioCuesheetEditor/Services/Audio/PlaybackService.cs @@ -47,7 +47,7 @@ private set } } } - public Track? CurrentlyPlayingTrack => _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).SingleOrDefault(x => x.Begin.HasValue == true && x.End.HasValue == true && x.Begin <= CurrentPosition && x.End > CurrentPosition); + public Track? CurrentlyPlayingTrack => _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).SingleOrDefault(x => x.Begin.HasValue == true && x.Finish.HasValue == true && x.Begin <= CurrentPosition && x.Finish > CurrentPosition); public TimeSpan? TotalTime { get @@ -62,8 +62,8 @@ public TimeSpan? TotalTime } public bool IsPaused { get; private set; } public bool IsPlaybackPossible => _sessionStateContainer.Cuesheet.Audiofiles.Any(x => string.IsNullOrEmpty(x.ObjectURL) == false); - public bool IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin) != null; - public bool IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End) != null; + public bool IsPreviousPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Finish <= CurrentlyPlayingTrack.Begin) != null; + public bool IsNextPossible => (CurrentlyPlayingTrack != null) && _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.Finish) != null; public bool IsPlaying => _currentlyPlayingAudiofile != null; public async Task InitializeAsync() @@ -135,7 +135,7 @@ public async Task PlayNextTrackAsync() { if (CurrentlyPlayingTrack != null) { - var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.End); + var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Begin >= CurrentlyPlayingTrack.Finish); if (trackToPlay != null) { await PlayAsync(trackToPlay); @@ -147,7 +147,7 @@ public async Task PlayPreviousTrackAsync() { if (CurrentlyPlayingTrack != null) { - var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.End <= CurrentlyPlayingTrack.Begin); + var trackToPlay = _sessionStateContainer.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).LastOrDefault(x => x.Finish <= CurrentlyPlayingTrack.Begin); if (trackToPlay != null) { await PlayAsync(trackToPlay); diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index a9ae433d..ed530ec3 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -114,9 +114,9 @@ public void AddTrack(Audiofile audiofile, Track track, bool setTracing = true) _trackManager.SetProperty(track, x => x.Begin, DateTime.UtcNow - cuesheet.RecordingStart); } var lastTrack = GetLastTrack(audiofile); - if ((audiofile.Duration.HasValue == true) && (lastTrack?.End.HasValue == true) && (lastTrack.End == audiofile.Duration)) + if ((audiofile.Duration.HasValue == true) && (lastTrack?.Finish.HasValue == true) && (lastTrack.Finish == audiofile.Duration)) { - _trackManager.SetProperty(lastTrack, x => x.End, null); + _trackManager.SetProperty(lastTrack, x => x.Finish, null); } var newValue = new List<Track>(audiofile.Tracks) { @@ -202,15 +202,15 @@ void RecalculateTrackProperties(Cuesheet cuesheet) _trackManager.SetProperty(track, x => x.Position, position); } var previousTrack = _trackManager.GetPreviousLinkedTrack(track); - if (previousTrack?.End.HasValue == true) + if (previousTrack?.Finish.HasValue == true) { - _trackManager.SetProperty(track, x => x.Begin, previousTrack.End); + _trackManager.SetProperty(track, x => x.Begin, previousTrack.Finish); } else { if (previousTrack != null) { - _trackManager.SetProperty(previousTrack, x => x.End, track.Begin); + _trackManager.SetProperty(previousTrack, x => x.Finish, track.Begin); } } position++; @@ -233,16 +233,16 @@ void RecalculateTrackProperties(Cuesheet cuesheet) { return audiofile.Tracks.OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .ThenByDescending(x => x.Finish.HasValue).ThenBy(x => x.Finish) .LastOrDefault(); } void SetLastTrackEnd(Audiofile audiofile) { var lastTrack = GetLastTrack(audiofile); - if ((lastTrack?.End.HasValue == false) && (audiofile.Duration.HasValue == true)) + if ((lastTrack?.Finish.HasValue == false) && (audiofile.Duration.HasValue == true)) { - _trackManager.SetProperty(lastTrack, x => x.End, audiofile.Duration); + _trackManager.SetProperty(lastTrack, x => x.Finish, audiofile.Duration); } } @@ -251,7 +251,7 @@ void SetLastTrackEnd(Audiofile audiofile) return cuesheet.Audiofiles.SelectMany(x => x.Tracks) .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .ThenByDescending(x => x.Finish.HasValue).ThenBy(x => x.Finish) .FirstOrDefault(); } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs index 461abae8..a69d357b 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/CuesheetManager.cs @@ -97,7 +97,7 @@ public void StopRecording() var lastTrack = GetLastTrack(cuesheet); if ((lastTrack != null) && cuesheet.RecordingStart.HasValue) { - lastTrack.End = DateTime.UtcNow - cuesheet.RecordingStart.Value; + lastTrack.Finish = DateTime.UtcNow - cuesheet.RecordingStart.Value; } cuesheet.RecordingStart = null; IsRecordingChanged?.Invoke(this, EventArgs.Empty); @@ -166,16 +166,16 @@ public Result MoveUp(HashSet<Track> selectedTracks, uint positions = 1) else { var newBegin = previousTrack?.Begin; - var newEnd = previousTrack?.End; + var newEnd = previousTrack?.Finish; if (previousTrack != null) { _trackManager.SetProperty(previousTrack, x => x.Position, selectedTrack.Position); _trackManager.SetProperty(previousTrack, x => x.Begin, selectedTrack.Begin); - _trackManager.SetProperty(previousTrack, x => x.End, selectedTrack.End); + _trackManager.SetProperty(previousTrack, x => x.Finish, selectedTrack.Finish); } _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position - 1)); _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); - _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); + _trackManager.SetProperty(selectedTrack, x => x.Finish, newEnd); } } @@ -250,16 +250,16 @@ public Result MoveDown(HashSet<Track> selectedTracks, uint positions = 1) else { var newBegin = nextTrack?.Begin; - var newEnd = nextTrack?.End; + var newEnd = nextTrack?.Finish; if (nextTrack != null) { _trackManager.SetProperty(nextTrack, x => x.Position, selectedTrack.Position); _trackManager.SetProperty(nextTrack, x => x.Begin, selectedTrack.Begin); - _trackManager.SetProperty(nextTrack, x => x.End, selectedTrack.End); + _trackManager.SetProperty(nextTrack, x => x.Finish, selectedTrack.Finish); } _trackManager.SetProperty(selectedTrack, x => x.Position, (ushort?)(selectedTrack.Position + 1)); _trackManager.SetProperty(selectedTrack, x => x.Begin, newBegin); - _trackManager.SetProperty(selectedTrack, x => x.End, newEnd); + _trackManager.SetProperty(selectedTrack, x => x.Finish, newEnd); } } foreach (var audiofile in cuesheet!.Audiofiles) @@ -370,7 +370,7 @@ void SwitchAudiofile(Track trackToMove, Audiofile audiofileToMoveTo) return cuesheet.Audiofiles.SelectMany(x => x.Tracks) .OrderByDescending(x => x.Position.HasValue).ThenBy(x => x.Position) .ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin) - .ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End) + .ThenByDescending(x => x.Finish.HasValue).ThenBy(x => x.Finish) .LastOrDefault(); } } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs index 3998435c..4191fa4d 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/TrackManager.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ public class TrackManager(ITraceChangeManager traceChangeManager) : ITrackManage public Track Clone(ITrack track) { var setLength = true; - if (track.Begin.HasValue && track.End.HasValue) + if (track.Begin.HasValue && track.Finish.HasValue) { setLength = false; } @@ -50,7 +50,7 @@ public Track Clone(ITrack track) Artist = track.Artist, Title = track.Title, Begin = track.Begin, - End = track.End, + Finish = track.Finish, Flags = track.Flags, PreGap = track.PreGap, PostGap = track.PostGap @@ -87,7 +87,7 @@ public void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTr } if (setEnd) { - SetValue(target, x => x.End, source.End); + SetValue(target, x => x.Finish, source.Finish); } if (setLength) { @@ -120,7 +120,7 @@ public void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTr } if (track.Begin.HasValue) { - return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.End).LastOrDefault(x => x.End <= track.Begin && Equals(x, track) == false); + return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Finish).LastOrDefault(x => x.Finish <= track.Begin && Equals(x, track) == false); } return null; } @@ -132,9 +132,9 @@ public void CopyValues(ITrack source, Track target, bool setIsLinkedToPreviousTr { return track.Cuesheet.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).FirstOrDefault(x => x.Position >= track.Position.Value + 1 && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); } - if (track.End.HasValue) + if (track.Finish.HasValue) { - return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).LastOrDefault(x => x.Begin <= track.End && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); + return track.Cuesheet?.Audiofiles.SelectMany(x => x.Tracks).OrderBy(x => x.Begin).LastOrDefault(x => x.Begin <= track.Finish && x.IsLinkedToPreviousTrack == true && Equals(x, track) == false); } return null; } @@ -151,13 +151,13 @@ public void RecalculateLinkedTracksProperties(Track track) { SetValue(track, x => x.Position, (ushort?)(previousTrack.Position + 1)); } - if (previousTrack.End.HasValue && (track.Begin != previousTrack.End)) + if (previousTrack.Finish.HasValue && (track.Begin != previousTrack.Finish)) { - SetValue(track, x => x.Begin, previousTrack.End); + SetValue(track, x => x.Begin, previousTrack.Finish); } - if ((previousTrack.End.HasValue == false) && track.Begin.HasValue) + if ((previousTrack.Finish.HasValue == false) && track.Begin.HasValue) { - SetValue(previousTrack, x => x.End, track.Begin); + SetValue(previousTrack, x => x.Finish, track.Begin); } } var nextTrack = GetNextLinkedTrack(track); @@ -167,7 +167,7 @@ public void RecalculateLinkedTracksProperties(Track track) { SetValue(nextTrack, x => x.Position, (ushort?)(track.Position + 1)); } - SetValue(nextTrack, x => x.Begin, track.End); + SetValue(nextTrack, x => x.Begin, track.Finish); } } } diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index ddc5318b..be4612c0 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -82,7 +82,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeTrackTitle, track.Title) .Replace(Exportprofile.SchemeTrackPosition, track.Position?.ToString(CultureInfo.CurrentCulture)) .Replace(Exportprofile.SchemeTrackBegin, track.Begin.ToString()) - .Replace(Exportprofile.SchemeTrackEnd, track.End.ToString()) + .Replace(Exportprofile.SchemeTrackEnd, track.Finish.ToString()) .Replace(Exportprofile.SchemeTrackLength, track.Length.ToString()) .Replace(Exportprofile.SchemeTrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))) .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty) diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index f67fb28a..cd490a84 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -242,13 +242,13 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) { sortedTracks = sortedTracks.ThenByDescending(x => x.Begin.HasValue).ThenBy(x => x.Begin); } - if (sortedTracks.All(x => x.End.HasValue)) + if (sortedTracks.All(x => x.Finish.HasValue)) { - sortedTracks = sortedTracks.ThenBy(x => x.End); + sortedTracks = sortedTracks.ThenBy(x => x.Finish); } else { - sortedTracks = sortedTracks.ThenByDescending(x => x.End.HasValue).ThenBy(x => x.End); + sortedTracks = sortedTracks.ThenByDescending(x => x.Finish.HasValue).ThenBy(x => x.Finish); } TimeSpan? begin = TimeSpan.Zero; ushort position = 1; @@ -268,7 +268,7 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) { var length = nextImportTrack.StartDateTime - importTrack.StartDateTime; clone.Begin = begin; - clone.End = begin + length; + clone.Finish = begin + length; } // Calculate properties if (clone.Position.HasValue == false) @@ -279,19 +279,19 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) { clone.Begin = begin; } - if ((clone.End.HasValue == false) && (nextTrack?.Begin.HasValue == true)) + if ((clone.Finish.HasValue == false) && (nextTrack?.Begin.HasValue == true)) { - clone.End = nextTrack.Begin; + clone.Finish = nextTrack.Begin; } - begin = clone.End; + begin = clone.Finish; position++; targetAudiofile.Tracks.Add(clone); } //Set last track end var lastTrack = targetAudiofile.Tracks.LastOrDefault(); - if ((lastTrack?.End.HasValue == false) && (targetAudiofile.Duration.HasValue == true)) + if ((lastTrack?.Finish.HasValue == false) && (targetAudiofile.Duration.HasValue == true)) { - _trackManager.SetProperty(lastTrack, x => x.End, targetAudiofile.Duration); + _trackManager.SetProperty(lastTrack, x => x.Finish, targetAudiofile.Duration); } target.Audiofiles.Add(targetAudiofile); } diff --git a/AudioCuesheetEditor/Services/IO/TextImportService.cs b/AudioCuesheetEditor/Services/IO/TextImportService.cs index 6531121f..abf89b87 100644 --- a/AudioCuesheetEditor/Services/IO/TextImportService.cs +++ b/AudioCuesheetEditor/Services/IO/TextImportService.cs @@ -210,7 +210,7 @@ void SearchForTrackData(ref Importfile importFile, string fileContent, Importpro nameof(ImportTrack.Artist), nameof(ImportTrack.Title), nameof(ImportTrack.Begin), - nameof(ImportTrack.End), + nameof(ImportTrack.Finish), nameof(ImportTrack.Length), nameof(ImportTrack.Position), nameof(ImportTrack.Flags), diff --git a/AudioCuesheetEditor/Services/UI/DialogManager.cs b/AudioCuesheetEditor/Services/UI/DialogManager.cs index 1e4fb582..112073f5 100644 --- a/AudioCuesheetEditor/Services/UI/DialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/DialogManager.cs @@ -13,11 +13,11 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //<http: //www.gnu.org/licenses />. +using AudioCuesheetEditor.Components.Dialogs; using AudioCuesheetEditor.Model.AudioCuesheet; using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Model.UI; using AudioCuesheetEditor.Services.AudioCuesheet; -using AudioCuesheetEditor.Shared.Dialogs; using MudBlazor; namespace AudioCuesheetEditor.Services.UI; @@ -58,7 +58,7 @@ public async Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks) { var position = editMultipleTracksModalResult.EditedTrack.Position; var begin = editMultipleTracksModalResult.EditedTrack.Begin; - var end = editMultipleTracksModalResult.EditedTrack.End; + var end = editMultipleTracksModalResult.EditedTrack.Finish; var length = editMultipleTracksModalResult.EditedTrack.Length; var preGap = editMultipleTracksModalResult.EditedTrack.PreGap; var postGap = editMultipleTracksModalResult.EditedTrack.PostGap; @@ -102,14 +102,14 @@ public async Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks) copyTrackEnd = true; break; case DynamicEditValue.EnteredValueAdd: - var newValue = editMultipleTracksModalResult.EditedTrack.End + track.End; - editMultipleTracksModalResult.EditedTrack.End = newValue; + var newValue = editMultipleTracksModalResult.EditedTrack.Finish + track.Finish; + editMultipleTracksModalResult.EditedTrack.Finish = newValue; _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: copyTrackEnd, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); copyTrackEnd = false; break; case DynamicEditValue.EnteredValueSubstract: - newValue = track.End - editMultipleTracksModalResult.EditedTrack.End; - editMultipleTracksModalResult.EditedTrack.End = newValue; + newValue = track.Finish - editMultipleTracksModalResult.EditedTrack.Finish; + editMultipleTracksModalResult.EditedTrack.Finish = newValue; _trackManager.CopyValues(editMultipleTracksModalResult.EditedTrack, track, setIsLinkedToPreviousTrack: false, setPosition: false, setArtist: false, setTitle: false, setBegin: false, setEnd: copyTrackEnd, setLength: false, setFlags: false, setPreGap: false, setPostGap: false); copyTrackEnd = false; break; @@ -179,7 +179,7 @@ public async Task ShowAndHandleModalEditDialogAsync(IEnumerable<Track> tracks) } editMultipleTracksModalResult.EditedTrack.Position = position; editMultipleTracksModalResult.EditedTrack.Begin = begin; - editMultipleTracksModalResult.EditedTrack.End = end; + editMultipleTracksModalResult.EditedTrack.Finish = end; editMultipleTracksModalResult.EditedTrack.Length = length; editMultipleTracksModalResult.EditedTrack.PreGap = preGap; editMultipleTracksModalResult.EditedTrack.PostGap = postGap; diff --git a/AudioCuesheetEditor/_Imports.razor b/AudioCuesheetEditor/_Imports.razor index d815267e..73737bae 100644 --- a/AudioCuesheetEditor/_Imports.razor +++ b/AudioCuesheetEditor/_Imports.razor @@ -1,4 +1,4 @@ -@using System.Net.Http +@using System.Net.Http @using System.Net.Http.Json @using System.IO @using System.Timers @@ -11,18 +11,18 @@ @using Microsoft.JSInterop @using AudioCuesheetEditor @using AudioCuesheetEditor.Pages -@using AudioCuesheetEditor.Shared -@using AudioCuesheetEditor.Shared.Dialogs -@using AudioCuesheetEditor.Shared.ViewModes -@using AudioCuesheetEditor.Shared.Layouts -@using AudioCuesheetEditor.Shared.TrackList -@using AudioCuesheetEditor.Shared.Cuesheet -@using AudioCuesheetEditor.Shared.Inputs -@using AudioCuesheetEditor.Shared.Import -@using AudioCuesheetEditor.Shared.Audio -@using AudioCuesheetEditor.Shared.Record -@using AudioCuesheetEditor.Shared.Export -@using AudioCuesheetEditor.Shared.Validation +@using AudioCuesheetEditor.Components +@using AudioCuesheetEditor.Components.Dialogs +@using AudioCuesheetEditor.Components.ViewModes +@using AudioCuesheetEditor.Components.Layouts +@using AudioCuesheetEditor.Components.TrackList +@using AudioCuesheetEditor.Components.Cuesheet +@using AudioCuesheetEditor.Components.Inputs +@using AudioCuesheetEditor.Components.Import +@using AudioCuesheetEditor.Components.Audio +@using AudioCuesheetEditor.Components.Record +@using AudioCuesheetEditor.Components.Export +@using AudioCuesheetEditor.Components.Validation @using AudioCuesheetEditor.Model.AudioCuesheet @using AudioCuesheetEditor.Model.IO @using AudioCuesheetEditor.Model.IO.Export @@ -45,4 +45,4 @@ @using Markdig @using Toolbelt.Blazor.HotKeys2 @using MudBlazor -@using Ganss.Xss \ No newline at end of file +@using Ganss.Xss From bbb098fe3a2664ad0ba480322974aac819845dd0 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:17:51 +0200 Subject: [PATCH 15/20] fix CA2201 --- .editorconfig | 3 -- .../Services/UI/TraceChangeManagerTests.cs | 18 +++++--- .../Utility/TestHelper.cs | 34 -------------- .../Services/IO/CuesheetExportService.cs | 4 -- .../Services/IO/CuesheetImportService.cs | 44 ++++--------------- .../Services/IO/ImportManager.cs | 12 ++--- .../Services/UI/TraceChangeManager.cs | 30 ++++--------- 7 files changed, 31 insertions(+), 114 deletions(-) delete mode 100644 AudioCuesheetEditor.Tests/Utility/TestHelper.cs diff --git a/.editorconfig b/.editorconfig index 0dc31054..6008f9ad 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,9 +15,6 @@ indent_size = 2 indent_size = 4 tab_width = 4 -#TODO: Enable all of these -dotnet_diagnostic.CA2201.severity = suggestion - # Organize usings dotnet_separate_import_directive_groups = false dotnet_sort_system_directives_first = true diff --git a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs index aea87b86..3f0a109b 100644 --- a/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs @@ -16,18 +16,22 @@ using AudioCuesheetEditor.Model.AudioCuesheet; using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Services.UI; -using AudioCuesheetEditor.Tests.Utility; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Linq; +using Microsoft.Extensions.Logging; +using Moq; namespace AudioCuesheetEditor.Tests.Services.UI; [TestClass()] public class TraceChangeManagerTests { - readonly TraceChangeManager _traceChangeManager = new(TestHelper.CreateLogger<TraceChangeManager>()); + readonly Mock<ILogger<TraceChangeManager>> _logger = new(); + + readonly TraceChangeManager _traceChangeManager; + + public TraceChangeManagerTests() + { + _traceChangeManager = new(_logger.Object); + } [TestMethod()] public void AddChange_SingleChange_EnablesUndo() @@ -399,4 +403,4 @@ public void RemoveTracedChanges_RemovesNoChanges_WhenNoChangesAvailable() Assert.IsNull(cuesheet2.CDTextfile); Assert.IsNull(cuesheet2.Title); } -} \ No newline at end of file +} diff --git a/AudioCuesheetEditor.Tests/Utility/TestHelper.cs b/AudioCuesheetEditor.Tests/Utility/TestHelper.cs deleted file mode 100644 index 2abc8390..00000000 --- a/AudioCuesheetEditor.Tests/Utility/TestHelper.cs +++ /dev/null @@ -1,34 +0,0 @@ -//This file is part of AudioCuesheetEditor. - -//AudioCuesheetEditor is free software: you can redistribute it and/or modify -//it under the terms of the GNU General Public License as published by -//the Free Software Foundation, either version 3 of the License, or -//(at your option) any later version. - -//AudioCuesheetEditor is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. - -//You should have received a copy of the GNU General Public License -//along with Foobar. If not, see -//<http: //www.gnu.org/licenses />. -using AudioCuesheetEditor.Model.Options; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace AudioCuesheetEditor.Tests.Utility; - -sealed class TestHelper -{ - public ApplicationOptions ApplicationOptions { get; private set; } = new(); - public static ILogger<T> CreateLogger<T>() - { - var serviceProvider = new ServiceCollection() - .AddLogging() - .BuildServiceProvider(); - - var factory = serviceProvider.GetService<ILoggerFactory>() ?? throw new NullReferenceException(); - return factory.CreateLogger<T>(); - } -} diff --git a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs index a3edb892..6c65e2a3 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetExportService.cs @@ -92,10 +92,6 @@ string WriteCuesheet() var begin = track.Begin.Value; _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackIndex01} {Math.Floor(begin.TotalMinutes):00}:{begin.Seconds:00}:{begin.Milliseconds * 75 / 1000:00}"); } - else - { - throw new NullReferenceException($"{nameof(Track.Begin)} may not be null!"); - } if (track.PostGap.HasValue) { _ = builder.AppendLine(CultureInfo.CurrentCulture, $"{CuesheetConstants.Tab}{CuesheetConstants.Tab}{CuesheetConstants.TrackPostGap} {Math.Floor(track.PostGap.Value.TotalMinutes):00}:{track.PostGap.Value.Seconds:00}:{track.PostGap.Value.Milliseconds * 75 / 1000:00}"); diff --git a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs index bb2fbbc9..a04aef56 100644 --- a/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs +++ b/AudioCuesheetEditor/Services/IO/CuesheetImportService.cs @@ -175,7 +175,7 @@ public static IImportfile Analyse(string fileContent) throw new ArgumentException($"Group '{trackTitleGroupName}' was null!"); } } - if (regexTrackFlags.IsMatch(line) == true) + if ((regexTrackFlags.IsMatch(line) == true) && (track != null)) { var match = regexTrackFlags.Match(line); recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); @@ -184,21 +184,14 @@ public static IImportfile Analyse(string fileContent) { var flags = matchGroup.Value; var flagList = Flag.AvailableFlags.Where(x => flags.Contains(x.CuesheetLabel)); - if (track != null) - { - track.Flags = flagList; - } - else - { - throw new NullReferenceException($"Track was null during input {line}"); - } + track.Flags = flagList; } else { throw new ArgumentException($"Group '{trackFlagsGroupName}' was null!"); } } - if (regexTrackPreGap.IsMatch(line) == true) + if ((regexTrackPreGap.IsMatch(line) == true) && (track != null)) { var match = regexTrackPreGap.Match(line); recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); @@ -208,21 +201,14 @@ public static IImportfile Analyse(string fileContent) var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')], CultureInfo.CurrentCulture); var seconds = int.Parse(matchGroup.Value.AsSpan(matchGroup.Value.IndexOf(':') + 1, 2), CultureInfo.CurrentCulture); var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..], CultureInfo.CurrentCulture); - if (track != null) - { - track.PreGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); - } - else - { - throw new NullReferenceException($"Track was null during input {line}"); - } + track.PreGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { throw new ArgumentException($"Group '{trackPreGapGroupName}' was null!"); } } - if (regexTrackIndex.IsMatch(line) == true) + if ((regexTrackIndex.IsMatch(line) == true) && (track != null)) { var match = regexTrackIndex.Match(line); recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); @@ -232,14 +218,7 @@ public static IImportfile Analyse(string fileContent) var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')], CultureInfo.CurrentCulture); var seconds = int.Parse(matchGroup.Value.AsSpan(matchGroup.Value.IndexOf(':') + 1, 2), CultureInfo.CurrentCulture); var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..], CultureInfo.CurrentCulture); - if (track != null) - { - track.Begin = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); - } - else - { - throw new NullReferenceException($"Track was null during input {line}"); - } + track.Begin = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { @@ -247,7 +226,7 @@ public static IImportfile Analyse(string fileContent) } audiofile?.Tracks.Add(track); } - if (regexTrackPostGap.IsMatch(line) == true) + if ((regexTrackPostGap.IsMatch(line) == true) && (track != null)) { var match = regexTrackPostGap.Match(line); recognizedLine = line.Replace(match.Value, CuesheetConstants.GetMarkedText(match.Value)); @@ -257,14 +236,7 @@ public static IImportfile Analyse(string fileContent) var minutes = int.Parse(matchGroup.Value[..matchGroup.Value.IndexOf(':')], CultureInfo.CurrentCulture); var seconds = int.Parse(matchGroup.Value.AsSpan(matchGroup.Value.IndexOf(':') + 1, 2), CultureInfo.CurrentCulture); var frames = int.Parse(matchGroup.Value[(matchGroup.Value.LastIndexOf(':') + 1)..], CultureInfo.CurrentCulture); - if (track != null) - { - track.PostGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); - } - else - { - throw new NullReferenceException($"Track was null during input {line}"); - } + track.PostGap = new TimeSpan(0, 0, minutes, seconds, Convert.ToInt32(frames / 75.0 * 1000)); } else { diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index cd490a84..871af196 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -199,8 +199,8 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) { foreach (var audiofile in audiofiles) { - Audiofile? targetAudiofile = null; - IEnumerable<ITrack>? tracks = null; + Audiofile targetAudiofile = default!; + IEnumerable<ITrack> tracks = default!; // Map uploaded import audiofiles by name var importAudiofileFound = _sessionStateContainer.ImportAudiofiles.FirstOrDefault(x => x.Name == audiofile.Name); if (importAudiofileFound != null) @@ -209,7 +209,7 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) } if (audiofile is ImportAudiofile importAudiofile) { - targetAudiofile ??= new Audiofile() + targetAudiofile = new Audiofile() { Name = importAudiofile.Name, AudioCodec = string.IsNullOrEmpty(importAudiofile.Name) == false ? _fileInputManager.GetAudioCodec(importAudiofile.Name) : null @@ -218,13 +218,9 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable<IAudiofile> audiofiles) } if (audiofile is Audiofile sourceAudiofile) { - targetAudiofile ??= new Audiofile(sourceAudiofile.Name, sourceAudiofile.ObjectURL, sourceAudiofile.AudioCodec, sourceAudiofile.Duration); + targetAudiofile = new Audiofile(sourceAudiofile.Name, sourceAudiofile.ObjectURL, sourceAudiofile.AudioCodec, sourceAudiofile.Duration); tracks = sourceAudiofile.Tracks; } - if (targetAudiofile == null || tracks == null) - { - throw new NullReferenceException(); - } IOrderedEnumerable<ITrack> sortedTracks; if (tracks.All(x => x.Position.HasValue)) { diff --git a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs index 83c0c2d5..439f8504 100644 --- a/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs +++ b/AudioCuesheetEditor/Services/UI/TraceChangeManager.cs @@ -70,17 +70,10 @@ public void Undo() if (tracedObject != null && traceAbleChange != null) { var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); - if (propertyInfo != null) - { - var currentValue = propertyInfo.GetValue(tracedObject); - redoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); - LogSettingProperty(traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); - propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); - } - else - { - throw new NullReferenceException($"Property {traceAbleChange.PropertyName} could not be found!"); - } + var currentValue = propertyInfo!.GetValue(tracedObject); + redoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); + LogSettingProperty(traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); + propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); } if (change != null) { @@ -121,17 +114,10 @@ public void Redo() if (tracedObject != null && traceAbleChange != null) { var propertyInfo = tracedObject.GetType().GetProperty(traceAbleChange.PropertyName); - if (propertyInfo != null) - { - var currentValue = propertyInfo.GetValue(tracedObject); - undoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); - LogSettingProperty(traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); - propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); - } - else - { - throw new NullReferenceException($"Property {traceAbleChange.PropertyName} could not be found!"); - } + var currentValue = propertyInfo!.GetValue(tracedObject); + undoChanges.Add(new TracedChange(tracedObject, new(currentValue, traceAbleChange.PropertyName))); + LogSettingProperty(traceAbleChange.PropertyName, tracedObject, currentValue, traceAbleChange.PreviousValue); + propertyInfo.SetValue(tracedObject, traceAbleChange.PreviousValue); } if (change != null) { From 17a8634ccd0e413ef1ad5d315361e2fa0290e264 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:59:31 +0200 Subject: [PATCH 16/20] fix tests --- .../Services/IO/TextImportServiceTests.cs | 8 ++++---- AudioCuesheetEditor/AudioCuesheetEditor.csproj | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs index c4e4dbdc..70b9d7c6 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/TextImportServiceTests.cs @@ -166,7 +166,7 @@ public async Task AnalyseAsync_InputfileWithExtraSeperator_CreatesValidCuesheetA { UseRegularExpression = true, SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[^\r\n]+)", - SchemeTracks = @"(?'Position'\d{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})" + SchemeTracks = @"(?'Position'\d{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Finish'.{1,})" }; var options = new ImportOptions { @@ -206,8 +206,8 @@ public async Task AnalyseAsync_InputfileWithSimplifiedScheme_CreatesValidCueshee var profile = new Importprofile() { UseRegularExpression = false, - SchemeCuesheet = @"Artist|Title CDTextfile", - SchemeTracks = @"Position|Artist - Title End" + SchemeCuesheet = @$"{nameof(Cuesheet.Artist)}|{nameof(Cuesheet.Title)} {nameof(Cuesheet.CDTextfile)}", + SchemeTracks = @$"{nameof(Track.Position)}|{nameof(Track.Artist)} - {nameof(Track.Title)} {nameof(Track.Finish)}" }; var options = new ImportOptions { @@ -299,7 +299,7 @@ public async Task AnalyseAsync_CuesheetWithTextfileAndCatalogueNumber_CreatesVal { UseRegularExpression = true, SchemeCuesheet = @"(?'Artist'\A.*)[|](?'Title'\w{1,})\t{1,}(?'CDTextfile'[a-zA-Z0-9_ .();äöü&:,\\]{1,})\t{1,}(?'Cataloguenumber'[^\r\n]+)", - SchemeTracks = @"(?'Position'.{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'End'.{1,})" + SchemeTracks = @"(?'Position'.{1,})[|](?'Artist'.{1,}) - (?'Title'[a-zA-Z0-9_ ]{1,})\t{1,}(?'Finish'.{1,})" }; var options = new ImportOptions { diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index 6a74a8bb..ed6119e7 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -4,7 +4,7 @@ <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData> <PackageProjectUrl>https://github.com/NeoCoderMatrix86/AudioCuesheetEditor</PackageProjectUrl> <RazorLangVersion>Latest</RazorLangVersion> - <Version>13.3.0</Version> + <Version>14.0.0</Version> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <PublishTrimmed>true</PublishTrimmed> <RunAOTCompilation>true</RunAOTCompilation> From d7f05aad008cdbfbfc951b4d648cd522467ac0eb Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 15:00:00 +0200 Subject: [PATCH 17/20] Update AudioCuesheetEditor.csproj --- AudioCuesheetEditor/AudioCuesheetEditor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index ed6119e7..c19939e2 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -21,7 +21,7 @@ <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.13" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.13" PrivateAssets="all" /> <PackageReference Include="BlazorDownloadFile" Version="2.4.0.2" /> - <PackageReference Include="Markdig" Version="1.4.1" /> + <PackageReference Include="Markdig" Version="1.4.2" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.13" /> <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="10.0.13" /> <PackageReference Include="MudBlazor" Version="9.11.0" /> From cf93d944f86ebda23db0dce4ae0683ce82ad7e6b Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 15:07:58 +0200 Subject: [PATCH 18/20] best practise corrections --- AudioCuesheetEditor.End2EndTests/Models/About.cs | 4 ++-- AudioCuesheetEditor.End2EndTests/Models/AppBar.cs | 4 ++-- AudioCuesheetEditor.End2EndTests/Models/DetailView.cs | 4 ++-- AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs | 4 ++-- AudioCuesheetEditor.End2EndTests/Models/ImportView.cs | 4 ++-- AudioCuesheetEditor.End2EndTests/Models/RecordView.cs | 4 ++-- AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Models/About.cs b/AudioCuesheetEditor.End2EndTests/Models/About.cs index 5a015b46..d5a7bb09 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/About.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/About.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -class About(IPage page) +sealed class About(IPage page) { internal const string BaseUrl = "http://localhost:5132/about"; diff --git a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs index 93d1a0c5..9d8112a2 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -partial class AppBar(IPage page) +sealed class AppBar(IPage page) { readonly IPage _page = page; internal ILocator MenuButton => _page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button, new() { Name = "More" }); diff --git a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs index 9a3de96d..75396bc0 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -class DetailView(IPage page) +sealed class DetailView(IPage page) { internal const string BaseUrl = "http://localhost:5132/"; diff --git a/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs b/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs index 40d2a194..382fb0bd 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ExportDialog.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -class ExportDialog(IPage page) +sealed class ExportDialog(IPage page) { readonly IPage _page = page; diff --git a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs index 4b353ff1..628201a4 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -partial class ImportView(IPage page, bool mobile) +sealed partial class ImportView(IPage page, bool mobile) { [GeneratedRegex("^Scheme common data$")] private static partial Regex SchemeCommonData(); diff --git a/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs b/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs index 6ac46056..2d94aac9 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/RecordView.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -class RecordView(IPage page) +sealed class RecordView(IPage page) { internal const string BaseUrl = "http://localhost:5132/"; diff --git a/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs b/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs index 58783602..e4ec4289 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ViewModes.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models; -partial class ViewModes(IPage page, bool mobile) +sealed partial class ViewModes(IPage page, bool mobile) { readonly IPage _page = page; readonly bool _isMobile = mobile; From a0601399c5b2aba73df74cf4b5ce04a9884d5f82 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 15:12:15 +0200 Subject: [PATCH 19/20] Update ProjectfileTests.cs --- AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs index 0c4fb921..203e18b9 100644 --- a/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs +++ b/AudioCuesheetEditor.Tests/Model/IO/ProjectfileTests.cs @@ -85,7 +85,7 @@ public void GenerateFile_WithoutSections_GeneratesOneFile() public void ImportFile_ValidProjectfile_ShouldImportFile() { // Arrange - var fileContent = "{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Cataloguenumber\":\"A123\",\"Audiofiles\":[{\"Name\":\"AudioFile.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:01:01\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"End\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"End\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"End\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"End\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true}]},{\"Name\":\"Other audiofile.wav\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/wav\",\"FileExtension\":\".wav\",\"Name\":\"AudioCodec WAVE\"},\"Tracks\":[{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"End\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"End\":\"00:28:28\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"End\":\"00:36:36\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"End\":\"00:45:45\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"End\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}]}],\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"}}"; + var fileContent = "{\"Artist\":\"CuesheetArtist\",\"Title\":\"CuesheetTitle\",\"Cataloguenumber\":\"A123\",\"Audiofiles\":[{\"Name\":\"AudioFile.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Artist 1\",\"Title\":\"Title 1\",\"Begin\":\"00:00:00\",\"Finish\":\"00:01:01\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":2,\"Artist\":\"Artist 2\",\"Title\":\"Title 2\",\"Begin\":\"00:01:01\",\"Finish\":\"00:03:03\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":3,\"Artist\":\"Artist 3\",\"Title\":\"Title 3\",\"Begin\":\"00:03:03\",\"Finish\":\"00:06:06\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":4,\"Artist\":\"Artist 4\",\"Title\":\"Title 4\",\"Begin\":\"00:06:06\",\"Finish\":\"00:10:10\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":5,\"Artist\":\"Artist 5\",\"Title\":\"Title 5\",\"Begin\":\"00:10:10\",\"Finish\":\"00:15:15\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true}]},{\"Name\":\"Other audiofile.wav\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/wav\",\"FileExtension\":\".wav\",\"Name\":\"AudioCodec WAVE\"},\"Tracks\":[{\"Position\":6,\"Artist\":\"Artist 6\",\"Title\":\"Title 6\",\"Begin\":\"00:15:15\",\"Finish\":\"00:21:21\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":7,\"Artist\":\"Artist 7\",\"Title\":\"Title 7\",\"Begin\":\"00:21:21\",\"Finish\":\"00:28:28\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":8,\"Artist\":\"Artist 8\",\"Title\":\"Title 8\",\"Begin\":\"00:28:28\",\"Finish\":\"00:36:36\",\"Flags\":[\"4CH\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":9,\"Artist\":\"Artist 9\",\"Title\":\"Title 9\",\"Begin\":\"00:36:36\",\"Finish\":\"00:45:45\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true},{\"Position\":10,\"Artist\":\"Artist 10\",\"Title\":\"Title 10\",\"Begin\":\"00:45:45\",\"Finish\":\"00:55:55\",\"Flags\":[\"4CH\",\"DCP\"],\"IsLinkedToPreviousTrack\":true}]}],\"CDTextfile\":{\"Name\":\"CDTextfile.cdt\"}}"; // Act var cuesheet = Projectfile.ImportFile(fileContent); // Assert From a8f90dc105132edcb4ec5a2e652498509c5e96fc Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 20 Oct 2026 16:18:20 +0200 Subject: [PATCH 20/20] corrections after renaming end to finish --- .../Sample_Project.ace | 2 +- .../Tests/Desktop/BasicTest.cs | 4 +- .../Tests/Desktop/ExportTest.cs | 4 +- .../Tests/Smartphone/BasicTest.cs | 4 +- .../Tests/Smartphone/ExportTest.cs | 4 +- .../AudioCuesheetEditor.csproj | 4 -- .../Export/EditExportProfile.de.resx | 5 ++- .../Components/Export/EditExportProfile.resx | 5 ++- .../Model/Entity/ValidationMessage.de.resx | 11 +++-- .../Model/Entity/ValidationMessage.resx | 11 +++-- .../Model/IO/Export/Exportprofile.cs | 40 ++++++++----------- .../Model/Options/DownloadOptions.cs | 2 +- .../Services/IO/ExportfileGenerator.cs | 2 +- 13 files changed, 50 insertions(+), 48 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Sample_Project.ace b/AudioCuesheetEditor.End2EndTests/Sample_Project.ace index d192e583..bbbe4c75 100644 --- a/AudioCuesheetEditor.End2EndTests/Sample_Project.ace +++ b/AudioCuesheetEditor.End2EndTests/Sample_Project.ace @@ -1 +1 @@ -{"Artist":"Sample CD Artist","Title":"Sample CD Title","Audiofiles":[{"Tracks":[{"Position":1,"Artist":"Sample Artist 1","Title":"Sample Title 1","Begin":"00:00:00","End":"00:05:00","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":2,"Artist":"Sample Artist 2","Title":"Sample Title 2","Begin":"00:05:00","End":"00:09:23","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":3,"Artist":"Sample Artist 3","Title":"Sample Title 3","Begin":"00:09:23","End":"00:15:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":4,"Artist":"Sample Artist 4","Title":"Sample Title 4","Begin":"00:15:54","End":"00:20:13","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":5,"Artist":"Sample Artist 5","Title":"Sample Title 5","Begin":"00:20:13","End":"00:24:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":6,"Artist":"Sample Artist 6","Title":"Sample Title 6","Begin":"00:24:54","End":"00:31:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":7,"Artist":"Sample Artist 7","Title":"Sample Title 7","Begin":"00:31:54","End":"00:45:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":8,"Artist":"Sample Artist 8","Title":"Sample Title 8","Begin":"00:45:54","End":"01:15:54","Flags":[],"IsLinkedToPreviousTrack":true}]}]} \ No newline at end of file +{"Artist":"Sample CD Artist","Title":"Sample CD Title","Audiofiles":[{"Tracks":[{"Position":1,"Artist":"Sample Artist 1","Title":"Sample Title 1","Begin":"00:00:00","Finish":"00:05:00","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":2,"Artist":"Sample Artist 2","Title":"Sample Title 2","Begin":"00:05:00","Finish":"00:09:23","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":3,"Artist":"Sample Artist 3","Title":"Sample Title 3","Begin":"00:09:23","Finish":"00:15:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":4,"Artist":"Sample Artist 4","Title":"Sample Title 4","Begin":"00:15:54","Finish":"00:20:13","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":5,"Artist":"Sample Artist 5","Title":"Sample Title 5","Begin":"00:20:13","Finish":"00:24:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":6,"Artist":"Sample Artist 6","Title":"Sample Title 6","Begin":"00:24:54","Finish":"00:31:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":7,"Artist":"Sample Artist 7","Title":"Sample Title 7","Begin":"00:31:54","Finish":"00:45:54","Flags":[],"IsLinkedToPreviousTrack":true},{"Position":8,"Artist":"Sample Artist 8","Title":"Sample Title 8","Begin":"00:45:54","Finish":"01:15:54","Flags":[],"IsLinkedToPreviousTrack":true}]}]} \ No newline at end of file diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs index 35f541a5..7e7d93f1 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -141,7 +141,7 @@ await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- d await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"CDTextdatei\":\r\n - paragraph: CDTextdatei\r\n - menuitem \"Katalognummer\":\r\n - paragraph: Katalognummer\r\n - menuitem \"Datum\":\r\n - paragraph: Datum\r\n - menuitem \"Datum & Uhrzeit\":\r\n - paragraph: Datum & Uhrzeit\r\n - menuitem \"Uhrzeit\":\r\n - paragraph: Uhrzeit"); await TestPage.GetByText("CDTextdatei").ClickAsync(); await exportDialog.OpenSchemeMenuAsync("Schema Titel"); - await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"End\":\r\n - paragraph: End\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); + await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"Ende\":\r\n - paragraph: Ende\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); } [TestMethod] diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs index 8a4f17e8..2af99541 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ExportTest.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -70,7 +70,7 @@ public async Task DownloadProject_GeneratesProjectFile_WhenCuesheetIsValidAsync( using var stream = await download.CreateReadStreamAsync(); using var reader = new StreamReader(stream); var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); + Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"Finish\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); } [TestMethod] diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs index 698e38ab..82f416ee 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -145,7 +145,7 @@ await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToMatchAriaSnapshotAsync(@"- d await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"CDTextdatei\":\r\n - paragraph: CDTextdatei\r\n - menuitem \"Katalognummer\":\r\n - paragraph: Katalognummer\r\n - menuitem \"Datum\":\r\n - paragraph: Datum\r\n - menuitem \"Datum & Uhrzeit\":\r\n - paragraph: Datum & Uhrzeit\r\n - menuitem \"Uhrzeit\":\r\n - paragraph: Uhrzeit"); await TestPage.GetByText("CDTextdatei").ClickAsync(); await exportDialog.OpenSchemeMenuAsync("Schema Titel"); - await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"End\":\r\n - paragraph: End\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); + await Expect(TestPage.GetByTestId("menu-wrapper")).ToMatchAriaSnapshotAsync("- menu:\r\n - menuitem \"Position\":\r\n - paragraph: Position\r\n - menuitem \"Künstler\":\r\n - paragraph: Künstler\r\n - menuitem \"Titel\":\r\n - paragraph: Titel\r\n - menuitem \"Begin\":\r\n - paragraph: Begin\r\n - menuitem \"Ende\":\r\n - paragraph: Ende\r\n - menuitem \"Länge\":\r\n - paragraph: Länge\r\n - menuitem \"Markierungen\":\r\n - paragraph: Markierungen\r\n - menuitem \"Vorlücke\":\r\n - paragraph: Vorlücke\r\n - menuitem \"Nachlücke\":\r\n - paragraph: Nachlücke"); } [TestMethod] diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs index 0ce32dc2..e67bc57c 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ExportTest.cs @@ -1,4 +1,4 @@ -//This file is part of AudioCuesheetEditor. +//This file is part of AudioCuesheetEditor. //AudioCuesheetEditor is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by @@ -72,7 +72,7 @@ public async Task DownloadProject_GeneratesProjectFile_WhenCuesheetIsValidAsync( using var stream = await download.CreateReadStreamAsync(); using var reader = new StreamReader(stream); var content = await reader.ReadToEndAsync(TestContext.CancellationToken); - Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"End\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); + Assert.AreEqual("{\"Artist\":\"Cuesheet Artist 1\",\"Title\":\"Cuesheet Title 1\",\"Audiofiles\":[{\"Name\":\"Kalimba.mp3\",\"Duration\":\"00:05:48.0608330\",\"AudioCodec\":{\"MimeType\":\"audio/mpeg\",\"FileExtension\":\".mp3\",\"Name\":\"AudioCodec MP3\"},\"Tracks\":[{\"Position\":1,\"Artist\":\"Track Artist 1\",\"Title\":\"Track Title 1\",\"Begin\":\"00:00:00\",\"Finish\":\"00:05:48.0608330\",\"Flags\":[],\"IsLinkedToPreviousTrack\":true}]}]}", content); } [TestMethod] diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index c19939e2..23277956 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -31,9 +31,5 @@ <ItemGroup> <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" /> </ItemGroup> - - <ItemGroup> - <Folder Include="Shared\" /> - </ItemGroup> </Project> diff --git a/AudioCuesheetEditor/Components/Export/EditExportProfile.de.resx b/AudioCuesheetEditor/Components/Export/EditExportProfile.de.resx index 8daa9cda..177cec34 100644 --- a/AudioCuesheetEditor/Components/Export/EditExportProfile.de.resx +++ b/AudioCuesheetEditor/Components/Export/EditExportProfile.de.resx @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <root> <!-- Microsoft ResX Schema @@ -156,6 +156,9 @@ <data name="Filename" xml:space="preserve"> <value>Dateiname</value> </data> + <data name="Finish" xml:space="preserve"> + <value>Ende</value> + </data> <data name="Flags" xml:space="preserve"> <value>Markierungen</value> </data> diff --git a/AudioCuesheetEditor/Components/Export/EditExportProfile.resx b/AudioCuesheetEditor/Components/Export/EditExportProfile.resx index f83a3659..1a28df87 100644 --- a/AudioCuesheetEditor/Components/Export/EditExportProfile.resx +++ b/AudioCuesheetEditor/Components/Export/EditExportProfile.resx @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <root> <!-- Microsoft ResX Schema @@ -156,6 +156,9 @@ <data name="Filename" xml:space="preserve"> <value>Filename</value> </data> + <data name="Finish" xml:space="preserve"> + <value>Finish</value> + </data> <data name="Flags" xml:space="preserve"> <value>Flags</value> </data> diff --git a/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx b/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx index fe1d904c..fe85f12b 100644 --- a/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx +++ b/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <root> <!-- Microsoft ResX Schema @@ -132,9 +132,6 @@ <data name="CuesheetFilename" xml:space="preserve"> <value>Cuesheetdateiname</value> </data> - <data name="End" xml:space="preserve"> - <value>Ende</value> - </data> <data name="Filename" xml:space="preserve"> <value>Dateiname</value> </data> @@ -219,4 +216,10 @@ <data name="AudioCodec" xml:space="preserve"> <value>Audio codec</value> </data> + <data name="Finish" xml:space="preserve"> + <value>Ende</value> + </data> + <data name="ProjectFilename" xml:space="preserve"> + <value>Projekt Dateiname</value> + </data> </root> \ No newline at end of file diff --git a/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx b/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx index 6546ba73..09dfc47c 100644 --- a/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx +++ b/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <root> <!-- Microsoft ResX Schema @@ -132,9 +132,6 @@ <data name="CuesheetFilename" xml:space="preserve"> <value>CuesheetFilename</value> </data> - <data name="End" xml:space="preserve"> - <value>End</value> - </data> <data name="Filename" xml:space="preserve"> <value>Filename</value> </data> @@ -219,4 +216,10 @@ <data name="AudioCodec" xml:space="preserve"> <value>Audio codec</value> </data> + <data name="Finish" xml:space="preserve"> + <value>Finish</value> + </data> + <data name="ProjectFilename" xml:space="preserve"> + <value>Project filename</value> + </data> </root> \ No newline at end of file diff --git a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs index 7dd68b49..46242a53 100644 --- a/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs +++ b/AudioCuesheetEditor/Model/IO/Export/Exportprofile.cs @@ -31,7 +31,7 @@ public class Exportprofile : Validateable public static readonly string SchemeTrackArtist = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Artist)}{SchemeCharacter}"; public static readonly string SchemeTrackTitle = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Title)}{SchemeCharacter}"; public static readonly string SchemeTrackBegin = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Begin)}{SchemeCharacter}"; - public static readonly string SchemeTrackEnd = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Finish)}{SchemeCharacter}"; + public static readonly string SchemeTrackFinish = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Finish)}{SchemeCharacter}"; public static readonly string SchemeTrackLength = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Length)}{SchemeCharacter}"; public static readonly string SchemeTrackPosition = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Position)}{SchemeCharacter}"; public static readonly string SchemeTrackFlags = $"{SchemeCharacter}{nameof(Track)}.{nameof(Track.Flags)}{SchemeCharacter}"; @@ -61,7 +61,7 @@ public class Exportprofile : Validateable { nameof(Track.Artist), SchemeTrackArtist }, { nameof(Track.Title), SchemeTrackTitle }, { nameof(Track.Begin), SchemeTrackBegin }, - { nameof(Track.Finish), SchemeTrackEnd }, + { nameof(Track.Finish), SchemeTrackFinish }, { nameof(Track.Length), SchemeTrackLength }, { nameof(Track.Flags), SchemeTrackFlags }, { nameof(Track.PreGap), SchemeTrackPreGap }, @@ -70,20 +70,14 @@ public class Exportprofile : Validateable public const string SchemeCharacter = "%"; - string _schemeHead; - string _schemeAudiofiles; - string _schemeTracks; - string _schemeFooter; - string _filename; - public Exportprofile() { Id = Guid.NewGuid(); - _schemeHead = string.Empty; - _schemeTracks = string.Empty; - _schemeAudiofiles = string.Empty; - _schemeFooter = string.Empty; - _filename = DefaultFileName; + SchemeHead = string.Empty; + SchemeTracks = string.Empty; + SchemeAudiofiles = string.Empty; + SchemeFooter = string.Empty; + Filename = DefaultFileName; var random = new Random(); Name = $"{nameof(Exportprofile)}_{random.Next(1, 100)}"; } @@ -95,28 +89,28 @@ public string Name } public string SchemeHead { - get => _schemeHead; - set { _schemeHead = value; OnValidateablePropertyChanged(); } + get; + set { field = value; OnValidateablePropertyChanged(); } } public string SchemeTracks { - get => _schemeTracks; - set { _schemeTracks = value; OnValidateablePropertyChanged(); } + get; + set { field = value; OnValidateablePropertyChanged(); } } public string SchemeAudiofiles { - get => _schemeAudiofiles; - set { _schemeAudiofiles = value; OnValidateablePropertyChanged(); } + get; + set { field = value; OnValidateablePropertyChanged(); } } public string SchemeFooter { - get => _schemeFooter; - set { _schemeFooter = value; OnValidateablePropertyChanged(); } + get; + set { field = value; OnValidateablePropertyChanged(); } } public string Filename { - get => _filename; - set { _filename = value; OnValidateablePropertyChanged(); } + get; + set { field = value; OnValidateablePropertyChanged(); } } public override ValidationResult Validate(string propertyName) diff --git a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs index 55f15f75..1d9eaff8 100644 --- a/AudioCuesheetEditor/Model/Options/DownloadOptions.cs +++ b/AudioCuesheetEditor/Model/Options/DownloadOptions.cs @@ -52,7 +52,7 @@ public string? ProjectFilename } field = value; } - } + } = Projectfile.DefaultFilename; public override ValidationResult Validate(string propertyName) { var validationStatus = ValidationStatus.NoValidation; diff --git a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs index be4612c0..08043af9 100644 --- a/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs +++ b/AudioCuesheetEditor/Services/IO/ExportfileGenerator.cs @@ -82,7 +82,7 @@ string WriteExport(Exportprofile exportprofile) .Replace(Exportprofile.SchemeTrackTitle, track.Title) .Replace(Exportprofile.SchemeTrackPosition, track.Position?.ToString(CultureInfo.CurrentCulture)) .Replace(Exportprofile.SchemeTrackBegin, track.Begin.ToString()) - .Replace(Exportprofile.SchemeTrackEnd, track.Finish.ToString()) + .Replace(Exportprofile.SchemeTrackFinish, track.Finish.ToString()) .Replace(Exportprofile.SchemeTrackLength, track.Length.ToString()) .Replace(Exportprofile.SchemeTrackFlags, string.Join(" ", track.Flags.Select(x => x.CuesheetLabel))) .Replace(Exportprofile.SchemeTrackPreGap, track.PreGap != null ? track.PreGap.Value.ToString() : string.Empty)