From e6a06915cd0b63651ce604c28b0a188a5cc10588 Mon Sep 17 00:00:00 2001 From: Macocian Alexandru Victor Date: Tue, 6 Sep 2022 15:49:07 +0200 Subject: [PATCH] Improve IHttpClient factories (#20) Codestyle fixes Setup CODEOWNERS Setup dependabot --- .editorconfig | 129 ++ .github/CODEOWNERS | 1 + .github/dependabot.yml | 16 + .../DefaultOptionsManagerTests.cs | 31 +- .../Configuration/DummyOptions.cs | 7 +- .../Configuration/LiveOptionsResolverTests.cs | 107 +- .../LiveUpdateableOptionsResolverTests.cs | 107 +- .../LiveUpdateableOptionsWrapperTests.cs | 57 +- .../Configuration/OptionsResolverTests.cs | 107 +- .../UpdateableOptionsResolverTests.cs | 107 +- .../UpdateableOptionsWrapperTests.cs | 61 +- .../Http/HttpClientBuilderTests.cs | 198 +++ .../Http/HttpClientResolverTests.cs | 105 +- .../Http/Models/HttpMessageHandlerMock.cs | 16 + .../Logging/CVLoggerProviderTests.cs | 57 +- .../Logging/CVLoggerTests.cs | 113 +- .../Logging/DebugLogsWriterTests.cs | 35 +- .../Logging/LoggerResolverTests.cs | 167 ++- .../Configuration/DefaultOptionsManager.cs | 21 +- .../Configuration/ILiveOptions.cs | 9 +- .../Configuration/ILiveUpdateableOptions.cs | 9 +- .../Configuration/IOptionsManager.cs | 15 +- .../Configuration/IUpdateableOptions.cs | 17 +- .../Configuration/LiveOptionsResolver.cs | 33 +- .../LiveUpdateableOptionsResolver.cs | 33 +- .../LiveUpdateableOptionsWrapper.cs | 45 +- .../Configuration/OptionsResolver.cs | 43 +- .../UpdateableOptionsResolver.cs | 43 +- .../Configuration/UpdateableOptionsWrapper.cs | 31 +- .../Extensions/ServiceManagerExtensions.cs | 289 +++-- .../Global.cs | 3 + .../Http/HttpClientBuilder.cs | 85 ++ .../Http/HttpClientResolver.cs | 68 +- .../Logging/CVLogger.cs | 67 +- .../Logging/CVLoggerProvider.cs | 49 +- .../Logging/DebugLogsWriter.cs | 11 +- .../Logging/ICVLoggerProvider.cs | 9 +- .../Logging/ILogsWriter.cs | 9 +- .../Logging/LoggerResolver.cs | 67 +- .../Models/Log.cs | 21 +- .../Models/TypedHttpClientFactory.cs | 8 + ...ons.NetStandard.DependencyInjection.csproj | 4 +- .../AesEncrypterTests.cs | 155 ++- .../CryptoRngProviderTests.cs | 71 +- ...8DeriveBytesPasswordHashingServiceTests.cs | 427 ++++--- .../SecureStringTests.cs | 183 ++- .../Sha256HashingServiceTests.cs | 65 +- .../Encryption/AesEncrypter.cs | 385 +++--- .../Encryption/ISymmetricEncrypter.cs | 39 +- .../Encryption/SecureString.cs | 175 ++- .../Hashing/IHashingService.cs | 13 +- .../Hashing/IPasswordHashingService.cs | 85 +- ...fc2898DeriveBytesPasswordHashingService.cs | 175 ++- .../Hashing/Sha256HashingService.cs | 99 +- .../Rng/CryptoRngProvider.cs | 91 +- .../Rng/ICryptoRngProvider.cs | 51 +- .../Utilities/NotClosingCryptoStream.cs | 25 +- .../Collections/AVLTree.cs | 695 +++++------ .../Collections/BinaryHeap.cs | 413 +++---- .../Collections/FibonacciHeap.cs | 1065 +++++++++-------- .../Collections/IQueue.cs | 69 +- .../Collections/PriorityQueue.cs | 189 ++- .../Collections/SkipList.cs | 434 +++---- .../Collections/Treap.cs | 553 ++++----- .../Extensions/BytesExtensions.cs | 33 +- .../Extensions/CastExtensions.cs | 75 +- .../Extensions/LinqExtensions.cs | 130 +- .../Extensions/LoggingExtensions.cs | 11 +- .../Extensions/ObjectExtensions.cs | 85 +- .../Extensions/Optional.cs | 285 ++--- .../Extensions/Result.cs | 405 ++++--- .../Extensions/StreamExtensions.cs | 139 ++- .../Extensions/StringExtensions.cs | 35 +- .../Extensions/TaskExtensions.cs | 339 +++--- .../Extensions/Try.cs | 103 +- .../Http/HttpClient.cs | 405 ++++--- .../Http/HttpClientEventMessage.cs | 25 +- .../Http/IHttpClient.cs | 81 +- .../Logging/ScopedLogger.cs | 119 +- .../BitStructures/Int32BitStruct.cs | 329 +++-- .../BitStructures/Int64BitStruct.cs | 391 +++--- .../SystemExtensions.NetStandard.csproj | 1 + .../Threading/PriorityThreadPool.cs | 1048 ++++++++-------- .../Collections/AVLTreeTests.cs | 277 ++--- .../Collections/BinaryHeapTests.cs | 366 +++--- .../Collections/FibonacciHeapTests.cs | 374 +++--- .../Collections/PriorityQueueTests.cs | 170 +-- .../Collections/SkipListTests.cs | 270 +++-- .../Collections/TreapTests.cs | 244 ++-- .../Extensions/OptionalTests.cs | 165 ++- .../Extensions/ResultTests.cs | 169 ++- .../Http/HttpClientTests.cs | 605 +++++----- .../Logging/Models/CachingLogger.cs | 33 +- .../Logging/ScopedLoggerTests.cs | 381 +++--- .../Structures/Int32BitStructTests.cs | 113 +- .../Structures/Int64BitStructTests.cs | 199 ++- .../Threading/PriorityThreadPoolTests.cs | 358 +++--- .../Utils/MockHttpMessageHandler.cs | 29 +- SystemExtensions.sln | 7 +- 99 files changed, 8108 insertions(+), 7558 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs create mode 100644 SystemExtensions.DependencyInjection.Tests/Http/Models/HttpMessageHandlerMock.cs create mode 100644 SystemExtensions.NetStandard.DependencyInjection/Global.cs create mode 100644 SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs create mode 100644 SystemExtensions.NetStandard.DependencyInjection/Models/TypedHttpClientFactory.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7cbcfbd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,129 @@ +[*.{cs,vb}] + +# IDE0003: Remove qualification +dotnet_diagnostic.IDE0003.severity = error +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error +dotnet_style_prefer_auto_properties = true:error +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion + +[*.cs] +csharp_indent_labels = one_less_than_current +csharp_space_around_binary_operators = before_and_after +csharp_using_directive_placement = outside_namespace:error +csharp_prefer_simple_using_statement = true:error +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = file_scoped:error +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:error +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:error +csharp_style_unused_value_assignment_preference = discard_variable:error +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_prefer_static_local_function = true:suggestion +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_parameter_null_checking = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_readonly_field = true:suggestion +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_allow_multiple_blank_lines_experimental = true:silent +dotnet_style_allow_statement_immediately_after_block_experimental = false:suggestion +dotnet_code_quality_unused_parameters = all:error +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion +dotnet_style_qualification_for_field = true:error +dotnet_style_qualification_for_property = true:error +dotnet_style_qualification_for_method = true:error +dotnet_style_qualification_for_event = true:error diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..707dc58 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* amacocian@yahoo.com \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..32f21e9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "daily" diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/DefaultOptionsManagerTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/DefaultOptionsManagerTests.cs index 06beae8..c42e5cb 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/DefaultOptionsManagerTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/DefaultOptionsManagerTests.cs @@ -2,25 +2,24 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class DefaultOptionsManagerTests { - [TestClass] - public class DefaultOptionsManagerTests + private readonly DefaultOptionsManager optionsManager = new(); + + [TestMethod] + public void GetOptions_ReturnsDefault() { - private readonly DefaultOptionsManager optionsManager = new(); + var options = this.optionsManager.GetOptions(); - [TestMethod] - public void GetOptions_ReturnsDefault() - { - var options = this.optionsManager.GetOptions(); + options.Should().BeNull(); + } - options.Should().BeNull(); - } - - [TestMethod] - public void UpdateOptions_Succeeds() - { - this.optionsManager.UpdateOptions(string.Empty); - } + [TestMethod] + public void UpdateOptions_Succeeds() + { + this.optionsManager.UpdateOptions(string.Empty); } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/DummyOptions.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/DummyOptions.cs index 06830f9..13d2d8d 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/DummyOptions.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/DummyOptions.cs @@ -1,6 +1,5 @@ -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +public sealed class DummyOptions { - public sealed class DummyOptions - { - } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/LiveOptionsResolverTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/LiveOptionsResolverTests.cs index 66a000d..aea3e30 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/LiveOptionsResolverTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/LiveOptionsResolverTests.cs @@ -4,66 +4,65 @@ using Moq; using System; using System.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class LiveOptionsResolverTests { - [TestClass] - public class LiveOptionsResolverTests + private readonly LiveOptionsResolver liveOptionsResolver = new(); + private readonly Mock serviceProviderMock = new(); + private readonly Mock optionsManagerMock = new(); + + [TestMethod] + public void CanResolve_ILiveOptions_ReturnsTrue() { - private readonly LiveOptionsResolver liveOptionsResolver = new(); - private readonly Mock serviceProviderMock = new(); - private readonly Mock optionsManagerMock = new(); + var type = typeof(ILiveOptions); - [TestMethod] - public void CanResolve_ILiveOptions_ReturnsTrue() + var canResolve = this.liveOptionsResolver.CanResolve(type); + + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_AnythingElse_ReturnsFalse() + { + var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) }; + + foreach (var type in types) { - var type = typeof(ILiveOptions); - var canResolve = this.liveOptionsResolver.CanResolve(type); - canResolve.Should().BeTrue(); - } - - [TestMethod] - public void CanResolve_AnythingElse_ReturnsFalse() - { - var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) }; - - foreach (var type in types) - { - var canResolve = this.liveOptionsResolver.CanResolve(type); - - canResolve.Should().BeFalse(); - } - } - - [TestMethod] - public void Resolve_ILiveOptions_ReturnsILiveOptions() - { - this.SetupServiceProvider(); - - var liveOptions = this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveOptions)); - - liveOptions.Should().BeAssignableTo>(); - } - - [TestMethod] - public void Resolve_AnythingElse_Throws() - { - this.SetupServiceProvider(); - - Action action = new(() => - { - this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); - }); - - action.Should().Throw(); - } - - private void SetupServiceProvider() - { - this.serviceProviderMock - .Setup(u => u.GetService()) - .Returns(this.optionsManagerMock.Object); + canResolve.Should().BeFalse(); } } + + [TestMethod] + public void Resolve_ILiveOptions_ReturnsILiveOptions() + { + this.SetupServiceProvider(); + + var liveOptions = this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveOptions)); + + liveOptions.Should().BeAssignableTo>(); + } + + [TestMethod] + public void Resolve_AnythingElse_Throws() + { + this.SetupServiceProvider(); + + Action action = new(() => + { + this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); + }); + + action.Should().Throw(); + } + + private void SetupServiceProvider() + { + this.serviceProviderMock + .Setup(u => u.GetService()) + .Returns(this.optionsManagerMock.Object); + } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsResolverTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsResolverTests.cs index ddf3984..13b1fba 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsResolverTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsResolverTests.cs @@ -4,66 +4,65 @@ using Moq; using System; using System.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class LiveUpdateableOptionsResolverTests { - [TestClass] - public class LiveUpdateableOptionsResolverTests + private readonly LiveUpdateableOptionsResolver liveUpdateableOptionsResolver = new(); + private readonly Mock serviceProviderMock = new(); + private readonly Mock optionsManagerMock = new(); + + [TestMethod] + public void CanResolve_ILiveUpdateableOptions_ReturnsTrue() { - private readonly LiveUpdateableOptionsResolver liveUpdateableOptionsResolver = new(); - private readonly Mock serviceProviderMock = new(); - private readonly Mock optionsManagerMock = new(); + var type = typeof(ILiveUpdateableOptions); - [TestMethod] - public void CanResolve_ILiveUpdateableOptions_ReturnsTrue() + var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type); + + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_AnythingElse_ReturnsFalse() + { + var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) }; + + foreach (var type in types) { - var type = typeof(ILiveUpdateableOptions); - var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type); - canResolve.Should().BeTrue(); - } - - [TestMethod] - public void CanResolve_AnythingElse_ReturnsFalse() - { - var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) }; - - foreach (var type in types) - { - var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type); - - canResolve.Should().BeFalse(); - } - } - - [TestMethod] - public void Resolve_ILiveUpdateableOptions_ReturnsILiveUpdateableOptions() - { - this.SetupServiceProvider(); - - var liveOptions = this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveUpdateableOptions)); - - liveOptions.Should().BeAssignableTo>(); - } - - [TestMethod] - public void Resolve_AnythingElse_Throws() - { - this.SetupServiceProvider(); - - Action action = new(() => - { - this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); - }); - - action.Should().Throw(); - } - - private void SetupServiceProvider() - { - this.serviceProviderMock - .Setup(u => u.GetService()) - .Returns(this.optionsManagerMock.Object); + canResolve.Should().BeFalse(); } } + + [TestMethod] + public void Resolve_ILiveUpdateableOptions_ReturnsILiveUpdateableOptions() + { + this.SetupServiceProvider(); + + var liveOptions = this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveUpdateableOptions)); + + liveOptions.Should().BeAssignableTo>(); + } + + [TestMethod] + public void Resolve_AnythingElse_Throws() + { + this.SetupServiceProvider(); + + Action action = new(() => + { + this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); + }); + + action.Should().Throw(); + } + + private void SetupServiceProvider() + { + this.serviceProviderMock + .Setup(u => u.GetService()) + .Returns(this.optionsManagerMock.Object); + } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsWrapperTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsWrapperTests.cs index 3e945f2..8ea9f96 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsWrapperTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/LiveUpdateableOptionsWrapperTests.cs @@ -3,42 +3,41 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class LiveUpdateableOptionsWrapperTests { - [TestClass] - public class LiveUpdateableOptionsWrapperTests + private LiveUpdateableOptionsWrapper optionsWrapper; + private readonly Mock optionsManagerMock = new(); + + [TestInitialize] + public void TestInitialize() { - private LiveUpdateableOptionsWrapper optionsWrapper; - private readonly Mock optionsManagerMock = new(); + this.optionsWrapper = new LiveUpdateableOptionsWrapper(this.optionsManagerMock.Object); + } - [TestInitialize] - public void TestInitialize() - { - this.optionsWrapper = new LiveUpdateableOptionsWrapper(this.optionsManagerMock.Object); - } + [TestMethod] + public void GetValue_ReturnsValue() + { + this.optionsManagerMock + .Setup(u => u.GetOptions()) + .Returns("hello"); - [TestMethod] - public void GetValue_ReturnsValue() - { - this.optionsManagerMock - .Setup(u => u.GetOptions()) - .Returns("hello"); + var value = this.optionsWrapper.Value; - var value = this.optionsWrapper.Value; + value.Should().Be("hello"); + } - value.Should().Be("hello"); - } + [TestMethod] + public void UpdateOption_CallsOptionsManager() + { + this.optionsManagerMock + .Setup(u => u.UpdateOptions(It.IsAny())) + .Verifiable(); - [TestMethod] - public void UpdateOption_CallsOptionsManager() - { - this.optionsManagerMock - .Setup(u => u.UpdateOptions(It.IsAny())) - .Verifiable(); + this.optionsWrapper.UpdateOption(); - this.optionsWrapper.UpdateOption(); - - this.optionsManagerMock.Verify(); - } + this.optionsManagerMock.Verify(); } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/OptionsResolverTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/OptionsResolverTests.cs index 82125ac..8d5d8bd 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/OptionsResolverTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/OptionsResolverTests.cs @@ -5,67 +5,66 @@ using Moq; using System; using System.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class OptionsResolverTests { - [TestClass] - public class OptionsResolverTests + private readonly OptionsResolver optionsResolver = new(); + private readonly Mock serviceProviderMock = new(); + + public Mock OptionsManagerMock { get; } = new(); + + [TestMethod] + public void CanResolve_ILiveOptions_ReturnsTrue() { - private readonly OptionsResolver optionsResolver = new(); - private readonly Mock serviceProviderMock = new(); + var type = typeof(IOptions); - public Mock OptionsManagerMock { get; } = new(); + var canResolve = this.optionsResolver.CanResolve(type); - [TestMethod] - public void CanResolve_ILiveOptions_ReturnsTrue() + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_AnythingElse_ReturnsFalse() + { + var types = new Type[] { typeof(object), typeof(string), typeof(OptionsResolverTests), typeof(int) }; + + foreach (var type in types) { - var type = typeof(IOptions); - var canResolve = this.optionsResolver.CanResolve(type); - canResolve.Should().BeTrue(); - } - - [TestMethod] - public void CanResolve_AnythingElse_ReturnsFalse() - { - var types = new Type[] { typeof(object), typeof(string), typeof(OptionsResolverTests), typeof(int) }; - - foreach (var type in types) - { - var canResolve = this.optionsResolver.CanResolve(type); - - canResolve.Should().BeFalse(); - } - } - - [TestMethod] - public void Resolve_IOptions_ReturnsIOptions() - { - this.SetupServiceProvider(); - - var liveOptions = this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IOptions)); - - liveOptions.Should().BeAssignableTo>(); - } - - [TestMethod] - public void Resolve_AnythingElse_Throws() - { - this.SetupServiceProvider(); - - Action action = new(() => - { - this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); - }); - - action.Should().Throw(); - } - - private void SetupServiceProvider() - { - this.serviceProviderMock - .Setup(u => u.GetService()) - .Returns(this.OptionsManagerMock.Object); + canResolve.Should().BeFalse(); } } + + [TestMethod] + public void Resolve_IOptions_ReturnsIOptions() + { + this.SetupServiceProvider(); + + var liveOptions = this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IOptions)); + + liveOptions.Should().BeAssignableTo>(); + } + + [TestMethod] + public void Resolve_AnythingElse_Throws() + { + this.SetupServiceProvider(); + + Action action = new(() => + { + this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); + }); + + action.Should().Throw(); + } + + private void SetupServiceProvider() + { + this.serviceProviderMock + .Setup(u => u.GetService()) + .Returns(this.OptionsManagerMock.Object); + } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsResolverTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsResolverTests.cs index 7f946ff..ad27069 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsResolverTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsResolverTests.cs @@ -4,66 +4,65 @@ using Moq; using System; using System.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class UpdateableOptionsResolverTests { - [TestClass] - public class UpdateableOptionsResolverTests + private readonly UpdateableOptionsResolver updateableOptionsResolver = new(); + private readonly Mock serviceProviderMock = new(); + private readonly Mock optionsManagerMock = new(); + + [TestMethod] + public void CanResolve_ILiveOptions_ReturnsTrue() { - private readonly UpdateableOptionsResolver updateableOptionsResolver = new(); - private readonly Mock serviceProviderMock = new(); - private readonly Mock optionsManagerMock = new(); + var type = typeof(IUpdateableOptions); - [TestMethod] - public void CanResolve_ILiveOptions_ReturnsTrue() + var canResolve = this.updateableOptionsResolver.CanResolve(type); + + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_AnythingElse_ReturnsFalse() + { + var types = new Type[] { typeof(object), typeof(string), typeof(UpdateableOptionsResolverTests), typeof(int) }; + + foreach (var type in types) { - var type = typeof(IUpdateableOptions); - var canResolve = this.updateableOptionsResolver.CanResolve(type); - canResolve.Should().BeTrue(); - } - - [TestMethod] - public void CanResolve_AnythingElse_ReturnsFalse() - { - var types = new Type[] { typeof(object), typeof(string), typeof(UpdateableOptionsResolverTests), typeof(int) }; - - foreach (var type in types) - { - var canResolve = this.updateableOptionsResolver.CanResolve(type); - - canResolve.Should().BeFalse(); - } - } - - [TestMethod] - public void Resolve_IUpdateableOptions_ReturnsIUpdateableOptions() - { - this.SetupServiceProvider(); - - var liveOptions = this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IUpdateableOptions)); - - liveOptions.Should().BeAssignableTo>(); - } - - [TestMethod] - public void Resolve_AnythingElse_Throws() - { - this.SetupServiceProvider(); - - Action action = new(() => - { - this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); - }); - - action.Should().Throw(); - } - - private void SetupServiceProvider() - { - this.serviceProviderMock - .Setup(u => u.GetService()) - .Returns(this.optionsManagerMock.Object); + canResolve.Should().BeFalse(); } } + + [TestMethod] + public void Resolve_IUpdateableOptions_ReturnsIUpdateableOptions() + { + this.SetupServiceProvider(); + + var liveOptions = this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IUpdateableOptions)); + + liveOptions.Should().BeAssignableTo>(); + } + + [TestMethod] + public void Resolve_AnythingElse_Throws() + { + this.SetupServiceProvider(); + + Action action = new(() => + { + this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); + }); + + action.Should().Throw(); + } + + private void SetupServiceProvider() + { + this.serviceProviderMock + .Setup(u => u.GetService()) + .Returns(this.optionsManagerMock.Object); + } } diff --git a/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsWrapperTests.cs b/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsWrapperTests.cs index 6db1642..cbd029c 100644 --- a/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsWrapperTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Configuration/UpdateableOptionsWrapperTests.cs @@ -5,44 +5,43 @@ using System; using System.Configuration; using System.Extensions.Configuration; -namespace SystemExtensions.DependencyInjection.Tests.Configuration +namespace SystemExtensions.DependencyInjection.Tests.Configuration; + +[TestClass] +public class UpdateableOptionsWrapperTests { - [TestClass] - public class UpdateableOptionsWrapperTests + private const string Value = "hello"; + + private UpdateableOptionsWrapper optionsWrapper; + private readonly Mock optionsManagerMock = new(); + + [TestInitialize] + public void TestInitialize() { - private const string Value = "hello"; + this.optionsWrapper = new UpdateableOptionsWrapper(this.optionsManagerMock.Object, Value); + } - private UpdateableOptionsWrapper optionsWrapper; - private readonly Mock optionsManagerMock = new(); + [TestMethod] + public void GetValue_ReturnsValue() + { + this.optionsManagerMock + .Setup(u => u.GetOptions()) + .Throws(); - [TestInitialize] - public void TestInitialize() - { - this.optionsWrapper = new UpdateableOptionsWrapper(optionsManagerMock.Object, Value); - } + var value = this.optionsWrapper.Value; - [TestMethod] - public void GetValue_ReturnsValue() - { - this.optionsManagerMock - .Setup(u => u.GetOptions()) - .Throws(); + value.Should().Be(Value); + } - var value = this.optionsWrapper.Value; + [TestMethod] + public void UpdateOption_CallsOptionsManager() + { + this.optionsManagerMock + .Setup(u => u.UpdateOptions(It.IsAny())) + .Verifiable(); - value.Should().Be(Value); - } + this.optionsWrapper.UpdateOption(); - [TestMethod] - public void UpdateOption_CallsOptionsManager() - { - this.optionsManagerMock - .Setup(u => u.UpdateOptions(It.IsAny())) - .Verifiable(); - - this.optionsWrapper.UpdateOption(); - - this.optionsManagerMock.Verify(); - } + this.optionsManagerMock.Verify(); } } diff --git a/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs b/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs new file mode 100644 index 0000000..112b127 --- /dev/null +++ b/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs @@ -0,0 +1,198 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Slim; +using System; +using System.DependencyInjection.Http; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using SystemExtensions.NetStandard.DependencyInjection.Tests.Http.Models; + +namespace SystemExtensions.NetStandard.DependencyInjection.Tests.Http; + +[TestClass] +public sealed class HttpClientBuilderTests +{ + private const string SomeHeader = "SomeHeader"; + private const string SomeValue = "SomeValue"; + + private readonly HttpClientBuilder httpClientBuilder; + private readonly Mock serviceProducerMock = new(); + private readonly Uri baseAddress = new("http://contoso.co"); + + public HttpClientBuilderTests() + { + this.httpClientBuilder = new HttpClientBuilder(this.serviceProducerMock.Object); + } + + [TestMethod] + public void Constructor_NullServiceProducer_Throws() + { + var action = () => new HttpClientBuilder(null); + + action.Should().Throw(); + } + + [TestMethod] + public void WithMessageHandler_NullHandler_Throws() + { + var action = () => this.httpClientBuilder.WithMessageHandler(null); + + action.Should().Throw(); + } + + [TestMethod] + public void WithBaseAddress_NullBaseAddress_Throws() + { + var action = () => this.httpClientBuilder.WithBaseAddress(null); + + action.Should().Throw(); + } + + [TestMethod] + public void WithDefaultRequestHeadersSetup_NullSetup_Throws() + { + var action = () => this.httpClientBuilder.WithDefaultRequestHeadersSetup(null); + + action.Should().Throw(); + } + + [TestMethod] + public void Build_ReturnsServiceProducer() + { + var producer = this.httpClientBuilder.Build(); + + producer.Should().Be(this.serviceProducerMock.Object); + } + + [TestMethod] + public void Build_RegistersWithServiceProducer() + { + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)); + + this.httpClientBuilder.Build(); + + this.serviceProducerMock.Verify(); + } + + [TestMethod] + public void Build_CreatesExpectedClient() + { + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)) + .Callback>, bool>((factory, _) => + { + var client = factory(new Mock().Object); + client.BaseAddress.Should().BeNull(); + client.DefaultRequestHeaders.Should().BeEmpty(); + client.MaxResponseContentBufferSize.Should().Be(2147483647L); + client.Timeout.Should().Be(TimeSpan.FromSeconds(100)); + }); + + this.httpClientBuilder.Build(); + } + + [TestMethod] + public void Build_WithBaseAddress_ReturnsClientWithBaseAddress() + { + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)) + .Callback>, bool>((factory, _) => + { + var client = factory(new Mock().Object); + client.BaseAddress.Should().Be(this.baseAddress); + }); + + this.httpClientBuilder.WithBaseAddress(this.baseAddress) + .Build(); + } + + [TestMethod] + public void Build_WithDefaultRequestHeaders_CallsFactory() + { + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)) + .Callback>, bool>((factory, _) => + { + var client = factory(new Mock().Object); + client.DefaultRequestHeaders.TryGetValues(SomeHeader, out var values); + + values.Should().HaveCount(1); + values.FirstOrDefault().Should().Be(SomeValue); + }); + + this.httpClientBuilder.WithDefaultRequestHeadersSetup((headers) => + { + headers.TryAddWithoutValidation(SomeHeader, SomeValue); + }).Build(); + } + + [TestMethod] + public void Build_WithMaxResponseBufferSize_ReturnsClientWithMaxResponseBufferSize() + { + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)) + .Callback>, bool>((factory, _) => + { + var client = factory(new Mock().Object); + client.MaxResponseContentBufferSize.Should().Be(100); + }); + + this.httpClientBuilder.WithMaxResponseBufferSize(100) + .Build(); + } + + [TestMethod] + public void Build_WithTimeout_ReturnsClientWithTimeout() + { + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)) + .Callback>, bool>((factory, _) => + { + var client = factory(new Mock().Object); + client.Timeout.Should().Be(TimeSpan.FromSeconds(5)); + }); + + this.httpClientBuilder.WithTimeout(TimeSpan.FromSeconds(5)) + .Build(); + } + + [TestMethod] + public void Build_WithMessageHandler_CallsMessageHandler() + { + var handlerMock = new HttpMessageHandlerMock(); + this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny>>(), false)) + .Callback>, bool>(async (factory, _) => + { + var client = factory(new Mock().Object); + await client.GetAsync(this.baseAddress); + handlerMock.Called.Should().BeTrue(); + }); + + this.httpClientBuilder.WithMessageHandler(handlerMock) + .Build(); + } + + [TestMethod] + public async Task HttpClientBuilder_RegistersClientCorrectly_IServiceProviderReturnsExpected() + { + var container = new ServiceManager(); + var messageHandler = new HttpMessageHandlerMock(); + new HttpClientBuilder(container) + .WithBaseAddress(this.baseAddress) + .WithDefaultRequestHeadersSetup(header => header.TryAddWithoutValidation(SomeHeader, SomeValue)) + .WithMaxResponseBufferSize(5) + .WithMessageHandler(messageHandler) + .WithTimeout(TimeSpan.FromSeconds(5)) + .Build(); + + var client = container.GetService>(); + await client.GetAsync(""); + + client.Should().NotBeNull(); + client.BaseAddress.Should().Be(this.baseAddress); + client.DefaultRequestHeaders.Should().HaveCount(1); + client.DefaultRequestHeaders.First().Key.Should().Be(SomeHeader); + client.DefaultRequestHeaders.First().Value.Should().HaveCount(1); + client.DefaultRequestHeaders.First().Value.First().Should().Be(SomeValue); + client.MaxResponseContentBufferSize.Should().Be(5); + client.Timeout.Should().Be(TimeSpan.FromSeconds(5)); + messageHandler.Called.Should().BeTrue(); + } +} diff --git a/SystemExtensions.DependencyInjection.Tests/Http/HttpClientResolverTests.cs b/SystemExtensions.DependencyInjection.Tests/Http/HttpClientResolverTests.cs index 9ba798c..a7ebb7d 100644 --- a/SystemExtensions.DependencyInjection.Tests/Http/HttpClientResolverTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Http/HttpClientResolverTests.cs @@ -5,65 +5,64 @@ using System; using System.Http; using System.Net.Http; -namespace SystemExtensions.DependencyInjection.Tests.Http +namespace SystemExtensions.DependencyInjection.Tests.Http; + +[TestClass] +public class HttpClientResolverTests { - [TestClass] - public class HttpClientResolverTests + private readonly HttpClientResolver httpClientResolver = new(); + private readonly Mock serviceProviderMock = new(); + + [TestMethod] + public void CanResolve_IHttpClient_ReturnsTrue() { - private readonly HttpClientResolver httpClientResolver = new(); - private readonly Mock serviceProviderMock = new(); + var type = typeof(IHttpClient<>); - [TestMethod] - public void CanResolve_IHttpClient_ReturnsTrue() + var canResolve = this.httpClientResolver.CanResolve(type); + + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_AnythingElse_ReturnsFalse() + { + var types = new Type[] { typeof(HttpClient), typeof(object), typeof(string), typeof(HttpClientResolverTests), typeof(int) }; + + foreach (var type in types) { - var type = typeof(IHttpClient<>); - var canResolve = this.httpClientResolver.CanResolve(type); - canResolve.Should().BeTrue(); - } - - [TestMethod] - public void CanResolve_AnythingElse_ReturnsFalse() - { - var types = new Type[] { typeof(HttpClient), typeof(object), typeof(string), typeof(HttpClientResolverTests), typeof(int) }; - - foreach (var type in types) - { - var canResolve = this.httpClientResolver.CanResolve(type); - - canResolve.Should().BeFalse(); - } - } - - [TestMethod] - public void Resolve_TypedClient_ReturnsIHttpClient() - { - var client = this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient)); - - client.Should().BeAssignableTo>(); - } - - [TestMethod] - public void Resolve_NonGenericType_Throws() - { - Action action = new(() => - { - this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<>)); - }); - - action.Should().Throw(); - } - - [TestMethod] - public void Resolve_RandomType_Throws() - { - Action action = new(() => - { - this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); - }); - - action.Should().Throw(); + canResolve.Should().BeFalse(); } } + + [TestMethod] + public void Resolve_TypedClient_ReturnsIHttpClient() + { + var client = this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient)); + + client.Should().BeAssignableTo>(); + } + + [TestMethod] + public void Resolve_NonGenericType_Throws() + { + Action action = new(() => + { + this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<>)); + }); + + action.Should().Throw(); + } + + [TestMethod] + public void Resolve_RandomType_Throws() + { + Action action = new(() => + { + this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); + }); + + action.Should().Throw(); + } } diff --git a/SystemExtensions.DependencyInjection.Tests/Http/Models/HttpMessageHandlerMock.cs b/SystemExtensions.DependencyInjection.Tests/Http/Models/HttpMessageHandlerMock.cs new file mode 100644 index 0000000..6f6e2be --- /dev/null +++ b/SystemExtensions.DependencyInjection.Tests/Http/Models/HttpMessageHandlerMock.cs @@ -0,0 +1,16 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace SystemExtensions.NetStandard.DependencyInjection.Tests.Http.Models; +public sealed class HttpMessageHandlerMock : HttpMessageHandler +{ + public bool Called { get; private set; } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + this.Called = true; + + return Task.FromResult(new HttpResponseMessage()); + } +} diff --git a/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerProviderTests.cs b/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerProviderTests.cs index 03a6efc..0b69dde 100644 --- a/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerProviderTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerProviderTests.cs @@ -3,41 +3,40 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System.Logging; -namespace SystemExtensions.DependencyInjection.Tests.Logging +namespace SystemExtensions.DependencyInjection.Tests.Logging; + +[TestClass] +public class CVLoggerProviderTests { - [TestClass] - public class CVLoggerProviderTests + private readonly Mock logsWriterMock = new(); + private CVLoggerProvider cVLoggerProvider; + + [TestInitialize] + public void TestInitialize() { - private readonly Mock logsWriterMock = new(); - private CVLoggerProvider cVLoggerProvider; + this.cVLoggerProvider = new CVLoggerProvider(this.logsWriterMock.Object); + } - [TestInitialize] - public void TestInitialize() - { - this.cVLoggerProvider = new CVLoggerProvider(this.logsWriterMock.Object); - } + [TestMethod] + public void CreateLogger_CreatesNewLogger() + { + var logger = this.cVLoggerProvider.CreateLogger(string.Empty); - [TestMethod] - public void CreateLogger_CreatesNewLogger() - { - var logger = this.cVLoggerProvider.CreateLogger(string.Empty); + logger.Should().NotBeNull(); + } - logger.Should().NotBeNull(); - } + [TestMethod] + public void LogEntry_CallsLogWriter() + { + this.cVLoggerProvider.LogEntry(new Log()); - [TestMethod] - public void LogEntry_CallsLogWriter() - { - this.cVLoggerProvider.LogEntry(new Log()); + this.logsWriterMock.Verify(); + } - this.logsWriterMock.Verify(); - } - - private void SetupLogsWriter() - { - this.logsWriterMock - .Setup(u => u.WriteLog(It.IsAny())) - .Verifiable(); - } + private void SetupLogsWriter() + { + this.logsWriterMock + .Setup(u => u.WriteLog(It.IsAny())) + .Verifiable(); } } diff --git a/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerTests.cs b/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerTests.cs index 91f2657..1beee90 100644 --- a/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Logging/CVLoggerTests.cs @@ -5,72 +5,71 @@ using Moq; using System; using System.Logging; -namespace SystemExtensions.DependencyInjection.Tests.Logging +namespace SystemExtensions.DependencyInjection.Tests.Logging; + +[TestClass] +public class CVLoggerTests { - [TestClass] - public class CVLoggerTests + private readonly Mock cvLoggerProviderMock = new(); + private CVLogger cVLogger; + + [TestInitialize] + public void TestInitialize() { - private readonly Mock cvLoggerProviderMock = new(); - private CVLogger cVLogger; + this.cVLogger = new CVLogger(string.Empty, this.cvLoggerProviderMock.Object); + } - [TestInitialize] - public void TestInitialize() + [TestMethod] + public void BeginScope_ReturnsNull() + { + var scope = this.cVLogger.BeginScope(string.Empty); + + scope.Should().BeNull(); + } + + [TestMethod] + [DataRow(LogLevel.Debug)] + [DataRow(LogLevel.Trace)] + [DataRow(LogLevel.Information)] + [DataRow(LogLevel.Warning)] + [DataRow(LogLevel.Error)] + [DataRow(LogLevel.Critical)] + public void IsEnabled_OnAllLogLevels_ReturnsTrue(LogLevel logLevel) + { + var enabled = this.cVLogger.IsEnabled(logLevel); + + enabled.Should().BeTrue(); + } + + [TestMethod] + public void Log_CallsFormatter() + { + var called = false; + Func messageFormatter = new((state, exception) => { - this.cVLogger = new CVLogger(string.Empty, this.cvLoggerProviderMock.Object); - } + called = true; + return string.Empty; + }); - [TestMethod] - public void BeginScope_ReturnsNull() - { - var scope = this.cVLogger.BeginScope(string.Empty); + this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), messageFormatter); - scope.Should().BeNull(); - } + called.Should().BeTrue(); + } - [TestMethod] - [DataRow(LogLevel.Debug)] - [DataRow(LogLevel.Trace)] - [DataRow(LogLevel.Information)] - [DataRow(LogLevel.Warning)] - [DataRow(LogLevel.Error)] - [DataRow(LogLevel.Critical)] - public void IsEnabled_OnAllLogLevels_ReturnsTrue(LogLevel logLevel) - { - var enabled = this.cVLogger.IsEnabled(logLevel); + [TestMethod] + public void Log_CallsLogsProvider() + { + this.SetupLoggerProvider(); - enabled.Should().BeTrue(); - } + this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), new Func((s, e) => string.Empty)); - [TestMethod] - public void Log_CallsFormatter() - { - var called = false; - Func messageFormatter = new((state, exception) => - { - called = true; - return string.Empty; - }); + this.cvLoggerProviderMock.Verify(); + } - this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), messageFormatter); - - called.Should().BeTrue(); - } - - [TestMethod] - public void Log_CallsLogsProvider() - { - this.SetupLoggerProvider(); - - this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), new Func((s, e) => string.Empty)); - - this.cvLoggerProviderMock.Verify(); - } - - private void SetupLoggerProvider() - { - this.cvLoggerProviderMock - .Setup(u => u.LogEntry(It.IsAny())) - .Verifiable(); - } + private void SetupLoggerProvider() + { + this.cvLoggerProviderMock + .Setup(u => u.LogEntry(It.IsAny())) + .Verifiable(); } } diff --git a/SystemExtensions.DependencyInjection.Tests/Logging/DebugLogsWriterTests.cs b/SystemExtensions.DependencyInjection.Tests/Logging/DebugLogsWriterTests.cs index 8a0a4c4..26556a8 100644 --- a/SystemExtensions.DependencyInjection.Tests/Logging/DebugLogsWriterTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Logging/DebugLogsWriterTests.cs @@ -3,28 +3,27 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Logging; -namespace SystemExtensions.DependencyInjection.Tests.Logging +namespace SystemExtensions.DependencyInjection.Tests.Logging; + +[TestClass] +public class DebugLogsWriterTests { - [TestClass] - public class DebugLogsWriterTests + private readonly DebugLogsWriter logsWriter = new(); + + [TestMethod] + public void WriteLog_Succeeds() { - private readonly DebugLogsWriter logsWriter = new(); + this.logsWriter.WriteLog(new Log()); + } - [TestMethod] - public void WriteLog_Succeeds() + [TestMethod] + public void WriteNullLog_Throws() + { + Action action = new(() => { - this.logsWriter.WriteLog(new Log()); - } + this.logsWriter.WriteLog(null); + }); - [TestMethod] - public void WriteNullLog_Throws() - { - Action action = new(() => - { - this.logsWriter.WriteLog(null); - }); - - action.Should().Throw(); - } + action.Should().Throw(); } } diff --git a/SystemExtensions.DependencyInjection.Tests/Logging/LoggerResolverTests.cs b/SystemExtensions.DependencyInjection.Tests/Logging/LoggerResolverTests.cs index c82aaf2..91a4fa1 100644 --- a/SystemExtensions.DependencyInjection.Tests/Logging/LoggerResolverTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Logging/LoggerResolverTests.cs @@ -5,104 +5,103 @@ using Moq; using System; using System.Logging; -namespace SystemExtensions.DependencyInjection.Tests.Logging +namespace SystemExtensions.DependencyInjection.Tests.Logging; + +[TestClass] +public class LoggerResolverTests { - [TestClass] - public class LoggerResolverTests + private readonly Mock serviceProviderMock = new(); + private readonly Mock loggerFactoryMock = new(); + private readonly Mock loggerMock = new(); + private readonly LoggerResolver loggerResolver = new(); + + [TestMethod] + public void CanResolve_ILogger_ReturnsTrue() { - private readonly Mock serviceProviderMock = new(); - private readonly Mock loggerFactoryMock = new(); - private readonly Mock loggerMock = new(); - private readonly LoggerResolver loggerResolver = new(); + var type = typeof(ILogger); - [TestMethod] - public void CanResolve_ILogger_ReturnsTrue() + var canResolve = this.loggerResolver.CanResolve(type); + + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_GenericILogger_ReturnsTrue() + { + var type = typeof(ILogger); + + var canResolve = this.loggerResolver.CanResolve(type); + + canResolve.Should().BeTrue(); + } + + [TestMethod] + public void CanResolve_AnythingElse_ReturnsFalse() + { + var types = new Type[] { typeof(CVLogger), typeof(object), typeof(string), typeof(LoggerResolverTests), typeof(int) }; + + foreach(var type in types) { - var type = typeof(ILogger); - var canResolve = this.loggerResolver.CanResolve(type); - canResolve.Should().BeTrue(); - } + canResolve.Should().BeFalse(); + } + } - [TestMethod] - public void CanResolve_GenericILogger_ReturnsTrue() + [TestMethod] + public void Resolve_ILogger_ReturnsILogger() + { + this.SetupIServiceProvider(); + + var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger)); + + logger.Should().BeAssignableTo(); + } + + [TestMethod] + public void Resolve_TypedILogger_ReturnsTypedILogger() + { + this.SetupIServiceProvider(); + + var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger)); + + logger.Should().BeAssignableTo>(); + } + + [TestMethod] + public void Resolve_RandomType_Throws() + { + this.SetupIServiceProvider(); + + Action action = new(() => { - var type = typeof(ILogger); + this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); + }); - var canResolve = this.loggerResolver.CanResolve(type); + action.Should().Throw(); + } - canResolve.Should().BeTrue(); - } + [TestMethod] + public void Resolve_NonTypedGeneric_Throws() + { + this.SetupIServiceProvider(); - [TestMethod] - public void CanResolve_AnythingElse_ReturnsFalse() + Action action = new(() => { - var types = new Type[] { typeof(CVLogger), typeof(object), typeof(string), typeof(LoggerResolverTests), typeof(int) }; + this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<>)); + }); - foreach(var type in types) - { - var canResolve = this.loggerResolver.CanResolve(type); + action.Should().Throw(); + } - canResolve.Should().BeFalse(); - } - } + private void SetupIServiceProvider() + { + this.serviceProviderMock + .Setup(u => u.GetService()) + .Returns(this.loggerFactoryMock.Object); - [TestMethod] - public void Resolve_ILogger_ReturnsILogger() - { - this.SetupIServiceProvider(); - - var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger)); - - logger.Should().BeAssignableTo(); - } - - [TestMethod] - public void Resolve_TypedILogger_ReturnsTypedILogger() - { - this.SetupIServiceProvider(); - - var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger)); - - logger.Should().BeAssignableTo>(); - } - - [TestMethod] - public void Resolve_RandomType_Throws() - { - this.SetupIServiceProvider(); - - Action action = new(() => - { - this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(string)); - }); - - action.Should().Throw(); - } - - [TestMethod] - public void Resolve_NonTypedGeneric_Throws() - { - this.SetupIServiceProvider(); - - Action action = new(() => - { - this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<>)); - }); - - action.Should().Throw(); - } - - private void SetupIServiceProvider() - { - this.serviceProviderMock - .Setup(u => u.GetService()) - .Returns(this.loggerFactoryMock.Object); - - this.loggerFactoryMock - .Setup(u => u.CreateLogger(It.IsAny())) - .Returns(this.loggerMock.Object); - } + this.loggerFactoryMock + .Setup(u => u.CreateLogger(It.IsAny())) + .Returns(this.loggerMock.Object); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/DefaultOptionsManager.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/DefaultOptionsManager.cs index b6553a8..96145a7 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/DefaultOptionsManager.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/DefaultOptionsManager.cs @@ -1,14 +1,13 @@ -namespace System.Configuration -{ - public sealed class DefaultOptionsManager : IOptionsManager - { - public T GetOptions() where T : class - { - return default; - } +namespace System.Configuration; - public void UpdateOptions(T value) where T : class - { - } +public sealed class DefaultOptionsManager : IOptionsManager +{ + public T GetOptions() where T : class + { + return default; + } + + public void UpdateOptions(T value) where T : class + { } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveOptions.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveOptions.cs index 24c73cb..e88c193 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveOptions.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveOptions.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.Options; -namespace System.Configuration +namespace System.Configuration; + +public interface ILiveOptions : IOptions + where T : class { - public interface ILiveOptions : IOptions - where T : class - { - } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveUpdateableOptions.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveUpdateableOptions.cs index cd637a9..1d498a8 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveUpdateableOptions.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/ILiveUpdateableOptions.cs @@ -1,7 +1,6 @@ -namespace System.Configuration +namespace System.Configuration; + +public interface ILiveUpdateableOptions : ILiveOptions, IUpdateableOptions + where T : class { - public interface ILiveUpdateableOptions : ILiveOptions, IUpdateableOptions - where T : class - { - } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/IOptionsManager.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/IOptionsManager.cs index a04b16e..5c69a9e 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/IOptionsManager.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/IOptionsManager.cs @@ -1,10 +1,9 @@ -namespace System.Configuration +namespace System.Configuration; + +public interface IOptionsManager { - public interface IOptionsManager - { - T GetOptions() - where T : class; - void UpdateOptions(T value) - where T : class; - } + T GetOptions() + where T : class; + void UpdateOptions(T value) + where T : class; } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/IUpdateableOptions.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/IUpdateableOptions.cs index 2a26a37..ce1a7ca 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/IUpdateableOptions.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/IUpdateableOptions.cs @@ -1,13 +1,12 @@ using Microsoft.Extensions.Options; -namespace System.Configuration +namespace System.Configuration; + +public interface IUpdateableOptions : IOptions + where T : class { - public interface IUpdateableOptions : IOptions - where T : class - { - /// - /// Updates the configuration with the current value stored in . - /// - void UpdateOption(); - } + /// + /// Updates the configuration with the current value stored in . + /// + void UpdateOption(); } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveOptionsResolver.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveOptionsResolver.cs index 153413d..0b5366e 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveOptionsResolver.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveOptionsResolver.cs @@ -1,27 +1,26 @@ using Slim.Resolvers; -namespace System.Configuration +namespace System.Configuration; + +public sealed class LiveOptionsResolver : IDependencyResolver { - public sealed class LiveOptionsResolver : IDependencyResolver + private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>); + + public bool CanResolve(Type type) { - private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>); - - public bool CanResolve(Type type) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>)) { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>)) - { - return true; - } - - return false; + return true; } - public object Resolve(Slim.IServiceProvider serviceProvider, Type type) - { - var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); - var configurationManager = serviceProvider.GetService(); + return false; + } - return Activator.CreateInstance(typedOptionsType, configurationManager); - } + public object Resolve(Slim.IServiceProvider serviceProvider, Type type) + { + var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); + var configurationManager = serviceProvider.GetService(); + + return Activator.CreateInstance(typedOptionsType, configurationManager); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsResolver.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsResolver.cs index 825d66e..47032b2 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsResolver.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsResolver.cs @@ -1,26 +1,25 @@ using Slim.Resolvers; -namespace System.Configuration +namespace System.Configuration; + +public sealed class LiveUpdateableOptionsResolver : IDependencyResolver { - public sealed class LiveUpdateableOptionsResolver : IDependencyResolver + private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>); + + public bool CanResolve(Type type) { - private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>); - - public bool CanResolve(Type type) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>)) { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>)) - { - return true; - } - - return false; + return true; } - public object Resolve(Slim.IServiceProvider serviceProvider, Type type) - { - var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); - var configurationManager = serviceProvider.GetService(); - return Activator.CreateInstance(typedOptionsType, configurationManager); - } + return false; + } + + public object Resolve(Slim.IServiceProvider serviceProvider, Type type) + { + var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); + var configurationManager = serviceProvider.GetService(); + return Activator.CreateInstance(typedOptionsType, configurationManager); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsWrapper.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsWrapper.cs index 971f4d0..f571dc9 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsWrapper.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/LiveUpdateableOptionsWrapper.cs @@ -1,31 +1,30 @@ using System.Extensions; -namespace System.Configuration +namespace System.Configuration; + +public sealed class LiveUpdateableOptionsWrapper : ILiveUpdateableOptions + where T : class { - public sealed class LiveUpdateableOptionsWrapper : ILiveUpdateableOptions - where T : class + private readonly IOptionsManager configurationManager; + + private T value; + + public T Value { - private readonly IOptionsManager configurationManager; - - private T value; - - public T Value + get { - get - { - this.value = this.configurationManager.GetOptions(); - return this.value; - } - } - - public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager) - { - this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager)); - } - - public void UpdateOption() - { - this.configurationManager.UpdateOptions(this.value); + this.value = this.configurationManager.GetOptions(); + return this.value; } } + + public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager) + { + this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager)); + } + + public void UpdateOption() + { + this.configurationManager.UpdateOptions(this.value); + } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/OptionsResolver.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/OptionsResolver.cs index a51941d..61e0073 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/OptionsResolver.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/OptionsResolver.cs @@ -1,33 +1,32 @@ using Microsoft.Extensions.Options; using Slim.Resolvers; -namespace System.Configuration +namespace System.Configuration; + +public sealed class OptionsResolver : IDependencyResolver { - public sealed class OptionsResolver : IDependencyResolver + private static readonly Type optionsType = typeof(OptionsWrapper<>); + private static readonly Type configurationType = typeof(IOptionsManager); + + public bool CanResolve(Type type) { - private static readonly Type optionsType = typeof(OptionsWrapper<>); - private static readonly Type configurationType = typeof(IOptionsManager); - - public bool CanResolve(Type type) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>)) { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>)) - { - return true; - } - - return false; + return true; } - public object Resolve(Slim.IServiceProvider serviceProvider, Type type) - { - var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); - var configurationManager = serviceProvider.GetService(); - var optionsValue = configurationType - .GetMethod(nameof(IOptionsManager.GetOptions)) - .MakeGenericMethod(type.GetGenericArguments()) - .Invoke(configurationManager, Array.Empty()); + return false; + } - return Activator.CreateInstance(typedOptionsType, optionsValue); - } + public object Resolve(Slim.IServiceProvider serviceProvider, Type type) + { + var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); + var configurationManager = serviceProvider.GetService(); + var optionsValue = configurationType + .GetMethod(nameof(IOptionsManager.GetOptions)) + .MakeGenericMethod(type.GetGenericArguments()) + .Invoke(configurationManager, Array.Empty()); + + return Activator.CreateInstance(typedOptionsType, optionsValue); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsResolver.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsResolver.cs index aa5236f..6554414 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsResolver.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsResolver.cs @@ -1,33 +1,32 @@ using Slim.Resolvers; using System.Extensions.Configuration; -namespace System.Configuration +namespace System.Configuration; + +public sealed class UpdateableOptionsResolver : IDependencyResolver { - public sealed class UpdateableOptionsResolver : IDependencyResolver + private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>); + private static readonly Type configurationType = typeof(IOptionsManager); + + public bool CanResolve(Type type) { - private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>); - private static readonly Type configurationType = typeof(IOptionsManager); - - public bool CanResolve(Type type) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>)) { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>)) - { - return true; - } - - return false; + return true; } - public object Resolve(Slim.IServiceProvider serviceProvider, Type type) - { - var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); - var configurationManager = serviceProvider.GetService(); - var optionsValue = configurationType - .GetMethod(nameof(IOptionsManager.GetOptions)) - .MakeGenericMethod(type.GetGenericArguments()) - .Invoke(configurationManager, Array.Empty()); + return false; + } - return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue); - } + public object Resolve(Slim.IServiceProvider serviceProvider, Type type) + { + var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments()); + var configurationManager = serviceProvider.GetService(); + var optionsValue = configurationType + .GetMethod(nameof(IOptionsManager.GetOptions)) + .MakeGenericMethod(type.GetGenericArguments()) + .Invoke(configurationManager, Array.Empty()); + + return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsWrapper.cs b/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsWrapper.cs index 9b0ba3b..7efef8b 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsWrapper.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Configuration/UpdateableOptionsWrapper.cs @@ -1,23 +1,22 @@ using System.Configuration; -namespace System.Extensions.Configuration +namespace System.Extensions.Configuration; + +public sealed class UpdateableOptionsWrapper : IUpdateableOptions + where T : class { - public sealed class UpdateableOptionsWrapper : IUpdateableOptions - where T : class + private readonly IOptionsManager configurationManager; + + public T Value { get; } + + public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options) { - private readonly IOptionsManager configurationManager; - - public T Value { get; } + this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager)); + this.Value = options; + } - public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options) - { - this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager)); - this.Value = options; - } - - public void UpdateOption() - { - this.configurationManager.UpdateOptions(this.Value); - } + public void UpdateOption() + { + this.configurationManager.UpdateOptions(this.Value); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs b/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs index ee24133..e6409a7 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs @@ -2,157 +2,188 @@ using Microsoft.Extensions.Options; using Slim; using System.Configuration; +using System.DependencyInjection.Http; using System.Http; using System.Logging; using System.Net.Http; -namespace System.Extensions +namespace System.Extensions; + +public static class ServiceManagerExtensions { - public static class ServiceManagerExtensions + /// + /// Registers a with the default . + /// This call also registers the resolver that resolves and . + /// + /// . + /// Provided . + public static IServiceProducer RegisterOptionsManager(this IServiceProducer serviceProducer) { - /// - /// Registers a with the default . - /// This call also registers the resolver that resolves and . - /// - /// . - /// Provided . - public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager) + serviceProducer.ThrowIfNull(nameof(serviceProducer)); + + serviceProducer.RegisterSingleton(); + serviceProducer.RegisterOptionsResolver(); + + return serviceProducer; + } + + /// + /// Registers a . + /// This call also registers the resolver that resolves and . + /// + /// Implementation of . + /// . + /// Provided . + public static IServiceProducer RegisterOptionsManager(this IServiceProducer serviceProducer) + where T : IOptionsManager + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); + + serviceProducer.RegisterSingleton(); + serviceProducer.RegisterOptionsResolver(); + + return serviceProducer; + } + + /// + /// Registers resolvers for and . + /// Depends on a in order to properly resolve options. + /// + /// . + /// . + public static IServiceProducer RegisterOptionsResolver(this IServiceProducer serviceProducer) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); + + serviceProducer.RegisterResolver(new OptionsResolver()); + serviceProducer.RegisterResolver(new UpdateableOptionsResolver()); + serviceProducer.RegisterResolver(new LiveOptionsResolver()); + serviceProducer.RegisterResolver(new LiveUpdateableOptionsResolver()); + + return serviceProducer; + } + + /// + /// Registers a with the default . + /// + /// Implementation of . + /// . + /// Provided . + public static IServiceProducer RegisterLogWriter(this IServiceProducer serviceManager) + where TLogsWriter : ILogsWriter + { + serviceManager.ThrowIfNull(nameof(serviceManager)); + + serviceManager.RegisterSingleton(); + serviceManager.RegisterScoped(sp => { - serviceManager.RegisterSingleton(); - serviceManager.RegisterOptionsResolver(); + var factory = new LoggerFactory(); + factory.AddProvider(new CVLoggerProvider(sp.GetService())); + return factory; + }); - return serviceManager; - } + return serviceManager; + } - /// - /// Registers a . - /// This call also registers the resolver that resolves and . - /// - /// Implementation of . - /// . - /// Provided . - public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager) - where T : IOptionsManager + /// + /// Registers a with the default . + /// + /// Interface of . + /// Implementation of . + /// . + /// Provided . + public static IServiceProducer RegisterLogWriter(this IServiceProducer serviceManager) + where TLogsWriter : TILogsWriter + where TILogsWriter : class, ILogsWriter + { + serviceManager.ThrowIfNull(nameof(serviceManager)); + + serviceManager.RegisterSingleton(); + serviceManager.RegisterScoped(sp => { - serviceManager.RegisterSingleton(); - serviceManager.RegisterOptionsResolver(); + var factory = new LoggerFactory(); + factory.AddProvider(new CVLoggerProvider(sp.GetService())); + return factory; + }); - return serviceManager; - } + return serviceManager; + } - /// - /// Registers resolvers for and . - /// Depends on a in order to properly resolve options. - /// - /// . - /// . - public static IServiceManager RegisterOptionsResolver(this IServiceManager serviceManager) + /// + /// Register a with a . + /// + /// + /// + public static IServiceProducer RegisterCVLoggerFactory(this IServiceProducer serviceProducer) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); + + serviceProducer.RegisterScoped(sp => { - serviceManager.ThrowIfNull(nameof(serviceManager)); + LoggerFactory loggerFactory = new(); + loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService())); + return loggerFactory; + }); - serviceManager.RegisterResolver(new OptionsResolver()); - serviceManager.RegisterResolver(new UpdateableOptionsResolver()); - serviceManager.RegisterResolver(new LiveOptionsResolver()); - serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver()); + return serviceProducer; + } - return serviceManager; - } + /// + /// Registers a . + /// + /// . + /// Factory that produces a . + /// + public static IServiceProducer RegisterLoggerFactory(this IServiceProducer serviceProducer, Func loggerFactory) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); - /// - /// Registers a with the default . - /// - /// Implementation of . - /// . - /// Provided . - public static IServiceProducer RegisterLogWriter(this IServiceProducer serviceManager) - where TLogsWriter : ILogsWriter - { - serviceManager.ThrowIfNull(nameof(serviceManager)); + serviceProducer.RegisterSingleton(loggerFactory); + return serviceProducer; + } - serviceManager.RegisterSingleton(); - serviceManager.RegisterScoped(sp => - { - var factory = new LoggerFactory(); - factory.AddProvider(new CVLoggerProvider(sp.GetService())); - return factory; - }); + /// + /// Registers a with a that writes to . + /// + /// . + /// + public static IServiceProducer RegisterDebugLoggerFactory(this IServiceProducer serviceProducer) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); - return serviceManager; - } + serviceProducer.RegisterLogWriter(); + return serviceProducer; + } - /// - /// Registers a with the default . - /// - /// Interface of . - /// Implementation of . - /// . - /// Provided . - public static IServiceProducer RegisterLogWriter(this IServiceProducer serviceManager) - where TLogsWriter : TILogsWriter - where TILogsWriter : class, ILogsWriter - { - serviceManager.ThrowIfNull(nameof(serviceManager)); + /// + /// Register a scoped to be used by the DI engine. + /// + /// Type of the scoped . + /// . + /// to build the http client. + public static HttpClientBuilder RegisterHttpClient(this IServiceProducer serviceProducer) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); - serviceManager.RegisterSingleton(); - serviceManager.RegisterScoped(sp => - { - var factory = new LoggerFactory(); - factory.AddProvider(new CVLoggerProvider(sp.GetService())); - return factory; - }); + return new HttpClientBuilder(serviceProducer); + } - return serviceManager; - } + [Obsolete($"{nameof(RegisterHttpFactory)} is obsolete. Please use {nameof(RegisterHttpClient)} for each service that requires an instance of {nameof(IHttpClient)}.")] + public static IServiceProducer RegisterHttpFactory(this IServiceProducer serviceProducer) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); - /// - /// Register a with a . - /// - /// - /// - public static IServiceManager RegisterCVLoggerFactory(this IServiceManager serviceManager) - { - serviceManager.RegisterScoped(sp => - { - LoggerFactory loggerFactory = new(); - loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService())); - return loggerFactory; - }); + serviceProducer.RegisterResolver(new HttpClientResolver()); + return serviceProducer; + } + [Obsolete($"{nameof(RegisterHttpFactory)} is obsolete. Please use {nameof(RegisterHttpClient)} for each service that requires an instance of {nameof(IHttpClient)}.")] + public static IServiceProducer RegisterHttpFactory(this IServiceProducer serviceProducer, Func handlerFactory) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); - return serviceManager; - } - - public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func loggerFactory) - { - serviceManager.ThrowIfNull(nameof(serviceManager)); - - serviceManager.RegisterSingleton(loggerFactory); - return serviceManager; - } - - public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager) - { - serviceManager.ThrowIfNull(nameof(serviceManager)); - - serviceManager.RegisterLogWriter(); - return serviceManager; - } - - public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager) - { - serviceManager.ThrowIfNull(nameof(serviceManager)); - - serviceManager.RegisterResolver(new HttpClientResolver()); - return serviceManager; - } - - public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager, Func handlerFactory) - { - serviceManager.ThrowIfNull(nameof(serviceManager)); - - serviceManager.RegisterResolver( - new HttpClientResolver() - .WithHttpMessageHandlerFactory(handlerFactory)); - return serviceManager; - } + serviceProducer.RegisterResolver( + new HttpClientResolver() + .WithHttpMessageHandlerFactory(handlerFactory)); + return serviceProducer; } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Global.cs b/SystemExtensions.NetStandard.DependencyInjection/Global.cs new file mode 100644 index 0000000..089cde4 --- /dev/null +++ b/SystemExtensions.NetStandard.DependencyInjection/Global.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("SystemExtensions.NetStandard.DependencyInjection.Tests")] \ No newline at end of file diff --git a/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs b/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs new file mode 100644 index 0000000..b719f86 --- /dev/null +++ b/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs @@ -0,0 +1,85 @@ +using Slim; +using System.Extensions; +using System.Net.Http; +using System.Net.Http.Headers; + +namespace System.DependencyInjection.Http; + +public sealed class HttpClientBuilder +{ + private readonly IServiceProducer serviceProducer; + + private Uri baseAddress; + private HttpMessageHandler httpMessageHandler; + private bool disposeMessageHandler; + private Action defaultRequestHeadersSetup; + private long maxResponseBufferSize = 2147483647L; //2GB default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.maxresponsecontentbuffersize?view=net-6.0] + private TimeSpan timeout = TimeSpan.FromSeconds(100); //100 seconds default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=net-6.0] + + internal HttpClientBuilder(IServiceProducer serviceProducer) + { + serviceProducer.ThrowIfNull(nameof(serviceProducer)); + + this.serviceProducer = serviceProducer; + } + + public HttpClientBuilder WithMessageHandler(HttpMessageHandler httpMessageHandler) + { + httpMessageHandler.ThrowIfNull(nameof(httpMessageHandler)); + + this.httpMessageHandler = httpMessageHandler; + return this; + } + + public HttpClientBuilder WithDisposeMessageHandler(bool disposeMessageHandler) + { + this.disposeMessageHandler = disposeMessageHandler; + return this; + } + + public HttpClientBuilder WithBaseAddress(Uri baseAddress) + { + baseAddress.ThrowIfNull(nameof(baseAddress)); + + this.baseAddress = baseAddress; + return this; + } + + public HttpClientBuilder WithDefaultRequestHeadersSetup(Action setup) + { + setup.ThrowIfNull(nameof(setup)); + + this.defaultRequestHeadersSetup = setup; + return this; + } + + public HttpClientBuilder WithMaxResponseBufferSize(long responseBufferSize) + { + this.maxResponseBufferSize = responseBufferSize; + return this; + } + + public HttpClientBuilder WithTimeout(TimeSpan timeout) + { + this.timeout = timeout; + return this; + } + + public IServiceProducer Build() + { + this.serviceProducer.RegisterScoped>(_ => + { + var client = this.httpMessageHandler is not null ? + new HttpClient(this.httpMessageHandler, this.disposeMessageHandler) : + new HttpClient(); + + client.BaseAddress = this.baseAddress; + this.defaultRequestHeadersSetup?.Invoke(client.DefaultRequestHeaders); + client.MaxResponseContentBufferSize = this.maxResponseBufferSize; + client.Timeout = this.timeout; + return client; + }); + + return this.serviceProducer; + } +} diff --git a/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientResolver.cs b/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientResolver.cs index 6cab276..ff607e5 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientResolver.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientResolver.cs @@ -2,46 +2,46 @@ using System.Linq; using System.Net.Http; -namespace System.Http +namespace System.Http; + +[Obsolete($"Please use {nameof(Extensions.ServiceManagerExtensions.RegisterHttpClient)} for each use case of {nameof(IHttpClient)}")] +public sealed class HttpClientResolver : IDependencyResolver { - public sealed class HttpClientResolver : IDependencyResolver + private static readonly Type clientType = typeof(HttpClient<>); + + /// + /// Factory method. parameter of the factory is the scope of . + /// + public Func HttpMessageHandlerFactory { get; set; } + + /// + /// Sets the . + /// + /// Factory method. parameter of the factory is the scope of . + /// + public HttpClientResolver WithHttpMessageHandlerFactory(Func factory) { - private static readonly Type clientType = typeof(HttpClient<>); + this.HttpMessageHandlerFactory = factory; + return this; + } - /// - /// Factory method. parameter of the factory is the scope of . - /// - public Func HttpMessageHandlerFactory { get; set; } - - /// - /// Sets the . - /// - /// Factory method. parameter of the factory is the scope of . - /// - public HttpClientResolver WithHttpMessageHandlerFactory(Func factory) + public bool CanResolve(Type type) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>)) { - this.HttpMessageHandlerFactory = factory; - return this; + return true; } - public bool CanResolve(Type type) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>)) - { - return true; - } + return false; + } - return false; - } - - public object Resolve(Slim.IServiceProvider serviceProvider, Type type) - { - var typedClientType = clientType.MakeGenericType(type.GetGenericArguments()); - var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First()); - var httpClient = handler is null ? - Activator.CreateInstance(typedClientType) : - Activator.CreateInstance(typedClientType, new object[] { handler }); - return httpClient; - } + public object Resolve(Slim.IServiceProvider serviceProvider, Type type) + { + var typedClientType = clientType.MakeGenericType(type.GetGenericArguments()); + var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First()); + var httpClient = handler is null ? + Activator.CreateInstance(typedClientType) : + Activator.CreateInstance(typedClientType, new object[] { handler }); + return httpClient; } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLogger.cs b/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLogger.cs index 97e3646..89e40b7 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLogger.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLogger.cs @@ -1,44 +1,43 @@ using Microsoft.Extensions.Logging; using System.Extensions; -namespace System.Logging +namespace System.Logging; + +public sealed class CVLogger : ILogger { - public sealed class CVLogger : ILogger + private readonly string category; + private readonly ICVLoggerProvider cvLoggerProvider; + + public CVLogger(string category, ICVLoggerProvider cvLoggerProvider) { - private readonly string category; - private readonly ICVLoggerProvider cvLoggerProvider; + this.category = category; + this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider)); + } - public CVLogger(string category, ICVLoggerProvider cvLoggerProvider) + public IDisposable BeginScope(TState state) + { + return null; + } + + public bool IsEnabled(LogLevel logLevel) + { + return true; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + var message = formatter(state, exception); + + var log = new Log { - this.category = category; - this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider)); - } + Exception = exception, + LogLevel = logLevel, + EventId = eventId.Name, + Message = message, + Category = category, + LogTime = DateTime.Now + }; - public IDisposable BeginScope(TState state) - { - return null; - } - - public bool IsEnabled(LogLevel logLevel) - { - return true; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - var message = formatter(state, exception); - - var log = new Log - { - Exception = exception, - LogLevel = logLevel, - EventId = eventId.Name, - Message = message, - Category = category, - LogTime = DateTime.Now - }; - - this.cvLoggerProvider.LogEntry(log); - } + this.cvLoggerProvider.LogEntry(log); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLoggerProvider.cs b/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLoggerProvider.cs index 458e576..6d8f5e2 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLoggerProvider.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Logging/CVLoggerProvider.cs @@ -2,38 +2,37 @@ using Microsoft.Extensions.Logging; using System.Extensions; -namespace System.Logging +namespace System.Logging; + +public sealed class CVLoggerProvider : ICVLoggerProvider { - public sealed class CVLoggerProvider : ICVLoggerProvider + private readonly ILogsWriter logsManager; + private readonly CorrelationVector correlationVector; + + public CVLoggerProvider(ILogsWriter logsWriter) { - private readonly ILogsWriter logsManager; - private readonly CorrelationVector correlationVector; + this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter)); + this.correlationVector = new CorrelationVector(); + } - public CVLoggerProvider(ILogsWriter logsWriter) + public void LogEntry(Log log) + { + if (this.correlationVector is not null) { - this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter)); - this.correlationVector = new CorrelationVector(); + log.CorrelationVector = this.correlationVector.Value.ToString(); + this.correlationVector.Increment(); } - public void LogEntry(Log log) - { - if (this.correlationVector is not null) - { - log.CorrelationVector = this.correlationVector.Value.ToString(); - this.correlationVector.Increment(); - } + this.logsManager.WriteLog(log); + } - this.logsManager.WriteLog(log); - } + public ILogger CreateLogger(string categoryName) + { + return new CVLogger(categoryName, this); + } - public ILogger CreateLogger(string categoryName) - { - return new CVLogger(categoryName, this); - } - - public void Dispose() - { - throw new System.NotImplementedException(); - } + public void Dispose() + { + throw new System.NotImplementedException(); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Logging/DebugLogsWriter.cs b/SystemExtensions.NetStandard.DependencyInjection/Logging/DebugLogsWriter.cs index 3f57ea2..8717d99 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Logging/DebugLogsWriter.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Logging/DebugLogsWriter.cs @@ -1,12 +1,11 @@ using System.Diagnostics; -namespace System.Logging +namespace System.Logging; + +public sealed class DebugLogsWriter : ILogsWriter { - public sealed class DebugLogsWriter : ILogsWriter + public void WriteLog(Log log) { - public void WriteLog(Log log) - { - Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}"); - } + Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}"); } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Logging/ICVLoggerProvider.cs b/SystemExtensions.NetStandard.DependencyInjection/Logging/ICVLoggerProvider.cs index 41343aa..4d9799c 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Logging/ICVLoggerProvider.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Logging/ICVLoggerProvider.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.Logging; -namespace System.Logging +namespace System.Logging; + +public interface ICVLoggerProvider : ILoggerProvider { - public interface ICVLoggerProvider : ILoggerProvider - { - void LogEntry(Log log); - } + void LogEntry(Log log); } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Logging/ILogsWriter.cs b/SystemExtensions.NetStandard.DependencyInjection/Logging/ILogsWriter.cs index 1a90c32..c8caaa7 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Logging/ILogsWriter.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Logging/ILogsWriter.cs @@ -1,7 +1,6 @@ -namespace System.Logging +namespace System.Logging; + +public interface ILogsWriter { - public interface ILogsWriter - { - void WriteLog(Log log); - } + void WriteLog(Log log); } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Logging/LoggerResolver.cs b/SystemExtensions.NetStandard.DependencyInjection/Logging/LoggerResolver.cs index 40b9079..a8b8fc6 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Logging/LoggerResolver.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Logging/LoggerResolver.cs @@ -2,49 +2,48 @@ using Slim.Resolvers; using System.Linq; -namespace System.Logging +namespace System.Logging; + +public sealed class LoggerResolver : IDependencyResolver { - public sealed class LoggerResolver : IDependencyResolver + public bool CanResolve(Type type) { - public bool CanResolve(Type type) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) || + type == typeof(ILogger)) { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) || - type == typeof(ILogger)) - { - return true; - } - - return false; + return true; } - public object Resolve(Slim.IServiceProvider serviceProvider, Type type) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>)) - { - return ResolveScopedLogger(serviceProvider, type); - } - else if (type == typeof(ILogger)) - { - return ResolveLogger(serviceProvider); - } - else - { - throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}"); - } - } + return false; + } - private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type) + public object Resolve(Slim.IServiceProvider serviceProvider, Type type) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>)) { - var loggerFactory = serviceProvider.GetService(); - var categoryTypes = type.GetGenericArguments(); - var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First(); - return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory }); + return ResolveScopedLogger(serviceProvider, type); } - - private static object ResolveLogger(Slim.IServiceProvider serviceProvider) + else if (type == typeof(ILogger)) { - var loggerFactory = serviceProvider.GetService(); - return loggerFactory.CreateLogger(string.Empty); + return ResolveLogger(serviceProvider); + } + else + { + throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}"); } } + + private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type) + { + var loggerFactory = serviceProvider.GetService(); + var categoryTypes = type.GetGenericArguments(); + var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First(); + return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory }); + } + + private static object ResolveLogger(Slim.IServiceProvider serviceProvider) + { + var loggerFactory = serviceProvider.GetService(); + return loggerFactory.CreateLogger(string.Empty); + } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/Models/Log.cs b/SystemExtensions.NetStandard.DependencyInjection/Models/Log.cs index 526d1f5..65faa1e 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Models/Log.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Models/Log.cs @@ -1,15 +1,14 @@ using Microsoft.Extensions.Logging; -namespace System.Logging +namespace System.Logging; + +public sealed record Log { - public sealed record Log - { - public Exception Exception { get; set; } - public DateTime LogTime { get; set; } - public string Category { get; set; } - public string EventId { get; set; } - public LogLevel LogLevel { get; set; } - public string Message { get; set; } - public string CorrelationVector { get; set; } - } + public Exception Exception { get; set; } + public DateTime LogTime { get; set; } + public string Category { get; set; } + public string EventId { get; set; } + public LogLevel LogLevel { get; set; } + public string Message { get; set; } + public string CorrelationVector { get; set; } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard.DependencyInjection/Models/TypedHttpClientFactory.cs b/SystemExtensions.NetStandard.DependencyInjection/Models/TypedHttpClientFactory.cs new file mode 100644 index 0000000..428dc97 --- /dev/null +++ b/SystemExtensions.NetStandard.DependencyInjection/Models/TypedHttpClientFactory.cs @@ -0,0 +1,8 @@ +using System.Net.Http; + +namespace System.DependencyInjection.Models; + +internal sealed class TypedHttpClientFactory +{ + public Func Factory { get; set; } +} diff --git a/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj b/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj index eaadab0..19862c2 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj +++ b/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj @@ -6,7 +6,7 @@ LICENSE true latest - 1.1.8 + 1.2 Alexandru Macocian https://github.com/AlexMacocian/SystemExtensions Extensions for the Slim Dependency Injection engine @@ -22,7 +22,7 @@ - + diff --git a/SystemExtensions.NetStandard.Security.Tests/AesEncrypterTests.cs b/SystemExtensions.NetStandard.Security.Tests/AesEncrypterTests.cs index bf5b5e3..668ad7d 100644 --- a/SystemExtensions.NetStandard.Security.Tests/AesEncrypterTests.cs +++ b/SystemExtensions.NetStandard.Security.Tests/AesEncrypterTests.cs @@ -7,99 +7,98 @@ using System.Security.Encryption; using System.Text; using System.Threading.Tasks; -namespace SystemExtensions.NetStandard.Security.Tests +namespace SystemExtensions.NetStandard.Security.Tests; + +[TestClass] +public class AesEncrypterTests { - [TestClass] - public class AesEncrypterTests + private ISymmetricEncrypter symmetricEncrypter; + private string keyString; + private byte[] keyBytes; + private byte[] ivBytes; + private string ivString; + private string toEncryptString; + private byte[] toEncryptBytes; + + [TestInitialize] + public void TestInitialize() { - private ISymmetricEncrypter symmetricEncrypter; - private string keyString; - private byte[] keyBytes; - private byte[] ivBytes; - private string ivString; - private string toEncryptString; - private byte[] toEncryptBytes; + this.symmetricEncrypter = new AesEncrypter(); + this.keyBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 }; + this.keyString = Convert.ToBase64String(this.keyBytes); + this.ivBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; + this.ivString = Convert.ToBase64String(this.ivBytes); + this.toEncryptBytes = Encoding.UTF8.GetBytes("toEncrypt"); + this.toEncryptString = Convert.ToBase64String(this.toEncryptBytes); + } - [TestInitialize] - public void TestInitialize() - { - this.symmetricEncrypter = new AesEncrypter(); - this.keyBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 }; - this.keyString = Convert.ToBase64String(this.keyBytes); - this.ivBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; - this.ivString = Convert.ToBase64String(this.ivBytes); - this.toEncryptBytes = Encoding.UTF8.GetBytes("toEncrypt"); - this.toEncryptString = Convert.ToBase64String(this.toEncryptBytes); - } + [TestMethod] + public async Task EncryptDecryptStringWithStringKeyStringIv() + { + var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptString).ConfigureAwait(false); + var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false); - [TestMethod] - public async Task EncryptDecryptStringWithStringKeyStringIv() - { - var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptString).ConfigureAwait(false); - var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false); + this.toEncryptString.Should().Be(decrypted); + } - this.toEncryptString.Should().Be(decrypted); - } + [TestMethod] + public async Task EncryptDecryptStringWithByteKeyByteIv() + { + var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptString).ConfigureAwait(false); + var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false); - [TestMethod] - public async Task EncryptDecryptStringWithByteKeyByteIv() - { - var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptString).ConfigureAwait(false); - var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false); + this.toEncryptString.Should().Be(decrypted); + } - this.toEncryptString.Should().Be(decrypted); - } + [TestMethod] + public async Task EncryptDecryptByteWithStringKeyStringIv() + { + var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptBytes).ConfigureAwait(false); + var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false); - [TestMethod] - public async Task EncryptDecryptByteWithStringKeyStringIv() - { - var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptBytes).ConfigureAwait(false); - var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false); + this.toEncryptBytes.Should().BeEquivalentTo(decrypted); + } - this.toEncryptBytes.Should().BeEquivalentTo(decrypted); - } + [TestMethod] + public async Task EncryptDecryptByteWithByteKeyByteIv() + { + var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptBytes).ConfigureAwait(false); + var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false); - [TestMethod] - public async Task EncryptDecryptByteWithByteKeyByteIv() - { - var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptBytes).ConfigureAwait(false); - var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false); + this.toEncryptBytes.Should().BeEquivalentTo(decrypted); + } - this.toEncryptBytes.Should().BeEquivalentTo(decrypted); - } + [TestMethod] + public async Task EncryptDecryptStreamWithStringKeyStringIv() + { + var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false); + encrypted.Position = 0; + var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false); - [TestMethod] - public async Task EncryptDecryptStreamWithStringKeyStringIv() - { - var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false); - encrypted.Position = 0; - var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false); + this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray()); + } - this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray()); - } + [TestMethod] + public async Task EncryptDecryptStreamWithByteKeyByteIv() + { + var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false); + encrypted.Position = 0; + var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false); - [TestMethod] - public async Task EncryptDecryptStreamWithByteKeyByteIv() - { - var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false); - encrypted.Position = 0; - var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false); + this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray()); + } - this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray()); - } + [TestMethod] + public void GetEncryptionStreamReturnsCryptoStream() + { + var encryptionStream = this.symmetricEncrypter.GetEncryptionStream(this.keyBytes, this.ivBytes, new MemoryStream()); + encryptionStream.Should().BeAssignableTo(); + } - [TestMethod] - public void GetEncryptionStreamReturnsCryptoStream() - { - var encryptionStream = this.symmetricEncrypter.GetEncryptionStream(this.keyBytes, this.ivBytes, new MemoryStream()); - encryptionStream.Should().BeAssignableTo(); - } - - [TestMethod] - public void GetDecryptionStreamReturnsCryptoStream() - { - var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream()); - encryptionStream.Should().BeAssignableTo(); - } + [TestMethod] + public void GetDecryptionStreamReturnsCryptoStream() + { + var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream()); + encryptionStream.Should().BeAssignableTo(); } } diff --git a/SystemExtensions.NetStandard.Security.Tests/CryptoRngProviderTests.cs b/SystemExtensions.NetStandard.Security.Tests/CryptoRngProviderTests.cs index bb06e99..5d3a3b1 100644 --- a/SystemExtensions.NetStandard.Security.Tests/CryptoRngProviderTests.cs +++ b/SystemExtensions.NetStandard.Security.Tests/CryptoRngProviderTests.cs @@ -3,53 +3,52 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; using System.Security.Rng; -namespace SystemExtensions.NetStandard.Security.Tests +namespace SystemExtensions.NetStandard.Security.Tests; + +[TestClass] +public class CryptoRngProviderTests { - [TestClass] - public class CryptoRngProviderTests + private CryptoRngProvider cryptoRngProvider; + + [TestInitialize] + public void TestInitialize() { - private CryptoRngProvider cryptoRngProvider; + this.cryptoRngProvider = new CryptoRngProvider(); + } - [TestInitialize] - public void TestInitialize() - { - this.cryptoRngProvider = new CryptoRngProvider(); - } + [TestMethod] + public void GetBytes_ShouldSetValues() + { + var bytes = new byte[100]; - [TestMethod] - public void GetBytes_ShouldSetValues() - { - var bytes = new byte[100]; + this.cryptoRngProvider.GetBytes(bytes); - this.cryptoRngProvider.GetBytes(bytes); + bytes.All(b => b == 0).Should().BeFalse(); + } - bytes.All(b => b == 0).Should().BeFalse(); - } + [TestMethod] + public void GetNonZeroBytes_ShouldSetNonZeroValues() + { + var bytes = new byte[100]; - [TestMethod] - public void GetNonZeroBytes_ShouldSetNonZeroValues() - { - var bytes = new byte[100]; + this.cryptoRngProvider.GetNonZeroBytes(bytes); - this.cryptoRngProvider.GetNonZeroBytes(bytes); + bytes.All(b => b != 0).Should().BeTrue(); + } - bytes.All(b => b != 0).Should().BeTrue(); - } + [TestMethod] + public void GetBytes_ShouldReturnBytes() + { + var bytes = this.cryptoRngProvider.GetBytes(10); - [TestMethod] - public void GetBytes_ShouldReturnBytes() - { - var bytes = this.cryptoRngProvider.GetBytes(10); + bytes.Length.Should().Be(10); + } - bytes.Length.Should().Be(10); - } + [TestMethod] + public void GetNonZeroBytes_ShouldReturnBytes() + { + var bytes = this.cryptoRngProvider.GetNonZeroBytes(10); - [TestMethod] - public void GetNonZeroBytes_ShouldReturnBytes() - { - var bytes = this.cryptoRngProvider.GetNonZeroBytes(10); - - bytes.Length.Should().Be(10); - } + bytes.Length.Should().Be(10); } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard.Security.Tests/Rfc2898DeriveBytesPasswordHashingServiceTests.cs b/SystemExtensions.NetStandard.Security.Tests/Rfc2898DeriveBytesPasswordHashingServiceTests.cs index ac0e3b3..0f1b135 100644 --- a/SystemExtensions.NetStandard.Security.Tests/Rfc2898DeriveBytesPasswordHashingServiceTests.cs +++ b/SystemExtensions.NetStandard.Security.Tests/Rfc2898DeriveBytesPasswordHashingServiceTests.cs @@ -4,258 +4,257 @@ using System; using System.Security.Hashing; using System.Threading.Tasks; -namespace SystemExtensions.NetStandard.Security.Tests +namespace SystemExtensions.NetStandard.Security.Tests; + +[TestClass] +public sealed class Rfc2898DeriveBytesPasswordHashingServiceTests { - [TestClass] - public sealed class Rfc2898DeriveBytesPasswordHashingServiceTests + private const int TooShortHashLength = 31; + private const int DesiredHashLength = 32; + private const int Iterations = 10000; + private const int TooLittleIterations = 1000; + + private readonly Rfc2898DeriveBytesPasswordHashingService rfc2898DeriveBytesPasswordHashingService = new(); + + private byte[] tooShortSaltBytes; + private string tooShortSaltString; + private byte[] incorrectSaltBytes; + private string incorrectSaltString; + private byte[] saltBytes; + private string saltString; + private byte[] passwordBytes; + private string passwordString; + private byte[] incorrectPasswordBytes; + private string incorrectPasswordString; + + [TestInitialize] + public void TestInitialize() { - private const int TooShortHashLength = 31; - private const int DesiredHashLength = 32; - private const int Iterations = 10000; - private const int TooLittleIterations = 1000; + this.tooShortSaltBytes = new byte[16]; + this.tooShortSaltString = Convert.ToBase64String(this.tooShortSaltBytes); + this.saltBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; + this.incorrectSaltBytes = new byte[32]; + this.incorrectSaltString = Convert.ToBase64String(this.incorrectSaltBytes); + this.saltString = Convert.ToBase64String(this.saltBytes); + this.passwordBytes = new byte[] { 5, 1, 2, 34, 35, 123, 4, 23, 1, 235, 32, 234 }; + this.passwordString = Convert.ToBase64String(this.passwordBytes); + this.incorrectPasswordBytes = new byte[] { 14, 123, 23, 4, 2, 1, 23, 25 }; + this.incorrectPasswordString = Convert.ToBase64String(this.incorrectPasswordBytes); + } - private readonly Rfc2898DeriveBytesPasswordHashingService rfc2898DeriveBytesPasswordHashingService = new(); + [TestMethod] + public void PasswordNull_HashBytes_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltBytes, DesiredHashLength, Iterations)); - private byte[] tooShortSaltBytes; - private string tooShortSaltString; - private byte[] incorrectSaltBytes; - private string incorrectSaltString; - private byte[] saltBytes; - private string saltString; - private byte[] passwordBytes; - private string passwordString; - private byte[] incorrectPasswordBytes; - private string incorrectPasswordString; + action.Should().ThrowAsync(); + } + [TestMethod] + public void PasswordNull_HashString_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltString, DesiredHashLength, Iterations)); - [TestInitialize] - public void TestInitialize() - { - this.tooShortSaltBytes = new byte[16]; - this.tooShortSaltString = Convert.ToBase64String(this.tooShortSaltBytes); - this.saltBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; - this.incorrectSaltBytes = new byte[32]; - this.incorrectSaltString = Convert.ToBase64String(this.incorrectSaltBytes); - this.saltString = Convert.ToBase64String(this.saltBytes); - this.passwordBytes = new byte[] { 5, 1, 2, 34, 35, 123, 4, 23, 1, 235, 32, 234 }; - this.passwordString = Convert.ToBase64String(this.passwordBytes); - this.incorrectPasswordBytes = new byte[] { 14, 123, 23, 4, 2, 1, 23, 25 }; - this.incorrectPasswordString = Convert.ToBase64String(this.incorrectPasswordBytes); - } + action.Should().ThrowAsync(); + } + [TestMethod] + public void SaltNull_HashBytes_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, null, DesiredHashLength, Iterations)); - [TestMethod] - public void PasswordNull_HashBytes_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltBytes, DesiredHashLength, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void SaltNull_HashString_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, null, DesiredHashLength, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void PasswordNull_HashString_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltString, DesiredHashLength, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void HashLengthTooSmall_HashBytes_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, TooShortHashLength, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void SaltNull_HashBytes_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, null, DesiredHashLength, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void HashLengthTooSmall_HashString_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, TooShortHashLength, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void SaltNull_HashString_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, null, DesiredHashLength, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void TooLittleIterations_HashBytes_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, TooLittleIterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void HashLengthTooSmall_HashBytes_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, TooShortHashLength, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void TooLittleIterations_HashString_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, TooLittleIterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void HashLengthTooSmall_HashString_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, TooShortHashLength, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void TooShortSalt_HashBytes_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.tooShortSaltBytes, DesiredHashLength, TooLittleIterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void TooLittleIterations_HashBytes_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, TooLittleIterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void TooShortSalt_HashString_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.tooShortSaltString, DesiredHashLength, TooLittleIterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void TooLittleIterations_HashString_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, TooLittleIterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void PasswordNull_VerifyBytes_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordBytes, this.saltBytes, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void TooShortSalt_HashBytes_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.tooShortSaltBytes, DesiredHashLength, TooLittleIterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void PasswordNull_VerifyString_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordString, this.saltString, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void TooShortSalt_HashString_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.tooShortSaltString, DesiredHashLength, TooLittleIterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void HashNull_VerifyBytes_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, null, this.saltBytes, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void PasswordNull_VerifyBytes_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordBytes, this.saltBytes, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void HashNull_VerifyString_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, null, this.saltString, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void PasswordNull_VerifyString_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordString, this.saltString, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void SaltNull_VerifyBytes_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, null, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void HashNull_VerifyBytes_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, null, this.saltBytes, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void SaltNull_VerifyString_Throws_ArgumentNullException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, null, Iterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void HashNull_VerifyString_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, null, this.saltString, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void TooLittleIterations_VerifyBytes_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, this.saltBytes, TooLittleIterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void SaltNull_VerifyBytes_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, null, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public void TooLittleIterations_VerifyString_Throws_InvalidOperationException() + { + var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, this.saltString, TooLittleIterations)); - action.Should().ThrowAsync(); - } - [TestMethod] - public void SaltNull_VerifyString_Throws_ArgumentNullException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, null, Iterations)); + action.Should().ThrowAsync(); + } + [TestMethod] + public async Task HashBytes_ReturnsHashedBytes() + { + var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); - action.Should().ThrowAsync(); - } - [TestMethod] - public void TooLittleIterations_VerifyBytes_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, this.saltBytes, TooLittleIterations)); + hashedBytes.Should().NotBeNull(); + hashedBytes.Should().HaveCount(DesiredHashLength); + } + [TestMethod] + public async Task HashString_ReturnsHashedString() + { + var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); - action.Should().ThrowAsync(); - } - [TestMethod] - public void TooLittleIterations_VerifyString_Throws_InvalidOperationException() - { - var action = new Func>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, this.saltString, TooLittleIterations)); + hashedString.Should().NotBeNull(); + var hashedBytes = Convert.FromBase64String(hashedString); + hashedBytes.Should().HaveCount(DesiredHashLength); + } + [TestMethod] + public async Task VerifyBytes_CorrectPassword_ReturnsTrue() + { + var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); - action.Should().ThrowAsync(); - } - [TestMethod] - public async Task HashBytes_ReturnsHashedBytes() - { - var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations); - hashedBytes.Should().NotBeNull(); - hashedBytes.Should().HaveCount(DesiredHashLength); - } - [TestMethod] - public async Task HashString_ReturnsHashedString() - { - var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); + result.Should().BeTrue(); + } + [TestMethod] + public async Task VerifyString_CorrectPassword_ReturnsTrue() + { + var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); - hashedString.Should().NotBeNull(); - var hashedBytes = Convert.FromBase64String(hashedString); - hashedBytes.Should().HaveCount(DesiredHashLength); - } - [TestMethod] - public async Task VerifyBytes_CorrectPassword_ReturnsTrue() - { - var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations); + result.Should().BeTrue(); + } + [TestMethod] + public async Task VerifyBytes_IncorrectPassword_ReturnsFalse() + { + var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); - result.Should().BeTrue(); - } - [TestMethod] - public async Task VerifyString_CorrectPassword_ReturnsTrue() - { - var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.incorrectPasswordBytes, this.saltBytes, Iterations); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations); + result.Should().BeFalse(); + } + [TestMethod] + public async Task VerifyString_IncorrectPassword_ReturnsFalse() + { + var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); - result.Should().BeTrue(); - } - [TestMethod] - public async Task VerifyBytes_IncorrectPassword_ReturnsFalse() - { - var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.incorrectPasswordString, this.saltString, Iterations); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.incorrectPasswordBytes, this.saltBytes, Iterations); + result.Should().BeFalse(); + } + [TestMethod] + public async Task VerifyBytes_IncorrectSalt_ReturnsFalse() + { + var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); - result.Should().BeFalse(); - } - [TestMethod] - public async Task VerifyString_IncorrectPassword_ReturnsFalse() - { - var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.incorrectSaltBytes, Iterations); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.incorrectPasswordString, this.saltString, Iterations); + result.Should().BeFalse(); + } + [TestMethod] + public async Task VerifyString_IncorrectSalt_ReturnsFalse() + { + var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); - result.Should().BeFalse(); - } - [TestMethod] - public async Task VerifyBytes_IncorrectSalt_ReturnsFalse() - { - var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.incorrectSaltString, Iterations); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.incorrectSaltBytes, Iterations); + result.Should().BeFalse(); + } + [TestMethod] + public async Task VerifyBytes_IncorrectIterations_ReturnsFalse() + { + var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); - result.Should().BeFalse(); - } - [TestMethod] - public async Task VerifyString_IncorrectSalt_ReturnsFalse() - { - var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations + 1); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.incorrectSaltString, Iterations); + result.Should().BeFalse(); + } + [TestMethod] + public async Task VerifyString_IncorrectIterations_ReturnsFalse() + { + var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); - result.Should().BeFalse(); - } - [TestMethod] - public async Task VerifyBytes_IncorrectIterations_ReturnsFalse() - { - var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations); + var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations + 1); - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations + 1); - - result.Should().BeFalse(); - } - [TestMethod] - public async Task VerifyString_IncorrectIterations_ReturnsFalse() - { - var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations); - - var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations + 1); - - result.Should().BeFalse(); - } + result.Should().BeFalse(); } } diff --git a/SystemExtensions.NetStandard.Security.Tests/SecureStringTests.cs b/SystemExtensions.NetStandard.Security.Tests/SecureStringTests.cs index 190598d..2e602d6 100644 --- a/SystemExtensions.NetStandard.Security.Tests/SecureStringTests.cs +++ b/SystemExtensions.NetStandard.Security.Tests/SecureStringTests.cs @@ -2,121 +2,120 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Security.Encryption; -namespace SystemExtensions.NetStandard.Security.Tests +namespace SystemExtensions.NetStandard.Security.Tests; + +[TestClass] +public class SecureStringTests { - [TestClass] - public class SecureStringTests + [TestMethod] + public void SecureString_NewSecureString_ReturnsValue() { - [TestMethod] - public void SecureString_NewSecureString_ReturnsValue() - { - var str = new SecureString("hello"); + var str = new SecureString("hello"); - str.Value.Should().Be("hello"); - } + str.Value.Should().Be("hello"); + } - [TestMethod] - public void SecureStringEmpty_AreEqual() - { - var str = SecureString.Empty; - str.Should().Be(SecureString.Empty); - } + [TestMethod] + public void SecureStringEmpty_AreEqual() + { + var str = SecureString.Empty; + str.Should().Be(SecureString.Empty); + } - [TestMethod] - public void SecureStringEmpty_Equals_StringEmpty() - { - var ss = SecureString.Empty; - var s = string.Empty; + [TestMethod] + public void SecureStringEmpty_Equals_StringEmpty() + { + var ss = SecureString.Empty; + var s = string.Empty; - ss.Should().Be(s); - } + ss.Should().Be(s); + } - [TestMethod] - public void SecureString_Equals_OtherSecureString() - { - var ss1 = new SecureString("Hello"); - var ss2 = new SecureString("Hello"); + [TestMethod] + public void SecureString_Equals_OtherSecureString() + { + var ss1 = new SecureString("Hello"); + var ss2 = new SecureString("Hello"); - ss1.Equals(ss2).Should().BeTrue(); - } + ss1.Equals(ss2).Should().BeTrue(); + } - [TestMethod] - [DataRow("hello", "hello", true)] - [DataRow("hello", "henlo", false)] - public void SecureString_EqualOperator_OtherSecureString(string str1, string str2, bool isEqual) - { - var ss1 = new SecureString(str1); - var ss2 = new SecureString(str2); + [TestMethod] + [DataRow("hello", "hello", true)] + [DataRow("hello", "henlo", false)] + public void SecureString_EqualOperator_OtherSecureString(string str1, string str2, bool isEqual) + { + var ss1 = new SecureString(str1); + var ss2 = new SecureString(str2); - (ss1 == ss2).Should().Be(isEqual); - } + (ss1 == ss2).Should().Be(isEqual); + } - [TestMethod] - [DataRow("hello", "hello", false)] - [DataRow("hello", "henlo", true)] - public void SecureString_DifferentOperator_OtherSecureString(string str1, string str2, bool isDifferent) - { - var ss1 = new SecureString(str1); - var ss2 = new SecureString(str2); + [TestMethod] + [DataRow("hello", "hello", false)] + [DataRow("hello", "henlo", true)] + public void SecureString_DifferentOperator_OtherSecureString(string str1, string str2, bool isDifferent) + { + var ss1 = new SecureString(str1); + var ss2 = new SecureString(str2); - (ss1 != ss2).Should().Be(isDifferent); - } + (ss1 != ss2).Should().Be(isDifferent); + } - [TestMethod] - [DataRow("hello", "hello", true)] - [DataRow("hello", "henlo", false)] - public void SecureString_EqualOperator_String(string str1, string str2, bool isEqual) - { - var ss1 = new SecureString(str1); + [TestMethod] + [DataRow("hello", "hello", true)] + [DataRow("hello", "henlo", false)] + public void SecureString_EqualOperator_String(string str1, string str2, bool isEqual) + { + var ss1 = new SecureString(str1); - (ss1 == str2).Should().Be(isEqual); - } + (ss1 == str2).Should().Be(isEqual); + } - [TestMethod] - [DataRow("hello", "hello", false)] - [DataRow("hello", "henlo", true)] - public void SecureString_DifferentOperator_String(string str1, string str2, bool isDifferent) - { - var ss1 = new SecureString(str1); + [TestMethod] + [DataRow("hello", "hello", false)] + [DataRow("hello", "henlo", true)] + public void SecureString_DifferentOperator_String(string str1, string str2, bool isDifferent) + { + var ss1 = new SecureString(str1); - (ss1 != str2).Should().Be(isDifferent); - } + (ss1 != str2).Should().Be(isDifferent); + } - [TestMethod] - public void SecureString_PlusOperator_SecureString() - { - var ss1 = new SecureString("Hello "); - var ss2 = new SecureString("World"); + [TestMethod] + public void SecureString_PlusOperator_SecureString() + { + var ss1 = new SecureString("Hello "); + var ss2 = new SecureString("World"); - (ss1 + ss2).Should().Be("Hello World"); - } + (ss1 + ss2).Should().Be("Hello World"); + } - [TestMethod] - public void SecureString_PlusOperator_String() - { - var ss1 = new SecureString("Hello "); - var ss2 = "World"; + [TestMethod] + public void SecureString_PlusOperator_String() + { + var ss1 = new SecureString("Hello "); + var ss2 = "World"; - (ss1 + ss2).Should().Be("Hello World"); - } + (ss1 + ss2).Should().Be("Hello World"); + } - [TestMethod] - public void SecureString_PlusOperator_Char() - { - var ss1 = new SecureString("Hello "); - var c = 'W'; + [TestMethod] + public void SecureString_PlusOperator_Char() + { + var ss1 = new SecureString("Hello "); + var c = 'W'; - (ss1 + c).Should().Be("Hello W"); - } + (ss1 + c).Should().Be("Hello W"); + } - [TestMethod] - public void SecureString_WithOptionalEntropy_Matches() - { - SecureString.AddOptionalEntropy(new byte[] { 10, 20, 25, 34, 56, 12, 10, 81, 200, 155, 123, 144, 123, 192, 122, 1 }); - var ss1 = new SecureString("Hello"); - var ss2 = new SecureString("Hello"); + [TestMethod] + public void SecureString_WithOptionalEntropy_Matches() + { + SecureString.AddOptionalEntropy(new byte[] { 10, 20, 25, 34, 56, 12, 10, 81, 200, 155, 123, 144, 123, 192, 122, 1 }); + var ss1 = new SecureString("Hello"); + var ss2 = new SecureString("Hello"); - ss1.Should().Be(ss2); - } + ss1.Should().Be(ss2); } } diff --git a/SystemExtensions.NetStandard.Security.Tests/Sha256HashingServiceTests.cs b/SystemExtensions.NetStandard.Security.Tests/Sha256HashingServiceTests.cs index ef8eaa2..42c007e 100644 --- a/SystemExtensions.NetStandard.Security.Tests/Sha256HashingServiceTests.cs +++ b/SystemExtensions.NetStandard.Security.Tests/Sha256HashingServiceTests.cs @@ -6,43 +6,42 @@ using System.Security.Hashing; using System.Text; using System.Threading.Tasks; -namespace SystemExtensions.NetStandard.Security.Tests +namespace SystemExtensions.NetStandard.Security.Tests; + +[TestClass] +public sealed class Sha256HashingServiceTests { - [TestClass] - public sealed class Sha256HashingServiceTests + private readonly IHashingService hashingService = new Sha256HashingService(); + private string toHashtString; + private byte[] toHashtBytes; + private Stream toHashStream; + + [TestInitialize] + public void TestInitialize() { - private readonly IHashingService hashingService = new Sha256HashingService(); - private string toHashtString; - private byte[] toHashtBytes; - private Stream toHashStream; + this.toHashtBytes = Encoding.UTF8.GetBytes("toEncrypt"); + this.toHashtString = Convert.ToBase64String(this.toHashtBytes); + this.toHashStream = new MemoryStream(this.toHashtBytes); + } - [TestInitialize] - public void TestInitialize() - { - this.toHashtBytes = Encoding.UTF8.GetBytes("toEncrypt"); - this.toHashtString = Convert.ToBase64String(this.toHashtBytes); - this.toHashStream = new MemoryStream(this.toHashtBytes); - } + [TestMethod] + public async Task HashString() + { + var hash = await this.hashingService.Hash(this.toHashtString).ConfigureAwait(false); + hash.Should().BeOfType(); + } - [TestMethod] - public async Task HashString() - { - var hash = await this.hashingService.Hash(this.toHashtString).ConfigureAwait(false); - hash.Should().BeOfType(); - } + [TestMethod] + public async Task HashBytes() + { + var hash = await this.hashingService.Hash(this.toHashtBytes).ConfigureAwait(false); + hash.Should().BeOfType(); + } - [TestMethod] - public async Task HashBytes() - { - var hash = await this.hashingService.Hash(this.toHashtBytes).ConfigureAwait(false); - hash.Should().BeOfType(); - } - - [TestMethod] - public async Task HashStream() - { - var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false); - hash.Should().BeAssignableTo(); - } + [TestMethod] + public async Task HashStream() + { + var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false); + hash.Should().BeAssignableTo(); } } diff --git a/SystemExtensions.NetStandard.Security/Encryption/AesEncrypter.cs b/SystemExtensions.NetStandard.Security/Encryption/AesEncrypter.cs index de97242..7eeb4bb 100644 --- a/SystemExtensions.NetStandard.Security/Encryption/AesEncrypter.cs +++ b/SystemExtensions.NetStandard.Security/Encryption/AesEncrypter.cs @@ -4,224 +4,223 @@ using System.Security.Cryptography; using System.Threading.Tasks; using System.Security.Utilities; -namespace System.Security.Encryption +namespace System.Security.Encryption; + +public sealed class AesEncrypter : ISymmetricEncrypter, IDisposable { - public sealed class AesEncrypter : ISymmetricEncrypter, IDisposable + private readonly Aes aes; + + public AesEncrypter() { - private readonly Aes aes; + this.aes = Aes.Create(); + } - public AesEncrypter() + public AesEncrypter(Aes aes) + { + this.aes = aes; + } + + public async Task Decrypt(string key, string iv, string value) + { + using var valueStream = BytesToStream(StringToBytes(value)); + using var decryptedStream = await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); + return StreamToString(decryptedStream); + } + + public async Task Decrypt(byte[] key, byte[] iv, string value) + { + using var valueStream = BytesToStream(StringToBytes(value)); + using var decryptedStream = await this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false); + return StreamToString(decryptedStream); + } + + public async Task Decrypt(string key, string iv, byte[] value) + { + using var valueStream = BytesToStream(value); + using var decryptedStream = await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); + return StreamToBytes(decryptedStream); + } + + public async Task Decrypt(byte[] key, byte[] iv, byte[] value) + { + using var valueStream = BytesToStream(value); + using var decryptedStream = await this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false); + return StreamToBytes(decryptedStream); + } + + public async Task Decrypt(string key, string iv, Stream value) + { + return await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false); + } + + public async Task Decrypt(byte[] key, byte[] iv, Stream value) + { + return await this.DecryptInternal(key, iv, value).ConfigureAwait(false); + } + + public async Task Encrypt(string key, string iv, string value) + { + using var valueStream = BytesToStream(StringToBytes(value)); + using var encryptedStream = await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); + return StreamToString(encryptedStream); + } + + public async Task Encrypt(byte[] key, byte[] iv, string value) + { + using var valueStream = BytesToStream(StringToBytes(value)); + using var encryptedStream = await this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false); + return StreamToString(encryptedStream); + } + + public async Task Encrypt(string key, string iv, byte[] value) + { + using var valueStream = BytesToStream(value); + using var encryptedStream = await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); + return StreamToBytes(encryptedStream); + } + + public async Task Encrypt(byte[] key, byte[] iv, byte[] value) + { + using var valueStream = BytesToStream(value); + using var encryptedStream = await this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false); + return StreamToBytes(encryptedStream); + } + + public async Task Encrypt(string key, string iv, Stream value) + { + return value is null + ? throw new ArgumentNullException(nameof(value)) + : await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false); + } + + public async Task Encrypt(byte[] key, byte[] iv, Stream value) + { + return value is null + ? throw new ArgumentNullException(nameof(value)) + : await this.EncryptInternal(key, iv, value).ConfigureAwait(false); + } + + public Stream GetEncryptionStream(string key, string iv, Stream outStream) + { + return this.GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream); + } + + public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream) + { + return this.GetEncryptionStreamInternal(key, iv, outStream); + } + + public Stream GetDecryptionStream(string key, string iv, Stream inStream) + { + return this.GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream); + } + + public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream) + { + return this.GetDecryptionStreamInternal(key, iv, inStream); + } + + private async Task EncryptInternal(byte[] key, byte[] iv, Stream toEncryptStream) + { + if (key.Length < 32) { - this.aes = Aes.Create(); + throw new ArgumentException($"{nameof(key)} must be at least 32 bytes"); } - public AesEncrypter(Aes aes) + if (iv.Length < 16) { - this.aes = aes; + throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes"); } - public async Task Decrypt(string key, string iv, string value) + key = key.Take(32).ToArray(); + iv = iv.Take(16).ToArray(); + + + var encryptedMemoryStream = new MemoryStream(); + using var cryptoStream = this.GetEncryptionStreamInternal(key, iv, encryptedMemoryStream); + await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false); + if (!cryptoStream.HasFlushedFinalBlock) { - using var valueStream = BytesToStream(StringToBytes(value)); - using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); - return StreamToString(decryptedStream); + cryptoStream.FlushFinalBlock(); } - public async Task Decrypt(byte[] key, byte[] iv, string value) + encryptedMemoryStream.Position = 0; + return encryptedMemoryStream; + } + + private async Task DecryptInternal(byte[] key, byte[] iv, Stream toDecryptStream) + { + if (key.Length < 32) { - using var valueStream = BytesToStream(StringToBytes(value)); - using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false); - return StreamToString(decryptedStream); + throw new ArgumentException($"{nameof(key)} must be at least 32 bytes"); } - public async Task Decrypt(string key, string iv, byte[] value) + if (iv.Length < 16) { - using var valueStream = BytesToStream(value); - using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); - return StreamToBytes(decryptedStream); + throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes"); } - public async Task Decrypt(byte[] key, byte[] iv, byte[] value) + key = key.Take(32).ToArray(); + iv = iv.Take(16).ToArray(); + + + var decryptedMemoryStream = new MemoryStream(); + using var cryptoStream = this.GetDecryptionStreamInternal(key, iv, toDecryptStream); + await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false); + if (!cryptoStream.HasFlushedFinalBlock) { - using var valueStream = BytesToStream(value); - using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false); - return StreamToBytes(decryptedStream); + cryptoStream.FlushFinalBlock(); } - public async Task Decrypt(string key, string iv, Stream value) + decryptedMemoryStream.Position = 0; + return decryptedMemoryStream; + } + + private CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream) + { + var crypto = this.aes.CreateEncryptor(key, iv); + var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write); + return cryptoStream; + } + + private CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream) + { + var crypto = this.aes.CreateDecryptor(key, iv); + var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read); + return cryptoStream; + } + + private static byte[] StreamToBytes(Stream value) + { + value.Position = 0; + var buffer = new byte[1024]; + using var ms = new MemoryStream(); + var read = -1; + do { - return await DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false); - } + read = value.Read(buffer, 0, buffer.Length); + ms.Write(buffer, 0, read); + } while (read > 0); + return ms.ToArray(); + } - public async Task Decrypt(byte[] key, byte[] iv, Stream value) - { - return await DecryptInternal(key, iv, value).ConfigureAwait(false); - } + private static string StreamToString(Stream value) + { + return Convert.ToBase64String(StreamToBytes(value)); + } - public async Task Encrypt(string key, string iv, string value) - { - using var valueStream = BytesToStream(StringToBytes(value)); - using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); - return StreamToString(encryptedStream); - } + private static byte[] StringToBytes(string value) + { + return Convert.FromBase64String(value); + } - public async Task Encrypt(byte[] key, byte[] iv, string value) - { - using var valueStream = BytesToStream(StringToBytes(value)); - using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false); - return StreamToString(encryptedStream); - } + private static Stream BytesToStream(byte[] value) + { + return new MemoryStream(value); + } - public async Task Encrypt(string key, string iv, byte[] value) - { - using var valueStream = BytesToStream(value); - using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false); - return StreamToBytes(encryptedStream); - } - - public async Task Encrypt(byte[] key, byte[] iv, byte[] value) - { - using var valueStream = BytesToStream(value); - using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false); - return StreamToBytes(encryptedStream); - } - - public async Task Encrypt(string key, string iv, Stream value) - { - return value is null - ? throw new ArgumentNullException(nameof(value)) - : await EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false); - } - - public async Task Encrypt(byte[] key, byte[] iv, Stream value) - { - return value is null - ? throw new ArgumentNullException(nameof(value)) - : await EncryptInternal(key, iv, value).ConfigureAwait(false); - } - - public Stream GetEncryptionStream(string key, string iv, Stream outStream) - { - return GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream); - } - - public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream) - { - return GetEncryptionStreamInternal(key, iv, outStream); - } - - public Stream GetDecryptionStream(string key, string iv, Stream inStream) - { - return GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream); - } - - public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream) - { - return GetDecryptionStreamInternal(key, iv, inStream); - } - - private async Task EncryptInternal(byte[] key, byte[] iv, Stream toEncryptStream) - { - if (key.Length < 32) - { - throw new ArgumentException($"{nameof(key)} must be at least 32 bytes"); - } - - if (iv.Length < 16) - { - throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes"); - } - - key = key.Take(32).ToArray(); - iv = iv.Take(16).ToArray(); - - - var encryptedMemoryStream = new MemoryStream(); - using var cryptoStream = this.GetEncryptionStreamInternal(key, iv, encryptedMemoryStream); - await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false); - if (!cryptoStream.HasFlushedFinalBlock) - { - cryptoStream.FlushFinalBlock(); - } - - encryptedMemoryStream.Position = 0; - return encryptedMemoryStream; - } - - private async Task DecryptInternal(byte[] key, byte[] iv, Stream toDecryptStream) - { - if (key.Length < 32) - { - throw new ArgumentException($"{nameof(key)} must be at least 32 bytes"); - } - - if (iv.Length < 16) - { - throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes"); - } - - key = key.Take(32).ToArray(); - iv = iv.Take(16).ToArray(); - - - var decryptedMemoryStream = new MemoryStream(); - using var cryptoStream = this.GetDecryptionStreamInternal(key, iv, toDecryptStream); - await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false); - if (!cryptoStream.HasFlushedFinalBlock) - { - cryptoStream.FlushFinalBlock(); - } - - decryptedMemoryStream.Position = 0; - return decryptedMemoryStream; - } - - private CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream) - { - var crypto = this.aes.CreateEncryptor(key, iv); - var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write); - return cryptoStream; - } - - private CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream) - { - var crypto = this.aes.CreateDecryptor(key, iv); - var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read); - return cryptoStream; - } - - private static byte[] StreamToBytes(Stream value) - { - value.Position = 0; - var buffer = new byte[1024]; - using var ms = new MemoryStream(); - var read = -1; - do - { - read = value.Read(buffer, 0, buffer.Length); - ms.Write(buffer, 0, read); - } while (read > 0); - return ms.ToArray(); - } - - private static string StreamToString(Stream value) - { - return Convert.ToBase64String(StreamToBytes(value)); - } - - private static byte[] StringToBytes(string value) - { - return Convert.FromBase64String(value); - } - - private static Stream BytesToStream(byte[] value) - { - return new MemoryStream(value); - } - - public void Dispose() - { - this.aes.Dispose(); - } + public void Dispose() + { + this.aes.Dispose(); } } diff --git a/SystemExtensions.NetStandard.Security/Encryption/ISymmetricEncrypter.cs b/SystemExtensions.NetStandard.Security/Encryption/ISymmetricEncrypter.cs index e3a7bab..2445709 100644 --- a/SystemExtensions.NetStandard.Security/Encryption/ISymmetricEncrypter.cs +++ b/SystemExtensions.NetStandard.Security/Encryption/ISymmetricEncrypter.cs @@ -1,25 +1,24 @@ using System.IO; using System.Threading.Tasks; -namespace System.Security.Encryption +namespace System.Security.Encryption; + +public interface ISymmetricEncrypter { - public interface ISymmetricEncrypter - { - Stream GetEncryptionStream(string key, string iv, Stream outStream); - Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream); - Stream GetDecryptionStream(string key, string iv, Stream inStream); - Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream); - Task Encrypt(string key, string iv, string value); - Task Encrypt(byte[] key, byte[] iv, string value); - Task Encrypt(string key, string iv, byte[] value); - Task Encrypt(byte[] key, byte[] iv, byte[] value); - Task Encrypt(string key, string iv, Stream value); - Task Encrypt(byte[] key, byte[] iv, Stream value); - Task Decrypt(string key, string iv, string value); - Task Decrypt(byte[] key, byte[] iv, string value); - Task Decrypt(string key, string iv, byte[] value); - Task Decrypt(byte[] key, byte[] iv, byte[] value); - Task Decrypt(string key, string iv, Stream value); - Task Decrypt(byte[] key, byte[] iv, Stream value); - } + Stream GetEncryptionStream(string key, string iv, Stream outStream); + Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream); + Stream GetDecryptionStream(string key, string iv, Stream inStream); + Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream); + Task Encrypt(string key, string iv, string value); + Task Encrypt(byte[] key, byte[] iv, string value); + Task Encrypt(string key, string iv, byte[] value); + Task Encrypt(byte[] key, byte[] iv, byte[] value); + Task Encrypt(string key, string iv, Stream value); + Task Encrypt(byte[] key, byte[] iv, Stream value); + Task Decrypt(string key, string iv, string value); + Task Decrypt(byte[] key, byte[] iv, string value); + Task Decrypt(string key, string iv, byte[] value); + Task Decrypt(byte[] key, byte[] iv, byte[] value); + Task Decrypt(string key, string iv, Stream value); + Task Decrypt(byte[] key, byte[] iv, Stream value); } diff --git a/SystemExtensions.NetStandard.Security/Encryption/SecureString.cs b/SystemExtensions.NetStandard.Security/Encryption/SecureString.cs index 568e973..d5f8823 100644 --- a/SystemExtensions.NetStandard.Security/Encryption/SecureString.cs +++ b/SystemExtensions.NetStandard.Security/Encryption/SecureString.cs @@ -1,102 +1,101 @@ using System.Security.Cryptography; using System.Text; -namespace System.Security.Encryption +namespace System.Security.Encryption; + +public sealed class SecureString { - public sealed class SecureString + private static byte[] optionalEntropy; + private byte[] encryptedValue; + + public string Value { + get => this.encryptedValue is not null ? Encoding.UTF8.GetString(ProtectedData.Unprotect(this.encryptedValue, optionalEntropy, DataProtectionScope.CurrentUser)) : null; + private set => this.encryptedValue = ProtectedData.Protect(Encoding.UTF8.GetBytes(value), optionalEntropy, DataProtectionScope.CurrentUser); + } + + public SecureString(string value) { - private static byte[] optionalEntropy; - private byte[] encryptedValue; + this.Value = value; + } - public string Value { - get => this.encryptedValue is not null ? Encoding.UTF8.GetString(ProtectedData.Unprotect(this.encryptedValue, optionalEntropy, DataProtectionScope.CurrentUser)) : null; - private set => this.encryptedValue = ProtectedData.Protect(Encoding.UTF8.GetBytes(value), optionalEntropy, DataProtectionScope.CurrentUser); - } - - public SecureString(string value) + public override bool Equals(object obj) + { + if (obj is string) { - this.Value = value; + return this == (obj as string); } - - public override bool Equals(object obj) + else if (obj is SecureString) { - if (obj is string) - { - return this == (obj as string); - } - else if (obj is SecureString) - { - return this == (obj as SecureString); - } - else - { - return base.Equals(obj); - } + return this == (obj as SecureString); } - public override int GetHashCode() + else { - return this.Value.GetHashCode(); - } - public override string ToString() - { - return this.Value; - } - - public static readonly SecureString Empty = new(string.Empty); - public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value; - public static implicit operator SecureString(string s) => new(s); - public static SecureString operator +(SecureString ss1, SecureString ss2) - { - if (ss1 is null) - { - throw new ArgumentNullException(nameof(ss1)); - } - - if (ss2 is null) - { - throw new ArgumentNullException(nameof(ss2)); - } - - return new SecureString(ss1.Value + ss2.Value); - } - public static SecureString operator +(SecureString ss1, string s2) - { - if (ss1 is null) - { - throw new ArgumentNullException(nameof(ss1)); - } - - return new SecureString(ss1.Value + s2); - } - public static SecureString operator +(SecureString ss1, char c) - { - if (ss1 is null) - { - throw new ArgumentNullException(nameof(ss1)); - } - - return new SecureString(ss1.Value + c); - } - public static bool operator ==(SecureString ss1, SecureString ss2) - { - return ss1?.Value == ss2?.Value; - } - public static bool operator !=(SecureString ss1, SecureString ss2) - { - return !(ss1 == ss2); - } - public static bool operator ==(SecureString ss1, string s2) - { - return ss1?.Value == s2; - } - public static bool operator !=(SecureString ss1, string s2) - { - return !(ss1?.Value == s2); - } - - public static void AddOptionalEntropy(byte[] entropy) - { - optionalEntropy = entropy; + return base.Equals(obj); } } + public override int GetHashCode() + { + return this.Value.GetHashCode(); + } + public override string ToString() + { + return this.Value; + } + + public static readonly SecureString Empty = new(string.Empty); + public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value; + public static implicit operator SecureString(string s) => new(s); + public static SecureString operator +(SecureString ss1, SecureString ss2) + { + if (ss1 is null) + { + throw new ArgumentNullException(nameof(ss1)); + } + + if (ss2 is null) + { + throw new ArgumentNullException(nameof(ss2)); + } + + return new SecureString(ss1.Value + ss2.Value); + } + public static SecureString operator +(SecureString ss1, string s2) + { + if (ss1 is null) + { + throw new ArgumentNullException(nameof(ss1)); + } + + return new SecureString(ss1.Value + s2); + } + public static SecureString operator +(SecureString ss1, char c) + { + if (ss1 is null) + { + throw new ArgumentNullException(nameof(ss1)); + } + + return new SecureString(ss1.Value + c); + } + public static bool operator ==(SecureString ss1, SecureString ss2) + { + return ss1?.Value == ss2?.Value; + } + public static bool operator !=(SecureString ss1, SecureString ss2) + { + return !(ss1 == ss2); + } + public static bool operator ==(SecureString ss1, string s2) + { + return ss1?.Value == s2; + } + public static bool operator !=(SecureString ss1, string s2) + { + return !(ss1?.Value == s2); + } + + public static void AddOptionalEntropy(byte[] entropy) + { + optionalEntropy = entropy; + } } diff --git a/SystemExtensions.NetStandard.Security/Hashing/IHashingService.cs b/SystemExtensions.NetStandard.Security/Hashing/IHashingService.cs index dce5596..1b2e5dd 100644 --- a/SystemExtensions.NetStandard.Security/Hashing/IHashingService.cs +++ b/SystemExtensions.NetStandard.Security/Hashing/IHashingService.cs @@ -1,12 +1,11 @@ using System.IO; using System.Threading.Tasks; -namespace System.Security.Hashing +namespace System.Security.Hashing; + +public interface IHashingService { - public interface IHashingService - { - Task Hash(string raw); - Task Hash(byte[] raw); - Task Hash(Stream raw); - } + Task Hash(string raw); + Task Hash(byte[] raw); + Task Hash(Stream raw); } diff --git a/SystemExtensions.NetStandard.Security/Hashing/IPasswordHashingService.cs b/SystemExtensions.NetStandard.Security/Hashing/IPasswordHashingService.cs index 063e93f..9e376de 100644 --- a/SystemExtensions.NetStandard.Security/Hashing/IPasswordHashingService.cs +++ b/SystemExtensions.NetStandard.Security/Hashing/IPasswordHashingService.cs @@ -1,47 +1,46 @@ using System.Threading.Tasks; -namespace System.Security.Hashing +namespace System.Security.Hashing; + +public interface IPasswordHashingService { - public interface IPasswordHashingService - { - /// - /// Hash provided raw password and return the hashed value. - /// - /// Base64 encoded password. - /// Base64 encoded salt to be used for hashing. - /// Length of the resulting hash. - /// Number of hashing iterations to be performed. - /// - /// The length of the hash will vary due to the base64 encoding of the resulting hash. - /// - /// Base64 encoded hashed password. - Task Hash(string raw, string salt, int length, int iterations); - /// - /// Hash provided raw password and return the hashed value. - /// - /// Password to be hashed. - /// Salt to be used for hashing. - /// Length of the resulting hash. - /// Number of hashing iterations to be performed. - /// Hashed password. - Task Hash(byte[] raw, byte[] salt, int length, int iterations); - /// - /// Verify provided password against a hashed password. - /// - /// Base64 encoding of the previously hashed password. - /// Base64 encoding of the password to be verified. - /// Salt used to hash the previous password. - /// Number of iterations used to hash the previous password. - /// Returns true if password matches the previously hashed password. Otherwise returns false. - Task VerifyPassword(string hash, string password, string salt, int iterations); - /// - /// Verify provided password against a hashed password. - /// - /// Previously hashed password. - /// Password to be verified. - /// Salt used to hash the previous password. - /// Number of iterations used to hash the previous password. - /// Returns true if password matches the previously hashed password. Otherwise returns false. - Task VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations); - } + /// + /// Hash provided raw password and return the hashed value. + /// + /// Base64 encoded password. + /// Base64 encoded salt to be used for hashing. + /// Length of the resulting hash. + /// Number of hashing iterations to be performed. + /// + /// The length of the hash will vary due to the base64 encoding of the resulting hash. + /// + /// Base64 encoded hashed password. + Task Hash(string raw, string salt, int length, int iterations); + /// + /// Hash provided raw password and return the hashed value. + /// + /// Password to be hashed. + /// Salt to be used for hashing. + /// Length of the resulting hash. + /// Number of hashing iterations to be performed. + /// Hashed password. + Task Hash(byte[] raw, byte[] salt, int length, int iterations); + /// + /// Verify provided password against a hashed password. + /// + /// Base64 encoding of the previously hashed password. + /// Base64 encoding of the password to be verified. + /// Salt used to hash the previous password. + /// Number of iterations used to hash the previous password. + /// Returns true if password matches the previously hashed password. Otherwise returns false. + Task VerifyPassword(string hash, string password, string salt, int iterations); + /// + /// Verify provided password against a hashed password. + /// + /// Previously hashed password. + /// Password to be verified. + /// Salt used to hash the previous password. + /// Number of iterations used to hash the previous password. + /// Returns true if password matches the previously hashed password. Otherwise returns false. + Task VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations); } diff --git a/SystemExtensions.NetStandard.Security/Hashing/Rfc2898DeriveBytesPasswordHashingService.cs b/SystemExtensions.NetStandard.Security/Hashing/Rfc2898DeriveBytesPasswordHashingService.cs index 17efb82..0934d0d 100644 --- a/SystemExtensions.NetStandard.Security/Hashing/Rfc2898DeriveBytesPasswordHashingService.cs +++ b/SystemExtensions.NetStandard.Security/Hashing/Rfc2898DeriveBytesPasswordHashingService.cs @@ -1,101 +1,100 @@ using System.Security.Cryptography; using System.Threading.Tasks; -namespace System.Security.Hashing +namespace System.Security.Hashing; + +public sealed class Rfc2898DeriveBytesPasswordHashingService : IPasswordHashingService { - public sealed class Rfc2898DeriveBytesPasswordHashingService : IPasswordHashingService + private const int MinimumIterations = 10000; + private const int MinimumHashLength = 32; + + public Rfc2898DeriveBytesPasswordHashingService() { - private const int MinimumIterations = 10000; - private const int MinimumHashLength = 32; + } - public Rfc2898DeriveBytesPasswordHashingService() + public async Task Hash(string raw, string salt, int length, int iterations) + { + this.ValidateHashArguments(raw, salt, length, iterations); + + var rawBytes = Convert.FromBase64String(raw); + var saltBytes = Convert.FromBase64String(salt); + var hashBytes = await this.HashInternal(rawBytes, saltBytes, length, iterations); + return Convert.ToBase64String(hashBytes); + } + public Task Hash(byte[] raw, byte[] salt, int length, int iterations) + { + this.ValidateHashArguments(raw, salt, length, iterations); + + return this.HashInternal(raw, salt, length, iterations); + } + public Task VerifyPassword(string hash, string password, string salt, int iterations) + { + this.ValidateVerifyArguments(hash, password, salt, iterations); + var hashBytes = Convert.FromBase64String(hash); + var saltBytes = Convert.FromBase64String(salt); + var passwordBytes = Convert.FromBase64String(password); + return this.VerifyPasswordInternal(hashBytes, passwordBytes, saltBytes, iterations); + } + public Task VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations) + { + this.ValidateVerifyArguments(hash, password, salt, iterations); + return this.VerifyPasswordInternal(hash, password, salt, iterations); + } + + private void ValidateHashArguments(object raw, object salt, int length, int iterations) + { + _ = raw ?? throw new ArgumentNullException(nameof(raw)); + _ = salt ?? throw new ArgumentNullException(nameof(salt)); + + if (iterations < MinimumIterations) { + throw new InvalidOperationException($"Unable to perform secure hash. Iteration count must be over {MinimumIterations}"); } - public async Task Hash(string raw, string salt, int length, int iterations) + if (length < MinimumHashLength) { - this.ValidateHashArguments(raw, salt, length, iterations); - - var rawBytes = Convert.FromBase64String(raw); - var saltBytes = Convert.FromBase64String(salt); - var hashBytes = await this.HashInternal(rawBytes, saltBytes, length, iterations); - return Convert.ToBase64String(hashBytes); - } - public Task Hash(byte[] raw, byte[] salt, int length, int iterations) - { - this.ValidateHashArguments(raw, salt, length, iterations); - - return this.HashInternal(raw, salt, length, iterations); - } - public Task VerifyPassword(string hash, string password, string salt, int iterations) - { - this.ValidateVerifyArguments(hash, password, salt, iterations); - var hashBytes = Convert.FromBase64String(hash); - var saltBytes = Convert.FromBase64String(salt); - var passwordBytes = Convert.FromBase64String(password); - return this.VerifyPasswordInternal(hashBytes, passwordBytes, saltBytes, iterations); - } - public Task VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations) - { - this.ValidateVerifyArguments(hash, password, salt, iterations); - return this.VerifyPasswordInternal(hash, password, salt, iterations); - } - - private void ValidateHashArguments(object raw, object salt, int length, int iterations) - { - _ = raw ?? throw new ArgumentNullException(nameof(raw)); - _ = salt ?? throw new ArgumentNullException(nameof(salt)); - - if (iterations < MinimumIterations) - { - throw new InvalidOperationException($"Unable to perform secure hash. Iteration count must be over {MinimumIterations}"); - } - - if (length < MinimumHashLength) - { - throw new InvalidOperationException($"Unable to perform secure hash. Hash length must be over {MinimumHashLength}"); - } - } - private void ValidateVerifyArguments(object hash, object password, object salt, int iterations) - { - _ = hash ?? throw new ArgumentNullException(nameof(hash)); - _ = salt ?? throw new ArgumentNullException(nameof(salt)); - _ = password ?? throw new ArgumentNullException(nameof(password)); - - if (iterations < MinimumIterations) - { - throw new InvalidOperationException($"Unable to verify hash. Iteration count must be over {MinimumIterations}"); - } - } - private Task HashInternal(byte[] raw, byte[] salt, int length, int iterations) - { - using var pbkdf2 = new Rfc2898DeriveBytes(raw, salt, iterations); - var hash = pbkdf2.GetBytes(length); - return Task.FromResult(hash); - } - private Task VerifyPasswordInternal(byte[] hash, byte[] password, byte[] salt, int iterations) - { - using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations); - var hashToVerify = pbkdf2.GetBytes(hash.Length); - var lengthToVerify = Math.Max(hash.Length, hashToVerify.Length); - var match = true; - if (lengthToVerify <= 0) - { - return Task.FromResult(false); - } - - for(var i = 0; i < lengthToVerify; i++) - { - if (i < hash.Length && i < hashToVerify.Length) - { - if (hashToVerify[i].Equals(hash[i]) is false) - { - match = false; - } - } - } - - return Task.FromResult(match && hash.Length.Equals(hashToVerify.Length)); + throw new InvalidOperationException($"Unable to perform secure hash. Hash length must be over {MinimumHashLength}"); } } + private void ValidateVerifyArguments(object hash, object password, object salt, int iterations) + { + _ = hash ?? throw new ArgumentNullException(nameof(hash)); + _ = salt ?? throw new ArgumentNullException(nameof(salt)); + _ = password ?? throw new ArgumentNullException(nameof(password)); + + if (iterations < MinimumIterations) + { + throw new InvalidOperationException($"Unable to verify hash. Iteration count must be over {MinimumIterations}"); + } + } + private Task HashInternal(byte[] raw, byte[] salt, int length, int iterations) + { + using var pbkdf2 = new Rfc2898DeriveBytes(raw, salt, iterations); + var hash = pbkdf2.GetBytes(length); + return Task.FromResult(hash); + } + private Task VerifyPasswordInternal(byte[] hash, byte[] password, byte[] salt, int iterations) + { + using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations); + var hashToVerify = pbkdf2.GetBytes(hash.Length); + var lengthToVerify = Math.Max(hash.Length, hashToVerify.Length); + var match = true; + if (lengthToVerify <= 0) + { + return Task.FromResult(false); + } + + for(var i = 0; i < lengthToVerify; i++) + { + if (i < hash.Length && i < hashToVerify.Length) + { + if (hashToVerify[i].Equals(hash[i]) is false) + { + match = false; + } + } + } + + return Task.FromResult(match && hash.Length.Equals(hashToVerify.Length)); + } } diff --git a/SystemExtensions.NetStandard.Security/Hashing/Sha256HashingService.cs b/SystemExtensions.NetStandard.Security/Hashing/Sha256HashingService.cs index d03ac76..8c72dc4 100644 --- a/SystemExtensions.NetStandard.Security/Hashing/Sha256HashingService.cs +++ b/SystemExtensions.NetStandard.Security/Hashing/Sha256HashingService.cs @@ -2,61 +2,60 @@ using System.Security.Cryptography; using System.Threading.Tasks; -namespace System.Security.Hashing +namespace System.Security.Hashing; + +public sealed class Sha256HashingService : IHashingService { - public sealed class Sha256HashingService : IHashingService + public async Task Hash(string raw) { - public async Task Hash(string raw) + using var rawStream = BytesToStream(StringToBytes(raw)); + using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false); + return StreamToString(hashedStream); + } + public async Task Hash(byte[] raw) + { + using var rawStream = BytesToStream(raw); + using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false); + return StreamToBytes(hashedStream); + } + public async Task Hash(Stream raw) + { + return await HashInternal(raw); + } + + private static byte[] StreamToBytes(Stream value) + { + value.Position = 0; + var buffer = new byte[1024]; + using var ms = new MemoryStream(); + var read = -1; + do { - using var rawStream = BytesToStream(StringToBytes(raw)); - using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false); - return StreamToString(hashedStream); - } - public async Task Hash(byte[] raw) + read = value.Read(buffer, 0, buffer.Length); + ms.Write(buffer, 0, read); + } while (read > 0); + return ms.ToArray(); + } + private static string StreamToString(Stream value) + { + return Convert.ToBase64String(StreamToBytes(value)); + } + private static byte[] StringToBytes(string value) + { + return Convert.FromBase64String(value); + } + private static Stream BytesToStream(byte[] value) + { + return new MemoryStream(value); + } + private static async Task HashInternal(Stream raw) + { + if (raw is null) { - using var rawStream = BytesToStream(raw); - using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false); - return StreamToBytes(hashedStream); - } - public async Task Hash(Stream raw) - { - return await HashInternal(raw); + throw new ArgumentNullException(nameof(raw)); } - private static byte[] StreamToBytes(Stream value) - { - value.Position = 0; - var buffer = new byte[1024]; - using var ms = new MemoryStream(); - var read = -1; - do - { - read = value.Read(buffer, 0, buffer.Length); - ms.Write(buffer, 0, read); - } while (read > 0); - return ms.ToArray(); - } - private static string StreamToString(Stream value) - { - return Convert.ToBase64String(StreamToBytes(value)); - } - private static byte[] StringToBytes(string value) - { - return Convert.FromBase64String(value); - } - private static Stream BytesToStream(byte[] value) - { - return new MemoryStream(value); - } - private static async Task HashInternal(Stream raw) - { - if (raw is null) - { - throw new ArgumentNullException(nameof(raw)); - } - - using var sha256 = SHA256.Create(); - return await Task.Run(() => new MemoryStream(sha256.ComputeHash(raw))); - } + using var sha256 = SHA256.Create(); + return await Task.Run(() => new MemoryStream(sha256.ComputeHash(raw))); } } diff --git a/SystemExtensions.NetStandard.Security/Rng/CryptoRngProvider.cs b/SystemExtensions.NetStandard.Security/Rng/CryptoRngProvider.cs index 76e2aef..b32b1cc 100644 --- a/SystemExtensions.NetStandard.Security/Rng/CryptoRngProvider.cs +++ b/SystemExtensions.NetStandard.Security/Rng/CryptoRngProvider.cs @@ -1,59 +1,58 @@ using System.Security.Cryptography; -namespace System.Security.Rng +namespace System.Security.Rng; + +public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable { - public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable + private readonly RNGCryptoServiceProvider rngProvider; + private bool disposedValue; + + public CryptoRngProvider() { - private readonly RNGCryptoServiceProvider rngProvider; - private bool disposedValue; - - public CryptoRngProvider() - { - this.rngProvider = new RNGCryptoServiceProvider(); - } - public CryptoRngProvider(CspParameters cspParams) - { - this.rngProvider = new RNGCryptoServiceProvider(cspParams); - } + this.rngProvider = new RNGCryptoServiceProvider(); + } + public CryptoRngProvider(CspParameters cspParams) + { + this.rngProvider = new RNGCryptoServiceProvider(cspParams); + } - public void GetBytes(byte[] data) - { - this.rngProvider.GetBytes(data); - } - public void GetNonZeroBytes(byte[] data) - { - this.rngProvider.GetNonZeroBytes(data); - } - public byte[] GetBytes(int byteCount) - { - var bytes = new byte[byteCount]; - this.GetBytes(bytes); - return bytes; - } - public byte[] GetNonZeroBytes(int byteCount) - { - var bytes = new byte[byteCount]; - this.GetNonZeroBytes(bytes); - return bytes; - } + public void GetBytes(byte[] data) + { + this.rngProvider.GetBytes(data); + } + public void GetNonZeroBytes(byte[] data) + { + this.rngProvider.GetNonZeroBytes(data); + } + public byte[] GetBytes(int byteCount) + { + var bytes = new byte[byteCount]; + this.GetBytes(bytes); + return bytes; + } + public byte[] GetNonZeroBytes(int byteCount) + { + var bytes = new byte[byteCount]; + this.GetNonZeroBytes(bytes); + return bytes; + } - private void Dispose(bool disposing) + private void Dispose(bool disposing) + { + if (!this.disposedValue) { - if (!this.disposedValue) + if (disposing) { - if (disposing) - { - this.rngProvider.Dispose(); - } - - this.disposedValue = true; + this.rngProvider.Dispose(); } - } - public void Dispose() - { - this.Dispose(disposing: true); - GC.SuppressFinalize(this); + + this.disposedValue = true; } } + public void Dispose() + { + this.Dispose(disposing: true); + GC.SuppressFinalize(this); + } } diff --git a/SystemExtensions.NetStandard.Security/Rng/ICryptoRngProvider.cs b/SystemExtensions.NetStandard.Security/Rng/ICryptoRngProvider.cs index ff5c412..95b1807 100644 --- a/SystemExtensions.NetStandard.Security/Rng/ICryptoRngProvider.cs +++ b/SystemExtensions.NetStandard.Security/Rng/ICryptoRngProvider.cs @@ -1,28 +1,27 @@ -namespace System.Security.Rng +namespace System.Security.Rng; + +public interface ICryptoRngProvider { - public interface ICryptoRngProvider - { - /// - /// Populate provided array of bytes with cryptographically secure random bytes. - /// - /// Array of bytes to be populated. - public void GetBytes(byte[] data); - /// - /// Return an array of cryptographically secure random bytes. - /// - /// Length of the returned array. - /// Array containing cryptographically secure random values. - public byte[] GetBytes(int byteCount); - /// - /// Populate provided array of bytes with cryptographically secure random non-zero bytes. - /// - /// Array of bytes to be populated. - public void GetNonZeroBytes(byte[] data); - /// - /// Return an array of cryptographically secure random non-zero bytes. - /// - /// Length of the returned array. - /// Array containing cryptographically secure random non-zero values. - public byte[] GetNonZeroBytes(int byteCount); - } + /// + /// Populate provided array of bytes with cryptographically secure random bytes. + /// + /// Array of bytes to be populated. + public void GetBytes(byte[] data); + /// + /// Return an array of cryptographically secure random bytes. + /// + /// Length of the returned array. + /// Array containing cryptographically secure random values. + public byte[] GetBytes(int byteCount); + /// + /// Populate provided array of bytes with cryptographically secure random non-zero bytes. + /// + /// Array of bytes to be populated. + public void GetNonZeroBytes(byte[] data); + /// + /// Return an array of cryptographically secure random non-zero bytes. + /// + /// Length of the returned array. + /// Array containing cryptographically secure random non-zero values. + public byte[] GetNonZeroBytes(int byteCount); } diff --git a/SystemExtensions.NetStandard.Security/Utilities/NotClosingCryptoStream.cs b/SystemExtensions.NetStandard.Security/Utilities/NotClosingCryptoStream.cs index f166b59..bfaf170 100644 --- a/SystemExtensions.NetStandard.Security/Utilities/NotClosingCryptoStream.cs +++ b/SystemExtensions.NetStandard.Security/Utilities/NotClosingCryptoStream.cs @@ -1,23 +1,22 @@ using System.IO; using System.Security.Cryptography; -namespace System.Security.Utilities +namespace System.Security.Utilities; + +internal sealed class NotClosingCryptoStream : CryptoStream { - internal sealed class NotClosingCryptoStream : CryptoStream + public NotClosingCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode) + : base(stream, transform, mode) { - public NotClosingCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode) - : base(stream, transform, mode) + } + + protected override void Dispose(bool disposing) + { + if (!this.HasFlushedFinalBlock) { + this.FlushFinalBlock(); } - protected override void Dispose(bool disposing) - { - if (!this.HasFlushedFinalBlock) - { - this.FlushFinalBlock(); - } - - base.Dispose(false); - } + base.Dispose(false); } } diff --git a/SystemExtensions.NetStandard/Collections/AVLTree.cs b/SystemExtensions.NetStandard/Collections/AVLTree.cs index 1e6c435..2bc95f3 100644 --- a/SystemExtensions.NetStandard/Collections/AVLTree.cs +++ b/SystemExtensions.NetStandard/Collections/AVLTree.cs @@ -1,393 +1,402 @@ using System.Collections.Generic; -namespace System.Collections.Generic -{ - /// - /// AVL tree implementation. - /// Thanks to Karim Oumghar for the implementation example. - /// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/ - /// - /// Provided type. - [Serializable] - public sealed class AVLTree : ICollection where T : IComparable - { - #region Fields - [Serializable] - private class AVLNode - { - public TKey Value; - public AVLNode Left; - public AVLNode Right; - public AVLNode(TKey value) - { - this.Value = value; - } - } - AVLNode root; - private int count = 0; - private readonly bool isReadOnly = false; - #endregion - #region Properties - /// - /// Count of items currently stored in the tree. - /// - public int Count - { - get - { - return count; - } - } - /// - /// True if the collection is readonly. False otherwise. - /// - public bool IsReadOnly => isReadOnly; - #endregion - #region Constructors - /// - /// Initializes a new instance of an AVLTree collection. - /// - public AVLTree() - { +namespace System.Collections.Generic; - } - #endregion - #region Public Methods - /// - /// Adds the value to the tree. - /// - /// Value to be added to the tree. - public void Add(T value) +/// +/// AVL tree implementation. +/// Thanks to Karim Oumghar for the implementation example. +/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/ +/// +/// Provided type. +[Serializable] +public sealed class AVLTree : ICollection where T : IComparable +{ + #region Fields + [Serializable] + private class AVLNode + { + public TKey Value; + public AVLNode Left; + public AVLNode Right; + public AVLNode(TKey value) { - count++; - var newItem = new AVLNode(value); - if (root == null) - { - root = newItem; - } - else - { - root = RecursiveInsertion(root, newItem); - } + this.Value = value; } - /// - /// Checks if the key is contained into the tree. - /// - /// Value to be checked if present in the tree. - /// True if the value is in the tree. - public bool Contains(T value) + } + AVLNode root; + private int count = 0; + private readonly bool isReadOnly = false; + #endregion + #region Properties + /// + /// Count of items currently stored in the tree. + /// + public int Count + { + get { - var node = Find(value, root); - if (node == null) - { - return false; - } - if (node.Value.CompareTo(value) == 0) - { - return true; - } - else - { - return false; - } + return this.count; } - /// - /// Removes the specified value from the tree. - /// - /// Value to be deleted. - public bool Remove(T value) + } + /// + /// True if the collection is readonly. False otherwise. + /// + public bool IsReadOnly => this.isReadOnly; + #endregion + #region Constructors + /// + /// Initializes a new instance of an AVLTree collection. + /// + public AVLTree() + { + + } + #endregion + #region Public Methods + /// + /// Adds the value to the tree. + /// + /// Value to be added to the tree. + public void Add(T value) + { + this.count++; + var newItem = new AVLNode(value); + if (this.root == null) + { + this.root = newItem; + } + else + { + this.root = this.RecursiveInsertion(this.root, newItem); + } + } + /// + /// Checks if the key is contained into the tree. + /// + /// Value to be checked if present in the tree. + /// True if the value is in the tree. + public bool Contains(T value) + { + var node = this.Find(value, this.root); + if (node == null) + { + return false; + } + + if (node.Value.CompareTo(value) == 0) { - root = Delete(root, value); return true; } - /// - /// Clears the tree. - /// - public void Clear() + else { - var queue = new Queue>(); - queue.Enqueue(root); + return false; + } + } + /// + /// Removes the specified value from the tree. + /// + /// Value to be deleted. + public bool Remove(T value) + { + this.root = this.Delete(this.root, value); + return true; + } + /// + /// Clears the tree. + /// + public void Clear() + { + var queue = new Queue>(); + queue.Enqueue(this.root); - while (queue.Count > 0) - { - var currentNode = queue.Dequeue(); - if (currentNode.Left != null) - { - queue.Enqueue(currentNode.Left); - currentNode.Left = null; - count--; - } - if (currentNode.Right != null) - { - queue.Enqueue(currentNode.Right); - currentNode.Right = null; - count--; - } - } - root = null; - count--; - } - /// - /// Copies the tree onto the provided array. - /// - /// Array to store the values in the tree. - /// Starting index of the provided array. - public void CopyTo(T[] array, int arrayIndex) + while (queue.Count > 0) { - var queue = new Queue>(); - queue.Enqueue(root); - while (queue.Count > 0) + var currentNode = queue.Dequeue(); + if (currentNode.Left != null) { - var currentNode = queue.Dequeue(); - array[arrayIndex++] = currentNode.Value; - if (currentNode.Left != null) - { - queue.Enqueue(currentNode.Left); - } - if (currentNode.Right != null) - { - queue.Enqueue(currentNode.Right); - } + queue.Enqueue(currentNode.Left); + currentNode.Left = null; + this.count--; + } + + if (currentNode.Right != null) + { + queue.Enqueue(currentNode.Right); + currentNode.Right = null; + this.count--; } } - /// - /// Enumerator that iterates over the tree. - /// - /// - public IEnumerator GetEnumerator() + + this.root = null; + this.count--; + } + /// + /// Copies the tree onto the provided array. + /// + /// Array to store the values in the tree. + /// Starting index of the provided array. + public void CopyTo(T[] array, int arrayIndex) + { + var queue = new Queue>(); + queue.Enqueue(this.root); + while (queue.Count > 0) { - return GetEnumerator(root); + var currentNode = queue.Dequeue(); + array[arrayIndex++] = currentNode.Value; + if (currentNode.Left != null) + { + queue.Enqueue(currentNode.Left); + } + + if (currentNode.Right != null) + { + queue.Enqueue(currentNode.Right); + } } - /// - /// Copies the tree structure into an array. - /// - /// Array containing the values contained in the tree. - public T[] ToArray() + } + /// + /// Enumerator that iterates over the tree. + /// + /// + public IEnumerator GetEnumerator() + { + return this.GetEnumerator(this.root); + } + /// + /// Copies the tree structure into an array. + /// + /// Array containing the values contained in the tree. + public T[] ToArray() + { + var array = new T[this.count]; + this.CopyTo(array, 0); + return array; + } + #endregion + #region Private Methods + private AVLNode RecursiveInsertion(AVLNode current, AVLNode n) + { + if (current == null) { - var array = new T[count]; - CopyTo(array, 0); - return array; - } - #endregion - #region Private Methods - private AVLNode RecursiveInsertion(AVLNode current, AVLNode n) - { - if (current == null) - { - current = n; - return current; - } - else if (n.Value.CompareTo(current.Value) < 0) - { - current.Left = RecursiveInsertion(current.Left, n); - current = BalanceTree(current); - } - else if (n.Value.CompareTo(current.Value) > 0) - { - current.Right = RecursiveInsertion(current.Right, n); - current = BalanceTree(current); - } + current = n; return current; } - private AVLNode BalanceTree(AVLNode current) + else if (n.Value.CompareTo(current.Value) < 0) { - var b_factor = BalanceFactor(current); - if (b_factor > 1) - { - if (BalanceFactor(current.Left) > 0) - { - current = RotateLL(current); - } - else - { - current = RotateLR(current); - } - } - else if (b_factor < -1) - { - if (BalanceFactor(current.Right) > 0) - { - current = RotateRL(current); - } - else - { - current = RotateRR(current); - } - } - return current; + current.Left = this.RecursiveInsertion(current.Left, n); + current = this.BalanceTree(current); } - private AVLNode Delete(AVLNode current, T target) + else if (n.Value.CompareTo(current.Value) > 0) { - AVLNode parent; - if (current == null) - { return null; } + current.Right = this.RecursiveInsertion(current.Right, n); + current = this.BalanceTree(current); + } + + return current; + } + private AVLNode BalanceTree(AVLNode current) + { + var b_factor = this.BalanceFactor(current); + if (b_factor > 1) + { + if (this.BalanceFactor(current.Left) > 0) + { + current = this.RotateLL(current); + } else { - //left subtree - if (target.CompareTo(current.Value) < 0) - { - current.Left = Delete(current.Left, target); - if (BalanceFactor(current) == -2)//here - { - if (BalanceFactor(current.Right) <= 0) - { - current = RotateRR(current); - } - else - { - current = RotateRL(current); - } - } - } - //right subtree - else if (target.CompareTo(current.Value) > 0) - { - current.Right = Delete(current.Right, target); - if (BalanceFactor(current) == 2) - { - if (BalanceFactor(current.Left) >= 0) - { - current = RotateLL(current); - } - else - { - current = RotateLR(current); - } - } - } - //if target is found - else - { - count--; - if (current.Right != null) - { - //delete its inorder successor - parent = current.Right; - while (parent.Left != null) - { - parent = parent.Left; - } - current.Value = parent.Value; - current.Right = Delete(current.Right, parent.Value); - if (BalanceFactor(current) == 2)//rebalancing - { - if (BalanceFactor(current.Left) >= 0) - { - current = RotateLL(current); - } - else { current = RotateLR(current); } - } - } - else - { //if current.left != null - return current.Left; - } - } + current = this.RotateLR(current); } - return current; } - private AVLNode Find(T target, AVLNode current) + else if (b_factor < -1) { - if (current == null) + if (this.BalanceFactor(current.Right) > 0) { - return null; + current = this.RotateRL(current); } + else + { + current = this.RotateRR(current); + } + } + + return current; + } + private AVLNode Delete(AVLNode current, T target) + { + AVLNode parent; + if (current == null) + { return null; } + else + { + //left subtree if (target.CompareTo(current.Value) < 0) { - if (target.CompareTo(current.Value) == 0) + current.Left = this.Delete(current.Left, target); + if (this.BalanceFactor(current) == -2)//here { - return current; + if (this.BalanceFactor(current.Right) <= 0) + { + current = this.RotateRR(current); + } + else + { + current = this.RotateRL(current); + } + } + } + //right subtree + else if (target.CompareTo(current.Value) > 0) + { + current.Right = this.Delete(current.Right, target); + if (this.BalanceFactor(current) == 2) + { + if (this.BalanceFactor(current.Left) >= 0) + { + current = this.RotateLL(current); + } + else + { + current = this.RotateLR(current); + } + } + } + //if target is found + else + { + this.count--; + if (current.Right != null) + { + //delete its inorder successor + parent = current.Right; + while (parent.Left != null) + { + parent = parent.Left; + } + + current.Value = parent.Value; + current.Right = this.Delete(current.Right, parent.Value); + if (this.BalanceFactor(current) == 2)//rebalancing + { + if (this.BalanceFactor(current.Left) >= 0) + { + current = this.RotateLL(current); + } + else { current = this.RotateLR(current); } + } } else - { - return Find(target, current.Left); + { //if current.left != null + return current.Left; } } + } + + return current; + } + private AVLNode Find(T target, AVLNode current) + { + if (current == null) + { + return null; + } + + if (target.CompareTo(current.Value) < 0) + { + if (target.CompareTo(current.Value) == 0) + { + return current; + } else { - if (target.CompareTo(current.Value) == 0) - { - return current; - } - else - { - return Find(target, current.Right); - } + return this.Find(target, current.Left); } - } - private int Max(int l, int r) + else { - return l > r ? l : r; - } - private int GetHeight(AVLNode current) - { - var height = 0; - if (current != null) + if (target.CompareTo(current.Value) == 0) { - var l = GetHeight(current.Left); - var r = GetHeight(current.Right); - var m = Max(l, r); - height = m + 1; + return current; } - return height; - } - private int BalanceFactor(AVLNode current) - { - var l = GetHeight(current.Left); - var r = GetHeight(current.Right); - var b_factor = l - r; - return b_factor; - } - private AVLNode RotateRR(AVLNode parent) - { - var pivot = parent.Right; - parent.Right = pivot.Left; - pivot.Left = parent; - return pivot; - } - private AVLNode RotateLL(AVLNode parent) - { - var pivot = parent.Left; - parent.Left = pivot.Right; - pivot.Right = parent; - return pivot; - } - private AVLNode RotateLR(AVLNode parent) - { - var pivot = parent.Left; - parent.Left = RotateRR(pivot); - return RotateLL(parent); - } - private AVLNode RotateRL(AVLNode parent) - { - var pivot = parent.Right; - parent.Right = RotateLL(pivot); - return RotateRR(parent); - } - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - private IEnumerator GetEnumerator(AVLNode rootNode) - { - var queue = new Queue>(); - queue.Enqueue(rootNode); - - while (queue.Count > 0) + else { - var currentNode = queue.Dequeue(); - yield return currentNode.Value; - if (currentNode.Left != null) - { - queue.Enqueue(currentNode.Left); - } - if (currentNode.Right != null) - { - queue.Enqueue(currentNode.Right); - } + return this.Find(target, current.Right); } } - #endregion } + private int Max(int l, int r) + { + return l > r ? l : r; + } + private int GetHeight(AVLNode current) + { + var height = 0; + if (current != null) + { + var l = this.GetHeight(current.Left); + var r = this.GetHeight(current.Right); + var m = this.Max(l, r); + height = m + 1; + } + + return height; + } + private int BalanceFactor(AVLNode current) + { + var l = this.GetHeight(current.Left); + var r = this.GetHeight(current.Right); + var b_factor = l - r; + return b_factor; + } + private AVLNode RotateRR(AVLNode parent) + { + var pivot = parent.Right; + parent.Right = pivot.Left; + pivot.Left = parent; + return pivot; + } + private AVLNode RotateLL(AVLNode parent) + { + var pivot = parent.Left; + parent.Left = pivot.Right; + pivot.Right = parent; + return pivot; + } + private AVLNode RotateLR(AVLNode parent) + { + var pivot = parent.Left; + parent.Left = this.RotateRR(pivot); + return this.RotateLL(parent); + } + private AVLNode RotateRL(AVLNode parent) + { + var pivot = parent.Right; + parent.Right = this.RotateLL(pivot); + return this.RotateRR(parent); + } + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + private IEnumerator GetEnumerator(AVLNode rootNode) + { + var queue = new Queue>(); + queue.Enqueue(rootNode); + + while (queue.Count > 0) + { + var currentNode = queue.Dequeue(); + yield return currentNode.Value; + if (currentNode.Left != null) + { + queue.Enqueue(currentNode.Left); + } + + if (currentNode.Right != null) + { + queue.Enqueue(currentNode.Right); + } + } + } + #endregion } diff --git a/SystemExtensions.NetStandard/Collections/BinaryHeap.cs b/SystemExtensions.NetStandard/Collections/BinaryHeap.cs index 17b874d..8a9f4eb 100644 --- a/SystemExtensions.NetStandard/Collections/BinaryHeap.cs +++ b/SystemExtensions.NetStandard/Collections/BinaryHeap.cs @@ -1,214 +1,219 @@ using System.Linq; -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// +/// Binary heap implementation. +/// +/// Provided type. +[Serializable] +public sealed class BinaryHeap : IEnumerable where T : IComparable { + #region Fields + T[] items; + private int capacity; + private int count; + private readonly int initialCapacity; + #endregion + #region Properties /// - /// Binary heap implementation. + /// Minimum value from the heap. /// - /// Provided type. - [Serializable] - public sealed class BinaryHeap : IEnumerable where T : IComparable + public T Min { - #region Fields - T[] items; - private int capacity; - private int count; - private readonly int initialCapacity; - #endregion - #region Properties - /// - /// Minimum value from the heap. - /// - public T Min + get { - get - { - return items[1]; - } + return this.items[1]; } - /// - /// Maximum value from the heap. - /// - public T Max - { - get - { - return items[count]; - } - } - /// - /// Capacity of the heap. - /// - public int Capacity - { - get => capacity; - set - { - if (value > capacity) - { - Array.Resize(ref items, value); - capacity = value; - } - } - } - /// - /// Number of elements in the heap. - /// - public int Count { get => count; } - #endregion - #region Constructors - /// - /// Constructor for a binary heap data structure. - /// - public BinaryHeap() - { - capacity = 10; - initialCapacity = capacity; - items = new T[capacity]; - } - /// - /// Constructor for a binary heap data structure. - /// - /// Initial capacity of the heap. Used for initial alocation of the array. - public BinaryHeap(int capacity) - { - this.capacity = capacity; - initialCapacity = capacity; - items = new T[capacity]; - } - #endregion - #region Public Methods - /// - /// Adds value to the queue. - /// - /// Value to be added. - public void Add(T value) - { - if (count == Capacity - 1) - { - Capacity = 2 * Capacity; - } - var position = ++count; - for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2) - { - items[position] = items[position / 2]; - } - items[position] = value; - } - /// - /// Removes the item at the root. Throws exception if there are no items in the heap. - /// - /// Value removed. - public T Remove() - { - if (count == 0) - { - throw new IndexOutOfRangeException("Heap is empty!"); - } - var min = items[1]; - items[1] = items[count--]; - BubbleDown(1); - return min; - } - /// - /// Peeks at the item at the root. Throws exception if there are no items in the heap. - /// - /// - public T Peek() - { - if (count == 0) - { - throw new IndexOutOfRangeException("Heap is empty!"); - } - var min = items[1]; - return min; - } - /// - /// Return the heap structure as an array - /// - /// Array with values sorted as in heap - public T[] ToArray() - { - var newArray = new T[count]; - Array.Copy(items, 1, newArray, 0, count); - return newArray; - } - /// - /// Determines whether the heap contains specified value - /// - /// Value to locate in the heap - /// - public bool Contains(T value) - { - return items.Contains(value); - } - /// - /// Clears the heap - /// - public void Clear() - { - count = 0; - } - /// - /// Clears the heap. - /// - /// Specifies if the underlying array should be cleared as well - public void Clear(bool completeClear) - { - count = 0; - if (completeClear) - { - capacity = initialCapacity; - items = new T[initialCapacity]; - } - } - /// - /// Returns an enumerator that iterates over the heap. - /// - /// Enumerator that iterates over the heap. - public IEnumerator GetEnumerator() - { - for (var i = 0; i < count; i++) - { - yield return items[i + 1]; - } - } - #endregion - #region Private Methods - /// - /// Bubble the specified element to its position - /// - /// Index of element to bubble - private void BubbleDown(int index) - { - var temp = items[index]; - int childIndex; - for (; 2 * index <= count; index = childIndex) - { - childIndex = 2 * index; - if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0) - { - childIndex++; - } - if (temp.CompareTo(items[childIndex]) > 0) - { - items[index] = items[childIndex]; - } - else - { - break; - } - } - items[index] = temp; - } - /// - /// Implementation of IEnumerator. - /// - /// Enumerator over the array. - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - #endregion } + /// + /// Maximum value from the heap. + /// + public T Max + { + get + { + return this.items[this.count]; + } + } + /// + /// Capacity of the heap. + /// + public int Capacity + { + get => this.capacity; + set + { + if (value > this.capacity) + { + Array.Resize(ref this.items, value); + this.capacity = value; + } + } + } + /// + /// Number of elements in the heap. + /// + public int Count { get => this.count; } + #endregion + #region Constructors + /// + /// Constructor for a binary heap data structure. + /// + public BinaryHeap() + { + this.capacity = 10; + this.initialCapacity = this.capacity; + this.items = new T[this.capacity]; + } + /// + /// Constructor for a binary heap data structure. + /// + /// Initial capacity of the heap. Used for initial alocation of the array. + public BinaryHeap(int capacity) + { + this.capacity = capacity; + this.initialCapacity = capacity; + this.items = new T[capacity]; + } + #endregion + #region Public Methods + /// + /// Adds value to the queue. + /// + /// Value to be added. + public void Add(T value) + { + if (this.count == this.Capacity - 1) + { + this.Capacity = 2 * this.Capacity; + } + + var position = ++this.count; + for (; position > 1 && value.CompareTo(this.items[position / 2]) < 0; position /= 2) + { + this.items[position] = this.items[position / 2]; + } + + this.items[position] = value; + } + /// + /// Removes the item at the root. Throws exception if there are no items in the heap. + /// + /// Value removed. + public T Remove() + { + if (this.count == 0) + { + throw new IndexOutOfRangeException("Heap is empty!"); + } + + var min = this.items[1]; + this.items[1] = this.items[this.count--]; + this.BubbleDown(1); + return min; + } + /// + /// Peeks at the item at the root. Throws exception if there are no items in the heap. + /// + /// + public T Peek() + { + if (this.count == 0) + { + throw new IndexOutOfRangeException("Heap is empty!"); + } + + var min = this.items[1]; + return min; + } + /// + /// Return the heap structure as an array + /// + /// Array with values sorted as in heap + public T[] ToArray() + { + var newArray = new T[this.count]; + Array.Copy(this.items, 1, newArray, 0, this.count); + return newArray; + } + /// + /// Determines whether the heap contains specified value + /// + /// Value to locate in the heap + /// + public bool Contains(T value) + { + return this.items.Contains(value); + } + /// + /// Clears the heap + /// + public void Clear() + { + this.count = 0; + } + /// + /// Clears the heap. + /// + /// Specifies if the underlying array should be cleared as well + public void Clear(bool completeClear) + { + this.count = 0; + if (completeClear) + { + this.capacity = this.initialCapacity; + this.items = new T[this.initialCapacity]; + } + } + /// + /// Returns an enumerator that iterates over the heap. + /// + /// Enumerator that iterates over the heap. + public IEnumerator GetEnumerator() + { + for (var i = 0; i < this.count; i++) + { + yield return this.items[i + 1]; + } + } + #endregion + #region Private Methods + /// + /// Bubble the specified element to its position + /// + /// Index of element to bubble + private void BubbleDown(int index) + { + var temp = this.items[index]; + int childIndex; + for (; 2 * index <= this.count; index = childIndex) + { + childIndex = 2 * index; + if (childIndex != this.Count && this.items[childIndex].CompareTo(this.items[childIndex + 1]) > 0) + { + childIndex++; + } + + if (temp.CompareTo(this.items[childIndex]) > 0) + { + this.items[index] = this.items[childIndex]; + } + else + { + break; + } + } + + this.items[index] = temp; + } + /// + /// Implementation of IEnumerator. + /// + /// Enumerator over the array. + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + #endregion } diff --git a/SystemExtensions.NetStandard/Collections/FibonacciHeap.cs b/SystemExtensions.NetStandard/Collections/FibonacciHeap.cs index f2f6d02..e747c2a 100644 --- a/SystemExtensions.NetStandard/Collections/FibonacciHeap.cs +++ b/SystemExtensions.NetStandard/Collections/FibonacciHeap.cs @@ -1,560 +1,579 @@ -namespace System.Collections.Generic -{ - /// - /// Fibonacci Heap implementation. - /// - /// Provided type - [Serializable] - public sealed class FibonacciHeap : IEnumerable where T : IComparable - { - #region Fields - private FibonacciNode root; - private int count; - #endregion - #region Properties - /// - /// Count of values in the heap. - /// - public int Count - { - get - { - return count; - } - } - /// - /// Minimal value contained in the heap. - /// - public T Minimum - { - get - { - return root.Value; - } - } - #endregion - #region Constructors - /// - /// Constructor for Fibonacci heap data structure. - /// - public FibonacciHeap() - { +namespace System.Collections.Generic; - } - #endregion - #region Public Methods - /// - /// Adds value to the heap. - /// - /// Value to be added. - public void Add(T value) +/// +/// Fibonacci Heap implementation. +/// +/// Provided type +[Serializable] +public sealed class FibonacciHeap : IEnumerable where T : IComparable +{ + #region Fields + private FibonacciNode root; + private int count; + #endregion + #region Properties + /// + /// Count of values in the heap. + /// + public int Count + { + get { - var node = new FibonacciNode + return this.count; + } + } + /// + /// Minimal value contained in the heap. + /// + public T Minimum + { + get + { + return this.root.Value; + } + } + #endregion + #region Constructors + /// + /// Constructor for Fibonacci heap data structure. + /// + public FibonacciHeap() + { + + } + #endregion + #region Public Methods + /// + /// Adds value to the heap. + /// + /// Value to be added. + public void Add(T value) + { + var node = new FibonacciNode + { + Value = value, + Marked = false, + Child = null, + Parent = null, + Degree = 0 + }; + node.Previous = node.Next = node; + this.root = this.Merge(this.root, node); + this.count++; + } + /// + /// Merge current heap with another heap. The other heap will be disposed at the end of this method. + /// + /// The heap to be merged with the current heap. + public void Merge(FibonacciHeap otherHeap) + { + this.root = this.Merge(this.root, otherHeap.root); + otherHeap.root = null; + this.count += otherHeap.count; + } + /// + /// Remove the minimum value from the heap. + /// + /// Minimum value. + public T Remove() + { + var currentRoot = this.root; + if (currentRoot != null) + { + this.root = this.RemoveMinimum(this.root); + this.count--; + return currentRoot.Value; + } + else + { + throw new IndexOutOfRangeException("Heap is empty!"); + } + } + /// + /// Decrease the old value to a new provided value. + /// + /// Old value used to find the node to have its key decreased. + /// New value to be assigned to the node. + public void DecreaseKey(T oldValue, T value) + { + var node = this.Find(this.root, oldValue); + this.root = this.DecreaseKey(this.root, node, value); + } + /// + /// Determines whether the heap contains a specified value. + /// + /// Value to locate in the heap. + /// + public bool Contains(T value) + { + return this.Find(this.root, value) != null; + } + /// + /// Clears the heap. + /// + public void Clear() + { + this.count = 0; + this.Remove(this.root); + this.root.Next = this.root.Previous = this.root.Parent = this.root.Child = null; + this.root = null; + } + /// + /// Return the heap structure as an array. Array is not sorted other than the + /// actual structure of the heap. + /// + /// Array with values from the heap. + public T[] ToArray() + { + if (this.count == 0) + { + return null; + } + + var array = new T[this.count]; + if (this.count == 1) + { + array[0] = this.root.Value; + return array; + } + else + { + var index = 0; + this.RecursiveFillArray(this.root, ref array, ref index); + return array; + } + } + /// + /// Enumerator that iterates over the heap. Note that the values are not sorted in any way. + /// + /// Enumerator that iterates over the heap. + public IEnumerator GetEnumerator() + { + return this.GetEnumerator(this.root); + } + #endregion + #region Private Methods + /// + /// Recursively traverse the heap and copy its contents to an array. + /// + /// Current node. + /// Array to be filled with contents of heap. + /// Index of the next unintialized element in the array. + private void RecursiveFillArray(FibonacciNode currentNode, ref T[] array, ref int index) + { + var oldNode = currentNode; + do + { + array[index] = currentNode.Value; + index++; + if (currentNode.HasChildren()) { - Value = value, - Marked = false, - Child = null, - Parent = null, - Degree = 0 - }; - node.Previous = node.Next = node; - root = this.Merge(root, node); - count++; - } - /// - /// Merge current heap with another heap. The other heap will be disposed at the end of this method. - /// - /// The heap to be merged with the current heap. - public void Merge(FibonacciHeap otherHeap) - { - root = Merge(root, otherHeap.root); - otherHeap.root = null; - count += otherHeap.count; - } - /// - /// Remove the minimum value from the heap. - /// - /// Minimum value. - public T Remove() - { - var currentRoot = root; - if (currentRoot != null) - { - root = RemoveMinimum(root); - count--; - return currentRoot.Value; + this.RecursiveFillArray(currentNode.Child, ref array, ref index); } - else - { - throw new IndexOutOfRangeException("Heap is empty!"); - } - } - /// - /// Decrease the old value to a new provided value. - /// - /// Old value used to find the node to have its key decreased. - /// New value to be assigned to the node. - public void DecreaseKey(T oldValue, T value) - { - var node = Find(root, oldValue); - root = DecreaseKey(root, node, value); - } - /// - /// Determines whether the heap contains a specified value. - /// - /// Value to locate in the heap. - /// - public bool Contains(T value) - { - return Find(root, value) != null; - } - /// - /// Clears the heap. - /// - public void Clear() - { - count = 0; - Remove(root); - root.Next = root.Previous = root.Parent = root.Child = null; - root = null; - } - /// - /// Return the heap structure as an array. Array is not sorted other than the - /// actual structure of the heap. - /// - /// Array with values from the heap. - public T[] ToArray() - { - if (count == 0) - { - return null; - } - var array = new T[count]; - if (count == 1) - { - array[0] = root.Value; - return array; - } - else - { - var index = 0; - RecursiveFillArray(root, ref array, ref index); - return array; - } - } - /// - /// Enumerator that iterates over the heap. Note that the values are not sorted in any way. - /// - /// Enumerator that iterates over the heap. - public IEnumerator GetEnumerator() - { - return GetEnumerator(root); - } - #endregion - #region Private Methods - /// - /// Recursively traverse the heap and copy its contents to an array. - /// - /// Current node. - /// Array to be filled with contents of heap. - /// Index of the next unintialized element in the array. - private void RecursiveFillArray(FibonacciNode currentNode, ref T[] array, ref int index) + + currentNode = currentNode.Previous; + } while (currentNode != oldNode); + } + /// + /// Recursively enumerates over the tree. + /// + /// Current node in the iteration. + private IEnumerator GetEnumerator(FibonacciNode currentNode) + { + var queue = new Queue>(); + queue.Enqueue(currentNode); + while (queue.Count > 0) { + currentNode = queue.Dequeue(); var oldNode = currentNode; do { - array[index] = currentNode.Value; - index++; + yield return currentNode.Value; if (currentNode.HasChildren()) { - RecursiveFillArray(currentNode.Child, ref array, ref index); + queue.Enqueue(currentNode.Child); } + currentNode = currentNode.Previous; } while (currentNode != oldNode); } - /// - /// Recursively enumerates over the tree. - /// - /// Current node in the iteration. - private IEnumerator GetEnumerator(FibonacciNode currentNode) + } + /// + /// Recursively remove the node and its children from the heap. + /// + /// Node to be removed. + private void Remove(FibonacciNode node) + { + if (node != null) { - var queue = new Queue>(); - queue.Enqueue(currentNode); - while (queue.Count > 0) - { - currentNode = queue.Dequeue(); - var oldNode = currentNode; - do - { - yield return currentNode.Value; - if (currentNode.HasChildren()) - { - queue.Enqueue(currentNode.Child); - } - currentNode = currentNode.Previous; - } while (currentNode != oldNode); - } - - } - /// - /// Recursively remove the node and its children from the heap. - /// - /// Node to be removed. - private void Remove(FibonacciNode node) - { - if (node != null) - { - var current = node; - do - { - Remove(current.Child); - if (current.Parent != null) - { - current.Parent.Child = null; - } - current = current.Next; - } while (current != node); - current.Next = current.Previous = current.Child = current.Parent = null; - } - } - /// - /// Merge two heaps into a larger heap. - /// - /// Root of first heap. - /// Root of second heap. - private FibonacciNode Merge(FibonacciNode node1, FibonacciNode node2) - { - if (node1 == null) - { - return node2; - } - if (node2 == null) - { - return node1; - } - if (node1.Value.CompareTo(node2.Value) > 0) - { - var temp = node1; - node1 = node2; - node2 = temp; - } - var node1Next = node1.Next; - var node2Prev = node2.Previous; - node1.Next = node2; - node2.Previous = node1; - node1Next.Previous = node2Prev; - node2Prev.Next = node1Next; - return node1; - } - /// - /// Adds child to the parent. - /// - /// Parent node to accept child. - /// Child node to be added to the parent. - private void AddChild(FibonacciNode parent, FibonacciNode child) - { - child.Previous = child.Next = child; - child.Parent = parent; - parent.Degree++; - parent.Child = Merge(parent.Child, child); - } - /// - /// Removes the parent of the specified node. - /// - /// Node to be removed from its parent. - private void RemoveParent(FibonacciNode node) - { - if (node == null) - { - return; - } var current = node; do { - current.Marked = false; - current.Parent = null; + this.Remove(current.Child); + if (current.Parent != null) + { + current.Parent.Child = null; + } + current = current.Next; } while (current != node); + current.Next = current.Previous = current.Child = current.Parent = null; } - /// - /// Removes the minimum node from the provided tree. - /// - /// Root of the provided tree. - /// - private FibonacciNode RemoveMinimum(FibonacciNode node) + } + /// + /// Merge two heaps into a larger heap. + /// + /// Root of first heap. + /// Root of second heap. + private FibonacciNode Merge(FibonacciNode node1, FibonacciNode node2) + { + if (node1 == null) { - RemoveParent(node.Child); - if (node.Next == node) + return node2; + } + + if (node2 == null) + { + return node1; + } + + if (node1.Value.CompareTo(node2.Value) > 0) + { + var temp = node1; + node1 = node2; + node2 = temp; + } + + var node1Next = node1.Next; + var node2Prev = node2.Previous; + node1.Next = node2; + node2.Previous = node1; + node1Next.Previous = node2Prev; + node2Prev.Next = node1Next; + return node1; + } + /// + /// Adds child to the parent. + /// + /// Parent node to accept child. + /// Child node to be added to the parent. + private void AddChild(FibonacciNode parent, FibonacciNode child) + { + child.Previous = child.Next = child; + child.Parent = parent; + parent.Degree++; + parent.Child = this.Merge(parent.Child, child); + } + /// + /// Removes the parent of the specified node. + /// + /// Node to be removed from its parent. + private void RemoveParent(FibonacciNode node) + { + if (node == null) + { + return; + } + + var current = node; + do + { + current.Marked = false; + current.Parent = null; + current = current.Next; + } while (current != node); + } + /// + /// Removes the minimum node from the provided tree. + /// + /// Root of the provided tree. + /// + private FibonacciNode RemoveMinimum(FibonacciNode node) + { + this.RemoveParent(node.Child); + if (node.Next == node) + { + node = node.Child; + } + else + { + node.Next.Previous = node.Previous; + node.Previous.Next = node.Next; + node = this.Merge(node.Next, node.Child); + } + + if (node == null) + { + return node; + } + + var trees = new FibonacciNode[64]; + while (true) + { + if (trees[node.Degree] != null) { - node = node.Child; + var t = trees[node.Degree]; + if (t == node) + { + break; + } + + trees[node.Degree] = null; + if (node.Value.CompareTo(t.Value) < 0) + { + t.Previous.Next = t.Next; + t.Next.Previous = t.Previous; + this.AddChild(node, t); + } + else + { + t.Previous.Next = t.Next; + t.Next.Previous = t.Previous; + if (node.Next == node) + { + t.Next = t.Previous = t; + this.AddChild(t, node); + node = t; + } + else + { + node.Previous.Next = t; + node.Next.Previous = t; + t.Next = node.Next; + t.Previous = node.Previous; + this.AddChild(t, node); + node = t; + } + } + + continue; } else { - node.Next.Previous = node.Previous; - node.Previous.Next = node.Next; - node = Merge(node.Next, node.Child); + trees[node.Degree] = node; } - if (node == null) + + node = node.Next; + } + + var min = node; + var start = node; + do + { + if (node.Value.CompareTo(min.Value) < 0) + { + min = node; + } + + node = node.Next; + } while (node != start); + return min; + } + /// + /// Cut node from heap. + /// + /// Root of heap. + /// Node to be cut. + /// + private FibonacciNode Cut(FibonacciNode root, FibonacciNode node) + { + if (node.Next == node) + { + node.Parent.Child = null; + } + else + { + node.Next.Previous = node.Previous; + node.Previous.Next = node.Next; + node.Parent.Child = node.Next; + } + + node.Next = node.Previous = node; + node.Marked = false; + return this.Merge(root, node); + } + /// + /// Decrease value of provided node substituting it with the provided value. + /// + /// Root of the heap. + /// Node to have value decreased. + /// New value of the node. It is only applied if the value is lower than the previous value. + /// + private FibonacciNode DecreaseKey(FibonacciNode root, FibonacciNode node, T value) + { + if (node.Value.CompareTo(value) < 0) + { + return root; + } + + node.Value = value; + if (node.Parent != null) + { + if (node.Value.CompareTo(node.Parent.Value) < 0) + { + root = this.Cut(root, node); + var parent = node.Parent; + node.Parent = null; + while (parent != null && parent.Marked) + { + root = this.Cut(root, parent); + node = parent; + parent = node.Parent; + node.Parent = null; + } + + if (parent != null && parent.Parent != null) + { + parent.Marked = true; + } + } + } + else + { + if (node.Value.CompareTo(root.Value) < 0) + { + root = node; + } + } + + return root; + } + /// + /// Find the node that has the specified value in the heap. + /// + /// Root of the heap. + /// Value to be found. + /// + private FibonacciNode Find(FibonacciNode root, T value) + { + var node = root; + if (node == null) + { + return null; + } + + do + { + if (node.Value.CompareTo(value) == 0) { return node; } - var trees = new FibonacciNode[64]; - while (true) + var ret = this.Find(node.Child, value); + if (ret != null) { - if (trees[node.Degree] != null) - { - var t = trees[node.Degree]; - if (t == node) - { - break; - } - trees[node.Degree] = null; - if (node.Value.CompareTo(t.Value) < 0) - { - t.Previous.Next = t.Next; - t.Next.Previous = t.Previous; - AddChild(node, t); - } - else - { - t.Previous.Next = t.Next; - t.Next.Previous = t.Previous; - if (node.Next == node) - { - t.Next = t.Previous = t; - AddChild(t, node); - node = t; - } - else - { - node.Previous.Next = t; - node.Next.Previous = t; - t.Next = node.Next; - t.Previous = node.Previous; - AddChild(t, node); - node = t; - } - } - continue; - } - else - { - trees[node.Degree] = node; - } - node = node.Next; + return ret; } - var min = node; - var start = node; - do - { - if (node.Value.CompareTo(min.Value) < 0) - { - min = node; - } - node = node.Next; - } while (node != start); - return min; - } - /// - /// Cut node from heap. - /// - /// Root of heap. - /// Node to be cut. - /// - private FibonacciNode Cut(FibonacciNode root, FibonacciNode node) - { - if (node.Next == node) - { - node.Parent.Child = null; - } - else - { - node.Next.Previous = node.Previous; - node.Previous.Next = node.Next; - node.Parent.Child = node.Next; - } - node.Next = node.Previous = node; - node.Marked = false; - return Merge(root, node); - } - /// - /// Decrease value of provided node substituting it with the provided value. - /// - /// Root of the heap. - /// Node to have value decreased. - /// New value of the node. It is only applied if the value is lower than the previous value. - /// - private FibonacciNode DecreaseKey(FibonacciNode root, FibonacciNode node, T value) - { - if (node.Value.CompareTo(value) < 0) - { - return root; - } - node.Value = value; - if (node.Parent != null) - { - if (node.Value.CompareTo(node.Parent.Value) < 0) - { - root = Cut(root, node); - var parent = node.Parent; - node.Parent = null; - while (parent != null && parent.Marked) - { - root = Cut(root, parent); - node = parent; - parent = node.Parent; - node.Parent = null; - } - if (parent != null && parent.Parent != null) - { - parent.Marked = true; - } - } - } - else - { - if (node.Value.CompareTo(root.Value) < 0) - { - root = node; - } - } - return root; - } - /// - /// Find the node that has the specified value in the heap. - /// - /// Root of the heap. - /// Value to be found. - /// - private FibonacciNode Find(FibonacciNode root, T value) - { - var node = root; - if (node == null) - { - return null; - } - do - { - if (node.Value.CompareTo(value) == 0) - { - return node; - } - var ret = Find(node.Child, value); - if (ret != null) - { - return ret; - } - node = node.Next; - } while (node != root); - return null; - } - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - #endregion + + node = node.Next; + } while (node != root); + return null; } - [Serializable] - internal sealed class FibonacciNode + IEnumerator IEnumerable.GetEnumerator() { - #region Fields - private FibonacciNode previous; - private FibonacciNode next; - private FibonacciNode child; - private FibonacciNode parent; - private T value; - private int degree; - private bool marked; - #endregion - #region Properties - public FibonacciNode Previous - { - get - { - return previous; - } - set - { - previous = value; - } - } - public FibonacciNode Next - { - get - { - return next; - } - set - { - next = value; - } - } - public FibonacciNode Child - { - get - { - return child; - } - set - { - child = value; - } - } - public FibonacciNode Parent - { - get - { - return parent; - } - set - { - parent = value; - } - } - public bool Marked - { - get - { - return marked; - } - set - { - marked = value; - } - } - public T Value - { - get - { - return value; - } - set - { - this.value = value; - } - } - public int Degree - { - get - { - return degree; - } - set - { - degree = value; - } - } - #endregion - #region Public Methods - public bool HasChildren() - { - return child != null; - } - public bool HasParent() - { - return parent != null; - } - #endregion + throw new NotImplementedException(); } + #endregion +} +[Serializable] +internal sealed class FibonacciNode +{ + #region Fields + private FibonacciNode previous; + private FibonacciNode next; + private FibonacciNode child; + private FibonacciNode parent; + private T value; + private int degree; + private bool marked; + #endregion + #region Properties + public FibonacciNode Previous + { + get + { + return this.previous; + } + set + { + this.previous = value; + } + } + public FibonacciNode Next + { + get + { + return this.next; + } + set + { + this.next = value; + } + } + public FibonacciNode Child + { + get + { + return this.child; + } + set + { + this.child = value; + } + } + public FibonacciNode Parent + { + get + { + return this.parent; + } + set + { + this.parent = value; + } + } + public bool Marked + { + get + { + return this.marked; + } + set + { + this.marked = value; + } + } + public T Value + { + get + { + return this.value; + } + set + { + this.value = value; + } + } + public int Degree + { + get + { + return this.degree; + } + set + { + this.degree = value; + } + } + #endregion + #region Public Methods + public bool HasChildren() + { + return this.child != null; + } + public bool HasParent() + { + return this.parent != null; + } + #endregion } diff --git a/SystemExtensions.NetStandard/Collections/IQueue.cs b/SystemExtensions.NetStandard/Collections/IQueue.cs index 6ac424e..e53b0f9 100644 --- a/SystemExtensions.NetStandard/Collections/IQueue.cs +++ b/SystemExtensions.NetStandard/Collections/IQueue.cs @@ -1,39 +1,38 @@ -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// +/// Interface for queue implementations. +/// +/// Provided type. +public interface IQueue : IEnumerable { /// - /// Interface for queue implementations. + /// Returns the number of items in the queue. /// - /// Provided type. - public interface IQueue : IEnumerable - { - /// - /// Returns the number of items in the queue. - /// - int Count { get; } - /// - /// Inserts item into the queue. - /// - /// Item to be inserted. - void Enqueue(T item); - /// - /// Remove the first item in the queue. - /// - /// First item in the queue. - T Dequeue(); - /// - /// Looks up the first item from the queue without removing it. - /// - /// First item from the queue. - T Peek(); - /// - /// Clears the contents of the queue. - /// - void Clear(); - /// - /// Checks if queue contains an item. - /// - /// Item to be checked. - /// True if queue contains provided item. False otherwise. - bool Contains(T item); - } + int Count { get; } + /// + /// Inserts item into the queue. + /// + /// Item to be inserted. + void Enqueue(T item); + /// + /// Remove the first item in the queue. + /// + /// First item in the queue. + T Dequeue(); + /// + /// Looks up the first item from the queue without removing it. + /// + /// First item from the queue. + T Peek(); + /// + /// Clears the contents of the queue. + /// + void Clear(); + /// + /// Checks if queue contains an item. + /// + /// Item to be checked. + /// True if queue contains provided item. False otherwise. + bool Contains(T item); } diff --git a/SystemExtensions.NetStandard/Collections/PriorityQueue.cs b/SystemExtensions.NetStandard/Collections/PriorityQueue.cs index b904093..299f940 100644 --- a/SystemExtensions.NetStandard/Collections/PriorityQueue.cs +++ b/SystemExtensions.NetStandard/Collections/PriorityQueue.cs @@ -1,103 +1,102 @@ -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// +/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap. +/// Exposes some of the functionality of the Binary Heap as a queue. +/// +/// Provided type. +[Serializable] +public sealed class PriorityQueue : IQueue where T : IComparable { + #region Fields + private readonly BinaryHeap binaryHeap; + #endregion + #region Properties /// - /// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap. - /// Exposes some of the functionality of the Binary Heap as a queue. + /// Returns the number of elements stored into the queue. /// - /// Provided type. - [Serializable] - public sealed class PriorityQueue : IQueue where T : IComparable + public int Count { - #region Fields - private readonly BinaryHeap binaryHeap; - #endregion - #region Properties - /// - /// Returns the number of elements stored into the queue. - /// - public int Count + get { - get - { - return binaryHeap.Count; - } + return this.binaryHeap.Count; } - #endregion - #region Constructors - /// - /// Constructor for priority queue data structure. - /// - public PriorityQueue() - { - binaryHeap = new BinaryHeap(); - } - #endregion - #region Public Methods - /// - /// Add provided value to the queue. - /// - /// Value to be added to the queue. - public void Enqueue(T value) - { - binaryHeap.Add(value); - } - /// - /// Pops the queue and removes the highest priority value from the queue. - /// - /// Highest priority value from the queue - public T Dequeue() - { - if (Count > 0) - { - return binaryHeap.Remove(); - } - else - { - throw new IndexOutOfRangeException("Queue is empty!"); - } - } - /// - /// Looks up the highest priority value from the queue. Doesn't alter the queue in any way. - /// - /// Highest priority value from the queue. - public T Peek() - { - return binaryHeap.Min; - } - /// - /// Clears the queue contents, removing any value stored into the queue. - /// - public void Clear() - { - binaryHeap.Clear(); - } - /// - /// Checks if queue contains provided item. - /// - /// Item to be checked. - /// True if queue contains the provided item. False otherwise. - public bool Contains(T item) - { - return binaryHeap.Contains(item); - } - /// - /// Returns an enumerator that iterates over the queue. - /// - /// Enumerator that iterates over the queue. - public IEnumerator GetEnumerator() - { - return binaryHeap.GetEnumerator(); - } - #endregion - #region Private Methods - /// - /// Necesarry for the implementatio of IQueue. - /// - /// - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - #endregion } + #endregion + #region Constructors + /// + /// Constructor for priority queue data structure. + /// + public PriorityQueue() + { + this.binaryHeap = new BinaryHeap(); + } + #endregion + #region Public Methods + /// + /// Add provided value to the queue. + /// + /// Value to be added to the queue. + public void Enqueue(T value) + { + this.binaryHeap.Add(value); + } + /// + /// Pops the queue and removes the highest priority value from the queue. + /// + /// Highest priority value from the queue + public T Dequeue() + { + if (this.Count > 0) + { + return this.binaryHeap.Remove(); + } + else + { + throw new IndexOutOfRangeException("Queue is empty!"); + } + } + /// + /// Looks up the highest priority value from the queue. Doesn't alter the queue in any way. + /// + /// Highest priority value from the queue. + public T Peek() + { + return this.binaryHeap.Min; + } + /// + /// Clears the queue contents, removing any value stored into the queue. + /// + public void Clear() + { + this.binaryHeap.Clear(); + } + /// + /// Checks if queue contains provided item. + /// + /// Item to be checked. + /// True if queue contains the provided item. False otherwise. + public bool Contains(T item) + { + return this.binaryHeap.Contains(item); + } + /// + /// Returns an enumerator that iterates over the queue. + /// + /// Enumerator that iterates over the queue. + public IEnumerator GetEnumerator() + { + return this.binaryHeap.GetEnumerator(); + } + #endregion + #region Private Methods + /// + /// Necesarry for the implementatio of IQueue. + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + #endregion } diff --git a/SystemExtensions.NetStandard/Collections/SkipList.cs b/SystemExtensions.NetStandard/Collections/SkipList.cs index 3ed1d0c..13a35b0 100644 --- a/SystemExtensions.NetStandard/Collections/SkipList.cs +++ b/SystemExtensions.NetStandard/Collections/SkipList.cs @@ -1,236 +1,248 @@ -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// +/// Skip list implementation. +/// +/// Provided type. +[Serializable] +public sealed class SkipList : ICollection where T : IComparable { - /// - /// Skip list implementation. - /// - /// Provided type. + #region Fields [Serializable] - public sealed class SkipList : ICollection where T : IComparable + private class NodeSet { - #region Fields - [Serializable] - private class NodeSet - { - public TKey Key; - public int Level; - public NodeSet[] Next; + public TKey Key; + public int Level; + public NodeSet[] Next; - public NodeSet(TKey key, int level) - { - this.Key = key; - this.Level = level; - Next = new NodeSet[level + 1]; - } - } - private int count; - private readonly Random random; - private readonly NodeSet head; - private readonly NodeSet end; - private readonly int maxLevel = 10; - private int level; - #endregion - #region Properties - /// - /// Number of elements in the list. - /// - public int Count { get => count; } - /// - /// Specifies if the collection can be modified. - /// - public bool IsReadOnly { get; set; } - #endregion - #region Constructors - /// - /// Creates a new instance of SkipList collection. - /// - /// Maximum level of the skip list. - public SkipList(int maxLevel = 10) + public NodeSet(TKey key, int level) { - this.maxLevel = maxLevel; - random = new Random(); - head = new NodeSet(default, maxLevel); - end = head; - for (var i = 0; i <= maxLevel; i++) - { - head.Next[i] = end; - } + this.Key = key; + this.Level = level; + this.Next = new NodeSet[level + 1]; + } + } + private int count; + private readonly Random random; + private readonly NodeSet head; + private readonly NodeSet end; + private readonly int maxLevel = 10; + private int level; + #endregion + #region Properties + /// + /// Number of elements in the list. + /// + public int Count { get => this.count; } + /// + /// Specifies if the collection can be modified. + /// + public bool IsReadOnly { get; set; } + #endregion + #region Constructors + /// + /// Creates a new instance of SkipList collection. + /// + /// Maximum level of the skip list. + public SkipList(int maxLevel = 10) + { + this.maxLevel = maxLevel; + this.random = new Random(); + this.head = new NodeSet(default, maxLevel); + this.end = this.head; + for (var i = 0; i <= maxLevel; i++) + { + this.head.Next[i] = this.end; + } + } + + #endregion + #region Public Methods + /// + /// Adds an item to the collection. + /// + /// Item to be added. + public void Add(T item) + { + var curNode = this.head; + var newLevel = 0; + while (this.random.Next(0, 2) > 0 && newLevel < this.maxLevel) + { + newLevel++; } - #endregion - #region Public Methods - /// - /// Adds an item to the collection. - /// - /// Item to be added. - public void Add(T item) + if (newLevel > this.level) { - var curNode = head; - var newLevel = 0; - while (random.Next(0, 2) > 0 && newLevel < maxLevel) - { - newLevel++; - } - if (newLevel > level) - { - level = newLevel; - } - var newNode = new NodeSet(item, newLevel); - for (var i = 0; i <= newLevel; i++) - { - if (i > curNode.Level) - { - curNode = head; - } - while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0) - { - curNode = curNode.Next[i]; - } - newNode.Next[i] = curNode.Next[i]; - curNode.Next[i] = newNode; - } - count++; + this.level = newLevel; } - /// - /// Removes provided item from the collection. - /// - /// Item to be removed. - /// True if removal was successful. - public bool Remove(T item) + + var newNode = new NodeSet(item, newLevel); + for (var i = 0; i <= newLevel; i++) { - var removed = false; - var curNode = head; - for (var i = 0; i <= maxLevel; i++) + if (i > curNode.Level) { - if (i > curNode.Level) - { - curNode = head; - } - while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0) - { - curNode = curNode.Next[i]; - } - if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level - { - curNode.Next[i] = curNode.Next[i].Next[i]; - removed = true; - } - else - { - break; - } + curNode = this.head; } - if (removed) + + while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0) { - count--; - return true; + curNode = curNode.Next[i]; + } + + newNode.Next[i] = curNode.Next[i]; + curNode.Next[i] = newNode; + } + + this.count++; + } + /// + /// Removes provided item from the collection. + /// + /// Item to be removed. + /// True if removal was successful. + public bool Remove(T item) + { + var removed = false; + var curNode = this.head; + for (var i = 0; i <= this.maxLevel; i++) + { + if (i > curNode.Level) + { + curNode = this.head; + } + + while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0) + { + curNode = curNode.Next[i]; + } + + if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level + { + curNode.Next[i] = curNode.Next[i].Next[i]; + removed = true; } else { - return false; + break; } } - /// - /// Clears the collection. - /// - public void Clear() + + if (removed) { - for (var i = 0; i < maxLevel; i++) - { - head.Next[i] = end; - } - count = 0; + this.count--; + return true; } - /// - /// Checks if item is present in the collection. - /// - /// Item to be checked. - /// True if item is present in the collection. - public bool Contains(T item) + else { - if (Find(item) != null) - { - return true; - } return false; } - /// - /// Copies the skip list contents onto the provided array. - /// - /// Array to hold the values from the list. - /// Index to start insertion in the array. - public void CopyTo(T[] array, int arrayIndex) - { - var node = head.Next[0]; - while (node != end) - { - array[arrayIndex] = node.Key; - arrayIndex++; - node = node.Next[0]; - } - } - /// - /// Copies the elements from the collection into an array. - /// - /// Array filled with elements from the collection. - public T[] ToArray() - { - var array = new T[count]; - var index = 0; - var curNode = head.Next[0]; - while (curNode != end) - { - array[index] = curNode.Key; - index++; - curNode = curNode.Next[0]; - } - return array; - } - /// - /// Enumerator that iterates over the collection. - /// - /// - public IEnumerator GetEnumerator() - { - var curNode = head.Next[0]; - while (curNode != end) - { - yield return curNode.Key; - curNode = curNode.Next[0]; - } - } - #endregion - #region Private Methods - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - private NodeSet Find(T key) - { - var curNode = head; - - for (var i = level; i >= 0; i--) - { - while (curNode.Next[i] != end) - { - if (curNode.Next[i].Key.CompareTo(key) > 0) - { - break; - } - else if (curNode.Next[i].Key.CompareTo(key) == 0) - { - return curNode.Next[i]; - } - curNode = curNode.Next[i]; - } - } - - curNode = curNode.Next[0]; - if (curNode != end && curNode.Key.CompareTo(key) == 0) - { - return curNode; - } - return null; - } - #endregion } + /// + /// Clears the collection. + /// + public void Clear() + { + for (var i = 0; i < this.maxLevel; i++) + { + this.head.Next[i] = this.end; + } + + this.count = 0; + } + /// + /// Checks if item is present in the collection. + /// + /// Item to be checked. + /// True if item is present in the collection. + public bool Contains(T item) + { + if (this.Find(item) != null) + { + return true; + } + + return false; + } + /// + /// Copies the skip list contents onto the provided array. + /// + /// Array to hold the values from the list. + /// Index to start insertion in the array. + public void CopyTo(T[] array, int arrayIndex) + { + var node = this.head.Next[0]; + while (node != this.end) + { + array[arrayIndex] = node.Key; + arrayIndex++; + node = node.Next[0]; + } + } + /// + /// Copies the elements from the collection into an array. + /// + /// Array filled with elements from the collection. + public T[] ToArray() + { + var array = new T[this.count]; + var index = 0; + var curNode = this.head.Next[0]; + while (curNode != this.end) + { + array[index] = curNode.Key; + index++; + curNode = curNode.Next[0]; + } + + return array; + } + /// + /// Enumerator that iterates over the collection. + /// + /// + public IEnumerator GetEnumerator() + { + var curNode = this.head.Next[0]; + while (curNode != this.end) + { + yield return curNode.Key; + curNode = curNode.Next[0]; + } + } + #endregion + #region Private Methods + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + private NodeSet Find(T key) + { + var curNode = this.head; + + for (var i = this.level; i >= 0; i--) + { + while (curNode.Next[i] != this.end) + { + if (curNode.Next[i].Key.CompareTo(key) > 0) + { + break; + } + else if (curNode.Next[i].Key.CompareTo(key) == 0) + { + return curNode.Next[i]; + } + + curNode = curNode.Next[i]; + } + } + + curNode = curNode.Next[0]; + if (curNode != this.end && curNode.Key.CompareTo(key) == 0) + { + return curNode; + } + + return null; + } + #endregion } diff --git a/SystemExtensions.NetStandard/Collections/Treap.cs b/SystemExtensions.NetStandard/Collections/Treap.cs index 372f97f..49323c0 100644 --- a/SystemExtensions.NetStandard/Collections/Treap.cs +++ b/SystemExtensions.NetStandard/Collections/Treap.cs @@ -1,280 +1,287 @@ -namespace System.Collections.Generic +namespace System.Collections.Generic; + +/// +/// Treap implementation. +/// +/// Provided type. +[Serializable] +public sealed class Treap : ICollection where T : IComparable { - /// - /// Treap implementation. - /// - /// Provided type. + #region Fields [Serializable] - public sealed class Treap : ICollection where T : IComparable + private class Node { - #region Fields - [Serializable] - private class Node + public TKey Key; + public int Priority; + public Node Left, Right; + public Node(TKey key, int priority) { - public TKey Key; - public int Priority; - public Node Left, Right; - public Node(TKey key, int priority) - { - Key = key; - Priority = priority; - Left = null; - Right = null; - } + this.Key = key; + this.Priority = priority; + this.Left = null; + this.Right = null; } - private readonly Random randomGen; - private Node root; - private int count; - #endregion - #region Properties - /// - /// Count of values in the treap. - /// - public int Count - { - get - { - return count; - } - } - /// - /// Not implemented. - /// - public bool IsReadOnly => false; - #endregion - #region Constructors - /// - /// Constructor for treap. - /// - public Treap() - { - randomGen = new Random(); - } - #endregion - #region Public Methods - /// - /// Adds value to the treap. - /// - /// Value to be added. - public void Add(T value) - { - root = InsertNode(root, value); - count++; - } - /// - /// Removes value from treap. - /// - /// Value to be removed. - public bool Remove(T value) - { - root = RemoveNode(root, value); - count--; - return true; - } - /// - /// Clears the treap. - /// - public void Clear() - { - Clear(root); - root = null; - count = 0; - } - /// - /// Determines whether the treap contains the specified value. - /// - /// Value to locate in the treap. - /// - public bool Contains(T value) - { - return Find(root, value) != null; - } - /// - /// Returns the treap structure as an ordered array. - /// - /// Ordered array containing the values stored in the treap. - public T[] ToArray() - { - if (root != null) - { - var array = new T[count]; - var index = 0; - ToArray(root, ref array, ref index); - return array; - } - else - { - return null; - } - } - /// - /// Copy the treap into the provided array. - /// - /// Array to be populated with the values contained in the array. - /// Starting index of the array. - public void CopyTo(T[] array, int arrayIndex) - { - ToArray(root, ref array, ref arrayIndex); - } - /// - /// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted. - /// - /// Enumerator that iterates over the treap. - public IEnumerator GetEnumerator() - { - return GetEnumerator(root); - } - #endregion - #region Private Methods - private Node InsertNode(Node node, T key) - { - if (node == null) - { - node = new Node(key, randomGen.Next(0, 100)); - return node; - } - else if (key.CompareTo(node.Key) <= 0) - { - node.Left = InsertNode(node.Left, key); - if (node.Left.Priority > node.Priority) - { - node = RotateRight(node); - } - } - else - { - node.Right = InsertNode(node.Right, key); - if (node.Right.Priority > node.Priority) - { - node = RotateLeft(node); - } - } - return node; - } - private Node RemoveNode(Node node, T key) - { - if (node == null) - { - return node; - } - if (key.CompareTo(node.Key) < 0) - { - node.Left = RemoveNode(node.Left, key); - } - else if (key.CompareTo(node.Key) > 0) - { - node.Right = RemoveNode(node.Right, key); - } - else if (node.Left == null) - { - node = node.Right; - } - else if (node.Right == null) - { - node = node.Left; - } - else if (node.Left.Priority < node.Right.Priority) - { - node = RotateLeft(node); - node.Left = RemoveNode(node.Left, key); - } - else - { - node = RotateRight(node); - node.Right = RemoveNode(node.Right, key); - } - return node; - } - private Node RotateRight(Node node) - { - Node temp = node.Left, temp2 = temp.Right; - temp.Right = node; - node.Left = temp2; - return temp; - } - private Node RotateLeft(Node node) - { - Node temp = node.Right, temp2 = temp.Left; - temp.Left = node; - node.Right = temp2; - return temp; - } - private void Clear(Node node) - { - if (node.Left != null) - { - Clear(node.Left); - } - if (node.Right != null) - { - Clear(node.Right); - } - node.Left = node.Right = null; - } - private Node Find(Node node, T key) - { - if (node == null) - { - return node; - } - else - { - if (node.Key.CompareTo(key) < 0) - { - var found = Find(node.Left, key); - if (found == null) - { - found = Find(node.Right, key); - } - return found; - } - else if (node.Key.CompareTo(key) > 0) - { - var found = Find(node.Right, key); - if (found == null) - { - found = Find(node.Left, key); - } - return found; - } - else - { - return node; - } - } - } - private void ToArray(Node node, ref T[] array, ref int index) - { - if (node != null) - { - ToArray(node.Left, ref array, ref index); - array[index] = node.Key; - index++; - ToArray(node.Right, ref array, ref index); - } - } - private IEnumerator GetEnumerator(Node currentNode) - { - var queue = new Queue>(); - queue.Enqueue(currentNode); - while (queue.Count > 0) - { - currentNode = queue.Dequeue(); - yield return currentNode.Key; - if (currentNode.Left != null) - { - queue.Enqueue(currentNode.Left); - } - if (currentNode.Right != null) - { - queue.Enqueue(currentNode.Right); - } - } - } - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - #endregion } + private readonly Random randomGen; + private Node root; + private int count; + #endregion + #region Properties + /// + /// Count of values in the treap. + /// + public int Count + { + get + { + return this.count; + } + } + /// + /// Not implemented. + /// + public bool IsReadOnly => false; + #endregion + #region Constructors + /// + /// Constructor for treap. + /// + public Treap() + { + this.randomGen = new Random(); + } + #endregion + #region Public Methods + /// + /// Adds value to the treap. + /// + /// Value to be added. + public void Add(T value) + { + this.root = this.InsertNode(this.root, value); + this.count++; + } + /// + /// Removes value from treap. + /// + /// Value to be removed. + public bool Remove(T value) + { + this.root = this.RemoveNode(this.root, value); + this.count--; + return true; + } + /// + /// Clears the treap. + /// + public void Clear() + { + this.Clear(this.root); + this.root = null; + this.count = 0; + } + /// + /// Determines whether the treap contains the specified value. + /// + /// Value to locate in the treap. + /// + public bool Contains(T value) + { + return this.Find(this.root, value) != null; + } + /// + /// Returns the treap structure as an ordered array. + /// + /// Ordered array containing the values stored in the treap. + public T[] ToArray() + { + if (this.root != null) + { + var array = new T[this.count]; + var index = 0; + this.ToArray(this.root, ref array, ref index); + return array; + } + else + { + return null; + } + } + /// + /// Copy the treap into the provided array. + /// + /// Array to be populated with the values contained in the array. + /// Starting index of the array. + public void CopyTo(T[] array, int arrayIndex) + { + this.ToArray(this.root, ref array, ref arrayIndex); + } + /// + /// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted. + /// + /// Enumerator that iterates over the treap. + public IEnumerator GetEnumerator() + { + return this.GetEnumerator(this.root); + } + #endregion + #region Private Methods + private Node InsertNode(Node node, T key) + { + if (node == null) + { + node = new Node(key, this.randomGen.Next(0, 100)); + return node; + } + else if (key.CompareTo(node.Key) <= 0) + { + node.Left = this.InsertNode(node.Left, key); + if (node.Left.Priority > node.Priority) + { + node = this.RotateRight(node); + } + } + else + { + node.Right = this.InsertNode(node.Right, key); + if (node.Right.Priority > node.Priority) + { + node = this.RotateLeft(node); + } + } + + return node; + } + private Node RemoveNode(Node node, T key) + { + if (node == null) + { + return node; + } + + if (key.CompareTo(node.Key) < 0) + { + node.Left = this.RemoveNode(node.Left, key); + } + else if (key.CompareTo(node.Key) > 0) + { + node.Right = this.RemoveNode(node.Right, key); + } + else if (node.Left == null) + { + node = node.Right; + } + else if (node.Right == null) + { + node = node.Left; + } + else if (node.Left.Priority < node.Right.Priority) + { + node = this.RotateLeft(node); + node.Left = this.RemoveNode(node.Left, key); + } + else + { + node = this.RotateRight(node); + node.Right = this.RemoveNode(node.Right, key); + } + + return node; + } + private Node RotateRight(Node node) + { + Node temp = node.Left, temp2 = temp.Right; + temp.Right = node; + node.Left = temp2; + return temp; + } + private Node RotateLeft(Node node) + { + Node temp = node.Right, temp2 = temp.Left; + temp.Left = node; + node.Right = temp2; + return temp; + } + private void Clear(Node node) + { + if (node.Left != null) + { + this.Clear(node.Left); + } + + if (node.Right != null) + { + this.Clear(node.Right); + } + + node.Left = node.Right = null; + } + private Node Find(Node node, T key) + { + if (node == null) + { + return node; + } + else + { + if (node.Key.CompareTo(key) < 0) + { + var found = this.Find(node.Left, key); + if (found == null) + { + found = this.Find(node.Right, key); + } + + return found; + } + else if (node.Key.CompareTo(key) > 0) + { + var found = this.Find(node.Right, key); + if (found == null) + { + found = this.Find(node.Left, key); + } + + return found; + } + else + { + return node; + } + } + } + private void ToArray(Node node, ref T[] array, ref int index) + { + if (node != null) + { + this.ToArray(node.Left, ref array, ref index); + array[index] = node.Key; + index++; + this.ToArray(node.Right, ref array, ref index); + } + } + private IEnumerator GetEnumerator(Node currentNode) + { + var queue = new Queue>(); + queue.Enqueue(currentNode); + while (queue.Count > 0) + { + currentNode = queue.Dequeue(); + yield return currentNode.Key; + if (currentNode.Left != null) + { + queue.Enqueue(currentNode.Left); + } + + if (currentNode.Right != null) + { + queue.Enqueue(currentNode.Right); + } + } + } + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + #endregion } diff --git a/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs b/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs index cbbe825..2dde536 100644 --- a/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs @@ -1,25 +1,24 @@ using System.IO; -namespace System.Extensions +namespace System.Extensions; + +public static class BytesExtensions { - public static class BytesExtensions + public static byte[] ReadAllBytes(this Stream stream) { - public static byte[] ReadAllBytes(this Stream stream) + if (stream is null) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - var buffer = new byte[256]; - using var ms = new MemoryStream(); - int read; - while ((read = stream.Read(buffer, 0, 256)) > 0) - { - ms.Write(buffer, 0, read); - } - - return ms.ToArray(); + throw new ArgumentNullException(nameof(stream)); } + + var buffer = new byte[256]; + using var ms = new MemoryStream(); + int read; + while ((read = stream.Read(buffer, 0, 256)) > 0) + { + ms.Write(buffer, 0, read); + } + + return ms.ToArray(); } } diff --git a/SystemExtensions.NetStandard/Extensions/CastExtensions.cs b/SystemExtensions.NetStandard/Extensions/CastExtensions.cs index 2ca904e..e785daf 100644 --- a/SystemExtensions.NetStandard/Extensions/CastExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/CastExtensions.cs @@ -1,50 +1,49 @@ -namespace System.Extensions +namespace System.Extensions; + +public static class CastExtensions { - public static class CastExtensions + public static int Floor(this double value) { - public static int Floor(this double value) - { - return (int)Math.Floor(value); - } + return (int)Math.Floor(value); + } - public static int Ceiling(this double value) - { - return (int)Math.Ceiling(value); - } + public static int Ceiling(this double value) + { + return (int)Math.Ceiling(value); + } - public static int Round(this double value) - { - return (int)Math.Round(value); - } + public static int Round(this double value) + { + return (int)Math.Round(value); + } - public static int Floor(this float value) - { - return (int)Math.Floor(value); - } + public static int Floor(this float value) + { + return (int)Math.Floor(value); + } - public static int Ceiling(this float value) - { - return (int)Math.Ceiling(value); - } + public static int Ceiling(this float value) + { + return (int)Math.Ceiling(value); + } - public static int Round(this float value) - { - return (int)Math.Round(value); - } + public static int Round(this float value) + { + return (int)Math.Round(value); + } - public static int ToInt(this double value) - { - return (int)value; - } + public static int ToInt(this double value) + { + return (int)value; + } - public static int ToInt(this float value) - { - return (int)value; - } + public static int ToInt(this float value) + { + return (int)value; + } - public static int ToInt(this decimal value) - { - return (int)value; - } + public static int ToInt(this decimal value) + { + return (int)value; } } diff --git a/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs b/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs index c4e95e2..cae8e74 100644 --- a/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs @@ -1,88 +1,88 @@ using System.Collections.Generic; using System.Linq; -namespace System.Extensions +namespace System.Extensions; + +public static class LinqExtensions { - public static class LinqExtensions + public static bool None(this IEnumerable enumerable, Func predicate) { - public static bool None(this IEnumerable enumerable, Func predicate) - { - enumerable.ThrowIfNull(nameof(enumerable)); - predicate.ThrowIfNull(nameof(predicate)); + enumerable.ThrowIfNull(nameof(enumerable)); + predicate.ThrowIfNull(nameof(predicate)); - return !enumerable.Any(predicate); + return !enumerable.Any(predicate); + } + + public static bool None(this IEnumerable enumerable) + { + enumerable.ThrowIfNull(nameof(enumerable)); + + return !enumerable.Any(); + } + + public static ICollection ClearAnd(this ICollection collection) + { + if (collection is null) + { + throw new ArgumentNullException(nameof(collection)); } - public static bool None(this IEnumerable enumerable) + collection.Clear(); + return collection; + } + + public static ICollection AddRange(this ICollection collection, IEnumerable values) + { + if (collection is null) { - enumerable.ThrowIfNull(nameof(enumerable)); - - return !enumerable.Any(); + throw new ArgumentNullException(nameof(collection)); } - public static ICollection ClearAnd(this ICollection collection) + if (values is null) { - if (collection is null) - { - throw new ArgumentNullException(nameof(collection)); - } - - collection.Clear(); - return collection; - } - - public static ICollection AddRange(this ICollection collection, IEnumerable values) - { - if (collection is null) - { - throw new ArgumentNullException(nameof(collection)); - } - - if (values is null) - { - throw new ArgumentNullException(nameof(values)); - } - - foreach (var item in values) - { - collection.Add(item); - } - - return collection; + throw new ArgumentNullException(nameof(values)); } - public static int IndexOfWhere(this ICollection collection, Func selector) + foreach (var item in values) { - if (collection is null) - { - throw new ArgumentNullException(nameof(collection)); - } - - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - var index = 0; - foreach (var item in collection) - { - if (selector(item)) - { - return index; - } - index++; - } - - return -1; + collection.Add(item); } - public static IEnumerable Do(this IEnumerable enumerable, Action action) + return collection; + } + + public static int IndexOfWhere(this ICollection collection, Func selector) + { + if (collection is null) { - foreach(var value in enumerable) + throw new ArgumentNullException(nameof(collection)); + } + + if (selector is null) + { + throw new ArgumentNullException(nameof(selector)); + } + + var index = 0; + foreach (var item in collection) + { + if (selector(item)) { - action(value); - yield return value; + return index; } + + index++; + } + + return -1; + } + + public static IEnumerable Do(this IEnumerable enumerable, Action action) + { + foreach(var value in enumerable) + { + action(value); + yield return value; } } } diff --git a/SystemExtensions.NetStandard/Extensions/LoggingExtensions.cs b/SystemExtensions.NetStandard/Extensions/LoggingExtensions.cs index d1894dd..91a3dd1 100644 --- a/SystemExtensions.NetStandard/Extensions/LoggingExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/LoggingExtensions.cs @@ -1,13 +1,12 @@ using Microsoft.Extensions.Logging; using System.Logging; -namespace System.Extensions +namespace System.Extensions; + +public static class LoggingExtensions { - public static class LoggingExtensions + public static ScopedLogger CreateScopedLogger(this ILogger logger, string methodName, string flowIdentifier) { - public static ScopedLogger CreateScopedLogger(this ILogger logger, string methodName, string flowIdentifier) - { - return ScopedLogger.Create(logger, methodName, flowIdentifier); - } + return ScopedLogger.Create(logger, methodName, flowIdentifier); } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs b/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs index 9790b7d..eda89f3 100644 --- a/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs @@ -1,59 +1,58 @@ using Newtonsoft.Json; -namespace System.Extensions +namespace System.Extensions; + +public static class ObjectExtensions { - public static class ObjectExtensions + public static T Deserialize(this string serialized) + where T : class { - public static T Deserialize(this string serialized) - where T : class + if (serialized.IsNullOrWhiteSpace()) { - if (serialized.IsNullOrWhiteSpace()) - { - throw new ArgumentException("Provided serialized string cannot be null or whitespace", nameof(serialized)); - } - - return JsonConvert.DeserializeObject(serialized); + throw new ArgumentException("Provided serialized string cannot be null or whitespace", nameof(serialized)); } - public static string Serialize(this T obj) - where T : class - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + return JsonConvert.DeserializeObject(serialized); + } - return JsonConvert.SerializeObject(obj); + public static string Serialize(this T obj) + where T : class + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); } - public static T Cast(this object obj) + return JsonConvert.SerializeObject(obj); + } + + public static T Cast(this object obj) + { + return (T)obj; + } + + public static T As(this object obj) where T : class + { + return obj as T; + } + + public static Optional ToOptional(this T obj) + { + return Optional.FromValue(obj); + } + + public static T ThrowIfNull([ValidatedNotNull] this T obj, string name) where T : class + { + if (obj is null) { - return (T)obj; + throw new ArgumentNullException(name); } - public static T As(this object obj) where T : class - { - return obj as T; - } + return obj; + } - public static Optional ToOptional(this T obj) - { - return Optional.FromValue(obj); - } - - public static T ThrowIfNull([ValidatedNotNull] this T obj, string name) where T : class - { - if (obj is null) - { - throw new ArgumentNullException(name); - } - - return obj; - } - - [AttributeUsage(AttributeTargets.Parameter)] - sealed class ValidatedNotNullAttribute : Attribute - { - } + [AttributeUsage(AttributeTargets.Parameter)] + sealed class ValidatedNotNullAttribute : Attribute + { } } diff --git a/SystemExtensions.NetStandard/Extensions/Optional.cs b/SystemExtensions.NetStandard/Extensions/Optional.cs index f70fd04..4ddc170 100644 --- a/SystemExtensions.NetStandard/Extensions/Optional.cs +++ b/SystemExtensions.NetStandard/Extensions/Optional.cs @@ -1,192 +1,193 @@ -namespace System.Extensions +namespace System.Extensions; + +public static class Optional { - public static class Optional + public static Optional None() { - public static Optional None() + return new Optional.None(); + } + + public static Optional FromValue(T value) + { + if (value == null) { return new Optional.None(); } - public static Optional FromValue(T value) - { - if (value == null) - { - return new Optional.None(); - } + return new Optional.Some(value); + } +} - return new Optional.Some(value); +public abstract class Optional : IEquatable> +{ + public Optional(T value) + { + this.Value = value; + } + + private T Value { get; } + + public T ExtractValue() + { + if (this is None) + { + return default; + } + else + { + return this.Value; + } + } + public Optional Do(Action onSome, Action onNone) + { + if (onSome is null) + { + throw new ArgumentNullException(nameof(onSome)); + } + + if (onNone is null) + { + throw new ArgumentNullException(nameof(onNone)); + } + + if (this is Some) + { + onSome.Invoke(this.Value); + } + else + { + onNone.Invoke(); + } + + return this; + } + public Optional DoAny(Action onSome = null, Action onNone = null) + { + if (this is Some) + { + onSome?.Invoke(this.Value); + } + else + { + onNone?.Invoke(); + } + + return this; + } + public Optional Switch(Func onSome, Func onNone) + { + if (onSome is null) + { + throw new ArgumentNullException($"{nameof(onSome)}"); + } + + if (onNone is null) + { + throw new ArgumentNullException($"{nameof(onNone)}"); + } + + if (this is Some) + { + return Optional.FromValue(onSome.Invoke(this.Value)); + } + else + { + return Optional.FromValue(onNone.Invoke()); + } + } + public Optional SwitchAny(Func onSome = null, Func onNone = null) + { + if (this is Some) + { + return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V)); + } + else + { + return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V)); } } - public abstract class Optional : IEquatable> + public override bool Equals(object obj) { - public Optional(T value) + if (obj is Optional) { - this.Value = value; + return this.Equals(obj); } - private T Value { get; } + return base.Equals(obj); + } - public T ExtractValue() + public bool Equals(Optional other) + { + if (this is Some && other is Some) { - if (this is None) - { - return default; - } - else - { - return Value; - } + return this.As().Equals(other.As()); } - public Optional Do(Action onSome, Action onNone) - { - if (onSome is null) - { - throw new ArgumentNullException(nameof(onSome)); - } - if (onNone is null) - { - throw new ArgumentNullException(nameof(onNone)); - } + return false; + } - if (this is Some) - { - onSome.Invoke(this.Value); - } - else - { - onNone.Invoke(); - } - return this; - } - public Optional DoAny(Action onSome = null, Action onNone = null) - { - if (this is Some) - { - onSome?.Invoke(this.Value); - } - else - { - onNone?.Invoke(); - } - return this; - } - public Optional Switch(Func onSome, Func onNone) - { - if (onSome is null) - { - throw new ArgumentNullException($"{nameof(onSome)}"); - } + public static implicit operator Optional(T value) + { + return Optional.FromValue(value); + } - if (onNone is null) - { - throw new ArgumentNullException($"{nameof(onNone)}"); - } + public override int GetHashCode() + { + return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode(); + } - if (this is Some) - { - return Optional.FromValue(onSome.Invoke(this.Value)); - } - else - { - return Optional.FromValue(onNone.Invoke()); - } - } - public Optional SwitchAny(Func onSome = null, Func onNone = null) + internal class Some : Optional, IEquatable + { + public Some(T value) : base(value) { - if (this is Some) - { - return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V)); - } - else - { - return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V)); - } } public override bool Equals(object obj) { - if (obj is Optional) + if (obj is Some) { - return this.Equals(obj); + return this.Equals(obj.As()); } return base.Equals(obj); } - public bool Equals(Optional other) + public bool Equals(Some other) { - if (this is Some && other is Some) + if (other is None) { - return this.As().Equals(other.As()); + return false; + } + + if (other is Some) + { + return this.Value.Equals(other.Value); } return false; } - public static implicit operator Optional(T value) + public static bool operator ==(Some left, Some right) { - return Optional.FromValue(value); + return left?.Equals(right) == true; + } + + public static bool operator !=(Some left, Some right) + { + return left?.Equals(right) != true; } public override int GetHashCode() { - return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode(); + return this.Value is object ? this.Value.GetHashCode() : this.As().GetHashCode(); } + } - internal class Some : Optional, IEquatable + internal class None : Optional + { + public None() : base(default) { - public Some(T value) : base(value) - { - } - - public override bool Equals(object obj) - { - if (obj is Some) - { - return this.Equals(obj.As()); - } - - return base.Equals(obj); - } - - public bool Equals(Some other) - { - if (other is None) - { - return false; - } - - if (other is Some) - { - return this.Value.Equals(other.Value); - } - - return false; - } - - public static bool operator ==(Some left, Some right) - { - return left?.Equals(right) == true; - } - - public static bool operator !=(Some left, Some right) - { - return left?.Equals(right) != true; - } - - public override int GetHashCode() - { - return this.Value is object ? this.Value.GetHashCode() : this.As().GetHashCode(); - } - } - - internal class None : Optional - { - public None() : base(default) - { - } } } } diff --git a/SystemExtensions.NetStandard/Extensions/Result.cs b/SystemExtensions.NetStandard/Extensions/Result.cs index b5843e7..90d856f 100644 --- a/SystemExtensions.NetStandard/Extensions/Result.cs +++ b/SystemExtensions.NetStandard/Extensions/Result.cs @@ -1,209 +1,216 @@ -namespace System.Extensions +namespace System.Extensions; + +public class Result { - public class Result + private readonly object value; + + public Result(TSuccess successValue) { - private readonly object value; + this.value = successValue; + } + public Result(TFailure failureValue) + { + this.value = failureValue; + } - public Result(TSuccess successValue) - { - value = successValue; - } - public Result(TFailure failureValue) - { - value = failureValue; - } + public bool TryExtractSuccess(out TSuccess successValue) + { - public bool TryExtractSuccess(out TSuccess successValue) + if (this.value is TSuccess success) { - - if (value is TSuccess success) - { - successValue = success; - return true; - } - else - { - successValue = default; - return false; - } + successValue = success; + return true; } - public bool TryExtractFailure(out TFailure failureValue) + else { - - if (value is TFailure failure) - { - failureValue = failure; - return true; - } - else - { - failureValue = default; - return false; - } - } - public Result Do(Action onSuccess, Action onFailure) - { - if (onSuccess is null) - { - throw new ArgumentNullException(nameof(onSuccess)); - } - - if (onFailure is null) - { - throw new ArgumentNullException(nameof(onFailure)); - } - - if (value is TSuccess) - { - onSuccess.Invoke(); - } - else if (value is TFailure) - { - onFailure.Invoke(); - } - return this; - } - public Result DoAny(Action onSuccess = null, Action onFailure = null) - { - if (value is TSuccess) - { - onSuccess?.Invoke(); - } - else if (value is TFailure) - { - onFailure?.Invoke(); - } - return this; - } - public Result Do(Action onSuccess, Action onFailure) - { - if (onSuccess is null) - { - throw new ArgumentNullException(nameof(onSuccess)); - } - - if (onFailure is null) - { - throw new ArgumentNullException(nameof(onFailure)); - } - - if (value is TSuccess success) - { - onSuccess.Invoke(success); - } - else if (value is TFailure failure) - { - onFailure.Invoke(failure); - } - return this; - } - public Result DoAny(Action onSuccess = null, Action onFailure = null) - { - if (value is TSuccess success) - { - onSuccess?.Invoke(success); - } - else if (value is TFailure failure) - { - onFailure?.Invoke(failure); - } - return this; - } - public T Switch(Func onSuccess, Func onFailure) - { - if (onSuccess is null) - { - throw new ArgumentNullException(nameof(onSuccess)); - } - - if (onFailure is null) - { - throw new ArgumentNullException(nameof(onFailure)); - } - - if (value is TSuccess success) - { - return onSuccess.Invoke(success); - } - else if (value is TFailure failure) - { - return onFailure.Invoke(failure); - } - throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); - } - public T SwitchAny(Func onSuccess = null, Func onFailure = null) - { - if (value is TSuccess success) - { - return onSuccess is null ? default : onSuccess.Invoke(success); - } - else if (value is TFailure failure) - { - return onFailure is null ? default : onFailure.Invoke(failure); - } - throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); - } - public Result Switch(Func onSuccess, Func onFailure) - { - if (onSuccess is null) - { - throw new ArgumentNullException(nameof(onSuccess)); - } - - if (onFailure is null) - { - throw new ArgumentNullException(nameof(onFailure)); - } - - if (value is TSuccess success) - { - return Result.Success(onSuccess.Invoke(success)); - } - else if (value is TFailure failure) - { - return Result.Failure(onFailure.Invoke(failure)); - } - throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); - } - public Result SwitchAny(Func onSuccess, Func onFailure) - { - if (value is TSuccess success) - { - return Result.Success(onSuccess is null ? default : onSuccess.Invoke(success)); - } - else if (value is TFailure failure) - { - return Result.Failure(onFailure is null ? default : onFailure.Invoke(failure)); - } - throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); - } - public Optional ToOptional() - { - if (value is TSuccess) - { - return Optional.FromValue(value.Cast()); - } - - return Optional.None(); - } - - public static implicit operator Result(TSuccess success) - { - return Success(success); - } - - public static implicit operator Result(TFailure failure) - { - return Failure(failure); - } - - public static Result Success(TSuccess value) - { - return new Result(value); - } - public static Result Failure(TFailure value) - { - return new Result(value); + successValue = default; + return false; } } + public bool TryExtractFailure(out TFailure failureValue) + { + + if (this.value is TFailure failure) + { + failureValue = failure; + return true; + } + else + { + failureValue = default; + return false; + } + } + public Result Do(Action onSuccess, Action onFailure) + { + if (onSuccess is null) + { + throw new ArgumentNullException(nameof(onSuccess)); + } + + if (onFailure is null) + { + throw new ArgumentNullException(nameof(onFailure)); + } + + if (this.value is TSuccess) + { + onSuccess.Invoke(); + } + else if (this.value is TFailure) + { + onFailure.Invoke(); + } + + return this; + } + public Result DoAny(Action onSuccess = null, Action onFailure = null) + { + if (this.value is TSuccess) + { + onSuccess?.Invoke(); + } + else if (this.value is TFailure) + { + onFailure?.Invoke(); + } + + return this; + } + public Result Do(Action onSuccess, Action onFailure) + { + if (onSuccess is null) + { + throw new ArgumentNullException(nameof(onSuccess)); + } + + if (onFailure is null) + { + throw new ArgumentNullException(nameof(onFailure)); + } + + if (this.value is TSuccess success) + { + onSuccess.Invoke(success); + } + else if (this.value is TFailure failure) + { + onFailure.Invoke(failure); + } + + return this; + } + public Result DoAny(Action onSuccess = null, Action onFailure = null) + { + if (this.value is TSuccess success) + { + onSuccess?.Invoke(success); + } + else if (this.value is TFailure failure) + { + onFailure?.Invoke(failure); + } + + return this; + } + public T Switch(Func onSuccess, Func onFailure) + { + if (onSuccess is null) + { + throw new ArgumentNullException(nameof(onSuccess)); + } + + if (onFailure is null) + { + throw new ArgumentNullException(nameof(onFailure)); + } + + if (this.value is TSuccess success) + { + return onSuccess.Invoke(success); + } + else if (this.value is TFailure failure) + { + return onFailure.Invoke(failure); + } + + throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); + } + public T SwitchAny(Func onSuccess = null, Func onFailure = null) + { + if (this.value is TSuccess success) + { + return onSuccess is null ? default : onSuccess.Invoke(success); + } + else if (this.value is TFailure failure) + { + return onFailure is null ? default : onFailure.Invoke(failure); + } + + throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); + } + public Result Switch(Func onSuccess, Func onFailure) + { + if (onSuccess is null) + { + throw new ArgumentNullException(nameof(onSuccess)); + } + + if (onFailure is null) + { + throw new ArgumentNullException(nameof(onFailure)); + } + + if (this.value is TSuccess success) + { + return Result.Success(onSuccess.Invoke(success)); + } + else if (this.value is TFailure failure) + { + return Result.Failure(onFailure.Invoke(failure)); + } + + throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); + } + public Result SwitchAny(Func onSuccess, Func onFailure) + { + if (this.value is TSuccess success) + { + return Result.Success(onSuccess is null ? default : onSuccess.Invoke(success)); + } + else if (this.value is TFailure failure) + { + return Result.Failure(onFailure is null ? default : onFailure.Invoke(failure)); + } + + throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); + } + public Optional ToOptional() + { + if (this.value is TSuccess) + { + return Optional.FromValue(this.value.Cast()); + } + + return Optional.None(); + } + + public static implicit operator Result(TSuccess success) + { + return Success(success); + } + + public static implicit operator Result(TFailure failure) + { + return Failure(failure); + } + + public static Result Success(TSuccess value) + { + return new Result(value); + } + public static Result Failure(TFailure value) + { + return new Result(value); + } } diff --git a/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs b/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs index 950c881..5930cfe 100644 --- a/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs @@ -1,85 +1,84 @@ using System.IO; using System.Text; -namespace System.Extensions +namespace System.Extensions; + +public static class StreamExtensions { - public static class StreamExtensions + public static void DoWhileReading(this Stream stream, Action action, int bufferLength = 256) { - public static void DoWhileReading(this Stream stream, Action action, int bufferLength = 256) + if (stream is null) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (action is null) - { - throw new ArgumentNullException(nameof(action)); - } - - var buffer = new byte[bufferLength]; - var read = stream.Read(buffer, 0, bufferLength); - while(read > 0) - { - action(bufferLength, buffer); - read = stream.Read(buffer, 0, bufferLength); - } + throw new ArgumentNullException(nameof(stream)); } - public static byte[] ReadBytes(this Stream stream, int count) + if (action is null) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - var buffer = new byte[count]; - stream.Read(buffer, 0, count); - return buffer; + throw new ArgumentNullException(nameof(action)); } - public static Stream Rewind(this Stream stream) + var buffer = new byte[bufferLength]; + var read = stream.Read(buffer, 0, bufferLength); + while(read > 0) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (!stream.CanSeek) - { - throw new InvalidOperationException("Stream doesn't support rewinding"); - } - - stream.Seek(0, SeekOrigin.Begin); - return stream; - } - - public static string ReadUntil(this StreamReader sr, string delim) - { - var sb = new StringBuilder(); - var found = false; - - while (!found && !sr.EndOfStream) - { - for (var i = 0; i < delim.Length; i++) - { - var c = (char)sr.Read(); - sb.Append(c); - - if (c != delim[i]) - { - break; - } - - if (i == delim.Length - 1) - { - sb.Remove(sb.Length - delim.Length, delim.Length); - found = true; - } - } - } - - return sb.ToString(); + action(bufferLength, buffer); + read = stream.Read(buffer, 0, bufferLength); } } + + public static byte[] ReadBytes(this Stream stream, int count) + { + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[count]; + stream.Read(buffer, 0, count); + return buffer; + } + + public static Stream Rewind(this Stream stream) + { + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (!stream.CanSeek) + { + throw new InvalidOperationException("Stream doesn't support rewinding"); + } + + stream.Seek(0, SeekOrigin.Begin); + return stream; + } + + public static string ReadUntil(this StreamReader sr, string delim) + { + var sb = new StringBuilder(); + var found = false; + + while (!found && !sr.EndOfStream) + { + for (var i = 0; i < delim.Length; i++) + { + var c = (char)sr.Read(); + sb.Append(c); + + if (c != delim[i]) + { + break; + } + + if (i == delim.Length - 1) + { + sb.Remove(sb.Length - delim.Length, delim.Length); + found = true; + } + } + } + + return sb.ToString(); + } } diff --git a/SystemExtensions.NetStandard/Extensions/StringExtensions.cs b/SystemExtensions.NetStandard/Extensions/StringExtensions.cs index 2c62f5b..9bc534f 100644 --- a/SystemExtensions.NetStandard/Extensions/StringExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/StringExtensions.cs @@ -1,27 +1,26 @@ using System.Text; -namespace System.Extensions +namespace System.Extensions; + +public static class StringExtensions { - public static class StringExtensions + public static bool IsNullOrEmpty(this string s) { - public static bool IsNullOrEmpty(this string s) - { - return string.IsNullOrEmpty(s); - } + return string.IsNullOrEmpty(s); + } - public static bool IsNullOrWhiteSpace(this string s) - { - return string.IsNullOrWhiteSpace(s); - } + public static bool IsNullOrWhiteSpace(this string s) + { + return string.IsNullOrWhiteSpace(s); + } - public static byte[] GetBytes(this string s) - { - return Encoding.UTF8.GetBytes(s); - } + public static byte[] GetBytes(this string s) + { + return Encoding.UTF8.GetBytes(s); + } - public static string GetString(this byte[] bytes) - { - return Encoding.UTF8.GetString(bytes); - } + public static string GetString(this byte[] bytes) + { + return Encoding.UTF8.GetString(bytes); } } diff --git a/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs b/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs index 596c1fa..954e9b2 100644 --- a/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs +++ b/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs @@ -2,183 +2,184 @@ using System.Threading; using System.Threading.Tasks; -namespace System.Extensions +namespace System.Extensions; + +public static class TaskExtensions { - public static class TaskExtensions + /// + /// Mark task as . + /// + /// Result type. + /// Task. + /// The started + public static Task LongRunning(this Task task) { - /// - /// Mark task as . - /// - /// Result type. - /// Task. - /// The started - public static Task LongRunning(this Task task) + return Task.Factory.StartNew(async () => { - return Task.Factory.StartNew(async () => - { - return await task; - }, TaskCreationOptions.LongRunning).Unwrap(); + return await task; + }, TaskCreationOptions.LongRunning).Unwrap(); + } + + /// + /// Mark task as . + /// + /// Task. + /// The started + public static Task LongRunning(this Task task) + { + return Task.Factory.StartNew(async () => + { + await task; + }, TaskCreationOptions.LongRunning).Unwrap(); + } + + /// + /// Execute action periodically and asynchronously. + /// + /// Action to be executed. + /// Time to pass before starting to execute. + /// Interval between procs. + /// Cancellation token used to cancel the cycle. + /// + public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token) + { + if (dueTime > TimeSpan.Zero) + { + await Task.Delay(dueTime, token).ConfigureAwait(false); } - /// - /// Mark task as . - /// - /// Task. - /// The started - public static Task LongRunning(this Task task) + while (!token.IsCancellationRequested) { - return Task.Factory.StartNew(async () => + onTick?.Invoke(); + if (interval > TimeSpan.Zero) { - await task; - }, TaskCreationOptions.LongRunning).Unwrap(); - } - - /// - /// Execute action periodically and asynchronously. - /// - /// Action to be executed. - /// Time to pass before starting to execute. - /// Interval between procs. - /// Cancellation token used to cancel the cycle. - /// - public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token) - { - if (dueTime > TimeSpan.Zero) - { - await Task.Delay(dueTime, token).ConfigureAwait(false); - } - - while (!token.IsCancellationRequested) - { - onTick?.Invoke(); - if (interval > TimeSpan.Zero) - { - await Task.Delay(interval, token).ConfigureAwait(false); - } - } - } - - /// - /// Execute's an async Task method which has a void return value synchronously - /// - /// Task method to execute - public static void RunSync(this Func task) - { - var oldContext = SynchronizationContext.Current; - var synch = new ExclusiveSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synch); - synch.Post(async _ => - { - try - { - await task(); - } - catch (Exception e) - { - synch.InnerException = e; - throw; - } - finally - { - synch.EndMessageLoop(); - } - }, null); - synch.BeginMessageLoop(); - - SynchronizationContext.SetSynchronizationContext(oldContext); - } - - /// - /// Execute's an async Task method which has a T return type synchronously - /// - /// Return Type - /// Task method to execute - /// - public static T RunSync(this Func> task) - { - var oldContext = SynchronizationContext.Current; - var synch = new ExclusiveSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synch); - var ret = default(T); - synch.Post(async _ => - { - try - { - ret = await task(); - } - catch (Exception e) - { - synch.InnerException = e; - throw; - } - finally - { - synch.EndMessageLoop(); - } - }, null); - synch.BeginMessageLoop(); - SynchronizationContext.SetSynchronizationContext(oldContext); - return ret; - } - - private class ExclusiveSynchronizationContext : SynchronizationContext - { - private bool done; - public Exception InnerException { get; set; } - readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); - readonly Queue> items = - new Queue>(); - - public override void Send(SendOrPostCallback d, object state) - { - throw new NotSupportedException("We cannot send to our same thread"); - } - - public override void Post(SendOrPostCallback d, object state) - { - lock (items) - { - items.Enqueue(Tuple.Create(d, state)); - } - workItemsWaiting.Set(); - } - - public void EndMessageLoop() - { - Post(_ => done = true, null); - } - - public void BeginMessageLoop() - { - while (!done) - { - Tuple task = null; - lock (items) - { - if (items.Count > 0) - { - task = items.Dequeue(); - } - } - if (task != null) - { - task.Item1(task.Item2); - if (InnerException != null) // the method threw an exeption - { - throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); - } - } - else - { - workItemsWaiting.WaitOne(); - } - } - } - - public override SynchronizationContext CreateCopy() - { - return this; + await Task.Delay(interval, token).ConfigureAwait(false); } } } + + /// + /// Execute's an async Task method which has a void return value synchronously + /// + /// Task method to execute + public static void RunSync(this Func task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + synch.Post(async _ => + { + try + { + await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + + SynchronizationContext.SetSynchronizationContext(oldContext); + } + + /// + /// Execute's an async Task method which has a T return type synchronously + /// + /// Return Type + /// Task method to execute + /// + public static T RunSync(this Func> task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + var ret = default(T); + synch.Post(async _ => + { + try + { + ret = await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + SynchronizationContext.SetSynchronizationContext(oldContext); + return ret; + } + + private class ExclusiveSynchronizationContext : SynchronizationContext + { + private bool done; + public Exception InnerException { get; set; } + readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); + readonly Queue> items = + new Queue>(); + + public override void Send(SendOrPostCallback d, object state) + { + throw new NotSupportedException("We cannot send to our same thread"); + } + + public override void Post(SendOrPostCallback d, object state) + { + lock (this.items) + { + this.items.Enqueue(Tuple.Create(d, state)); + } + + this.workItemsWaiting.Set(); + } + + public void EndMessageLoop() + { + this.Post(_ => this.done = true, null); + } + + public void BeginMessageLoop() + { + while (!this.done) + { + Tuple task = null; + lock (this.items) + { + if (this.items.Count > 0) + { + task = this.items.Dequeue(); + } + } + + if (task != null) + { + task.Item1(task.Item2); + if (this.InnerException != null) // the method threw an exeption + { + throw new AggregateException("AsyncHelpers.Run method threw an exception.", this.InnerException); + } + } + else + { + this.workItemsWaiting.WaitOne(); + } + } + } + + public override SynchronizationContext CreateCopy() + { + return this; + } + } } diff --git a/SystemExtensions.NetStandard/Extensions/Try.cs b/SystemExtensions.NetStandard/Extensions/Try.cs index 5395e29..bb018b7 100644 --- a/SystemExtensions.NetStandard/Extensions/Try.cs +++ b/SystemExtensions.NetStandard/Extensions/Try.cs @@ -1,72 +1,73 @@ using System.Collections.Generic; -namespace System.Extensions +namespace System.Extensions; + +public static class Try { - public static class Try + public static Try Action(Func act) { - public static Try Action(Func act) + return new Try(act); + } +} +public class Try +{ + private readonly Func action; + private readonly List> catchActions = new List>(); + internal Try(Func action) + { + this.action = action; + } + public static Try Action(Func act) + { + return new Try(act); + } + + public Try Catch(Func act) where TException : Exception + { + this.catchActions.Add((Func)act); + return this; + } + + public TResult Run() + { + try { - return new Try(act); + return this.action(); + } + catch (Exception ex) + { + foreach (var catchAction in this.catchActions) + { + return catchAction(ex); + } + + throw; } } - public class Try + + public TResult Finally(Action act) { - private readonly Func action; - private readonly List> catchActions = new List>(); - internal Try(Func action) + if (act is null) { - this.action = action; - } - public static Try Action(Func act) - { - return new Try(act); + throw new ArgumentNullException(nameof(act)); } - public Try Catch(Func act) where TException : Exception + try { - this.catchActions.Add((Func)act); - return this; + return this.action(); } - - public TResult Run() + catch (Exception ex) { - try + foreach (var catchAction in this.catchActions) { - return action(); - } - catch (Exception ex) - { - foreach (var catchAction in this.catchActions) - { - return catchAction(ex); - } - throw; + return catchAction(ex); } + + throw; } - - public TResult Finally(Action act) + finally { - if (act is null) - { - throw new ArgumentNullException(nameof(act)); - } - - try - { - return this.action(); - } - catch (Exception ex) - { - foreach (var catchAction in this.catchActions) - { - return catchAction(ex); - } - throw; - } - finally - { - act(); - } + act(); } } } diff --git a/SystemExtensions.NetStandard/Http/HttpClient.cs b/SystemExtensions.NetStandard/Http/HttpClient.cs index f622213..c366471 100644 --- a/SystemExtensions.NetStandard/Http/HttpClient.cs +++ b/SystemExtensions.NetStandard/Http/HttpClient.cs @@ -3,214 +3,213 @@ using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -namespace System.Net.Http +namespace System.Net.Http; + +public sealed class HttpClient : IHttpClient, IDisposable { - public sealed class HttpClient : IHttpClient, IDisposable + private readonly HttpClient httpClient; + private readonly Type scope; + private EventHandler eventEmitted; + + public event EventHandler EventEmitted { - private readonly HttpClient httpClient; - private readonly Type scope; - private EventHandler eventEmitted; - - public event EventHandler EventEmitted + add { - add - { - this.eventEmitted += value; - } - remove - { - this.eventEmitted -= value; - } + this.eventEmitted += value; } - public Uri BaseAddress { get => this.httpClient.BaseAddress; set => this.httpClient.BaseAddress = value; } - public HttpRequestHeaders DefaultRequestHeaders => this.httpClient.DefaultRequestHeaders; - public long MaxResponseContentBufferSize { get => this.httpClient.MaxResponseContentBufferSize; set => this.httpClient.MaxResponseContentBufferSize = value; } - public TimeSpan Timeout { get => this.httpClient.Timeout; set => this.httpClient.Timeout = value; } - - public HttpClient() + remove { - this.httpClient = new HttpClient(); - this.scope = typeof(Tscope); - } - - public HttpClient( - HttpMessageHandler handler) - { - this.httpClient = new HttpClient(handler); - this.scope = typeof(Tscope); - } - - public HttpClient( - HttpMessageHandler handler, - bool disposeHandler) - { - this.httpClient = new HttpClient(handler, disposeHandler); - this.scope = typeof(Tscope); - } - - public void CancelPendingRequests() - { - this.LogInformation(string.Empty, "Canceling request"); - this.httpClient.CancelPendingRequests(); - } - public Task DeleteAsync(string requestUri) - { - this.LogInformation(requestUri, nameof(DeleteAsync)); - return this.httpClient.DeleteAsync(requestUri); - } - public Task DeleteAsync(string requestUri, CancellationToken cancellationToken) - { - this.LogInformation(requestUri, nameof(DeleteAsync)); - return this.httpClient.DeleteAsync(requestUri, cancellationToken); - } - public Task DeleteAsync(Uri requestUri) - { - this.LogInformation(requestUri.ToString(), nameof(DeleteAsync)); - return this.httpClient.DeleteAsync(requestUri); - } - public Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken) - { - this.LogInformation(requestUri.ToString(), nameof(DeleteAsync)); - return this.httpClient.DeleteAsync(requestUri, cancellationToken); - } - public Task GetAsync(string requestUri) - { - this.LogInformation(requestUri, nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri); - } - public Task GetAsync(string requestUri, HttpCompletionOption completionOption) - { - this.LogInformation(requestUri, nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri, completionOption); - } - public Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) - { - this.LogInformation(requestUri, nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken); - } - public Task GetAsync(string requestUri, CancellationToken cancellationToken) - { - this.LogInformation(requestUri, nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri, cancellationToken); - } - public Task GetAsync(Uri requestUri) - { - this.LogInformation(requestUri.ToString(), nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri); - } - public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption) - { - this.LogInformation(requestUri.ToString(), nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri, completionOption); - } - public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) - { - this.LogInformation(requestUri.ToString(), nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken); - } - public Task GetAsync(Uri requestUri, CancellationToken cancellationToken) - { - this.LogInformation(requestUri.ToString(), nameof(GetAsync)); - return this.httpClient.GetAsync(requestUri, cancellationToken); - } - public Task GetByteArrayAsync(string requestUri) - { - this.LogInformation(requestUri, nameof(GetByteArrayAsync)); - return this.httpClient.GetByteArrayAsync(requestUri); - } - public Task GetByteArrayAsync(Uri requestUri) - { - this.LogInformation(requestUri.ToString(), nameof(GetByteArrayAsync)); - return this.httpClient.GetByteArrayAsync(requestUri); - } - public Task GetStreamAsync(string requestUri) - { - this.LogInformation(requestUri, nameof(GetStreamAsync)); - return this.httpClient.GetStreamAsync(requestUri); - } - public Task GetStreamAsync(Uri requestUri) - { - this.LogInformation(requestUri.ToString(), nameof(GetStreamAsync)); - return this.httpClient.GetStreamAsync(requestUri); - } - public Task GetStringAsync(string requestUri) - { - this.LogInformation(requestUri, nameof(GetStringAsync)); - return this.httpClient.GetStringAsync(requestUri); - } - public Task GetStringAsync(Uri requestUri) - { - this.LogInformation(requestUri.ToString(), nameof(GetStringAsync)); - return this.httpClient.GetStringAsync(requestUri); - } - public Task PostAsync(string requestUri, HttpContent content) - { - this.LogInformation(requestUri, nameof(PostAsync)); - return this.httpClient.PostAsync(requestUri, content); - } - public Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) - { - this.LogInformation(requestUri, nameof(PostAsync)); - return this.httpClient.PostAsync(requestUri, content, cancellationToken); - } - public Task PostAsync(Uri requestUri, HttpContent content) - { - this.LogInformation(requestUri.ToString(), nameof(PostAsync)); - return this.httpClient.PostAsync(requestUri, content); - } - public Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) - { - this.LogInformation(requestUri.ToString(), nameof(PostAsync)); - return this.httpClient.PostAsync(requestUri, content, cancellationToken); - } - public Task PutAsync(string requestUri, HttpContent content) - { - this.LogInformation(requestUri, nameof(PutAsync)); - return this.httpClient.PutAsync(requestUri, content); - } - public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) - { - this.LogInformation(requestUri, nameof(PutAsync)); - return this.httpClient.PutAsync(requestUri, content, cancellationToken); - } - public Task PutAsync(Uri requestUri, HttpContent content) - { - this.LogInformation(requestUri.ToString(), nameof(PutAsync)); - return this.httpClient.PutAsync(requestUri, content); - } - public Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) - { - this.LogInformation(requestUri.ToString(), nameof(PutAsync)); - return this.httpClient.PutAsync(requestUri, content, cancellationToken); - } - public Task SendAsync(HttpRequestMessage request) - { - this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); - return this.httpClient.SendAsync(request); - } - public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption) - { - this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); - return this.httpClient.SendAsync(request, completionOption); - } - public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) - { - this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); - return this.httpClient.SendAsync(request, completionOption, cancellationToken); - } - public Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); - return this.httpClient.SendAsync(request, cancellationToken); - } - public void Dispose() - { - this.httpClient.Dispose(); - } - - private void LogInformation(string url, string method) - { - this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url)); + this.eventEmitted -= value; } } + public Uri BaseAddress { get => this.httpClient.BaseAddress; set => this.httpClient.BaseAddress = value; } + public HttpRequestHeaders DefaultRequestHeaders => this.httpClient.DefaultRequestHeaders; + public long MaxResponseContentBufferSize { get => this.httpClient.MaxResponseContentBufferSize; set => this.httpClient.MaxResponseContentBufferSize = value; } + public TimeSpan Timeout { get => this.httpClient.Timeout; set => this.httpClient.Timeout = value; } + + public HttpClient() + { + this.httpClient = new HttpClient(); + this.scope = typeof(Tscope); + } + + public HttpClient( + HttpMessageHandler handler) + { + this.httpClient = new HttpClient(handler); + this.scope = typeof(Tscope); + } + + public HttpClient( + HttpMessageHandler handler, + bool disposeHandler) + { + this.httpClient = new HttpClient(handler, disposeHandler); + this.scope = typeof(Tscope); + } + + public void CancelPendingRequests() + { + this.LogInformation(string.Empty, "Canceling request"); + this.httpClient.CancelPendingRequests(); + } + public Task DeleteAsync(string requestUri) + { + this.LogInformation(requestUri, nameof(DeleteAsync)); + return this.httpClient.DeleteAsync(requestUri); + } + public Task DeleteAsync(string requestUri, CancellationToken cancellationToken) + { + this.LogInformation(requestUri, nameof(DeleteAsync)); + return this.httpClient.DeleteAsync(requestUri, cancellationToken); + } + public Task DeleteAsync(Uri requestUri) + { + this.LogInformation(requestUri.ToString(), nameof(DeleteAsync)); + return this.httpClient.DeleteAsync(requestUri); + } + public Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken) + { + this.LogInformation(requestUri.ToString(), nameof(DeleteAsync)); + return this.httpClient.DeleteAsync(requestUri, cancellationToken); + } + public Task GetAsync(string requestUri) + { + this.LogInformation(requestUri, nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri); + } + public Task GetAsync(string requestUri, HttpCompletionOption completionOption) + { + this.LogInformation(requestUri, nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri, completionOption); + } + public Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + this.LogInformation(requestUri, nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken); + } + public Task GetAsync(string requestUri, CancellationToken cancellationToken) + { + this.LogInformation(requestUri, nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri, cancellationToken); + } + public Task GetAsync(Uri requestUri) + { + this.LogInformation(requestUri.ToString(), nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri); + } + public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption) + { + this.LogInformation(requestUri.ToString(), nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri, completionOption); + } + public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + this.LogInformation(requestUri.ToString(), nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken); + } + public Task GetAsync(Uri requestUri, CancellationToken cancellationToken) + { + this.LogInformation(requestUri.ToString(), nameof(GetAsync)); + return this.httpClient.GetAsync(requestUri, cancellationToken); + } + public Task GetByteArrayAsync(string requestUri) + { + this.LogInformation(requestUri, nameof(GetByteArrayAsync)); + return this.httpClient.GetByteArrayAsync(requestUri); + } + public Task GetByteArrayAsync(Uri requestUri) + { + this.LogInformation(requestUri.ToString(), nameof(GetByteArrayAsync)); + return this.httpClient.GetByteArrayAsync(requestUri); + } + public Task GetStreamAsync(string requestUri) + { + this.LogInformation(requestUri, nameof(GetStreamAsync)); + return this.httpClient.GetStreamAsync(requestUri); + } + public Task GetStreamAsync(Uri requestUri) + { + this.LogInformation(requestUri.ToString(), nameof(GetStreamAsync)); + return this.httpClient.GetStreamAsync(requestUri); + } + public Task GetStringAsync(string requestUri) + { + this.LogInformation(requestUri, nameof(GetStringAsync)); + return this.httpClient.GetStringAsync(requestUri); + } + public Task GetStringAsync(Uri requestUri) + { + this.LogInformation(requestUri.ToString(), nameof(GetStringAsync)); + return this.httpClient.GetStringAsync(requestUri); + } + public Task PostAsync(string requestUri, HttpContent content) + { + this.LogInformation(requestUri, nameof(PostAsync)); + return this.httpClient.PostAsync(requestUri, content); + } + public Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) + { + this.LogInformation(requestUri, nameof(PostAsync)); + return this.httpClient.PostAsync(requestUri, content, cancellationToken); + } + public Task PostAsync(Uri requestUri, HttpContent content) + { + this.LogInformation(requestUri.ToString(), nameof(PostAsync)); + return this.httpClient.PostAsync(requestUri, content); + } + public Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) + { + this.LogInformation(requestUri.ToString(), nameof(PostAsync)); + return this.httpClient.PostAsync(requestUri, content, cancellationToken); + } + public Task PutAsync(string requestUri, HttpContent content) + { + this.LogInformation(requestUri, nameof(PutAsync)); + return this.httpClient.PutAsync(requestUri, content); + } + public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) + { + this.LogInformation(requestUri, nameof(PutAsync)); + return this.httpClient.PutAsync(requestUri, content, cancellationToken); + } + public Task PutAsync(Uri requestUri, HttpContent content) + { + this.LogInformation(requestUri.ToString(), nameof(PutAsync)); + return this.httpClient.PutAsync(requestUri, content); + } + public Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) + { + this.LogInformation(requestUri.ToString(), nameof(PutAsync)); + return this.httpClient.PutAsync(requestUri, content, cancellationToken); + } + public Task SendAsync(HttpRequestMessage request) + { + this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); + return this.httpClient.SendAsync(request); + } + public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption) + { + this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); + return this.httpClient.SendAsync(request, completionOption); + } + public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); + return this.httpClient.SendAsync(request, completionOption, cancellationToken); + } + public Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync)); + return this.httpClient.SendAsync(request, cancellationToken); + } + public void Dispose() + { + this.httpClient.Dispose(); + } + + private void LogInformation(string url, string method) + { + this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url)); + } } diff --git a/SystemExtensions.NetStandard/Http/HttpClientEventMessage.cs b/SystemExtensions.NetStandard/Http/HttpClientEventMessage.cs index ed1b2b6..13c8f62 100644 --- a/SystemExtensions.NetStandard/Http/HttpClientEventMessage.cs +++ b/SystemExtensions.NetStandard/Http/HttpClientEventMessage.cs @@ -1,16 +1,15 @@ -namespace System.Net.Http -{ - public sealed class HttpClientEventMessage - { - public Type Scope { get; } - public string Method { get; } - public string Url { get; } +namespace System.Net.Http; - internal HttpClientEventMessage(Type scope, string method, string url) - { - this.Scope = scope; - this.Method = method; - this.Url = url; - } +public sealed class HttpClientEventMessage +{ + public Type Scope { get; } + public string Method { get; } + public string Url { get; } + + internal HttpClientEventMessage(Type scope, string method, string url) + { + this.Scope = scope; + this.Method = method; + this.Url = url; } } diff --git a/SystemExtensions.NetStandard/Http/IHttpClient.cs b/SystemExtensions.NetStandard/Http/IHttpClient.cs index 8453a8a..b562964 100644 --- a/SystemExtensions.NetStandard/Http/IHttpClient.cs +++ b/SystemExtensions.NetStandard/Http/IHttpClient.cs @@ -3,46 +3,45 @@ using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -namespace System.Net.Http -{ - public interface IHttpClient - { - event EventHandler EventEmitted; - Uri BaseAddress { get; set; } - HttpRequestHeaders DefaultRequestHeaders { get; } - long MaxResponseContentBufferSize { get; set; } - TimeSpan Timeout { get; set; } +namespace System.Net.Http; - void CancelPendingRequests(); - Task DeleteAsync(string requestUri); - Task DeleteAsync(string requestUri, CancellationToken cancellationToken); - Task DeleteAsync(Uri requestUri); - Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken); - Task GetAsync(string requestUri); - Task GetAsync(string requestUri, HttpCompletionOption completionOption); - Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); - Task GetAsync(string requestUri, CancellationToken cancellationToken); - Task GetAsync(Uri requestUri); - Task GetAsync(Uri requestUri, HttpCompletionOption completionOption); - Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); - Task GetAsync(Uri requestUri, CancellationToken cancellationToken); - Task GetByteArrayAsync(string requestUri); - Task GetByteArrayAsync(Uri requestUri); - Task GetStreamAsync(string requestUri); - Task GetStreamAsync(Uri requestUri); - Task GetStringAsync(string requestUri); - Task GetStringAsync(Uri requestUri); - Task PostAsync(string requestUri, HttpContent content); - Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); - Task PostAsync(Uri requestUri, HttpContent content); - Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); - Task PutAsync(string requestUri, HttpContent content); - Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); - Task PutAsync(Uri requestUri, HttpContent content); - Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); - Task SendAsync(HttpRequestMessage request); - Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption); - Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken); - Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); - } +public interface IHttpClient +{ + event EventHandler EventEmitted; + Uri BaseAddress { get; set; } + HttpRequestHeaders DefaultRequestHeaders { get; } + long MaxResponseContentBufferSize { get; set; } + TimeSpan Timeout { get; set; } + + void CancelPendingRequests(); + Task DeleteAsync(string requestUri); + Task DeleteAsync(string requestUri, CancellationToken cancellationToken); + Task DeleteAsync(Uri requestUri); + Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken); + Task GetAsync(string requestUri); + Task GetAsync(string requestUri, HttpCompletionOption completionOption); + Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); + Task GetAsync(string requestUri, CancellationToken cancellationToken); + Task GetAsync(Uri requestUri); + Task GetAsync(Uri requestUri, HttpCompletionOption completionOption); + Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); + Task GetAsync(Uri requestUri, CancellationToken cancellationToken); + Task GetByteArrayAsync(string requestUri); + Task GetByteArrayAsync(Uri requestUri); + Task GetStreamAsync(string requestUri); + Task GetStreamAsync(Uri requestUri); + Task GetStringAsync(string requestUri); + Task GetStringAsync(Uri requestUri); + Task PostAsync(string requestUri, HttpContent content); + Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); + Task PostAsync(Uri requestUri, HttpContent content); + Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); + Task PutAsync(string requestUri, HttpContent content); + Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); + Task PutAsync(Uri requestUri, HttpContent content); + Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); + Task SendAsync(HttpRequestMessage request); + Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption); + Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken); + Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); } diff --git a/SystemExtensions.NetStandard/Logging/ScopedLogger.cs b/SystemExtensions.NetStandard/Logging/ScopedLogger.cs index 0879c81..1df1a54 100644 --- a/SystemExtensions.NetStandard/Logging/ScopedLogger.cs +++ b/SystemExtensions.NetStandard/Logging/ScopedLogger.cs @@ -1,77 +1,76 @@ using Microsoft.Extensions.Logging; using System.Extensions; -namespace System.Logging +namespace System.Logging; + +public struct ScopedLogger { - public struct ScopedLogger + private readonly ILogger logger; + private readonly string scope; + private readonly string flowId; + + private ScopedLogger(ILogger logger, string scope, string flowId) { - private readonly ILogger logger; - private readonly string scope; - private readonly string flowId; + this.logger = logger; + this.scope = scope; + this.flowId = flowId.IsNullOrWhiteSpace() ? string.Empty : $"[{flowId}] "; + } - private ScopedLogger(ILogger logger, string scope, string flowId) - { - this.logger = logger; - this.scope = scope; - this.flowId = flowId.IsNullOrWhiteSpace() ? string.Empty : $"[{flowId}] "; - } + public ScopedLogger LogInformation(string message, params object[] parameters) + { + this.logger.LogInformation(this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogInformation(string message, params object[] parameters) - { - this.logger.LogInformation(this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogDebug(string message, params object[] parameters) + { + this.logger.LogDebug(this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogDebug(string message, params object[] parameters) - { - this.logger.LogDebug(this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogWarning(string message, params object[] parameters) + { + this.logger.LogWarning(this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogWarning(string message, params object[] parameters) - { - this.logger.LogWarning(this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogError(string message, params object[] parameters) + { + this.logger.LogError(this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogError(string message, params object[] parameters) - { - this.logger.LogError(this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogCritical(string message, params object[] parameters) + { + this.logger.LogCritical(this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogCritical(string message, params object[] parameters) - { - this.logger.LogCritical(this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogWarning(Exception e, string message, params object[] parameters) + { + this.logger.LogWarning(e, this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogWarning(Exception e, string message, params object[] parameters) - { - this.logger.LogWarning(e, this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogError(Exception e, string message, params object[] parameters) + { + this.logger.LogError(e, this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogError(Exception e, string message, params object[] parameters) - { - this.logger.LogError(e, this.CreateMessage(message), parameters); - return this; - } + public ScopedLogger LogCritical(Exception e, string message, params object[] parameters) + { + this.logger.LogCritical(e, this.CreateMessage(message), parameters); + return this; + } - public ScopedLogger LogCritical(Exception e, string message, params object[] parameters) - { - this.logger.LogCritical(e, this.CreateMessage(message), parameters); - return this; - } + private string CreateMessage(string message) + { + return $"{this.flowId}{this.scope}: {message}"; + } - private string CreateMessage(string message) - { - return $"{this.flowId}{this.scope}: {message}"; - } - - public static ScopedLogger Create(ILogger logger, string scope, string flowId) - { - return new ScopedLogger(logger, scope.ThrowIfNull(nameof(scope)), flowId); - } + public static ScopedLogger Create(ILogger logger, string scope, string flowId) + { + return new ScopedLogger(logger, scope.ThrowIfNull(nameof(scope)), flowId); } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard/Structures/BitStructures/Int32BitStruct.cs b/SystemExtensions.NetStandard/Structures/BitStructures/Int32BitStruct.cs index 685c9b7..2ae7302 100644 --- a/SystemExtensions.NetStandard/Structures/BitStructures/Int32BitStruct.cs +++ b/SystemExtensions.NetStandard/Structures/BitStructures/Int32BitStruct.cs @@ -1,175 +1,174 @@ -namespace System.Structures.BitStructures +namespace System.Structures.BitStructures; + +public struct Int32BitStruct : IEquatable { - public struct Int32BitStruct : IEquatable + public Int32BitStruct(uint value) => this.Value = value; + public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } } + public uint Value { get; set; } + public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); } + public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); } + public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); } + public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); } + public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); } + public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); } + public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); } + public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); } + public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); } + public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); } + public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); } + public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); } + public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); } + public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); } + public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); } + public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); } + public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); } + public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); } + public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); } + public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); } + public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); } + public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); } + public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); } + public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); } + public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); } + public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); } + public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); } + public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); } + public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); } + public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); } + public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); } + public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); } + + public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value); + public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value); + public static implicit operator int(Int32BitStruct value) => (int)value.Value; + public static implicit operator uint(Int32BitStruct value) => value.Value; + public static bool operator ==(Int32BitStruct first, Int32BitStruct second) { - public Int32BitStruct(uint value) => this.Value = value; - public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } } - public uint Value { get; set; } - public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); } - public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); } - public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); } - public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); } - public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); } - public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); } - public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); } - public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); } - public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); } - public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); } - public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); } - public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); } - public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); } - public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); } - public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); } - public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); } - public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); } - public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); } - public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); } - public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); } - public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); } - public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); } - public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); } - public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); } - public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); } - public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); } - public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); } - public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); } - public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); } - public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); } - public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); } - public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); } + return first.Value == second.Value; + } - public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value); - public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value); - public static implicit operator int(Int32BitStruct value) => (int)value.Value; - public static implicit operator uint(Int32BitStruct value) => value.Value; - public static bool operator ==(Int32BitStruct first, Int32BitStruct second) - { - return first.Value == second.Value; - } + public static bool operator !=(Int32BitStruct first, Int32BitStruct second) + { + return first.Value != second.Value; + } - public static bool operator !=(Int32BitStruct first, Int32BitStruct second) - { - return first.Value != second.Value; - } + public static bool operator ==(Int32BitStruct first, uint second) + { + return first.Value == second; + } - public static bool operator ==(Int32BitStruct first, uint second) - { - return first.Value == second; - } + public static bool operator !=(Int32BitStruct first, uint second) + { + return first.Value != second; + } - public static bool operator !=(Int32BitStruct first, uint second) + public static bool operator ==(Int32BitStruct first, int second) + { + unchecked { - return first.Value != second; - } - - public static bool operator ==(Int32BitStruct first, int second) - { - unchecked - { - return first.Value == (uint)second; - } - } - - public static bool operator !=(Int32BitStruct first, int second) - { - unchecked - { - return first.Value != (uint)second; - } - } - - public static bool operator >=(Int32BitStruct first, Int32BitStruct second) - { - return first.Value >= second.Value; - } - - public static bool operator <=(Int32BitStruct first, Int32BitStruct second) - { - return first.Value <= second.Value; - } - - public static bool operator >=(Int32BitStruct first, int second) - { - unchecked - { - return first.Value >= (uint)second; - } - } - - public static bool operator <=(Int32BitStruct first, int second) - { - unchecked - { - return first.Value <= (uint)second; - } - } - - public static bool operator >=(Int32BitStruct first, uint second) - { - return first.Value >= second; - } - - public static bool operator <=(Int32BitStruct first, uint second) - { - return first.Value <= second; - } - - public static bool operator >(Int32BitStruct first, Int32BitStruct second) - { - return first.Value > second.Value; - } - - public static bool operator <(Int32BitStruct first, Int32BitStruct second) - { - return first.Value < second.Value; - } - - public static bool operator >(Int32BitStruct first, int second) - { - unchecked - { - return first.Value > (uint)second; - } - } - - public static bool operator <(Int32BitStruct first, int second) - { - unchecked - { - return first.Value < (uint)second; - } - } - - public static bool operator >(Int32BitStruct first, uint second) - { - return first.Value > second; - } - - public static bool operator <(Int32BitStruct first, uint second) - { - return first.Value < second; - } - - public bool Equals(Int32BitStruct other) - { - return this.Value == other.Value; - } - - public override bool Equals(object obj) - { - if (obj is Int32BitStruct) - { - return this.Equals((Int32BitStruct)obj); - } - else - { - return base.Equals(obj); - } - } - - public override int GetHashCode() - { - return (this.Value).GetHashCode(); + return first.Value == (uint)second; } } + + public static bool operator !=(Int32BitStruct first, int second) + { + unchecked + { + return first.Value != (uint)second; + } + } + + public static bool operator >=(Int32BitStruct first, Int32BitStruct second) + { + return first.Value >= second.Value; + } + + public static bool operator <=(Int32BitStruct first, Int32BitStruct second) + { + return first.Value <= second.Value; + } + + public static bool operator >=(Int32BitStruct first, int second) + { + unchecked + { + return first.Value >= (uint)second; + } + } + + public static bool operator <=(Int32BitStruct first, int second) + { + unchecked + { + return first.Value <= (uint)second; + } + } + + public static bool operator >=(Int32BitStruct first, uint second) + { + return first.Value >= second; + } + + public static bool operator <=(Int32BitStruct first, uint second) + { + return first.Value <= second; + } + + public static bool operator >(Int32BitStruct first, Int32BitStruct second) + { + return first.Value > second.Value; + } + + public static bool operator <(Int32BitStruct first, Int32BitStruct second) + { + return first.Value < second.Value; + } + + public static bool operator >(Int32BitStruct first, int second) + { + unchecked + { + return first.Value > (uint)second; + } + } + + public static bool operator <(Int32BitStruct first, int second) + { + unchecked + { + return first.Value < (uint)second; + } + } + + public static bool operator >(Int32BitStruct first, uint second) + { + return first.Value > second; + } + + public static bool operator <(Int32BitStruct first, uint second) + { + return first.Value < second; + } + + public bool Equals(Int32BitStruct other) + { + return this.Value == other.Value; + } + + public override bool Equals(object obj) + { + if (obj is Int32BitStruct) + { + return this.Equals((Int32BitStruct)obj); + } + else + { + return base.Equals(obj); + } + } + + public override int GetHashCode() + { + return (this.Value).GetHashCode(); + } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard/Structures/BitStructures/Int64BitStruct.cs b/SystemExtensions.NetStandard/Structures/BitStructures/Int64BitStruct.cs index 286637d..7cd1ce1 100644 --- a/SystemExtensions.NetStandard/Structures/BitStructures/Int64BitStruct.cs +++ b/SystemExtensions.NetStandard/Structures/BitStructures/Int64BitStruct.cs @@ -1,205 +1,204 @@ using System; -namespace System.Structures.BitStructures +namespace System.Structures.BitStructures; + +public struct Int64BitStruct : IEquatable { - public struct Int64BitStruct : IEquatable + public Int64BitStruct(uint low, uint high) { - public Int64BitStruct(uint low, uint high) - { - this.Value = low + ((ulong)high << 32); - } + this.Value = low + ((ulong)high << 32); + } - public Int64BitStruct(int low, int high) + public Int64BitStruct(int low, int high) + { + unchecked { - unchecked - { - this.Value = (uint)low + ((ulong)high << 32); - } - } - - public Int64BitStruct(long value) - { - unchecked - { - this.Value = (ulong)value; - } - } - - public Int64BitStruct(ulong value) - { - this.Value = value; - } - - public ulong Value { get; set; } - public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); } - public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); } - public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); } - public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); } - public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); } - public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); } - public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); } - public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); } - public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); } - public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); } - public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); } - public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); } - public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); } - public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); } - public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); } - public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); } - public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); } - public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); } - public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); } - public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); } - public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); } - public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); } - public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); } - public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); } - public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); } - public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); } - public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); } - public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); } - public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); } - public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); } - public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); } - public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); } - public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); } - public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); } - public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); } - public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); } - public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); } - public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); } - public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); } - public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); } - public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); } - public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); } - public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); } - public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); } - public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); } - public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); } - public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); } - public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); } - public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); } - public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); } - public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); } - public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); } - public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); } - public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); } - public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); } - public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); } - public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); } - public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); } - public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); } - public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); } - public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); } - public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); } - public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); } - public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); } - public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); } - public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); } - - public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value); - public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value); - public static implicit operator long(Int64BitStruct value) => (long)value.Value; - public static implicit operator ulong(Int64BitStruct value) => value.Value; - public static bool operator ==(Int64BitStruct first, Int64BitStruct second) - { - return first.Value == second.Value; - } - - public static bool operator !=(Int64BitStruct first, Int64BitStruct second) - { - return first.Value != second.Value; - } - - public static bool operator ==(Int64BitStruct first, ulong second) - { - return first.Value == second; - } - - public static bool operator !=(Int64BitStruct first, ulong second) - { - return first.Value != second; - } - - public static bool operator ==(Int64BitStruct first, long second) - { - unchecked - { - return first.Value == (ulong)second; - } - } - - public static bool operator !=(Int64BitStruct first, long second) - { - unchecked - { - return first.Value != (ulong)second; - } - } - - public static bool operator >=(Int64BitStruct first, Int64BitStruct second) - { - return first.Value >= second.Value; - } - - public static bool operator <=(Int64BitStruct first, Int64BitStruct second) - { - return first.Value <= second.Value; - } - - public static bool operator >=(Int64BitStruct first, long second) - { - unchecked - { - return first.Value >= (ulong)second; - } - } - - public static bool operator <=(Int64BitStruct first, long second) - { - unchecked - { - return first.Value <= (ulong)second; - } - } - - public static bool operator >=(Int64BitStruct first, ulong second) - { - unchecked - { - return first.Value >= second; - } - } - - public static bool operator <=(Int64BitStruct first, ulong second) - { - unchecked - { - return first.Value <= second; - } - } - - public bool Equals(Int64BitStruct other) - { - return this.Value == other.Value; - } - - public override bool Equals(object obj) - { - if (obj is Int64BitStruct) - { - return this.Equals((Int64BitStruct)obj); - } - else - { - return base.Equals(obj); - } - } - - public override int GetHashCode() - { - return this.Value.GetHashCode(); + this.Value = (uint)low + ((ulong)high << 32); } } + + public Int64BitStruct(long value) + { + unchecked + { + this.Value = (ulong)value; + } + } + + public Int64BitStruct(ulong value) + { + this.Value = value; + } + + public ulong Value { get; set; } + public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); } + public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); } + public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); } + public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); } + public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); } + public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); } + public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); } + public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); } + public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); } + public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); } + public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); } + public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); } + public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); } + public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); } + public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); } + public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); } + public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); } + public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); } + public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); } + public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); } + public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); } + public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); } + public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); } + public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); } + public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); } + public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); } + public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); } + public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); } + public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); } + public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); } + public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); } + public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); } + public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); } + public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); } + public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); } + public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); } + public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); } + public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); } + public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); } + public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); } + public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); } + public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); } + public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); } + public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); } + public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); } + public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); } + public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); } + public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); } + public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); } + public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); } + public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); } + public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); } + public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); } + public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); } + public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); } + public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); } + public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); } + public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); } + public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); } + public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); } + public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); } + public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); } + public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); } + public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); } + public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); } + public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); } + + public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value); + public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value); + public static implicit operator long(Int64BitStruct value) => (long)value.Value; + public static implicit operator ulong(Int64BitStruct value) => value.Value; + public static bool operator ==(Int64BitStruct first, Int64BitStruct second) + { + return first.Value == second.Value; + } + + public static bool operator !=(Int64BitStruct first, Int64BitStruct second) + { + return first.Value != second.Value; + } + + public static bool operator ==(Int64BitStruct first, ulong second) + { + return first.Value == second; + } + + public static bool operator !=(Int64BitStruct first, ulong second) + { + return first.Value != second; + } + + public static bool operator ==(Int64BitStruct first, long second) + { + unchecked + { + return first.Value == (ulong)second; + } + } + + public static bool operator !=(Int64BitStruct first, long second) + { + unchecked + { + return first.Value != (ulong)second; + } + } + + public static bool operator >=(Int64BitStruct first, Int64BitStruct second) + { + return first.Value >= second.Value; + } + + public static bool operator <=(Int64BitStruct first, Int64BitStruct second) + { + return first.Value <= second.Value; + } + + public static bool operator >=(Int64BitStruct first, long second) + { + unchecked + { + return first.Value >= (ulong)second; + } + } + + public static bool operator <=(Int64BitStruct first, long second) + { + unchecked + { + return first.Value <= (ulong)second; + } + } + + public static bool operator >=(Int64BitStruct first, ulong second) + { + unchecked + { + return first.Value >= second; + } + } + + public static bool operator <=(Int64BitStruct first, ulong second) + { + unchecked + { + return first.Value <= second; + } + } + + public bool Equals(Int64BitStruct other) + { + return this.Value == other.Value; + } + + public override bool Equals(object obj) + { + if (obj is Int64BitStruct) + { + return this.Equals((Int64BitStruct)obj); + } + else + { + return base.Equals(obj); + } + } + + public override int GetHashCode() + { + return this.Value.GetHashCode(); + } } \ No newline at end of file diff --git a/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj b/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj index 1a18e4e..0d1f7af 100644 --- a/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj +++ b/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj @@ -18,6 +18,7 @@ True + diff --git a/SystemExtensions.NetStandard/Threading/PriorityThreadPool.cs b/SystemExtensions.NetStandard/Threading/PriorityThreadPool.cs index 66e68a3..09d29be 100644 --- a/SystemExtensions.NetStandard/Threading/PriorityThreadPool.cs +++ b/SystemExtensions.NetStandard/Threading/PriorityThreadPool.cs @@ -1,563 +1,577 @@ using System.Collections.Generic; -namespace System.Threading +namespace System.Threading; + +/// +/// Threadpool implementation that uses a priority queue as the queue for the tasks to execute. +/// Features both an automated algorithm to calibrate the number of active threads and a Constructor for constructing +/// a threadpool manually, without the auto-managed pool algorithm. +/// +public class PriorityThreadPool : IDisposable { - /// - /// Threadpool implementation that uses a priority queue as the queue for the tasks to execute. - /// Features both an automated algorithm to calibrate the number of active threads and a Constructor for constructing - /// a threadpool manually, without the auto-managed pool algorithm. - /// - public class PriorityThreadPool : IDisposable + private class QueueEntry : IComparable { - private class QueueEntry : IComparable + public TaskPriority TaskPriority { get; } + public WaitCallback WaitCallback { get; } + public object Object { get; } + public QueueEntry(TaskPriority priority, WaitCallback callback, object obj) { - public TaskPriority TaskPriority { get; } - public WaitCallback WaitCallback { get; } - public object Object { get; } - public QueueEntry(TaskPriority priority, WaitCallback callback, object obj) + this.TaskPriority = priority; + this.WaitCallback = callback; + this.Object = obj; + } + + public int CompareTo(QueueEntry other) + { + int priority1 = 0, priority2 = 0; + switch (this.TaskPriority) { - this.TaskPriority = priority; - this.WaitCallback = callback; - this.Object = obj; + case TaskPriority.Highest: + priority1 = 4; + break; + case TaskPriority.AboveNormal: + priority1 = 3; + break; + case TaskPriority.Normal: + priority1 = 2; + break; + case TaskPriority.BelowNormal: + priority1 = 1; + break; + case TaskPriority.Lowest: + priority1 = 0; + break; } - public int CompareTo(QueueEntry other) + switch (other.TaskPriority) { - int priority1 = 0, priority2 = 0; - switch (this.TaskPriority) + case TaskPriority.Highest: + priority2 = 4; + break; + case TaskPriority.AboveNormal: + priority2 = 3; + break; + case TaskPriority.Normal: + priority2 = 2; + break; + case TaskPriority.BelowNormal: + priority2 = 1; + break; + case TaskPriority.Lowest: + priority2 = 0; + break; + } + + if (priority1 == priority2) + { + return 0; + } + else if (priority1 > priority2) + { + return -1; + } + else + { + return 1; + } + } + } + + #region Enum + /// + /// Enum for priority of task scheduled + /// + public enum TaskPriority + { + /// + /// Highest priority of a task. + /// + Highest, + /// + /// Priority level above the default level. + /// + AboveNormal, + /// + /// Default priority level of all tasks without a specified priority level. + /// + Normal, + /// + /// Priority level below the default level. + /// + BelowNormal, + /// + /// Lowest priority level. + /// + Lowest + } + #endregion + #region Fields + /// + /// List that contains current running threads and their status. + /// + private volatile List threadpool; + private volatile PriorityQueue tasks; + private Thread observer; + private CancellationTokenSource observerCancellationTokenSource = new CancellationTokenSource(); + private readonly object tasksLock = new object(); + private struct WorkerThread + { + public Thread Thread { get; set; } + public bool Running { get; set; } + public bool Working { get; set; } + public CancellationTokenSource CancellationTokenSource { get; set; } + } + private struct Statistics + { + public bool Initialized { get; set; } + public int PerformanceCounter { get; set; } + public DateTime LastUpdate { get; set; } + public double LoopFrequency { get; set; } + } + #endregion + #region Properties + /// + /// Returns the number of active threads in the threadpool. + /// + public int NumberOfThreads + { + get + { + return this.threadpool is null ? 0 : this.threadpool.Count; + } + } + /// + /// Returns true if there are no tasks queued. + /// + public bool Empty + { + get + { + return this.tasks is null ? true : this.tasks.Count == 0; + } + } + /// + /// Maximum amount of threads that the pool can utilize + /// + public int MaxThreads { set; get; } + #endregion + #region Constructors + /// + /// Constructor that initializes a threadpool using default values. All threads run at the same priority. + /// The maximum number of threads is equal to System.Environment.ProcessorCount + /// + public PriorityThreadPool() + { + this.threadpool = new List(); + this.tasks = new PriorityQueue(); + this.MaxThreads = System.Environment.ProcessorCount; + for (var i = 0; i < this.MaxThreads; i++) + { + this.CreateAndStartWorkerThread(); + } + + this.observer = new Thread(() => this.ObserverLoop()) + { + Name = "ThreadPool ObserverThread", + Priority = ThreadPriority.BelowNormal + }; + this.observer.Start(); + } + /// + /// Constructor that initializes a threadpool with a number of threads, all of the same priority. + /// + /// Maximum number of threads + public PriorityThreadPool(int maxThreads) + { + this.threadpool = new List(); + this.tasks = new PriorityQueue(); + this.MaxThreads = Math.Max(maxThreads, 1); + for (var i = 0; i < maxThreads; i++) + { + this.CreateAndStartWorkerThread(); + } + + this.observer = new Thread(() => this.ObserverLoop()); + this.observer.Name = "ThreadPool ObserverThread"; + this.observer.Priority = ThreadPriority.BelowNormal; + this.observer.Start(); + } + /// + /// Constructor for a manually-configured threadpool that runs a specified number of threads. + /// This threadpool with not be automatically managed and will always run the specified amount of threads + /// + /// Number of threads with Lowest priority. + /// Number of threads with BelowNormal priority. + /// Number of threads with Normal priority. + /// Number of threads with AboveNormal priority. + /// Number of threads with Highest priority. + public PriorityThreadPool(int lowest, int belowNormal, int normal, int aboveNormal, int highest) + { + this.threadpool = new List(); + this.tasks = new PriorityQueue(); + for (var i = 0; i < lowest; i++) + { + this.CreateAndStartWorkerThread(ThreadPriority.Lowest); + } + + for (var i = 0; i < belowNormal; i++) + { + this.CreateAndStartWorkerThread(ThreadPriority.BelowNormal); + } + + for (var i = 0; i < normal; i++) + { + this.CreateAndStartWorkerThread(ThreadPriority.Normal); + } + + for (var i = 0; i < aboveNormal; i++) + { + this.CreateAndStartWorkerThread(ThreadPriority.AboveNormal); + } + + for (var i = 0; i < highest; i++) + { + this.CreateAndStartWorkerThread(ThreadPriority.Highest); + } + } + #endregion + #region Public Methods + /// + /// Add a work item into the queue. + /// + /// WaitCallBack delegate that will be invoked by the threads. + /// State used as parameter during invoke. + /// Priority of task. Affects its position into the queue. + public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority) + { + while (!Monitor.TryEnter(this.tasksLock)) + { + ; + } + + this.tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState)); + Monitor.Exit(this.tasksLock); + } + /// + /// Add a work item into the queue. + /// + /// WaitCallBack delegate that will be invoked by the threads. + /// State used as parameter during invoke. + public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState) + { + this.QueueUserWorkItem(waitCallback, callbackState, TaskPriority.Normal); + } + #endregion + #region Private Methods + private void CreateAndStartWorkerThread(ThreadPriority threadPriority) + { + var worker = new WorkerThread(); + worker.Thread = new Thread(() => this.ThreadMainLoop(ref worker)); + worker.Thread.Name = "ThreadPool WorkerThread"; + worker.Thread.Priority = threadPriority; + worker.Running = true; + worker.CancellationTokenSource = new CancellationTokenSource(); + worker.Thread.Start(); + this.threadpool.Add(worker); + } + private void CreateAndStartWorkerThread() + { + var worker = new WorkerThread(); + worker.Thread = new Thread(() => this.ThreadMainLoop(ref worker)); + worker.Thread.Name = "ThreadPool WorkerThread"; + worker.Running = true; + worker.CancellationTokenSource = new CancellationTokenSource(); + worker.Thread.Start(); + this.threadpool.Add(worker); + } + /// + /// Main loop that a thread from the pool is running. + /// + /// Id of thread + private void ThreadMainLoop(ref WorkerThread thisWorkerThread) + { + thisWorkerThread.Running = true; + while (thisWorkerThread.Running) + { + if (thisWorkerThread.CancellationTokenSource.Token.IsCancellationRequested) + { + thisWorkerThread.Running = false; + return; + } + + //Check if there are tasks + if (this.tasks.Count > 0) + { + //If there are tasks, acquire a lock onto the list + //and try to dequeue the highest priority task. + //Finally, release the lock and invoke the task. + + thisWorkerThread.Working = true; + QueueEntry task = null; + while (!Monitor.TryEnter(this.tasksLock)) { - case TaskPriority.Highest: - priority1 = 4; - break; - case TaskPriority.AboveNormal: - priority1 = 3; - break; - case TaskPriority.Normal: - priority1 = 2; - break; - case TaskPriority.BelowNormal: - priority1 = 1; - break; - case TaskPriority.Lowest: - priority1 = 0; - break; + ; } - switch (other.TaskPriority) + if (this.tasks.Count > 0) { - case TaskPriority.Highest: - priority2 = 4; - break; - case TaskPriority.AboveNormal: - priority2 = 3; - break; - case TaskPriority.Normal: - priority2 = 2; - break; - case TaskPriority.BelowNormal: - priority2 = 1; - break; - case TaskPriority.Lowest: - priority2 = 0; - break; + task = this.tasks.Dequeue(); } - if (priority1 == priority2) + Monitor.Exit(this.tasksLock); + if (task != null) { - return 0; + System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!"); + var waitCallback = task.WaitCallback; + waitCallback.Invoke(task.Object); } - else if (priority1 > priority2) + + thisWorkerThread.Working = false; + } + } + } + /// + /// Loop of the thread that adjusts and manipulates the threadpool + /// + private void ObserverLoop() + { + var statistics = new Statistics(); + while (true) + { + //Observer operates on a 100ms loop. Due to the low priority of the thread itself, this loop will almost always take + //considerably longer than 100ms. + //Checks if the queue is empty. If yes, counter is decremented, else, counter is incremented. + //If counter exceeds 5, it will try to add another thread to the thread, unless the threadpool has reached max size. + //If counter is under -10, it will try to remove a thread from the threadpool, unless the threadpool has reached less than + //max size / 4. + + if (this.observerCancellationTokenSource.Token.IsCancellationRequested) + { + return; + } + + //This part of code updates the statistics of the threadpool. + if (statistics.Initialized) + { + var loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds; + if (statistics.LoopFrequency == 0) { - return -1; + statistics.LoopFrequency = loopDuration; } else { - return 1; + statistics.LoopFrequency = (statistics.LoopFrequency + loopDuration) / 2; } } - } - - #region Enum - /// - /// Enum for priority of task scheduled - /// - public enum TaskPriority - { - /// - /// Highest priority of a task. - /// - Highest, - /// - /// Priority level above the default level. - /// - AboveNormal, - /// - /// Default priority level of all tasks without a specified priority level. - /// - Normal, - /// - /// Priority level below the default level. - /// - BelowNormal, - /// - /// Lowest priority level. - /// - Lowest - } - #endregion - #region Fields - /// - /// List that contains current running threads and their status. - /// - private volatile List threadpool; - private volatile PriorityQueue tasks; - private Thread observer; - private CancellationTokenSource observerCancellationTokenSource = new CancellationTokenSource(); - private readonly object tasksLock = new object(); - private struct WorkerThread - { - public Thread Thread { get; set; } - public bool Running { get; set; } - public bool Working { get; set; } - public CancellationTokenSource CancellationTokenSource { get; set; } - } - private struct Statistics - { - public bool Initialized { get; set; } - public int PerformanceCounter { get; set; } - public DateTime LastUpdate { get; set; } - public double LoopFrequency { get; set; } - } - #endregion - #region Properties - /// - /// Returns the number of active threads in the threadpool. - /// - public int NumberOfThreads - { - get + else { - return this.threadpool is null ? 0 : this.threadpool.Count; - } - } - /// - /// Returns true if there are no tasks queued. - /// - public bool Empty - { - get - { - return this.tasks is null ? true : this.tasks.Count == 0; - } - } - /// - /// Maximum amount of threads that the pool can utilize - /// - public int MaxThreads { set; get; } - #endregion - #region Constructors - /// - /// Constructor that initializes a threadpool using default values. All threads run at the same priority. - /// The maximum number of threads is equal to System.Environment.ProcessorCount - /// - public PriorityThreadPool() - { - threadpool = new List(); - tasks = new PriorityQueue(); - MaxThreads = System.Environment.ProcessorCount; - for (var i = 0; i < MaxThreads; i++) - { - this.CreateAndStartWorkerThread(); - } - observer = new Thread(() => ObserverLoop()) - { - Name = "ThreadPool ObserverThread", - Priority = ThreadPriority.BelowNormal - }; - observer.Start(); - } - /// - /// Constructor that initializes a threadpool with a number of threads, all of the same priority. - /// - /// Maximum number of threads - public PriorityThreadPool(int maxThreads) - { - threadpool = new List(); - tasks = new PriorityQueue(); - this.MaxThreads = Math.Max(maxThreads, 1); - for (var i = 0; i < maxThreads; i++) - { - this.CreateAndStartWorkerThread(); - } - observer = new Thread(() => ObserverLoop()); - observer.Name = "ThreadPool ObserverThread"; - observer.Priority = ThreadPriority.BelowNormal; - observer.Start(); - } - /// - /// Constructor for a manually-configured threadpool that runs a specified number of threads. - /// This threadpool with not be automatically managed and will always run the specified amount of threads - /// - /// Number of threads with Lowest priority. - /// Number of threads with BelowNormal priority. - /// Number of threads with Normal priority. - /// Number of threads with AboveNormal priority. - /// Number of threads with Highest priority. - public PriorityThreadPool(int lowest, int belowNormal, int normal, int aboveNormal, int highest) - { - threadpool = new List(); - tasks = new PriorityQueue(); - for (var i = 0; i < lowest; i++) - { - this.CreateAndStartWorkerThread(ThreadPriority.Lowest); - } - for (var i = 0; i < belowNormal; i++) - { - this.CreateAndStartWorkerThread(ThreadPriority.BelowNormal); - } - for (var i = 0; i < normal; i++) - { - this.CreateAndStartWorkerThread(ThreadPriority.Normal); - } - for (var i = 0; i < aboveNormal; i++) - { - this.CreateAndStartWorkerThread(ThreadPriority.AboveNormal); - } - for (var i = 0; i < highest; i++) - { - this.CreateAndStartWorkerThread(ThreadPriority.Highest); - } - } - #endregion - #region Public Methods - /// - /// Add a work item into the queue. - /// - /// WaitCallBack delegate that will be invoked by the threads. - /// State used as parameter during invoke. - /// Priority of task. Affects its position into the queue. - public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority) - { - while (!Monitor.TryEnter(tasksLock)) - { - ; + statistics.Initialized = true; } - tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState)); - Monitor.Exit(tasksLock); - } - /// - /// Add a work item into the queue. - /// - /// WaitCallBack delegate that will be invoked by the threads. - /// State used as parameter during invoke. - public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState) - { - QueueUserWorkItem(waitCallback, callbackState, TaskPriority.Normal); - } - #endregion - #region Private Methods - private void CreateAndStartWorkerThread(ThreadPriority threadPriority) - { - var worker = new WorkerThread(); - worker.Thread = new Thread(() => ThreadMainLoop(ref worker)); - worker.Thread.Name = "ThreadPool WorkerThread"; - worker.Thread.Priority = threadPriority; - worker.Running = true; - worker.CancellationTokenSource = new CancellationTokenSource(); - worker.Thread.Start(); - threadpool.Add(worker); - } - private void CreateAndStartWorkerThread() - { - var worker = new WorkerThread(); - worker.Thread = new Thread(() => ThreadMainLoop(ref worker)); - worker.Thread.Name = "ThreadPool WorkerThread"; - worker.Running = true; - worker.CancellationTokenSource = new CancellationTokenSource(); - worker.Thread.Start(); - threadpool.Add(worker); - } - /// - /// Main loop that a thread from the pool is running. - /// - /// Id of thread - private void ThreadMainLoop(ref WorkerThread thisWorkerThread) - { - thisWorkerThread.Running = true; - while (thisWorkerThread.Running) + statistics.LastUpdate = DateTime.Now; + + Thread.Sleep(100); + + + //This part of code adjusts the performance counter. Ideally, the value should be 0. + if (this.tasks.Count > 0) { - if (thisWorkerThread.CancellationTokenSource.Token.IsCancellationRequested) + statistics.PerformanceCounter++; + if (statistics.PerformanceCounter > 5) { - thisWorkerThread.Running = false; - return; - } - - //Check if there are tasks - if (tasks.Count > 0) - { - //If there are tasks, acquire a lock onto the list - //and try to dequeue the highest priority task. - //Finally, release the lock and invoke the task. - - thisWorkerThread.Working = true; - QueueEntry task = null; - while (!Monitor.TryEnter(tasksLock)) - { - ; - } - - if (tasks.Count > 0) - { - task = tasks.Dequeue(); - } - Monitor.Exit(tasksLock); - if (task != null) - { - System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!"); - var waitCallback = task.WaitCallback; - waitCallback.Invoke(task.Object); - } - thisWorkerThread.Working = false; + statistics.PerformanceCounter = 5; } } - } - /// - /// Loop of the thread that adjusts and manipulates the threadpool - /// - private void ObserverLoop() - { - var statistics = new Statistics(); - while (true) + else { - //Observer operates on a 100ms loop. Due to the low priority of the thread itself, this loop will almost always take - //considerably longer than 100ms. - //Checks if the queue is empty. If yes, counter is decremented, else, counter is incremented. - //If counter exceeds 5, it will try to add another thread to the thread, unless the threadpool has reached max size. - //If counter is under -10, it will try to remove a thread from the threadpool, unless the threadpool has reached less than - //max size / 4. - - if (observerCancellationTokenSource.Token.IsCancellationRequested) + statistics.PerformanceCounter--; + if (statistics.PerformanceCounter < -10) { - return; + statistics.PerformanceCounter = -10; } + } - //This part of code updates the statistics of the threadpool. - if (statistics.Initialized) + //This part of code adjusts thread priorities based on the current performance of the threadpool + if (this.tasks.Count > 0) + { + //If there are tasks pending, find a thread with priority under Normal and upgrade its priority. + var t = this.FindThreadWithLowPriority(); + if (t != null) { - var loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds; - if (statistics.LoopFrequency == 0) + this.UpgradeThreadPriority(t); + } + } + else + { + //If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority. + var t = this.FindThreadWithAcceptablePriority(); + if (t != null) + { + this.DowngradeThreadPriority(t); + } + } + + + //This part of code modifies the number of active threads based on the current performance of the threadpool + if (statistics.PerformanceCounter >= 5) + { + if (this.threadpool.Count < this.MaxThreads) + { + //Add a thread to the threadpool. + //Reset counter to 0. + statistics.PerformanceCounter = 0; + this.CreateAndStartWorkerThread(); + } + } + else if (statistics.PerformanceCounter <= -10) + { + if (this.threadpool.Count > this.MaxThreads / 4) + { + //Remove the last thread in the threadpool. + //If thread is currently working, notify it to close. + //Else, abort the thread. + //Reset counter to 0. + var worker = this.threadpool[this.threadpool.Count - 1]; + if (worker.Working) { - statistics.LoopFrequency = loopDuration; + worker.Running = false; } else - { - statistics.LoopFrequency = (statistics.LoopFrequency + loopDuration) / 2; - } - } - else - { - statistics.Initialized = true; - } - statistics.LastUpdate = DateTime.Now; - - Thread.Sleep(100); - - - //This part of code adjusts the performance counter. Ideally, the value should be 0. - if (tasks.Count > 0) - { - statistics.PerformanceCounter++; - if (statistics.PerformanceCounter > 5) - { - statistics.PerformanceCounter = 5; - } - } - else - { - statistics.PerformanceCounter--; - if (statistics.PerformanceCounter < -10) - { - statistics.PerformanceCounter = -10; - } - } - - //This part of code adjusts thread priorities based on the current performance of the threadpool - if (tasks.Count > 0) - { - //If there are tasks pending, find a thread with priority under Normal and upgrade its priority. - var t = FindThreadWithLowPriority(); - if (t != null) - { - UpgradeThreadPriority(t); - } - } - else - { - //If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority. - var t = FindThreadWithAcceptablePriority(); - if (t != null) - { - DowngradeThreadPriority(t); - } - } - - - //This part of code modifies the number of active threads based on the current performance of the threadpool - if (statistics.PerformanceCounter >= 5) - { - if (threadpool.Count < this.MaxThreads) - { - //Add a thread to the threadpool. - //Reset counter to 0. - statistics.PerformanceCounter = 0; - this.CreateAndStartWorkerThread(); - } - } - else if (statistics.PerformanceCounter <= -10) - { - if (threadpool.Count > MaxThreads / 4) - { - //Remove the last thread in the threadpool. - //If thread is currently working, notify it to close. - //Else, abort the thread. - //Reset counter to 0. - var worker = threadpool[threadpool.Count - 1]; - if (worker.Working) - { - worker.Running = false; - } - else - { - worker.CancellationTokenSource.Cancel(); - } - threadpool.RemoveAt(threadpool.Count - 1); - statistics.PerformanceCounter = 0; - } - } - } - } - /// - /// Find a thread with Lowest or BelowNormal priority. - /// - /// Thread with low priority. - private Thread FindThreadWithLowPriority() - { - foreach (var t in threadpool) - { - if (t.Thread.Priority == ThreadPriority.Lowest || t.Thread.Priority == ThreadPriority.BelowNormal) - { - return t.Thread; - } - } - return null; - } - /// - /// Find a thread with BelowNormal or Normal priority. - /// - /// Thread with BelowNormal or Normal priority. - private Thread FindThreadWithAcceptablePriority() - { - foreach (var t in threadpool) - { - if (t.Thread.Priority == ThreadPriority.Normal || t.Thread.Priority == ThreadPriority.BelowNormal) - { - return t.Thread; - } - } - return null; - } - /// - /// Downgrades the priority of a thread one level. - /// - /// Thread to have its priority level downgraded. - /// - private void DowngradeThreadPriority(Thread t) - { - switch (t.Priority) - { - case ThreadPriority.Highest: - t.Priority = ThreadPriority.AboveNormal; - break; - case ThreadPriority.AboveNormal: - t.Priority = ThreadPriority.Normal; - break; - case ThreadPriority.Normal: - t.Priority = ThreadPriority.BelowNormal; - break; - case ThreadPriority.BelowNormal: - t.Priority = ThreadPriority.Lowest; - break; - case ThreadPriority.Lowest: - t.Priority = ThreadPriority.Lowest; - break; - } - } - /// - /// Upgrades the priority of a thread one level. - /// - /// Thread to have its priority level upgraded. - /// - private void UpgradeThreadPriority(Thread t) - { - switch (t.Priority) - { - case ThreadPriority.Highest: - t.Priority = ThreadPriority.Highest; - break; - case ThreadPriority.AboveNormal: - t.Priority = ThreadPriority.Highest; - break; - case ThreadPriority.Normal: - t.Priority = ThreadPriority.AboveNormal; - break; - case ThreadPriority.BelowNormal: - t.Priority = ThreadPriority.Normal; - break; - case ThreadPriority.Lowest: - t.Priority = ThreadPriority.BelowNormal; - break; - } - } - #endregion - #region IDisposable Support - private bool disposedValue = false; - /// - /// Disposes of the tasks as well as aborts all threads. Called by the public Dispose() method. - /// - /// - protected virtual void Dispose(bool disposing) - { - if (!this.disposedValue) - { - if (disposing) - { - if (this.observer != null) - { - this.observerCancellationTokenSource.Cancel(); - this.observer.Join(); - } - foreach (var worker in threadpool) { worker.CancellationTokenSource.Cancel(); - worker.Thread.Join(); } - this.threadpool.Clear(); - this.tasks.Clear(); + + this.threadpool.RemoveAt(this.threadpool.Count - 1); + statistics.PerformanceCounter = 0; } - this.threadpool = null; - this.tasks = null; - this.observer = null; - this.disposedValue = true; } } - /// - /// Disposes of the tasks as well as aborts all threads. - /// - public void Dispose() - { - Dispose(true); - } - #endregion } + /// + /// Find a thread with Lowest or BelowNormal priority. + /// + /// Thread with low priority. + private Thread FindThreadWithLowPriority() + { + foreach (var t in this.threadpool) + { + if (t.Thread.Priority == ThreadPriority.Lowest || t.Thread.Priority == ThreadPriority.BelowNormal) + { + return t.Thread; + } + } + + return null; + } + /// + /// Find a thread with BelowNormal or Normal priority. + /// + /// Thread with BelowNormal or Normal priority. + private Thread FindThreadWithAcceptablePriority() + { + foreach (var t in this.threadpool) + { + if (t.Thread.Priority == ThreadPriority.Normal || t.Thread.Priority == ThreadPriority.BelowNormal) + { + return t.Thread; + } + } + + return null; + } + /// + /// Downgrades the priority of a thread one level. + /// + /// Thread to have its priority level downgraded. + /// + private void DowngradeThreadPriority(Thread t) + { + switch (t.Priority) + { + case ThreadPriority.Highest: + t.Priority = ThreadPriority.AboveNormal; + break; + case ThreadPriority.AboveNormal: + t.Priority = ThreadPriority.Normal; + break; + case ThreadPriority.Normal: + t.Priority = ThreadPriority.BelowNormal; + break; + case ThreadPriority.BelowNormal: + t.Priority = ThreadPriority.Lowest; + break; + case ThreadPriority.Lowest: + t.Priority = ThreadPriority.Lowest; + break; + } + } + /// + /// Upgrades the priority of a thread one level. + /// + /// Thread to have its priority level upgraded. + /// + private void UpgradeThreadPriority(Thread t) + { + switch (t.Priority) + { + case ThreadPriority.Highest: + t.Priority = ThreadPriority.Highest; + break; + case ThreadPriority.AboveNormal: + t.Priority = ThreadPriority.Highest; + break; + case ThreadPriority.Normal: + t.Priority = ThreadPriority.AboveNormal; + break; + case ThreadPriority.BelowNormal: + t.Priority = ThreadPriority.Normal; + break; + case ThreadPriority.Lowest: + t.Priority = ThreadPriority.BelowNormal; + break; + } + } + #endregion + #region IDisposable Support + private bool disposedValue = false; + /// + /// Disposes of the tasks as well as aborts all threads. Called by the public Dispose() method. + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!this.disposedValue) + { + if (disposing) + { + if (this.observer != null) + { + this.observerCancellationTokenSource.Cancel(); + this.observer.Join(); + } + + foreach (var worker in this.threadpool) + { + worker.CancellationTokenSource.Cancel(); + worker.Thread.Join(); + } + + this.threadpool.Clear(); + this.tasks.Clear(); + } + + this.threadpool = null; + this.tasks = null; + this.observer = null; + this.disposedValue = true; + } + } + /// + /// Disposes of the tasks as well as aborts all threads. + /// + public void Dispose() + { + this.Dispose(true); + } + #endregion } diff --git a/SystemExtensions.Tests/Collections/AVLTreeTests.cs b/SystemExtensions.Tests/Collections/AVLTreeTests.cs index 357aaf5..e46af26 100644 --- a/SystemExtensions.Tests/Collections/AVLTreeTests.cs +++ b/SystemExtensions.Tests/Collections/AVLTreeTests.cs @@ -3,152 +3,157 @@ using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace System.Collections.Tests +namespace System.Collections.Tests; + +[TestClass()] +public class AVLTreeTests { - [TestClass()] - public class AVLTreeTests + private AVLTree avlTree = new AVLTree(); + [TestMethod()] + public void AVLTreeTest() { - private AVLTree avlTree = new AVLTree(); - [TestMethod()] - public void AVLTreeTest() + this.avlTree = new AVLTree(); + } + + [TestMethod()] + public void AddTest() + { + try { - avlTree = new AVLTree(); + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i * 20 - (50 + i)); + } + } + catch (Exception e) + { + Assert.Fail(e.Message + "\n" + e.StackTrace); } - [TestMethod()] - public void AddTest() + if (this.avlTree.Count != 100) { - try - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i * 20 - (50 + i)); - } - } - catch (Exception e) - { - Assert.Fail(e.Message + "\n" + e.StackTrace); - } - if (avlTree.Count != 100) + Assert.Fail(); + } + } + + [TestMethod()] + public void ContainsTest() + { + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + if (!this.avlTree.Contains(50)) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void RemoveTest() + { + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + this.avlTree.Remove(50); + + if (this.avlTree.Contains(50)) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ClearTest() + { + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + this.avlTree.Clear(); + if(this.avlTree.Count > 0) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void CopyToTest() + { + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + var array = new int[100]; + this.avlTree.CopyTo(array, 0); + } + + [TestMethod()] + public void GetEnumeratorTest() + { + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + var count = 0; + foreach(var value in this.avlTree) + { + count++; + System.Diagnostics.Debug.WriteLine(value); + } + + if(count != this.avlTree.Count) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ToArrayTest() + { + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + _ = this.avlTree.ToArray(); + } + + [TestMethod()] + public void Serialize() + { + var avlTree2 = new AVLTree(); + for (var i = 0; i < 100; i++) + { + this.avlTree.Add(i); + } + + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, this.avlTree); + stream.Position = 0; + avlTree2 = (AVLTree)serializer.Deserialize(stream); + } + + var avlTreeEnum = this.avlTree.GetEnumerator(); + var avlTree2Enum = avlTree2.GetEnumerator(); + + for(var i = 0; i < 100; i++) + { + if(avlTreeEnum.Current != avlTree2Enum.Current) { Assert.Fail(); } - } - [TestMethod()] - public void ContainsTest() - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - - if (!avlTree.Contains(50)) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void RemoveTest() - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - - avlTree.Remove(50); - - if (avlTree.Contains(50)) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ClearTest() - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - avlTree.Clear(); - if(avlTree.Count > 0) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void CopyToTest() - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - - var array = new int[100]; - avlTree.CopyTo(array, 0); - } - - [TestMethod()] - public void GetEnumeratorTest() - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - var count = 0; - foreach(var value in avlTree) - { - count++; - System.Diagnostics.Debug.WriteLine(value); - } - - if(count != avlTree.Count) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ToArrayTest() - { - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - - _ = avlTree.ToArray(); - } - - [TestMethod()] - public void Serialize() - { - var avlTree2 = new AVLTree(); - for (var i = 0; i < 100; i++) - { - avlTree.Add(i); - } - var serializer = new BinaryFormatter(); - using (var stream = new MemoryStream()) - { - serializer.Serialize(stream, avlTree); - stream.Position = 0; - avlTree2 = (AVLTree)serializer.Deserialize(stream); - } - var avlTreeEnum = avlTree.GetEnumerator(); - var avlTree2Enum = avlTree2.GetEnumerator(); - - for(var i = 0; i < 100; i++) - { - if(avlTreeEnum.Current != avlTree2Enum.Current) - { - Assert.Fail(); - } - avlTreeEnum.MoveNext(); - avlTree2Enum.MoveNext(); - } + avlTreeEnum.MoveNext(); + avlTree2Enum.MoveNext(); } } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Collections/BinaryHeapTests.cs b/SystemExtensions.Tests/Collections/BinaryHeapTests.cs index a3aa2e9..a32e9cc 100644 --- a/SystemExtensions.Tests/Collections/BinaryHeapTests.cs +++ b/SystemExtensions.Tests/Collections/BinaryHeapTests.cs @@ -3,199 +3,211 @@ using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace System.Collections.Tests +namespace System.Collections.Tests; + +[TestClass()] +public class BinaryHeapTests { - [TestClass()] - public class BinaryHeapTests + private BinaryHeap binaryHeap = new BinaryHeap(); + [TestMethod()] + public void BinaryHeapTest() { - private BinaryHeap binaryHeap = new BinaryHeap(); - [TestMethod()] - public void BinaryHeapTest() + this.binaryHeap = new BinaryHeap(); + } + + [TestMethod()] + public void BinaryHeapTest1() + { + this.binaryHeap = new BinaryHeap(100); + if (this.binaryHeap.Count != 0 && this.binaryHeap.Capacity != 100) { - binaryHeap = new BinaryHeap(); - } - - [TestMethod()] - public void BinaryHeapTest1() - { - binaryHeap = new BinaryHeap(100); - if (binaryHeap.Count != 0 && binaryHeap.Capacity != 100) - { - Assert.Fail(); - } - } - - [TestMethod()] - [Timeout(500)] - public void InsertTest() - { - try - { - for (var i = 0; i < 100; i++) - { - binaryHeap.Add(i * 20 - (50 + i)); - } - } - catch (Exception e) - { - Assert.Fail(e.Message + "\n" + e.StackTrace); - } - if (binaryHeap.Count != 100) - { - Assert.Fail(); - } - } - - [TestMethod()] - [Timeout(500)] - public void DeleteMinTest() - { - try - { - var tries = binaryHeap.Count; - while (binaryHeap.Count > 0) - { - if (tries == 0) - { - Assert.Fail(); - } - System.Diagnostics.Debug.WriteLine(binaryHeap.Remove()); - tries--; - } - } - catch (Exception e) - { - Assert.Fail(e.Message + "\n" + e.StackTrace); - } - } - - [TestMethod()] - public void MinMaxTest() - { - for (var i = 0; i < 1000; i++) - { - binaryHeap.Add(i); - } - if (binaryHeap.Min != 0 || binaryHeap.Max != 999) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ClearTest() - { - for (var i = 0; i < 100; i++) - { - binaryHeap.Add(i); - } - binaryHeap.Clear(); - if (binaryHeap.Count > 0 || binaryHeap.Capacity != 160) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ClearTest2() - { - for (var i = 100; i < 200; i++) - { - binaryHeap.Add(i); - } - binaryHeap.Clear(false); - var array = binaryHeap.ToArray(); - if (binaryHeap.Count > 0 || binaryHeap.Capacity == 10) - { - Assert.Fail(); - } - if (array.Length != 0) - { - Assert.Fail(); - } - binaryHeap.Clear(true); - if (binaryHeap.Capacity != 10 || binaryHeap.Count != 0) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ContainsTest() - { - binaryHeap.Add(100); - if (!binaryHeap.Contains(100)) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ToArrayTest() - { - for(var i = 0; i < 1000; i++) - { - binaryHeap.Add(i); - } - var array = binaryHeap.ToArray(); - if(array.Length != binaryHeap.Count) - { - Assert.Fail(); - } - if(array[0] != 0 && array[999] != 999) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void GetEnumeratorTest() - { - for (var i = 0; i < 1000; i++) - { - binaryHeap.Add(i); - } - var count = 0; - foreach(var value in binaryHeap) - { - System.Diagnostics.Debug.WriteLine(value); - count++; - } - - if(count == binaryHeap.Count) - { - return; - } - Assert.Fail(); } + } - [TestMethod()] - public void Serialize() + [TestMethod()] + [Timeout(500)] + public void InsertTest() + { + try { - var binaryHeap2 = new BinaryHeap(); for (var i = 0; i < 100; i++) { - binaryHeap.Add(i); + this.binaryHeap.Add(i * 20 - (50 + i)); } - var serializer = new BinaryFormatter(); - using (var stream = new MemoryStream()) { - serializer.Serialize(stream, binaryHeap); - stream.Position = 0; - binaryHeap2 = (BinaryHeap)serializer.Deserialize(stream); - } - var binaryHeapEnum = binaryHeap.GetEnumerator(); - var binaryHeapEnum2 = binaryHeap2.GetEnumerator(); + } + catch (Exception e) + { + Assert.Fail(e.Message + "\n" + e.StackTrace); + } - for (var i = 0; i < 100; i++) + if (this.binaryHeap.Count != 100) + { + Assert.Fail(); + } + } + + [TestMethod()] + [Timeout(500)] + public void DeleteMinTest() + { + try + { + var tries = this.binaryHeap.Count; + while (this.binaryHeap.Count > 0) { - if (binaryHeapEnum.Current != binaryHeapEnum2.Current) + if (tries == 0) { Assert.Fail(); } - binaryHeapEnum.MoveNext(); - binaryHeapEnum2.MoveNext(); + + System.Diagnostics.Debug.WriteLine(this.binaryHeap.Remove()); + tries--; } } + catch (Exception e) + { + Assert.Fail(e.Message + "\n" + e.StackTrace); + } + } + + [TestMethod()] + public void MinMaxTest() + { + for (var i = 0; i < 1000; i++) + { + this.binaryHeap.Add(i); + } + + if (this.binaryHeap.Min != 0 || this.binaryHeap.Max != 999) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ClearTest() + { + for (var i = 0; i < 100; i++) + { + this.binaryHeap.Add(i); + } + + this.binaryHeap.Clear(); + if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity != 160) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ClearTest2() + { + for (var i = 100; i < 200; i++) + { + this.binaryHeap.Add(i); + } + + this.binaryHeap.Clear(false); + var array = this.binaryHeap.ToArray(); + if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity == 10) + { + Assert.Fail(); + } + + if (array.Length != 0) + { + Assert.Fail(); + } + + this.binaryHeap.Clear(true); + if (this.binaryHeap.Capacity != 10 || this.binaryHeap.Count != 0) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ContainsTest() + { + this.binaryHeap.Add(100); + if (!this.binaryHeap.Contains(100)) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ToArrayTest() + { + for(var i = 0; i < 1000; i++) + { + this.binaryHeap.Add(i); + } + + var array = this.binaryHeap.ToArray(); + if(array.Length != this.binaryHeap.Count) + { + Assert.Fail(); + } + + if(array[0] != 0 && array[999] != 999) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void GetEnumeratorTest() + { + for (var i = 0; i < 1000; i++) + { + this.binaryHeap.Add(i); + } + + var count = 0; + foreach(var value in this.binaryHeap) + { + System.Diagnostics.Debug.WriteLine(value); + count++; + } + + if(count == this.binaryHeap.Count) + { + return; + } + + Assert.Fail(); + } + + [TestMethod()] + public void Serialize() + { + var binaryHeap2 = new BinaryHeap(); + for (var i = 0; i < 100; i++) + { + this.binaryHeap.Add(i); + } + + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) { + serializer.Serialize(stream, this.binaryHeap); + stream.Position = 0; + binaryHeap2 = (BinaryHeap)serializer.Deserialize(stream); + } + + var binaryHeapEnum = this.binaryHeap.GetEnumerator(); + var binaryHeapEnum2 = binaryHeap2.GetEnumerator(); + + for (var i = 0; i < 100; i++) + { + if (binaryHeapEnum.Current != binaryHeapEnum2.Current) + { + Assert.Fail(); + } + + binaryHeapEnum.MoveNext(); + binaryHeapEnum2.MoveNext(); + } } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Collections/FibonacciHeapTests.cs b/SystemExtensions.Tests/Collections/FibonacciHeapTests.cs index e8bb56e..036eaf5 100644 --- a/SystemExtensions.Tests/Collections/FibonacciHeapTests.cs +++ b/SystemExtensions.Tests/Collections/FibonacciHeapTests.cs @@ -3,202 +3,210 @@ using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace System.Collections.Tests +namespace System.Collections.Tests; + +[TestClass()] +public class FibonacciHeapTests { - [TestClass()] - public class FibonacciHeapTests + FibonacciHeap fibonacciHeap = new FibonacciHeap(); + [TestMethod()] + public void InsertTest() { - FibonacciHeap fibonacciHeap = new FibonacciHeap(); - [TestMethod()] - public void InsertTest() + for (var i = 0; i < 1000; i++) { - for (var i = 0; i < 1000; i++) - { - fibonacciHeap.Add(i); - } + this.fibonacciHeap.Add(i); } + } - [TestMethod()] - public void FibonacciHeapTest() + [TestMethod()] + public void FibonacciHeapTest() + { + this.fibonacciHeap = new FibonacciHeap(); + if(this.fibonacciHeap.Count != 0) { - fibonacciHeap = new FibonacciHeap(); - if(fibonacciHeap.Count != 0) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void MergeTest() - { - var fibonacciHeap1 = new FibonacciHeap(); - var fibonacciHeap2 = new FibonacciHeap(); - - for(var i = 0; i < 100; i++) - { - fibonacciHeap1.Add(i); - } - - for(var i = 100; i < 300; i++) - { - fibonacciHeap2.Add(i); - } - - fibonacciHeap1.Merge(fibonacciHeap2); - for(var i = 1; i < 300; i++) - { - if (!fibonacciHeap1.Contains(i)) - { - Assert.Fail(); - } - } - } - - [TestMethod()] - public void RemoveMinimumTest() - { - try - { - fibonacciHeap.Remove(); - Assert.Fail(); - } - catch (IndexOutOfRangeException) - { - - } - catch (Exception) - { - Assert.Fail(); - } - for (var i = 0; i < 1000; i++) - { - fibonacciHeap.Add(i); - } - for (var i = 0; i < 1000; i++) - { - if (fibonacciHeap.Remove() != i) - { - Assert.Fail(); - } - } - } - - [TestMethod()] - public void DecreaseKeyTest() - { - fibonacciHeap.Add(5); - fibonacciHeap.Add(10); - fibonacciHeap.Add(7); - fibonacciHeap.DecreaseKey(5, 3); - if(fibonacciHeap.Contains(5) || !fibonacciHeap.Contains(3)) - { - Assert.Fail(); - } - fibonacciHeap.DecreaseKey(10, 1); - if(fibonacciHeap.Remove() != 1) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ContainsTest() - { - for(var i = 0; i < 10000; i++) - { - fibonacciHeap.Add(i); - } - if (!fibonacciHeap.Contains(5124)) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ClearTest() - { - for(var i = 0; i < 10000; i++) - { - fibonacciHeap.Add(i); - } - fibonacciHeap.Remove(); - fibonacciHeap.Clear(); - if(fibonacciHeap.Count > 0) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ToArrayTest() - { - for(var i = 999; i >= 0; i--) - { - fibonacciHeap.Add(i); - } - fibonacciHeap.Remove(); - var arr = fibonacciHeap.ToArray(); - - for(var i = 1; i < 512; i++) - { - if(arr[i - 1] != i) - { - Assert.Fail(); - } - } - } - - [TestMethod()] - public void GetEnumeratorTest() - { - for (var i = 999; i >= 0; i--) - { - fibonacciHeap.Add(i); - } - - var count = 0; - - foreach(var value in fibonacciHeap) - { - System.Diagnostics.Debug.WriteLine(value); - count++; - } - - if(count == fibonacciHeap.Count) - { - return; - } - Assert.Fail(); } + } - [TestMethod()] - public void Serialize() + [TestMethod()] + public void MergeTest() + { + var fibonacciHeap1 = new FibonacciHeap(); + var fibonacciHeap2 = new FibonacciHeap(); + + for(var i = 0; i < 100; i++) { - var fibonacciHeap2 = new FibonacciHeap(); - for (var i = 0; i < 100; i++) - { - fibonacciHeap.Add(i); - } - var serializer = new BinaryFormatter(); - using (var stream = new MemoryStream()) - { - serializer.Serialize(stream, fibonacciHeap); - stream.Position = 0; - fibonacciHeap2 = (FibonacciHeap)serializer.Deserialize(stream); - } - var enum1 = fibonacciHeap.GetEnumerator(); - var enum2 = fibonacciHeap2.GetEnumerator(); + fibonacciHeap1.Add(i); + } - for (var i = 0; i < 100; i++) + for(var i = 100; i < 300; i++) + { + fibonacciHeap2.Add(i); + } + + fibonacciHeap1.Merge(fibonacciHeap2); + for(var i = 1; i < 300; i++) + { + if (!fibonacciHeap1.Contains(i)) { - if (enum1.Current != enum2.Current) - { - Assert.Fail(); - } - enum1.MoveNext(); - enum2.MoveNext(); + Assert.Fail(); } } } + + [TestMethod()] + public void RemoveMinimumTest() + { + try + { + this.fibonacciHeap.Remove(); + Assert.Fail(); + } + catch (IndexOutOfRangeException) + { + + } + catch (Exception) + { + Assert.Fail(); + } + + for (var i = 0; i < 1000; i++) + { + this.fibonacciHeap.Add(i); + } + + for (var i = 0; i < 1000; i++) + { + if (this.fibonacciHeap.Remove() != i) + { + Assert.Fail(); + } + } + } + + [TestMethod()] + public void DecreaseKeyTest() + { + this.fibonacciHeap.Add(5); + this.fibonacciHeap.Add(10); + this.fibonacciHeap.Add(7); + this.fibonacciHeap.DecreaseKey(5, 3); + if(this.fibonacciHeap.Contains(5) || !this.fibonacciHeap.Contains(3)) + { + Assert.Fail(); + } + + this.fibonacciHeap.DecreaseKey(10, 1); + if(this.fibonacciHeap.Remove() != 1) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ContainsTest() + { + for(var i = 0; i < 10000; i++) + { + this.fibonacciHeap.Add(i); + } + + if (!this.fibonacciHeap.Contains(5124)) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ClearTest() + { + for(var i = 0; i < 10000; i++) + { + this.fibonacciHeap.Add(i); + } + + this.fibonacciHeap.Remove(); + this.fibonacciHeap.Clear(); + if(this.fibonacciHeap.Count > 0) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ToArrayTest() + { + for(var i = 999; i >= 0; i--) + { + this.fibonacciHeap.Add(i); + } + + this.fibonacciHeap.Remove(); + var arr = this.fibonacciHeap.ToArray(); + + for(var i = 1; i < 512; i++) + { + if(arr[i - 1] != i) + { + Assert.Fail(); + } + } + } + + [TestMethod()] + public void GetEnumeratorTest() + { + for (var i = 999; i >= 0; i--) + { + this.fibonacciHeap.Add(i); + } + + var count = 0; + + foreach(var value in this.fibonacciHeap) + { + System.Diagnostics.Debug.WriteLine(value); + count++; + } + + if(count == this.fibonacciHeap.Count) + { + return; + } + + Assert.Fail(); + } + + [TestMethod()] + public void Serialize() + { + var fibonacciHeap2 = new FibonacciHeap(); + for (var i = 0; i < 100; i++) + { + this.fibonacciHeap.Add(i); + } + + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, this.fibonacciHeap); + stream.Position = 0; + fibonacciHeap2 = (FibonacciHeap)serializer.Deserialize(stream); + } + + var enum1 = this.fibonacciHeap.GetEnumerator(); + var enum2 = fibonacciHeap2.GetEnumerator(); + + for (var i = 0; i < 100; i++) + { + if (enum1.Current != enum2.Current) + { + Assert.Fail(); + } + + enum1.MoveNext(); + enum2.MoveNext(); + } + } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Collections/PriorityQueueTests.cs b/SystemExtensions.Tests/Collections/PriorityQueueTests.cs index 5776b0c..9fb1a31 100644 --- a/SystemExtensions.Tests/Collections/PriorityQueueTests.cs +++ b/SystemExtensions.Tests/Collections/PriorityQueueTests.cs @@ -3,108 +3,114 @@ using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace System.Collections.Tests +namespace System.Collections.Tests; + +[TestClass()] +public class PriorityQueueTests { - [TestClass()] - public class PriorityQueueTests + private PriorityQueue priorityQueue = new PriorityQueue(); + [TestMethod()] + public void PriorityQueueTest() { - private PriorityQueue priorityQueue = new PriorityQueue(); - [TestMethod()] - public void PriorityQueueTest() + try { - try + this.priorityQueue = new PriorityQueue(); + if(this.priorityQueue.Count > 0) { - priorityQueue = new PriorityQueue(); - if(priorityQueue.Count > 0) - { - Assert.Fail(); - } - } - catch(Exception e) - { - Assert.Fail(e.Message + "\n" + e.StackTrace); + Assert.Fail(); } } - - [TestMethod()] - public void EnqueueTest() + catch(Exception e) { - for(var i = 0; i < 100; i++) - { - priorityQueue.Enqueue(i); - } - if(priorityQueue.Count != 100) + Assert.Fail(e.Message + "\n" + e.StackTrace); + } + } + + [TestMethod()] + public void EnqueueTest() + { + for(var i = 0; i < 100; i++) + { + this.priorityQueue.Enqueue(i); + } + + if(this.priorityQueue.Count != 100) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void DequeueTest() + { + for(var i = 0; i < 100; i++) + { + this.priorityQueue.Enqueue(i); + } + + for(var i = 0; i < 100; i++) + { + if(i != this.priorityQueue.Dequeue()) { Assert.Fail(); } } - [TestMethod()] - public void DequeueTest() + if(this.priorityQueue.Count > 0) { - for(var i = 0; i < 100; i++) - { - priorityQueue.Enqueue(i); - } - for(var i = 0; i < 100; i++) - { - if(i != priorityQueue.Dequeue()) - { - Assert.Fail(); - } - } - if(priorityQueue.Count > 0) - { - Assert.Fail(); - } - try - { - priorityQueue.Dequeue(); - Assert.Fail(); - } - catch - { - - } + Assert.Fail(); } - [TestMethod()] - public void PeekTest() + try { - priorityQueue.Enqueue(1051); - if(priorityQueue.Peek() != 1051 && priorityQueue.Count != 1) + this.priorityQueue.Dequeue(); + Assert.Fail(); + } + catch + { + + } + } + + [TestMethod()] + public void PeekTest() + { + this.priorityQueue.Enqueue(1051); + if(this.priorityQueue.Peek() != 1051 && this.priorityQueue.Count != 1) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void Serialize() + { + var priorityQueue2 = new PriorityQueue(); + for (var i = 0; i < 100; i++) + { + this.priorityQueue.Enqueue(i); + } + + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, this.priorityQueue); + stream.Position = 0; + priorityQueue2 = (PriorityQueue)serializer.Deserialize(stream); + } + + var enum1 = this.priorityQueue.GetEnumerator(); + var enum2 = priorityQueue2.GetEnumerator(); + + for (var i = 0; i < 100; i++) + { + if (enum1.Current != enum2.Current) { Assert.Fail(); } - } - [TestMethod()] - public void Serialize() - { - var priorityQueue2 = new PriorityQueue(); - for (var i = 0; i < 100; i++) - { - priorityQueue.Enqueue(i); - } - var serializer = new BinaryFormatter(); - using (var stream = new MemoryStream()) - { - serializer.Serialize(stream, priorityQueue); - stream.Position = 0; - priorityQueue2 = (PriorityQueue)serializer.Deserialize(stream); - } - var enum1 = priorityQueue.GetEnumerator(); - var enum2 = priorityQueue2.GetEnumerator(); - - for (var i = 0; i < 100; i++) - { - if (enum1.Current != enum2.Current) - { - Assert.Fail(); - } - enum1.MoveNext(); - enum2.MoveNext(); - } + enum1.MoveNext(); + enum2.MoveNext(); } } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Collections/SkipListTests.cs b/SystemExtensions.Tests/Collections/SkipListTests.cs index e0b4e19..ba93f7b 100644 --- a/SystemExtensions.Tests/Collections/SkipListTests.cs +++ b/SystemExtensions.Tests/Collections/SkipListTests.cs @@ -3,153 +3,159 @@ using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace System.Collections.Tests +namespace System.Collections.Tests; + +[TestClass()] +public class SkipListTests { - [TestClass()] - public class SkipListTests + SkipList skipList = new SkipList(); + [TestMethod()] + public void SkipListTest() { - SkipList skipList = new SkipList(); - [TestMethod()] - public void SkipListTest() + _ = new SkipList(); + } + + [TestMethod()] + public void SkipListTest2() + { + _ = new SkipList(30); + } + + [TestMethod()] + public void AddTest() + { + for(var i = 0; i < 200; i++) { - _ = new SkipList(); + this.skipList.Add(i); + } + } + + [TestMethod()] + public void ClearTest() + { + for (var i = 0; i < 200; i++) + { + this.skipList.Add(i); } - [TestMethod()] - public void SkipListTest2() + this.skipList.Clear(); + if(this.skipList.Count > 0) { - _ = new SkipList(30); + Assert.Fail(); + } + } + + [TestMethod()] + public void ContainsTest() + { + for (var i = 0; i < 200; i++) + { + this.skipList.Add(i); } - [TestMethod()] - public void AddTest() + if (!this.skipList.Contains(50)) { - for(var i = 0; i < 200; i++) - { - skipList.Add(i); - } + Assert.Fail(); + } + } + + [TestMethod()] + public void CopyToTest() + { + for (var i = 0; i < 200; i++) + { + this.skipList.Add(i); } - [TestMethod()] - public void ClearTest() + var array = new int[this.skipList.Count]; + this.skipList.CopyTo(array, 0); + for (var i = 0; i < 200; i++) { - for (var i = 0; i < 200; i++) - { - skipList.Add(i); - } - skipList.Clear(); - if(skipList.Count > 0) + if(array[i] != i) { Assert.Fail(); } } - - [TestMethod()] - public void ContainsTest() - { - for (var i = 0; i < 200; i++) - { - skipList.Add(i); - } - - if (!skipList.Contains(50)) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void CopyToTest() - { - for (var i = 0; i < 200; i++) - { - skipList.Add(i); - } - var array = new int[skipList.Count]; - skipList.CopyTo(array, 0); - for (var i = 0; i < 200; i++) - { - if(array[i] != i) - { - Assert.Fail(); - } - } - } - - [TestMethod()] - public void ToArrayTest() - { - for (var i = 0; i < 200; i++) - { - skipList.Add(i); - } - var array = skipList.ToArray(); - - for (var i = 0; i < 200; i++) - { - if(array[i] != i) - { - Assert.Fail(); - } - } - } - - [TestMethod()] - public void GetEnumeratorTest() - { - for (var i = 0; i < 200; i++) - { - skipList.Add(i); - } - - foreach(var i in skipList) - { - System.Diagnostics.Debug.WriteLine(i); - } - } - - [TestMethod()] - public void RemoveTest() - { - for (var i = 0; i < 200; i++) - { - skipList.Add(i); - } - skipList.Remove(50); - if (skipList.Contains(50)) - { - Assert.Fail(); - } - } - - [TestMethod()] - [Ignore("Binary serialization is obsolete and should not be used anymore")] - public void Serialize() - { - var skipList2 = new SkipList(); - for (var i = 0; i < 100; i++) - { - skipList.Add(i); - } - var serializer = new BinaryFormatter(); - using (var stream = new MemoryStream()) - { - serializer.Serialize(stream, skipList); - stream.Position = 0; - skipList2 = (SkipList)serializer.Deserialize(stream); - } - var enum1 = skipList.GetEnumerator(); - var enum2 = skipList2.GetEnumerator(); - - for (var i = 0; i < 100; i++) - { - if (enum1.Current != enum2.Current) - { - Assert.Fail(); - } - enum1.MoveNext(); - enum2.MoveNext(); - } - } + } + + [TestMethod()] + public void ToArrayTest() + { + for (var i = 0; i < 200; i++) + { + this.skipList.Add(i); + } + + var array = this.skipList.ToArray(); + + for (var i = 0; i < 200; i++) + { + if(array[i] != i) + { + Assert.Fail(); + } + } + } + + [TestMethod()] + public void GetEnumeratorTest() + { + for (var i = 0; i < 200; i++) + { + this.skipList.Add(i); + } + + foreach(var i in this.skipList) + { + System.Diagnostics.Debug.WriteLine(i); + } + } + + [TestMethod()] + public void RemoveTest() + { + for (var i = 0; i < 200; i++) + { + this.skipList.Add(i); + } + + this.skipList.Remove(50); + if (this.skipList.Contains(50)) + { + Assert.Fail(); + } + } + + [TestMethod()] + [Ignore("Binary serialization is obsolete and should not be used anymore")] + public void Serialize() + { + var skipList2 = new SkipList(); + for (var i = 0; i < 100; i++) + { + this.skipList.Add(i); + } + + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, this.skipList); + stream.Position = 0; + skipList2 = (SkipList)serializer.Deserialize(stream); + } + + var enum1 = this.skipList.GetEnumerator(); + var enum2 = skipList2.GetEnumerator(); + + for (var i = 0; i < 100; i++) + { + if (enum1.Current != enum2.Current) + { + Assert.Fail(); + } + + enum1.MoveNext(); + enum2.MoveNext(); + } } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Collections/TreapTests.cs b/SystemExtensions.Tests/Collections/TreapTests.cs index 53f6de5..542c578 100644 --- a/SystemExtensions.Tests/Collections/TreapTests.cs +++ b/SystemExtensions.Tests/Collections/TreapTests.cs @@ -3,139 +3,143 @@ using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace System.Collections.Tests +namespace System.Collections.Tests; + +[TestClass()] +public class TreapTests { - [TestClass()] - public class TreapTests + Treap treap = new Treap(); + [TestMethod()] + public void TreapTest() { - Treap treap = new Treap(); - [TestMethod()] - public void TreapTest() + this.treap = new Treap(); + } + + [TestMethod()] + public void InsertTest() + { + var random = new Random(); + for(var i = 0; i < 1000; i++) { - treap = new Treap(); + this.treap.Add(random.Next(0, 5000)); } + } - [TestMethod()] - public void InsertTest() + [TestMethod()] + public void RemoveTest() + { + this.treap.Add(60); + this.treap.Add(6); + this.treap.Add(5); + this.treap.Remove(60); + if(this.treap.Contains(60) || this.treap.Count > 2) { - var random = new Random(); - for(var i = 0; i < 1000; i++) - { - treap.Add(random.Next(0, 5000)); - } - } - - [TestMethod()] - public void RemoveTest() - { - treap.Add(60); - treap.Add(6); - treap.Add(5); - treap.Remove(60); - if(treap.Contains(60) || treap.Count > 2) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ClearTest() - { - var random = new Random(); - for (var i = 0; i < 100; i++) - { - treap.Add(random.Next(0, 5000)); - } - treap.Clear(); - if(treap.Count > 0) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ContainsTest() - { - treap.Add(50); - treap.Add(25); - treap.Add(991142); - treap.Add(12313); - treap.Add(24); - treap.Add(23); - if (!treap.Contains(24)) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void ToArrayTest() - { - for(var i = 0; i < 1000; i++) - { - treap.Add(i); - } - var arr = treap.ToArray(); - for(var i = 0; i < 1000; i++) - { - if(arr[i] != i) - { - Assert.Fail(); - } - } - } - - [TestMethod()] - public void GetEnumeratorTest() - { - for (var i = 0; i < 1000; i++) - { - treap.Add(i); - } - - var count = 0; - foreach(var value in treap) - { - System.Diagnostics.Debug.WriteLine(value); - count++; - } - - if(count == treap.Count) - { - return; - } - Assert.Fail(); } + } - [TestMethod()] - [Ignore("Binary serialization is obsolete and should not be used anymore")] - public void Serialize() + [TestMethod()] + public void ClearTest() + { + var random = new Random(); + for (var i = 0; i < 100; i++) { - var treap2 = new Treap(); - for (var i = 0; i < 100; i++) - { - treap.Add(i); - } - var serializer = new BinaryFormatter(); - using (var stream = new MemoryStream()) - { - serializer.Serialize(stream, treap); - stream.Position = 0; - treap2 = (Treap)serializer.Deserialize(stream); - } - var enum1 = treap.GetEnumerator(); - var enum2 = treap2.GetEnumerator(); + this.treap.Add(random.Next(0, 5000)); + } - for (var i = 0; i < 100; i++) + this.treap.Clear(); + if(this.treap.Count > 0) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ContainsTest() + { + this.treap.Add(50); + this.treap.Add(25); + this.treap.Add(991142); + this.treap.Add(12313); + this.treap.Add(24); + this.treap.Add(23); + if (!this.treap.Contains(24)) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void ToArrayTest() + { + for(var i = 0; i < 1000; i++) + { + this.treap.Add(i); + } + + var arr = this.treap.ToArray(); + for(var i = 0; i < 1000; i++) + { + if(arr[i] != i) { - if (enum1.Current != enum2.Current) - { - Assert.Fail(); - } - enum1.MoveNext(); - enum2.MoveNext(); + Assert.Fail(); } } } + + [TestMethod()] + public void GetEnumeratorTest() + { + for (var i = 0; i < 1000; i++) + { + this.treap.Add(i); + } + + var count = 0; + foreach(var value in this.treap) + { + System.Diagnostics.Debug.WriteLine(value); + count++; + } + + if(count == this.treap.Count) + { + return; + } + + Assert.Fail(); + } + + [TestMethod()] + [Ignore("Binary serialization is obsolete and should not be used anymore")] + public void Serialize() + { + var treap2 = new Treap(); + for (var i = 0; i < 100; i++) + { + this.treap.Add(i); + } + + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, this.treap); + stream.Position = 0; + treap2 = (Treap)serializer.Deserialize(stream); + } + + var enum1 = this.treap.GetEnumerator(); + var enum2 = treap2.GetEnumerator(); + + for (var i = 0; i < 100; i++) + { + if (enum1.Current != enum2.Current) + { + Assert.Fail(); + } + + enum1.MoveNext(); + enum2.MoveNext(); + } + } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Extensions/OptionalTests.cs b/SystemExtensions.Tests/Extensions/OptionalTests.cs index 747dbd6..a2aee02 100644 --- a/SystemExtensions.Tests/Extensions/OptionalTests.cs +++ b/SystemExtensions.Tests/Extensions/OptionalTests.cs @@ -1,111 +1,110 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace System.Extensions.Tests +namespace System.Extensions.Tests; + +[TestClass] +public class OptionalTests { - [TestClass] - public class OptionalTests + [TestMethod] + public void SomeValueShouldEqualOptional() { - [TestMethod] - public void SomeValueShouldEqualOptional() - { - var value = string.Empty; - var optional = value.ToOptional(); + var value = string.Empty; + var optional = value.ToOptional(); - Assert.IsTrue(optional.Equals(value)); - } + Assert.IsTrue(optional.Equals(value)); + } - [TestMethod] - public void OptionalFromNullShouldNotEqual() - { - object value = null; - var optional = value.ToOptional(); + [TestMethod] + public void OptionalFromNullShouldNotEqual() + { + object value = null; + var optional = value.ToOptional(); - Assert.IsFalse(optional.Equals(value)); - } + Assert.IsFalse(optional.Equals(value)); + } - [TestMethod] - public void OptionalFromValueShouldBeSome() - { - var optional = Optional.FromValue(new object()); + [TestMethod] + public void OptionalFromValueShouldBeSome() + { + var optional = Optional.FromValue(new object()); - optional.DoAny( - onNone: () => throw new InvalidOperationException()); - } + optional.DoAny( + onNone: () => throw new InvalidOperationException()); + } - [TestMethod] - public void OptionalFromNullShouldBeNone() - { - var optional = Optional.FromValue(null); + [TestMethod] + public void OptionalFromNullShouldBeNone() + { + var optional = Optional.FromValue(null); - optional.DoAny( - onSome: _ => throw new InvalidOperationException()); - } + optional.DoAny( + onSome: _ => throw new InvalidOperationException()); + } - [TestMethod] - public void DoShouldExecute() - { - var optional = Optional.FromValue(string.Empty); - var nullOptional = Optional.FromValue(null); + [TestMethod] + public void DoShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); - optional.Do( - onSome: _ => { }, - onNone: () => throw new InvalidOperationException()); + optional.Do( + onSome: _ => { }, + onNone: () => throw new InvalidOperationException()); - nullOptional.Do( - onSome: _ => throw new InvalidOperationException(), - onNone: () => { }); - } + nullOptional.Do( + onSome: _ => throw new InvalidOperationException(), + onNone: () => { }); + } - [TestMethod] - public void DoAnyShouldExecute() - { - var optional = Optional.FromValue(string.Empty); - var nullOptional = Optional.FromValue(null); + [TestMethod] + public void DoAnyShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); - optional.DoAny( - onNone: () => throw new InvalidOperationException()); + optional.DoAny( + onNone: () => throw new InvalidOperationException()); - nullOptional.DoAny( - onSome: _ => throw new InvalidOperationException()); - } + nullOptional.DoAny( + onSome: _ => throw new InvalidOperationException()); + } - [TestMethod] - public void SwitchShouldExecute() - { - var optional = Optional.FromValue(string.Empty); - var nullOptional = Optional.FromValue(null); + [TestMethod] + public void SwitchShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); - var newValue = optional.Switch( - onSome: _ => string.Empty, - onNone: () => throw new InvalidOperationException()) - .ExtractValue(); + var newValue = optional.Switch( + onSome: _ => string.Empty, + onNone: () => throw new InvalidOperationException()) + .ExtractValue(); - var newNullValue = nullOptional.Switch( - onSome: _ => throw new InvalidOperationException(), - onNone: () => null) - .ExtractValue(); + var newNullValue = nullOptional.Switch( + onSome: _ => throw new InvalidOperationException(), + onNone: () => null) + .ExtractValue(); - newValue.Should().Be(string.Empty); - newNullValue.Should().Be(null); - } + newValue.Should().Be(string.Empty); + newNullValue.Should().Be(null); + } - [TestMethod] - public void SwitchAnyShouldExecute() - { - var optional = Optional.FromValue(string.Empty); - var nullOptional = Optional.FromValue(null); + [TestMethod] + public void SwitchAnyShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); - var newValue = optional.SwitchAny( - onSome: _ => string.Empty) - .ExtractValue(); + var newValue = optional.SwitchAny( + onSome: _ => string.Empty) + .ExtractValue(); - var newNullValue = nullOptional.SwitchAny( - onNone: () => null) - .ExtractValue(); + var newNullValue = nullOptional.SwitchAny( + onNone: () => null) + .ExtractValue(); - newValue.Should().Be(string.Empty); - newNullValue.Should().Be(null); - } + newValue.Should().Be(string.Empty); + newNullValue.Should().Be(null); } } diff --git a/SystemExtensions.Tests/Extensions/ResultTests.cs b/SystemExtensions.Tests/Extensions/ResultTests.cs index 828aee5..b3d68e7 100644 --- a/SystemExtensions.Tests/Extensions/ResultTests.cs +++ b/SystemExtensions.Tests/Extensions/ResultTests.cs @@ -1,117 +1,116 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace System.Extensions.Tests +namespace System.Extensions.Tests; + +[TestClass] +public class ResultTests { - [TestClass] - public class ResultTests + [TestMethod] + public void SuccessResultShouldCreateFromSuccess() { - [TestMethod] - public void SuccessResultShouldCreateFromSuccess() - { - var success = string.Empty; - var result = Result.Success(success); + var success = string.Empty; + var result = Result.Success(success); - result.DoAny( - onFailure: () => throw new InvalidOperationException()); - } + result.DoAny( + onFailure: () => throw new InvalidOperationException()); + } - [TestMethod] - public void FailureResultShouldCreateFromFailure() - { - var failure = new object(); - var result = Result.Failure(failure); + [TestMethod] + public void FailureResultShouldCreateFromFailure() + { + var failure = new object(); + var result = Result.Failure(failure); - result.DoAny( - onSuccess: () => throw new InvalidOperationException()); - } + result.DoAny( + onSuccess: () => throw new InvalidOperationException()); + } - [TestMethod] - public void DoShouldExecute() - { - var success = string.Empty; - var successResult = Result.Success(success); + [TestMethod] + public void DoShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); - var failure = new object(); - var failedResult = Result.Failure(failure); + var failure = new object(); + var failedResult = Result.Failure(failure); - successResult.Do( - onSuccess: _ => { }, - onFailure: _ => throw new InvalidOperationException()); + successResult.Do( + onSuccess: _ => { }, + onFailure: _ => throw new InvalidOperationException()); - failedResult.Do( - onSuccess: _ => throw new InvalidOperationException(), - onFailure: _ => { }); - } + failedResult.Do( + onSuccess: _ => throw new InvalidOperationException(), + onFailure: _ => { }); + } - [TestMethod] - public void DoAnyShouldExecute() - { - var success = string.Empty; - var successResult = Result.Success(success); + [TestMethod] + public void DoAnyShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); - var failure = new object(); - var failedResult = Result.Failure(failure); + var failure = new object(); + var failedResult = Result.Failure(failure); - successResult.DoAny( - onSuccess: _ => { }); + successResult.DoAny( + onSuccess: _ => { }); - failedResult.DoAny( - onFailure: _ => { }); - } + failedResult.DoAny( + onFailure: _ => { }); + } - [TestMethod] - public void SwitchShouldExecute() - { - var success = string.Empty; - var successResult = Result.Success(success); + [TestMethod] + public void SwitchShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); - var failure = new object(); - var failedResult = Result.Failure(failure); + var failure = new object(); + var failedResult = Result.Failure(failure); - var successSwitch = successResult.Switch( - onSuccess: _ => string.Empty, - onFailure: _ => throw new InvalidOperationException()); + var successSwitch = successResult.Switch( + onSuccess: _ => string.Empty, + onFailure: _ => throw new InvalidOperationException()); - var failedSwitch = failedResult.Switch( - onSuccess: _ => throw new InvalidOperationException(), - onFailure: _ => string.Empty); + var failedSwitch = failedResult.Switch( + onSuccess: _ => throw new InvalidOperationException(), + onFailure: _ => string.Empty); - success.Should().Be(failedSwitch); - } + success.Should().Be(failedSwitch); + } - [TestMethod] - public void SwitchAnyShouldExecute() - { - var success = string.Empty; - var successResult = Result.Success(success); + [TestMethod] + public void SwitchAnyShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); - var failure = new object(); - var failedResult = Result.Failure(failure); + var failure = new object(); + var failedResult = Result.Failure(failure); - var successSwitch = successResult.SwitchAny( - onSuccess: _ => string.Empty); + var successSwitch = successResult.SwitchAny( + onSuccess: _ => string.Empty); - var failedSwitch = failedResult.SwitchAny( - onFailure: _ => string.Empty); + var failedSwitch = failedResult.SwitchAny( + onFailure: _ => string.Empty); - success.Should().Be(failedSwitch); - } + success.Should().Be(failedSwitch); + } - [TestMethod] - public void ToOptionalShouldConvert() - { - var success = string.Empty; - var successResult = Result.Success(success); + [TestMethod] + public void ToOptionalShouldConvert() + { + var success = string.Empty; + var successResult = Result.Success(success); - var failure = new object(); - var failedResult = Result.Failure(failure); + var failure = new object(); + var failedResult = Result.Failure(failure); - var successOptional = successResult.ToOptional(); - var failureOptional = failedResult.ToOptional(); + var successOptional = successResult.ToOptional(); + var failureOptional = failedResult.ToOptional(); - successOptional.Should().NotBeNull(); - failureOptional.Should().NotBeNull(); - } + successOptional.Should().NotBeNull(); + failureOptional.Should().NotBeNull(); } } diff --git a/SystemExtensions.Tests/Http/HttpClientTests.cs b/SystemExtensions.Tests/Http/HttpClientTests.cs index ba25653..09a30a5 100644 --- a/SystemExtensions.Tests/Http/HttpClientTests.cs +++ b/SystemExtensions.Tests/Http/HttpClientTests.cs @@ -5,313 +5,312 @@ using System.Threading; using System.Threading.Tasks; using SystemExtensionsTests.Utils; -namespace System.Net.Http.Tests +namespace System.Net.Http.Tests; + +[TestClass] +public class HttpClientTests { - [TestClass] - public class HttpClientTests + private const string resourceUrl = "resource"; + + private static readonly Uri TestAddressUrl = new("https://helloworld.xyz"); + private readonly MockHttpMessageHandler handler = new(); + private IHttpClient httpClient; + + [TestInitialize] + public void TestInitialize() { - private const string resourceUrl = "resource"; - - private static readonly Uri TestAddressUrl = new("https://helloworld.xyz"); - private readonly MockHttpMessageHandler handler = new(); - private IHttpClient httpClient; - - [TestInitialize] - public void TestInitialize() + this.httpClient = new HttpClient(this.handler, false) { - this.httpClient = new HttpClient(this.handler, false) + BaseAddress = TestAddressUrl + }; + } + + [TestMethod] + public async Task HttpClientEmitsCorrectMessages() + { + var messagesEmitted = 0; + this.httpClient.EventEmitted += (sender, message) => + { + messagesEmitted++; + message.Scope.Should().Be(typeof(object)); + message.Method.Should().Be("GetAsync"); + message.Url.Should().Be(TestAddressUrl.ToString()); + }; + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); + + await this.httpClient.GetAsync(TestAddressUrl); + + messagesEmitted.Should().Be(1); + } + [TestMethod] + public void SetBaseAddress() + { + this.httpClient.BaseAddress = TestAddressUrl; + this.httpClient.BaseAddress.Should().Be(TestAddressUrl); + } + [TestMethod] + public void SetDefaultRequestHeaders() + { + this.httpClient.DefaultRequestHeaders.TryAddWithoutValidation("someheader", "thisvalue"); + this.httpClient.DefaultRequestHeaders.GetValues("someheader").Should().BeEquivalentTo("thisvalue"); + } + [TestMethod] + public void SetMaxResponseContentBufferSize() + { + this.httpClient.MaxResponseContentBufferSize = 2000; + this.httpClient.MaxResponseContentBufferSize.Should().Be(2000); + } + [TestMethod] + public void SetTimeout() + { + this.httpClient.Timeout = TimeSpan.FromSeconds(1); + this.httpClient.Timeout.Should().Be(TimeSpan.FromSeconds(1)); + } + [TestMethod] + public async Task DeleteAsyncStringReturns200() + { + this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK); + + var response = await this.httpClient.DeleteAsync(resourceUrl); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + public async Task DeleteAsyncUriReturns200() + { + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); + + var response = await this.httpClient.DeleteAsync(TestAddressUrl); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] + public async Task DeleteAsyncCanceledThrowsTaskCanceledException() + { + this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); + var cts = new CancellationTokenSource(); + + var responseTask = this.httpClient.DeleteAsync(TestAddressUrl, cts.Token); + cts.Cancel(); + + var awaitAction = new Func>(async () => + { + return await responseTask; + }); + + await awaitAction.Should().ThrowAsync(); + } + [TestMethod] + public async Task GetAsyncStringReturns200() + { + this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK); + + var response = await this.httpClient.GetAsync(resourceUrl); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + public async Task GetAsyncUriReturns200() + { + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); + + var response = await this.httpClient.GetAsync(TestAddressUrl); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] + public async Task GetAsyncCanceledThrowsTaskCanceledException() + { + this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); + var cts = new CancellationTokenSource(); + + var responseTask = this.httpClient.GetAsync(TestAddressUrl, cts.Token); + cts.Cancel(); + + var awaitAction = new Func>(async () => + { + return await responseTask; + }); + + await awaitAction.Should().ThrowAsync(); + } + [TestMethod] + public async Task PostAsyncStringReturns200() + { + this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK); + + var response = await this.httpClient.PostAsync(resourceUrl, null); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + public async Task PostAsyncUriReturns200() + { + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); + + var response = await this.httpClient.PostAsync(TestAddressUrl, null); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] + public async Task PostAsyncCanceledThrowsTaskCanceledException() + { + this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); + var cts = new CancellationTokenSource(); + + var responseTask = this.httpClient.PostAsync(TestAddressUrl, null, cts.Token); + cts.Cancel(); + + var awaitAction = new Func>(async () => + { + return await responseTask; + }); + + await awaitAction.Should().ThrowAsync(); + } + [TestMethod] + public async Task SendAsyncUriReturns200() + { + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); + + var response = await this.httpClient.SendAsync(new HttpRequestMessage { RequestUri = TestAddressUrl }); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + [TestMethod] + [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] + public async Task SendAsyncCanceledThrowsTaskCanceledException() + { + this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); + var cts = new CancellationTokenSource(); + + var responseTask = this.httpClient.SendAsync(new HttpRequestMessage { RequestUri = TestAddressUrl }, cts.Token); + cts.Cancel(); + + var awaitAction = new Func>(async () => + { + return await responseTask; + }); + + await awaitAction.Should().ThrowAsync(); + } + [TestMethod] + public async Task GetStreamAsyncStringReturns200() + { + var ms = new MemoryStream(new byte[] { 13, 10, 11, 12 }); + var sc = new StreamContent(ms); + this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc); + + var response = await this.httpClient.GetStreamAsync(resourceUrl); + + var responseBuffer = new byte[4]; + await response.ReadAsync(responseBuffer, 0, 4); + responseBuffer[0].Should().Be(13); + responseBuffer[1].Should().Be(10); + responseBuffer[2].Should().Be(11); + responseBuffer[3].Should().Be(12); + } + [TestMethod] + public async Task GetStreamAsyncUriReturns200() + { + var ms = new MemoryStream(new byte[] { 13, 10, 11, 12 }); + var sc = new StreamContent(ms); + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc); + + var response = await this.httpClient.GetStreamAsync(TestAddressUrl); + + var responseBuffer = new byte[4]; + await response.ReadAsync(responseBuffer, 0, 4); + responseBuffer[0].Should().Be(13); + responseBuffer[1].Should().Be(10); + responseBuffer[2].Should().Be(11); + responseBuffer[3].Should().Be(12); + } + [TestMethod] + public async Task GetStringAsyncStringReturns200() + { + var sc = new StringContent("hello"); + this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc); + + var response = await this.httpClient.GetStringAsync(resourceUrl); + + response.Should().Be("hello"); + } + [TestMethod] + public async Task GetStringAsyncUriReturns200() + { + var sc = new StringContent("hello"); + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc); + + var response = await this.httpClient.GetStringAsync(TestAddressUrl); + + response.Should().Be("hello"); + } + [TestMethod] + public async Task GetByteArrayAsyncStringReturns200() + { + var sc = new ByteArrayContent(new byte[4] { 13, 10, 11, 12 }); + this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc); + + var response = await this.httpClient.GetByteArrayAsync(resourceUrl); + + response[0].Should().Be(13); + response[1].Should().Be(10); + response[2].Should().Be(11); + response[3].Should().Be(12); + } + [TestMethod] + public async Task GetByteArrayAsyncUriReturns200() + { + var sc = new ByteArrayContent(new byte[4] { 13, 10, 11, 12 }); + this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc); + + var response = await this.httpClient.GetByteArrayAsync(TestAddressUrl); + + response[0].Should().Be(13); + response[1].Should().Be(10); + response[2].Should().Be(11); + response[3].Should().Be(12); + } + [TestMethod] + [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] + public async Task CancelPendingRequestThrowsTaskCanceledException() + { + this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); + + var responseTask = this.httpClient.GetAsync(TestAddressUrl); + this.httpClient.CancelPendingRequests(); + + var awaitAction = new Func>(async () => + { + return await responseTask; + }); + + await awaitAction.Should().ThrowAsync(); + } + + private void SetupResponse(Uri expectedUri, HttpStatusCode statusCode, HttpContent httpContent = null) + { + this.handler.ResponseResolver = (request) => + { + request.RequestUri.Should().Be(expectedUri); + return new HttpResponseMessage { StatusCode = statusCode, Content = httpContent }; + }; + } + private void SetupLongResponse(Uri expectedUri, HttpStatusCode statusCode, HttpContent httpContent = null) + { + this.handler.ResponseResolverAsync = async (request) => + { + request.RequestUri.Should().Be(expectedUri); + for (var i = 0; i < 10; i++) { - BaseAddress = TestAddressUrl - }; - } + await Task.Delay(100); + } - [TestMethod] - public async Task HttpClientEmitsCorrectMessages() - { - var messagesEmitted = 0; - this.httpClient.EventEmitted += (sender, message) => - { - messagesEmitted++; - message.Scope.Should().Be(typeof(object)); - message.Method.Should().Be("GetAsync"); - message.Url.Should().Be(TestAddressUrl.ToString()); - }; - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); - - await this.httpClient.GetAsync(TestAddressUrl); - - messagesEmitted.Should().Be(1); - } - [TestMethod] - public void SetBaseAddress() - { - this.httpClient.BaseAddress = TestAddressUrl; - this.httpClient.BaseAddress.Should().Be(TestAddressUrl); - } - [TestMethod] - public void SetDefaultRequestHeaders() - { - this.httpClient.DefaultRequestHeaders.TryAddWithoutValidation("someheader", "thisvalue"); - this.httpClient.DefaultRequestHeaders.GetValues("someheader").Should().BeEquivalentTo("thisvalue"); - } - [TestMethod] - public void SetMaxResponseContentBufferSize() - { - this.httpClient.MaxResponseContentBufferSize = 2000; - this.httpClient.MaxResponseContentBufferSize.Should().Be(2000); - } - [TestMethod] - public void SetTimeout() - { - this.httpClient.Timeout = TimeSpan.FromSeconds(1); - this.httpClient.Timeout.Should().Be(TimeSpan.FromSeconds(1)); - } - [TestMethod] - public async Task DeleteAsyncStringReturns200() - { - this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK); - - var response = await this.httpClient.DeleteAsync(resourceUrl); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - public async Task DeleteAsyncUriReturns200() - { - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); - - var response = await this.httpClient.DeleteAsync(TestAddressUrl); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] - public async Task DeleteAsyncCanceledThrowsTaskCanceledException() - { - this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); - var cts = new CancellationTokenSource(); - - var responseTask = this.httpClient.DeleteAsync(TestAddressUrl, cts.Token); - cts.Cancel(); - - var awaitAction = new Func>(async () => - { - return await responseTask; - }); - - await awaitAction.Should().ThrowAsync(); - } - [TestMethod] - public async Task GetAsyncStringReturns200() - { - this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK); - - var response = await this.httpClient.GetAsync(resourceUrl); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - public async Task GetAsyncUriReturns200() - { - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); - - var response = await this.httpClient.GetAsync(TestAddressUrl); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] - public async Task GetAsyncCanceledThrowsTaskCanceledException() - { - this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); - var cts = new CancellationTokenSource(); - - var responseTask = this.httpClient.GetAsync(TestAddressUrl, cts.Token); - cts.Cancel(); - - var awaitAction = new Func>(async () => - { - return await responseTask; - }); - - await awaitAction.Should().ThrowAsync(); - } - [TestMethod] - public async Task PostAsyncStringReturns200() - { - this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK); - - var response = await this.httpClient.PostAsync(resourceUrl, null); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - public async Task PostAsyncUriReturns200() - { - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); - - var response = await this.httpClient.PostAsync(TestAddressUrl, null); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] - public async Task PostAsyncCanceledThrowsTaskCanceledException() - { - this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); - var cts = new CancellationTokenSource(); - - var responseTask = this.httpClient.PostAsync(TestAddressUrl, null, cts.Token); - cts.Cancel(); - - var awaitAction = new Func>(async () => - { - return await responseTask; - }); - - await awaitAction.Should().ThrowAsync(); - } - [TestMethod] - public async Task SendAsyncUriReturns200() - { - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK); - - var response = await this.httpClient.SendAsync(new HttpRequestMessage { RequestUri = TestAddressUrl }); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - [TestMethod] - [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] - public async Task SendAsyncCanceledThrowsTaskCanceledException() - { - this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); - var cts = new CancellationTokenSource(); - - var responseTask = this.httpClient.SendAsync(new HttpRequestMessage { RequestUri = TestAddressUrl }, cts.Token); - cts.Cancel(); - - var awaitAction = new Func>(async () => - { - return await responseTask; - }); - - await awaitAction.Should().ThrowAsync(); - } - [TestMethod] - public async Task GetStreamAsyncStringReturns200() - { - var ms = new MemoryStream(new byte[] { 13, 10, 11, 12 }); - var sc = new StreamContent(ms); - this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc); - - var response = await this.httpClient.GetStreamAsync(resourceUrl); - - var responseBuffer = new byte[4]; - await response.ReadAsync(responseBuffer, 0, 4); - responseBuffer[0].Should().Be(13); - responseBuffer[1].Should().Be(10); - responseBuffer[2].Should().Be(11); - responseBuffer[3].Should().Be(12); - } - [TestMethod] - public async Task GetStreamAsyncUriReturns200() - { - var ms = new MemoryStream(new byte[] { 13, 10, 11, 12 }); - var sc = new StreamContent(ms); - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc); - - var response = await this.httpClient.GetStreamAsync(TestAddressUrl); - - var responseBuffer = new byte[4]; - await response.ReadAsync(responseBuffer, 0, 4); - responseBuffer[0].Should().Be(13); - responseBuffer[1].Should().Be(10); - responseBuffer[2].Should().Be(11); - responseBuffer[3].Should().Be(12); - } - [TestMethod] - public async Task GetStringAsyncStringReturns200() - { - var sc = new StringContent("hello"); - this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc); - - var response = await this.httpClient.GetStringAsync(resourceUrl); - - response.Should().Be("hello"); - } - [TestMethod] - public async Task GetStringAsyncUriReturns200() - { - var sc = new StringContent("hello"); - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc); - - var response = await this.httpClient.GetStringAsync(TestAddressUrl); - - response.Should().Be("hello"); - } - [TestMethod] - public async Task GetByteArrayAsyncStringReturns200() - { - var sc = new ByteArrayContent(new byte[4] { 13, 10, 11, 12 }); - this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc); - - var response = await this.httpClient.GetByteArrayAsync(resourceUrl); - - response[0].Should().Be(13); - response[1].Should().Be(10); - response[2].Should().Be(11); - response[3].Should().Be(12); - } - [TestMethod] - public async Task GetByteArrayAsyncUriReturns200() - { - var sc = new ByteArrayContent(new byte[4] { 13, 10, 11, 12 }); - this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc); - - var response = await this.httpClient.GetByteArrayAsync(TestAddressUrl); - - response[0].Should().Be(13); - response[1].Should().Be(10); - response[2].Should().Be(11); - response[3].Should().Be(12); - } - [TestMethod] - [Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")] - public async Task CancelPendingRequestThrowsTaskCanceledException() - { - this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK); - - var responseTask = this.httpClient.GetAsync(TestAddressUrl); - this.httpClient.CancelPendingRequests(); - - var awaitAction = new Func>(async () => - { - return await responseTask; - }); - - await awaitAction.Should().ThrowAsync(); - } - - private void SetupResponse(Uri expectedUri, HttpStatusCode statusCode, HttpContent httpContent = null) - { - this.handler.ResponseResolver = (request) => - { - request.RequestUri.Should().Be(expectedUri); - return new HttpResponseMessage { StatusCode = statusCode, Content = httpContent }; - }; - } - private void SetupLongResponse(Uri expectedUri, HttpStatusCode statusCode, HttpContent httpContent = null) - { - this.handler.ResponseResolverAsync = async (request) => - { - request.RequestUri.Should().Be(expectedUri); - for (var i = 0; i < 10; i++) - { - await Task.Delay(100); - } - - return new HttpResponseMessage { StatusCode = statusCode, Content = httpContent }; - }; - } + return new HttpResponseMessage { StatusCode = statusCode, Content = httpContent }; + }; } } diff --git a/SystemExtensions.Tests/Logging/Models/CachingLogger.cs b/SystemExtensions.Tests/Logging/Models/CachingLogger.cs index 502bbc6..0b20b16 100644 --- a/SystemExtensions.Tests/Logging/Models/CachingLogger.cs +++ b/SystemExtensions.Tests/Logging/Models/CachingLogger.cs @@ -2,26 +2,25 @@ using System; using System.Collections.Generic; -namespace SystemExtensions.NetStandard.Tests.Logging.Models +namespace SystemExtensions.NetStandard.Tests.Logging.Models; + +public sealed class CachingLogger : ILogger { - public sealed class CachingLogger : ILogger + public List LogCache { get; } = new(); + + public IDisposable BeginScope(TState state) { - public List LogCache { get; } = new(); + throw new NotImplementedException(); + } - public IDisposable BeginScope(TState state) - { - throw new NotImplementedException(); - } + public bool IsEnabled(LogLevel logLevel) + { + return true; + } - public bool IsEnabled(LogLevel logLevel) - { - return true; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - var message = formatter(state, exception); - this.LogCache.Add(message); - } + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + var message = formatter(state, exception); + this.LogCache.Add(message); } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Logging/ScopedLoggerTests.cs b/SystemExtensions.Tests/Logging/ScopedLoggerTests.cs index 5eb6d1f..6ba904d 100644 --- a/SystemExtensions.Tests/Logging/ScopedLoggerTests.cs +++ b/SystemExtensions.Tests/Logging/ScopedLoggerTests.cs @@ -4,257 +4,256 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using SystemExtensions.NetStandard.Tests.Logging.Models; -namespace System.Logging.Tests +namespace System.Logging.Tests; + +[TestClass] +public class ScopedLoggerTests { - [TestClass] - public class ScopedLoggerTests + private const string Flow = "Flow"; + private const string Message = "Some message"; + private readonly CachingLogger cachingLogger = new(); + + [TestMethod] + public void CreateLogger_CreatesNewLogger() { - private const string Flow = "Flow"; - private const string Message = "Some message"; - private readonly CachingLogger cachingLogger = new(); + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.CreateLogger_CreatesNewLogger), Flow); + scopedLogger.Should().BeOfType>(); + } - [TestMethod] - public void CreateLogger_CreatesNewLogger() + [TestMethod] + public void CreateLogger_NullScope_ThrowsArgumentNullException() + { + var action = new Action(() => { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.CreateLogger_CreatesNewLogger), Flow); - scopedLogger.Should().BeOfType>(); - } - - [TestMethod] - public void CreateLogger_NullScope_ThrowsArgumentNullException() - { - var action = new Action(() => - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(null, Flow); - }); + var scopedLogger = this.cachingLogger.CreateScopedLogger(null, Flow); + }); - action.Should().Throw(); - } + action.Should().Throw(); + } - [TestMethod] - public void CreateLogger_NullFlow_ReturnsScopedLogger() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.CreateLogger_NullFlow_ReturnsScopedLogger), null); - } + [TestMethod] + public void CreateLogger_NullFlow_ReturnsScopedLogger() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.CreateLogger_NullFlow_ReturnsScopedLogger), null); + } - [TestMethod] - public void LogInformation_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogInformation_LogsExpected)}: {Message}"; + [TestMethod] + public void LogInformation_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogInformation_LogsExpected)}: {Message}"; - scopedLogger.LogInformation(Message); + scopedLogger.LogInformation(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogInformation_EmptyFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), string.Empty); - var expectedMessage = $"{nameof(this.LogInformation_LogsExpected)}: {Message}"; + [TestMethod] + public void LogInformation_EmptyFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), string.Empty); + var expectedMessage = $"{nameof(this.LogInformation_LogsExpected)}: {Message}"; - scopedLogger.LogInformation(Message); + scopedLogger.LogInformation(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogInformation_WhitespaceFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), " "); - var expectedMessage = $"{nameof(this.LogInformation_LogsExpected)}: {Message}"; + [TestMethod] + public void LogInformation_WhitespaceFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), " "); + var expectedMessage = $"{nameof(this.LogInformation_LogsExpected)}: {Message}"; - scopedLogger.LogInformation(Message); + scopedLogger.LogInformation(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogDebug_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogDebug_LogsExpected)}: {Message}"; + [TestMethod] + public void LogDebug_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogDebug_LogsExpected)}: {Message}"; - scopedLogger.LogDebug(Message); + scopedLogger.LogDebug(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogDebug_EmptyFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_EmptyFlow_LogsExpected), string.Empty); - var expectedMessage = $"{nameof(this.LogDebug_EmptyFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogDebug_EmptyFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_EmptyFlow_LogsExpected), string.Empty); + var expectedMessage = $"{nameof(this.LogDebug_EmptyFlow_LogsExpected)}: {Message}"; - scopedLogger.LogDebug(Message); + scopedLogger.LogDebug(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogDebug_WhitespaceFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_WhitespaceFlow_LogsExpected), " "); - var expectedMessage = $"{nameof(this.LogDebug_WhitespaceFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogDebug_WhitespaceFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_WhitespaceFlow_LogsExpected), " "); + var expectedMessage = $"{nameof(this.LogDebug_WhitespaceFlow_LogsExpected)}: {Message}"; - scopedLogger.LogDebug(Message); + scopedLogger.LogDebug(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogWarning_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogWarning_LogsExpected)}: {Message}"; + [TestMethod] + public void LogWarning_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogWarning_LogsExpected)}: {Message}"; - scopedLogger.LogWarning(Message); + scopedLogger.LogWarning(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogWarning_EmptyFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_EmptyFlow_LogsExpected), string.Empty); - var expectedMessage = $"{nameof(this.LogWarning_EmptyFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogWarning_EmptyFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_EmptyFlow_LogsExpected), string.Empty); + var expectedMessage = $"{nameof(this.LogWarning_EmptyFlow_LogsExpected)}: {Message}"; - scopedLogger.LogWarning(Message); + scopedLogger.LogWarning(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogWarning_WhitespaceFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_WhitespaceFlow_LogsExpected), " "); - var expectedMessage = $"{nameof(this.LogWarning_WhitespaceFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogWarning_WhitespaceFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_WhitespaceFlow_LogsExpected), " "); + var expectedMessage = $"{nameof(this.LogWarning_WhitespaceFlow_LogsExpected)}: {Message}"; - scopedLogger.LogWarning(Message); + scopedLogger.LogWarning(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogError_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogError_LogsExpected)}: {Message}"; + [TestMethod] + public void LogError_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogError_LogsExpected)}: {Message}"; - scopedLogger.LogError(Message); + scopedLogger.LogError(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogError_EmptyFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_EmptyFlow_LogsExpected), string.Empty); - var expectedMessage = $"{nameof(this.LogError_EmptyFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogError_EmptyFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_EmptyFlow_LogsExpected), string.Empty); + var expectedMessage = $"{nameof(this.LogError_EmptyFlow_LogsExpected)}: {Message}"; - scopedLogger.LogError(Message); + scopedLogger.LogError(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogError_WhitespaceFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_WhitespaceFlow_LogsExpected), " "); - var expectedMessage = $"{nameof(this.LogError_WhitespaceFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogError_WhitespaceFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_WhitespaceFlow_LogsExpected), " "); + var expectedMessage = $"{nameof(this.LogError_WhitespaceFlow_LogsExpected)}: {Message}"; - scopedLogger.LogError(Message); + scopedLogger.LogError(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogCritical_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogCritical_LogsExpected)}: {Message}"; + [TestMethod] + public void LogCritical_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogCritical_LogsExpected)}: {Message}"; - scopedLogger.LogCritical(Message); + scopedLogger.LogCritical(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogCritical_EmptyFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_EmptyFlow_LogsExpected), string.Empty); - var expectedMessage = $"{nameof(this.LogCritical_EmptyFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogCritical_EmptyFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_EmptyFlow_LogsExpected), string.Empty); + var expectedMessage = $"{nameof(this.LogCritical_EmptyFlow_LogsExpected)}: {Message}"; - scopedLogger.LogCritical(Message); + scopedLogger.LogCritical(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogCritical_WhitespaceFlow_LogsExpected() - { - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_WhitespaceFlow_LogsExpected), " "); - var expectedMessage = $"{nameof(this.LogCritical_WhitespaceFlow_LogsExpected)}: {Message}"; + [TestMethod] + public void LogCritical_WhitespaceFlow_LogsExpected() + { + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_WhitespaceFlow_LogsExpected), " "); + var expectedMessage = $"{nameof(this.LogCritical_WhitespaceFlow_LogsExpected)}: {Message}"; - scopedLogger.LogCritical(Message); + scopedLogger.LogCritical(Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogWarning_WithException_LogsExpected() - { - var exception = new Exception(); - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_WithException_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogWarning_WithException_LogsExpected)}: {Message}"; + [TestMethod] + public void LogWarning_WithException_LogsExpected() + { + var exception = new Exception(); + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_WithException_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogWarning_WithException_LogsExpected)}: {Message}"; - scopedLogger.LogWarning(exception, Message); + scopedLogger.LogWarning(exception, Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogError_WithException_LogsExpected() - { - var exception = new Exception(); - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_WithException_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogError_WithException_LogsExpected)}: {Message}"; + [TestMethod] + public void LogError_WithException_LogsExpected() + { + var exception = new Exception(); + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_WithException_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogError_WithException_LogsExpected)}: {Message}"; - scopedLogger.LogError(exception, Message); + scopedLogger.LogError(exception, Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); + } - [TestMethod] - public void LogCritical_WithException_LogsExpected() - { - var exception = new Exception(); - var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_WithException_LogsExpected), Flow); - var expectedMessage = $"[{Flow}] {nameof(this.LogCritical_WithException_LogsExpected)}: {Message}"; + [TestMethod] + public void LogCritical_WithException_LogsExpected() + { + var exception = new Exception(); + var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_WithException_LogsExpected), Flow); + var expectedMessage = $"[{Flow}] {nameof(this.LogCritical_WithException_LogsExpected)}: {Message}"; - scopedLogger.LogCritical(exception, Message); + scopedLogger.LogCritical(exception, Message); - this.cachingLogger.LogCache.Should().HaveCount(1); - this.cachingLogger.LogCache.First().Should().Be(expectedMessage); - } + this.cachingLogger.LogCache.Should().HaveCount(1); + this.cachingLogger.LogCache.First().Should().Be(expectedMessage); } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Structures/Int32BitStructTests.cs b/SystemExtensions.Tests/Structures/Int32BitStructTests.cs index dcd814a..c0e5754 100644 --- a/SystemExtensions.Tests/Structures/Int32BitStructTests.cs +++ b/SystemExtensions.Tests/Structures/Int32BitStructTests.cs @@ -1,72 +1,71 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace System.Structures.BitStructures.Tests +namespace System.Structures.BitStructures.Tests; + +[TestClass] +public class Int32BitStructTests { - [TestClass] - public class Int32BitStructTests + [DataTestMethod] + [DataRow(-1)] + [DataRow(int.MaxValue)] + public void TestSetValueInt(int value) { - [DataTestMethod] - [DataRow(-1)] - [DataRow(int.MaxValue)] - public void TestSetValueInt(int value) - { - Int32BitStruct int32 = value; - Assert.IsTrue(int32 == value); - } + Int32BitStruct int32 = value; + Assert.IsTrue(int32 == value); + } - [DataTestMethod] - [DataRow(1)] - public void TestSetValueUint(int value) - { - Int32BitStruct int32 = value; - Assert.IsTrue(int32 == value); - } + [DataTestMethod] + [DataRow(1)] + public void TestSetValueUint(int value) + { + Int32BitStruct int32 = value; + Assert.IsTrue(int32 == value); + } - public void TestSetMaxValueUint() - { - Int32BitStruct int32 = uint.MaxValue; - Assert.IsTrue(int32 == uint.MaxValue); - } + public void TestSetMaxValueUint() + { + Int32BitStruct int32 = uint.MaxValue; + Assert.IsTrue(int32 == uint.MaxValue); + } - [DataTestMethod] - [DataRow(0)] - [DataRow(int.MaxValue)] - [DataRow(int.MinValue)] - public void TestGetBit(int value) - { - Int32BitStruct int32 = value; - Assert.IsTrue(value >= 0 ? int32.Bit31 == 0 : int32.Bit31 == 1); - } + [DataTestMethod] + [DataRow(0)] + [DataRow(int.MaxValue)] + [DataRow(int.MinValue)] + public void TestGetBit(int value) + { + Int32BitStruct int32 = value; + Assert.IsTrue(value >= 0 ? int32.Bit31 == 0 : int32.Bit31 == 1); + } - [DataTestMethod] - [DataRow(0)] - [DataRow(1)] - public void TestSetBit(int value) - { - Int32BitStruct int32 = 0; - int32.Bit0 = (uint)value; - Assert.IsTrue(int32 == value); - } + [DataTestMethod] + [DataRow(0)] + [DataRow(1)] + public void TestSetBit(int value) + { + Int32BitStruct int32 = 0; + int32.Bit0 = (uint)value; + Assert.IsTrue(int32 == value); + } - [TestMethod] - public void TestUseCaseExample() - { - // Set value = -1, represented as MSB being 1 and the rest 0. - Int32BitStruct int32 = int.MinValue; + [TestMethod] + public void TestUseCaseExample() + { + // Set value = -1, represented as MSB being 1 and the rest 0. + Int32BitStruct int32 = int.MinValue; - // Test that MSB is 1. - Assert.IsTrue(int32.Bit31 == 1); + // Test that MSB is 1. + Assert.IsTrue(int32.Bit31 == 1); - // Set MSB to 0 and test that everything else is 0. - int32.Bit31 = 0; - Assert.IsTrue(int32 == 0); + // Set MSB to 0 and test that everything else is 0. + int32.Bit31 = 0; + Assert.IsTrue(int32 == 0); - // Set the least 31 significant bits (all besides MSB) to 1. - int32 = int.MaxValue; + // Set the least 31 significant bits (all besides MSB) to 1. + int32 = int.MaxValue; - // Set the MSB to 1 and test that everything is 1. - int32.Bit31 = 1; - Assert.IsTrue(int32 == uint.MaxValue); - } + // Set the MSB to 1 and test that everything is 1. + int32.Bit31 = 1; + Assert.IsTrue(int32 == uint.MaxValue); } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Structures/Int64BitStructTests.cs b/SystemExtensions.Tests/Structures/Int64BitStructTests.cs index 9837459..f8f2956 100644 --- a/SystemExtensions.Tests/Structures/Int64BitStructTests.cs +++ b/SystemExtensions.Tests/Structures/Int64BitStructTests.cs @@ -1,108 +1,107 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace System.Structures.BitStructures.Tests +namespace System.Structures.BitStructures.Tests; + +[TestClass] +public class Int64BitStructTests { - [TestClass] - public class Int64BitStructTests + [DataTestMethod] + [DataRow(-1L)] + [DataRow(long.MaxValue)] + public void TestSetValueInt(long value) { - [DataTestMethod] - [DataRow(-1L)] - [DataRow(long.MaxValue)] - public void TestSetValueInt(long value) + Int64BitStruct int64 = value; + Assert.IsTrue(int64 == value); + } + + [DataTestMethod] + [DataRow(1UL)] + public void TestSetValueUint(ulong value) + { + Int64BitStruct int64 = value; + Assert.IsTrue(int64 == value); + } + + [TestMethod] + public void TestSetMaxValueUint() + { + Int64BitStruct int64 = ulong.MaxValue; + Assert.IsTrue(int64 == ulong.MaxValue); + } + + [DataTestMethod] + [DataRow(0)] + [DataRow(long.MaxValue)] + [DataRow(long.MinValue)] + public void TestGetBit(long value) + { + Int64BitStruct int64 = value; + Assert.IsTrue(value >= 0L ? int64.Bit63 == 0 : int64.Bit63 == 1); + } + + [DataTestMethod] + [DataRow(0)] + [DataRow(1)] + public void TestSetBit(long value) + { + Int64BitStruct int64 = 0L; + int64.Bit0 = (ulong)value; + Assert.IsTrue(int64 == value); + } + + [DataTestMethod] + [DataRow(int.MaxValue, int.MinValue)] + public void TestLowHigh(int low, int high) + { + var int64 = new Int64BitStruct(low, high); + Int32BitStruct lowStruct = low; + Int32BitStruct highStruct = high; + Assert.IsTrue(int64.Low == lowStruct); + Assert.IsTrue(int64.High == highStruct); + unchecked { - Int64BitStruct int64 = value; - Assert.IsTrue(int64 == value); - } - - [DataTestMethod] - [DataRow(1UL)] - public void TestSetValueUint(ulong value) - { - Int64BitStruct int64 = value; - Assert.IsTrue(int64 == value); - } - - [TestMethod] - public void TestSetMaxValueUint() - { - Int64BitStruct int64 = ulong.MaxValue; - Assert.IsTrue(int64 == ulong.MaxValue); - } - - [DataTestMethod] - [DataRow(0)] - [DataRow(long.MaxValue)] - [DataRow(long.MinValue)] - public void TestGetBit(long value) - { - Int64BitStruct int64 = value; - Assert.IsTrue(value >= 0L ? int64.Bit63 == 0 : int64.Bit63 == 1); - } - - [DataTestMethod] - [DataRow(0)] - [DataRow(1)] - public void TestSetBit(long value) - { - Int64BitStruct int64 = 0L; - int64.Bit0 = (ulong)value; - Assert.IsTrue(int64 == value); - } - - [DataTestMethod] - [DataRow(int.MaxValue, int.MinValue)] - public void TestLowHigh(int low, int high) - { - var int64 = new Int64BitStruct(low, high); - Int32BitStruct lowStruct = low; - Int32BitStruct highStruct = high; - Assert.IsTrue(int64.Low == lowStruct); - Assert.IsTrue(int64.High == highStruct); - unchecked - { - Assert.IsTrue(int64 == ((ulong)low + ((ulong)high << 32))); - } - } - - [TestMethod] - public void TestUseCaseExample() - { - // Set value = -1, represented as MSB being 1 and the rest 0. - Int64BitStruct int64 = long.MinValue; - - // Test that MSB is 1. - Assert.IsTrue(int64.Bit63 == 1); - - // Set MSB to 0 and test that everything else is 0. - int64.Bit63 = 0; - Assert.IsTrue(int64 == 0UL); - - // Set the least 31 significant bits (all besides MSB) to 1. - int64 = long.MaxValue; - - // Set the MSB to 1 and test that everything is 1. - int64.Bit63 = 1; - Assert.IsTrue(int64 == ulong.MaxValue); - } - - [TestMethod] - public void TestUseCaseExample2() - { - // Set all bits to 1. Check low and high values to be equal to having all 32 bits set. - Int64BitStruct int64 = ulong.MaxValue; - Assert.IsTrue(int64.Low == uint.MaxValue && int64.High == uint.MaxValue); - - // Set all 63 least significant bits to 1 and MSB to 0. - int64 = long.MaxValue; - Assert.IsTrue(int64.Bit63 == 0); - - // Check that high has all bits besides MSB set to 1 and that low has all bits set to 1. - Assert.IsTrue(int64.High == int.MaxValue && int64.Low == uint.MaxValue); - - // Set the MSB back to 1 and check that all bits are set to 1. - int64.Bit63 = 1; - Assert.IsTrue(int64 == ulong.MaxValue); - Assert.IsTrue(int64.High == uint.MaxValue && int64.Low == uint.MaxValue); + Assert.IsTrue(int64 == ((ulong)low + ((ulong)high << 32))); } } + + [TestMethod] + public void TestUseCaseExample() + { + // Set value = -1, represented as MSB being 1 and the rest 0. + Int64BitStruct int64 = long.MinValue; + + // Test that MSB is 1. + Assert.IsTrue(int64.Bit63 == 1); + + // Set MSB to 0 and test that everything else is 0. + int64.Bit63 = 0; + Assert.IsTrue(int64 == 0UL); + + // Set the least 31 significant bits (all besides MSB) to 1. + int64 = long.MaxValue; + + // Set the MSB to 1 and test that everything is 1. + int64.Bit63 = 1; + Assert.IsTrue(int64 == ulong.MaxValue); + } + + [TestMethod] + public void TestUseCaseExample2() + { + // Set all bits to 1. Check low and high values to be equal to having all 32 bits set. + Int64BitStruct int64 = ulong.MaxValue; + Assert.IsTrue(int64.Low == uint.MaxValue && int64.High == uint.MaxValue); + + // Set all 63 least significant bits to 1 and MSB to 0. + int64 = long.MaxValue; + Assert.IsTrue(int64.Bit63 == 0); + + // Check that high has all bits besides MSB set to 1 and that low has all bits set to 1. + Assert.IsTrue(int64.High == int.MaxValue && int64.Low == uint.MaxValue); + + // Set the MSB back to 1 and check that all bits are set to 1. + int64.Bit63 = 1; + Assert.IsTrue(int64 == ulong.MaxValue); + Assert.IsTrue(int64.High == uint.MaxValue && int64.Low == uint.MaxValue); + } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Threading/PriorityThreadPoolTests.cs b/SystemExtensions.Tests/Threading/PriorityThreadPoolTests.cs index 1950986..11494ec 100644 --- a/SystemExtensions.Tests/Threading/PriorityThreadPoolTests.cs +++ b/SystemExtensions.Tests/Threading/PriorityThreadPoolTests.cs @@ -1,200 +1,208 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using static System.Threading.PriorityThreadPool; -namespace System.Threading.Tests +namespace System.Threading.Tests; + +[TestClass()] +public class PriorityThreadPoolTests { - [TestClass()] - public class PriorityThreadPoolTests + private static PriorityThreadPool threadPool = new PriorityThreadPool(); + private static int lowest = 0, belowAverage = 0, + normal = 0, aboveAverage = 0, highest = 0; + [TestMethod()] + public void PriorityThreadPoolTest() { - private static PriorityThreadPool threadPool = new PriorityThreadPool(); - private static int lowest = 0, belowAverage = 0, - normal = 0, aboveAverage = 0, highest = 0; - [TestMethod()] - public void PriorityThreadPoolTest() + threadPool.Dispose(); + threadPool = new PriorityThreadPool(); + if (threadPool.NumberOfThreads != Environment.ProcessorCount) { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(); - if (threadPool.NumberOfThreads != Environment.ProcessorCount) + Assert.Fail(); + } + } + + [TestMethod()] + public void PriorityThreadPoolTest1() + { + threadPool.Dispose(); + threadPool = new PriorityThreadPool(4); + if (threadPool.NumberOfThreads != 4) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void PriorityThreadPoolTest2() + { + threadPool.Dispose(); + threadPool = new PriorityThreadPool(1, 1, 1, 1, 1); + if (threadPool.NumberOfThreads != 5) + { + Assert.Fail(); + } + } + + [TestMethod()] + public void DisposeTest() + { + threadPool.Dispose(); + Thread.Sleep(100); + try + { + var x = threadPool.NumberOfThreads; + Assert.Fail(); + } + catch (Exception) + { + + } + } + + [TestMethod()] + public void DefaultQueueTest() + { + threadPool.Dispose(); + threadPool = new PriorityThreadPool(); + for (var i = 0; i < 10; i++) + { + threadPool.QueueUserWorkItem(o => { - Assert.Fail(); - } + for (var x = 0; x < 100; x++) + { + System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x); + } + }, null); } - [TestMethod()] - public void PriorityThreadPoolTest1() + for (var i = 0; i < 10; i++) { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(4); - if (threadPool.NumberOfThreads != 4) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void PriorityThreadPoolTest2() - { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(1, 1, 1, 1, 1); - if (threadPool.NumberOfThreads != 5) - { - Assert.Fail(); - } - } - - [TestMethod()] - public void DisposeTest() - { - threadPool.Dispose(); + System.Diagnostics.Debug.WriteLine("====================================="); + System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); + System.Diagnostics.Debug.WriteLine("====================================="); Thread.Sleep(100); - try - { - var x = threadPool.NumberOfThreads; - Assert.Fail(); - } - catch (Exception) - { - - } } - [TestMethod()] - public void DefaultQueueTest() + while (threadPool.NumberOfThreads != System.Environment.ProcessorCount / 4) { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(); - for (var i = 0; i < 10; i++) - { - threadPool.QueueUserWorkItem(o => - { - for (var x = 0; x < 100; x++) - { - System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x); - } - }, null); - } - for (var i = 0; i < 10; i++) - { - System.Diagnostics.Debug.WriteLine("====================================="); - System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); - System.Diagnostics.Debug.WriteLine("====================================="); - Thread.Sleep(100); - } - while (threadPool.NumberOfThreads != System.Environment.ProcessorCount / 4) - { - System.Diagnostics.Debug.WriteLine("====================================="); - System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); - System.Diagnostics.Debug.WriteLine("====================================="); - Thread.Sleep(100); - } + System.Diagnostics.Debug.WriteLine("====================================="); + System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); + System.Diagnostics.Debug.WriteLine("====================================="); + Thread.Sleep(100); + } + } + + [TestMethod()] + public void QueueTestWith4MaxThreads() + { + threadPool.Dispose(); + threadPool = new PriorityThreadPool(4); + if (threadPool.NumberOfThreads != 4) + { + Assert.Fail(); } - [TestMethod()] - public void QueueTestWith4MaxThreads() + for (var i = 0; i < 10; i++) { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(4); - if (threadPool.NumberOfThreads != 4) + threadPool.QueueUserWorkItem(o => { - Assert.Fail(); - } - for (var i = 0; i < 10; i++) - { - threadPool.QueueUserWorkItem(o => + for (var x = 0; x < 100; x++) { - for (var x = 0; x < 100; x++) - { - System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x); - } - }, null); - } - while (threadPool.NumberOfThreads != 1) - { - System.Diagnostics.Debug.WriteLine("====================================="); - System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); - System.Diagnostics.Debug.WriteLine("====================================="); - Thread.Sleep(100); - } - } - - [TestMethod()] - public void QueueTestWith5ManualThreads() - { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(1, 1, 1, 1, 1); - if (threadPool.NumberOfThreads != 5) - { - Assert.Fail(); - } - for (var i = 0; i < 10; i++) - { - threadPool.QueueUserWorkItem(o => - { - for (var x = 0; x < 100; x++) - { - switch (Thread.CurrentThread.Priority) - { - case ThreadPriority.Lowest: - lowest++; - break; - case ThreadPriority.BelowNormal: - belowAverage++; - break; - case ThreadPriority.Normal: - normal++; - break; - case ThreadPriority.AboveNormal: - aboveAverage++; - break; - case ThreadPriority.Highest: - highest++; - break; - } - } - }, null); - } - for (var i = 0; i < 50; i++) - { - System.Diagnostics.Debug.WriteLine("====================================="); - System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); - System.Diagnostics.Debug.WriteLine("====================================="); - Thread.Sleep(100); - } - System.Diagnostics.Debug.WriteLine("\nL: " + lowest + "\nBN: " + belowAverage + "\nN: " + normal + "\nAN:" + aboveAverage + "\nH: " + highest); - } - - [TestMethod()] - public void QueueTestWithDifferentPriorityTasks() - { - threadPool.Dispose(); - threadPool = new PriorityThreadPool(); - for (var i = 0; i < 1000; i++) - { - var taskPriority = TaskPriority.Lowest; - if(i % 10 == 0) - { - taskPriority = TaskPriority.Highest; + System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x); } - else if(i % 5 == 0) - { - taskPriority = TaskPriority.Normal; - } - else if(i % 2 == 0) - { - taskPriority = TaskPriority.BelowNormal; - } - threadPool.QueueUserWorkItem(o => - { - System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + taskPriority); - }, null, taskPriority); - } - while (threadPool.NumberOfThreads != System.Environment.ProcessorCount / 4) + }, null); + } + + while (threadPool.NumberOfThreads != 1) + { + System.Diagnostics.Debug.WriteLine("====================================="); + System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); + System.Diagnostics.Debug.WriteLine("====================================="); + Thread.Sleep(100); + } + } + + [TestMethod()] + public void QueueTestWith5ManualThreads() + { + threadPool.Dispose(); + threadPool = new PriorityThreadPool(1, 1, 1, 1, 1); + if (threadPool.NumberOfThreads != 5) + { + Assert.Fail(); + } + + for (var i = 0; i < 10; i++) + { + threadPool.QueueUserWorkItem(o => { - System.Diagnostics.Debug.WriteLine("====================================="); - System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); - System.Diagnostics.Debug.WriteLine("====================================="); - Thread.Sleep(100); + for (var x = 0; x < 100; x++) + { + switch (Thread.CurrentThread.Priority) + { + case ThreadPriority.Lowest: + lowest++; + break; + case ThreadPriority.BelowNormal: + belowAverage++; + break; + case ThreadPriority.Normal: + normal++; + break; + case ThreadPriority.AboveNormal: + aboveAverage++; + break; + case ThreadPriority.Highest: + highest++; + break; + } + } + }, null); + } + + for (var i = 0; i < 50; i++) + { + System.Diagnostics.Debug.WriteLine("====================================="); + System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); + System.Diagnostics.Debug.WriteLine("====================================="); + Thread.Sleep(100); + } + + System.Diagnostics.Debug.WriteLine("\nL: " + lowest + "\nBN: " + belowAverage + "\nN: " + normal + "\nAN:" + aboveAverage + "\nH: " + highest); + } + + [TestMethod()] + public void QueueTestWithDifferentPriorityTasks() + { + threadPool.Dispose(); + threadPool = new PriorityThreadPool(); + for (var i = 0; i < 1000; i++) + { + var taskPriority = TaskPriority.Lowest; + if(i % 10 == 0) + { + taskPriority = TaskPriority.Highest; } + else if(i % 5 == 0) + { + taskPriority = TaskPriority.Normal; + } + else if(i % 2 == 0) + { + taskPriority = TaskPriority.BelowNormal; + } + + threadPool.QueueUserWorkItem(o => + { + System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + taskPriority); + }, null, taskPriority); + } + + while (threadPool.NumberOfThreads != System.Environment.ProcessorCount / 4) + { + System.Diagnostics.Debug.WriteLine("====================================="); + System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads); + System.Diagnostics.Debug.WriteLine("====================================="); + Thread.Sleep(100); } } } \ No newline at end of file diff --git a/SystemExtensions.Tests/Utils/MockHttpMessageHandler.cs b/SystemExtensions.Tests/Utils/MockHttpMessageHandler.cs index b326e94..3e54e80 100644 --- a/SystemExtensions.Tests/Utils/MockHttpMessageHandler.cs +++ b/SystemExtensions.Tests/Utils/MockHttpMessageHandler.cs @@ -3,27 +3,26 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; -namespace SystemExtensionsTests.Utils +namespace SystemExtensionsTests.Utils; + +public sealed class MockHttpMessageHandler : HttpMessageHandler { - public sealed class MockHttpMessageHandler : HttpMessageHandler + public Func ResponseResolver { get; set; } + public Func> ResponseResolverAsync { get; set; } + + public MockHttpMessageHandler() { - public Func ResponseResolver { get; set; } - public Func> ResponseResolverAsync { get; set; } + } - public MockHttpMessageHandler() + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (this.ResponseResolver is object) { + return Task.FromResult(this.ResponseResolver(request)); } - - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + else { - if (this.ResponseResolver is object) - { - return Task.FromResult(this.ResponseResolver(request)); - } - else - { - return this.ResponseResolverAsync(request); - } + return this.ResponseResolverAsync(request); } } } diff --git a/SystemExtensions.sln b/SystemExtensions.sln index cdddf4d..9419f5c 100644 --- a/SystemExtensions.sln +++ b/SystemExtensions.sln @@ -18,7 +18,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandar EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.Security.Tests", "SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj", "{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemExtensions.NetCore", "SystemExtensions.NetCore\SystemExtensions.NetCore.csproj", "{9E6EBBF0-671B-4941-A72B-2CA60C882038}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetCore", "SystemExtensions.NetCore\SystemExtensions.NetCore.csproj", "{9E6EBBF0-671B-4941-A72B-2CA60C882038}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{BBA334F6-779A-4A45-8BF3-EA321D0D12CF}" EndProject @@ -28,6 +28,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\ci.yaml = .github\workflows\ci.yaml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9E031839-ABF6-4527-9D53-09E2298375A9}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU