Compare commits

...

46 Commits

Author SHA1 Message Date
dependabot[bot] 2cfbe56f8d Bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.5.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.2 to 17.5.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.3.2...v17.5.0)

---
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>
2023-02-21 11:06:34 +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
Alexandru Macocian 2944d9887e Update dependencies 2021-10-02 07:45:42 +02:00
amacocian 57925151fa Update dependencies (#10)
Fix code style
2021-09-16 13:56:05 +02:00
amacocian d20e5bd308 Fix CV extension (#9) 2021-08-18 16:34:54 +02:00
amacocian c9d1ba8773 Merge pull request #8 from AlexMacocian/alexmacocian/extend-cryptorngprovider
Extend CryptoRngProvider api
2021-07-15 16:33:28 +03:00
Alexandru Macocian ce3cac9fa2 Extend CryptoRngProvider api 2021-07-15 16:32:40 +03:00
amacocian a2d23ed716 Merge pull request #7 from AlexMacocian/alexmacocian/rngprovider-securestring
Implementation of SecureString and CryptoRngProvider
2021-07-15 16:19:32 +03:00
Alexandru Macocian 7660893087 Remove UTs expecting exception 2021-07-15 16:15:17 +03:00
Alexandru Macocian 68ec8f983d Implementation of SecureString and CryptoRngProvider 2021-07-15 16:11:05 +03:00
amacocian 1711dd2ec2 Merge pull request #6 from AlexMacocian/alexmacocian/serialization-extensions
Serialize and Deserialize extensions
2021-07-15 12:46:48 +03:00
Alexandru Macocian 3b67e45e64 Bump version 2021-07-15 12:41:47 +03:00
Alexandru Macocian 22fa8eccf7 Serialize and Deserialize extensions 2021-07-15 12:41:18 +03:00
amacocian 9609b2912c Merge pull request #5 from AlexMacocian/alexmacocian/security-package
SystemExtensions Security
2021-07-14 12:22:53 +03:00
Alexandru Macocian a2e99cb263 SystemExtensions Security 2021-07-14 12:17:31 +03:00
amacocian f9088a5aef Merge pull request #4 from AlexMacocian/alexmacocian/move-logger-resolver
Move logger resolver to System.Logging
2021-07-10 13:06:35 +03:00
Alexandru Macocian d67ee95916 Fix UTs 2021-07-10 13:02:54 +03:00
Alexandru Macocian 8bfb8f1757 Move logger resolver to System.Logging
Nit fixes
2021-07-10 13:01:47 +03:00
amacocian a6572a1d15 Merge pull request #3 from AlexMacocian/alexmacocian/move-di-config-namespace
Move configuration namespace to system
2021-07-10 11:29:20 +03:00
Alexandru Macocian 646b6dc253 Move configuration namespace to system 2021-07-10 11:24:37 +03:00
amacocian 0b2a76143b Merge pull request #2 from AlexMacocian/alexmacocian/di-extensions
Dependency Injection extensions
2021-07-10 11:15:48 +03:00
Alexandru Macocian 019d7e240d Stop CD pipeline from running on PR 2021-07-10 11:04:31 +03:00
111 changed files with 8809 additions and 6210 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"
+24 -17
View File
@@ -4,10 +4,7 @@ on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
@@ -24,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
@@ -48,17 +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: Push 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: Build SystemExtensions.NetStandard.Security project
run: dotnet build SystemExtensions.NetStandard.Security -c $env:Configuration
- name: Push 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.NetStandard
run: dotnet pack -c Release -o . SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
- name: Package SystemExtensions.NetCore
run: dotnet pack -c Release -o . SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
- 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
+7 -3
View File
@@ -22,19 +22,20 @@ jobs:
Solution_Path: SystemExtensions.sln
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
Sec_Test_Project_Path: SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.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,6 +46,9 @@ jobs:
- name: Execute DI Unit Tests
run: dotnet test $env:DI_Test_Project_Path
- name: Execute Security Unit Tests
run: dotnet test $env:Sec_Test_Project_Path
- name: Restore Project
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
env:
@@ -1,26 +1,25 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Extensions.Configuration;
using System.Configuration;
namespace SystemExtensions.DependencyInjection.Tests.Configuration
namespace SystemExtensions.DependencyInjection.Tests.Configuration;
[TestClass]
public class DefaultOptionsManagerTests
{
[TestClass]
public class DefaultOptionsManagerTests
private readonly DefaultOptionsManager optionsManager = new();
[TestMethod]
public void GetOptions_ReturnsDefault()
{
private readonly DefaultOptionsManager optionsManager = new();
var options = this.optionsManager.GetOptions<string>();
[TestMethod]
public void GetOptions_ReturnsDefault()
{
var options = this.optionsManager.GetOptions<string>();
options.Should().BeNull();
}
options.Should().BeNull();
}
[TestMethod]
public void UpdateOptions_Succeeds()
{
this.optionsManager.UpdateOptions(string.Empty);
}
[TestMethod]
public void UpdateOptions_Succeeds()
{
this.optionsManager.UpdateOptions(string.Empty);
}
}
@@ -1,6 +1,5 @@
namespace SystemExtensions.DependencyInjection.Tests.Configuration
namespace SystemExtensions.DependencyInjection.Tests.Configuration;
public sealed class DummyOptions
{
public sealed class DummyOptions
{
}
}
@@ -2,68 +2,67 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Extensions.Configuration;
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();
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
{
private readonly LiveOptionsResolver liveOptionsResolver = new();
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
var type = typeof(ILiveOptions<string>);
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
var canResolve = this.liveOptionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var type = typeof(ILiveOptions<string>);
var canResolve = this.liveOptionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var canResolve = this.liveOptionsResolver.CanResolve(type);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_ILiveOptions_ReturnsILiveOptions()
{
this.SetupServiceProvider();
var liveOptions = this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveOptions<string>));
liveOptions.Should().BeAssignableTo<ILiveOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_ILiveOptions_ReturnsILiveOptions()
{
this.SetupServiceProvider();
var liveOptions = this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveOptions<string>));
liveOptions.Should().BeAssignableTo<ILiveOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
}
}
@@ -2,68 +2,67 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Extensions.Configuration;
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();
[TestMethod]
public void CanResolve_ILiveUpdateableOptions_ReturnsTrue()
{
private readonly LiveUpdateableOptionsResolver liveUpdateableOptionsResolver = new();
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
var type = typeof(ILiveUpdateableOptions<string>);
[TestMethod]
public void CanResolve_ILiveUpdateableOptions_ReturnsTrue()
var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var type = typeof(ILiveUpdateableOptions<string>);
var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_ILiveUpdateableOptions_ReturnsILiveUpdateableOptions()
{
this.SetupServiceProvider();
var liveOptions = this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveUpdateableOptions<string>));
liveOptions.Should().BeAssignableTo<ILiveUpdateableOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_ILiveUpdateableOptions_ReturnsILiveUpdateableOptions()
{
this.SetupServiceProvider();
var liveOptions = this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveUpdateableOptions<string>));
liveOptions.Should().BeAssignableTo<ILiveUpdateableOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
}
}
@@ -1,44 +1,43 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Extensions.Configuration;
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();
[TestInitialize]
public void TestInitialize()
{
private LiveUpdateableOptionsWrapper<string> optionsWrapper;
private readonly Mock<IOptionsManager> optionsManagerMock = new();
this.optionsWrapper = new LiveUpdateableOptionsWrapper<string>(this.optionsManagerMock.Object);
}
[TestInitialize]
public void TestInitialize()
{
this.optionsWrapper = new LiveUpdateableOptionsWrapper<string>(this.optionsManagerMock.Object);
}
[TestMethod]
public void GetValue_ReturnsValue()
{
this.optionsManagerMock
.Setup(u => u.GetOptions<string>())
.Returns("hello");
[TestMethod]
public void GetValue_ReturnsValue()
{
this.optionsManagerMock
.Setup(u => u.GetOptions<string>())
.Returns("hello");
var value = this.optionsWrapper.Value;
var value = this.optionsWrapper.Value;
value.Should().Be("hello");
}
value.Should().Be("hello");
}
[TestMethod]
public void UpdateOption_CallsOptionsManager()
{
this.optionsManagerMock
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
.Verifiable();
[TestMethod]
public void UpdateOption_CallsOptionsManager()
{
this.optionsManagerMock
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
.Verifiable();
this.optionsWrapper.UpdateOption();
this.optionsWrapper.UpdateOption();
this.optionsManagerMock.Verify();
}
this.optionsManagerMock.Verify();
}
}
@@ -3,70 +3,68 @@ using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Extensions.Configuration;
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();
public Mock<IOptionsManager> OptionsManagerMock { get; } = new();
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
{
private readonly OptionsResolver optionsResolver = new();
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
var type = typeof(IOptions<string>);
public Mock<IOptionsManager> OptionsManagerMock => optionsManagerMock;
var canResolve = this.optionsResolver.CanResolve(type);
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(OptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var type = typeof(IOptions<string>);
var canResolve = this.optionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(OptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var canResolve = this.optionsResolver.CanResolve(type);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_IOptions_ReturnsIOptions()
{
this.SetupServiceProvider();
var liveOptions = this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IOptions<string>));
liveOptions.Should().BeAssignableTo<IOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.OptionsManagerMock.Object);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_IOptions_ReturnsIOptions()
{
this.SetupServiceProvider();
var liveOptions = this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IOptions<string>));
liveOptions.Should().BeAssignableTo<IOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.OptionsManagerMock.Object);
}
}
@@ -2,68 +2,67 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Extensions.Configuration;
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();
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
{
private readonly UpdateableOptionsResolver updateableOptionsResolver = new();
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<IOptionsManager> optionsManagerMock = new();
var type = typeof(IUpdateableOptions<string>);
[TestMethod]
public void CanResolve_ILiveOptions_ReturnsTrue()
var canResolve = this.updateableOptionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(UpdateableOptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var type = typeof(IUpdateableOptions<string>);
var canResolve = this.updateableOptionsResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(object), typeof(string), typeof(UpdateableOptionsResolverTests), typeof(int) };
foreach (var type in types)
{
var canResolve = this.updateableOptionsResolver.CanResolve(type);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_IUpdateableOptions_ReturnsIUpdateableOptions()
{
this.SetupServiceProvider();
var liveOptions = this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IUpdateableOptions<string>));
liveOptions.Should().BeAssignableTo<IUpdateableOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_IUpdateableOptions_ReturnsIUpdateableOptions()
{
this.SetupServiceProvider();
var liveOptions = this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IUpdateableOptions<string>));
liveOptions.Should().BeAssignableTo<IUpdateableOptions<string>>();
}
[TestMethod]
public void Resolve_AnythingElse_Throws()
{
this.SetupServiceProvider();
Action action = new(() =>
{
this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
private void SetupServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<IOptionsManager>())
.Returns(this.optionsManagerMock.Object);
}
}
@@ -2,46 +2,46 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
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;
private readonly Mock<IOptionsManager> optionsManagerMock = new();
[TestInitialize]
public void TestInitialize()
{
private const string Value = "hello";
this.optionsWrapper = new UpdateableOptionsWrapper<string>(this.optionsManagerMock.Object, Value);
}
private UpdateableOptionsWrapper<string> optionsWrapper;
private readonly Mock<IOptionsManager> optionsManagerMock = new();
[TestMethod]
public void GetValue_ReturnsValue()
{
this.optionsManagerMock
.Setup(u => u.GetOptions<string>())
.Throws<Exception>();
[TestInitialize]
public void TestInitialize()
{
this.optionsWrapper = new UpdateableOptionsWrapper<string>(optionsManagerMock.Object, Value);
}
var value = this.optionsWrapper.Value;
[TestMethod]
public void GetValue_ReturnsValue()
{
this.optionsManagerMock
.Setup(u => u.GetOptions<string>())
.Throws<Exception>();
value.Should().Be(Value);
}
var value = this.optionsWrapper.Value;
[TestMethod]
public void UpdateOption_CallsOptionsManager()
{
this.optionsManagerMock
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
.Verifiable();
value.Should().Be(Value);
}
this.optionsWrapper.UpdateOption();
[TestMethod]
public void UpdateOption_CallsOptionsManager()
{
this.optionsManagerMock
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
.Verifiable();
this.optionsWrapper.UpdateOption();
this.optionsManagerMock.Verify();
}
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,65 +5,64 @@ using System;
using System.Http;
using System.Net.Http;
namespace SystemExtensions.DependencyInjection.Tests.Http
namespace SystemExtensions.DependencyInjection.Tests.Http;
[TestClass]
public class HttpClientResolverTests
{
[TestClass]
public class HttpClientResolverTests
private readonly HttpClientResolver httpClientResolver = new();
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
[TestMethod]
public void CanResolve_IHttpClient_ReturnsTrue()
{
private readonly HttpClientResolver httpClientResolver = new();
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
var type = typeof(IHttpClient<>);
[TestMethod]
public void CanResolve_IHttpClient_ReturnsTrue()
var canResolve = this.httpClientResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(HttpClient), typeof(object), typeof(string), typeof(HttpClientResolverTests), typeof(int) };
foreach (var type in types)
{
var type = typeof(IHttpClient<>);
var canResolve = this.httpClientResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(HttpClient), typeof(object), typeof(string), typeof(HttpClientResolverTests), typeof(int) };
foreach (var type in types)
{
var canResolve = this.httpClientResolver.CanResolve(type);
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_TypedClient_ReturnsIHttpClient()
{
var client = this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<string>));
client.Should().BeAssignableTo<IHttpClient<string>>();
}
[TestMethod]
public void Resolve_NonGenericType_Throws()
{
Action action = new(() =>
{
this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<>));
});
action.Should().Throw<Exception>();
}
[TestMethod]
public void Resolve_RandomType_Throws()
{
Action action = new(() =>
{
this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void Resolve_TypedClient_ReturnsIHttpClient()
{
var client = this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<string>));
client.Should().BeAssignableTo<IHttpClient<string>>();
}
[TestMethod]
public void Resolve_NonGenericType_Throws()
{
Action action = new(() =>
{
this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<>));
});
action.Should().Throw<Exception>();
}
[TestMethod]
public void Resolve_RandomType_Throws()
{
Action action = new(() =>
{
this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
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,41 +3,40 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Logging;
namespace SystemExtensions.DependencyInjection.Tests.Logging
namespace SystemExtensions.DependencyInjection.Tests.Logging;
[TestClass]
public class CVLoggerProviderTests
{
[TestClass]
public class CVLoggerProviderTests
private readonly Mock<ILogsWriter> logsWriterMock = new();
private CVLoggerProvider cVLoggerProvider;
[TestInitialize]
public void TestInitialize()
{
private readonly Mock<ILogsWriter> logsWriterMock = new();
private CVLoggerProvider cVLoggerProvider;
this.cVLoggerProvider = new CVLoggerProvider(this.logsWriterMock.Object);
}
[TestInitialize]
public void TestInitialize()
{
this.cVLoggerProvider = new CVLoggerProvider(this.logsWriterMock.Object);
}
[TestMethod]
public void CreateLogger_CreatesNewLogger()
{
var logger = this.cVLoggerProvider.CreateLogger(string.Empty);
[TestMethod]
public void CreateLogger_CreatesNewLogger()
{
var logger = this.cVLoggerProvider.CreateLogger(string.Empty);
logger.Should().NotBeNull();
}
logger.Should().NotBeNull();
}
[TestMethod]
public void LogEntry_CallsLogWriter()
{
this.cVLoggerProvider.LogEntry(new Log());
[TestMethod]
public void LogEntry_CallsLogWriter()
{
this.cVLoggerProvider.LogEntry(new Log());
this.logsWriterMock.Verify();
}
this.logsWriterMock.Verify();
}
private void SetupLogsWriter()
{
this.logsWriterMock
.Setup(u => u.WriteLog(It.IsAny<Log>()))
.Verifiable();
}
private void SetupLogsWriter()
{
this.logsWriterMock
.Setup(u => u.WriteLog(It.IsAny<Log>()))
.Verifiable();
}
}
@@ -5,72 +5,71 @@ using Moq;
using System;
using System.Logging;
namespace SystemExtensions.DependencyInjection.Tests.Logging
namespace SystemExtensions.DependencyInjection.Tests.Logging;
[TestClass]
public class CVLoggerTests
{
[TestClass]
public class CVLoggerTests
private readonly Mock<ICVLoggerProvider> cvLoggerProviderMock = new();
private CVLogger cVLogger;
[TestInitialize]
public void TestInitialize()
{
private readonly Mock<ICVLoggerProvider> cvLoggerProviderMock = new();
private CVLogger cVLogger;
this.cVLogger = new CVLogger(string.Empty, this.cvLoggerProviderMock.Object);
}
[TestInitialize]
public void TestInitialize()
[TestMethod]
public void BeginScope_ReturnsNull()
{
var scope = this.cVLogger.BeginScope(string.Empty);
scope.Should().BeNull();
}
[TestMethod]
[DataRow(LogLevel.Debug)]
[DataRow(LogLevel.Trace)]
[DataRow(LogLevel.Information)]
[DataRow(LogLevel.Warning)]
[DataRow(LogLevel.Error)]
[DataRow(LogLevel.Critical)]
public void IsEnabled_OnAllLogLevels_ReturnsTrue(LogLevel logLevel)
{
var enabled = this.cVLogger.IsEnabled(logLevel);
enabled.Should().BeTrue();
}
[TestMethod]
public void Log_CallsFormatter()
{
var called = false;
Func<string, Exception, string> messageFormatter = new((state, exception) =>
{
this.cVLogger = new CVLogger(string.Empty, this.cvLoggerProviderMock.Object);
}
called = true;
return string.Empty;
});
[TestMethod]
public void BeginScope_ReturnsNull()
{
var scope = this.cVLogger.BeginScope(string.Empty);
this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), messageFormatter);
scope.Should().BeNull();
}
called.Should().BeTrue();
}
[TestMethod]
[DataRow(LogLevel.Debug)]
[DataRow(LogLevel.Trace)]
[DataRow(LogLevel.Information)]
[DataRow(LogLevel.Warning)]
[DataRow(LogLevel.Error)]
[DataRow(LogLevel.Critical)]
public void IsEnabled_OnAllLogLevels_ReturnsTrue(LogLevel logLevel)
{
var enabled = this.cVLogger.IsEnabled(logLevel);
[TestMethod]
public void Log_CallsLogsProvider()
{
this.SetupLoggerProvider();
enabled.Should().BeTrue();
}
this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), new Func<string, Exception, string>((s, e) => string.Empty));
[TestMethod]
public void Log_CallsFormatter()
{
var called = false;
Func<string, Exception, string> messageFormatter = new((state, exception) =>
{
called = true;
return string.Empty;
});
this.cvLoggerProviderMock.Verify();
}
this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), messageFormatter);
called.Should().BeTrue();
}
[TestMethod]
public void Log_CallsLogsProvider()
{
this.SetupLoggerProvider();
this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), new Func<string, Exception, string>((s, e) => string.Empty));
this.cvLoggerProviderMock.Verify();
}
private void SetupLoggerProvider()
{
this.cvLoggerProviderMock
.Setup(u => u.LogEntry(It.IsAny<Log>()))
.Verifiable();
}
private void SetupLoggerProvider()
{
this.cvLoggerProviderMock
.Setup(u => u.LogEntry(It.IsAny<Log>()))
.Verifiable();
}
}
@@ -3,28 +3,27 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Logging;
namespace SystemExtensions.DependencyInjection.Tests.Logging
namespace SystemExtensions.DependencyInjection.Tests.Logging;
[TestClass]
public class DebugLogsWriterTests
{
[TestClass]
public class DebugLogsWriterTests
private readonly DebugLogsWriter logsWriter = new();
[TestMethod]
public void WriteLog_Succeeds()
{
private readonly DebugLogsWriter logsWriter = new();
this.logsWriter.WriteLog(new Log());
}
[TestMethod]
public void WriteLog_Succeeds()
[TestMethod]
public void WriteNullLog_Throws()
{
Action action = new(() =>
{
this.logsWriter.WriteLog(new Log());
}
this.logsWriter.WriteLog(null);
});
[TestMethod]
public void WriteNullLog_Throws()
{
Action action = new(() =>
{
this.logsWriter.WriteLog(null);
});
action.Should().Throw<Exception>();
}
action.Should().Throw<Exception>();
}
}
@@ -4,106 +4,104 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Logging;
using System.Windows.Extensions.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();
private readonly LoggerResolver loggerResolver = new();
[TestMethod]
public void CanResolve_ILogger_ReturnsTrue()
{
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
private readonly Mock<ILoggerFactory> loggerFactoryMock = new();
private readonly Mock<ILogger> loggerMock = new();
private readonly LoggerResolver loggerResolver = new();
var type = typeof(ILogger);
[TestMethod]
public void CanResolve_ILogger_ReturnsTrue()
var canResolve = this.loggerResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_GenericILogger_ReturnsTrue()
{
var type = typeof(ILogger<string>);
var canResolve = this.loggerResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
{
var types = new Type[] { typeof(CVLogger), typeof(object), typeof(string), typeof(LoggerResolverTests), typeof(int) };
foreach(var type in types)
{
var type = typeof(ILogger);
var canResolve = this.loggerResolver.CanResolve(type);
canResolve.Should().BeTrue();
}
canResolve.Should().BeFalse();
}
}
[TestMethod]
public void CanResolve_GenericILogger_ReturnsTrue()
[TestMethod]
public void Resolve_ILogger_ReturnsILogger()
{
this.SetupIServiceProvider();
var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger));
logger.Should().BeAssignableTo<ILogger>();
}
[TestMethod]
public void Resolve_TypedILogger_ReturnsTypedILogger()
{
this.SetupIServiceProvider();
var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<string>));
logger.Should().BeAssignableTo<ILogger<string>>();
}
[TestMethod]
public void Resolve_RandomType_Throws()
{
this.SetupIServiceProvider();
Action action = new(() =>
{
var type = typeof(ILogger<string>);
this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
var canResolve = this.loggerResolver.CanResolve(type);
action.Should().Throw<Exception>();
}
canResolve.Should().BeTrue();
}
[TestMethod]
public void Resolve_NonTypedGeneric_Throws()
{
this.SetupIServiceProvider();
[TestMethod]
public void CanResolve_AnythingElse_ReturnsFalse()
Action action = new(() =>
{
var types = new Type[] { typeof(CVLogger), typeof(object), typeof(string), typeof(LoggerResolverTests), typeof(int) };
this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<>));
});
foreach(var type in types)
{
var canResolve = this.loggerResolver.CanResolve(type);
action.Should().Throw<Exception>();
}
canResolve.Should().BeFalse();
}
}
private void SetupIServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<ILoggerFactory>())
.Returns(this.loggerFactoryMock.Object);
[TestMethod]
public void Resolve_ILogger_ReturnsILogger()
{
this.SetupIServiceProvider();
var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger));
logger.Should().BeAssignableTo<ILogger>();
}
[TestMethod]
public void Resolve_TypedILogger_ReturnsTypedILogger()
{
this.SetupIServiceProvider();
var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<string>));
logger.Should().BeAssignableTo<ILogger<string>>();
}
[TestMethod]
public void Resolve_RandomType_Throws()
{
this.SetupIServiceProvider();
Action action = new(() =>
{
this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
});
action.Should().Throw<Exception>();
}
[TestMethod]
public void Resolve_NonTypedGeneric_Throws()
{
this.SetupIServiceProvider();
Action action = new(() =>
{
this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<>));
});
action.Should().Throw<Exception>();
}
private void SetupIServiceProvider()
{
this.serviceProviderMock
.Setup(u => u.GetService<ILoggerFactory>())
.Returns(this.loggerFactoryMock.Object);
this.loggerFactoryMock
.Setup(u => u.CreateLogger(It.IsAny<string>()))
.Returns(this.loggerMock.Object);
}
this.loggerFactoryMock
.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.5.0" />
<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,14 +1,13 @@
namespace System.Extensions.Configuration
{
public sealed class DefaultOptionsManager : IOptionsManager
{
public T GetOptions<T>() where T : class
{
return default;
}
namespace System.Configuration;
public void UpdateOptions<T>(T value) where T : class
{
}
public sealed class DefaultOptionsManager : IOptionsManager
{
public T GetOptions<T>() where T : class
{
return default;
}
public void UpdateOptions<T>(T value) where T : class
{
}
}
@@ -1,9 +1,8 @@
using Microsoft.Extensions.Options;
namespace System.Extensions.Configuration
namespace System.Configuration;
public interface ILiveOptions<T> : IOptions<T>
where T : class
{
public interface ILiveOptions<T> : IOptions<T>
where T : class
{
}
}
@@ -1,7 +1,6 @@
namespace System.Extensions.Configuration
namespace System.Configuration;
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
where T : class
{
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
where T : class
{
}
}
@@ -1,10 +1,9 @@
namespace System.Extensions.Configuration
namespace System.Configuration;
public interface IOptionsManager
{
public interface IOptionsManager
{
T GetOptions<T>()
where T : class;
void UpdateOptions<T>(T value)
where T : class;
}
T GetOptions<T>()
where T : class;
void UpdateOptions<T>(T value)
where T : class;
}
@@ -1,13 +1,12 @@
using Microsoft.Extensions.Options;
namespace System.Extensions.Configuration
namespace System.Configuration;
public interface IUpdateableOptions<out T> : IOptions<T>
where T : class
{
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();
}
/// <summary>
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
/// </summary>
void UpdateOption();
}
@@ -1,27 +1,26 @@
using Slim.Resolvers;
namespace System.Extensions.Configuration
namespace System.Configuration;
public sealed class LiveOptionsResolver : IDependencyResolver
{
public sealed class LiveOptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return false;
}
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
}
@@ -1,26 +1,25 @@
using Slim.Resolvers;
namespace System.Extensions.Configuration
namespace System.Configuration;
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
{
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
return false;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
}
@@ -1,31 +1,30 @@
using System.Extensions;
namespace System.Extensions.Configuration
namespace System.Configuration;
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
where T : class
{
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
where T : class
private readonly IOptionsManager configurationManager;
private T value;
public T Value
{
private readonly IOptionsManager configurationManager;
private T value;
public T Value
get
{
get
{
this.value = this.configurationManager.GetOptions<T>();
return this.value;
}
}
public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions<T>(this.value);
this.value = this.configurationManager.GetOptions<T>();
return this.value;
}
}
public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions<T>(this.value);
}
}
@@ -1,33 +1,32 @@
using Microsoft.Extensions.Options;
using Slim.Resolvers;
namespace System.Extensions.Configuration
namespace System.Configuration;
public sealed class OptionsResolver : IDependencyResolver
{
public sealed class OptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(OptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(OptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return false;
}
return Activator.CreateInstance(typedOptionsType, optionsValue);
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return Activator.CreateInstance(typedOptionsType, optionsValue);
}
}
@@ -1,32 +1,32 @@
using Slim.Resolvers;
using System.Extensions.Configuration;
namespace System.Extensions.Configuration
namespace System.Configuration;
public sealed class UpdateableOptionsResolver : IDependencyResolver
{
public sealed class UpdateableOptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return false;
}
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
}
}
@@ -1,23 +1,22 @@
using System.Extensions;
using System.Configuration;
namespace System.Extensions.Configuration
namespace System.Extensions.Configuration;
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
where T : class
{
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
where T : class
private readonly IOptionsManager configurationManager;
public T Value { get; }
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
{
private readonly IOptionsManager configurationManager;
public T Value { get; }
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.Value = options;
}
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.Value = options;
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions(this.Value);
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions(this.Value);
}
}
@@ -1,142 +1,189 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Slim;
using System.Extensions;
using System.Extensions.Configuration;
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 IServiceProducer RegisterOptionsManager(this IServiceProducer serviceProducer)
{
/// <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)
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
serviceProducer.RegisterOptionsResolver();
return serviceProducer;
}
/// <summary>
/// Registers a <see cref="IOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <typeparam name="T">Implementation of <see cref="IOptionsManager"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceProducer RegisterOptionsManager<T>(this IServiceProducer serviceProducer)
where T : IOptionsManager
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterSingleton<IOptionsManager, T>();
serviceProducer.RegisterOptionsResolver();
return serviceProducer;
}
/// <summary>
/// Registers resolvers for <see cref="IOptions{TOptions}"/> and <see cref="IUpdateableOptions{T}"/>.
/// Depends on a <see cref="IOptionsManager"/> in order to properly resolve options.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns><see cref="IServiceManager"/>.</returns>
public static IServiceProducer RegisterOptionsResolver(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterResolver(new OptionsResolver());
serviceProducer.RegisterResolver(new UpdateableOptionsResolver());
serviceProducer.RegisterResolver(new LiveOptionsResolver());
serviceProducer.RegisterResolver(new LiveUpdateableOptionsResolver());
return serviceProducer;
}
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
serviceManager.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
serviceManager.RegisterOptionsResolver();
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return factory;
});
return serviceManager;
}
return serviceManager;
}
/// <summary>
/// Registers a <see cref="IOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <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)
where T : IOptionsManager
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : TILogsWriter
where TILogsWriter : class, ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
serviceManager.RegisterSingleton<IOptionsManager, T>();
serviceManager.RegisterOptionsResolver();
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
return factory;
});
return serviceManager;
}
return serviceManager;
}
/// <summary>
/// Registers resolvers for <see cref="IOptions{TOptions}"/> and <see cref="IUpdateableOptions{T}"/>.
/// Depends on a <see cref="IOptionsManager"/> in order to properly resolve options.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns><see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsResolver(this IServiceManager serviceManager)
/// <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)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
serviceManager.ThrowIfNull(nameof(serviceManager));
LoggerFactory loggerFactory = new();
loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return loggerFactory;
});
serviceManager.RegisterResolver(new OptionsResolver());
serviceManager.RegisterResolver(new UpdateableOptionsResolver());
serviceManager.RegisterResolver(new LiveOptionsResolver());
serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver());
return serviceProducer;
}
return 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)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceProducer;
}
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return factory;
});
/// <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)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
return serviceManager;
}
serviceProducer.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceProducer;
}
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : TILogsWriter
where TILogsWriter : class, ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
/// <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)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
return factory;
});
return new HttpClientBuilder<T>(serviceProducer);
}
return serviceManager;
}
[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));
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
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));
serviceManager.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceManager;
}
public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceManager;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterResolver(new HttpClientResolver());
return serviceManager;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory(handlerFactory));
return serviceManager;
}
serviceProducer.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory(handlerFactory));
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,46 +2,46 @@
using System.Linq;
using System.Net.Http;
namespace System.Http
namespace System.Http;
[Obsolete($"Please use {nameof(Extensions.ServiceManagerExtensions.RegisterHttpClient)} for each use case of {nameof(IHttpClient<object>)}")]
public sealed class HttpClientResolver : IDependencyResolver
{
public sealed class HttpClientResolver : IDependencyResolver
private static readonly Type clientType = typeof(HttpClient<>);
/// <summary>
/// Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.
/// </summary>
public Func<Slim.IServiceProvider, Type, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
/// <summary>
/// Sets the <see cref="HttpMessageHandlerFactory"/>.
/// </summary>
/// <param name="factory">Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.</param>
/// <returns></returns>
public HttpClientResolver WithHttpMessageHandlerFactory(Func<Slim.IServiceProvider, Type, HttpMessageHandler> factory)
{
private static readonly Type clientType = typeof(HttpClient<>);
this.HttpMessageHandlerFactory = factory;
return this;
}
/// <summary>
/// Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.
/// </summary>
public Func<Slim.IServiceProvider, Type, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
/// <summary>
/// Sets the <see cref="HttpMessageHandlerFactory"/>.
/// </summary>
/// <param name="factory">Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.</param>
/// <returns></returns>
public HttpClientResolver WithHttpMessageHandlerFactory(Func<Slim.IServiceProvider, Type, HttpMessageHandler> factory)
public bool CanResolve(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
{
this.HttpMessageHandlerFactory = factory;
return this;
return true;
}
public bool CanResolve(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
{
return true;
}
return false;
}
return false;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedClientType = clientType.MakeGenericType(type.GetGenericArguments());
var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First());
var httpClient = handler is null ?
Activator.CreateInstance(typedClientType) :
Activator.CreateInstance(typedClientType, new object[] { handler });
return httpClient;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedClientType = clientType.MakeGenericType(type.GetGenericArguments());
var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First());
var httpClient = handler is null ?
Activator.CreateInstance(typedClientType) :
Activator.CreateInstance(typedClientType, new object[] { handler });
return httpClient;
}
}
@@ -1,44 +1,43 @@
using Microsoft.Extensions.Logging;
using System.Extensions;
namespace System.Logging
namespace System.Logging;
public sealed class CVLogger : ILogger
{
public sealed class CVLogger : ILogger
private readonly string category;
private readonly ICVLoggerProvider cvLoggerProvider;
public CVLogger(string category, ICVLoggerProvider cvLoggerProvider)
{
private readonly string category;
private readonly ICVLoggerProvider cvLoggerProvider;
this.category = category;
this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider));
}
public CVLogger(string category, ICVLoggerProvider cvLoggerProvider)
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var message = formatter(state, exception);
var log = new Log
{
this.category = category;
this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider));
}
Exception = exception,
LogLevel = logLevel,
EventId = eventId.Name,
Message = message,
Category = category,
LogTime = DateTime.Now
};
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var message = formatter(state, exception);
var log = new Log
{
Exception = exception,
LogLevel = logLevel,
EventId = eventId.Name,
Message = message,
Category = category,
LogTime = DateTime.Now
};
this.cvLoggerProvider.LogEntry(log);
}
this.cvLoggerProvider.LogEntry(log);
}
}
@@ -2,43 +2,37 @@
using Microsoft.Extensions.Logging;
using System.Extensions;
namespace System.Logging
namespace System.Logging;
public sealed class CVLoggerProvider : ICVLoggerProvider
{
public sealed class CVLoggerProvider : ICVLoggerProvider
private readonly ILogsWriter logsManager;
private readonly CorrelationVector correlationVector;
public CVLoggerProvider(ILogsWriter logsWriter)
{
private readonly ILogsWriter logsManager;
private CorrelationVector correlationVector;
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
this.correlationVector = new CorrelationVector();
}
public CVLoggerProvider(ILogsWriter logsWriter)
public void LogEntry(Log log)
{
if (this.correlationVector is not null)
{
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
this.correlationVector = new CorrelationVector();
log.CorrelationVector = this.correlationVector.Value.ToString();
this.correlationVector.Increment();
}
public void LogEntry(Log log)
{
if (this.correlationVector is not null)
{
log.CorrelationVector = this.correlationVector.Value.ToString();
this.correlationVector.Increment();
}
this.logsManager.WriteLog(log);
}
this.logsManager.WriteLog(log);
}
public ILogger CreateLogger(string categoryName)
{
return new CVLogger(categoryName, this);
}
public ILogger CreateLogger(string categoryName)
{
if (this.correlationVector is not null)
{
this.correlationVector = CorrelationVector.Extend(this.correlationVector.ToString());
}
return new CVLogger(categoryName, this);
}
public void Dispose()
{
throw new System.NotImplementedException();
}
public void Dispose()
{
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)
{
public void WriteLog(Log log)
{
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
}
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
}
}
@@ -1,9 +1,8 @@
using Microsoft.Extensions.Logging;
namespace System.Logging
namespace System.Logging;
public interface ICVLoggerProvider : ILoggerProvider
{
public interface ICVLoggerProvider : ILoggerProvider
{
void LogEntry(Log log);
}
void LogEntry(Log log);
}
@@ -1,7 +1,6 @@
namespace System.Logging
namespace System.Logging;
public interface ILogsWriter
{
public interface ILogsWriter
{
void WriteLog(Log log);
}
void WriteLog(Log log);
}
@@ -2,49 +2,48 @@
using Slim.Resolvers;
using System.Linq;
namespace System.Windows.Extensions.Logging
namespace System.Logging;
public sealed class LoggerResolver : IDependencyResolver
{
public sealed class LoggerResolver : IDependencyResolver
public bool CanResolve(Type type)
{
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
type == typeof(ILogger))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
type == typeof(ILogger))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
{
return ResolveScopedLogger(serviceProvider, type);
}
else if (type == typeof(ILogger))
{
return ResolveLogger(serviceProvider, type);
}
else
{
throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}");
}
}
return false;
}
private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type)
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var categoryTypes = type.GetGenericArguments();
var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First();
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
return ResolveScopedLogger(serviceProvider, type);
}
private static object ResolveLogger(Slim.IServiceProvider serviceProvider, Type type)
else if (type == typeof(ILogger))
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
return ResolveLogger(serviceProvider);
}
else
{
throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}");
}
}
private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var categoryTypes = type.GetGenericArguments();
var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First();
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
}
private static object ResolveLogger(Slim.IServiceProvider serviceProvider)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
}
}
@@ -1,15 +1,14 @@
using Microsoft.Extensions.Logging;
namespace System.Logging
namespace System.Logging;
public sealed record Log
{
public sealed record Log
{
public Exception Exception { get; set; }
public DateTime LogTime { get; set; }
public string Category { get; set; }
public string EventId { get; set; }
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public string CorrelationVector { get; set; }
}
public Exception Exception { get; set; }
public DateTime LogTime { get; set; }
public string Category { get; set; }
public string EventId { get; set; }
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public string CorrelationVector { get; set; }
}
@@ -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.0.0</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.1" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
<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>
@@ -0,0 +1,104 @@
using FluentAssertions;
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;
namespace SystemExtensions.NetStandard.Security.Tests;
[TestClass]
public class AesEncrypterTests
{
private ISymmetricEncrypter symmetricEncrypter;
private string keyString;
private byte[] keyBytes;
private byte[] ivBytes;
private string ivString;
private string toEncryptString;
private byte[] toEncryptBytes;
[TestInitialize]
public void TestInitialize()
{
this.symmetricEncrypter = new AesEncrypter();
this.keyBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
this.keyString = Convert.ToBase64String(this.keyBytes);
this.ivBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
this.ivString = Convert.ToBase64String(this.ivBytes);
this.toEncryptBytes = Encoding.UTF8.GetBytes("toEncrypt");
this.toEncryptString = Convert.ToBase64String(this.toEncryptBytes);
}
[TestMethod]
public async Task EncryptDecryptStringWithStringKeyStringIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptString).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
this.toEncryptString.Should().Be(decrypted);
}
[TestMethod]
public async Task EncryptDecryptStringWithByteKeyByteIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptString).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
this.toEncryptString.Should().Be(decrypted);
}
[TestMethod]
public async Task EncryptDecryptByteWithStringKeyStringIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptBytes).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
}
[TestMethod]
public async Task EncryptDecryptByteWithByteKeyByteIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptBytes).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
}
[TestMethod]
public async Task EncryptDecryptStreamWithStringKeyStringIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
encrypted.Position = 0;
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
}
[TestMethod]
public async Task EncryptDecryptStreamWithByteKeyByteIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
encrypted.Position = 0;
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
}
[TestMethod]
public void GetEncryptionStreamReturnsCryptoStream()
{
var encryptionStream = this.symmetricEncrypter.GetEncryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
encryptionStream.Should().BeAssignableTo<CryptoStream>();
}
[TestMethod]
public void GetDecryptionStreamReturnsCryptoStream()
{
var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
encryptionStream.Should().BeAssignableTo<CryptoStream>();
}
}
@@ -0,0 +1,54 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Security.Rng;
namespace SystemExtensions.NetStandard.Security.Tests;
[TestClass]
public class CryptoRngProviderTests
{
private CryptoRngProvider cryptoRngProvider;
[TestInitialize]
public void TestInitialize()
{
this.cryptoRngProvider = new CryptoRngProvider();
}
[TestMethod]
public void GetBytes_ShouldSetValues()
{
var bytes = new byte[100];
this.cryptoRngProvider.GetBytes(bytes);
bytes.All(b => b == 0).Should().BeFalse();
}
[TestMethod]
public void GetNonZeroBytes_ShouldSetNonZeroValues()
{
var bytes = new byte[100];
this.cryptoRngProvider.GetNonZeroBytes(bytes);
bytes.All(b => b != 0).Should().BeTrue();
}
[TestMethod]
public void GetBytes_ShouldReturnBytes()
{
var bytes = this.cryptoRngProvider.GetBytes(10);
bytes.Length.Should().Be(10);
}
[TestMethod]
public void GetNonZeroBytes_ShouldReturnBytes()
{
var bytes = this.cryptoRngProvider.GetNonZeroBytes(10);
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();
}
}
@@ -0,0 +1,121 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Encryption;
namespace SystemExtensions.NetStandard.Security.Tests;
[TestClass]
public class SecureStringTests
{
[TestMethod]
public void SecureString_NewSecureString_ReturnsValue()
{
var str = new SecureString("hello");
str.Value.Should().Be("hello");
}
[TestMethod]
public void SecureStringEmpty_AreEqual()
{
var str = SecureString.Empty;
str.Should().Be(SecureString.Empty);
}
[TestMethod]
public void SecureStringEmpty_Equals_StringEmpty()
{
var ss = SecureString.Empty;
var s = string.Empty;
ss.Should().Be(s);
}
[TestMethod]
public void SecureString_Equals_OtherSecureString()
{
var ss1 = new SecureString("Hello");
var ss2 = new SecureString("Hello");
ss1.Equals(ss2).Should().BeTrue();
}
[TestMethod]
[DataRow("hello", "hello", true)]
[DataRow("hello", "henlo", false)]
public void SecureString_EqualOperator_OtherSecureString(string str1, string str2, bool isEqual)
{
var ss1 = new SecureString(str1);
var ss2 = new SecureString(str2);
(ss1 == ss2).Should().Be(isEqual);
}
[TestMethod]
[DataRow("hello", "hello", false)]
[DataRow("hello", "henlo", true)]
public void SecureString_DifferentOperator_OtherSecureString(string str1, string str2, bool isDifferent)
{
var ss1 = new SecureString(str1);
var ss2 = new SecureString(str2);
(ss1 != ss2).Should().Be(isDifferent);
}
[TestMethod]
[DataRow("hello", "hello", true)]
[DataRow("hello", "henlo", false)]
public void SecureString_EqualOperator_String(string str1, string str2, bool isEqual)
{
var ss1 = new SecureString(str1);
(ss1 == str2).Should().Be(isEqual);
}
[TestMethod]
[DataRow("hello", "hello", false)]
[DataRow("hello", "henlo", true)]
public void SecureString_DifferentOperator_String(string str1, string str2, bool isDifferent)
{
var ss1 = new SecureString(str1);
(ss1 != str2).Should().Be(isDifferent);
}
[TestMethod]
public void SecureString_PlusOperator_SecureString()
{
var ss1 = new SecureString("Hello ");
var ss2 = new SecureString("World");
(ss1 + ss2).Should().Be("Hello World");
}
[TestMethod]
public void SecureString_PlusOperator_String()
{
var ss1 = new SecureString("Hello ");
var ss2 = "World";
(ss1 + ss2).Should().Be("Hello World");
}
[TestMethod]
public void SecureString_PlusOperator_Char()
{
var ss1 = new SecureString("Hello ");
var c = 'W';
(ss1 + c).Should().Be("Hello W");
}
[TestMethod]
public void SecureString_WithOptionalEntropy_Matches()
{
SecureString.AddOptionalEntropy(new byte[] { 10, 20, 25, 34, 56, 12, 10, 81, 200, 155, 123, 144, 123, 192, 122, 1 });
var ss1 = new SecureString("Hello");
var ss2 = new SecureString("Hello");
ss1.Should().Be(ss2);
}
}
@@ -0,0 +1,47 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Security.Hashing;
using System.Text;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Tests;
[TestClass]
public sealed class Sha256HashingServiceTests
{
private readonly IHashingService hashingService = new Sha256HashingService();
private string toHashtString;
private byte[] toHashtBytes;
private Stream toHashStream;
[TestInitialize]
public void TestInitialize()
{
this.toHashtBytes = Encoding.UTF8.GetBytes("toEncrypt");
this.toHashtString = Convert.ToBase64String(this.toHashtBytes);
this.toHashStream = new MemoryStream(this.toHashtBytes);
}
[TestMethod]
public async Task HashString()
{
var hash = await this.hashingService.Hash(this.toHashtString).ConfigureAwait(false);
hash.Should().BeOfType<string>();
}
[TestMethod]
public async Task HashBytes()
{
var hash = await this.hashingService.Hash(this.toHashtBytes).ConfigureAwait(false);
hash.Should().BeOfType<byte[]>();
}
[TestMethod]
public async Task HashStream()
{
var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false);
hash.Should().BeAssignableTo<Stream>();
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<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>
<ProjectReference Include="..\SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,226 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Security.Utilities;
namespace System.Security.Encryption;
public sealed class AesEncrypter : ISymmetricEncrypter, IDisposable
{
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 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 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 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 this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToBytes(decryptedStream);
}
public async Task<Stream> Decrypt(string key, string iv, Stream value)
{
return await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
}
public async Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value)
{
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 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 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 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 this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToBytes(encryptedStream);
}
public async Task<Stream> Encrypt(string key, string iv, Stream value)
{
return value is null
? throw new ArgumentNullException(nameof(value))
: await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
}
public async Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value)
{
return value is null
? throw new ArgumentNullException(nameof(value))
: await this.EncryptInternal(key, iv, value).ConfigureAwait(false);
}
public Stream GetEncryptionStream(string key, string iv, Stream outStream)
{
return this.GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
}
public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream)
{
return this.GetEncryptionStreamInternal(key, iv, outStream);
}
public Stream GetDecryptionStream(string key, string iv, Stream inStream)
{
return this.GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
}
public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream)
{
return this.GetDecryptionStreamInternal(key, iv, inStream);
}
private async Task<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)
{
value.Position = 0;
var buffer = new byte[1024];
using var ms = new MemoryStream();
var read = -1;
do
{
read = value.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
} while (read > 0);
return ms.ToArray();
}
private static string StreamToString(Stream value)
{
return Convert.ToBase64String(StreamToBytes(value));
}
private static byte[] StringToBytes(string value)
{
return Convert.FromBase64String(value);
}
private static Stream BytesToStream(byte[] value)
{
return new MemoryStream(value);
}
public void Dispose()
{
this.aes.Dispose();
}
}
@@ -0,0 +1,24 @@
using System.IO;
using System.Threading.Tasks;
namespace System.Security.Encryption;
public interface ISymmetricEncrypter
{
Stream GetEncryptionStream(string key, string iv, Stream outStream);
Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream);
Stream GetDecryptionStream(string key, string iv, Stream inStream);
Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream);
Task<string> Encrypt(string key, string iv, string value);
Task<string> Encrypt(byte[] key, byte[] iv, string value);
Task<byte[]> Encrypt(string key, string iv, byte[] value);
Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value);
Task<Stream> Encrypt(string key, string iv, Stream value);
Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value);
Task<string> Decrypt(string key, string iv, string value);
Task<string> Decrypt(byte[] key, byte[] iv, string value);
Task<byte[]> Decrypt(string key, string iv, byte[] value);
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);
}
@@ -0,0 +1,101 @@
using System.Security.Cryptography;
using System.Text;
namespace System.Security.Encryption;
public sealed class SecureString
{
private static byte[] optionalEntropy;
private byte[] encryptedValue;
public string Value {
get => this.encryptedValue is not null ? Encoding.UTF8.GetString(ProtectedData.Unprotect(this.encryptedValue, optionalEntropy, DataProtectionScope.CurrentUser)) : null;
private set => this.encryptedValue = ProtectedData.Protect(Encoding.UTF8.GetBytes(value), optionalEntropy, DataProtectionScope.CurrentUser);
}
public SecureString(string value)
{
this.Value = value;
}
public override bool Equals(object obj)
{
if (obj is string)
{
return this == (obj as string);
}
else if (obj is SecureString)
{
return this == (obj as SecureString);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
}
public override string ToString()
{
return this.Value;
}
public static readonly SecureString Empty = new(string.Empty);
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
public static implicit operator SecureString(string s) => new(s);
public static SecureString operator +(SecureString ss1, SecureString ss2)
{
if (ss1 is null)
{
throw new ArgumentNullException(nameof(ss1));
}
if (ss2 is null)
{
throw new ArgumentNullException(nameof(ss2));
}
return new SecureString(ss1.Value + ss2.Value);
}
public static SecureString operator +(SecureString ss1, string s2)
{
if (ss1 is null)
{
throw new ArgumentNullException(nameof(ss1));
}
return new SecureString(ss1.Value + s2);
}
public static SecureString operator +(SecureString ss1, char c)
{
if (ss1 is null)
{
throw new ArgumentNullException(nameof(ss1));
}
return new SecureString(ss1.Value + c);
}
public static bool operator ==(SecureString ss1, SecureString ss2)
{
return ss1?.Value == ss2?.Value;
}
public static bool operator !=(SecureString ss1, SecureString ss2)
{
return !(ss1 == ss2);
}
public static bool operator ==(SecureString ss1, string s2)
{
return ss1?.Value == s2;
}
public static bool operator !=(SecureString ss1, string s2)
{
return !(ss1?.Value == s2);
}
public static void AddOptionalEntropy(byte[] entropy)
{
optionalEntropy = entropy;
}
}
@@ -0,0 +1,11 @@
using System.IO;
using System.Threading.Tasks;
namespace System.Security.Hashing;
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));
}
}
@@ -0,0 +1,61 @@
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace System.Security.Hashing;
public sealed class Sha256HashingService : IHashingService
{
public async Task<string> Hash(string raw)
{
using var rawStream = BytesToStream(StringToBytes(raw));
using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false);
return StreamToString(hashedStream);
}
public async Task<byte[]> Hash(byte[] raw)
{
using var rawStream = BytesToStream(raw);
using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false);
return StreamToBytes(hashedStream);
}
public async Task<Stream> Hash(Stream raw)
{
return await HashInternal(raw);
}
private static byte[] StreamToBytes(Stream value)
{
value.Position = 0;
var buffer = new byte[1024];
using var ms = new MemoryStream();
var read = -1;
do
{
read = value.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
} while (read > 0);
return ms.ToArray();
}
private static string StreamToString(Stream value)
{
return Convert.ToBase64String(StreamToBytes(value));
}
private static byte[] StringToBytes(string value)
{
return Convert.FromBase64String(value);
}
private static Stream BytesToStream(byte[] value)
{
return new MemoryStream(value);
}
private static async Task<Stream> HashInternal(Stream raw)
{
if (raw is null)
{
throw new ArgumentNullException(nameof(raw));
}
using var sha256 = SHA256.Create();
return await Task.Run(() => new MemoryStream(sha256.ComputeHash(raw)));
}
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Macocian Alexandru Victor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,58 @@
using System.Security.Cryptography;
namespace System.Security.Rng;
public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable
{
private readonly RNGCryptoServiceProvider rngProvider;
private bool disposedValue;
public CryptoRngProvider()
{
this.rngProvider = new RNGCryptoServiceProvider();
}
public CryptoRngProvider(CspParameters cspParams)
{
this.rngProvider = new RNGCryptoServiceProvider(cspParams);
}
public void GetBytes(byte[] data)
{
this.rngProvider.GetBytes(data);
}
public void GetNonZeroBytes(byte[] data)
{
this.rngProvider.GetNonZeroBytes(data);
}
public byte[] GetBytes(int byteCount)
{
var bytes = new byte[byteCount];
this.GetBytes(bytes);
return bytes;
}
public byte[] GetNonZeroBytes(int byteCount)
{
var bytes = new byte[byteCount];
this.GetNonZeroBytes(bytes);
return bytes;
}
private void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
this.rngProvider.Dispose();
}
this.disposedValue = true;
}
}
public void Dispose()
{
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
@@ -0,0 +1,27 @@
namespace System.Security.Rng;
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);
}
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RootNamespace>System</RootNamespace>
<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>
<None Include="../LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="6.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,22 @@
using System.IO;
using System.Security.Cryptography;
namespace System.Security.Utilities;
internal sealed class NotClosingCryptoStream : CryptoStream
{
public NotClosingCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
: base(stream, transform, mode)
{
}
protected override void Dispose(bool disposing)
{
if (!this.HasFlushedFinalBlock)
{
this.FlushFinalBlock();
}
base.Dispose(false);
}
}
@@ -1,389 +1,402 @@
using 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>
{
#region Fields
[Serializable]
private class AVLNode<TKey>
{
public TKey Value;
public AVLNode<TKey> Left;
public AVLNode<TKey> Right;
public AVLNode(TKey value)
{
this.Value = value;
}
}
AVLNode<T> root;
private int count = 0;
private readonly bool isReadOnly = false;
#endregion
#region Properties
/// <summary>
/// Count of items currently stored in the tree.
/// </summary>
public int Count
{
get
{
return count;
}
}
/// <summary>
/// True if the collection is readonly. False otherwise.
/// </summary>
public bool IsReadOnly => isReadOnly;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of an AVLTree collection.
/// </summary>
public AVLTree()
{
namespace System.Collections.Generic;
}
#endregion
#region Public Methods
/// <summary>
/// Adds the value to the tree.
/// </summary>
/// <param name="value">Value to be added to the tree.</param>
public void Add(T value)
/// <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>
{
public TKey Value;
public AVLNode<TKey> Left;
public AVLNode<TKey> Right;
public AVLNode(TKey value)
{
count++;
AVLNode<T> newItem = new AVLNode<T>(value);
if (root == null)
{
root = newItem;
}
else
{
root = RecursiveInsertion(root, newItem);
}
this.Value = value;
}
/// <summary>
/// Checks if the key is contained into the tree.
/// </summary>
/// <param name="value">Value to be checked if present in the tree.</param>
/// <returns>True if the value is in the tree.</returns>
public bool Contains(T value)
}
AVLNode<T> root;
private int count = 0;
private readonly bool isReadOnly = false;
#endregion
#region Properties
/// <summary>
/// Count of items currently stored in the tree.
/// </summary>
public int Count
{
get
{
AVLNode<T> node = Find(value, root);
if (node == null)
{
return false;
}
if (node.Value.CompareTo(value) == 0)
{
return true;
}
else
{
return false;
}
return this.count;
}
/// <summary>
/// Removes the specified value from the tree.
/// </summary>
/// <param name="value">Value to be deleted.</param>
public bool Remove(T value)
}
/// <summary>
/// True if the collection is readonly. False otherwise.
/// </summary>
public bool IsReadOnly => this.isReadOnly;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of an AVLTree collection.
/// </summary>
public AVLTree()
{
}
#endregion
#region Public Methods
/// <summary>
/// Adds the value to the tree.
/// </summary>
/// <param name="value">Value to be added to the tree.</param>
public void Add(T value)
{
this.count++;
var newItem = new AVLNode<T>(value);
if (this.root == null)
{
this.root = newItem;
}
else
{
this.root = this.RecursiveInsertion(this.root, newItem);
}
}
/// <summary>
/// Checks if the key is contained into the tree.
/// </summary>
/// <param name="value">Value to be checked if present in the tree.</param>
/// <returns>True if the value is in the tree.</returns>
public bool Contains(T value)
{
var node = this.Find(value, this.root);
if (node == null)
{
return false;
}
if (node.Value.CompareTo(value) == 0)
{
root = Delete(root, value);
return true;
}
/// <summary>
/// Clears the tree.
/// </summary>
public void Clear()
else
{
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
queue.Enqueue(root);
return false;
}
}
/// <summary>
/// Removes the specified value from the tree.
/// </summary>
/// <param name="value">Value to be deleted.</param>
public bool Remove(T value)
{
this.root = this.Delete(this.root, value);
return true;
}
/// <summary>
/// Clears the tree.
/// </summary>
public void Clear()
{
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(this.root);
while (queue.Count > 0)
{
AVLNode<T> currentNode = queue.Dequeue();
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
currentNode.Left = null;
count--;
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
currentNode.Right = null;
count--;
}
}
root = null;
count--;
}
/// <summary>
/// Copies the tree onto the provided array.
/// </summary>
/// <param name="array">Array to store the values in the tree.</param>
/// <param name="arrayIndex">Starting index of the provided array.</param>
public void CopyTo(T[] array, int arrayIndex)
while (queue.Count > 0)
{
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
queue.Enqueue(root);
while (queue.Count > 0)
var currentNode = queue.Dequeue();
if (currentNode.Left != null)
{
AVLNode<T> currentNode = queue.Dequeue();
array[arrayIndex++] = currentNode.Value;
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
}
queue.Enqueue(currentNode.Left);
currentNode.Left = null;
this.count--;
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
currentNode.Right = null;
this.count--;
}
}
/// <summary>
/// Enumerator that iterates over the tree.
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
this.root = null;
this.count--;
}
/// <summary>
/// Copies the tree onto the provided array.
/// </summary>
/// <param name="array">Array to store the values in the tree.</param>
/// <param name="arrayIndex">Starting index of the provided array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(this.root);
while (queue.Count > 0)
{
return GetEnumerator(root);
var currentNode = queue.Dequeue();
array[arrayIndex++] = currentNode.Value;
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
}
}
/// <summary>
/// Copies the tree structure into an array.
/// </summary>
/// <returns>Array containing the values contained in the tree.</returns>
public T[] ToArray()
}
/// <summary>
/// Enumerator that iterates over the tree.
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return this.GetEnumerator(this.root);
}
/// <summary>
/// Copies the tree structure into an array.
/// </summary>
/// <returns>Array containing the values contained in the tree.</returns>
public T[] ToArray()
{
var array = new T[this.count];
this.CopyTo(array, 0);
return array;
}
#endregion
#region Private Methods
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
{
if (current == null)
{
T[] array = new T[count];
CopyTo(array, 0);
return array;
}
#endregion
#region Private Methods
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
{
if (current == null)
{
current = n;
return current;
}
else if (n.Value.CompareTo(current.Value) < 0)
{
current.Left = RecursiveInsertion(current.Left, n);
current = BalanceTree(current);
}
else if (n.Value.CompareTo(current.Value) > 0)
{
current.Right = RecursiveInsertion(current.Right, n);
current = BalanceTree(current);
}
current = n;
return current;
}
private AVLNode<T> BalanceTree(AVLNode<T> current)
else if (n.Value.CompareTo(current.Value) < 0)
{
int b_factor = BalanceFactor(current);
if (b_factor > 1)
{
if (BalanceFactor(current.Left) > 0)
{
current = RotateLL(current);
}
else
{
current = RotateLR(current);
}
}
else if (b_factor < -1)
{
if (BalanceFactor(current.Right) > 0)
{
current = RotateRL(current);
}
else
{
current = RotateRR(current);
}
}
return current;
current.Left = this.RecursiveInsertion(current.Left, n);
current = this.BalanceTree(current);
}
private AVLNode<T> Delete(AVLNode<T> current, T target)
else if (n.Value.CompareTo(current.Value) > 0)
{
AVLNode<T> parent;
if (current == null)
{ return null; }
current.Right = this.RecursiveInsertion(current.Right, n);
current = this.BalanceTree(current);
}
return current;
}
private AVLNode<T> BalanceTree(AVLNode<T> current)
{
var b_factor = this.BalanceFactor(current);
if (b_factor > 1)
{
if (this.BalanceFactor(current.Left) > 0)
{
current = this.RotateLL(current);
}
else
{
//left subtree
if (target.CompareTo(current.Value) < 0)
{
current.Left = Delete(current.Left, target);
if (BalanceFactor(current) == -2)//here
{
if (BalanceFactor(current.Right) <= 0)
{
current = RotateRR(current);
}
else
{
current = RotateRL(current);
}
}
}
//right subtree
else if (target.CompareTo(current.Value) > 0)
{
current.Right = Delete(current.Right, target);
if (BalanceFactor(current) == 2)
{
if (BalanceFactor(current.Left) >= 0)
{
current = RotateLL(current);
}
else
{
current = RotateLR(current);
}
}
}
//if target is found
else
{
count--;
if (current.Right != null)
{
//delete its inorder successor
parent = current.Right;
while (parent.Left != null)
{
parent = parent.Left;
}
current.Value = parent.Value;
current.Right = Delete(current.Right, parent.Value);
if (BalanceFactor(current) == 2)//rebalancing
{
if (BalanceFactor(current.Left) >= 0)
{
current = RotateLL(current);
}
else { current = RotateLR(current); }
}
}
else
{ //if current.left != null
return current.Left;
}
}
current = this.RotateLR(current);
}
return current;
}
private AVLNode<T> Find(T target, AVLNode<T> current)
else if (b_factor < -1)
{
if (current == null)
if (this.BalanceFactor(current.Right) > 0)
{
return null;
current = this.RotateRL(current);
}
else
{
current = this.RotateRR(current);
}
}
return current;
}
private AVLNode<T> Delete(AVLNode<T> current, T target)
{
AVLNode<T> parent;
if (current == null)
{ return null; }
else
{
//left subtree
if (target.CompareTo(current.Value) < 0)
{
if (target.CompareTo(current.Value) == 0)
current.Left = this.Delete(current.Left, target);
if (this.BalanceFactor(current) == -2)//here
{
return current;
if (this.BalanceFactor(current.Right) <= 0)
{
current = this.RotateRR(current);
}
else
{
current = this.RotateRL(current);
}
}
}
//right subtree
else if (target.CompareTo(current.Value) > 0)
{
current.Right = this.Delete(current.Right, target);
if (this.BalanceFactor(current) == 2)
{
if (this.BalanceFactor(current.Left) >= 0)
{
current = this.RotateLL(current);
}
else
{
current = this.RotateLR(current);
}
}
}
//if target is found
else
{
this.count--;
if (current.Right != null)
{
//delete its inorder successor
parent = current.Right;
while (parent.Left != null)
{
parent = parent.Left;
}
current.Value = parent.Value;
current.Right = this.Delete(current.Right, parent.Value);
if (this.BalanceFactor(current) == 2)//rebalancing
{
if (this.BalanceFactor(current.Left) >= 0)
{
current = this.RotateLL(current);
}
else { current = this.RotateLR(current); }
}
}
else
return Find(target, current.Left);
{ //if current.left != null
return current.Left;
}
}
}
return current;
}
private AVLNode<T> Find(T target, AVLNode<T> current)
{
if (current == null)
{
return null;
}
if (target.CompareTo(current.Value) < 0)
{
if (target.CompareTo(current.Value) == 0)
{
return current;
}
else
{
if (target.CompareTo(current.Value) == 0)
{
return current;
}
else
return Find(target, current.Right);
return this.Find(target, current.Left);
}
}
private int Max(int l, int r)
else
{
return l > r ? l : r;
}
private int GetHeight(AVLNode<T> current)
{
int height = 0;
if (current != null)
if (target.CompareTo(current.Value) == 0)
{
int l = GetHeight(current.Left);
int r = GetHeight(current.Right);
int m = Max(l, r);
height = m + 1;
return current;
}
return height;
}
private int BalanceFactor(AVLNode<T> current)
{
int l = GetHeight(current.Left);
int r = GetHeight(current.Right);
int b_factor = l - r;
return b_factor;
}
private AVLNode<T> RotateRR(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Right;
parent.Right = pivot.Left;
pivot.Left = parent;
return pivot;
}
private AVLNode<T> RotateLL(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Left;
parent.Left = pivot.Right;
pivot.Right = parent;
return pivot;
}
private AVLNode<T> RotateLR(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Left;
parent.Left = RotateRR(pivot);
return RotateLL(parent);
}
private AVLNode<T> RotateRL(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Right;
parent.Right = RotateLL(pivot);
return RotateRR(parent);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
{
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
queue.Enqueue(rootNode);
while (queue.Count > 0)
else
{
AVLNode<T> currentNode = queue.Dequeue();
yield return currentNode.Value;
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
}
return this.Find(target, current.Right);
}
}
#endregion
}
private int Max(int l, int r)
{
return l > r ? l : r;
}
private int GetHeight(AVLNode<T> current)
{
var height = 0;
if (current != null)
{
var l = this.GetHeight(current.Left);
var r = this.GetHeight(current.Right);
var m = this.Max(l, r);
height = m + 1;
}
return height;
}
private int BalanceFactor(AVLNode<T> current)
{
var l = this.GetHeight(current.Left);
var r = this.GetHeight(current.Right);
var b_factor = l - r;
return b_factor;
}
private AVLNode<T> RotateRR(AVLNode<T> parent)
{
var pivot = parent.Right;
parent.Right = pivot.Left;
pivot.Left = parent;
return pivot;
}
private AVLNode<T> RotateLL(AVLNode<T> parent)
{
var pivot = parent.Left;
parent.Left = pivot.Right;
pivot.Right = parent;
return pivot;
}
private AVLNode<T> RotateLR(AVLNode<T> parent)
{
var pivot = parent.Left;
parent.Left = this.RotateRR(pivot);
return this.RotateLL(parent);
}
private AVLNode<T> RotateRL(AVLNode<T> parent)
{
var pivot = parent.Right;
parent.Right = this.RotateLL(pivot);
return this.RotateRR(parent);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
{
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(rootNode);
while (queue.Count > 0)
{
var currentNode = queue.Dequeue();
yield return currentNode.Value;
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
}
}
}
#endregion
}
@@ -1,214 +1,219 @@
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>
{
#region Fields
T[] items;
private int capacity;
private int count;
private readonly int initialCapacity;
#endregion
#region Properties
/// <summary>
/// Binary heap implementation.
/// Minimum value from the heap.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
public T Min
{
#region Fields
T[] items;
private int capacity;
private int count;
private readonly int initialCapacity;
#endregion
#region Properties
/// <summary>
/// Minimum value from the heap.
/// </summary>
public T Min
get
{
get
{
return items[1];
}
return this.items[1];
}
/// <summary>
/// Maximum value from the heap.
/// </summary>
public T Max
{
get
{
return items[count];
}
}
/// <summary>
/// Capacity of the heap.
/// </summary>
public int Capacity
{
get => capacity;
set
{
if (value > capacity)
{
Array.Resize(ref items, value);
capacity = value;
}
}
}
/// <summary>
/// Number of elements in the heap.
/// </summary>
public int Count { get => count; }
#endregion
#region Constructors
/// <summary>
/// Constructor for a binary heap data structure.
/// </summary>
public BinaryHeap()
{
capacity = 10;
initialCapacity = capacity;
items = new T[capacity];
}
/// <summary>
/// Constructor for a binary heap data structure.
/// </summary>
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
public BinaryHeap(int capacity)
{
this.capacity = capacity;
initialCapacity = capacity;
items = new T[capacity];
}
#endregion
#region Public Methods
/// <summary>
/// Adds value to the queue.
/// </summary>
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
if (count == Capacity - 1)
{
Capacity = 2 * Capacity;
}
int position = ++count;
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
{
items[position] = items[position / 2];
}
items[position] = value;
}
/// <summary>
/// Removes the item at the root. Throws exception if there are no items in the heap.
/// </summary>
/// <returns>Value removed.</returns>
public T Remove()
{
if (count == 0)
{
throw new IndexOutOfRangeException("Heap is empty!");
}
T min = items[1];
items[1] = items[count--];
BubbleDown(1);
return min;
}
/// <summary>
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
/// </summary>
/// <returns></returns>
public T Peek()
{
if (count == 0)
{
throw new IndexOutOfRangeException("Heap is empty!");
}
T min = items[1];
return min;
}
/// <summary>
/// Return the heap structure as an array
/// </summary>
/// <returns>Array with values sorted as in heap</returns>
public T[] ToArray()
{
T[] newArray = new T[count];
Array.Copy(items, 1, newArray, 0, count);
return newArray;
}
/// <summary>
/// Determines whether the heap contains specified value
/// </summary>
/// <param name="value">Value to locate in the heap</param>
/// <returns></returns>
public bool Contains(T value)
{
return items.Contains(value);
}
/// <summary>
/// Clears the heap
/// </summary>
public void Clear()
{
count = 0;
}
/// <summary>
/// Clears the heap.
/// </summary>
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
public void Clear(bool completeClear)
{
count = 0;
if (completeClear)
{
capacity = initialCapacity;
items = new T[initialCapacity];
}
}
/// <summary>
/// Returns an enumerator that iterates over the heap.
/// </summary>
/// <returns>Enumerator that iterates over the heap.</returns>
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < count; i++)
{
yield return items[i + 1];
}
}
#endregion
#region Private Methods
/// <summary>
/// Bubble the specified element to its position
/// </summary>
/// <param name="index">Index of element to bubble</param>
private void BubbleDown(int index)
{
T temp = items[index];
int childIndex;
for (; 2 * index <= count; index = childIndex)
{
childIndex = 2 * index;
if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
{
childIndex++;
}
if (temp.CompareTo(items[childIndex]) > 0)
{
items[index] = items[childIndex];
}
else
{
break;
}
}
items[index] = temp;
}
/// <summary>
/// Implementation of IEnumerator.
/// </summary>
/// <returns>Enumerator over the array.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
/// <summary>
/// Maximum value from the heap.
/// </summary>
public T Max
{
get
{
return this.items[this.count];
}
}
/// <summary>
/// Capacity of the heap.
/// </summary>
public int Capacity
{
get => this.capacity;
set
{
if (value > this.capacity)
{
Array.Resize(ref this.items, value);
this.capacity = value;
}
}
}
/// <summary>
/// Number of elements in the heap.
/// </summary>
public int Count { get => this.count; }
#endregion
#region Constructors
/// <summary>
/// Constructor for a binary heap data structure.
/// </summary>
public BinaryHeap()
{
this.capacity = 10;
this.initialCapacity = this.capacity;
this.items = new T[this.capacity];
}
/// <summary>
/// Constructor for a binary heap data structure.
/// </summary>
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
public BinaryHeap(int capacity)
{
this.capacity = capacity;
this.initialCapacity = capacity;
this.items = new T[capacity];
}
#endregion
#region Public Methods
/// <summary>
/// Adds value to the queue.
/// </summary>
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
if (this.count == this.Capacity - 1)
{
this.Capacity = 2 * this.Capacity;
}
var position = ++this.count;
for (; position > 1 && value.CompareTo(this.items[position / 2]) < 0; position /= 2)
{
this.items[position] = this.items[position / 2];
}
this.items[position] = value;
}
/// <summary>
/// Removes the item at the root. Throws exception if there are no items in the heap.
/// </summary>
/// <returns>Value removed.</returns>
public T Remove()
{
if (this.count == 0)
{
throw new IndexOutOfRangeException("Heap is empty!");
}
var min = this.items[1];
this.items[1] = this.items[this.count--];
this.BubbleDown(1);
return min;
}
/// <summary>
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
/// </summary>
/// <returns></returns>
public T Peek()
{
if (this.count == 0)
{
throw new IndexOutOfRangeException("Heap is empty!");
}
var min = this.items[1];
return min;
}
/// <summary>
/// Return the heap structure as an array
/// </summary>
/// <returns>Array with values sorted as in heap</returns>
public T[] ToArray()
{
var newArray = new T[this.count];
Array.Copy(this.items, 1, newArray, 0, this.count);
return newArray;
}
/// <summary>
/// Determines whether the heap contains specified value
/// </summary>
/// <param name="value">Value to locate in the heap</param>
/// <returns></returns>
public bool Contains(T value)
{
return this.items.Contains(value);
}
/// <summary>
/// Clears the heap
/// </summary>
public void Clear()
{
this.count = 0;
}
/// <summary>
/// Clears the heap.
/// </summary>
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
public void Clear(bool completeClear)
{
this.count = 0;
if (completeClear)
{
this.capacity = this.initialCapacity;
this.items = new T[this.initialCapacity];
}
}
/// <summary>
/// Returns an enumerator that iterates over the heap.
/// </summary>
/// <returns>Enumerator that iterates over the heap.</returns>
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < this.count; i++)
{
yield return this.items[i + 1];
}
}
#endregion
#region Private Methods
/// <summary>
/// Bubble the specified element to its position
/// </summary>
/// <param name="index">Index of element to bubble</param>
private void BubbleDown(int index)
{
var temp = this.items[index];
int childIndex;
for (; 2 * index <= this.count; index = childIndex)
{
childIndex = 2 * index;
if (childIndex != this.Count && this.items[childIndex].CompareTo(this.items[childIndex + 1]) > 0)
{
childIndex++;
}
if (temp.CompareTo(this.items[childIndex]) > 0)
{
this.items[index] = this.items[childIndex];
}
else
{
break;
}
}
this.items[index] = temp;
}
/// <summary>
/// Implementation of IEnumerator.
/// </summary>
/// <returns>Enumerator over the array.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
File diff suppressed because it is too large Load Diff
@@ -1,39 +1,38 @@
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.
/// Returns the number of items in the queue.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
public interface IQueue<T> : IEnumerable<T>
{
/// <summary>
/// Returns the number of items in the queue.
/// </summary>
int Count { get; }
/// <summary>
/// Inserts item into the queue.
/// </summary>
/// <param name="item">Item to be inserted.</param>
void Enqueue(T item);
/// <summary>
/// Remove the first item in the queue.
/// </summary>
/// <returns>First item in the queue.</returns>
T Dequeue();
/// <summary>
/// Looks up the first item from the queue without removing it.
/// </summary>
/// <returns>First item from the queue.</returns>
T Peek();
/// <summary>
/// Clears the contents of the queue.
/// </summary>
void Clear();
/// <summary>
/// Checks if queue contains an item.
/// </summary>
/// <param name="item">Item to be checked.</param>
/// <returns>True if queue contains provided item. False otherwise.</returns>
bool Contains(T item);
}
int Count { get; }
/// <summary>
/// Inserts item into the queue.
/// </summary>
/// <param name="item">Item to be inserted.</param>
void Enqueue(T item);
/// <summary>
/// Remove the first item in the queue.
/// </summary>
/// <returns>First item in the queue.</returns>
T Dequeue();
/// <summary>
/// Looks up the first item from the queue without removing it.
/// </summary>
/// <returns>First item from the queue.</returns>
T Peek();
/// <summary>
/// Clears the contents of the queue.
/// </summary>
void Clear();
/// <summary>
/// Checks if queue contains an item.
/// </summary>
/// <param name="item">Item to be checked.</param>
/// <returns>True if queue contains provided item. False otherwise.</returns>
bool Contains(T item);
}
@@ -1,103 +1,102 @@
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>
{
#region Fields
private readonly BinaryHeap<T> binaryHeap;
#endregion
#region Properties
/// <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.
/// Returns the number of elements stored into the queue.
/// </summary>
/// <typeparam name="T">Provided type.</typeparam>
[Serializable]
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
public int Count
{
#region Fields
private readonly BinaryHeap<T> binaryHeap;
#endregion
#region Properties
/// <summary>
/// Returns the number of elements stored into the queue.
/// </summary>
public int Count
get
{
get
{
return binaryHeap.Count;
}
return this.binaryHeap.Count;
}
#endregion
#region Constructors
/// <summary>
/// Constructor for priority queue data structure.
/// </summary>
public PriorityQueue()
{
binaryHeap = new BinaryHeap<T>();
}
#endregion
#region Public Methods
/// <summary>
/// Add provided value to the queue.
/// </summary>
/// <param name="value">Value to be added to the queue.</param>
public void Enqueue(T value)
{
binaryHeap.Add(value);
}
/// <summary>
/// Pops the queue and removes the highest priority value from the queue.
/// </summary>
/// <returns>Highest priority value from the queue</returns>
public T Dequeue()
{
if (Count > 0)
{
return binaryHeap.Remove();
}
else
{
throw new IndexOutOfRangeException("Queue is empty!");
}
}
/// <summary>
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
/// </summary>
/// <returns>Highest priority value from the queue.</returns>
public T Peek()
{
return binaryHeap.Min;
}
/// <summary>
/// Clears the queue contents, removing any value stored into the queue.
/// </summary>
public void Clear()
{
binaryHeap.Clear();
}
/// <summary>
/// Checks if queue contains provided item.
/// </summary>
/// <param name="item">Item to be checked.</param>
/// <returns>True if queue contains the provided item. False otherwise.</returns>
public bool Contains(T item)
{
return binaryHeap.Contains(item);
}
/// <summary>
/// Returns an enumerator that iterates over the queue.
/// </summary>
/// <returns>Enumerator that iterates over the queue.</returns>
public IEnumerator<T> GetEnumerator()
{
return binaryHeap.GetEnumerator();
}
#endregion
#region Private Methods
/// <summary>
/// Necesarry for the implementatio of IQueue.
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
#endregion
#region Constructors
/// <summary>
/// Constructor for priority queue data structure.
/// </summary>
public PriorityQueue()
{
this.binaryHeap = new BinaryHeap<T>();
}
#endregion
#region Public Methods
/// <summary>
/// Add provided value to the queue.
/// </summary>
/// <param name="value">Value to be added to the queue.</param>
public void Enqueue(T value)
{
this.binaryHeap.Add(value);
}
/// <summary>
/// Pops the queue and removes the highest priority value from the queue.
/// </summary>
/// <returns>Highest priority value from the queue</returns>
public T Dequeue()
{
if (this.Count > 0)
{
return this.binaryHeap.Remove();
}
else
{
throw new IndexOutOfRangeException("Queue is empty!");
}
}
/// <summary>
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
/// </summary>
/// <returns>Highest priority value from the queue.</returns>
public T Peek()
{
return this.binaryHeap.Min;
}
/// <summary>
/// Clears the queue contents, removing any value stored into the queue.
/// </summary>
public void Clear()
{
this.binaryHeap.Clear();
}
/// <summary>
/// Checks if queue contains provided item.
/// </summary>
/// <param name="item">Item to be checked.</param>
/// <returns>True if queue contains the provided item. False otherwise.</returns>
public bool Contains(T item)
{
return this.binaryHeap.Contains(item);
}
/// <summary>
/// Returns an enumerator that iterates over the queue.
/// </summary>
/// <returns>Enumerator that iterates over the queue.</returns>
public IEnumerator<T> GetEnumerator()
{
return this.binaryHeap.GetEnumerator();
}
#endregion
#region Private Methods
/// <summary>
/// Necesarry for the implementatio of IQueue.
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
@@ -1,236 +1,248 @@
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>
#region Fields
[Serializable]
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
private class NodeSet<TKey>
{
#region Fields
[Serializable]
private class NodeSet<TKey>
{
public TKey Key;
public int Level;
public NodeSet<TKey>[] Next;
public TKey Key;
public int Level;
public NodeSet<TKey>[] Next;
public NodeSet(TKey key, int level)
{
this.Key = key;
this.Level = level;
Next = new NodeSet<TKey>[level + 1];
}
}
private int count;
private readonly Random random;
private readonly NodeSet<T> head;
private readonly NodeSet<T> end;
private readonly int maxLevel = 10;
private int level;
#endregion
#region Properties
/// <summary>
/// Number of elements in the list.
/// </summary>
public int Count { get => count; }
/// <summary>
/// Specifies if the collection can be modified.
/// </summary>
public bool IsReadOnly { get; set; }
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of SkipList collection.
/// </summary>
/// <param name="maxLevel">Maximum level of the skip list.</param>
public SkipList(int maxLevel = 10)
public NodeSet(TKey key, int level)
{
this.maxLevel = maxLevel;
random = new Random();
head = new NodeSet<T>(default, maxLevel);
end = head;
for (int i = 0; i <= maxLevel; i++)
{
head.Next[i] = end;
}
this.Key = key;
this.Level = level;
this.Next = new NodeSet<TKey>[level + 1];
}
}
private int count;
private readonly Random random;
private readonly NodeSet<T> head;
private readonly NodeSet<T> end;
private readonly int maxLevel = 10;
private int level;
#endregion
#region Properties
/// <summary>
/// Number of elements in the list.
/// </summary>
public int Count { get => this.count; }
/// <summary>
/// Specifies if the collection can be modified.
/// </summary>
public bool IsReadOnly { get; set; }
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of SkipList collection.
/// </summary>
/// <param name="maxLevel">Maximum level of the skip list.</param>
public SkipList(int maxLevel = 10)
{
this.maxLevel = maxLevel;
this.random = new Random();
this.head = new NodeSet<T>(default, maxLevel);
this.end = this.head;
for (var i = 0; i <= maxLevel; i++)
{
this.head.Next[i] = this.end;
}
}
#endregion
#region Public Methods
/// <summary>
/// Adds an item to the collection.
/// </summary>
/// <param name="item">Item to be added.</param>
public void Add(T item)
{
var curNode = this.head;
var newLevel = 0;
while (this.random.Next(0, 2) > 0 && newLevel < this.maxLevel)
{
newLevel++;
}
#endregion
#region Public Methods
/// <summary>
/// Adds an item to the collection.
/// </summary>
/// <param name="item">Item to be added.</param>
public void Add(T item)
if (newLevel > this.level)
{
NodeSet<T> curNode = head;
int newLevel = 0;
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
{
newLevel++;
}
if (newLevel > level)
{
level = newLevel;
}
NodeSet<T> newNode = new NodeSet<T>(item, newLevel);
for (var i = 0; i <= newLevel; i++)
{
if (i > curNode.Level)
{
curNode = head;
}
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
{
curNode = curNode.Next[i];
}
newNode.Next[i] = curNode.Next[i];
curNode.Next[i] = newNode;
}
count++;
this.level = newLevel;
}
/// <summary>
/// Removes provided item from the collection.
/// </summary>
/// <param name="item">Item to be removed.</param>
/// <returns>True if removal was successful.</returns>
public bool Remove(T item)
var newNode = new NodeSet<T>(item, newLevel);
for (var i = 0; i <= newLevel; i++)
{
bool removed = false;
NodeSet<T> curNode = head;
for (var i = 0; i <= maxLevel; i++)
if (i > curNode.Level)
{
if (i > curNode.Level)
{
curNode = head;
}
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
{
curNode = curNode.Next[i];
}
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
{
curNode.Next[i] = curNode.Next[i].Next[i];
removed = true;
}
else
{
break;
}
curNode = this.head;
}
if (removed)
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
{
count--;
return true;
curNode = curNode.Next[i];
}
newNode.Next[i] = curNode.Next[i];
curNode.Next[i] = newNode;
}
this.count++;
}
/// <summary>
/// Removes provided item from the collection.
/// </summary>
/// <param name="item">Item to be removed.</param>
/// <returns>True if removal was successful.</returns>
public bool Remove(T item)
{
var removed = false;
var curNode = this.head;
for (var i = 0; i <= this.maxLevel; i++)
{
if (i > curNode.Level)
{
curNode = this.head;
}
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
{
curNode = curNode.Next[i];
}
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
{
curNode.Next[i] = curNode.Next[i].Next[i];
removed = true;
}
else
{
return false;
break;
}
}
/// <summary>
/// Clears the collection.
/// </summary>
public void Clear()
if (removed)
{
for (int i = 0; i < maxLevel; i++)
{
head.Next[i] = end;
}
count = 0;
this.count--;
return true;
}
/// <summary>
/// Checks if item is present in the collection.
/// </summary>
/// <param name="item">Item to be checked.</param>
/// <returns>True if item is present in the collection.</returns>
public bool Contains(T item)
else
{
if (Find(item) != null)
{
return true;
}
return false;
}
/// <summary>
/// Copies the skip list contents onto the provided array.
/// </summary>
/// <param name="array">Array to hold the values from the list.</param>
/// <param name="arrayIndex">Index to start insertion in the array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
NodeSet<T> node = head.Next[0];
while (node != end)
{
array[arrayIndex] = node.Key;
arrayIndex++;
node = node.Next[0];
}
}
/// <summary>
/// Copies the elements from the collection into an array.
/// </summary>
/// <returns>Array filled with elements from the collection.</returns>
public T[] ToArray()
{
T[] array = new T[count];
int index = 0;
NodeSet<T> curNode = head.Next[0];
while (curNode != end)
{
array[index] = curNode.Key;
index++;
curNode = curNode.Next[0];
}
return array;
}
/// <summary>
/// Enumerator that iterates over the collection.
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
NodeSet<T> curNode = head.Next[0];
while (curNode != end)
{
yield return curNode.Key;
curNode = curNode.Next[0];
}
}
#endregion
#region Private Methods
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
private NodeSet<T> Find(T key)
{
NodeSet<T> curNode = head;
for (int i = level; i >= 0; i--)
{
while (curNode.Next[i] != end)
{
if (curNode.Next[i].Key.CompareTo(key) > 0)
{
break;
}
else if (curNode.Next[i].Key.CompareTo(key) == 0)
{
return curNode.Next[i];
}
curNode = curNode.Next[i];
}
}
curNode = curNode.Next[0];
if (curNode != end && curNode.Key.CompareTo(key) == 0)
{
return curNode;
}
return null;
}
#endregion
}
/// <summary>
/// Clears the collection.
/// </summary>
public void Clear()
{
for (var i = 0; i < this.maxLevel; i++)
{
this.head.Next[i] = this.end;
}
this.count = 0;
}
/// <summary>
/// Checks if item is present in the collection.
/// </summary>
/// <param name="item">Item to be checked.</param>
/// <returns>True if item is present in the collection.</returns>
public bool Contains(T item)
{
if (this.Find(item) != null)
{
return true;
}
return false;
}
/// <summary>
/// Copies the skip list contents onto the provided array.
/// </summary>
/// <param name="array">Array to hold the values from the list.</param>
/// <param name="arrayIndex">Index to start insertion in the array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
var node = this.head.Next[0];
while (node != this.end)
{
array[arrayIndex] = node.Key;
arrayIndex++;
node = node.Next[0];
}
}
/// <summary>
/// Copies the elements from the collection into an array.
/// </summary>
/// <returns>Array filled with elements from the collection.</returns>
public T[] ToArray()
{
var array = new T[this.count];
var index = 0;
var curNode = this.head.Next[0];
while (curNode != this.end)
{
array[index] = curNode.Key;
index++;
curNode = curNode.Next[0];
}
return array;
}
/// <summary>
/// Enumerator that iterates over the collection.
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
var curNode = this.head.Next[0];
while (curNode != this.end)
{
yield return curNode.Key;
curNode = curNode.Next[0];
}
}
#endregion
#region Private Methods
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
private NodeSet<T> Find(T key)
{
var curNode = this.head;
for (var i = this.level; i >= 0; i--)
{
while (curNode.Next[i] != this.end)
{
if (curNode.Next[i].Key.CompareTo(key) > 0)
{
break;
}
else if (curNode.Next[i].Key.CompareTo(key) == 0)
{
return curNode.Next[i];
}
curNode = curNode.Next[i];
}
}
curNode = curNode.Next[0];
if (curNode != this.end && curNode.Key.CompareTo(key) == 0)
{
return curNode;
}
return null;
}
#endregion
}
+280 -273
View File
@@ -1,280 +1,287 @@
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>
#region Fields
[Serializable]
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
private class Node<TKey>
{
#region Fields
[Serializable]
private class Node<TKey>
public TKey Key;
public int Priority;
public Node<TKey> Left, Right;
public Node(TKey key, int priority)
{
public TKey Key;
public int Priority;
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;
private Node<T> root;
private int count;
#endregion
#region Properties
/// <summary>
/// Count of values in the treap.
/// </summary>
public int Count
{
get
{
return count;
}
}
/// <summary>
/// Not implemented.
/// </summary>
public bool IsReadOnly => false;
#endregion
#region Constructors
/// <summary>
/// Constructor for treap.
/// </summary>
public Treap()
{
randomGen = new Random();
}
#endregion
#region Public Methods
/// <summary>
/// Adds value to the treap.
/// </summary>
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
root = InsertNode(root, value);
count++;
}
/// <summary>
/// Removes value from treap.
/// </summary>
/// <param name="value">Value to be removed.</param>
public bool Remove(T value)
{
root = RemoveNode(root, value);
count--;
return true;
}
/// <summary>
/// Clears the treap.
/// </summary>
public void Clear()
{
Clear(root);
root = null;
count = 0;
}
/// <summary>
/// Determines whether the treap contains the specified value.
/// </summary>
/// <param name="value">Value to locate in the treap.</param>
/// <returns></returns>
public bool Contains(T value)
{
return Find(root, value) != null;
}
/// <summary>
/// Returns the treap structure as an ordered array.
/// </summary>
/// <returns>Ordered array containing the values stored in the treap.</returns>
public T[] ToArray()
{
if (root != null)
{
T[] array = new T[count];
int index = 0;
ToArray(root, ref array, ref index);
return array;
}
else
{
return null;
}
}
/// <summary>
/// Copy the treap into the provided array.
/// </summary>
/// <param name="array">Array to be populated with the values contained in the array.</param>
/// <param name="arrayIndex">Starting index of the array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
ToArray(root, ref array, ref arrayIndex);
}
/// <summary>
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
/// </summary>
/// <returns>Enumerator that iterates over the treap.</returns>
public IEnumerator<T> GetEnumerator()
{
return GetEnumerator(root);
}
#endregion
#region Private Methods
private Node<T> InsertNode(Node<T> node, T key)
{
if (node == null)
{
node = new Node<T>(key, randomGen.Next(0, 100));
return node;
}
else if (key.CompareTo(node.Key) <= 0)
{
node.Left = InsertNode(node.Left, key);
if (node.Left.Priority > node.Priority)
{
node = RotateRight(node);
}
}
else
{
node.Right = InsertNode(node.Right, key);
if (node.Right.Priority > node.Priority)
{
node = RotateLeft(node);
}
}
return node;
}
private Node<T> RemoveNode(Node<T> node, T key)
{
if (node == null)
{
return node;
}
if (key.CompareTo(node.Key) < 0)
{
node.Left = RemoveNode(node.Left, key);
}
else if (key.CompareTo(node.Key) > 0)
{
node.Right = RemoveNode(node.Right, key);
}
else if (node.Left == null)
{
node = node.Right;
}
else if (node.Right == null)
{
node = node.Left;
}
else if (node.Left.Priority < node.Right.Priority)
{
node = RotateLeft(node);
node.Left = RemoveNode(node.Left, key);
}
else
{
node = RotateRight(node);
node.Right = RemoveNode(node.Right, key);
}
return node;
}
private Node<T> RotateRight(Node<T> node)
{
Node<T> temp = node.Left, temp2 = temp.Right;
temp.Right = node;
node.Left = temp2;
return temp;
}
private Node<T> RotateLeft(Node<T> node)
{
Node<T> temp = node.Right, temp2 = temp.Left;
temp.Left = node;
node.Right = temp2;
return temp;
}
private void Clear(Node<T> node)
{
if (node.Left != null)
{
Clear(node.Left);
}
if (node.Right != null)
{
Clear(node.Right);
}
node.Left = node.Right = null;
}
private Node<T> Find(Node<T> node, T key)
{
if (node == null)
{
return node;
}
else
{
if (node.Key.CompareTo(key) < 0)
{
Node<T> found = Find(node.Left, key);
if (found == null)
{
found = Find(node.Right, key);
}
return found;
}
else if (node.Key.CompareTo(key) > 0)
{
Node<T> found = Find(node.Right, key);
if (found == null)
{
found = Find(node.Left, key);
}
return found;
}
else
{
return node;
}
}
}
private void ToArray(Node<T> node, ref T[] array, ref int index)
{
if (node != null)
{
ToArray(node.Left, ref array, ref index);
array[index] = node.Key;
index++;
ToArray(node.Right, ref array, ref index);
}
}
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
{
Queue<Node<T>> queue = new Queue<Node<T>>();
queue.Enqueue(currentNode);
while (queue.Count > 0)
{
currentNode = queue.Dequeue();
yield return currentNode.Key;
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
private readonly Random randomGen;
private Node<T> root;
private int count;
#endregion
#region Properties
/// <summary>
/// Count of values in the treap.
/// </summary>
public int Count
{
get
{
return this.count;
}
}
/// <summary>
/// Not implemented.
/// </summary>
public bool IsReadOnly => false;
#endregion
#region Constructors
/// <summary>
/// Constructor for treap.
/// </summary>
public Treap()
{
this.randomGen = new Random();
}
#endregion
#region Public Methods
/// <summary>
/// Adds value to the treap.
/// </summary>
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
this.root = this.InsertNode(this.root, value);
this.count++;
}
/// <summary>
/// Removes value from treap.
/// </summary>
/// <param name="value">Value to be removed.</param>
public bool Remove(T value)
{
this.root = this.RemoveNode(this.root, value);
this.count--;
return true;
}
/// <summary>
/// Clears the treap.
/// </summary>
public void Clear()
{
this.Clear(this.root);
this.root = null;
this.count = 0;
}
/// <summary>
/// Determines whether the treap contains the specified value.
/// </summary>
/// <param name="value">Value to locate in the treap.</param>
/// <returns></returns>
public bool Contains(T value)
{
return this.Find(this.root, value) != null;
}
/// <summary>
/// Returns the treap structure as an ordered array.
/// </summary>
/// <returns>Ordered array containing the values stored in the treap.</returns>
public T[] ToArray()
{
if (this.root != null)
{
var array = new T[this.count];
var index = 0;
this.ToArray(this.root, ref array, ref index);
return array;
}
else
{
return null;
}
}
/// <summary>
/// Copy the treap into the provided array.
/// </summary>
/// <param name="array">Array to be populated with the values contained in the array.</param>
/// <param name="arrayIndex">Starting index of the array.</param>
public void CopyTo(T[] array, int 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.
/// </summary>
/// <returns>Enumerator that iterates over the treap.</returns>
public IEnumerator<T> GetEnumerator()
{
return this.GetEnumerator(this.root);
}
#endregion
#region Private Methods
private Node<T> InsertNode(Node<T> node, T key)
{
if (node == null)
{
node = new Node<T>(key, this.randomGen.Next(0, 100));
return node;
}
else if (key.CompareTo(node.Key) <= 0)
{
node.Left = this.InsertNode(node.Left, key);
if (node.Left.Priority > node.Priority)
{
node = this.RotateRight(node);
}
}
else
{
node.Right = this.InsertNode(node.Right, key);
if (node.Right.Priority > node.Priority)
{
node = this.RotateLeft(node);
}
}
return node;
}
private Node<T> RemoveNode(Node<T> node, T key)
{
if (node == null)
{
return node;
}
if (key.CompareTo(node.Key) < 0)
{
node.Left = this.RemoveNode(node.Left, key);
}
else if (key.CompareTo(node.Key) > 0)
{
node.Right = this.RemoveNode(node.Right, key);
}
else if (node.Left == null)
{
node = node.Right;
}
else if (node.Right == null)
{
node = node.Left;
}
else if (node.Left.Priority < node.Right.Priority)
{
node = this.RotateLeft(node);
node.Left = this.RemoveNode(node.Left, key);
}
else
{
node = this.RotateRight(node);
node.Right = this.RemoveNode(node.Right, key);
}
return node;
}
private Node<T> RotateRight(Node<T> node)
{
Node<T> temp = node.Left, temp2 = temp.Right;
temp.Right = node;
node.Left = temp2;
return temp;
}
private Node<T> RotateLeft(Node<T> node)
{
Node<T> temp = node.Right, temp2 = temp.Left;
temp.Left = node;
node.Right = temp2;
return temp;
}
private void Clear(Node<T> node)
{
if (node.Left != null)
{
this.Clear(node.Left);
}
if (node.Right != null)
{
this.Clear(node.Right);
}
node.Left = node.Right = null;
}
private Node<T> Find(Node<T> node, T key)
{
if (node == null)
{
return node;
}
else
{
if (node.Key.CompareTo(key) < 0)
{
var found = this.Find(node.Left, key);
if (found == null)
{
found = this.Find(node.Right, key);
}
return found;
}
else if (node.Key.CompareTo(key) > 0)
{
var found = this.Find(node.Right, key);
if (found == null)
{
found = this.Find(node.Left, key);
}
return found;
}
else
{
return node;
}
}
}
private void ToArray(Node<T> node, ref T[] array, ref int index)
{
if (node != null)
{
this.ToArray(node.Left, ref array, ref index);
array[index] = node.Key;
index++;
this.ToArray(node.Right, ref array, ref index);
}
}
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
{
var queue = new Queue<Node<T>>();
queue.Enqueue(currentNode);
while (queue.Count > 0)
{
currentNode = queue.Dequeue();
yield return currentNode.Key;
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
}
if (currentNode.Right != null)
{
queue.Enqueue(currentNode.Right);
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
@@ -1,24 +1,24 @@
using System.IO;
namespace System.Extensions
namespace System.Extensions;
public static class BytesExtensions
{
public static class BytesExtensions
public static byte[] ReadAllBytes(this Stream stream)
{
public static byte[] ReadAllBytes(this Stream stream)
if (stream is null)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
var buffer = new byte[256];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = stream.Read(buffer, 0, 256)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
throw new ArgumentNullException(nameof(stream));
}
var buffer = new byte[256];
using var ms = new MemoryStream();
int read;
while ((read = stream.Read(buffer, 0, 256)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
@@ -1,50 +1,49 @@
namespace System.Extensions
namespace System.Extensions;
public static class CastExtensions
{
public static class CastExtensions
public static int Floor(this double value)
{
public static int Floor(this double value)
{
return (int)Math.Floor(value);
}
return (int)Math.Floor(value);
}
public static int Ceiling(this double value)
{
return (int)Math.Ceiling(value);
}
public static int Ceiling(this double value)
{
return (int)Math.Ceiling(value);
}
public static int Round(this double value)
{
return (int)Math.Round(value);
}
public static int Round(this double value)
{
return (int)Math.Round(value);
}
public static int Floor(this float value)
{
return (int)Math.Floor(value);
}
public static int Floor(this float value)
{
return (int)Math.Floor(value);
}
public static int Ceiling(this float value)
{
return (int)Math.Ceiling(value);
}
public static int Ceiling(this float value)
{
return (int)Math.Ceiling(value);
}
public static int Round(this float value)
{
return (int)Math.Round(value);
}
public static int Round(this float value)
{
return (int)Math.Round(value);
}
public static int ToInt(this double value)
{
return (int)value;
}
public static int ToInt(this double value)
{
return (int)value;
}
public static int ToInt(this float value)
{
return (int)value;
}
public static int ToInt(this float value)
{
return (int)value;
}
public static int ToInt(this decimal value)
{
return (int)value;
}
public static int ToInt(this decimal value)
{
return (int)value;
}
}
@@ -1,71 +1,88 @@
using System.Collections.Generic;
using System.Linq;
namespace System.Extensions
namespace System.Extensions;
public static class LinqExtensions
{
public static class LinqExtensions
public static bool None<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
public static bool None<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
enumerable.ThrowIfNull(nameof(enumerable));
predicate.ThrowIfNull(nameof(predicate));
enumerable.ThrowIfNull(nameof(enumerable));
predicate.ThrowIfNull(nameof(predicate));
return !enumerable.Any(predicate);
return !enumerable.Any(predicate);
}
public static bool None<T>(this IEnumerable<T> enumerable)
{
enumerable.ThrowIfNull(nameof(enumerable));
return !enumerable.Any();
}
public static ICollection<T> ClearAnd<T>(this ICollection<T> collection)
{
if (collection is null)
{
throw new ArgumentNullException(nameof(collection));
}
public static bool None<T>(this IEnumerable<T> enumerable)
collection.Clear();
return collection;
}
public static ICollection<T> AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
{
if (collection is null)
{
enumerable.ThrowIfNull(nameof(enumerable));
return !enumerable.Any();
throw new ArgumentNullException(nameof(collection));
}
public static ICollection<T> ClearAnd<T>(this ICollection<T> collection)
if (values is null)
{
if (collection is null) throw new ArgumentNullException(nameof(collection));
collection.Clear();
return collection;
throw new ArgumentNullException(nameof(values));
}
public static ICollection<T> AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
{
if (collection is null) throw new ArgumentNullException(nameof(collection));
if (values is null) throw new ArgumentNullException(nameof(values));
foreach(var item in values)
foreach (var item in values)
{
collection.Add(item);
}
return collection;
}
public static int IndexOfWhere<T>(this ICollection<T> collection, Func<T, bool> selector)
{
if (collection is null)
{
throw new ArgumentNullException(nameof(collection));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}
var index = 0;
foreach (var item in collection)
{
if (selector(item))
{
collection.Add(item);
return index;
}
return collection;
index++;
}
public static int IndexOfWhere<T>(this ICollection<T> collection, Func<T, bool> selector)
return -1;
}
public static IEnumerable<T> Do<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach(var value in enumerable)
{
if (collection is null) throw new ArgumentNullException(nameof(collection));
if (selector is null) throw new ArgumentNullException(nameof(selector));
var index = 0;
foreach (var item in collection)
{
if (selector(item))
{
return index;
}
index++;
}
return -1;
}
public static IEnumerable<T> Do<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach(var value in enumerable)
{
action(value);
yield return value;
}
action(value);
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,32 +1,58 @@
namespace System.Extensions
using Newtonsoft.Json;
namespace System.Extensions;
public static class ObjectExtensions
{
public static class ObjectExtensions
public static T Deserialize<T>(this string serialized)
where T : class
{
public static T Cast<T>(this object obj)
if (serialized.IsNullOrWhiteSpace())
{
return (T)obj;
throw new ArgumentException("Provided serialized string cannot be null or whitespace", nameof(serialized));
}
public static T As<T>(this object obj) where T : class
return JsonConvert.DeserializeObject<T>(serialized);
}
public static string Serialize<T>(this T obj)
where T : class
{
if (obj is null)
{
return obj as T;
throw new ArgumentNullException(nameof(obj));
}
public static Optional<T> ToOptional<T>(this T obj)
return JsonConvert.SerializeObject(obj);
}
public static T Cast<T>(this object obj)
{
return (T)obj;
}
public static T As<T>(this object obj) where T : class
{
return obj as T;
}
public static Optional<T> ToOptional<T>(this T obj)
{
return Optional.FromValue(obj);
}
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, string name) where T : class
{
if (obj is null)
{
return Optional.FromValue(obj);
throw new ArgumentNullException(name);
}
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, string name) where T : class
{
if (obj is null) throw new ArgumentNullException(name);
return obj;
}
return obj;
}
[AttributeUsage(AttributeTargets.Parameter)]
sealed class ValidatedNotNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter)]
sealed class ValidatedNotNullAttribute : Attribute
{
}
}
@@ -1,178 +1,193 @@
namespace System.Extensions
namespace System.Extensions;
public static class Optional
{
public static class Optional
public static Optional<T> None<T>()
{
public static Optional<T> None<T>()
return new Optional<T>.None();
}
public static Optional<T> FromValue<T>(T value)
{
if (value == null)
{
return new Optional<T>.None();
}
public static Optional<T> FromValue<T>(T value)
{
if (value == null)
{
return new Optional<T>.None();
}
return new Optional<T>.Some(value);
}
}
return new Optional<T>.Some(value);
public abstract class Optional<T> : IEquatable<Optional<T>>
{
public Optional(T value)
{
this.Value = value;
}
private T Value { get; }
public T ExtractValue()
{
if (this is None)
{
return default;
}
else
{
return this.Value;
}
}
public Optional<T> Do(Action<T> onSome, Action onNone)
{
if (onSome is null)
{
throw new ArgumentNullException(nameof(onSome));
}
if (onNone is null)
{
throw new ArgumentNullException(nameof(onNone));
}
if (this is Some)
{
onSome.Invoke(this.Value);
}
else
{
onNone.Invoke();
}
return this;
}
public Optional<T> DoAny(Action<T> onSome = null, Action onNone = null)
{
if (this is Some)
{
onSome?.Invoke(this.Value);
}
else
{
onNone?.Invoke();
}
return this;
}
public Optional<V> Switch<V>(Func<T, V> onSome, Func<V> onNone)
{
if (onSome is null)
{
throw new ArgumentNullException($"{nameof(onSome)}");
}
if (onNone is null)
{
throw new ArgumentNullException($"{nameof(onNone)}");
}
if (this is Some)
{
return Optional.FromValue(onSome.Invoke(this.Value));
}
else
{
return Optional.FromValue(onNone.Invoke());
}
}
public Optional<V> SwitchAny<V>(Func<T, V> onSome = null, Func<V> onNone = null)
{
if (this is Some)
{
return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V));
}
else
{
return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V));
}
}
public abstract class Optional<T> : IEquatable<Optional<T>>
public override bool Equals(object obj)
{
public Optional(T value)
if (obj is Optional<T>)
{
this.Value = value;
return this.Equals(obj);
}
private T Value { get; }
return base.Equals(obj);
}
public T ExtractValue()
public bool Equals(Optional<T> other)
{
if (this is Some && other is Some)
{
if (this is None)
{
return default;
}
else
{
return Value;
}
return this.As<Some>().Equals(other.As<Some>());
}
public Optional<T> Do(Action<T> onSome, Action onNone)
{
if (onSome is null) throw new ArgumentNullException(nameof(onSome));
if (onNone is null) throw new ArgumentNullException(nameof(onNone));
if (this is Some)
{
onSome.Invoke(this.Value);
}
else
{
onNone.Invoke();
}
return this;
}
public Optional<T> DoAny(Action<T> onSome = null, Action onNone = null)
{
if (this is Some)
{
onSome?.Invoke(this.Value);
}
else
{
onNone?.Invoke();
}
return this;
}
public Optional<V> Switch<V>(Func<T, V> onSome, Func<V> onNone)
{
if (onSome is null) throw new ArgumentNullException($"{nameof(onSome)}");
if (onNone is null) throw new ArgumentNullException($"{nameof(onNone)}");
return false;
}
if (this is Some)
{
return Optional.FromValue(onSome.Invoke(this.Value));
}
else
{
return Optional.FromValue(onNone.Invoke());
}
}
public Optional<V> SwitchAny<V>(Func<T, V> onSome = null, Func<V> onNone = null)
public static implicit operator Optional<T>(T value)
{
return Optional.FromValue(value);
}
public override int GetHashCode()
{
return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode();
}
internal class Some : Optional<T>, IEquatable<Some>
{
public Some(T value) : base(value)
{
if (this is Some)
{
return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V));
}
else
{
return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V));
}
}
public override bool Equals(object obj)
{
if (obj is Optional<T>)
if (obj is Some)
{
return this.Equals(obj);
return this.Equals(obj.As<Some>());
}
return base.Equals(obj);
}
public bool Equals(Optional<T> other)
public bool Equals(Some other)
{
if (this is Some && other is Some)
if (other is None)
{
return this.As<Some>().Equals(other.As<Some>());
return false;
}
if (other is Some)
{
return this.Value.Equals(other.Value);
}
return false;
}
public static implicit operator Optional<T>(T value)
public static bool operator ==(Some left, Some right)
{
return Optional.FromValue(value);
return left?.Equals(right) == true;
}
public static bool operator !=(Some left, Some right)
{
return left?.Equals(right) != true;
}
public override int GetHashCode()
{
return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode();
return this.Value is object ? this.Value.GetHashCode() : this.As<object>().GetHashCode();
}
}
internal class Some : Optional<T>, IEquatable<Some>
internal class None : Optional<T>
{
public None() : base(default)
{
public Some(T value) : base(value)
{
}
public override bool Equals(object obj)
{
if (obj is Some)
{
return this.Equals(obj.As<Some>());
}
return base.Equals(obj);
}
public bool Equals(Some other)
{
if (other is None)
{
return false;
}
if (other is Some)
{
return this.Value.Equals(other.Value);
}
return false;
}
public static bool operator ==(Some left, Some right)
{
return left?.Equals(right) == true;
}
public static bool operator !=(Some left, Some right)
{
return left?.Equals(right) != true;
}
public override int GetHashCode()
{
return this.Value is object ? this.Value.GetHashCode() : this.As<object>().GetHashCode();
}
}
internal class None : Optional<T>
{
public None() : base(default)
{
}
}
}
}
+206 -175
View File
@@ -1,185 +1,216 @@
namespace System.Extensions
namespace System.Extensions;
public class Result<TSuccess, TFailure>
{
public class Result<TSuccess, TFailure>
private readonly object value;
public Result(TSuccess successValue)
{
private readonly object value;
this.value = successValue;
}
public Result(TFailure failureValue)
{
this.value = failureValue;
}
public Result(TSuccess successValue)
{
value = successValue;
}
public Result(TFailure failureValue)
{
value = failureValue;
}
public bool TryExtractSuccess(out TSuccess successValue)
{
public bool TryExtractSuccess(out TSuccess successValue)
if (this.value is TSuccess success)
{
if (value is TSuccess success)
{
successValue = success;
return true;
}
else
{
successValue = default;
return false;
}
successValue = success;
return true;
}
public bool TryExtractFailure(out TFailure failureValue)
else
{
if (value is TFailure failure)
{
failureValue = failure;
return true;
}
else
{
failureValue = default;
return false;
}
}
public Result<TSuccess, TFailure> Do(Action onSuccess, Action onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (value is TSuccess)
{
onSuccess.Invoke();
}
else if (value is TFailure)
{
onFailure.Invoke();
}
return this;
}
public Result<TSuccess, TFailure> DoAny(Action onSuccess = null, Action onFailure = null)
{
if (value is TSuccess)
{
onSuccess?.Invoke();
}
else if (value is TFailure)
{
onFailure?.Invoke();
}
return this;
}
public Result<TSuccess, TFailure> Do(Action<TSuccess> onSuccess, Action<TFailure> onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (value is TSuccess success)
{
onSuccess.Invoke(success);
}
else if (value is TFailure failure)
{
onFailure.Invoke(failure);
}
return this;
}
public Result<TSuccess, TFailure> DoAny(Action<TSuccess> onSuccess = null, Action<TFailure> onFailure = null)
{
if (value is TSuccess success)
{
onSuccess?.Invoke(success);
}
else if (value is TFailure failure)
{
onFailure?.Invoke(failure);
}
return this;
}
public T Switch<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (value is TSuccess success)
{
return onSuccess.Invoke(success);
}
else if (value is TFailure failure)
{
return onFailure.Invoke(failure);
}
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
}
public T SwitchAny<T>(Func<TSuccess, T> onSuccess = null, Func<TFailure, T> onFailure = null)
{
if (value is TSuccess success)
{
return onSuccess is null ? default : onSuccess.Invoke(success);
}
else if (value is TFailure failure)
{
return onFailure is null ? default : onFailure.Invoke(failure);
}
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
}
public Result<V, K> Switch<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (value is TSuccess success)
{
return Result<V, K>.Success(onSuccess.Invoke(success));
}
else if (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)}");
}
public Result<V, K> SwitchAny<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
if (value is TSuccess success)
{
return Result<V, K>.Success(onSuccess is null ? default : onSuccess.Invoke(success));
}
else if (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)}");
}
public Optional<TSuccess> ToOptional()
{
if (value is TSuccess)
{
return Optional.FromValue(value.Cast<TSuccess>());
}
return Optional.None<TSuccess>();
}
public static implicit operator Result<TSuccess, TFailure>(TSuccess success)
{
return Success(success);
}
public static implicit operator Result<TSuccess, TFailure>(TFailure failure)
{
return Failure(failure);
}
public static Result<TSuccess, TFailure> Success(TSuccess value)
{
return new Result<TSuccess, TFailure>(value);
}
public static Result<TSuccess, TFailure> Failure(TFailure value)
{
return new Result<TSuccess, TFailure>(value);
successValue = default;
return false;
}
}
public bool TryExtractFailure(out TFailure failureValue)
{
if (this.value is TFailure failure)
{
failureValue = failure;
return true;
}
else
{
failureValue = default;
return false;
}
}
public Result<TSuccess, TFailure> Do(Action onSuccess, Action onFailure)
{
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (this.value is TSuccess)
{
onSuccess.Invoke();
}
else if (this.value is TFailure)
{
onFailure.Invoke();
}
return this;
}
public Result<TSuccess, TFailure> DoAny(Action onSuccess = null, Action onFailure = null)
{
if (this.value is TSuccess)
{
onSuccess?.Invoke();
}
else if (this.value is TFailure)
{
onFailure?.Invoke();
}
return this;
}
public Result<TSuccess, TFailure> Do(Action<TSuccess> onSuccess, Action<TFailure> onFailure)
{
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (this.value is TSuccess success)
{
onSuccess.Invoke(success);
}
else if (this.value is TFailure failure)
{
onFailure.Invoke(failure);
}
return this;
}
public Result<TSuccess, TFailure> DoAny(Action<TSuccess> onSuccess = null, Action<TFailure> onFailure = null)
{
if (this.value is TSuccess success)
{
onSuccess?.Invoke(success);
}
else if (this.value is TFailure failure)
{
onFailure?.Invoke(failure);
}
return this;
}
public T Switch<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure)
{
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (this.value is TSuccess success)
{
return onSuccess.Invoke(success);
}
else if (this.value is TFailure failure)
{
return onFailure.Invoke(failure);
}
throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
}
public T SwitchAny<T>(Func<TSuccess, T> onSuccess = null, Func<TFailure, T> onFailure = null)
{
if (this.value is TSuccess success)
{
return onSuccess is null ? default : onSuccess.Invoke(success);
}
else if (this.value is TFailure failure)
{
return onFailure is null ? default : onFailure.Invoke(failure);
}
throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
}
public Result<V, K> Switch<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (this.value is TSuccess success)
{
return Result<V, K>.Success(onSuccess.Invoke(success));
}
else if (this.value is TFailure failure)
{
return Result<V, K>.Failure(onFailure.Invoke(failure));
}
throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}");
}
public Result<V, K> SwitchAny<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
if (this.value is TSuccess success)
{
return Result<V, K>.Success(onSuccess is null ? default : onSuccess.Invoke(success));
}
else if (this.value is TFailure failure)
{
return Result<V, K>.Failure(onFailure is null ? default : onFailure.Invoke(failure));
}
throw new InvalidOperationException($"{nameof(this.value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}");
}
public Optional<TSuccess> ToOptional()
{
if (this.value is TSuccess)
{
return Optional.FromValue(this.value.Cast<TSuccess>());
}
return Optional.None<TSuccess>();
}
public static implicit operator Result<TSuccess, TFailure>(TSuccess success)
{
return Success(success);
}
public static implicit operator Result<TSuccess, TFailure>(TFailure failure)
{
return Failure(failure);
}
public static Result<TSuccess, TFailure> Success(TSuccess value)
{
return new Result<TSuccess, TFailure>(value);
}
public static Result<TSuccess, TFailure> Failure(TFailure value)
{
return new Result<TSuccess, TFailure>(value);
}
}
@@ -1,67 +1,84 @@
using System.IO;
using System.Text;
namespace System.Extensions
namespace System.Extensions;
public static class StreamExtensions
{
public static class StreamExtensions
public static void DoWhileReading(this Stream stream, Action<int, byte[]> action, int bufferLength = 256)
{
public static void DoWhileReading(this Stream stream, Action<int, byte[]> action, int bufferLength = 256)
if (stream is null)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
if (action is null) throw new ArgumentNullException(nameof(action));
var buffer = new byte[bufferLength];
var read = stream.Read(buffer, 0, bufferLength);
while(read > 0)
{
action(bufferLength, buffer);
read = stream.Read(buffer, 0, bufferLength);
}
throw new ArgumentNullException(nameof(stream));
}
public static byte[] ReadBytes(this Stream stream, int count)
if (action is null)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
var buffer = new byte[count];
stream.Read(buffer, 0, count);
return buffer;
throw new ArgumentNullException(nameof(action));
}
public static Stream Rewind(this Stream stream)
var buffer = new byte[bufferLength];
var read = stream.Read(buffer, 0, bufferLength);
while(read > 0)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
if (!stream.CanSeek) throw new InvalidOperationException("Stream doesn't support rewinding");
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
public static string ReadUntil(this StreamReader sr, string delim)
{
var sb = new StringBuilder();
bool found = false;
while (!found && !sr.EndOfStream)
{
for (int i = 0; i < delim.Length; i++)
{
char c = (char)sr.Read();
sb.Append(c);
if (c != delim[i])
break;
if (i == delim.Length - 1)
{
sb.Remove(sb.Length - delim.Length, delim.Length);
found = true;
}
}
}
return sb.ToString();
action(bufferLength, buffer);
read = stream.Read(buffer, 0, bufferLength);
}
}
public static byte[] ReadBytes(this Stream stream, int count)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
var buffer = new byte[count];
stream.Read(buffer, 0, count);
return buffer;
}
public static Stream Rewind(this Stream stream)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
if (!stream.CanSeek)
{
throw new InvalidOperationException("Stream doesn't support rewinding");
}
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
public static string ReadUntil(this StreamReader sr, string delim)
{
var sb = new StringBuilder();
var found = false;
while (!found && !sr.EndOfStream)
{
for (var i = 0; i < delim.Length; i++)
{
var c = (char)sr.Read();
sb.Append(c);
if (c != delim[i])
{
break;
}
if (i == delim.Length - 1)
{
sb.Remove(sb.Length - delim.Length, delim.Length);
found = true;
}
}
}
return sb.ToString();
}
}
@@ -1,27 +1,26 @@
using System.Text;
namespace System.Extensions
namespace System.Extensions;
public static class StringExtensions
{
public static class StringExtensions
public static bool IsNullOrEmpty(this string s)
{
public static bool IsNullOrEmpty(this string s)
{
return string.IsNullOrEmpty(s);
}
return string.IsNullOrEmpty(s);
}
public static bool IsNullOrWhiteSpace(this string s)
{
return string.IsNullOrWhiteSpace(s);
}
public static bool IsNullOrWhiteSpace(this string s)
{
return string.IsNullOrWhiteSpace(s);
}
public static byte[] GetBytes(this string s)
{
return Encoding.UTF8.GetBytes(s);
}
public static byte[] GetBytes(this string s)
{
return Encoding.UTF8.GetBytes(s);
}
public static string GetString(this byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
public static string GetString(this byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
}
@@ -2,179 +2,184 @@
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>
/// <typeparam name="T">Result type.</typeparam>
/// <param name="task">Task.</param>
/// <returns>The started <see cref="Task{TResult}"/></returns>
public static Task<T> LongRunning<T>(this Task<T> task)
{
/// <summary>
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
/// </summary>
/// <typeparam name="T">Result type.</typeparam>
/// <param name="task">Task.</param>
/// <returns>The started <see cref="Task{TResult}"/></returns>
public static Task<T> LongRunning<T>(this Task<T> task)
return Task.Factory.StartNew(async () =>
{
return Task.Factory.StartNew(async () =>
{
return await task;
}, TaskCreationOptions.LongRunning).Unwrap();
return await task;
}, TaskCreationOptions.LongRunning).Unwrap();
}
/// <summary>
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
/// </summary>
/// <param name="task">Task.</param>
/// <returns>The started <see cref="Task"/></returns>
public static Task LongRunning(this Task task)
{
return Task.Factory.StartNew(async () =>
{
await task;
}, TaskCreationOptions.LongRunning).Unwrap();
}
/// <summary>
/// Execute action periodically and asynchronously.
/// </summary>
/// <param name="onTick">Action to be executed.</param>
/// <param name="dueTime">Time to pass before starting to execute.</param>
/// <param name="interval">Interval between procs.</param>
/// <param name="token">Cancellation token used to cancel the cycle.</param>
/// <returns></returns>
public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token)
{
if (dueTime > TimeSpan.Zero)
{
await Task.Delay(dueTime, token).ConfigureAwait(false);
}
/// <summary>
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
/// </summary>
/// <param name="task">Task.</param>
/// <returns>The started <see cref="Task"/></returns>
public static Task LongRunning(this Task task)
while (!token.IsCancellationRequested)
{
return Task.Factory.StartNew(async () =>
onTick?.Invoke();
if (interval > TimeSpan.Zero)
{
await task;
}, TaskCreationOptions.LongRunning).Unwrap();
}
/// <summary>
/// Execute action periodically and asynchronously.
/// </summary>
/// <param name="onTick">Action to be executed.</param>
/// <param name="dueTime">Time to pass before starting to execute.</param>
/// <param name="interval">Interval between procs.</param>
/// <param name="token">Cancellation token used to cancel the cycle.</param>
/// <returns></returns>
public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token)
{
if (dueTime > TimeSpan.Zero)
await Task.Delay(dueTime, token).ConfigureAwait(false);
while (!token.IsCancellationRequested)
{
onTick?.Invoke();
if (interval > TimeSpan.Zero)
await Task.Delay(interval, token).ConfigureAwait(false);
}
}
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(this Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(this Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default(T);
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
new Queue<Tuple<SendOrPostCallback, object>>();
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
public override void Post(SendOrPostCallback d, object state)
{
lock (items)
{
items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => done = true, null);
}
public void BeginMessageLoop()
{
while (!done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
{
if (items.Count > 0)
{
task = items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
await Task.Delay(interval, token).ConfigureAwait(false);
}
}
}
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(this Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(this Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
var ret = default(T);
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
new Queue<Tuple<SendOrPostCallback, object>>();
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
public override void Post(SendOrPostCallback d, object state)
{
lock (this.items)
{
this.items.Enqueue(Tuple.Create(d, state));
}
this.workItemsWaiting.Set();
}
public void EndMessageLoop()
{
this.Post(_ => this.done = true, null);
}
public void BeginMessageLoop()
{
while (!this.done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (this.items)
{
if (this.items.Count > 0)
{
task = this.items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (this.InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncHelpers.Run method threw an exception.", this.InnerException);
}
}
else
{
this.workItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
}
+52 -48
View File
@@ -1,69 +1,73 @@
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)
{
public static Try<TResult> Action<TResult>(Func<TResult> act)
return new Try<TResult>(act);
}
}
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)
{
this.action = action;
}
public static Try<TResult> Action(Func<TResult> act)
{
return new Try<TResult>(act);
}
public Try<TResult> Catch<TException>(Func<TException, TResult> act) where TException : Exception
{
this.catchActions.Add((Func<Exception, TResult>)act);
return this;
}
public TResult Run()
{
try
{
return new Try<TResult>(act);
return this.action();
}
catch (Exception ex)
{
foreach (var catchAction in this.catchActions)
{
return catchAction(ex);
}
throw;
}
}
public class Try<TResult>
public TResult Finally(Action act)
{
private readonly Func<TResult> action;
private readonly List<Func<Exception, TResult>> catchActions = new List<Func<Exception, TResult>>();
internal Try(Func<TResult> action)
if (act is null)
{
this.action = action;
}
public static Try<TResult> Action(Func<TResult> act)
{
return new Try<TResult>(act);
throw new ArgumentNullException(nameof(act));
}
public Try<TResult> Catch<TException>(Func<TException, TResult> act) where TException : Exception
try
{
this.catchActions.Add((Func<Exception, TResult>)act);
return this;
return this.action();
}
public TResult Run()
catch (Exception ex)
{
try
foreach (var catchAction in this.catchActions)
{
return action();
}
catch (Exception ex)
{
foreach (var catchAction in this.catchActions)
{
return catchAction(ex);
}
throw;
return catchAction(ex);
}
throw;
}
public TResult Finally(Action act)
finally
{
if (act is null) throw new ArgumentNullException(nameof(act));
try
{
return this.action();
}
catch (Exception ex)
{
foreach (var catchAction in this.catchActions)
{
return catchAction(ex);
}
throw;
}
finally
{
act();
}
act();
}
}
}
+202 -204
View File
@@ -1,217 +1,215 @@
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;
public event EventHandler<HttpClientEventMessage> EventEmitted
{
private readonly HttpClient httpClient;
private readonly Type scope;
private EventHandler<HttpClientEventMessage> eventEmitted;
public event EventHandler<HttpClientEventMessage> EventEmitted
add
{
add
{
this.eventEmitted += value;
}
remove
{
this.eventEmitted -= value;
}
this.eventEmitted += value;
}
public Uri BaseAddress { get => this.httpClient.BaseAddress; set => this.httpClient.BaseAddress = value; }
public HttpRequestHeaders DefaultRequestHeaders => this.httpClient.DefaultRequestHeaders;
public long MaxResponseContentBufferSize { get => this.httpClient.MaxResponseContentBufferSize; set => this.httpClient.MaxResponseContentBufferSize = value; }
public TimeSpan Timeout { get => this.httpClient.Timeout; set => this.httpClient.Timeout = value; }
public HttpClient()
remove
{
this.httpClient = new HttpClient();
this.scope = typeof(Tscope);
}
public HttpClient(
HttpMessageHandler handler)
{
this.httpClient = new HttpClient(handler);
this.scope = typeof(Tscope);
}
public HttpClient(
HttpMessageHandler handler,
bool disposeHandler)
{
this.httpClient = new HttpClient(handler, disposeHandler);
this.scope = typeof(Tscope);
}
public void CancelPendingRequests()
{
this.LogInformation(string.Empty, "Canceling request");
this.httpClient.CancelPendingRequests();
}
public Task<HttpResponseMessage> DeleteAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri);
}
public Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
}
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri);
}
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri);
}
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption);
}
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, cancellationToken);
}
public Task<byte[]> GetByteArrayAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetByteArrayAsync));
return this.httpClient.GetByteArrayAsync(requestUri);
}
public Task<byte[]> GetByteArrayAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetByteArrayAsync));
return this.httpClient.GetByteArrayAsync(requestUri);
}
public Task<Stream> GetStreamAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetStreamAsync));
return this.httpClient.GetStreamAsync(requestUri);
}
public Task<Stream> GetStreamAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetStreamAsync));
return this.httpClient.GetStreamAsync(requestUri);
}
public Task<string> GetStringAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetStringAsync));
return this.httpClient.GetStringAsync(requestUri);
}
public Task<string> GetStringAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetStringAsync));
return this.httpClient.GetStringAsync(requestUri);
}
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
{
this.LogInformation(requestUri, nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content);
}
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
{
this.LogInformation(requestUri.ToString(), nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content);
}
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content)
{
this.LogInformation(requestUri, nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content);
}
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content)
{
this.LogInformation(requestUri.ToString(), nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content);
}
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request, completionOption);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request, completionOption, cancellationToken);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request, cancellationToken);
}
public void Dispose()
{
this.httpClient.Dispose();
}
private void LogInformation(string url, string method)
{
this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url));
this.eventEmitted -= value;
}
}
public Uri BaseAddress { get => this.httpClient.BaseAddress; set => this.httpClient.BaseAddress = value; }
public HttpRequestHeaders DefaultRequestHeaders => this.httpClient.DefaultRequestHeaders;
public long MaxResponseContentBufferSize { get => this.httpClient.MaxResponseContentBufferSize; set => this.httpClient.MaxResponseContentBufferSize = value; }
public TimeSpan Timeout { get => this.httpClient.Timeout; set => this.httpClient.Timeout = value; }
public HttpClient()
{
this.httpClient = new HttpClient();
this.scope = typeof(Tscope);
}
public HttpClient(
HttpMessageHandler handler)
{
this.httpClient = new HttpClient(handler);
this.scope = typeof(Tscope);
}
public HttpClient(
HttpMessageHandler handler,
bool disposeHandler)
{
this.httpClient = new HttpClient(handler, disposeHandler);
this.scope = typeof(Tscope);
}
public void CancelPendingRequests()
{
this.LogInformation(string.Empty, "Canceling request");
this.httpClient.CancelPendingRequests();
}
public Task<HttpResponseMessage> DeleteAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri);
}
public Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
}
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri);
}
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(DeleteAsync));
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri);
}
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption);
}
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
}
public Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
return this.httpClient.GetAsync(requestUri, cancellationToken);
}
public Task<byte[]> GetByteArrayAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetByteArrayAsync));
return this.httpClient.GetByteArrayAsync(requestUri);
}
public Task<byte[]> GetByteArrayAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetByteArrayAsync));
return this.httpClient.GetByteArrayAsync(requestUri);
}
public Task<Stream> GetStreamAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetStreamAsync));
return this.httpClient.GetStreamAsync(requestUri);
}
public Task<Stream> GetStreamAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetStreamAsync));
return this.httpClient.GetStreamAsync(requestUri);
}
public Task<string> GetStringAsync(string requestUri)
{
this.LogInformation(requestUri, nameof(GetStringAsync));
return this.httpClient.GetStringAsync(requestUri);
}
public Task<string> GetStringAsync(Uri requestUri)
{
this.LogInformation(requestUri.ToString(), nameof(GetStringAsync));
return this.httpClient.GetStringAsync(requestUri);
}
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
{
this.LogInformation(requestUri, nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content);
}
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
{
this.LogInformation(requestUri.ToString(), nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content);
}
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(PostAsync));
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content)
{
this.LogInformation(requestUri, nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content);
}
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri, nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content)
{
this.LogInformation(requestUri.ToString(), nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content);
}
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
{
this.LogInformation(requestUri.ToString(), nameof(PutAsync));
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request, completionOption);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request, completionOption, cancellationToken);
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
return this.httpClient.SendAsync(request, cancellationToken);
}
public void Dispose()
{
this.httpClient.Dispose();
}
private void LogInformation(string url, string method)
{
this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url));
}
}
@@ -1,16 +1,15 @@
namespace System.Http
{
public sealed class HttpClientEventMessage
{
public Type Scope { get; }
public string Method { get; }
public string Url { get; }
namespace System.Net.Http;
internal HttpClientEventMessage(Type scope, string method, string url)
{
this.Scope = scope;
this.Method = method;
this.Url = url;
}
public sealed class HttpClientEventMessage
{
public Type Scope { get; }
public string Method { get; }
public string Url { get; }
internal HttpClientEventMessage(Type scope, string method, string url)
{
this.Scope = scope;
this.Method = method;
this.Url = url;
}
}
@@ -1,49 +1,47 @@
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace System.Http
{
public interface IHttpClient<TScope>
{
event EventHandler<HttpClientEventMessage> EventEmitted;
Uri BaseAddress { get; set; }
HttpRequestHeaders DefaultRequestHeaders { get; }
long MaxResponseContentBufferSize { get; set; }
TimeSpan Timeout { get; set; }
namespace System.Net.Http;
void CancelPendingRequests();
Task<HttpResponseMessage> DeleteAsync(string requestUri);
Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken);
Task<HttpResponseMessage> DeleteAsync(Uri requestUri);
Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(string requestUri);
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption);
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(Uri requestUri);
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption);
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken);
Task<byte[]> GetByteArrayAsync(string requestUri);
Task<byte[]> GetByteArrayAsync(Uri requestUri);
Task<Stream> GetStreamAsync(string requestUri);
Task<Stream> GetStreamAsync(Uri requestUri);
Task<string> GetStringAsync(string requestUri);
Task<string> GetStringAsync(Uri requestUri);
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content);
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content);
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content);
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
}
public interface IHttpClient<TScope>
{
event EventHandler<HttpClientEventMessage> EventEmitted;
Uri BaseAddress { get; set; }
HttpRequestHeaders DefaultRequestHeaders { get; }
long MaxResponseContentBufferSize { get; set; }
TimeSpan Timeout { get; set; }
void CancelPendingRequests();
Task<HttpResponseMessage> DeleteAsync(string requestUri);
Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken);
Task<HttpResponseMessage> DeleteAsync(Uri requestUri);
Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(string requestUri);
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption);
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(Uri requestUri);
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption);
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken);
Task<byte[]> GetByteArrayAsync(string requestUri);
Task<byte[]> GetByteArrayAsync(Uri requestUri);
Task<Stream> GetStreamAsync(string requestUri);
Task<Stream> GetStreamAsync(Uri requestUri);
Task<string> GetStringAsync(string requestUri);
Task<string> GetStringAsync(Uri requestUri);
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content);
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content);
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content);
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
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,175 +1,174 @@
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; }
public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); }
public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); }
public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); }
public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); }
public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); }
public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); }
public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); }
public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); }
public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); }
public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); }
public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); }
public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); }
public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); }
public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); }
public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); }
public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); }
public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); }
public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); }
public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); }
public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); }
public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); }
public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); }
public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); }
public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); }
public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); }
public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); }
public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); }
public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); }
public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); }
public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); }
public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); }
public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); }
public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value);
public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value);
public static implicit operator int(Int32BitStruct value) => (int)value.Value;
public static implicit operator uint(Int32BitStruct value) => value.Value;
public static bool operator ==(Int32BitStruct first, Int32BitStruct second)
{
public Int32BitStruct(uint value) => this.Value = value;
public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } }
public uint Value { get; set; }
public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); }
public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); }
public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); }
public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); }
public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); }
public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); }
public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); }
public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); }
public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); }
public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); }
public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); }
public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); }
public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); }
public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); }
public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); }
public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); }
public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); }
public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); }
public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); }
public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); }
public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); }
public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); }
public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); }
public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); }
public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); }
public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); }
public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); }
public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); }
public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); }
public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); }
public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); }
public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); }
return first.Value == second.Value;
}
public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value);
public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value);
public static implicit operator int(Int32BitStruct value) => (int)value.Value;
public static implicit operator uint(Int32BitStruct value) => value.Value;
public static bool operator ==(Int32BitStruct first, Int32BitStruct second)
{
return first.Value == second.Value;
}
public static bool operator !=(Int32BitStruct first, Int32BitStruct second)
{
return first.Value != second.Value;
}
public static bool operator !=(Int32BitStruct first, Int32BitStruct second)
{
return first.Value != second.Value;
}
public static bool operator ==(Int32BitStruct first, uint second)
{
return first.Value == second;
}
public static bool operator ==(Int32BitStruct first, uint second)
{
return first.Value == second;
}
public static bool operator !=(Int32BitStruct first, uint second)
{
return first.Value != second;
}
public static bool operator !=(Int32BitStruct first, uint second)
public static bool operator ==(Int32BitStruct first, int second)
{
unchecked
{
return first.Value != second;
}
public static bool operator ==(Int32BitStruct first, int second)
{
unchecked
{
return first.Value == (uint)second;
}
}
public static bool operator !=(Int32BitStruct first, int second)
{
unchecked
{
return first.Value != (uint)second;
}
}
public static bool operator >=(Int32BitStruct first, Int32BitStruct second)
{
return first.Value >= second.Value;
}
public static bool operator <=(Int32BitStruct first, Int32BitStruct second)
{
return first.Value <= second.Value;
}
public static bool operator >=(Int32BitStruct first, int second)
{
unchecked
{
return first.Value >= (uint)second;
}
}
public static bool operator <=(Int32BitStruct first, int second)
{
unchecked
{
return first.Value <= (uint)second;
}
}
public static bool operator >=(Int32BitStruct first, uint second)
{
return first.Value >= second;
}
public static bool operator <=(Int32BitStruct first, uint second)
{
return first.Value <= second;
}
public static bool operator >(Int32BitStruct first, Int32BitStruct second)
{
return first.Value > second.Value;
}
public static bool operator <(Int32BitStruct first, Int32BitStruct second)
{
return first.Value < second.Value;
}
public static bool operator >(Int32BitStruct first, int second)
{
unchecked
{
return first.Value > (uint)second;
}
}
public static bool operator <(Int32BitStruct first, int second)
{
unchecked
{
return first.Value < (uint)second;
}
}
public static bool operator >(Int32BitStruct first, uint second)
{
return first.Value > second;
}
public static bool operator <(Int32BitStruct first, uint second)
{
return first.Value < second;
}
public bool Equals(Int32BitStruct other)
{
return this.Value == other.Value;
}
public override bool Equals(object obj)
{
if (obj is Int32BitStruct)
{
return this.Equals((Int32BitStruct)obj);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return (this.Value).GetHashCode();
return first.Value == (uint)second;
}
}
public static bool operator !=(Int32BitStruct first, int second)
{
unchecked
{
return first.Value != (uint)second;
}
}
public static bool operator >=(Int32BitStruct first, Int32BitStruct second)
{
return first.Value >= second.Value;
}
public static bool operator <=(Int32BitStruct first, Int32BitStruct second)
{
return first.Value <= second.Value;
}
public static bool operator >=(Int32BitStruct first, int second)
{
unchecked
{
return first.Value >= (uint)second;
}
}
public static bool operator <=(Int32BitStruct first, int second)
{
unchecked
{
return first.Value <= (uint)second;
}
}
public static bool operator >=(Int32BitStruct first, uint second)
{
return first.Value >= second;
}
public static bool operator <=(Int32BitStruct first, uint second)
{
return first.Value <= second;
}
public static bool operator >(Int32BitStruct first, Int32BitStruct second)
{
return first.Value > second.Value;
}
public static bool operator <(Int32BitStruct first, Int32BitStruct second)
{
return first.Value < second.Value;
}
public static bool operator >(Int32BitStruct first, int second)
{
unchecked
{
return first.Value > (uint)second;
}
}
public static bool operator <(Int32BitStruct first, int second)
{
unchecked
{
return first.Value < (uint)second;
}
}
public static bool operator >(Int32BitStruct first, uint second)
{
return first.Value > second;
}
public static bool operator <(Int32BitStruct first, uint second)
{
return first.Value < second;
}
public bool Equals(Int32BitStruct other)
{
return this.Value == other.Value;
}
public override bool Equals(object obj)
{
if (obj is Int32BitStruct)
{
return this.Equals((Int32BitStruct)obj);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return (this.Value).GetHashCode();
}
}
@@ -1,205 +1,204 @@
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)
{
public Int64BitStruct(uint low, uint high)
{
this.Value = low + ((ulong)high << 32);
}
this.Value = low + ((ulong)high << 32);
}
public Int64BitStruct(int low, int high)
public Int64BitStruct(int low, int high)
{
unchecked
{
unchecked
{
this.Value = (uint)low + ((ulong)high << 32);
}
}
public Int64BitStruct(long value)
{
unchecked
{
this.Value = (ulong)value;
}
}
public Int64BitStruct(ulong value)
{
this.Value = value;
}
public ulong Value { get; set; }
public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); }
public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); }
public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); }
public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); }
public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); }
public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); }
public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); }
public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); }
public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); }
public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); }
public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); }
public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); }
public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); }
public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); }
public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); }
public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); }
public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); }
public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); }
public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); }
public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); }
public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); }
public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); }
public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); }
public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); }
public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); }
public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); }
public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); }
public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); }
public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); }
public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); }
public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); }
public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); }
public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); }
public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); }
public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); }
public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); }
public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); }
public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); }
public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); }
public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); }
public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); }
public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); }
public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); }
public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); }
public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); }
public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); }
public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); }
public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); }
public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); }
public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); }
public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); }
public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); }
public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); }
public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); }
public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); }
public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); }
public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); }
public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); }
public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); }
public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); }
public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); }
public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); }
public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); }
public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); }
public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); }
public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); }
public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value);
public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value);
public static implicit operator long(Int64BitStruct value) => (long)value.Value;
public static implicit operator ulong(Int64BitStruct value) => value.Value;
public static bool operator ==(Int64BitStruct first, Int64BitStruct second)
{
return first.Value == second.Value;
}
public static bool operator !=(Int64BitStruct first, Int64BitStruct second)
{
return first.Value != second.Value;
}
public static bool operator ==(Int64BitStruct first, ulong second)
{
return first.Value == second;
}
public static bool operator !=(Int64BitStruct first, ulong second)
{
return first.Value != second;
}
public static bool operator ==(Int64BitStruct first, long second)
{
unchecked
{
return first.Value == (ulong)second;
}
}
public static bool operator !=(Int64BitStruct first, long second)
{
unchecked
{
return first.Value != (ulong)second;
}
}
public static bool operator >=(Int64BitStruct first, Int64BitStruct second)
{
return first.Value >= second.Value;
}
public static bool operator <=(Int64BitStruct first, Int64BitStruct second)
{
return first.Value <= second.Value;
}
public static bool operator >=(Int64BitStruct first, long second)
{
unchecked
{
return first.Value >= (ulong)second;
}
}
public static bool operator <=(Int64BitStruct first, long second)
{
unchecked
{
return first.Value <= (ulong)second;
}
}
public static bool operator >=(Int64BitStruct first, ulong second)
{
unchecked
{
return first.Value >= second;
}
}
public static bool operator <=(Int64BitStruct first, ulong second)
{
unchecked
{
return first.Value <= second;
}
}
public bool Equals(Int64BitStruct other)
{
return this.Value == other.Value;
}
public override bool Equals(object obj)
{
if (obj is Int64BitStruct)
{
return this.Equals((Int64BitStruct)obj);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
this.Value = (uint)low + ((ulong)high << 32);
}
}
public Int64BitStruct(long value)
{
unchecked
{
this.Value = (ulong)value;
}
}
public Int64BitStruct(ulong value)
{
this.Value = value;
}
public ulong Value { get; set; }
public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); }
public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); }
public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); }
public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); }
public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); }
public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); }
public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); }
public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); }
public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); }
public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); }
public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); }
public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); }
public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); }
public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); }
public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); }
public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); }
public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); }
public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); }
public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); }
public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); }
public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); }
public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); }
public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); }
public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); }
public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); }
public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); }
public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); }
public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); }
public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); }
public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); }
public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); }
public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); }
public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); }
public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); }
public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); }
public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); }
public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); }
public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); }
public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); }
public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); }
public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); }
public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); }
public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); }
public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); }
public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); }
public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); }
public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); }
public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); }
public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); }
public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); }
public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); }
public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); }
public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); }
public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); }
public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); }
public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); }
public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); }
public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); }
public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); }
public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); }
public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); }
public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); }
public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); }
public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); }
public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); }
public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); }
public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value);
public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value);
public static implicit operator long(Int64BitStruct value) => (long)value.Value;
public static implicit operator ulong(Int64BitStruct value) => value.Value;
public static bool operator ==(Int64BitStruct first, Int64BitStruct second)
{
return first.Value == second.Value;
}
public static bool operator !=(Int64BitStruct first, Int64BitStruct second)
{
return first.Value != second.Value;
}
public static bool operator ==(Int64BitStruct first, ulong second)
{
return first.Value == second;
}
public static bool operator !=(Int64BitStruct first, ulong second)
{
return first.Value != second;
}
public static bool operator ==(Int64BitStruct first, long second)
{
unchecked
{
return first.Value == (ulong)second;
}
}
public static bool operator !=(Int64BitStruct first, long second)
{
unchecked
{
return first.Value != (ulong)second;
}
}
public static bool operator >=(Int64BitStruct first, Int64BitStruct second)
{
return first.Value >= second.Value;
}
public static bool operator <=(Int64BitStruct first, Int64BitStruct second)
{
return first.Value <= second.Value;
}
public static bool operator >=(Int64BitStruct first, long second)
{
unchecked
{
return first.Value >= (ulong)second;
}
}
public static bool operator <=(Int64BitStruct first, long second)
{
unchecked
{
return first.Value <= (ulong)second;
}
}
public static bool operator >=(Int64BitStruct first, ulong second)
{
unchecked
{
return first.Value >= second;
}
}
public static bool operator <=(Int64BitStruct first, ulong second)
{
unchecked
{
return first.Value <= second;
}
}
public bool Equals(Int64BitStruct other)
{
return this.Value == other.Value;
}
public override bool Equals(object obj)
{
if (obj is Int64BitStruct)
{
return this.Equals((Int64BitStruct)obj);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
}
}
@@ -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.0</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,6 +18,12 @@
<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>
</Project>
@@ -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())
{
}
}
File diff suppressed because it is too large Load Diff
+141 -137
View File
@@ -3,153 +3,157 @@ using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace System.Collections.Tests
namespace System.Collections.Tests;
[TestClass()]
public class AVLTreeTests
{
[TestClass()]
public class AVLTreeTests
private AVLTree<int> avlTree = new AVLTree<int>();
[TestMethod()]
public void AVLTreeTest()
{
private AVLTree<int> avlTree = new AVLTree<int>();
[TestMethod()]
public void AVLTreeTest()
this.avlTree = new AVLTree<int>();
}
[TestMethod()]
public void AddTest()
{
try
{
avlTree = new AVLTree<int>();
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i * 20 - (50 + i));
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
[TestMethod()]
public void AddTest()
if (this.avlTree.Count != 100)
{
try
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i * 20 - (50 + i));
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
if (avlTree.Count != 100)
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
if (!this.avlTree.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
public void RemoveTest()
{
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
this.avlTree.Remove(50);
if (this.avlTree.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
this.avlTree.Clear();
if(this.avlTree.Count > 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void CopyToTest()
{
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
var array = new int[100];
this.avlTree.CopyTo(array, 0);
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
var count = 0;
foreach(var value in this.avlTree)
{
count++;
System.Diagnostics.Debug.WriteLine(value);
}
if(count != this.avlTree.Count)
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
_ = this.avlTree.ToArray();
}
[TestMethod()]
public void Serialize()
{
var avlTree2 = new AVLTree<int>();
for (var i = 0; i < 100; i++)
{
this.avlTree.Add(i);
}
var serializer = new BinaryFormatter();
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, this.avlTree);
stream.Position = 0;
avlTree2 = (AVLTree<int>)serializer.Deserialize(stream);
}
var avlTreeEnum = this.avlTree.GetEnumerator();
var avlTree2Enum = avlTree2.GetEnumerator();
for(var i = 0; i < 100; i++)
{
if(avlTreeEnum.Current != avlTree2Enum.Current)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
if (!avlTree.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
public void RemoveTest()
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
avlTree.Remove(50);
if (avlTree.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
avlTree.Clear();
if(avlTree.Count > 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void CopyToTest()
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
int[] array = new int[100];
avlTree.CopyTo(array, 0);
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
int count = 0;
foreach(int value in avlTree)
{
count++;
System.Diagnostics.Debug.WriteLine(value);
}
if(count != avlTree.Count)
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
int[] array = avlTree.ToArray();
}
[TestMethod()]
public void Serialize()
{
AVLTree<int> avlTree2 = new AVLTree<int>();
for (int i = 0; i < 100; i++)
{
avlTree.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, avlTree);
stream.Position = 0;
avlTree2 = (AVLTree<int>)serializer.Deserialize(stream);
}
IEnumerator<int> avlTreeEnum = avlTree.GetEnumerator();
IEnumerator<int> avlTree2Enum = avlTree2.GetEnumerator();
for(int i = 0; i < 100; i++)
{
if(avlTreeEnum.Current != avlTree2Enum.Current)
{
Assert.Fail();
}
avlTreeEnum.MoveNext();
avlTree2Enum.MoveNext();
}
avlTreeEnum.MoveNext();
avlTree2Enum.MoveNext();
}
}
}
@@ -3,200 +3,211 @@ using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace System.Collections.Tests
namespace System.Collections.Tests;
[TestClass()]
public class BinaryHeapTests
{
[TestClass()]
public class BinaryHeapTests
private BinaryHeap<int> binaryHeap = new BinaryHeap<int>();
[TestMethod()]
public void BinaryHeapTest()
{
private BinaryHeap<int> binaryHeap = new BinaryHeap<int>();
[TestMethod()]
public void BinaryHeapTest()
this.binaryHeap = new BinaryHeap<int>();
}
[TestMethod()]
public void BinaryHeapTest1()
{
this.binaryHeap = new BinaryHeap<int>(100);
if (this.binaryHeap.Count != 0 && this.binaryHeap.Capacity != 100)
{
binaryHeap = new BinaryHeap<int>();
}
[TestMethod()]
public void BinaryHeapTest1()
{
binaryHeap = new BinaryHeap<int>(100);
if (binaryHeap.Count != 0 && binaryHeap.Capacity != 100)
{
Assert.Fail();
}
}
[TestMethod()]
[Timeout(500)]
public void InsertTest()
{
try
{
for (int i = 0; i < 100; i++)
{
binaryHeap.Add(i * 20 - (50 + i));
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
if (binaryHeap.Count != 100)
{
Assert.Fail();
}
}
[TestMethod()]
[Timeout(500)]
public void DeleteMinTest()
{
try
{
int tries = binaryHeap.Count;
while (binaryHeap.Count > 0)
{
if (tries == 0)
{
Assert.Fail();
}
System.Diagnostics.Debug.WriteLine(binaryHeap.Remove());
tries--;
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
}
[TestMethod()]
public void MinMaxTest()
{
for (int i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
}
if (binaryHeap.Min != 0 || binaryHeap.Max != 999)
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
for (int i = 0; i < 100; i++)
{
binaryHeap.Add(i);
}
binaryHeap.Clear();
if (binaryHeap.Count > 0 || binaryHeap.Capacity != 160)
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest2()
{
for (int i = 100; i < 200; i++)
{
binaryHeap.Add(i);
}
binaryHeap.Clear(false);
int[] array = binaryHeap.ToArray();
if (binaryHeap.Count > 0 || binaryHeap.Capacity == 10)
{
Assert.Fail();
}
if (array.Length != 0)
{
Assert.Fail();
}
binaryHeap.Clear(true);
if (binaryHeap.Capacity != 10 || binaryHeap.Count != 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
binaryHeap.Add(100);
if (!binaryHeap.Contains(100))
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for(int i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
}
int[] array = binaryHeap.ToArray();
if(array.Length != binaryHeap.Count)
{
Assert.Fail();
}
if(array[0] != 0 && array[999] != 999)
{
Assert.Fail();
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
}
int count = 0;
foreach(int value in binaryHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == binaryHeap.Count)
{
return;
}
Assert.Fail();
}
}
[TestMethod()]
public void Serialize()
[TestMethod()]
[Timeout(500)]
public void InsertTest()
{
try
{
BinaryHeap<int> binaryHeap2 = new BinaryHeap<int>();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i);
this.binaryHeap.Add(i * 20 - (50 + i));
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
using (var stream = new MemoryStream()) {
serializer.Serialize(stream, binaryHeap);
stream.Position = 0;
binaryHeap2 = (BinaryHeap<int>)serializer.Deserialize(stream);
}
IEnumerator<int> binaryHeapEnum = binaryHeap.GetEnumerator();
IEnumerator<int> binaryHeapEnum2 = binaryHeap2.GetEnumerator();
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
for (int i = 0; i < 100; i++)
if (this.binaryHeap.Count != 100)
{
Assert.Fail();
}
}
[TestMethod()]
[Timeout(500)]
public void DeleteMinTest()
{
try
{
var tries = this.binaryHeap.Count;
while (this.binaryHeap.Count > 0)
{
if (binaryHeapEnum.Current != binaryHeapEnum2.Current)
if (tries == 0)
{
Assert.Fail();
}
binaryHeapEnum.MoveNext();
binaryHeapEnum2.MoveNext();
System.Diagnostics.Debug.WriteLine(this.binaryHeap.Remove());
tries--;
}
}
catch (Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
}
[TestMethod()]
public void MinMaxTest()
{
for (var i = 0; i < 1000; i++)
{
this.binaryHeap.Add(i);
}
if (this.binaryHeap.Min != 0 || this.binaryHeap.Max != 999)
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
for (var i = 0; i < 100; i++)
{
this.binaryHeap.Add(i);
}
this.binaryHeap.Clear();
if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity != 160)
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest2()
{
for (var i = 100; i < 200; i++)
{
this.binaryHeap.Add(i);
}
this.binaryHeap.Clear(false);
var array = this.binaryHeap.ToArray();
if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity == 10)
{
Assert.Fail();
}
if (array.Length != 0)
{
Assert.Fail();
}
this.binaryHeap.Clear(true);
if (this.binaryHeap.Capacity != 10 || this.binaryHeap.Count != 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
this.binaryHeap.Add(100);
if (!this.binaryHeap.Contains(100))
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for(var i = 0; i < 1000; i++)
{
this.binaryHeap.Add(i);
}
var array = this.binaryHeap.ToArray();
if(array.Length != this.binaryHeap.Count)
{
Assert.Fail();
}
if(array[0] != 0 && array[999] != 999)
{
Assert.Fail();
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (var i = 0; i < 1000; i++)
{
this.binaryHeap.Add(i);
}
var count = 0;
foreach(var value in this.binaryHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == this.binaryHeap.Count)
{
return;
}
Assert.Fail();
}
[TestMethod()]
public void Serialize()
{
var binaryHeap2 = new BinaryHeap<int>();
for (var i = 0; i < 100; i++)
{
this.binaryHeap.Add(i);
}
var serializer = new BinaryFormatter();
using (var stream = new MemoryStream()) {
serializer.Serialize(stream, this.binaryHeap);
stream.Position = 0;
binaryHeap2 = (BinaryHeap<int>)serializer.Deserialize(stream);
}
var binaryHeapEnum = this.binaryHeap.GetEnumerator();
var binaryHeapEnum2 = binaryHeap2.GetEnumerator();
for (var i = 0; i < 100; i++)
{
if (binaryHeapEnum.Current != binaryHeapEnum2.Current)
{
Assert.Fail();
}
binaryHeapEnum.MoveNext();
binaryHeapEnum2.MoveNext();
}
}
}
@@ -3,203 +3,210 @@ using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace System.Collections.Tests
namespace System.Collections.Tests;
[TestClass()]
public class FibonacciHeapTests
{
[TestClass()]
public class FibonacciHeapTests
FibonacciHeap<int> fibonacciHeap = new FibonacciHeap<int>();
[TestMethod()]
public void InsertTest()
{
FibonacciHeap<int> fibonacciHeap = new FibonacciHeap<int>();
[TestMethod()]
public void InsertTest()
for (var i = 0; i < 1000; i++)
{
for (int i = 0; i < 1000; i++)
{
fibonacciHeap.Add(i);
}
this.fibonacciHeap.Add(i);
}
}
[TestMethod()]
public void FibonacciHeapTest()
[TestMethod()]
public void FibonacciHeapTest()
{
this.fibonacciHeap = new FibonacciHeap<int>();
if(this.fibonacciHeap.Count != 0)
{
fibonacciHeap = new FibonacciHeap<int>();
if(fibonacciHeap.Count != 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void MergeTest()
{
FibonacciHeap<int> fibonacciHeap1 = new FibonacciHeap<int>();
FibonacciHeap<int> fibonacciHeap2 = new FibonacciHeap<int>();
for(int i = 0; i < 100; i++)
{
fibonacciHeap1.Add(i);
}
for(int i = 100; i < 300; i++)
{
fibonacciHeap2.Add(i);
}
fibonacciHeap1.Merge(fibonacciHeap2);
for(int i = 1; i < 300; i++)
{
if (!fibonacciHeap1.Contains(i))
{
Assert.Fail();
}
}
}
[TestMethod()]
public void RemoveMinimumTest()
{
try
{
fibonacciHeap.Remove();
Assert.Fail();
}
catch(IndexOutOfRangeException exception)
{
}
catch(Exception e)
{
Assert.Fail();
}
for (int i = 0; i < 1000; i++)
{
fibonacciHeap.Add(i);
}
for (int i = 0; i < 1000; i++)
{
if (fibonacciHeap.Remove() != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void DecreaseKeyTest()
{
fibonacciHeap.Add(5);
fibonacciHeap.Add(10);
fibonacciHeap.Add(7);
fibonacciHeap.DecreaseKey(5, 3);
if(fibonacciHeap.Contains(5) || !fibonacciHeap.Contains(3))
{
Assert.Fail();
}
fibonacciHeap.DecreaseKey(10, 1);
if(fibonacciHeap.Remove() != 1)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
for(int i = 0; i < 10000; i++)
{
fibonacciHeap.Add(i);
}
if (!fibonacciHeap.Contains(5124))
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
for(int i = 0; i < 10000; i++)
{
fibonacciHeap.Add(i);
}
fibonacciHeap.Remove();
fibonacciHeap.Clear();
if(fibonacciHeap.Count > 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for(int i = 999; i >= 0; i--)
{
fibonacciHeap.Add(i);
}
fibonacciHeap.Remove();
int[] arr = fibonacciHeap.ToArray();
for(int i = 1; i < 512; i++)
{
if(arr[i - 1] != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 999; i >= 0; i--)
{
fibonacciHeap.Add(i);
}
int count = 0;
foreach(int value in fibonacciHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == fibonacciHeap.Count)
{
return;
}
Assert.Fail();
}
}
[TestMethod()]
public void Serialize()
[TestMethod()]
public void MergeTest()
{
var fibonacciHeap1 = new FibonacciHeap<int>();
var fibonacciHeap2 = new FibonacciHeap<int>();
for(var i = 0; i < 100; i++)
{
FibonacciHeap<int> fibonacciHeap2 = new FibonacciHeap<int>();
for (int i = 0; i < 100; i++)
{
fibonacciHeap.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, fibonacciHeap);
stream.Position = 0;
fibonacciHeap2 = (FibonacciHeap<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = fibonacciHeap.GetEnumerator();
IEnumerator<int> enum2 = fibonacciHeap2.GetEnumerator();
fibonacciHeap1.Add(i);
}
for (int i = 0; i < 100; i++)
for(var i = 100; i < 300; i++)
{
fibonacciHeap2.Add(i);
}
fibonacciHeap1.Merge(fibonacciHeap2);
for(var i = 1; i < 300; i++)
{
if (!fibonacciHeap1.Contains(i))
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
Assert.Fail();
}
}
}
[TestMethod()]
public void RemoveMinimumTest()
{
try
{
this.fibonacciHeap.Remove();
Assert.Fail();
}
catch (IndexOutOfRangeException)
{
}
catch (Exception)
{
Assert.Fail();
}
for (var i = 0; i < 1000; i++)
{
this.fibonacciHeap.Add(i);
}
for (var i = 0; i < 1000; i++)
{
if (this.fibonacciHeap.Remove() != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void DecreaseKeyTest()
{
this.fibonacciHeap.Add(5);
this.fibonacciHeap.Add(10);
this.fibonacciHeap.Add(7);
this.fibonacciHeap.DecreaseKey(5, 3);
if(this.fibonacciHeap.Contains(5) || !this.fibonacciHeap.Contains(3))
{
Assert.Fail();
}
this.fibonacciHeap.DecreaseKey(10, 1);
if(this.fibonacciHeap.Remove() != 1)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
for(var i = 0; i < 10000; i++)
{
this.fibonacciHeap.Add(i);
}
if (!this.fibonacciHeap.Contains(5124))
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
for(var i = 0; i < 10000; i++)
{
this.fibonacciHeap.Add(i);
}
this.fibonacciHeap.Remove();
this.fibonacciHeap.Clear();
if(this.fibonacciHeap.Count > 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for(var i = 999; i >= 0; i--)
{
this.fibonacciHeap.Add(i);
}
this.fibonacciHeap.Remove();
var arr = this.fibonacciHeap.ToArray();
for(var i = 1; i < 512; i++)
{
if(arr[i - 1] != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (var i = 999; i >= 0; i--)
{
this.fibonacciHeap.Add(i);
}
var count = 0;
foreach(var value in this.fibonacciHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == this.fibonacciHeap.Count)
{
return;
}
Assert.Fail();
}
[TestMethod()]
public void Serialize()
{
var fibonacciHeap2 = new FibonacciHeap<int>();
for (var i = 0; i < 100; i++)
{
this.fibonacciHeap.Add(i);
}
var serializer = new BinaryFormatter();
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, this.fibonacciHeap);
stream.Position = 0;
fibonacciHeap2 = (FibonacciHeap<int>)serializer.Deserialize(stream);
}
var enum1 = this.fibonacciHeap.GetEnumerator();
var enum2 = fibonacciHeap2.GetEnumerator();
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
@@ -3,109 +3,114 @@ using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace System.Collections.Tests
namespace System.Collections.Tests;
[TestClass()]
public class PriorityQueueTests
{
[TestClass()]
public class PriorityQueueTests
private PriorityQueue<int> priorityQueue = new PriorityQueue<int>();
[TestMethod()]
public void PriorityQueueTest()
{
private PriorityQueue<int> priorityQueue = new PriorityQueue<int>();
[TestMethod()]
public void PriorityQueueTest()
try
{
try
this.priorityQueue = new PriorityQueue<int>();
if(this.priorityQueue.Count > 0)
{
priorityQueue = new PriorityQueue<int>();
if(priorityQueue.Count > 0)
{
Assert.Fail();
}
}
catch(Exception e)
{
Assert.Fail(e.Message + "\n" + e.StackTrace);
Assert.Fail();
}
}
[TestMethod()]
public void EnqueueTest()
catch(Exception e)
{
for(int i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
}
if(priorityQueue.Count != 100)
Assert.Fail(e.Message + "\n" + e.StackTrace);
}
}
[TestMethod()]
public void EnqueueTest()
{
for(var i = 0; i < 100; i++)
{
this.priorityQueue.Enqueue(i);
}
if(this.priorityQueue.Count != 100)
{
Assert.Fail();
}
}
[TestMethod()]
public void DequeueTest()
{
for(var i = 0; i < 100; i++)
{
this.priorityQueue.Enqueue(i);
}
for(var i = 0; i < 100; i++)
{
if(i != this.priorityQueue.Dequeue())
{
Assert.Fail();
}
}
[TestMethod()]
public void DequeueTest()
if(this.priorityQueue.Count > 0)
{
for(int i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
}
for(int i = 0; i < 100; i++)
{
if(i != priorityQueue.Dequeue())
{
Assert.Fail();
}
}
if(priorityQueue.Count > 0)
{
Assert.Fail();
}
try
{
priorityQueue.Dequeue();
Assert.Fail();
}
catch
{
}
Assert.Fail();
}
[TestMethod()]
public void PeekTest()
try
{
priorityQueue.Enqueue(1051);
if(priorityQueue.Peek() != 1051 && priorityQueue.Count != 1)
this.priorityQueue.Dequeue();
Assert.Fail();
}
catch
{
}
}
[TestMethod()]
public void PeekTest()
{
this.priorityQueue.Enqueue(1051);
if(this.priorityQueue.Peek() != 1051 && this.priorityQueue.Count != 1)
{
Assert.Fail();
}
}
[TestMethod()]
public void Serialize()
{
var priorityQueue2 = new PriorityQueue<int>();
for (var i = 0; i < 100; i++)
{
this.priorityQueue.Enqueue(i);
}
var serializer = new BinaryFormatter();
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, this.priorityQueue);
stream.Position = 0;
priorityQueue2 = (PriorityQueue<int>)serializer.Deserialize(stream);
}
var enum1 = this.priorityQueue.GetEnumerator();
var enum2 = priorityQueue2.GetEnumerator();
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
}
[TestMethod()]
public void Serialize()
{
PriorityQueue<int> priorityQueue2 = new PriorityQueue<int>();
for (int i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, priorityQueue);
stream.Position = 0;
priorityQueue2 = (PriorityQueue<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = priorityQueue.GetEnumerator();
IEnumerator<int> enum2 = priorityQueue2.GetEnumerator();
for (int i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
@@ -3,154 +3,159 @@ using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace System.Collections.Tests
namespace System.Collections.Tests;
[TestClass()]
public class SkipListTests
{
[TestClass()]
public class SkipListTests
SkipList<int> skipList = new SkipList<int>();
[TestMethod()]
public void SkipListTest()
{
SkipList<int> skipList = new SkipList<int>();
[TestMethod()]
public void SkipListTest()
_ = new SkipList<int>();
}
[TestMethod()]
public void SkipListTest2()
{
_ = new SkipList<int>(30);
}
[TestMethod()]
public void AddTest()
{
for(var i = 0; i < 200; i++)
{
SkipList<int> skipList = new SkipList<int>();
this.skipList.Add(i);
}
}
[TestMethod()]
public void ClearTest()
{
for (var i = 0; i < 200; i++)
{
this.skipList.Add(i);
}
[TestMethod()]
public void SkipListTest2()
this.skipList.Clear();
if(this.skipList.Count > 0)
{
SkipList<int> skipList = new SkipList<int>(30);
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
for (var i = 0; i < 200; i++)
{
this.skipList.Add(i);
}
[TestMethod()]
public void AddTest()
if (!this.skipList.Contains(50))
{
for(int i = 0; i < 200; i++)
{
skipList.Add(i);
}
Assert.Fail();
}
}
[TestMethod()]
public void CopyToTest()
{
for (var i = 0; i < 200; i++)
{
this.skipList.Add(i);
}
[TestMethod()]
public void ClearTest()
var array = new int[this.skipList.Count];
this.skipList.CopyTo(array, 0);
for (var i = 0; i < 200; i++)
{
for (int i = 0; i < 200; i++)
{
skipList.Add(i);
}
skipList.Clear();
if(skipList.Count > 0)
if(array[i] != i)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
for (int i = 0; i < 200; i++)
{
skipList.Add(i);
}
if (!skipList.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
public void CopyToTest()
{
for (int i = 0; i < 200; i++)
{
skipList.Add(i);
}
int[] array = new int[skipList.Count];
skipList.CopyTo(array, 0);
for (int i = 0; i < 200; i++)
{
if(array[i] != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void ToArrayTest()
{
for (int i = 0; i < 200; i++)
{
skipList.Add(i);
}
int[] array = skipList.ToArray();
for (int i = 0; i < 200; i++)
{
if(array[i] != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 200; i++)
{
skipList.Add(i);
}
foreach(int i in skipList)
{
System.Diagnostics.Debug.WriteLine(i);
}
}
[TestMethod()]
public void RemoveTest()
{
for (int i = 0; i < 200; i++)
{
skipList.Add(i);
}
skipList.Remove(50);
if (skipList.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
[Ignore("Binary serialization is obsolete and should not be used anymore")]
public void Serialize()
{
SkipList<int> skipList2 = new SkipList<int>();
for (int i = 0; i < 100; i++)
{
skipList.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, skipList);
stream.Position = 0;
skipList2 = (SkipList<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = skipList.GetEnumerator();
IEnumerator<int> enum2 = skipList2.GetEnumerator();
for (int i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
[TestMethod()]
public void ToArrayTest()
{
for (var i = 0; i < 200; i++)
{
this.skipList.Add(i);
}
var array = this.skipList.ToArray();
for (var i = 0; i < 200; i++)
{
if(array[i] != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (var i = 0; i < 200; i++)
{
this.skipList.Add(i);
}
foreach(var i in this.skipList)
{
System.Diagnostics.Debug.WriteLine(i);
}
}
[TestMethod()]
public void RemoveTest()
{
for (var i = 0; i < 200; i++)
{
this.skipList.Add(i);
}
this.skipList.Remove(50);
if (this.skipList.Contains(50))
{
Assert.Fail();
}
}
[TestMethod()]
[Ignore("Binary serialization is obsolete and should not be used anymore")]
public void Serialize()
{
var skipList2 = new SkipList<int>();
for (var i = 0; i < 100; i++)
{
this.skipList.Add(i);
}
var serializer = new BinaryFormatter();
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, this.skipList);
stream.Position = 0;
skipList2 = (SkipList<int>)serializer.Deserialize(stream);
}
var enum1 = this.skipList.GetEnumerator();
var enum2 = skipList2.GetEnumerator();
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
+124 -121
View File
@@ -3,140 +3,143 @@ using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace System.Collections.Tests
namespace System.Collections.Tests;
[TestClass()]
public class TreapTests
{
[TestClass()]
public class TreapTests
Treap<int> treap = new Treap<int>();
[TestMethod()]
public void TreapTest()
{
Treap<int> treap = new Treap<int>();
[TestMethod()]
public void TreapTest()
this.treap = new Treap<int>();
}
[TestMethod()]
public void InsertTest()
{
var random = new Random();
for(var i = 0; i < 1000; i++)
{
treap = new Treap<int>();
this.treap.Add(random.Next(0, 5000));
}
}
[TestMethod()]
public void InsertTest()
[TestMethod()]
public void RemoveTest()
{
this.treap.Add(60);
this.treap.Add(6);
this.treap.Add(5);
this.treap.Remove(60);
if(this.treap.Contains(60) || this.treap.Count > 2)
{
Random random = new Random();
for(int i = 0; i < 1000; i++)
{
treap.Add(random.Next(0, 5000));
}
}
[TestMethod()]
public void RemoveTest()
{
treap.Add(60);
treap.Add(6);
treap.Add(5);
treap.Remove(60);
if(treap.Contains(60) || treap.Count > 2)
{
Assert.Fail();
}
}
[TestMethod()]
public void ClearTest()
{
Random random = new Random();
for (int i = 0; i < 100; i++)
{
treap.Add(random.Next(0, 5000));
}
treap.Clear();
if(treap.Count > 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
treap.Add(50);
treap.Add(25);
treap.Add(991142);
treap.Add(12313);
treap.Add(24);
treap.Add(23);
if (!treap.Contains(24))
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for(int i = 0; i < 1000; i++)
{
treap.Add(i);
}
int[] arr = treap.ToArray();
for(int i = 0; i < 1000; i++)
{
if(arr[i] != i)
{
Assert.Fail();
}
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 1000; i++)
{
treap.Add(i);
}
int count = 0;
foreach(int value in treap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == treap.Count)
{
return;
}
Assert.Fail();
}
}
[TestMethod()]
[Ignore("Binary serialization is obsolete and should not be used anymore")]
public void Serialize()
[TestMethod()]
public void ClearTest()
{
var random = new Random();
for (var i = 0; i < 100; i++)
{
Treap<int> treap2 = new Treap<int>();
for (int i = 0; i < 100; i++)
{
treap.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, treap);
stream.Position = 0;
treap2 = (Treap<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = treap.GetEnumerator();
IEnumerator<int> enum2 = treap2.GetEnumerator();
this.treap.Add(random.Next(0, 5000));
}
for (int i = 0; i < 100; i++)
this.treap.Clear();
if(this.treap.Count > 0)
{
Assert.Fail();
}
}
[TestMethod()]
public void ContainsTest()
{
this.treap.Add(50);
this.treap.Add(25);
this.treap.Add(991142);
this.treap.Add(12313);
this.treap.Add(24);
this.treap.Add(23);
if (!this.treap.Contains(24))
{
Assert.Fail();
}
}
[TestMethod()]
public void ToArrayTest()
{
for(var i = 0; i < 1000; i++)
{
this.treap.Add(i);
}
var arr = this.treap.ToArray();
for(var i = 0; i < 1000; i++)
{
if(arr[i] != i)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
Assert.Fail();
}
}
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (var i = 0; i < 1000; i++)
{
this.treap.Add(i);
}
var count = 0;
foreach(var value in this.treap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
}
if(count == this.treap.Count)
{
return;
}
Assert.Fail();
}
[TestMethod()]
[Ignore("Binary serialization is obsolete and should not be used anymore")]
public void Serialize()
{
var treap2 = new Treap<int>();
for (var i = 0; i < 100; i++)
{
this.treap.Add(i);
}
var serializer = new BinaryFormatter();
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, this.treap);
stream.Position = 0;
treap2 = (Treap<int>)serializer.Deserialize(stream);
}
var enum1 = this.treap.GetEnumerator();
var enum2 = treap2.GetEnumerator();
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
Assert.Fail();
}
enum1.MoveNext();
enum2.MoveNext();
}
}
}
@@ -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,111 +1,110 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace System.Extensions.Tests
namespace System.Extensions.Tests;
[TestClass]
public class OptionalTests
{
[TestClass]
public class OptionalTests
[TestMethod]
public void SomeValueShouldEqualOptional()
{
[TestMethod]
public void SomeValueShouldEqualOptional()
{
var value = string.Empty;
var optional = value.ToOptional();
var value = string.Empty;
var optional = value.ToOptional();
Assert.IsTrue(optional.Equals(value));
}
Assert.IsTrue(optional.Equals(value));
}
[TestMethod]
public void OptionalFromNullShouldNotEqual()
{
object value = null;
var optional = value.ToOptional();
[TestMethod]
public void OptionalFromNullShouldNotEqual()
{
object value = null;
var optional = value.ToOptional();
Assert.IsFalse(optional.Equals(value));
}
Assert.IsFalse(optional.Equals(value));
}
[TestMethod]
public void OptionalFromValueShouldBeSome()
{
var optional = Optional.FromValue<object>(new object());
[TestMethod]
public void OptionalFromValueShouldBeSome()
{
var optional = Optional.FromValue<object>(new object());
optional.DoAny(
onNone: () => throw new InvalidOperationException());
}
optional.DoAny(
onNone: () => throw new InvalidOperationException());
}
[TestMethod]
public void OptionalFromNullShouldBeNone()
{
var optional = Optional.FromValue<object>(null);
[TestMethod]
public void OptionalFromNullShouldBeNone()
{
var optional = Optional.FromValue<object>(null);
optional.DoAny(
onSome: _ => throw new InvalidOperationException());
}
optional.DoAny(
onSome: _ => throw new InvalidOperationException());
}
[TestMethod]
public void DoShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
[TestMethod]
public void DoShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
optional.Do(
onSome: _ => { },
onNone: () => throw new InvalidOperationException());
optional.Do(
onSome: _ => { },
onNone: () => throw new InvalidOperationException());
nullOptional.Do(
onSome: _ => throw new InvalidOperationException(),
onNone: () => { });
}
nullOptional.Do(
onSome: _ => throw new InvalidOperationException(),
onNone: () => { });
}
[TestMethod]
public void DoAnyShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
[TestMethod]
public void DoAnyShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
optional.DoAny(
onNone: () => throw new InvalidOperationException());
optional.DoAny(
onNone: () => throw new InvalidOperationException());
nullOptional.DoAny(
onSome: _ => throw new InvalidOperationException());
}
nullOptional.DoAny(
onSome: _ => throw new InvalidOperationException());
}
[TestMethod]
public void SwitchShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
[TestMethod]
public void SwitchShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
var newValue = optional.Switch(
onSome: _ => string.Empty,
onNone: () => throw new InvalidOperationException())
.ExtractValue();
var newValue = optional.Switch(
onSome: _ => string.Empty,
onNone: () => throw new InvalidOperationException())
.ExtractValue();
var newNullValue = nullOptional.Switch<string>(
onSome: _ => throw new InvalidOperationException(),
onNone: () => null)
.ExtractValue();
var newNullValue = nullOptional.Switch<string>(
onSome: _ => throw new InvalidOperationException(),
onNone: () => null)
.ExtractValue();
newValue.Should().Be(string.Empty);
newNullValue.Should().Be(null);
}
newValue.Should().Be(string.Empty);
newNullValue.Should().Be(null);
}
[TestMethod]
public void SwitchAnyShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
[TestMethod]
public void SwitchAnyShouldExecute()
{
var optional = Optional.FromValue(string.Empty);
var nullOptional = Optional.FromValue<string>(null);
var newValue = optional.SwitchAny(
onSome: _ => string.Empty)
.ExtractValue();
var newValue = optional.SwitchAny(
onSome: _ => string.Empty)
.ExtractValue();
var newNullValue = nullOptional.SwitchAny<string>(
onNone: () => null)
.ExtractValue();
var newNullValue = nullOptional.SwitchAny<string>(
onNone: () => null)
.ExtractValue();
newValue.Should().Be(string.Empty);
newNullValue.Should().Be(null);
}
newValue.Should().Be(string.Empty);
newNullValue.Should().Be(null);
}
}

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