Compare commits

..

26 Commits

Author SHA1 Message Date
dependabot[bot] 1fae173b11 Bump System.Security.Cryptography.ProtectedData from 6.0.0 to 7.0.1
Bumps [System.Security.Cryptography.ProtectedData](https://github.com/dotnet/runtime) from 6.0.0 to 7.0.1.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v6.0.0...v7.0.1)

---
updated-dependencies:
- dependency-name: System.Security.Cryptography.ProtectedData
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-15 11:07:14 +00:00
dependabot[bot] a25f2e5acb Bump FluentAssertions from 6.7.0 to 6.9.0 (#41)
Bumps [FluentAssertions](https://github.com/fluentassertions/fluentassertions) from 6.7.0 to 6.9.0.
- [Release notes](https://github.com/fluentassertions/fluentassertions/releases)
- [Changelog](https://github.com/fluentassertions/fluentassertions/blob/develop/AcceptApiChanges.ps1)
- [Commits](https://github.com/fluentassertions/fluentassertions/compare/6.7.0...6.9.0)

---
updated-dependencies:
- dependency-name: FluentAssertions
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-25 21:37:09 +01:00
dependabot[bot] 8e64309c2e Bump actions/setup-dotnet from 2 to 3 (#32)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 2 to 3.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-11 12:16:48 +02:00
dependabot[bot] 24c3e37b5e Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2 (#31)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.1 to 17.3.2.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.3.1...v17.3.2)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-27 11:44:21 +02:00
amacocian f6435b24ab Increment dependency injection version (#29) 2022-09-12 19:28:10 +02:00
amacocian 9118c864bf Make httpclient use a factory to create handlers (#28) 2022-09-12 17:22:55 +00:00
amacocian fb84036215 Bump slim to 1.9.2 (#27)
Signed-off-by: Macocian Alexandru Victor <amacocian@yahoo.com>

Signed-off-by: Macocian Alexandru Victor <amacocian@yahoo.com>
2022-09-12 09:59:05 +00:00
amacocian f6fd9ec616 Update Slim (#26) 2022-09-09 15:05:48 +00:00
dependabot[bot] 6a10fe91e3 Bump actions/checkout from 2 to 3 (#22)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-06 14:20:27 +00:00
dependabot[bot] e890b21bb6 Bump actions/setup-dotnet from 1 to 2 (#21)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 1 to 2.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-06 14:12:59 +00:00
dependabot[bot] e36e6605ff Bump Microsoft.NET.Test.Sdk from 17.2.0 to 17.3.1 (#23)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.2.0 to 17.3.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.2.0...v17.3.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-06 16:06:51 +02:00
dependabot[bot] 5e8e772d36 Bump Moq from 4.18.1 to 4.18.2 (#24)
Bumps [Moq](https://github.com/moq/moq4) from 4.18.1 to 4.18.2.
- [Release notes](https://github.com/moq/moq4/releases)
- [Changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md)
- [Commits](https://github.com/moq/moq4/compare/v4.18.1...v4.18.2)

---
updated-dependencies:
- dependency-name: Moq
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-06 15:58:34 +02:00
amacocian e6a06915cd Improve IHttpClient factories (#20)
Codestyle fixes
Setup CODEOWNERS
Setup dependabot
2022-09-06 15:49:07 +02:00
amacocian 3c741ab969 Make AesEncrypter disposable (#19) 2022-06-07 12:49:39 +02:00
amacocian a46fde652d Expose Aes object in AesEncrypter constructor (#18) 2022-06-07 12:26:08 +02:00
amacocian ecc65a4302 Update dependencies for NetStandard.DependencyInjection (#17) 2022-06-02 11:35:08 +02:00
amacocian 7222528eed Update dependencies (#16)
* Update dependencies
Implement AsyncLazy
Fix namespaces
Fix CD pipeline

* Fix code issues
Fix Int64BitStruct test
2022-06-02 10:42:34 +02:00
amacocian 41b1b48f98 Remove null check for flow id in scoped loggers (#15) 2022-01-23 21:13:37 +01:00
amacocian 721b444dda Scoped logger (#14)
Logging extensions
2022-01-16 15:14:23 +01:00
amacocian 1c7d3a2be2 Adjust project descriptions (#12)
* Adjust package description
2022-01-02 16:54:15 +02:00
amacocian 0a30872781 Introduce .netcore extensions (#11)
* Introduce .netcore extensions
Implement ArgumentNullException for .net6 and c#10

* Update pipelines to install .netcore 6

* Update test projects to .net 6.0
2022-01-02 00:10:49 +02:00
Alexandru Macocian 7eed1ca466 Unify namespace naming 2021-11-15 22:21:46 +01:00
Alexandru Macocian b6cc64fd51 Update dependencies 2021-11-15 22:08:24 +01:00
Alexandru Macocian c8bfaffb42 Fix namespaces 2021-11-15 22:04:18 +01:00
Alexandru Macocian bf163251dd Password hashing implementation 2021-11-15 21:52:39 +01:00
Alexandru Macocian c0b5734b71 Add extensions to simplify CVLoggerFactory usage 2021-11-01 16:18:10 +01:00
110 changed files with 8524 additions and 6976 deletions
+129
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
* amacocian@yahoo.com
+16
View File
@@ -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"
+19 -18
View File
@@ -21,18 +21,19 @@ jobs:
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
Core_Project_Path: SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
Actions_Allow_Unsecure_Commands: true
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v3
with:
dotnet-version: '5.0.202'
dotnet-version: '6.0.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -45,26 +46,26 @@ jobs:
- name: Build SystemExtensions.NetStandard project
run: dotnet build SystemExtensions.NetStandard -c $env:Configuration
- name: Build SystemExtensions.NetCore project
run: dotnet build SystemExtensions.NetCore -c $env:Configuration
- name: Build SystemExtensions.NetStandard.DependencyInjection project
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
- name: Build SystemExtensions.NetStandard.Security project
run: dotnet build SystemExtensions.NetStandard.Security -c $env:Configuration
- name: Push SystemExtensions.NetStandard nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Package SystemExtensions.NetStandard
run: dotnet pack -c Release -o . SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
- name: Push SystemExtensions.NetStandard.DependencyInjection nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Package SystemExtensions.NetCore
run: dotnet pack -c Release -o . SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
- name: Push SystemExtensions.NetStandard.Security nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Package SystemExtensions.NetStandard.DependencyInjection
run: dotnet pack -c Release -o . SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
- name: Package SystemExtensions.NetStandard.Security
run: dotnet pack -c Release -o . SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj
- name: Publish
run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
+3 -3
View File
@@ -28,14 +28,14 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v3
with:
dotnet-version: '5.0.202'
dotnet-version: '6.0.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -2,11 +2,11 @@
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]
@@ -22,5 +22,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
{
this.optionsManager.UpdateOptions(string.Empty);
}
}
}
@@ -1,6 +1,5 @@
namespace SystemExtensions.DependencyInjection.Tests.Configuration
namespace SystemExtensions.DependencyInjection.Tests.Configuration;
public sealed class DummyOptions
{
public sealed class DummyOptions
{
}
}
@@ -4,11 +4,11 @@ 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<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
@@ -65,5 +65,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
}
}
}
@@ -4,11 +4,11 @@ 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<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
@@ -65,5 +65,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
}
}
}
@@ -3,11 +3,11 @@ 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<string> optionsWrapper;
private readonly Mock<IOptionsManager> optionsManagerMock = new();
@@ -40,5 +40,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
this.optionsManagerMock.Verify();
}
}
}
@@ -5,16 +5,15 @@ 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<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
public Mock<IOptionsManager> OptionsManagerMock => optionsManagerMock;
public Mock<IOptionsManager> OptionsManagerMock { get; } = new();
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
@@ -68,5 +67,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.OptionsManagerMock.Object);
}
}
}
@@ -4,11 +4,11 @@ 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<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
@@ -65,5 +65,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
}
}
}
@@ -5,11 +5,11 @@ 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<string> optionsWrapper;
@@ -18,7 +18,7 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
[TestInitialize]
public void TestInitialize()
{
this.optionsWrapper = new UpdateableOptionsWrapper<string>(optionsManagerMock.Object, Value);
this.optionsWrapper = new UpdateableOptionsWrapper<string>(this.optionsManagerMock.Object, Value);
}
[TestMethod]
@@ -44,5 +44,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Configuration
this.optionsManagerMock.Verify();
}
}
}
@@ -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<object> httpClientBuilder;
private readonly Mock<IServiceProducer> serviceProducerMock = new();
private readonly Uri baseAddress = new("http://contoso.co");
public HttpClientBuilderTests()
{
this.httpClientBuilder = new HttpClientBuilder<object>(this.serviceProducerMock.Object);
}
[TestMethod]
public void Constructor_NullServiceProducer_Throws()
{
var action = () => new HttpClientBuilder<object>(null);
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void WithMessageHandler_NullHandler_Throws()
{
var action = () => this.httpClientBuilder.WithMessageHandler(null);
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void WithBaseAddress_NullBaseAddress_Throws()
{
var action = () => this.httpClientBuilder.WithBaseAddress(null);
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void WithDefaultRequestHeadersSetup_NullSetup_Throws()
{
var action = () => this.httpClientBuilder.WithDefaultRequestHeadersSetup(null);
action.Should().Throw<ArgumentNullException>();
}
[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<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false));
this.httpClientBuilder.Build();
this.serviceProducerMock.Verify();
}
[TestMethod]
public void Build_CreatesExpectedClient()
{
this.serviceProducerMock.Setup(u => u.RegisterScoped(It.IsAny<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false))
.Callback<Func<Slim.IServiceProvider, IHttpClient<object>>, bool>((factory, _) =>
{
var client = factory(new Mock<Slim.IServiceProvider>().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<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false))
.Callback<Func<Slim.IServiceProvider, IHttpClient<object>>, bool>((factory, _) =>
{
var client = factory(new Mock<Slim.IServiceProvider>().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<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false))
.Callback<Func<Slim.IServiceProvider, IHttpClient<object>>, bool>((factory, _) =>
{
var client = factory(new Mock<Slim.IServiceProvider>().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<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false))
.Callback<Func<Slim.IServiceProvider, IHttpClient<object>>, bool>((factory, _) =>
{
var client = factory(new Mock<Slim.IServiceProvider>().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<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false))
.Callback<Func<Slim.IServiceProvider, IHttpClient<object>>, bool>((factory, _) =>
{
var client = factory(new Mock<Slim.IServiceProvider>().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<Func<Slim.IServiceProvider, IHttpClient<object>>>(), false))
.Callback<Func<Slim.IServiceProvider, IHttpClient<object>>, bool>(async (factory, _) =>
{
var client = factory(new Mock<Slim.IServiceProvider>().Object);
await client.GetAsync(this.baseAddress);
handlerMock.Called.Should().BeTrue();
});
this.httpClientBuilder.WithMessageHandler(sp => handlerMock)
.Build();
}
[TestMethod]
public async Task HttpClientBuilder_RegistersClientCorrectly_IServiceProviderReturnsExpected()
{
var container = new ServiceManager();
var messageHandler = new HttpMessageHandlerMock();
new HttpClientBuilder<object>(container)
.WithBaseAddress(this.baseAddress)
.WithDefaultRequestHeadersSetup(header => header.TryAddWithoutValidation(SomeHeader, SomeValue))
.WithMaxResponseBufferSize(5)
.WithMessageHandler(sp => messageHandler)
.WithTimeout(TimeSpan.FromSeconds(5))
.Build();
var client = container.GetService<IHttpClient<object>>();
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();
}
}
@@ -5,11 +5,11 @@ 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<Slim.IServiceProvider> serviceProviderMock = new();
@@ -65,5 +65,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Http
action.Should().Throw<Exception>();
}
}
}
@@ -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<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
this.Called = true;
return Task.FromResult(new HttpResponseMessage());
}
}
@@ -3,11 +3,11 @@ 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<ILogsWriter> logsWriterMock = new();
private CVLoggerProvider cVLoggerProvider;
@@ -39,5 +39,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Logging
.Setup(u => u.WriteLog(It.IsAny<Log>()))
.Verifiable();
}
}
}
@@ -5,11 +5,11 @@ 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<ICVLoggerProvider> cvLoggerProviderMock = new();
private CVLogger cVLogger;
@@ -72,5 +72,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Logging
.Setup(u => u.LogEntry(It.IsAny<Log>()))
.Verifiable();
}
}
}
@@ -3,11 +3,11 @@ 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]
@@ -26,5 +26,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Logging
action.Should().Throw<Exception>();
}
}
}
@@ -5,11 +5,11 @@ 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<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<ILoggerFactory> loggerFactoryMock = new();
private readonly Mock<ILogger> loggerMock = new();
@@ -104,5 +104,4 @@ namespace SystemExtensions.DependencyInjection.Tests.Logging
.Setup(u => u.CreateLogger(It.IsAny<string>()))
.Returns(this.loggerMock.Object);
}
}
}
@@ -1,18 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
<PackageReference Include="coverlet.collector" Version="3.0.2" />
<PackageReference Include="FluentAssertions" Version="6.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
@@ -0,0 +1,22 @@
using System.Runtime.CompilerServices;
namespace System.Core.Extensions;
public static class ObjectExtensions
{
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, [CallerArgumentExpression("obj")] string? paramName = null)
where T : class
{
if (obj is null)
{
throw new ArgumentNullException(paramName);
}
return obj;
}
[AttributeUsage(AttributeTargets.Parameter)]
sealed class ValidatedNotNullAttribute : Attribute
{
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Nullable>enable</Nullable>
<RootNamespace>System</RootNamespace>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Version>1.0.1</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the System namespace</Description>
</PropertyGroup>
<ItemGroup>
<None Include="../LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>
@@ -1,7 +1,7 @@
namespace System.Configuration
namespace System.Configuration;
public sealed class DefaultOptionsManager : IOptionsManager
{
public sealed class DefaultOptionsManager : IOptionsManager
{
public T GetOptions<T>() where T : class
{
return default;
@@ -10,5 +10,4 @@
public void UpdateOptions<T>(T value) where T : class
{
}
}
}
@@ -1,9 +1,8 @@
using Microsoft.Extensions.Options;
namespace System.Configuration
{
public interface ILiveOptions<T> : IOptions<T>
namespace System.Configuration;
public interface ILiveOptions<T> : IOptions<T>
where T : class
{
}
{
}
@@ -1,7 +1,6 @@
namespace System.Configuration
{
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
namespace System.Configuration;
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
where T : class
{
}
{
}
@@ -1,10 +1,9 @@
namespace System.Configuration
namespace System.Configuration;
public interface IOptionsManager
{
public interface IOptionsManager
{
T GetOptions<T>()
where T : class;
void UpdateOptions<T>(T value)
where T : class;
}
}
@@ -1,13 +1,12 @@
using Microsoft.Extensions.Options;
namespace System.Configuration
{
public interface IUpdateableOptions<out T> : IOptions<T>
namespace System.Configuration;
public interface IUpdateableOptions<out T> : IOptions<T>
where T : class
{
{
/// <summary>
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
/// </summary>
void UpdateOption();
}
}
@@ -1,9 +1,9 @@
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)
@@ -23,5 +23,4 @@ namespace System.Configuration
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
}
}
@@ -1,9 +1,9 @@
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)
@@ -22,5 +22,4 @@ namespace System.Configuration
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
}
}
@@ -1,10 +1,10 @@
using System.Extensions;
namespace System.Configuration
{
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
namespace System.Configuration;
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
where T : class
{
{
private readonly IOptionsManager configurationManager;
private T value;
@@ -27,5 +27,4 @@ namespace System.Configuration
{
this.configurationManager.UpdateOptions<T>(this.value);
}
}
}
@@ -1,10 +1,10 @@
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);
@@ -29,5 +29,4 @@ namespace System.Configuration
return Activator.CreateInstance(typedOptionsType, optionsValue);
}
}
}
@@ -1,10 +1,10 @@
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);
@@ -29,5 +29,4 @@ namespace System.Configuration
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
}
}
}
@@ -1,10 +1,10 @@
using System.Configuration;
namespace System.Extensions.Configuration
{
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
namespace System.Extensions.Configuration;
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
where T : class
{
{
private readonly IOptionsManager configurationManager;
public T Value { get; }
@@ -19,5 +19,4 @@ namespace System.Extensions.Configuration
{
this.configurationManager.UpdateOptions(this.Value);
}
}
}
@@ -2,26 +2,29 @@
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
{
/// <summary>
/// Registers a <see cref="IOptionsManager"/> with the default <see cref="DefaultOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager)
public static IServiceProducer RegisterOptionsManager(this IServiceProducer serviceProducer)
{
serviceManager.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
serviceManager.RegisterOptionsResolver();
serviceProducer.ThrowIfNull(nameof(serviceProducer));
return serviceManager;
serviceProducer.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
serviceProducer.RegisterOptionsResolver();
return serviceProducer;
}
/// <summary>
@@ -31,13 +34,15 @@ namespace System.Extensions
/// <typeparam name="T">Implementation of <see cref="IOptionsManager"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsManager<T>(this IServiceManager serviceManager)
public static IServiceProducer RegisterOptionsManager<T>(this IServiceProducer serviceProducer)
where T : IOptionsManager
{
serviceManager.RegisterSingleton<IOptionsManager, T>();
serviceManager.RegisterOptionsResolver();
serviceProducer.ThrowIfNull(nameof(serviceProducer));
return serviceManager;
serviceProducer.RegisterSingleton<IOptionsManager, T>();
serviceProducer.RegisterOptionsResolver();
return serviceProducer;
}
/// <summary>
@@ -46,16 +51,16 @@ namespace System.Extensions
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns><see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsResolver(this IServiceManager serviceManager)
public static IServiceProducer RegisterOptionsResolver(this IServiceProducer serviceProducer)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterResolver(new OptionsResolver());
serviceManager.RegisterResolver(new UpdateableOptionsResolver());
serviceManager.RegisterResolver(new LiveOptionsResolver());
serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver());
serviceProducer.RegisterResolver(new OptionsResolver());
serviceProducer.RegisterResolver(new UpdateableOptionsResolver());
serviceProducer.RegisterResolver(new LiveOptionsResolver());
serviceProducer.RegisterResolver(new LiveUpdateableOptionsResolver());
return serviceManager;
return serviceProducer;
}
/// <summary>
@@ -104,38 +109,81 @@ namespace System.Extensions
return serviceManager;
}
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
/// <summary>
/// Register a <see cref="ILoggerFactory"/> with a <see cref="CVLoggerProvider"/>.
/// </summary>
/// <param name="serviceProducer"></param>
/// <returns></returns>
public static IServiceProducer RegisterCVLoggerFactory(this IServiceProducer serviceProducer)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceManager;
serviceProducer.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
LoggerFactory loggerFactory = new();
loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return loggerFactory;
});
return serviceProducer;
}
public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager)
/// <summary>
/// Registers a <see cref="ILoggerFactory"/>.
/// </summary>
/// <param name="serviceProducer"><see cref="IServiceProducer"/>.</param>
/// <param name="loggerFactory">Factory that produces a <see cref="ILoggerFactory"/>.</param>
/// <returns></returns>
public static IServiceProducer RegisterLoggerFactory(this IServiceProducer serviceProducer, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceManager;
serviceProducer.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceProducer;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager)
/// <summary>
/// Registers a <see cref="ILoggerFactory"/> with a <see cref="ILogsWriter"/> that writes to <see cref="Diagnostics.Debug"/>.
/// </summary>
/// <param name="serviceProducer"><see cref="IServiceProducer"/>.</param>
/// <returns></returns>
public static IServiceProducer RegisterDebugLoggerFactory(this IServiceProducer serviceProducer)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterResolver(new HttpClientResolver());
return serviceManager;
serviceProducer.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceProducer;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
/// <summary>
/// Register a scoped <see cref="IHttpClient{TScope}"/> to be used by the DI engine.
/// </summary>
/// <typeparam name="T">Type of the scoped <see cref="IHttpClient{TScope}"/>.</typeparam>
/// <param name="serviceProducer"><see cref="IServiceProducer"/>.</param>
/// <returns><see cref="HttpClientBuilder{T}"/> to build the http client.</returns>
public static HttpClientBuilder<T> RegisterHttpClient<T>(this IServiceProducer serviceProducer)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterResolver(
return new HttpClientBuilder<T>(serviceProducer);
}
[Obsolete($"{nameof(RegisterHttpFactory)} is obsolete. Please use {nameof(RegisterHttpClient)} for each service that requires an instance of {nameof(IHttpClient<object>)}.")]
public static IServiceProducer RegisterHttpFactory(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
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<object>)}.")]
public static IServiceProducer RegisterHttpFactory(this IServiceProducer serviceProducer, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory(handlerFactory));
return serviceManager;
}
return serviceProducer;
}
}
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("SystemExtensions.NetStandard.DependencyInjection.Tests")]
@@ -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<T>
{
private readonly IServiceProducer serviceProducer;
private Uri baseAddress;
private Func<IServiceProvider, HttpMessageHandler> httpMessageHandlerFactory;
private bool disposeMessageHandler;
private Action<HttpRequestHeaders> 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<T> WithMessageHandler(Func<IServiceProvider, HttpMessageHandler> httpMessageHandlerFactory)
{
httpMessageHandlerFactory.ThrowIfNull(nameof(httpMessageHandlerFactory));
this.httpMessageHandlerFactory = httpMessageHandlerFactory;
return this;
}
public HttpClientBuilder<T> WithDisposeMessageHandler(bool disposeMessageHandler)
{
this.disposeMessageHandler = disposeMessageHandler;
return this;
}
public HttpClientBuilder<T> WithBaseAddress(Uri baseAddress)
{
baseAddress.ThrowIfNull(nameof(baseAddress));
this.baseAddress = baseAddress;
return this;
}
public HttpClientBuilder<T> WithDefaultRequestHeadersSetup(Action<HttpRequestHeaders> setup)
{
setup.ThrowIfNull(nameof(setup));
this.defaultRequestHeadersSetup = setup;
return this;
}
public HttpClientBuilder<T> WithMaxResponseBufferSize(long responseBufferSize)
{
this.maxResponseBufferSize = responseBufferSize;
return this;
}
public HttpClientBuilder<T> WithTimeout(TimeSpan timeout)
{
this.timeout = timeout;
return this;
}
public IServiceProducer Build()
{
this.serviceProducer.RegisterScoped<IHttpClient<T>>(sp =>
{
var client = this.httpMessageHandlerFactory is not null ?
new HttpClient<T>(this.httpMessageHandlerFactory(sp), this.disposeMessageHandler) :
new HttpClient<T>();
client.BaseAddress = this.baseAddress;
this.defaultRequestHeadersSetup?.Invoke(client.DefaultRequestHeaders);
client.MaxResponseContentBufferSize = this.maxResponseBufferSize;
client.Timeout = this.timeout;
return client;
});
return this.serviceProducer;
}
}
@@ -2,10 +2,11 @@
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<object>)}")]
public sealed class HttpClientResolver : IDependencyResolver
{
public sealed class HttpClientResolver : IDependencyResolver
{
private static readonly Type clientType = typeof(HttpClient<>);
/// <summary>
@@ -43,5 +44,4 @@ namespace System.Http
Activator.CreateInstance(typedClientType, new object[] { handler });
return httpClient;
}
}
}
@@ -1,10 +1,10 @@
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;
@@ -40,5 +40,4 @@ namespace System.Logging
this.cvLoggerProvider.LogEntry(log);
}
}
}
@@ -2,10 +2,10 @@
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;
@@ -35,5 +35,4 @@ namespace System.Logging
{
throw new System.NotImplementedException();
}
}
}
@@ -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)
{
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
}
}
}
@@ -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);
}
}
@@ -1,7 +1,6 @@
namespace System.Logging
namespace System.Logging;
public interface ILogsWriter
{
public interface ILogsWriter
{
void WriteLog(Log log);
}
}
@@ -2,10 +2,10 @@
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)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
@@ -46,5 +46,4 @@ namespace System.Logging
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
}
}
}
@@ -1,9 +1,9 @@
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; }
@@ -11,5 +11,4 @@ namespace System.Logging
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public string CorrelationVector { get; set; }
}
}
@@ -0,0 +1,8 @@
using System.Net.Http;
namespace System.DependencyInjection.Models;
internal sealed class TypedHttpClientFactory<T>
{
public Func<Slim.IServiceProvider, HttpMessageHandler> Factory { get; set; }
}
@@ -6,9 +6,10 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<LangVersion>latest</LangVersion>
<Version>1.1.4</Version>
<Version>1.2.3</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the Slim Dependency Injection engine</Description>
</PropertyGroup>
<ItemGroup>
@@ -20,9 +21,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Slim" Version="1.5.4" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Slim" Version="1.9.2" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
</ItemGroup>
</Project>
@@ -3,15 +3,15 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Encryption;
using System.Text;
using System.Threading.Tasks;
using SystemExtensions.NetStandard.Security.Encryption;
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;
@@ -101,5 +101,4 @@ namespace SystemExtensions.NetStandard.Security.Tests
var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
encryptionStream.Should().BeAssignableTo<CryptoStream>();
}
}
}
@@ -1,13 +1,13 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Rng;
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]
@@ -51,5 +51,4 @@ namespace SystemExtensions.NetStandard.Security.Tests
bytes.Length.Should().Be(10);
}
}
}
@@ -0,0 +1,260 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Security.Hashing;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Tests;
[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()
{
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);
}
[TestMethod]
public void PasswordNull_HashBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltBytes, DesiredHashLength, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void PasswordNull_HashString_Throws_ArgumentNullException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltString, DesiredHashLength, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_HashBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, null, DesiredHashLength, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_HashString_Throws_ArgumentNullException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, null, DesiredHashLength, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void HashLengthTooSmall_HashBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, TooShortHashLength, Iterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void HashLengthTooSmall_HashString_Throws_InvalidOperationException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, TooShortHashLength, Iterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void TooLittleIterations_HashBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, TooLittleIterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void TooLittleIterations_HashString_Throws_InvalidOperationException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, TooLittleIterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void TooShortSalt_HashBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.tooShortSaltBytes, DesiredHashLength, TooLittleIterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void TooShortSalt_HashString_Throws_InvalidOperationException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.tooShortSaltString, DesiredHashLength, TooLittleIterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void PasswordNull_VerifyBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordBytes, this.saltBytes, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void PasswordNull_VerifyString_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordString, this.saltString, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void HashNull_VerifyBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, null, this.saltBytes, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void HashNull_VerifyString_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, null, this.saltString, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_VerifyBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, null, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_VerifyString_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, null, Iterations));
action.Should().ThrowAsync<ArgumentNullException>();
}
[TestMethod]
public void TooLittleIterations_VerifyBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, this.saltBytes, TooLittleIterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public void TooLittleIterations_VerifyString_Throws_InvalidOperationException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, this.saltString, TooLittleIterations));
action.Should().ThrowAsync<InvalidOperationException>();
}
[TestMethod]
public async Task HashBytes_ReturnsHashedBytes()
{
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, 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);
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(hashedBytes, this.passwordBytes, this.saltBytes, 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(hashedString, this.passwordString, this.saltString, 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(hashedBytes, this.incorrectPasswordBytes, this.saltBytes, 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(hashedString, this.incorrectPasswordString, this.saltString, 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(hashedBytes, this.passwordBytes, this.incorrectSaltBytes, 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(hashedString, this.passwordString, this.incorrectSaltString, 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(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();
}
}
@@ -1,13 +1,12 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Encryption;
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()
{
@@ -119,5 +118,4 @@ namespace SystemExtensions.NetStandard.Security.Tests
ss1.Should().Be(ss2);
}
}
}
@@ -2,15 +2,15 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Security.Hashing;
using System.Text;
using System.Threading.Tasks;
using SystemExtensions.NetStandard.Security.Hashing;
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;
@@ -44,5 +44,4 @@ namespace SystemExtensions.NetStandard.Security.Tests
var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false);
hash.Should().BeAssignableTo<Stream>();
}
}
}
@@ -1,17 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
<PackageReference Include="coverlet.collector" Version="3.0.2" />
<PackageReference Include="FluentAssertions" Version="6.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
@@ -1,77 +1,88 @@
using System;
using System.IO;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using SystemExtensions.NetStandard.Security.Utilities;
using System.Security.Utilities;
namespace SystemExtensions.NetStandard.Security.Encryption
namespace System.Security.Encryption;
public sealed class AesEncrypter : ISymmetricEncrypter, IDisposable
{
public sealed class AesEncrypter : ISymmetricEncrypter
private readonly Aes aes;
public AesEncrypter()
{
this.aes = Aes.Create();
}
public AesEncrypter(Aes aes)
{
this.aes = aes;
}
public async Task<string> Decrypt(string key, string iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
using var decryptedStream = await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToString(decryptedStream);
}
public async Task<string> Decrypt(byte[] key, byte[] iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
using var decryptedStream = await this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToString(decryptedStream);
}
public async Task<byte[]> Decrypt(string key, string iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
using var decryptedStream = await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToBytes(decryptedStream);
}
public async Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
using var decryptedStream = await this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToBytes(decryptedStream);
}
public async Task<Stream> Decrypt(string key, string iv, Stream value)
{
return await DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
return await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
}
public async Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value)
{
return await DecryptInternal(key, iv, value).ConfigureAwait(false);
return await this.DecryptInternal(key, iv, value).ConfigureAwait(false);
}
public async Task<string> 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);
using var encryptedStream = await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToString(encryptedStream);
}
public async Task<string> Encrypt(byte[] key, byte[] iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
using var encryptedStream = await this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToString(encryptedStream);
}
public async Task<byte[]> Encrypt(string key, string iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
using var encryptedStream = await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToBytes(encryptedStream);
}
public async Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
using var encryptedStream = await this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToBytes(encryptedStream);
}
@@ -79,34 +90,104 @@ namespace SystemExtensions.NetStandard.Security.Encryption
{
return value is null
? throw new ArgumentNullException(nameof(value))
: await EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
: await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
}
public async Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value)
{
return value is null
? throw new ArgumentNullException(nameof(value))
: await EncryptInternal(key, iv, value).ConfigureAwait(false);
: await this.EncryptInternal(key, iv, value).ConfigureAwait(false);
}
public Stream GetEncryptionStream(string key, string iv, Stream outStream)
{
return GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
return this.GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
}
public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream)
{
return GetEncryptionStreamInternal(key, iv, outStream);
return this.GetEncryptionStreamInternal(key, iv, outStream);
}
public Stream GetDecryptionStream(string key, string iv, Stream inStream)
{
return GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
return this.GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
}
public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream)
{
return GetDecryptionStreamInternal(key, iv, inStream);
return this.GetDecryptionStreamInternal(key, iv, inStream);
}
private async Task<Stream> 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<Stream> 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)
@@ -138,78 +219,8 @@ namespace SystemExtensions.NetStandard.Security.Encryption
return new MemoryStream(value);
}
private static async Task<Stream> EncryptInternal(byte[] key, byte[] iv, Stream toEncryptStream)
public void Dispose()
{
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 = GetEncryptionStreamInternal(key, iv, encryptedMemoryStream);
await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false);
if (!cryptoStream.HasFlushedFinalBlock)
{
cryptoStream.FlushFinalBlock();
}
encryptedMemoryStream.Position = 0;
return encryptedMemoryStream;
}
private static async Task<Stream> 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 = GetDecryptionStreamInternal(key, iv, toDecryptStream);
await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false);
if (!cryptoStream.HasFlushedFinalBlock)
{
cryptoStream.FlushFinalBlock();
}
decryptedMemoryStream.Position = 0;
return decryptedMemoryStream;
}
private static CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
{
using var aes = Aes.Create();
aes.Padding = PaddingMode.PKCS7;
var crypto = aes.CreateEncryptor(key, iv);
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write);
return cryptoStream;
}
private static CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
{
using var aes = Aes.Create();
aes.Padding = PaddingMode.PKCS7;
var crypto = aes.CreateDecryptor(key, iv);
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read);
return cryptoStream;
}
this.aes.Dispose();
}
}
@@ -1,10 +1,10 @@
using System.IO;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.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);
@@ -21,5 +21,4 @@ namespace SystemExtensions.NetStandard.Security.Encryption
Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value);
Task<Stream> Decrypt(string key, string iv, Stream value);
Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value);
}
}
@@ -1,10 +1,10 @@
using System.Security.Cryptography;
using System.Text;
namespace System.Encryption
namespace System.Security.Encryption;
public sealed class SecureString
{
public sealed class SecureString
{
private static byte[] optionalEntropy;
private byte[] encryptedValue;
@@ -98,5 +98,4 @@ namespace System.Encryption
{
optionalEntropy = entropy;
}
}
}
@@ -1,12 +1,11 @@
using System.IO;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Hashing
namespace System.Security.Hashing;
public interface IHashingService
{
public interface IHashingService
{
Task<string> Hash(string raw);
Task<byte[]> Hash(byte[] raw);
Task<Stream> Hash(Stream raw);
}
}
@@ -0,0 +1,46 @@
using System.Threading.Tasks;
namespace System.Security.Hashing;
public interface IPasswordHashingService
{
/// <summary>
/// Hash provided raw password and return the hashed value.
/// </summary>
/// <param name="raw">Base64 encoded password.</param>
/// <param name="salt">Base64 encoded salt to be used for hashing.</param>
/// <param name="length">Length of the resulting hash.</param>
/// <param name="iterations">Number of hashing iterations to be performed.</param>
/// <remarks>
/// The length of the hash will vary due to the base64 encoding of the resulting hash.
/// </remarks>
/// <returns>Base64 encoded hashed password.</returns>
Task<string> Hash(string raw, string salt, int length, int iterations);
/// <summary>
/// Hash provided raw password and return the hashed value.
/// </summary>
/// <param name="raw">Password to be hashed.</param>
/// <param name="salt">Salt to be used for hashing.</param>
/// <param name="length">Length of the resulting hash.</param>
/// <param name="iterations">Number of hashing iterations to be performed.</param>
/// <returns>Hashed password.</returns>
Task<byte[]> Hash(byte[] raw, byte[] salt, int length, int iterations);
/// <summary>
/// Verify provided password against a hashed password.
/// </summary>
/// <param name="hash">Base64 encoding of the previously hashed password.</param>
/// <param name="password">Base64 encoding of the password to be verified.</param>
/// <param name="salt">Salt used to hash the previous password.</param>
/// <param name="iterations">Number of iterations used to hash the previous password.</param>
/// <returns>Returns true if password matches the previously hashed password. Otherwise returns false.</returns>
Task<bool> VerifyPassword(string hash, string password, string salt, int iterations);
/// <summary>
/// Verify provided password against a hashed password.
/// </summary>
/// <param name="hash">Previously hashed password.</param>
/// <param name="password">Password to be verified.</param>
/// <param name="salt">Salt used to hash the previous password.</param>
/// <param name="iterations">Number of iterations used to hash the previous password.</param>
/// <returns>Returns true if password matches the previously hashed password. Otherwise returns false.</returns>
Task<bool> VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations);
}
@@ -0,0 +1,100 @@
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace System.Security.Hashing;
public sealed class Rfc2898DeriveBytesPasswordHashingService : IPasswordHashingService
{
private const int MinimumIterations = 10000;
private const int MinimumHashLength = 32;
public Rfc2898DeriveBytesPasswordHashingService()
{
}
public async Task<string> 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<byte[]> Hash(byte[] raw, byte[] salt, int length, int iterations)
{
this.ValidateHashArguments(raw, salt, length, iterations);
return this.HashInternal(raw, salt, length, iterations);
}
public Task<bool> 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<bool> 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<byte[]> 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<bool> 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));
}
}
@@ -1,12 +1,11 @@
using System;
using System.IO;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Hashing
namespace System.Security.Hashing;
public sealed class Sha256HashingService : IHashingService
{
public sealed class Sha256HashingService : IHashingService
{
public async Task<string> Hash(string raw)
{
using var rawStream = BytesToStream(StringToBytes(raw));
@@ -59,5 +58,4 @@ namespace SystemExtensions.NetStandard.Security.Hashing
using var sha256 = SHA256.Create();
return await Task.Run(() => new MemoryStream(sha256.ComputeHash(raw)));
}
}
}
@@ -1,9 +1,9 @@
using System.Security.Cryptography;
namespace System.Rng
namespace System.Security.Rng;
public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable
{
public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable
{
private readonly RNGCryptoServiceProvider rngProvider;
private bool disposedValue;
@@ -55,5 +55,4 @@ namespace System.Rng
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
@@ -1,10 +1,27 @@
namespace System.Rng
namespace System.Security.Rng;
public interface ICryptoRngProvider
{
public interface ICryptoRngProvider
{
/// <summary>
/// Populate provided array of bytes with cryptographically secure random bytes.
/// </summary>
/// <param name="data">Array of bytes to be populated.</param>
public void GetBytes(byte[] data);
/// <summary>
/// Return an array of cryptographically secure random bytes.
/// </summary>
/// <param name="byteCount">Length of the returned array.</param>
/// <returns>Array containing cryptographically secure random values.</returns>
public byte[] GetBytes(int byteCount);
/// <summary>
/// Populate provided array of bytes with cryptographically secure random non-zero bytes.
/// </summary>
/// <param name="data">Array of bytes to be populated.</param>
public void GetNonZeroBytes(byte[] data);
/// <summary>
/// Return an array of cryptographically secure random non-zero bytes.
/// </summary>
/// <param name="byteCount">Length of the returned array.</param>
/// <returns>Array containing cryptographically secure random non-zero values.</returns>
public byte[] GetNonZeroBytes(int byteCount);
}
}
@@ -7,9 +7,10 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RootNamespace>System</RootNamespace>
<Version>1.1.1</Version>
<Version>1.2.5</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Security extensions for the System namespace</Description>
</PropertyGroup>
<ItemGroup>
@@ -20,7 +21,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="5.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="7.0.1" />
</ItemGroup>
</Project>
@@ -1,10 +1,10 @@
using System.IO;
using System.Security.Cryptography;
namespace SystemExtensions.NetStandard.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)
{
@@ -19,5 +19,4 @@ namespace SystemExtensions.NetStandard.Security.Utilities
base.Dispose(false);
}
}
}
@@ -1,16 +1,16 @@
using System.Collections.Generic;
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// AVL tree implementation.
/// Thanks to Karim Oumghar for the implementation example.
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
{
/// <summary>
/// AVL tree implementation.
/// Thanks to Karim Oumghar for the implementation example.
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
{
#region Fields
[Serializable]
private class AVLNode<TKey>
@@ -35,13 +35,13 @@ namespace System.Collections.Generic
{
get
{
return count;
return this.count;
}
}
/// <summary>
/// True if the collection is readonly. False otherwise.
/// </summary>
public bool IsReadOnly => isReadOnly;
public bool IsReadOnly => this.isReadOnly;
#endregion
#region Constructors
/// <summary>
@@ -59,15 +59,15 @@ namespace System.Collections.Generic
/// <param name="value">Value to be added to the tree.</param>
public void Add(T value)
{
count++;
this.count++;
var newItem = new AVLNode<T>(value);
if (root == null)
if (this.root == null)
{
root = newItem;
this.root = newItem;
}
else
{
root = RecursiveInsertion(root, newItem);
this.root = this.RecursiveInsertion(this.root, newItem);
}
}
/// <summary>
@@ -77,11 +77,12 @@ namespace System.Collections.Generic
/// <returns>True if the value is in the tree.</returns>
public bool Contains(T value)
{
var node = Find(value, root);
var node = this.Find(value, this.root);
if (node == null)
{
return false;
}
if (node.Value.CompareTo(value) == 0)
{
return true;
@@ -97,7 +98,7 @@ namespace System.Collections.Generic
/// <param name="value">Value to be deleted.</param>
public bool Remove(T value)
{
root = Delete(root, value);
this.root = this.Delete(this.root, value);
return true;
}
/// <summary>
@@ -106,7 +107,7 @@ namespace System.Collections.Generic
public void Clear()
{
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(root);
queue.Enqueue(this.root);
while (queue.Count > 0)
{
@@ -115,17 +116,19 @@ namespace System.Collections.Generic
{
queue.Enqueue(currentNode.Left);
currentNode.Left = null;
count--;
this.count--;
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
currentNode.Right = null;
count--;
this.count--;
}
}
root = null;
count--;
this.root = null;
this.count--;
}
/// <summary>
/// Copies the tree onto the provided array.
@@ -135,7 +138,7 @@ namespace System.Collections.Generic
public void CopyTo(T[] array, int arrayIndex)
{
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(root);
queue.Enqueue(this.root);
while (queue.Count > 0)
{
var currentNode = queue.Dequeue();
@@ -144,6 +147,7 @@ namespace System.Collections.Generic
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
@@ -156,7 +160,7 @@ namespace System.Collections.Generic
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return GetEnumerator(root);
return this.GetEnumerator(this.root);
}
/// <summary>
/// Copies the tree structure into an array.
@@ -164,8 +168,8 @@ namespace System.Collections.Generic
/// <returns>Array containing the values contained in the tree.</returns>
public T[] ToArray()
{
var array = new T[count];
CopyTo(array, 0);
var array = new T[this.count];
this.CopyTo(array, 0);
return array;
}
#endregion
@@ -179,41 +183,43 @@ namespace System.Collections.Generic
}
else if (n.Value.CompareTo(current.Value) < 0)
{
current.Left = RecursiveInsertion(current.Left, n);
current = BalanceTree(current);
current.Left = this.RecursiveInsertion(current.Left, n);
current = this.BalanceTree(current);
}
else if (n.Value.CompareTo(current.Value) > 0)
{
current.Right = RecursiveInsertion(current.Right, n);
current = BalanceTree(current);
current.Right = this.RecursiveInsertion(current.Right, n);
current = this.BalanceTree(current);
}
return current;
}
private AVLNode<T> BalanceTree(AVLNode<T> current)
{
var b_factor = BalanceFactor(current);
var b_factor = this.BalanceFactor(current);
if (b_factor > 1)
{
if (BalanceFactor(current.Left) > 0)
if (this.BalanceFactor(current.Left) > 0)
{
current = RotateLL(current);
current = this.RotateLL(current);
}
else
{
current = RotateLR(current);
current = this.RotateLR(current);
}
}
else if (b_factor < -1)
{
if (BalanceFactor(current.Right) > 0)
if (this.BalanceFactor(current.Right) > 0)
{
current = RotateRL(current);
current = this.RotateRL(current);
}
else
{
current = RotateRR(current);
current = this.RotateRR(current);
}
}
return current;
}
private AVLNode<T> Delete(AVLNode<T> current, T target)
@@ -226,39 +232,39 @@ namespace System.Collections.Generic
//left subtree
if (target.CompareTo(current.Value) < 0)
{
current.Left = Delete(current.Left, target);
if (BalanceFactor(current) == -2)//here
current.Left = this.Delete(current.Left, target);
if (this.BalanceFactor(current) == -2)//here
{
if (BalanceFactor(current.Right) <= 0)
if (this.BalanceFactor(current.Right) <= 0)
{
current = RotateRR(current);
current = this.RotateRR(current);
}
else
{
current = RotateRL(current);
current = this.RotateRL(current);
}
}
}
//right subtree
else if (target.CompareTo(current.Value) > 0)
{
current.Right = Delete(current.Right, target);
if (BalanceFactor(current) == 2)
current.Right = this.Delete(current.Right, target);
if (this.BalanceFactor(current) == 2)
{
if (BalanceFactor(current.Left) >= 0)
if (this.BalanceFactor(current.Left) >= 0)
{
current = RotateLL(current);
current = this.RotateLL(current);
}
else
{
current = RotateLR(current);
current = this.RotateLR(current);
}
}
}
//if target is found
else
{
count--;
this.count--;
if (current.Right != null)
{
//delete its inorder successor
@@ -267,15 +273,16 @@ namespace System.Collections.Generic
{
parent = parent.Left;
}
current.Value = parent.Value;
current.Right = Delete(current.Right, parent.Value);
if (BalanceFactor(current) == 2)//rebalancing
current.Right = this.Delete(current.Right, parent.Value);
if (this.BalanceFactor(current) == 2)//rebalancing
{
if (BalanceFactor(current.Left) >= 0)
if (this.BalanceFactor(current.Left) >= 0)
{
current = RotateLL(current);
current = this.RotateLL(current);
}
else { current = RotateLR(current); }
else { current = this.RotateLR(current); }
}
}
else
@@ -284,6 +291,7 @@ namespace System.Collections.Generic
}
}
}
return current;
}
private AVLNode<T> Find(T target, AVLNode<T> current)
@@ -292,6 +300,7 @@ namespace System.Collections.Generic
{
return null;
}
if (target.CompareTo(current.Value) < 0)
{
if (target.CompareTo(current.Value) == 0)
@@ -300,7 +309,7 @@ namespace System.Collections.Generic
}
else
{
return Find(target, current.Left);
return this.Find(target, current.Left);
}
}
else
@@ -311,10 +320,9 @@ namespace System.Collections.Generic
}
else
{
return Find(target, current.Right);
return this.Find(target, current.Right);
}
}
}
private int Max(int l, int r)
{
@@ -325,17 +333,18 @@ namespace System.Collections.Generic
var height = 0;
if (current != null)
{
var l = GetHeight(current.Left);
var r = GetHeight(current.Right);
var m = Max(l, r);
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<T> current)
{
var l = GetHeight(current.Left);
var r = GetHeight(current.Right);
var l = this.GetHeight(current.Left);
var r = this.GetHeight(current.Right);
var b_factor = l - r;
return b_factor;
}
@@ -356,14 +365,14 @@ namespace System.Collections.Generic
private AVLNode<T> RotateLR(AVLNode<T> parent)
{
var pivot = parent.Left;
parent.Left = RotateRR(pivot);
return RotateLL(parent);
parent.Left = this.RotateRR(pivot);
return this.RotateLL(parent);
}
private AVLNode<T> RotateRL(AVLNode<T> parent)
{
var pivot = parent.Right;
parent.Right = RotateLL(pivot);
return RotateRR(parent);
parent.Right = this.RotateLL(pivot);
return this.RotateRR(parent);
}
IEnumerator IEnumerable.GetEnumerator()
{
@@ -382,6 +391,7 @@ namespace System.Collections.Generic
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
@@ -389,5 +399,4 @@ namespace System.Collections.Generic
}
}
#endregion
}
}
@@ -1,14 +1,14 @@
using System.Linq;
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// Binary heap implementation.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
{
/// <summary>
/// Binary heap implementation.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
{
#region Fields
T[] items;
private int capacity;
@@ -23,7 +23,7 @@ namespace System.Collections.Generic
{
get
{
return items[1];
return this.items[1];
}
}
/// <summary>
@@ -33,7 +33,7 @@ namespace System.Collections.Generic
{
get
{
return items[count];
return this.items[this.count];
}
}
/// <summary>
@@ -41,20 +41,20 @@ namespace System.Collections.Generic
/// </summary>
public int Capacity
{
get => capacity;
get => this.capacity;
set
{
if (value > capacity)
if (value > this.capacity)
{
Array.Resize(ref items, value);
capacity = value;
Array.Resize(ref this.items, value);
this.capacity = value;
}
}
}
/// <summary>
/// Number of elements in the heap.
/// </summary>
public int Count { get => count; }
public int Count { get => this.count; }
#endregion
#region Constructors
/// <summary>
@@ -62,9 +62,9 @@ namespace System.Collections.Generic
/// </summary>
public BinaryHeap()
{
capacity = 10;
initialCapacity = capacity;
items = new T[capacity];
this.capacity = 10;
this.initialCapacity = this.capacity;
this.items = new T[this.capacity];
}
/// <summary>
/// Constructor for a binary heap data structure.
@@ -73,8 +73,8 @@ namespace System.Collections.Generic
public BinaryHeap(int capacity)
{
this.capacity = capacity;
initialCapacity = capacity;
items = new T[capacity];
this.initialCapacity = capacity;
this.items = new T[capacity];
}
#endregion
#region Public Methods
@@ -84,16 +84,18 @@ namespace System.Collections.Generic
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
if (count == Capacity - 1)
if (this.count == this.Capacity - 1)
{
Capacity = 2 * Capacity;
this.Capacity = 2 * this.Capacity;
}
var position = ++count;
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
var position = ++this.count;
for (; position > 1 && value.CompareTo(this.items[position / 2]) < 0; position /= 2)
{
items[position] = items[position / 2];
this.items[position] = this.items[position / 2];
}
items[position] = value;
this.items[position] = value;
}
/// <summary>
/// Removes the item at the root. Throws exception if there are no items in the heap.
@@ -101,13 +103,14 @@ namespace System.Collections.Generic
/// <returns>Value removed.</returns>
public T Remove()
{
if (count == 0)
if (this.count == 0)
{
throw new IndexOutOfRangeException("Heap is empty!");
}
var min = items[1];
items[1] = items[count--];
BubbleDown(1);
var min = this.items[1];
this.items[1] = this.items[this.count--];
this.BubbleDown(1);
return min;
}
/// <summary>
@@ -116,11 +119,12 @@ namespace System.Collections.Generic
/// <returns></returns>
public T Peek()
{
if (count == 0)
if (this.count == 0)
{
throw new IndexOutOfRangeException("Heap is empty!");
}
var min = items[1];
var min = this.items[1];
return min;
}
/// <summary>
@@ -129,8 +133,8 @@ namespace System.Collections.Generic
/// <returns>Array with values sorted as in heap</returns>
public T[] ToArray()
{
var newArray = new T[count];
Array.Copy(items, 1, newArray, 0, count);
var newArray = new T[this.count];
Array.Copy(this.items, 1, newArray, 0, this.count);
return newArray;
}
/// <summary>
@@ -140,14 +144,14 @@ namespace System.Collections.Generic
/// <returns></returns>
public bool Contains(T value)
{
return items.Contains(value);
return this.items.Contains(value);
}
/// <summary>
/// Clears the heap
/// </summary>
public void Clear()
{
count = 0;
this.count = 0;
}
/// <summary>
/// Clears the heap.
@@ -155,11 +159,11 @@ namespace System.Collections.Generic
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
public void Clear(bool completeClear)
{
count = 0;
this.count = 0;
if (completeClear)
{
capacity = initialCapacity;
items = new T[initialCapacity];
this.capacity = this.initialCapacity;
this.items = new T[this.initialCapacity];
}
}
/// <summary>
@@ -168,9 +172,9 @@ namespace System.Collections.Generic
/// <returns>Enumerator that iterates over the heap.</returns>
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < count; i++)
for (var i = 0; i < this.count; i++)
{
yield return items[i + 1];
yield return this.items[i + 1];
}
}
#endregion
@@ -181,25 +185,27 @@ namespace System.Collections.Generic
/// <param name="index">Index of element to bubble</param>
private void BubbleDown(int index)
{
var temp = items[index];
var temp = this.items[index];
int childIndex;
for (; 2 * index <= count; index = childIndex)
for (; 2 * index <= this.count; index = childIndex)
{
childIndex = 2 * index;
if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
if (childIndex != this.Count && this.items[childIndex].CompareTo(this.items[childIndex + 1]) > 0)
{
childIndex++;
}
if (temp.CompareTo(items[childIndex]) > 0)
if (temp.CompareTo(this.items[childIndex]) > 0)
{
items[index] = items[childIndex];
this.items[index] = this.items[childIndex];
}
else
{
break;
}
}
items[index] = temp;
this.items[index] = temp;
}
/// <summary>
/// Implementation of IEnumerator.
@@ -210,5 +216,4 @@ namespace System.Collections.Generic
throw new NotImplementedException();
}
#endregion
}
}
@@ -1,12 +1,12 @@
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// Fibonacci Heap implementation.
/// </summary>
/// <typeparam name="T">Provided type</typeparam>
[Serializable]
public sealed class FibonacciHeap<T> : IEnumerable<T> where T : IComparable<T>
{
/// <summary>
/// Fibonacci Heap implementation.
/// </summary>
/// <typeparam name="T">Provided type</typeparam>
[Serializable]
public sealed class FibonacciHeap<T> : IEnumerable<T> where T : IComparable<T>
{
#region Fields
private FibonacciNode<T> root;
private int count;
@@ -19,7 +19,7 @@
{
get
{
return count;
return this.count;
}
}
/// <summary>
@@ -29,7 +29,7 @@
{
get
{
return root.Value;
return this.root.Value;
}
}
#endregion
@@ -58,8 +58,8 @@
Degree = 0
};
node.Previous = node.Next = node;
root = this.Merge(root, node);
count++;
this.root = this.Merge(this.root, node);
this.count++;
}
/// <summary>
/// Merge current heap with another heap. The other heap will be disposed at the end of this method.
@@ -67,9 +67,9 @@
/// <param name="otherHeap">The heap to be merged with the current heap.</param>
public void Merge(FibonacciHeap<T> otherHeap)
{
root = Merge(root, otherHeap.root);
this.root = this.Merge(this.root, otherHeap.root);
otherHeap.root = null;
count += otherHeap.count;
this.count += otherHeap.count;
}
/// <summary>
/// Remove the minimum value from the heap.
@@ -77,11 +77,11 @@
/// <returns>Minimum value.</returns>
public T Remove()
{
var currentRoot = root;
var currentRoot = this.root;
if (currentRoot != null)
{
root = RemoveMinimum(root);
count--;
this.root = this.RemoveMinimum(this.root);
this.count--;
return currentRoot.Value;
}
else
@@ -96,8 +96,8 @@
/// <param name="value">New value to be assigned to the node.</param>
public void DecreaseKey(T oldValue, T value)
{
var node = Find(root, oldValue);
root = DecreaseKey(root, node, value);
var node = this.Find(this.root, oldValue);
this.root = this.DecreaseKey(this.root, node, value);
}
/// <summary>
/// Determines whether the heap contains a specified value.
@@ -106,17 +106,17 @@
/// <returns></returns>
public bool Contains(T value)
{
return Find(root, value) != null;
return this.Find(this.root, value) != null;
}
/// <summary>
/// Clears the heap.
/// </summary>
public void Clear()
{
count = 0;
Remove(root);
root.Next = root.Previous = root.Parent = root.Child = null;
root = null;
this.count = 0;
this.Remove(this.root);
this.root.Next = this.root.Previous = this.root.Parent = this.root.Child = null;
this.root = null;
}
/// <summary>
/// Return the heap structure as an array. Array is not sorted other than the
@@ -125,20 +125,21 @@
/// <returns>Array with values from the heap.</returns>
public T[] ToArray()
{
if (count == 0)
if (this.count == 0)
{
return null;
}
var array = new T[count];
if (count == 1)
var array = new T[this.count];
if (this.count == 1)
{
array[0] = root.Value;
array[0] = this.root.Value;
return array;
}
else
{
var index = 0;
RecursiveFillArray(root, ref array, ref index);
this.RecursiveFillArray(this.root, ref array, ref index);
return array;
}
}
@@ -148,7 +149,7 @@
/// <returns>Enumerator that iterates over the heap.</returns>
public IEnumerator<T> GetEnumerator()
{
return GetEnumerator(root);
return this.GetEnumerator(this.root);
}
#endregion
#region Private Methods
@@ -167,8 +168,9 @@
index++;
if (currentNode.HasChildren())
{
RecursiveFillArray(currentNode.Child, ref array, ref index);
this.RecursiveFillArray(currentNode.Child, ref array, ref index);
}
currentNode = currentNode.Previous;
} while (currentNode != oldNode);
}
@@ -191,10 +193,10 @@
{
queue.Enqueue(currentNode.Child);
}
currentNode = currentNode.Previous;
} while (currentNode != oldNode);
}
}
/// <summary>
/// Recursively remove the node and its children from the heap.
@@ -207,11 +209,12 @@
var current = node;
do
{
Remove(current.Child);
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;
@@ -228,16 +231,19 @@
{
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;
@@ -256,7 +262,7 @@
child.Previous = child.Next = child;
child.Parent = parent;
parent.Degree++;
parent.Child = Merge(parent.Child, child);
parent.Child = this.Merge(parent.Child, child);
}
/// <summary>
/// Removes the parent of the specified node.
@@ -268,6 +274,7 @@
{
return;
}
var current = node;
do
{
@@ -283,7 +290,7 @@
/// <returns></returns>
private FibonacciNode<T> RemoveMinimum(FibonacciNode<T> node)
{
RemoveParent(node.Child);
this.RemoveParent(node.Child);
if (node.Next == node)
{
node = node.Child;
@@ -292,8 +299,9 @@
{
node.Next.Previous = node.Previous;
node.Previous.Next = node.Next;
node = Merge(node.Next, node.Child);
node = this.Merge(node.Next, node.Child);
}
if (node == null)
{
return node;
@@ -309,12 +317,13 @@
{
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);
this.AddChild(node, t);
}
else
{
@@ -323,7 +332,7 @@
if (node.Next == node)
{
t.Next = t.Previous = t;
AddChild(t, node);
this.AddChild(t, node);
node = t;
}
else
@@ -332,18 +341,21 @@
node.Next.Previous = t;
t.Next = node.Next;
t.Previous = node.Previous;
AddChild(t, node);
this.AddChild(t, node);
node = t;
}
}
continue;
}
else
{
trees[node.Degree] = node;
}
node = node.Next;
}
var min = node;
var start = node;
do
@@ -352,6 +364,7 @@
{
min = node;
}
node = node.Next;
} while (node != start);
return min;
@@ -374,9 +387,10 @@
node.Previous.Next = node.Next;
node.Parent.Child = node.Next;
}
node.Next = node.Previous = node;
node.Marked = false;
return Merge(root, node);
return this.Merge(root, node);
}
/// <summary>
/// Decrease value of provided node substituting it with the provided value.
@@ -391,21 +405,23 @@
{
return root;
}
node.Value = value;
if (node.Parent != null)
{
if (node.Value.CompareTo(node.Parent.Value) < 0)
{
root = Cut(root, node);
root = this.Cut(root, node);
var parent = node.Parent;
node.Parent = null;
while (parent != null && parent.Marked)
{
root = Cut(root, parent);
root = this.Cut(root, parent);
node = parent;
parent = node.Parent;
node.Parent = null;
}
if (parent != null && parent.Parent != null)
{
parent.Marked = true;
@@ -419,6 +435,7 @@
root = node;
}
}
return root;
}
/// <summary>
@@ -434,17 +451,20 @@
{
return null;
}
do
{
if (node.Value.CompareTo(value) == 0)
{
return node;
}
var ret = Find(node.Child, value);
var ret = this.Find(node.Child, value);
if (ret != null)
{
return ret;
}
node = node.Next;
} while (node != root);
return null;
@@ -454,10 +474,10 @@
throw new NotImplementedException();
}
#endregion
}
[Serializable]
internal sealed class FibonacciNode<T>
{
}
[Serializable]
internal sealed class FibonacciNode<T>
{
#region Fields
private FibonacciNode<T> previous;
private FibonacciNode<T> next;
@@ -472,62 +492,62 @@
{
get
{
return previous;
return this.previous;
}
set
{
previous = value;
this.previous = value;
}
}
public FibonacciNode<T> Next
{
get
{
return next;
return this.next;
}
set
{
next = value;
this.next = value;
}
}
public FibonacciNode<T> Child
{
get
{
return child;
return this.child;
}
set
{
child = value;
this.child = value;
}
}
public FibonacciNode<T> Parent
{
get
{
return parent;
return this.parent;
}
set
{
parent = value;
this.parent = value;
}
}
public bool Marked
{
get
{
return marked;
return this.marked;
}
set
{
marked = value;
this.marked = value;
}
}
public T Value
{
get
{
return value;
return this.value;
}
set
{
@@ -538,23 +558,22 @@
{
get
{
return degree;
return this.degree;
}
set
{
degree = value;
this.degree = value;
}
}
#endregion
#region Public Methods
public bool HasChildren()
{
return child != null;
return this.child != null;
}
public bool HasParent()
{
return parent != null;
return this.parent != null;
}
#endregion
}
}
@@ -1,11 +1,11 @@
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// Interface for queue implementations.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
public interface IQueue<T> : IEnumerable<T>
{
/// <summary>
/// Interface for queue implementations.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
public interface IQueue<T> : IEnumerable<T>
{
/// <summary>
/// Returns the number of items in the queue.
/// </summary>
@@ -35,5 +35,4 @@
/// <param name="item">Item to be checked.</param>
/// <returns>True if queue contains provided item. False otherwise.</returns>
bool Contains(T item);
}
}
@@ -1,13 +1,13 @@
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
{
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
{
#region Fields
private readonly BinaryHeap<T> binaryHeap;
#endregion
@@ -19,7 +19,7 @@
{
get
{
return binaryHeap.Count;
return this.binaryHeap.Count;
}
}
#endregion
@@ -29,7 +29,7 @@
/// </summary>
public PriorityQueue()
{
binaryHeap = new BinaryHeap<T>();
this.binaryHeap = new BinaryHeap<T>();
}
#endregion
#region Public Methods
@@ -39,7 +39,7 @@
/// <param name="value">Value to be added to the queue.</param>
public void Enqueue(T value)
{
binaryHeap.Add(value);
this.binaryHeap.Add(value);
}
/// <summary>
/// Pops the queue and removes the highest priority value from the queue.
@@ -47,9 +47,9 @@
/// <returns>Highest priority value from the queue</returns>
public T Dequeue()
{
if (Count > 0)
if (this.Count > 0)
{
return binaryHeap.Remove();
return this.binaryHeap.Remove();
}
else
{
@@ -62,14 +62,14 @@
/// <returns>Highest priority value from the queue.</returns>
public T Peek()
{
return binaryHeap.Min;
return this.binaryHeap.Min;
}
/// <summary>
/// Clears the queue contents, removing any value stored into the queue.
/// </summary>
public void Clear()
{
binaryHeap.Clear();
this.binaryHeap.Clear();
}
/// <summary>
/// Checks if queue contains provided item.
@@ -78,7 +78,7 @@
/// <returns>True if queue contains the provided item. False otherwise.</returns>
public bool Contains(T item)
{
return binaryHeap.Contains(item);
return this.binaryHeap.Contains(item);
}
/// <summary>
/// Returns an enumerator that iterates over the queue.
@@ -86,7 +86,7 @@
/// <returns>Enumerator that iterates over the queue.</returns>
public IEnumerator<T> GetEnumerator()
{
return binaryHeap.GetEnumerator();
return this.binaryHeap.GetEnumerator();
}
#endregion
#region Private Methods
@@ -99,5 +99,4 @@
throw new NotImplementedException();
}
#endregion
}
}
@@ -1,12 +1,12 @@
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// Skip list implementation.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
{
/// <summary>
/// Skip list implementation.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
{
#region Fields
[Serializable]
private class NodeSet<TKey>
@@ -19,7 +19,7 @@
{
this.Key = key;
this.Level = level;
Next = new NodeSet<TKey>[level + 1];
this.Next = new NodeSet<TKey>[level + 1];
}
}
private int count;
@@ -33,7 +33,7 @@
/// <summary>
/// Number of elements in the list.
/// </summary>
public int Count { get => count; }
public int Count { get => this.count; }
/// <summary>
/// Specifies if the collection can be modified.
/// </summary>
@@ -47,12 +47,12 @@
public SkipList(int maxLevel = 10)
{
this.maxLevel = maxLevel;
random = new Random();
head = new NodeSet<T>(default, maxLevel);
end = head;
this.random = new Random();
this.head = new NodeSet<T>(default, maxLevel);
this.end = this.head;
for (var i = 0; i <= maxLevel; i++)
{
head.Next[i] = end;
this.head.Next[i] = this.end;
}
}
@@ -64,31 +64,36 @@
/// <param name="item">Item to be added.</param>
public void Add(T item)
{
var curNode = head;
var curNode = this.head;
var newLevel = 0;
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
while (this.random.Next(0, 2) > 0 && newLevel < this.maxLevel)
{
newLevel++;
}
if (newLevel > level)
if (newLevel > this.level)
{
level = newLevel;
this.level = newLevel;
}
var newNode = new NodeSet<T>(item, newLevel);
for (var i = 0; i <= newLevel; i++)
{
if (i > curNode.Level)
{
curNode = head;
curNode = this.head;
}
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
{
curNode = curNode.Next[i];
}
newNode.Next[i] = curNode.Next[i];
curNode.Next[i] = newNode;
}
count++;
this.count++;
}
/// <summary>
/// Removes provided item from the collection.
@@ -98,17 +103,19 @@
public bool Remove(T item)
{
var removed = false;
var curNode = head;
for (var i = 0; i <= maxLevel; i++)
var curNode = this.head;
for (var i = 0; i <= this.maxLevel; i++)
{
if (i > curNode.Level)
{
curNode = head;
curNode = this.head;
}
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
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];
@@ -119,9 +126,10 @@
break;
}
}
if (removed)
{
count--;
this.count--;
return true;
}
else
@@ -134,11 +142,12 @@
/// </summary>
public void Clear()
{
for (var i = 0; i < maxLevel; i++)
for (var i = 0; i < this.maxLevel; i++)
{
head.Next[i] = end;
this.head.Next[i] = this.end;
}
count = 0;
this.count = 0;
}
/// <summary>
/// Checks if item is present in the collection.
@@ -147,10 +156,11 @@
/// <returns>True if item is present in the collection.</returns>
public bool Contains(T item)
{
if (Find(item) != null)
if (this.Find(item) != null)
{
return true;
}
return false;
}
/// <summary>
@@ -160,8 +170,8 @@
/// <param name="arrayIndex">Index to start insertion in the array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
var node = head.Next[0];
while (node != end)
var node = this.head.Next[0];
while (node != this.end)
{
array[arrayIndex] = node.Key;
arrayIndex++;
@@ -174,15 +184,16 @@
/// <returns>Array filled with elements from the collection.</returns>
public T[] ToArray()
{
var array = new T[count];
var array = new T[this.count];
var index = 0;
var curNode = head.Next[0];
while (curNode != end)
var curNode = this.head.Next[0];
while (curNode != this.end)
{
array[index] = curNode.Key;
index++;
curNode = curNode.Next[0];
}
return array;
}
/// <summary>
@@ -191,8 +202,8 @@
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
var curNode = head.Next[0];
while (curNode != end)
var curNode = this.head.Next[0];
while (curNode != this.end)
{
yield return curNode.Key;
curNode = curNode.Next[0];
@@ -206,11 +217,11 @@
}
private NodeSet<T> Find(T key)
{
var curNode = head;
var curNode = this.head;
for (var i = level; i >= 0; i--)
for (var i = this.level; i >= 0; i--)
{
while (curNode.Next[i] != end)
while (curNode.Next[i] != this.end)
{
if (curNode.Next[i].Key.CompareTo(key) > 0)
{
@@ -220,17 +231,18 @@
{
return curNode.Next[i];
}
curNode = curNode.Next[i];
}
}
curNode = curNode.Next[0];
if (curNode != end && curNode.Key.CompareTo(key) == 0)
if (curNode != this.end && curNode.Key.CompareTo(key) == 0)
{
return curNode;
}
return null;
}
#endregion
}
}
@@ -1,12 +1,12 @@
namespace System.Collections.Generic
namespace System.Collections.Generic;
/// <summary>
/// Treap implementation.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
{
/// <summary>
/// Treap implementation.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
{
#region Fields
[Serializable]
private class Node<TKey>
@@ -16,10 +16,10 @@
public Node<TKey> 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;
@@ -34,7 +34,7 @@
{
get
{
return count;
return this.count;
}
}
/// <summary>
@@ -48,7 +48,7 @@
/// </summary>
public Treap()
{
randomGen = new Random();
this.randomGen = new Random();
}
#endregion
#region Public Methods
@@ -58,8 +58,8 @@
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
root = InsertNode(root, value);
count++;
this.root = this.InsertNode(this.root, value);
this.count++;
}
/// <summary>
/// Removes value from treap.
@@ -67,8 +67,8 @@
/// <param name="value">Value to be removed.</param>
public bool Remove(T value)
{
root = RemoveNode(root, value);
count--;
this.root = this.RemoveNode(this.root, value);
this.count--;
return true;
}
/// <summary>
@@ -76,9 +76,9 @@
/// </summary>
public void Clear()
{
Clear(root);
root = null;
count = 0;
this.Clear(this.root);
this.root = null;
this.count = 0;
}
/// <summary>
/// Determines whether the treap contains the specified value.
@@ -87,7 +87,7 @@
/// <returns></returns>
public bool Contains(T value)
{
return Find(root, value) != null;
return this.Find(this.root, value) != null;
}
/// <summary>
/// Returns the treap structure as an ordered array.
@@ -95,11 +95,11 @@
/// <returns>Ordered array containing the values stored in the treap.</returns>
public T[] ToArray()
{
if (root != null)
if (this.root != null)
{
var array = new T[count];
var array = new T[this.count];
var index = 0;
ToArray(root, ref array, ref index);
this.ToArray(this.root, ref array, ref index);
return array;
}
else
@@ -114,7 +114,7 @@
/// <param name="arrayIndex">Starting index of the array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
ToArray(root, ref array, ref arrayIndex);
this.ToArray(this.root, ref array, ref arrayIndex);
}
/// <summary>
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
@@ -122,7 +122,7 @@
/// <returns>Enumerator that iterates over the treap.</returns>
public IEnumerator<T> GetEnumerator()
{
return GetEnumerator(root);
return this.GetEnumerator(this.root);
}
#endregion
#region Private Methods
@@ -130,25 +130,26 @@
{
if (node == null)
{
node = new Node<T>(key, randomGen.Next(0, 100));
node = new Node<T>(key, this.randomGen.Next(0, 100));
return node;
}
else if (key.CompareTo(node.Key) <= 0)
{
node.Left = InsertNode(node.Left, key);
node.Left = this.InsertNode(node.Left, key);
if (node.Left.Priority > node.Priority)
{
node = RotateRight(node);
node = this.RotateRight(node);
}
}
else
{
node.Right = InsertNode(node.Right, key);
node.Right = this.InsertNode(node.Right, key);
if (node.Right.Priority > node.Priority)
{
node = RotateLeft(node);
node = this.RotateLeft(node);
}
}
return node;
}
private Node<T> RemoveNode(Node<T> node, T key)
@@ -157,13 +158,14 @@
{
return node;
}
if (key.CompareTo(node.Key) < 0)
{
node.Left = RemoveNode(node.Left, key);
node.Left = this.RemoveNode(node.Left, key);
}
else if (key.CompareTo(node.Key) > 0)
{
node.Right = RemoveNode(node.Right, key);
node.Right = this.RemoveNode(node.Right, key);
}
else if (node.Left == null)
{
@@ -175,14 +177,15 @@
}
else if (node.Left.Priority < node.Right.Priority)
{
node = RotateLeft(node);
node.Left = RemoveNode(node.Left, key);
node = this.RotateLeft(node);
node.Left = this.RemoveNode(node.Left, key);
}
else
{
node = RotateRight(node);
node.Right = RemoveNode(node.Right, key);
node = this.RotateRight(node);
node.Right = this.RemoveNode(node.Right, key);
}
return node;
}
private Node<T> RotateRight(Node<T> node)
@@ -203,12 +206,14 @@
{
if (node.Left != null)
{
Clear(node.Left);
this.Clear(node.Left);
}
if (node.Right != null)
{
Clear(node.Right);
this.Clear(node.Right);
}
node.Left = node.Right = null;
}
private Node<T> Find(Node<T> node, T key)
@@ -221,20 +226,22 @@
{
if (node.Key.CompareTo(key) < 0)
{
var found = Find(node.Left, key);
var found = this.Find(node.Left, key);
if (found == null)
{
found = Find(node.Right, key);
found = this.Find(node.Right, key);
}
return found;
}
else if (node.Key.CompareTo(key) > 0)
{
var found = Find(node.Right, key);
var found = this.Find(node.Right, key);
if (found == null)
{
found = Find(node.Left, key);
found = this.Find(node.Left, key);
}
return found;
}
else
@@ -247,10 +254,10 @@
{
if (node != null)
{
ToArray(node.Left, ref array, ref index);
this.ToArray(node.Left, ref array, ref index);
array[index] = node.Key;
index++;
ToArray(node.Right, ref array, ref index);
this.ToArray(node.Right, ref array, ref index);
}
}
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
@@ -265,6 +272,7 @@
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
@@ -276,5 +284,4 @@
throw new NotImplementedException();
}
#endregion
}
}
@@ -1,9 +1,9 @@
using System.IO;
namespace System.Extensions
namespace System.Extensions;
public static class BytesExtensions
{
public static class BytesExtensions
{
public static byte[] ReadAllBytes(this Stream stream)
{
if (stream is null)
@@ -12,8 +12,7 @@ namespace System.Extensions
}
var buffer = new byte[256];
using (var ms = new MemoryStream())
{
using var ms = new MemoryStream();
int read;
while ((read = stream.Read(buffer, 0, 256)) > 0)
{
@@ -22,6 +21,4 @@ namespace System.Extensions
return ms.ToArray();
}
}
}
}
@@ -1,7 +1,7 @@
namespace System.Extensions
namespace System.Extensions;
public static class CastExtensions
{
public static class CastExtensions
{
public static int Floor(this double value)
{
return (int)Math.Floor(value);
@@ -46,5 +46,4 @@
{
return (int)value;
}
}
}
@@ -1,10 +1,10 @@
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<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
enumerable.ThrowIfNull(nameof(enumerable));
@@ -70,6 +70,7 @@ namespace System.Extensions
{
return index;
}
index++;
}
@@ -84,5 +85,4 @@ namespace System.Extensions
yield return value;
}
}
}
}
@@ -0,0 +1,12 @@
using Microsoft.Extensions.Logging;
using System.Logging;
namespace System.Extensions;
public static class LoggingExtensions
{
public static ScopedLogger<T> CreateScopedLogger<T>(this ILogger<T> logger, string methodName, string flowIdentifier)
{
return ScopedLogger<T>.Create(logger, methodName, flowIdentifier);
}
}
@@ -1,9 +1,9 @@
using Newtonsoft.Json;
namespace System.Extensions
namespace System.Extensions;
public static class ObjectExtensions
{
public static class ObjectExtensions
{
public static T Deserialize<T>(this string serialized)
where T : class
{
@@ -55,5 +55,4 @@ namespace System.Extensions
sealed class ValidatedNotNullAttribute : Attribute
{
}
}
}
@@ -1,7 +1,7 @@
namespace System.Extensions
namespace System.Extensions;
public static class Optional
{
public static class Optional
{
public static Optional<T> None<T>()
{
return new Optional<T>.None();
@@ -16,10 +16,10 @@
return new Optional<T>.Some(value);
}
}
}
public abstract class Optional<T> : IEquatable<Optional<T>>
{
public abstract class Optional<T> : IEquatable<Optional<T>>
{
public Optional(T value)
{
this.Value = value;
@@ -35,7 +35,7 @@
}
else
{
return Value;
return this.Value;
}
}
public Optional<T> Do(Action<T> onSome, Action onNone)
@@ -58,6 +58,7 @@
{
onNone.Invoke();
}
return this;
}
public Optional<T> DoAny(Action<T> onSome = null, Action onNone = null)
@@ -70,6 +71,7 @@
{
onNone?.Invoke();
}
return this;
}
public Optional<V> Switch<V>(Func<T, V> onSome, Func<V> onNone)
@@ -188,5 +190,4 @@
{
}
}
}
}
@@ -1,22 +1,22 @@
namespace System.Extensions
namespace System.Extensions;
public class Result<TSuccess, TFailure>
{
public class Result<TSuccess, TFailure>
{
private readonly object value;
public Result(TSuccess successValue)
{
value = successValue;
this.value = successValue;
}
public Result(TFailure failureValue)
{
value = failureValue;
this.value = failureValue;
}
public bool TryExtractSuccess(out TSuccess successValue)
{
if (value is TSuccess success)
if (this.value is TSuccess success)
{
successValue = success;
return true;
@@ -30,7 +30,7 @@
public bool TryExtractFailure(out TFailure failureValue)
{
if (value is TFailure failure)
if (this.value is TFailure failure)
{
failureValue = failure;
return true;
@@ -53,26 +53,28 @@
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess)
if (this.value is TSuccess)
{
onSuccess.Invoke();
}
else if (value is TFailure)
else if (this.value is TFailure)
{
onFailure.Invoke();
}
return this;
}
public Result<TSuccess, TFailure> DoAny(Action onSuccess = null, Action onFailure = null)
{
if (value is TSuccess)
if (this.value is TSuccess)
{
onSuccess?.Invoke();
}
else if (value is TFailure)
else if (this.value is TFailure)
{
onFailure?.Invoke();
}
return this;
}
public Result<TSuccess, TFailure> Do(Action<TSuccess> onSuccess, Action<TFailure> onFailure)
@@ -87,26 +89,28 @@
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess success)
if (this.value is TSuccess success)
{
onSuccess.Invoke(success);
}
else if (value is TFailure failure)
else if (this.value is TFailure failure)
{
onFailure.Invoke(failure);
}
return this;
}
public Result<TSuccess, TFailure> DoAny(Action<TSuccess> onSuccess = null, Action<TFailure> onFailure = null)
{
if (value is TSuccess success)
if (this.value is TSuccess success)
{
onSuccess?.Invoke(success);
}
else if (value is TFailure failure)
else if (this.value is TFailure failure)
{
onFailure?.Invoke(failure);
}
return this;
}
public T Switch<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure)
@@ -121,27 +125,29 @@
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess success)
if (this.value is TSuccess success)
{
return onSuccess.Invoke(success);
}
else if (value is TFailure failure)
else if (this.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)}");
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<T>(Func<TSuccess, T> onSuccess = null, Func<TFailure, T> onFailure = null)
{
if (value is TSuccess success)
if (this.value is TSuccess success)
{
return onSuccess is null ? default : onSuccess.Invoke(success);
}
else if (value is TFailure failure)
else if (this.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)}");
throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
}
public Result<V, K> Switch<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
@@ -155,33 +161,35 @@
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess success)
if (this.value is TSuccess success)
{
return Result<V, K>.Success(onSuccess.Invoke(success));
}
else if (value is TFailure failure)
else if (this.value is TFailure failure)
{
return Result<V, K>.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)}");
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<V, K> SwitchAny<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
if (value is TSuccess success)
if (this.value is TSuccess success)
{
return Result<V, K>.Success(onSuccess is null ? default : onSuccess.Invoke(success));
}
else if (value is TFailure failure)
else if (this.value is TFailure failure)
{
return Result<V, K>.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)}");
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<TSuccess> ToOptional()
{
if (value is TSuccess)
if (this.value is TSuccess)
{
return Optional.FromValue(value.Cast<TSuccess>());
return Optional.FromValue(this.value.Cast<TSuccess>());
}
return Optional.None<TSuccess>();
@@ -205,5 +213,4 @@
{
return new Result<TSuccess, TFailure>(value);
}
}
}
@@ -1,10 +1,10 @@
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<int, byte[]> action, int bufferLength = 256)
{
if (stream is null)
@@ -81,5 +81,4 @@ namespace System.Extensions
return sb.ToString();
}
}
}
@@ -1,9 +1,9 @@
using System.Text;
namespace System.Extensions
namespace System.Extensions;
public static class StringExtensions
{
public static class StringExtensions
{
public static bool IsNullOrEmpty(this string s)
{
return string.IsNullOrEmpty(s);
@@ -23,5 +23,4 @@ namespace System.Extensions
{
return Encoding.UTF8.GetString(bytes);
}
}
}
@@ -2,10 +2,10 @@
using System.Threading;
using System.Threading.Tasks;
namespace System.Extensions
namespace System.Extensions;
public static class TaskExtensions
{
public static class TaskExtensions
{
/// <summary>
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
/// </summary>
@@ -136,41 +136,43 @@ namespace System.Extensions
public override void Post(SendOrPostCallback d, object state)
{
lock (items)
lock (this.items)
{
items.Enqueue(Tuple.Create(d, state));
this.items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
this.workItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => done = true, null);
this.Post(_ => this.done = true, null);
}
public void BeginMessageLoop()
{
while (!done)
while (!this.done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
lock (this.items)
{
if (items.Count > 0)
if (this.items.Count > 0)
{
task = items.Dequeue();
task = this.items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
if (this.InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
throw new AggregateException("AsyncHelpers.Run method threw an exception.", this.InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
this.workItemsWaiting.WaitOne();
}
}
}
@@ -180,5 +182,4 @@ namespace System.Extensions
return this;
}
}
}
}
@@ -1,16 +1,16 @@
using System.Collections.Generic;
namespace System.Extensions
namespace System.Extensions;
public static class Try
{
public static class Try
{
public static Try<TResult> Action<TResult>(Func<TResult> act)
{
return new Try<TResult>(act);
}
}
public class Try<TResult>
{
}
public class Try<TResult>
{
private readonly Func<TResult> action;
private readonly List<Func<Exception, TResult>> catchActions = new List<Func<Exception, TResult>>();
internal Try(Func<TResult> action)
@@ -32,7 +32,7 @@ namespace System.Extensions
{
try
{
return action();
return this.action();
}
catch (Exception ex)
{
@@ -40,6 +40,7 @@ namespace System.Extensions
{
return catchAction(ex);
}
throw;
}
}
@@ -61,6 +62,7 @@ namespace System.Extensions
{
return catchAction(ex);
}
throw;
}
finally
@@ -68,5 +70,4 @@ namespace System.Extensions
act();
}
}
}
}
@@ -1,13 +1,12 @@
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace System.Http
namespace System.Net.Http;
public sealed class HttpClient<Tscope> : IHttpClient<Tscope>, IDisposable
{
public sealed class HttpClient<Tscope> : IHttpClient<Tscope>, IDisposable
{
private readonly HttpClient httpClient;
private readonly Type scope;
private EventHandler<HttpClientEventMessage> eventEmitted;
@@ -213,5 +212,4 @@ namespace System.Http
{
this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url));
}
}
}
@@ -1,7 +1,7 @@
namespace System.Http
namespace System.Net.Http;
public sealed class HttpClientEventMessage
{
public sealed class HttpClientEventMessage
{
public Type Scope { get; }
public string Method { get; }
public string Url { get; }
@@ -12,5 +12,4 @@
this.Method = method;
this.Url = url;
}
}
}
@@ -1,13 +1,12 @@
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace System.Http
namespace System.Net.Http;
public interface IHttpClient<TScope>
{
public interface IHttpClient<TScope>
{
event EventHandler<HttpClientEventMessage> EventEmitted;
Uri BaseAddress { get; set; }
HttpRequestHeaders DefaultRequestHeaders { get; }
@@ -45,5 +44,4 @@ namespace System.Http
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
}
}
@@ -0,0 +1,76 @@
using Microsoft.Extensions.Logging;
using System.Extensions;
namespace System.Logging;
public struct ScopedLogger<T>
{
private readonly ILogger<T> logger;
private readonly string scope;
private readonly string flowId;
private ScopedLogger(ILogger<T> logger, string scope, string flowId)
{
this.logger = logger;
this.scope = scope;
this.flowId = flowId.IsNullOrWhiteSpace() ? string.Empty : $"[{flowId}] ";
}
public ScopedLogger<T> LogInformation(string message, params object[] parameters)
{
this.logger.LogInformation(this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> LogDebug(string message, params object[] parameters)
{
this.logger.LogDebug(this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> LogWarning(string message, params object[] parameters)
{
this.logger.LogWarning(this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> LogError(string message, params object[] parameters)
{
this.logger.LogError(this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> LogCritical(string message, params object[] parameters)
{
this.logger.LogCritical(this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> LogWarning(Exception e, string message, params object[] parameters)
{
this.logger.LogWarning(e, this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> LogError(Exception e, string message, params object[] parameters)
{
this.logger.LogError(e, this.CreateMessage(message), parameters);
return this;
}
public ScopedLogger<T> 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}";
}
public static ScopedLogger<T> Create(ILogger<T> logger, string scope, string flowId)
{
return new ScopedLogger<T>(logger, scope.ThrowIfNull(nameof(scope)), flowId);
}
}
@@ -1,7 +1,7 @@
namespace System.Structures.BitStructures
namespace System.Structures.BitStructures;
public struct Int32BitStruct : IEquatable<Int32BitStruct>
{
public struct Int32BitStruct : IEquatable<Int32BitStruct>
{
public Int32BitStruct(uint value) => this.Value = value;
public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } }
public uint Value { get; set; }
@@ -171,5 +171,4 @@
{
return (this.Value).GetHashCode();
}
}
}
@@ -1,9 +1,9 @@
using System;
namespace System.Structures.BitStructures
namespace System.Structures.BitStructures;
public struct Int64BitStruct : IEquatable<Int64BitStruct>
{
public struct Int64BitStruct : IEquatable<Int64BitStruct>
{
public Int64BitStruct(uint low, uint high)
{
this.Value = low + ((ulong)high << 32);
@@ -201,5 +201,4 @@ namespace System.Structures.BitStructures
{
return this.Value.GetHashCode();
}
}
}
@@ -2,13 +2,15 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RootNamespace>System</RootNamespace>
<Version>1.3.1</Version>
<Version>1.5</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the System namespace</Description>
</PropertyGroup>
<ItemGroup>
@@ -16,9 +18,11 @@
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
@@ -0,0 +1,26 @@
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace System;
/// <summary>
/// Async implementation of <see cref="Lazy{T}"/>.
/// </summary>
/// <remarks>
/// Credits: https://devblogs.microsoft.com/pfxteam/asynclazyt/
/// </remarks>
/// <typeparam name="T">Type of value to be returned.</typeparam>
public sealed class AsyncLazy<T> : Lazy<Task<T>>
{
public TaskAwaiter<T> GetAwaiter() => this.Value.GetAwaiter();
public AsyncLazy(Func<T> valueFactory)
: base(() => Task.Factory.StartNew(valueFactory))
{
}
public AsyncLazy(Func<Task<T>> taskFactory)
: base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap())
{
}
}
@@ -1,14 +1,14 @@
using System.Collections.Generic;
namespace System.Threading
namespace System.Threading;
/// <summary>
/// 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.
/// </summary>
public class PriorityThreadPool : IDisposable
{
/// <summary>
/// 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.
/// </summary>
public class PriorityThreadPool : IDisposable
{
private class QueueEntry : IComparable<QueueEntry>
{
public TaskPriority TaskPriority { get; }
@@ -42,6 +42,7 @@ namespace System.Threading
priority1 = 0;
break;
}
switch (other.TaskPriority)
{
case TaskPriority.Highest:
@@ -60,6 +61,7 @@ namespace System.Threading
priority2 = 0;
break;
}
if (priority1 == priority2)
{
return 0;
@@ -111,7 +113,6 @@ namespace System.Threading
private volatile PriorityQueue<QueueEntry> tasks;
private Thread observer;
private CancellationTokenSource observerCancellationTokenSource = new CancellationTokenSource();
private int maxThreads;
private readonly object tasksLock = new object();
private struct WorkerThread
{
@@ -152,17 +153,7 @@ namespace System.Threading
/// <summary>
/// Maximum amount of threads that the pool can utilize
/// </summary>
public int MaxThreads
{
set
{
maxThreads = value;
}
get
{
return maxThreads;
}
}
public int MaxThreads { set; get; }
#endregion
#region Constructors
/// <summary>
@@ -171,19 +162,20 @@ namespace System.Threading
/// </summary>
public PriorityThreadPool()
{
threadpool = new List<WorkerThread>();
tasks = new PriorityQueue<QueueEntry>();
maxThreads = System.Environment.ProcessorCount;
for (var i = 0; i < maxThreads; i++)
this.threadpool = new List<WorkerThread>();
this.tasks = new PriorityQueue<QueueEntry>();
this.MaxThreads = System.Environment.ProcessorCount;
for (var i = 0; i < this.MaxThreads; i++)
{
this.CreateAndStartWorkerThread();
}
observer = new Thread(() => ObserverLoop())
this.observer = new Thread(() => this.ObserverLoop())
{
Name = "ThreadPool ObserverThread",
Priority = ThreadPriority.BelowNormal
};
observer.Start();
this.observer.Start();
}
/// <summary>
/// Constructor that initializes a threadpool with a number of threads, all of the same priority.
@@ -191,17 +183,18 @@ namespace System.Threading
/// <param name="maxThreads">Maximum number of threads</param>
public PriorityThreadPool(int maxThreads)
{
threadpool = new List<WorkerThread>();
tasks = new PriorityQueue<QueueEntry>();
this.maxThreads = Math.Max(maxThreads, 1);
this.threadpool = new List<WorkerThread>();
this.tasks = new PriorityQueue<QueueEntry>();
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();
this.observer = new Thread(() => this.ObserverLoop());
this.observer.Name = "ThreadPool ObserverThread";
this.observer.Priority = ThreadPriority.BelowNormal;
this.observer.Start();
}
/// <summary>
/// Constructor for a manually-configured threadpool that runs a specified number of threads.
@@ -214,24 +207,28 @@ namespace System.Threading
/// <param name="highest">Number of threads with Highest priority.</param>
public PriorityThreadPool(int lowest, int belowNormal, int normal, int aboveNormal, int highest)
{
threadpool = new List<WorkerThread>();
tasks = new PriorityQueue<QueueEntry>();
this.threadpool = new List<WorkerThread>();
this.tasks = new PriorityQueue<QueueEntry>();
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);
@@ -247,13 +244,13 @@ namespace System.Threading
/// <param name="taskPriority">Priority of task. Affects its position into the queue.</param>
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority)
{
while (!Monitor.TryEnter(tasksLock))
while (!Monitor.TryEnter(this.tasksLock))
{
;
}
tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState));
Monitor.Exit(tasksLock);
this.tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState));
Monitor.Exit(this.tasksLock);
}
/// <summary>
/// Add a work item into the queue.
@@ -262,30 +259,30 @@ namespace System.Threading
/// <param name="callbackState">State used as parameter during invoke.</param>
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState)
{
QueueUserWorkItem(waitCallback, callbackState, TaskPriority.Normal);
this.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 = 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();
threadpool.Add(worker);
this.threadpool.Add(worker);
}
private void CreateAndStartWorkerThread()
{
var worker = new WorkerThread();
worker.Thread = new Thread(() => ThreadMainLoop(ref worker));
worker.Thread = new Thread(() => this.ThreadMainLoop(ref worker));
worker.Thread.Name = "ThreadPool WorkerThread";
worker.Running = true;
worker.CancellationTokenSource = new CancellationTokenSource();
worker.Thread.Start();
threadpool.Add(worker);
this.threadpool.Add(worker);
}
/// <summary>
/// Main loop that a thread from the pool is running.
@@ -303,7 +300,7 @@ namespace System.Threading
}
//Check if there are tasks
if (tasks.Count > 0)
if (this.tasks.Count > 0)
{
//If there are tasks, acquire a lock onto the list
//and try to dequeue the highest priority task.
@@ -311,22 +308,24 @@ namespace System.Threading
thisWorkerThread.Working = true;
QueueEntry task = null;
while (!Monitor.TryEnter(tasksLock))
while (!Monitor.TryEnter(this.tasksLock))
{
;
}
if (tasks.Count > 0)
if (this.tasks.Count > 0)
{
task = tasks.Dequeue();
task = this.tasks.Dequeue();
}
Monitor.Exit(tasksLock);
Monitor.Exit(this.tasksLock);
if (task != null)
{
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!");
var waitCallback = task.WaitCallback;
waitCallback.Invoke(task.Object);
}
thisWorkerThread.Working = false;
}
}
@@ -346,7 +345,7 @@ namespace System.Threading
//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)
if (this.observerCancellationTokenSource.Token.IsCancellationRequested)
{
return;
}
@@ -368,13 +367,14 @@ namespace System.Threading
{
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)
if (this.tasks.Count > 0)
{
statistics.PerformanceCounter++;
if (statistics.PerformanceCounter > 5)
@@ -392,22 +392,22 @@ namespace System.Threading
}
//This part of code adjusts thread priorities based on the current performance of the threadpool
if (tasks.Count > 0)
if (this.tasks.Count > 0)
{
//If there are tasks pending, find a thread with priority under Normal and upgrade its priority.
var t = FindThreadWithLowPriority();
var t = this.FindThreadWithLowPriority();
if (t != null)
{
UpgradeThreadPriority(t);
this.UpgradeThreadPriority(t);
}
}
else
{
//If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority.
var t = FindThreadWithAcceptablePriority();
var t = this.FindThreadWithAcceptablePriority();
if (t != null)
{
DowngradeThreadPriority(t);
this.DowngradeThreadPriority(t);
}
}
@@ -415,7 +415,7 @@ namespace System.Threading
//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)
if (this.threadpool.Count < this.MaxThreads)
{
//Add a thread to the threadpool.
//Reset counter to 0.
@@ -425,13 +425,13 @@ namespace System.Threading
}
else if (statistics.PerformanceCounter <= -10)
{
if (threadpool.Count > maxThreads / 4)
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 = threadpool[threadpool.Count - 1];
var worker = this.threadpool[this.threadpool.Count - 1];
if (worker.Working)
{
worker.Running = false;
@@ -440,7 +440,8 @@ namespace System.Threading
{
worker.CancellationTokenSource.Cancel();
}
threadpool.RemoveAt(threadpool.Count - 1);
this.threadpool.RemoveAt(this.threadpool.Count - 1);
statistics.PerformanceCounter = 0;
}
}
@@ -452,13 +453,14 @@ namespace System.Threading
/// <returns>Thread with low priority.</returns>
private Thread FindThreadWithLowPriority()
{
foreach (var t in threadpool)
foreach (var t in this.threadpool)
{
if (t.Thread.Priority == ThreadPriority.Lowest || t.Thread.Priority == ThreadPriority.BelowNormal)
{
return t.Thread;
}
}
return null;
}
/// <summary>
@@ -467,13 +469,14 @@ namespace System.Threading
/// <returns>Thread with BelowNormal or Normal priority.</returns>
private Thread FindThreadWithAcceptablePriority()
{
foreach (var t in threadpool)
foreach (var t in this.threadpool)
{
if (t.Thread.Priority == ThreadPriority.Normal || t.Thread.Priority == ThreadPriority.BelowNormal)
{
return t.Thread;
}
}
return null;
}
/// <summary>
@@ -546,14 +549,17 @@ namespace System.Threading
this.observerCancellationTokenSource.Cancel();
this.observer.Join();
}
foreach (var worker in threadpool)
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;
@@ -565,8 +571,7 @@ namespace System.Threading
/// </summary>
public void Dispose()
{
Dispose(true);
this.Dispose(true);
}
#endregion
}
}
@@ -3,16 +3,16 @@ 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<int> avlTree = new AVLTree<int>();
[TestMethod()]
public void AVLTreeTest()
{
avlTree = new AVLTree<int>();
this.avlTree = new AVLTree<int>();
}
[TestMethod()]
@@ -22,14 +22,15 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i * 20 - (50 + i));
this.avlTree.Add(i * 20 - (50 + i));
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
if (avlTree.Count != 100)
if (this.avlTree.Count != 100)
{
Assert.Fail();
}
@@ -40,10 +41,10 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
if (!avlTree.Contains(50))
if (!this.avlTree.Contains(50))
{
Assert.Fail();
}
@@ -54,12 +55,12 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
avlTree.Remove(50);
this.avlTree.Remove(50);
if (avlTree.Contains(50))
if (this.avlTree.Contains(50))
{
Assert.Fail();
}
@@ -70,10 +71,11 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
avlTree.Clear();
if(avlTree.Count > 0)
this.avlTree.Clear();
if(this.avlTree.Count > 0)
{
Assert.Fail();
}
@@ -84,11 +86,11 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
var array = new int[100];
avlTree.CopyTo(array, 0);
this.avlTree.CopyTo(array, 0);
}
[TestMethod()]
@@ -96,16 +98,17 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
var count = 0;
foreach(var value in avlTree)
foreach(var value in this.avlTree)
{
count++;
System.Diagnostics.Debug.WriteLine(value);
}
if(count != avlTree.Count)
if(count != this.avlTree.Count)
{
Assert.Fail();
}
@@ -116,10 +119,10 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
var array = avlTree.ToArray();
_ = this.avlTree.ToArray();
}
[TestMethod()]
@@ -128,17 +131,18 @@ namespace System.Collections.Tests
var avlTree2 = new AVLTree<int>();
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
this.avlTree.Add(i);
}
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, avlTree);
serializer.Serialize(stream, this.avlTree);
stream.Position = 0;
avlTree2 = (AVLTree<int>)serializer.Deserialize(stream);
}
var avlTreeEnum = avlTree.GetEnumerator();
var avlTreeEnum = this.avlTree.GetEnumerator();
var avlTree2Enum = avlTree2.GetEnumerator();
for(var i = 0; i < 100; i++)
@@ -147,9 +151,9 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
avlTreeEnum.MoveNext();
avlTree2Enum.MoveNext();
}
}
}
}
@@ -3,23 +3,23 @@ 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<int> binaryHeap = new BinaryHeap<int>();
[TestMethod()]
public void BinaryHeapTest()
{
binaryHeap = new BinaryHeap<int>();
this.binaryHeap = new BinaryHeap<int>();
}
[TestMethod()]
public void BinaryHeapTest1()
{
binaryHeap = new BinaryHeap<int>(100);
if (binaryHeap.Count != 0 && binaryHeap.Capacity != 100)
this.binaryHeap = new BinaryHeap<int>(100);
if (this.binaryHeap.Count != 0 && this.binaryHeap.Capacity != 100)
{
Assert.Fail();
}
@@ -33,14 +33,15 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i * 20 - (50 + i));
this.binaryHeap.Add(i * 20 - (50 + i));
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
if (binaryHeap.Count != 100)
if (this.binaryHeap.Count != 100)
{
Assert.Fail();
}
@@ -52,14 +53,15 @@ namespace System.Collections.Tests
{
try
{
var tries = binaryHeap.Count;
while (binaryHeap.Count > 0)
var tries = this.binaryHeap.Count;
while (this.binaryHeap.Count > 0)
{
if (tries == 0)
{
Assert.Fail();
}
System.Diagnostics.Debug.WriteLine(binaryHeap.Remove());
System.Diagnostics.Debug.WriteLine(this.binaryHeap.Remove());
tries--;
}
}
@@ -74,9 +76,10 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i);
}
if (binaryHeap.Min != 0 || binaryHeap.Max != 999)
if (this.binaryHeap.Min != 0 || this.binaryHeap.Max != 999)
{
Assert.Fail();
}
@@ -87,10 +90,11 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i);
}
binaryHeap.Clear();
if (binaryHeap.Count > 0 || binaryHeap.Capacity != 160)
this.binaryHeap.Clear();
if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity != 160)
{
Assert.Fail();
}
@@ -101,20 +105,23 @@ namespace System.Collections.Tests
{
for (var i = 100; i < 200; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i);
}
binaryHeap.Clear(false);
var array = binaryHeap.ToArray();
if (binaryHeap.Count > 0 || binaryHeap.Capacity == 10)
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();
}
binaryHeap.Clear(true);
if (binaryHeap.Capacity != 10 || binaryHeap.Count != 0)
this.binaryHeap.Clear(true);
if (this.binaryHeap.Capacity != 10 || this.binaryHeap.Count != 0)
{
Assert.Fail();
}
@@ -123,8 +130,8 @@ namespace System.Collections.Tests
[TestMethod()]
public void ContainsTest()
{
binaryHeap.Add(100);
if (!binaryHeap.Contains(100))
this.binaryHeap.Add(100);
if (!this.binaryHeap.Contains(100))
{
Assert.Fail();
}
@@ -135,13 +142,15 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i);
}
var array = binaryHeap.ToArray();
if(array.Length != binaryHeap.Count)
var array = this.binaryHeap.ToArray();
if(array.Length != this.binaryHeap.Count)
{
Assert.Fail();
}
if(array[0] != 0 && array[999] != 999)
{
Assert.Fail();
@@ -153,16 +162,17 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i);
}
var count = 0;
foreach(var value in binaryHeap)
foreach(var value in this.binaryHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == binaryHeap.Count)
if(count == this.binaryHeap.Count)
{
return;
}
@@ -176,16 +186,17 @@ namespace System.Collections.Tests
var binaryHeap2 = new BinaryHeap<int>();
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i);
}
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream()) {
serializer.Serialize(stream, binaryHeap);
serializer.Serialize(stream, this.binaryHeap);
stream.Position = 0;
binaryHeap2 = (BinaryHeap<int>)serializer.Deserialize(stream);
}
var binaryHeapEnum = binaryHeap.GetEnumerator();
var binaryHeapEnum = this.binaryHeap.GetEnumerator();
var binaryHeapEnum2 = binaryHeap2.GetEnumerator();
for (var i = 0; i < 100; i++)
@@ -194,9 +205,9 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
binaryHeapEnum.MoveNext();
binaryHeapEnum2.MoveNext();
}
}
}
}
@@ -3,26 +3,26 @@ 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<int> fibonacciHeap = new FibonacciHeap<int>();
[TestMethod()]
public void InsertTest()
{
for (var i = 0; i < 1000; i++)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
}
[TestMethod()]
public void FibonacciHeapTest()
{
fibonacciHeap = new FibonacciHeap<int>();
if(fibonacciHeap.Count != 0)
this.fibonacciHeap = new FibonacciHeap<int>();
if(this.fibonacciHeap.Count != 0)
{
Assert.Fail();
}
@@ -59,24 +59,26 @@ namespace System.Collections.Tests
{
try
{
fibonacciHeap.Remove();
this.fibonacciHeap.Remove();
Assert.Fail();
}
catch(IndexOutOfRangeException exception)
catch (IndexOutOfRangeException)
{
}
catch(Exception e)
catch (Exception)
{
Assert.Fail();
}
for (var i = 0; i < 1000; i++)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
for (var i = 0; i < 1000; i++)
{
if (fibonacciHeap.Remove() != i)
if (this.fibonacciHeap.Remove() != i)
{
Assert.Fail();
}
@@ -86,16 +88,17 @@ namespace System.Collections.Tests
[TestMethod()]
public void DecreaseKeyTest()
{
fibonacciHeap.Add(5);
fibonacciHeap.Add(10);
fibonacciHeap.Add(7);
fibonacciHeap.DecreaseKey(5, 3);
if(fibonacciHeap.Contains(5) || !fibonacciHeap.Contains(3))
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();
}
fibonacciHeap.DecreaseKey(10, 1);
if(fibonacciHeap.Remove() != 1)
this.fibonacciHeap.DecreaseKey(10, 1);
if(this.fibonacciHeap.Remove() != 1)
{
Assert.Fail();
}
@@ -106,9 +109,10 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 10000; i++)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
if (!fibonacciHeap.Contains(5124))
if (!this.fibonacciHeap.Contains(5124))
{
Assert.Fail();
}
@@ -119,11 +123,12 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 10000; i++)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
fibonacciHeap.Remove();
fibonacciHeap.Clear();
if(fibonacciHeap.Count > 0)
this.fibonacciHeap.Remove();
this.fibonacciHeap.Clear();
if(this.fibonacciHeap.Count > 0)
{
Assert.Fail();
}
@@ -134,10 +139,11 @@ namespace System.Collections.Tests
{
for(var i = 999; i >= 0; i--)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
fibonacciHeap.Remove();
var arr = fibonacciHeap.ToArray();
this.fibonacciHeap.Remove();
var arr = this.fibonacciHeap.ToArray();
for(var i = 1; i < 512; i++)
{
@@ -153,18 +159,18 @@ namespace System.Collections.Tests
{
for (var i = 999; i >= 0; i--)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
var count = 0;
foreach(var value in fibonacciHeap)
foreach(var value in this.fibonacciHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == fibonacciHeap.Count)
if(count == this.fibonacciHeap.Count)
{
return;
}
@@ -178,17 +184,18 @@ namespace System.Collections.Tests
var fibonacciHeap2 = new FibonacciHeap<int>();
for (var i = 0; i < 100; i++)
{
fibonacciHeap.Add(i);
this.fibonacciHeap.Add(i);
}
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, fibonacciHeap);
serializer.Serialize(stream, this.fibonacciHeap);
stream.Position = 0;
fibonacciHeap2 = (FibonacciHeap<int>)serializer.Deserialize(stream);
}
var enum1 = fibonacciHeap.GetEnumerator();
var enum1 = this.fibonacciHeap.GetEnumerator();
var enum2 = fibonacciHeap2.GetEnumerator();
for (var i = 0; i < 100; i++)
@@ -197,9 +204,9 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
}
@@ -3,19 +3,19 @@ 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<int> priorityQueue = new PriorityQueue<int>();
[TestMethod()]
public void PriorityQueueTest()
{
try
{
priorityQueue = new PriorityQueue<int>();
if(priorityQueue.Count > 0)
this.priorityQueue = new PriorityQueue<int>();
if(this.priorityQueue.Count > 0)
{
Assert.Fail();
}
@@ -31,9 +31,10 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
this.priorityQueue.Enqueue(i);
}
if(priorityQueue.Count != 100)
if(this.priorityQueue.Count != 100)
{
Assert.Fail();
}
@@ -44,22 +45,25 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
this.priorityQueue.Enqueue(i);
}
for(var i = 0; i < 100; i++)
{
if(i != priorityQueue.Dequeue())
if(i != this.priorityQueue.Dequeue())
{
Assert.Fail();
}
}
if(priorityQueue.Count > 0)
if(this.priorityQueue.Count > 0)
{
Assert.Fail();
}
try
{
priorityQueue.Dequeue();
this.priorityQueue.Dequeue();
Assert.Fail();
}
catch
@@ -71,8 +75,8 @@ namespace System.Collections.Tests
[TestMethod()]
public void PeekTest()
{
priorityQueue.Enqueue(1051);
if(priorityQueue.Peek() != 1051 && priorityQueue.Count != 1)
this.priorityQueue.Enqueue(1051);
if(this.priorityQueue.Peek() != 1051 && this.priorityQueue.Count != 1)
{
Assert.Fail();
}
@@ -84,17 +88,18 @@ namespace System.Collections.Tests
var priorityQueue2 = new PriorityQueue<int>();
for (var i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
this.priorityQueue.Enqueue(i);
}
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, priorityQueue);
serializer.Serialize(stream, this.priorityQueue);
stream.Position = 0;
priorityQueue2 = (PriorityQueue<int>)serializer.Deserialize(stream);
}
var enum1 = priorityQueue.GetEnumerator();
var enum1 = this.priorityQueue.GetEnumerator();
var enum2 = priorityQueue2.GetEnumerator();
for (var i = 0; i < 100; i++)
@@ -103,9 +108,9 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
}
@@ -3,22 +3,22 @@ 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<int> skipList = new SkipList<int>();
[TestMethod()]
public void SkipListTest()
{
var skipList = new SkipList<int>();
_ = new SkipList<int>();
}
[TestMethod()]
public void SkipListTest2()
{
var skipList = new SkipList<int>(30);
_ = new SkipList<int>(30);
}
[TestMethod()]
@@ -26,7 +26,7 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
}
@@ -35,10 +35,11 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
skipList.Clear();
if(skipList.Count > 0)
this.skipList.Clear();
if(this.skipList.Count > 0)
{
Assert.Fail();
}
@@ -49,10 +50,10 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
if (!skipList.Contains(50))
if (!this.skipList.Contains(50))
{
Assert.Fail();
}
@@ -63,10 +64,11 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
var array = new int[skipList.Count];
skipList.CopyTo(array, 0);
var array = new int[this.skipList.Count];
this.skipList.CopyTo(array, 0);
for (var i = 0; i < 200; i++)
{
if(array[i] != i)
@@ -81,9 +83,10 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
var array = skipList.ToArray();
var array = this.skipList.ToArray();
for (var i = 0; i < 200; i++)
{
@@ -99,10 +102,10 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
foreach(var i in skipList)
foreach(var i in this.skipList)
{
System.Diagnostics.Debug.WriteLine(i);
}
@@ -113,10 +116,11 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
skipList.Remove(50);
if (skipList.Contains(50))
this.skipList.Remove(50);
if (this.skipList.Contains(50))
{
Assert.Fail();
}
@@ -129,17 +133,18 @@ namespace System.Collections.Tests
var skipList2 = new SkipList<int>();
for (var i = 0; i < 100; i++)
{
skipList.Add(i);
this.skipList.Add(i);
}
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, skipList);
serializer.Serialize(stream, this.skipList);
stream.Position = 0;
skipList2 = (SkipList<int>)serializer.Deserialize(stream);
}
var enum1 = skipList.GetEnumerator();
var enum1 = this.skipList.GetEnumerator();
var enum2 = skipList2.GetEnumerator();
for (var i = 0; i < 100; i++)
@@ -148,9 +153,9 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
}
@@ -3,16 +3,16 @@ 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<int> treap = new Treap<int>();
[TestMethod()]
public void TreapTest()
{
treap = new Treap<int>();
this.treap = new Treap<int>();
}
[TestMethod()]
@@ -21,18 +21,18 @@ namespace System.Collections.Tests
var random = new Random();
for(var i = 0; i < 1000; i++)
{
treap.Add(random.Next(0, 5000));
this.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)
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)
{
Assert.Fail();
}
@@ -44,10 +44,11 @@ namespace System.Collections.Tests
var random = new Random();
for (var i = 0; i < 100; i++)
{
treap.Add(random.Next(0, 5000));
this.treap.Add(random.Next(0, 5000));
}
treap.Clear();
if(treap.Count > 0)
this.treap.Clear();
if(this.treap.Count > 0)
{
Assert.Fail();
}
@@ -56,13 +57,13 @@ namespace System.Collections.Tests
[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))
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();
}
@@ -73,9 +74,10 @@ namespace System.Collections.Tests
{
for(var i = 0; i < 1000; i++)
{
treap.Add(i);
this.treap.Add(i);
}
var arr = treap.ToArray();
var arr = this.treap.ToArray();
for(var i = 0; i < 1000; i++)
{
if(arr[i] != i)
@@ -90,17 +92,17 @@ namespace System.Collections.Tests
{
for (var i = 0; i < 1000; i++)
{
treap.Add(i);
this.treap.Add(i);
}
var count = 0;
foreach(var value in treap)
foreach(var value in this.treap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == treap.Count)
if(count == this.treap.Count)
{
return;
}
@@ -115,17 +117,18 @@ namespace System.Collections.Tests
var treap2 = new Treap<int>();
for (var i = 0; i < 100; i++)
{
treap.Add(i);
this.treap.Add(i);
}
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, treap);
serializer.Serialize(stream, this.treap);
stream.Position = 0;
treap2 = (Treap<int>)serializer.Deserialize(stream);
}
var enum1 = treap.GetEnumerator();
var enum1 = this.treap.GetEnumerator();
var enum2 = treap2.GetEnumerator();
for (var i = 0; i < 100; i++)
@@ -134,9 +137,9 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
}
@@ -0,0 +1,42 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace System.Extensions.Tests;
[TestClass]
public class ObjectExtensionsTests
{
[TestMethod]
public void ThrowIfNull_NetCore_ThrowsWithCorrectName()
{
object obj = null;
try
{
System.Core.Extensions.ObjectExtensions.ThrowIfNull(obj);
}
catch (ArgumentNullException ex)
{
ex.ParamName.Should().Be("obj");
return;
}
Assert.Fail("Null object should throw");
}
[TestMethod]
public void ThrowIfNull_NetStandard_ThrowsWithCorrectName()
{
object obj = null;
try
{
ObjectExtensions.ThrowIfNull(obj, nameof(obj));
}
catch (ArgumentNullException ex)
{
ex.ParamName.Should().Be("obj");
return;
}
Assert.Fail("Null object should throw");
}
}
@@ -1,11 +1,11 @@
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()
{
@@ -107,5 +107,4 @@ namespace System.Extensions.Tests
newValue.Should().Be(string.Empty);
newNullValue.Should().Be(null);
}
}
}
@@ -1,11 +1,11 @@
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()
{
@@ -113,5 +113,4 @@ namespace System.Extensions.Tests
successOptional.Should().NotBeNull();
failureOptional.Should().NotBeNull();
}
}
}

Some files were not shown because too many files have changed in this diff Show More