mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-16 22:39:29 +00:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 721b444dda | |||
| 1c7d3a2be2 | |||
| 0a30872781 | |||
| 7eed1ca466 | |||
| b6cc64fd51 | |||
| c8bfaffb42 | |||
| bf163251dd | |||
| c0b5734b71 | |||
| 2944d9887e | |||
| 57925151fa | |||
| d20e5bd308 | |||
| c9d1ba8773 | |||
| ce3cac9fa2 | |||
| a2d23ed716 | |||
| 7660893087 | |||
| 68ec8f983d | |||
| 1711dd2ec2 | |||
| 3b67e45e64 | |||
| 22fa8eccf7 | |||
| 9609b2912c | |||
| a2e99cb263 | |||
| f9088a5aef | |||
| d67ee95916 | |||
| 8bfb8f1757 | |||
| a6572a1d15 | |||
| 646b6dc253 | |||
| 0b2a76143b | |||
| 019d7e240d | |||
| 7a764a5929 | |||
| 5aaa0d318a | |||
| 5767ccfd70 | |||
| 16a9208e07 | |||
| 3038661f6d | |||
| 035e58248e | |||
| 0d418ac9bf | |||
| 0288b385a0 | |||
| 5d442580c3 | |||
| ee341af2c3 | |||
| 8d1355ecbc | |||
| c04b6ba906 | |||
| 9a7125fbb0 | |||
| 66b766326b | |||
| c8a98a0494 | |||
| f39e8cf89e | |||
| 0b5e93f9ea | |||
| 8fd22b3644 | |||
| f6069bd3aa | |||
| 89159e6cba | |||
| a608b1ac95 | |||
| 2ebd821bbd | |||
| f0a5d509ea | |||
| 9003157a0f | |||
| 47c1e67f38 |
@@ -0,0 +1,80 @@
|
||||
name: SystemExtensions CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
environment: Default
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
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
|
||||
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
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
- name: Restore project
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Build SystemExtensions.NetStandard project
|
||||
run: dotnet build SystemExtensions.NetStandard -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetCore project
|
||||
run: dotnet build SystemExtensions.NetCore -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetStandard.DependencyInjection project
|
||||
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetStandard.Security project
|
||||
run: dotnet build SystemExtensions.NetStandard.Security -c $env:Configuration
|
||||
|
||||
- name: Push SystemExtensions.NetStandard nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
|
||||
- name: Push SystemExtensions.NetCore nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
|
||||
- name: Push SystemExtensions.NetStandard.DependencyInjection nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
|
||||
- name: Push SystemExtensions.NetStandard.Security nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
@@ -0,0 +1,56 @@
|
||||
name: SystemExtensions CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x64]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
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
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
- 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:
|
||||
Configuration: Debug
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Macocian Alexandru Victor
|
||||
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
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class DefaultOptionsManagerTests
|
||||
{
|
||||
private readonly DefaultOptionsManager optionsManager = new();
|
||||
|
||||
[TestMethod]
|
||||
public void GetOptions_ReturnsDefault()
|
||||
{
|
||||
var options = this.optionsManager.GetOptions<string>();
|
||||
|
||||
options.Should().BeNull();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOptions_Succeeds()
|
||||
{
|
||||
this.optionsManager.UpdateOptions(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
public sealed class DummyOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class LiveUpdateableOptionsWrapperTests
|
||||
{
|
||||
private LiveUpdateableOptionsWrapper<string> optionsWrapper;
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[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");
|
||||
|
||||
var value = this.optionsWrapper.Value;
|
||||
|
||||
value.Should().Be("hello");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOption_CallsOptionsManager()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
|
||||
.Verifiable();
|
||||
|
||||
this.optionsWrapper.UpdateOption();
|
||||
|
||||
this.optionsManagerMock.Verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class OptionsResolverTests
|
||||
{
|
||||
private readonly OptionsResolver optionsResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
public Mock<IOptionsManager> OptionsManagerMock => optionsManagerMock;
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_ILiveOptions_ReturnsTrue()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class UpdateableOptionsWrapperTests
|
||||
{
|
||||
private const string Value = "hello";
|
||||
|
||||
private UpdateableOptionsWrapper<string> optionsWrapper;
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.optionsWrapper = new UpdateableOptionsWrapper<string>(optionsManagerMock.Object, Value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetValue_ReturnsValue()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.GetOptions<string>())
|
||||
.Throws<Exception>();
|
||||
|
||||
var value = this.optionsWrapper.Value;
|
||||
|
||||
value.Should().Be(Value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOption_CallsOptionsManager()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
|
||||
.Verifiable();
|
||||
|
||||
this.optionsWrapper.UpdateOption();
|
||||
|
||||
this.optionsManagerMock.Verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Http;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Http
|
||||
{
|
||||
[TestClass]
|
||||
public class HttpClientResolverTests
|
||||
{
|
||||
private readonly HttpClientResolver httpClientResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_IHttpClient_ReturnsTrue()
|
||||
{
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class CVLoggerProviderTests
|
||||
{
|
||||
private readonly Mock<ILogsWriter> logsWriterMock = new();
|
||||
private CVLoggerProvider cVLoggerProvider;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.cVLoggerProvider = new CVLoggerProvider(this.logsWriterMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CreateLogger_CreatesNewLogger()
|
||||
{
|
||||
var logger = this.cVLoggerProvider.CreateLogger(string.Empty);
|
||||
|
||||
logger.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogEntry_CallsLogWriter()
|
||||
{
|
||||
this.cVLoggerProvider.LogEntry(new Log());
|
||||
|
||||
this.logsWriterMock.Verify();
|
||||
}
|
||||
|
||||
private void SetupLogsWriter()
|
||||
{
|
||||
this.logsWriterMock
|
||||
.Setup(u => u.WriteLog(It.IsAny<Log>()))
|
||||
.Verifiable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class CVLoggerTests
|
||||
{
|
||||
private readonly Mock<ICVLoggerProvider> cvLoggerProviderMock = new();
|
||||
private CVLogger cVLogger;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.cVLogger = new CVLogger(string.Empty, this.cvLoggerProviderMock.Object);
|
||||
}
|
||||
|
||||
[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) =>
|
||||
{
|
||||
called = true;
|
||||
return string.Empty;
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class DebugLogsWriterTests
|
||||
{
|
||||
private readonly DebugLogsWriter logsWriter = new();
|
||||
|
||||
[TestMethod]
|
||||
public void WriteLog_Succeeds()
|
||||
{
|
||||
this.logsWriter.WriteLog(new Log());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullLog_Throws()
|
||||
{
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.logsWriter.WriteLog(null);
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[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()
|
||||
{
|
||||
var type = typeof(ILogger);
|
||||
|
||||
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 canResolve = this.loggerResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
namespace System.Configuration
|
||||
{
|
||||
public sealed class DefaultOptionsManager : IOptionsManager
|
||||
{
|
||||
public T GetOptions<T>() where T : class
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public void UpdateOptions<T>(T value) where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public interface ILiveOptions<T> : IOptions<T>
|
||||
where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
namespace System.Configuration
|
||||
{
|
||||
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace System.Configuration
|
||||
{
|
||||
public interface IOptionsManager
|
||||
{
|
||||
T GetOptions<T>()
|
||||
where T : class;
|
||||
void UpdateOptions<T>(T value)
|
||||
where T : class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public interface IUpdateableOptions<out T> : IOptions<T>
|
||||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
|
||||
/// </summary>
|
||||
void UpdateOption();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public sealed class LiveOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly IOptionsManager configurationManager;
|
||||
|
||||
private T value;
|
||||
|
||||
public T Value
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public sealed class OptionsResolver : IDependencyResolver
|
||||
{
|
||||
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<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using Slim.Resolvers;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace System.Configuration
|
||||
{
|
||||
public sealed class UpdateableOptionsResolver : IDependencyResolver
|
||||
{
|
||||
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<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly IOptionsManager configurationManager;
|
||||
|
||||
public T Value { get; }
|
||||
|
||||
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.Value = options;
|
||||
}
|
||||
|
||||
public void UpdateOption()
|
||||
{
|
||||
this.configurationManager.UpdateOptions(this.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Slim;
|
||||
using System.Configuration;
|
||||
using System.Http;
|
||||
using System.Logging;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class ServiceManagerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a <see cref="IOptionsManager"/> with the default <see cref="DefaultOptionsManager"/>.
|
||||
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
|
||||
serviceManager.RegisterOptionsResolver();
|
||||
|
||||
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
|
||||
{
|
||||
serviceManager.RegisterSingleton<IOptionsManager, T>();
|
||||
serviceManager.RegisterOptionsResolver();
|
||||
|
||||
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)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterResolver(new OptionsResolver());
|
||||
serviceManager.RegisterResolver(new UpdateableOptionsResolver());
|
||||
serviceManager.RegisterResolver(new LiveOptionsResolver());
|
||||
serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver());
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <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 =>
|
||||
{
|
||||
var factory = new LoggerFactory();
|
||||
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
|
||||
return factory;
|
||||
});
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <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 =>
|
||||
{
|
||||
var factory = new LoggerFactory();
|
||||
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
|
||||
return factory;
|
||||
});
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a <see cref="ILoggerFactory"/> with a <see cref="CVLoggerProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceManager"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceManager RegisterCVLoggerFactory(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
LoggerFactory loggerFactory = new();
|
||||
loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
|
||||
return loggerFactory;
|
||||
});
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Slim.Resolvers;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace System.Http
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.HttpMessageHandlerFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class CVLogger : ILogger
|
||||
{
|
||||
private readonly string category;
|
||||
private readonly ICVLoggerProvider cvLoggerProvider;
|
||||
|
||||
public CVLogger(string category, ICVLoggerProvider cvLoggerProvider)
|
||||
{
|
||||
this.category = category;
|
||||
this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(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
|
||||
{
|
||||
Exception = exception,
|
||||
LogLevel = logLevel,
|
||||
EventId = eventId.Name,
|
||||
Message = message,
|
||||
Category = category,
|
||||
LogTime = DateTime.Now
|
||||
};
|
||||
|
||||
this.cvLoggerProvider.LogEntry(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Microsoft.CorrelationVector;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class CVLoggerProvider : ICVLoggerProvider
|
||||
{
|
||||
private readonly ILogsWriter logsManager;
|
||||
private readonly CorrelationVector correlationVector;
|
||||
|
||||
public CVLoggerProvider(ILogsWriter logsWriter)
|
||||
{
|
||||
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
|
||||
this.correlationVector = new CorrelationVector();
|
||||
}
|
||||
|
||||
public void LogEntry(Log log)
|
||||
{
|
||||
if (this.correlationVector is not null)
|
||||
{
|
||||
log.CorrelationVector = this.correlationVector.Value.ToString();
|
||||
this.correlationVector.Increment();
|
||||
}
|
||||
|
||||
this.logsManager.WriteLog(log);
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return new CVLogger(categoryName, this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class DebugLogsWriter : ILogsWriter
|
||||
{
|
||||
public void WriteLog(Log log)
|
||||
{
|
||||
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public interface ICVLoggerProvider : ILoggerProvider
|
||||
{
|
||||
void LogEntry(Log log);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace System.Logging
|
||||
{
|
||||
public interface ILogsWriter
|
||||
{
|
||||
void WriteLog(Log log);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Slim.Resolvers;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class LoggerResolver : IDependencyResolver
|
||||
{
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
|
||||
type == typeof(ILogger))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
|
||||
{
|
||||
return ResolveScopedLogger(serviceProvider, type);
|
||||
}
|
||||
else if (type == typeof(ILogger))
|
||||
{
|
||||
return ResolveLogger(serviceProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>System.DependencyInjection</RootNamespace>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.1.7</Version>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||
<Description>Extensions for the Slim Dependency Injection engine</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE" Link="LICENSE">
|
||||
<PackagePath></PackagePath>
|
||||
<Pack>True</Pack>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Slim" Version="1.6.0" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,105 @@
|
||||
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,55 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
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().Throw<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void PasswordNull_HashString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltString, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SaltNull_HashBytes_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, null, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SaltNull_HashString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, null, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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().Throw<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,122 @@
|
||||
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,48 @@
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,214 @@
|
||||
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
|
||||
{
|
||||
public async Task<string> Decrypt(string key, string iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToString(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<string> Decrypt(byte[] key, byte[] iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToString(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Decrypt(string key, string iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<Stream> Decrypt(string key, string iv, Stream value)
|
||||
{
|
||||
return await DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value)
|
||||
{
|
||||
return await DecryptInternal(key, iv, value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<string> Encrypt(string key, string iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToString(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<string> Encrypt(byte[] key, byte[] iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToString(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Encrypt(string key, string iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<Stream> Encrypt(string key, string iv, Stream value)
|
||||
{
|
||||
return value is null
|
||||
? throw new ArgumentNullException(nameof(value))
|
||||
: await EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value)
|
||||
{
|
||||
return value is null
|
||||
? throw new ArgumentNullException(nameof(value))
|
||||
: await EncryptInternal(key, iv, value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Stream GetEncryptionStream(string key, string iv, Stream outStream)
|
||||
{
|
||||
return GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
|
||||
}
|
||||
|
||||
public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream)
|
||||
{
|
||||
return GetEncryptionStreamInternal(key, iv, outStream);
|
||||
}
|
||||
|
||||
public Stream GetDecryptionStream(string key, string iv, Stream inStream)
|
||||
{
|
||||
return GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
|
||||
}
|
||||
|
||||
public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream)
|
||||
{
|
||||
return GetDecryptionStreamInternal(key, iv, inStream);
|
||||
}
|
||||
|
||||
private 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> 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 = GetEncryptionStreamInternal(key, iv, encryptedMemoryStream);
|
||||
await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false);
|
||||
if (!cryptoStream.HasFlushedFinalBlock)
|
||||
{
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
encryptedMemoryStream.Position = 0;
|
||||
return encryptedMemoryStream;
|
||||
}
|
||||
|
||||
private static async Task<Stream> DecryptInternal(byte[] key, byte[] iv, Stream toDecryptStream)
|
||||
{
|
||||
if (key.Length < 32)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
|
||||
}
|
||||
|
||||
if (iv.Length < 16)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
|
||||
}
|
||||
|
||||
key = key.Take(32).ToArray();
|
||||
iv = iv.Take(16).ToArray();
|
||||
|
||||
|
||||
var decryptedMemoryStream = new MemoryStream();
|
||||
using var cryptoStream = GetDecryptionStreamInternal(key, iv, toDecryptStream);
|
||||
await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false);
|
||||
if (!cryptoStream.HasFlushedFinalBlock)
|
||||
{
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
decryptedMemoryStream.Position = 0;
|
||||
return decryptedMemoryStream;
|
||||
}
|
||||
|
||||
private static CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
|
||||
{
|
||||
using var aes = Aes.Create();
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
var crypto = aes.CreateEncryptor(key, iv);
|
||||
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write);
|
||||
return cryptoStream;
|
||||
}
|
||||
|
||||
private static CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
|
||||
{
|
||||
using var aes = Aes.Create();
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
var crypto = aes.CreateDecryptor(key, iv);
|
||||
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read);
|
||||
return cryptoStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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,102 @@
|
||||
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,12 @@
|
||||
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,47 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
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,62 @@
|
||||
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,59 @@
|
||||
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,28 @@
|
||||
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.3</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="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,23 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
-38
@@ -1,11 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// AVL tree implementation.
|
||||
@@ -30,13 +25,14 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
AVLNode<T> root;
|
||||
private int count = 0;
|
||||
private bool isReadOnly = false;
|
||||
private readonly bool isReadOnly = false;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of items currently stored in the tree.
|
||||
/// </summary>
|
||||
public int Count {
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
@@ -51,7 +47,6 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an AVLTree collection.
|
||||
/// </summary>
|
||||
/// <param name="comparator"></param>
|
||||
public AVLTree()
|
||||
{
|
||||
|
||||
@@ -65,7 +60,7 @@ namespace SystemExtensions.Collections
|
||||
public void Add(T value)
|
||||
{
|
||||
count++;
|
||||
AVLNode<T> newItem = new AVLNode<T>(value);
|
||||
var newItem = new AVLNode<T>(value);
|
||||
if (root == null)
|
||||
{
|
||||
root = newItem;
|
||||
@@ -82,8 +77,8 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>True if the value is in the tree.</returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
AVLNode<T> node = Find(value, root);
|
||||
if(node == null)
|
||||
var node = Find(value, root);
|
||||
if (node == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -110,19 +105,19 @@ namespace SystemExtensions.Collections
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
|
||||
while(queue.Count > 0)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
if(currentNode.Left != null)
|
||||
var currentNode = queue.Dequeue();
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
currentNode.Left = null;
|
||||
count--;
|
||||
}
|
||||
if(currentNode.Right != null)
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
currentNode.Right = null;
|
||||
@@ -139,11 +134,11 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="arrayIndex">Starting index of the provided array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
var currentNode = queue.Dequeue();
|
||||
array[arrayIndex++] = currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
@@ -169,7 +164,7 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>Array containing the values contained in the tree.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] array = new T[count];
|
||||
var array = new T[count];
|
||||
CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
@@ -196,7 +191,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private AVLNode<T> BalanceTree(AVLNode<T> current)
|
||||
{
|
||||
int b_factor = BalanceFactor(current);
|
||||
var b_factor = BalanceFactor(current);
|
||||
if (b_factor > 1)
|
||||
{
|
||||
if (BalanceFactor(current.Left) > 0)
|
||||
@@ -293,7 +288,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private AVLNode<T> Find(T target, AVLNode<T> current)
|
||||
{
|
||||
if(current == null)
|
||||
if (current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -304,7 +299,9 @@ namespace SystemExtensions.Collections
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Find(target, current.Left);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -313,7 +310,9 @@ namespace SystemExtensions.Collections
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Find(target, current.Right);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -323,46 +322,46 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private int GetHeight(AVLNode<T> current)
|
||||
{
|
||||
int height = 0;
|
||||
var height = 0;
|
||||
if (current != null)
|
||||
{
|
||||
int l = GetHeight(current.Left);
|
||||
int r = GetHeight(current.Right);
|
||||
int m = Max(l, r);
|
||||
var l = GetHeight(current.Left);
|
||||
var r = GetHeight(current.Right);
|
||||
var m = Max(l, r);
|
||||
height = m + 1;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
private int BalanceFactor(AVLNode<T> current)
|
||||
{
|
||||
int l = GetHeight(current.Left);
|
||||
int r = GetHeight(current.Right);
|
||||
int b_factor = l - r;
|
||||
var l = GetHeight(current.Left);
|
||||
var r = GetHeight(current.Right);
|
||||
var b_factor = l - r;
|
||||
return b_factor;
|
||||
}
|
||||
private AVLNode<T> RotateRR(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Right;
|
||||
var pivot = parent.Right;
|
||||
parent.Right = pivot.Left;
|
||||
pivot.Left = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLL(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Left;
|
||||
var pivot = parent.Left;
|
||||
parent.Left = pivot.Right;
|
||||
pivot.Right = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLR(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Left;
|
||||
var pivot = parent.Left;
|
||||
parent.Left = RotateRR(pivot);
|
||||
return RotateLL(parent);
|
||||
}
|
||||
private AVLNode<T> RotateRL(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Right;
|
||||
var pivot = parent.Right;
|
||||
parent.Right = RotateLL(pivot);
|
||||
return RotateRR(parent);
|
||||
}
|
||||
@@ -372,12 +371,12 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
var currentNode = queue.Dequeue();
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
@@ -390,7 +389,5 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+26
-36
@@ -1,11 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Binary heap implementation.
|
||||
@@ -16,7 +11,9 @@ namespace SystemExtensions.Collections
|
||||
{
|
||||
#region Fields
|
||||
T[] items;
|
||||
int capacity, count, initialCapacity;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private readonly int initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
@@ -42,10 +39,12 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity { get => capacity;
|
||||
public int Capacity
|
||||
{
|
||||
get => capacity;
|
||||
set
|
||||
{
|
||||
if(value > capacity)
|
||||
if (value > capacity)
|
||||
{
|
||||
Array.Resize(ref items, value);
|
||||
capacity = value;
|
||||
@@ -61,7 +60,6 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
public BinaryHeap()
|
||||
{
|
||||
capacity = 10;
|
||||
@@ -71,7 +69,6 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(int capacity)
|
||||
{
|
||||
@@ -87,12 +84,12 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
if(count == Capacity - 1)
|
||||
if (count == Capacity - 1)
|
||||
{
|
||||
Capacity = 2 * Capacity;
|
||||
}
|
||||
int position = ++count;
|
||||
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position = position / 2)
|
||||
var position = ++count;
|
||||
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
|
||||
{
|
||||
items[position] = items[position / 2];
|
||||
}
|
||||
@@ -108,7 +105,7 @@ namespace SystemExtensions.Collections
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
T min = items[1];
|
||||
var min = items[1];
|
||||
items[1] = items[count--];
|
||||
BubbleDown(1);
|
||||
return min;
|
||||
@@ -123,7 +120,7 @@ namespace SystemExtensions.Collections
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
T min = items[1];
|
||||
var min = items[1];
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -132,7 +129,7 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>Array with values sorted as in heap</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] newArray = new T[count];
|
||||
var newArray = new T[count];
|
||||
Array.Copy(items, 1, newArray, 0, count);
|
||||
return newArray;
|
||||
}
|
||||
@@ -159,8 +156,11 @@ namespace SystemExtensions.Collections
|
||||
public void Clear(bool completeClear)
|
||||
{
|
||||
count = 0;
|
||||
capacity = initialCapacity;
|
||||
items = new T[initialCapacity];
|
||||
if (completeClear)
|
||||
{
|
||||
capacity = initialCapacity;
|
||||
items = new T[initialCapacity];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the heap.
|
||||
@@ -168,7 +168,7 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
yield return items[i + 1];
|
||||
}
|
||||
@@ -181,16 +181,16 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="index">Index of element to bubble</param>
|
||||
private void BubbleDown(int index)
|
||||
{
|
||||
T temp = items[index];
|
||||
int childIndex = 0;
|
||||
for(; 2*index <= count; index = childIndex)
|
||||
var temp = items[index];
|
||||
int childIndex;
|
||||
for (; 2 * index <= count; index = childIndex)
|
||||
{
|
||||
childIndex = 2 * index;
|
||||
if(childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
|
||||
if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
|
||||
{
|
||||
childIndex++;
|
||||
}
|
||||
if(temp.CompareTo(items[childIndex]) > 0)
|
||||
if (temp.CompareTo(items[childIndex]) > 0)
|
||||
{
|
||||
items[index] = items[childIndex];
|
||||
}
|
||||
@@ -202,16 +202,6 @@ namespace SystemExtensions.Collections
|
||||
items[index] = temp;
|
||||
}
|
||||
/// <summary>
|
||||
/// Build heap from unordered array
|
||||
/// </summary>
|
||||
private void BuildHeap()
|
||||
{
|
||||
for(int i = count / 2; i > 0; i--)
|
||||
{
|
||||
BubbleDown(i);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Implementation of IEnumerator.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator over the array.</returns>
|
||||
+56
-62
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Fibonacci Heap implementation.
|
||||
@@ -44,7 +37,6 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Constructor for Fibonacci heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
public FibonacciHeap()
|
||||
{
|
||||
|
||||
@@ -57,14 +49,16 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
FibonacciNode<T> node = new FibonacciNode<T>();
|
||||
node.Value = value;
|
||||
var node = new FibonacciNode<T>
|
||||
{
|
||||
Value = value,
|
||||
Marked = false,
|
||||
Child = null,
|
||||
Parent = null,
|
||||
Degree = 0
|
||||
};
|
||||
node.Previous = node.Next = node;
|
||||
node.Degree = 0;
|
||||
node.Marked = false;
|
||||
node.Child = null;
|
||||
node.Parent = null;
|
||||
root = Merge(root, node);
|
||||
root = this.Merge(root, node);
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -83,7 +77,7 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>Minimum value.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
FibonacciNode<T> currentRoot = root;
|
||||
var currentRoot = root;
|
||||
if (currentRoot != null)
|
||||
{
|
||||
root = RemoveMinimum(root);
|
||||
@@ -102,7 +96,7 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="value">New value to be assigned to the node.</param>
|
||||
public void DecreaseKey(T oldValue, T value)
|
||||
{
|
||||
FibonacciNode<T> node = Find(root, oldValue);
|
||||
var node = Find(root, oldValue);
|
||||
root = DecreaseKey(root, node, value);
|
||||
}
|
||||
/// <summary>
|
||||
@@ -131,11 +125,11 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>Array with values from the heap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
if(count == 0)
|
||||
if (count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
T[] array = new T[count];
|
||||
var array = new T[count];
|
||||
if (count == 1)
|
||||
{
|
||||
array[0] = root.Value;
|
||||
@@ -143,7 +137,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = 0;
|
||||
var index = 0;
|
||||
RecursiveFillArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
@@ -166,7 +160,7 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="index">Index of the next unintialized element in the array.</param>
|
||||
private void RecursiveFillArray(FibonacciNode<T> currentNode, ref T[] array, ref int index)
|
||||
{
|
||||
FibonacciNode<T> oldNode = currentNode;
|
||||
var oldNode = currentNode;
|
||||
do
|
||||
{
|
||||
array[index] = currentNode.Value;
|
||||
@@ -184,12 +178,12 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="currentNode">Current node in the iteration.</param>
|
||||
private IEnumerator<T> GetEnumerator(FibonacciNode<T> currentNode)
|
||||
{
|
||||
Queue<FibonacciNode<T>> queue = new Queue<FibonacciNode<T>>();
|
||||
var queue = new Queue<FibonacciNode<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while(queue.Count > 0)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
FibonacciNode<T> oldNode = currentNode;
|
||||
var oldNode = currentNode;
|
||||
do
|
||||
{
|
||||
yield return currentNode.Value;
|
||||
@@ -199,8 +193,8 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
currentNode = currentNode.Previous;
|
||||
} while (currentNode != oldNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Recursively remove the node and its children from the heap.
|
||||
@@ -208,9 +202,9 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="node">Node to be removed.</param>
|
||||
private void Remove(FibonacciNode<T> node)
|
||||
{
|
||||
if(node != null)
|
||||
if (node != null)
|
||||
{
|
||||
FibonacciNode<T> current = node;
|
||||
var current = node;
|
||||
do
|
||||
{
|
||||
Remove(current.Child);
|
||||
@@ -230,22 +224,22 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="node2">Root of second heap.</param>
|
||||
private FibonacciNode<T> Merge(FibonacciNode<T> node1, FibonacciNode<T> node2)
|
||||
{
|
||||
if(node1 == null)
|
||||
if (node1 == null)
|
||||
{
|
||||
return node2;
|
||||
}
|
||||
if(node2 == null)
|
||||
if (node2 == null)
|
||||
{
|
||||
return node1;
|
||||
}
|
||||
if(node1.Value.CompareTo(node2.Value) > 0)
|
||||
if (node1.Value.CompareTo(node2.Value) > 0)
|
||||
{
|
||||
FibonacciNode<T> temp = node1;
|
||||
var temp = node1;
|
||||
node1 = node2;
|
||||
node2 = temp;
|
||||
}
|
||||
FibonacciNode<T> node1Next = node1.Next;
|
||||
FibonacciNode<T> node2Prev = node2.Previous;
|
||||
var node1Next = node1.Next;
|
||||
var node2Prev = node2.Previous;
|
||||
node1.Next = node2;
|
||||
node2.Previous = node1;
|
||||
node1Next.Previous = node2Prev;
|
||||
@@ -270,11 +264,11 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="node">Node to be removed from its parent.</param>
|
||||
private void RemoveParent(FibonacciNode<T> node)
|
||||
{
|
||||
if(node == null)
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FibonacciNode<T> current = node;
|
||||
var current = node;
|
||||
do
|
||||
{
|
||||
current.Marked = false;
|
||||
@@ -290,7 +284,7 @@ namespace SystemExtensions.Collections
|
||||
private FibonacciNode<T> RemoveMinimum(FibonacciNode<T> node)
|
||||
{
|
||||
RemoveParent(node.Child);
|
||||
if(node.Next == node)
|
||||
if (node.Next == node)
|
||||
{
|
||||
node = node.Child;
|
||||
}
|
||||
@@ -300,23 +294,23 @@ namespace SystemExtensions.Collections
|
||||
node.Previous.Next = node.Next;
|
||||
node = Merge(node.Next, node.Child);
|
||||
}
|
||||
if(node == null)
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
FibonacciNode<T>[] trees = new FibonacciNode<T>[64];
|
||||
var trees = new FibonacciNode<T>[64];
|
||||
while (true)
|
||||
{
|
||||
if(trees[node.Degree] != null)
|
||||
if (trees[node.Degree] != null)
|
||||
{
|
||||
FibonacciNode<T> t = trees[node.Degree];
|
||||
if(t == node)
|
||||
var t = trees[node.Degree];
|
||||
if (t == node)
|
||||
{
|
||||
break;
|
||||
}
|
||||
trees[node.Degree] = null;
|
||||
if(node.Value.CompareTo(t.Value) < 0)
|
||||
if (node.Value.CompareTo(t.Value) < 0)
|
||||
{
|
||||
t.Previous.Next = t.Next;
|
||||
t.Next.Previous = t.Previous;
|
||||
@@ -326,7 +320,7 @@ namespace SystemExtensions.Collections
|
||||
{
|
||||
t.Previous.Next = t.Next;
|
||||
t.Next.Previous = t.Previous;
|
||||
if(node.Next == node)
|
||||
if (node.Next == node)
|
||||
{
|
||||
t.Next = t.Previous = t;
|
||||
AddChild(t, node);
|
||||
@@ -350,11 +344,11 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
node = node.Next;
|
||||
}
|
||||
FibonacciNode<T> min = node;
|
||||
FibonacciNode<T> start = node;
|
||||
var min = node;
|
||||
var start = node;
|
||||
do
|
||||
{
|
||||
if(node.Value.CompareTo(min.Value) < 0)
|
||||
if (node.Value.CompareTo(min.Value) < 0)
|
||||
{
|
||||
min = node;
|
||||
}
|
||||
@@ -370,7 +364,7 @@ namespace SystemExtensions.Collections
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> Cut(FibonacciNode<T> root, FibonacciNode<T> node)
|
||||
{
|
||||
if(node.Next == node)
|
||||
if (node.Next == node)
|
||||
{
|
||||
node.Parent.Child = null;
|
||||
}
|
||||
@@ -393,26 +387,26 @@ namespace SystemExtensions.Collections
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> DecreaseKey(FibonacciNode<T> root, FibonacciNode<T> node, T value)
|
||||
{
|
||||
if(node.Value.CompareTo(value) < 0)
|
||||
if (node.Value.CompareTo(value) < 0)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
node.Value = value;
|
||||
if(node.Parent != null)
|
||||
if (node.Parent != null)
|
||||
{
|
||||
if(node.Value.CompareTo(node.Parent.Value) < 0)
|
||||
if (node.Value.CompareTo(node.Parent.Value) < 0)
|
||||
{
|
||||
root = Cut(root, node);
|
||||
FibonacciNode<T> parent = node.Parent;
|
||||
var parent = node.Parent;
|
||||
node.Parent = null;
|
||||
while(parent != null && parent.Marked)
|
||||
while (parent != null && parent.Marked)
|
||||
{
|
||||
root = Cut(root, parent);
|
||||
node = parent;
|
||||
parent = node.Parent;
|
||||
node.Parent = null;
|
||||
}
|
||||
if(parent != null && parent.Parent != null)
|
||||
if (parent != null && parent.Parent != null)
|
||||
{
|
||||
parent.Marked = true;
|
||||
}
|
||||
@@ -420,7 +414,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node.Value.CompareTo(root.Value) < 0)
|
||||
if (node.Value.CompareTo(root.Value) < 0)
|
||||
{
|
||||
root = node;
|
||||
}
|
||||
@@ -435,19 +429,19 @@ namespace SystemExtensions.Collections
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> Find(FibonacciNode<T> root, T value)
|
||||
{
|
||||
FibonacciNode<T> node = root;
|
||||
if(node == null)
|
||||
var node = root;
|
||||
if (node == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
do
|
||||
{
|
||||
if(node.Value.CompareTo(value) == 0)
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
FibonacciNode<T> ret = Find(node.Child, value);
|
||||
if(ret != null)
|
||||
var ret = Find(node.Child, value);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
@@ -537,7 +531,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
set
|
||||
{
|
||||
this.value = value;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
public int Degree
|
||||
+1
-7
@@ -1,10 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for queue implementations.
|
||||
+2
-10
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
@@ -16,7 +9,7 @@ namespace SystemExtensions.Collections
|
||||
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
private BinaryHeap<T> binaryHeap;
|
||||
private readonly BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
@@ -34,7 +27,6 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
public PriorityQueue()
|
||||
{
|
||||
binaryHeap = new BinaryHeap<T>();
|
||||
+31
-38
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Skip list implementation.
|
||||
@@ -30,10 +23,10 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
}
|
||||
private int count;
|
||||
private Random random;
|
||||
private NodeSet<T> head;
|
||||
private NodeSet<T> end;
|
||||
private int maxLevel = 10;
|
||||
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
|
||||
@@ -53,11 +46,11 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="maxLevel">Maximum level of the skip list.</param>
|
||||
public SkipList(int maxLevel = 10)
|
||||
{
|
||||
this.maxLevel = maxLevel;
|
||||
this.maxLevel = maxLevel;
|
||||
random = new Random();
|
||||
head = new NodeSet<T>(default(T), maxLevel);
|
||||
head = new NodeSet<T>(default, maxLevel);
|
||||
end = head;
|
||||
for(int i = 0; i <= maxLevel; i++)
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
@@ -71,8 +64,8 @@ namespace SystemExtensions.Collections
|
||||
/// <param name="item">Item to be added.</param>
|
||||
public void Add(T item)
|
||||
{
|
||||
NodeSet<T> curNode = head;
|
||||
int newLevel = 0;
|
||||
var curNode = head;
|
||||
var newLevel = 0;
|
||||
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
|
||||
{
|
||||
newLevel++;
|
||||
@@ -81,10 +74,10 @@ namespace SystemExtensions.Collections
|
||||
{
|
||||
level = newLevel;
|
||||
}
|
||||
NodeSet<T> newNode = new NodeSet<T>(item, newLevel);
|
||||
var newNode = new NodeSet<T>(item, newLevel);
|
||||
for (var i = 0; i <= newLevel; i++)
|
||||
{
|
||||
if(i > curNode.Level)
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
@@ -104,11 +97,11 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>True if removal was successful.</returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
bool removed = false;
|
||||
NodeSet<T> curNode = head;
|
||||
var removed = false;
|
||||
var curNode = head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
if(i > curNode.Level)
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
@@ -141,7 +134,7 @@ namespace SystemExtensions.Collections
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
for(int i = 0; i < maxLevel; i++)
|
||||
for (var i = 0; i < maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
@@ -154,7 +147,7 @@ namespace SystemExtensions.Collections
|
||||
/// <returns>True if item is present in the collection.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if(Find(item) != null)
|
||||
if (Find(item) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -167,8 +160,8 @@ namespace SystemExtensions.Collections
|
||||
/// <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)
|
||||
var node = head.Next[0];
|
||||
while (node != end)
|
||||
{
|
||||
array[arrayIndex] = node.Key;
|
||||
arrayIndex++;
|
||||
@@ -181,10 +174,10 @@ namespace SystemExtensions.Collections
|
||||
/// <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)
|
||||
var array = new T[count];
|
||||
var index = 0;
|
||||
var curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
array[index] = curNode.Key;
|
||||
index++;
|
||||
@@ -198,8 +191,8 @@ namespace SystemExtensions.Collections
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
NodeSet<T> curNode = head.Next[0];
|
||||
while(curNode != end)
|
||||
var curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
yield return curNode.Key;
|
||||
curNode = curNode.Next[0];
|
||||
@@ -213,17 +206,17 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private NodeSet<T> Find(T key)
|
||||
{
|
||||
NodeSet<T> curNode = head;
|
||||
var curNode = head;
|
||||
|
||||
for(int i = level; i >= 0; i--)
|
||||
for (var i = level; i >= 0; i--)
|
||||
{
|
||||
while(curNode.Next[i] != end)
|
||||
while (curNode.Next[i] != end)
|
||||
{
|
||||
if(curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
if (curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
else if (curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode.Next[i];
|
||||
}
|
||||
@@ -232,7 +225,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
|
||||
curNode = curNode.Next[0];
|
||||
if(curNode != end && curNode.Key.CompareTo(key) == 0)
|
||||
if (curNode != end && curNode.Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode;
|
||||
}
|
||||
+32
-37
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
@@ -29,7 +22,7 @@ namespace SystemExtensions.Collections
|
||||
Right = null;
|
||||
}
|
||||
}
|
||||
private Random randomGen;
|
||||
private readonly Random randomGen;
|
||||
private Node<T> root;
|
||||
private int count;
|
||||
#endregion
|
||||
@@ -44,14 +37,15 @@ namespace SystemExtensions.Collections
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => throw new NotImplementedException();
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Comparator method used to compare values.</param>
|
||||
public Treap()
|
||||
{
|
||||
randomGen = new Random();
|
||||
@@ -103,8 +97,8 @@ namespace SystemExtensions.Collections
|
||||
{
|
||||
if (root != null)
|
||||
{
|
||||
T[] array = new T[count];
|
||||
int index = 0;
|
||||
var array = new T[count];
|
||||
var index = 0;
|
||||
ToArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
@@ -134,14 +128,15 @@ namespace SystemExtensions.Collections
|
||||
#region Private Methods
|
||||
private Node<T> InsertNode(Node<T> node, T key)
|
||||
{
|
||||
if(node == null) {
|
||||
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)
|
||||
if (node.Left.Priority > node.Priority)
|
||||
{
|
||||
node = RotateRight(node);
|
||||
}
|
||||
@@ -149,7 +144,7 @@ namespace SystemExtensions.Collections
|
||||
else
|
||||
{
|
||||
node.Right = InsertNode(node.Right, key);
|
||||
if(node.Right.Priority > node.Priority)
|
||||
if (node.Right.Priority > node.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
}
|
||||
@@ -158,27 +153,27 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private Node<T> RemoveNode(Node<T> node, T key)
|
||||
{
|
||||
if(node == null)
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
return node;
|
||||
}
|
||||
if(key.CompareTo(node.Key) < 0)
|
||||
if (key.CompareTo(node.Key) < 0)
|
||||
{
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else if(key.CompareTo(node.Key) > 0)
|
||||
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)
|
||||
else if (node.Right == null)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if(node.Left.Priority < node.Right.Priority)
|
||||
else if (node.Left.Priority < node.Right.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
@@ -206,11 +201,11 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private void Clear(Node<T> node)
|
||||
{
|
||||
if(node.Left != null)
|
||||
if (node.Left != null)
|
||||
{
|
||||
Clear(node.Left);
|
||||
}
|
||||
if(node.Right != null)
|
||||
if (node.Right != null)
|
||||
{
|
||||
Clear(node.Right);
|
||||
}
|
||||
@@ -218,24 +213,24 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private Node<T> Find(Node<T> node, T key)
|
||||
{
|
||||
if(node == null)
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node.Key.CompareTo(key) < 0)
|
||||
if (node.Key.CompareTo(key) < 0)
|
||||
{
|
||||
Node<T> found = Find(node.Left, key);
|
||||
if(found == null)
|
||||
var found = Find(node.Left, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Right, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else if(node.Key.CompareTo(key) > 0)
|
||||
else if (node.Key.CompareTo(key) > 0)
|
||||
{
|
||||
Node<T> found = Find(node.Right, key);
|
||||
var found = Find(node.Right, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Left, key);
|
||||
@@ -250,7 +245,7 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private void ToArray(Node<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if(node != null)
|
||||
if (node != null)
|
||||
{
|
||||
ToArray(node.Left, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
@@ -260,17 +255,17 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
|
||||
{
|
||||
Queue<Node<T>> queue = new Queue<Node<T>>();
|
||||
var queue = new Queue<Node<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while(queue.Count > 0)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
yield return currentNode.Key;
|
||||
if(currentNode.Left != null)
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if(currentNode.Right != null)
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class BytesExtensions
|
||||
{
|
||||
public static byte[] ReadAllBytes(this Stream stream)
|
||||
{
|
||||
if (stream is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
|
||||
var buffer = new byte[256];
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, 0, 256)) > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, read);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class CastExtensions
|
||||
{
|
||||
public static int Floor(this double value)
|
||||
{
|
||||
return (int)Math.Floor(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 Floor(this float value)
|
||||
{
|
||||
return (int)Math.Floor(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 ToInt(this double value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public static int ToInt(this float value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public static int ToInt(this decimal value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class LinqExtensions
|
||||
{
|
||||
public static bool None<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
|
||||
{
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
predicate.ThrowIfNull(nameof(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));
|
||||
}
|
||||
|
||||
collection.Clear();
|
||||
return collection;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static T Deserialize<T>(this string serialized)
|
||||
where T : class
|
||||
{
|
||||
if (serialized.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ArgumentException("Provided serialized string cannot be null or whitespace", nameof(serialized));
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(serialized);
|
||||
}
|
||||
|
||||
public static string Serialize<T>(this T obj)
|
||||
where T : class
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(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)
|
||||
{
|
||||
throw new ArgumentNullException(name);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
sealed class ValidatedNotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class Optional
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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 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 override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Optional<T>)
|
||||
{
|
||||
return this.Equals(obj);
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public bool Equals(Optional<T> other)
|
||||
{
|
||||
if (this is Some && other is Some)
|
||||
{
|
||||
return this.As<Some>().Equals(other.As<Some>());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public class Result<TSuccess, TFailure>
|
||||
{
|
||||
private readonly object value;
|
||||
|
||||
public Result(TSuccess successValue)
|
||||
{
|
||||
value = successValue;
|
||||
}
|
||||
public Result(TFailure failureValue)
|
||||
{
|
||||
value = failureValue;
|
||||
}
|
||||
|
||||
public bool TryExtractSuccess(out TSuccess successValue)
|
||||
{
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
successValue = success;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
successValue = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool TryExtractFailure(out TFailure failureValue)
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static void DoWhileReading(this Stream stream, Action<int, byte[]> action, int bufferLength = 256)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Text;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static bool IsNullOrEmpty(this string s)
|
||||
{
|
||||
return string.IsNullOrEmpty(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 string GetString(this byte[] bytes)
|
||||
{
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
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)
|
||||
{
|
||||
return Task.Factory.StartNew(async () =>
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class Try
|
||||
{
|
||||
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 action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
foreach (var catchAction in this.catchActions)
|
||||
{
|
||||
return catchAction(ex);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public TResult Finally(Action act)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Http
|
||||
{
|
||||
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
|
||||
{
|
||||
add
|
||||
{
|
||||
this.eventEmitted += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace System.Http
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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; }
|
||||
|
||||
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,77 @@
|
||||
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.ThrowIfNull(nameof(flowId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
namespace System.Structures.BitStructures
|
||||
{
|
||||
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)
|
||||
{
|
||||
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, 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
|
||||
namespace System.Structures.BitStructures
|
||||
{
|
||||
public struct Int64BitStruct : IEquatable<Int64BitStruct>
|
||||
{
|
||||
public Int64BitStruct(uint low, uint high)
|
||||
{
|
||||
this.Value = low + ((ulong)high << 32);
|
||||
}
|
||||
|
||||
public Int64BitStruct(int low, int high)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<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.4</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>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+120
-155
@@ -1,12 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SystemExtensions.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SystemExtensions.Threading
|
||||
namespace System.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// Threadpool implementation that uses a priority queue as the queue for the tasks to execute.
|
||||
@@ -17,9 +11,9 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
private class QueueEntry : IComparable<QueueEntry>
|
||||
{
|
||||
public TaskPriority TaskPriority;
|
||||
public WaitCallback WaitCallback;
|
||||
public Object Object;
|
||||
public TaskPriority TaskPriority { get; }
|
||||
public WaitCallback WaitCallback { get; }
|
||||
public object Object { get; }
|
||||
public QueueEntry(TaskPriority priority, WaitCallback callback, object obj)
|
||||
{
|
||||
this.TaskPriority = priority;
|
||||
@@ -116,19 +110,22 @@ namespace SystemExtensions.Threading
|
||||
private volatile List<WorkerThread> threadpool;
|
||||
private volatile PriorityQueue<QueueEntry> tasks;
|
||||
private Thread observer;
|
||||
private CancellationTokenSource observerCancellationTokenSource = new CancellationTokenSource();
|
||||
private int maxThreads;
|
||||
private object tasksLock = new object();
|
||||
private readonly object tasksLock = new object();
|
||||
private struct WorkerThread
|
||||
{
|
||||
public Thread thread;
|
||||
public bool running, working;
|
||||
public Thread Thread { get; set; }
|
||||
public bool Running { get; set; }
|
||||
public bool Working { get; set; }
|
||||
public CancellationTokenSource CancellationTokenSource { get; set; }
|
||||
}
|
||||
private struct Statistics
|
||||
{
|
||||
public bool Initialized;
|
||||
public int PerformanceCounter;
|
||||
public DateTime LastUpdate;
|
||||
public double LoopFrequency;
|
||||
public bool Initialized { get; set; }
|
||||
public int PerformanceCounter { get; set; }
|
||||
public DateTime LastUpdate { get; set; }
|
||||
public double LoopFrequency { get; set; }
|
||||
}
|
||||
#endregion
|
||||
#region Properties
|
||||
@@ -139,7 +136,7 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
get
|
||||
{
|
||||
return threadpool.Count;
|
||||
return this.threadpool is null ? 0 : this.threadpool.Count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -149,7 +146,7 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
get
|
||||
{
|
||||
return tasks.Count == 0;
|
||||
return this.tasks is null ? true : this.tasks.Count == 0;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -177,24 +174,15 @@ namespace SystemExtensions.Threading
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<QueueEntry>();
|
||||
maxThreads = System.Environment.ProcessorCount;
|
||||
for (int i = 0; i < maxThreads; i++)
|
||||
for (var i = 0; i < maxThreads; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread();
|
||||
}
|
||||
observer = new Thread(() =>
|
||||
observer = new Thread(() => ObserverLoop())
|
||||
{
|
||||
ObserverLoop();
|
||||
});
|
||||
observer.Name = "ThreadPool ObserverThread";
|
||||
observer.Priority = ThreadPriority.BelowNormal;
|
||||
Name = "ThreadPool ObserverThread",
|
||||
Priority = ThreadPriority.BelowNormal
|
||||
};
|
||||
observer.Start();
|
||||
}
|
||||
/// <summary>
|
||||
@@ -206,22 +194,11 @@ namespace SystemExtensions.Threading
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<QueueEntry>();
|
||||
this.maxThreads = Math.Max(maxThreads, 1);
|
||||
for (int i = 0; i < maxThreads; i++)
|
||||
for (var i = 0; i < maxThreads; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread();
|
||||
}
|
||||
observer = new Thread(() =>
|
||||
{
|
||||
ObserverLoop();
|
||||
});
|
||||
observer = new Thread(() => ObserverLoop());
|
||||
observer.Name = "ThreadPool ObserverThread";
|
||||
observer.Priority = ThreadPriority.BelowNormal;
|
||||
observer.Start();
|
||||
@@ -239,72 +216,27 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<QueueEntry>();
|
||||
for(int i = 0; i < lowest; i++)
|
||||
for (var i = 0; i < lowest; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Lowest;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread(ThreadPriority.Lowest);
|
||||
}
|
||||
for (int i = 0; i < belowNormal; i++)
|
||||
for (var i = 0; i < belowNormal; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.BelowNormal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread(ThreadPriority.BelowNormal);
|
||||
}
|
||||
for (int i = 0; i < normal; i++)
|
||||
for (var i = 0; i < normal; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Normal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread(ThreadPriority.Normal);
|
||||
}
|
||||
for (int i = 0; i < aboveNormal; i++)
|
||||
for (var i = 0; i < aboveNormal; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.AboveNormal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread(ThreadPriority.AboveNormal);
|
||||
}
|
||||
for (int i = 0; i < highest; i++)
|
||||
for (var i = 0; i < highest; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Highest;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread(ThreadPriority.Highest);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
@@ -315,7 +247,11 @@ namespace SystemExtensions.Threading
|
||||
/// <param name="taskPriority">Priority of task. Affects its position into the queue.</param>
|
||||
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority)
|
||||
{
|
||||
while (!Monitor.TryEnter(tasksLock));
|
||||
while (!Monitor.TryEnter(tasksLock))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState));
|
||||
Monitor.Exit(tasksLock);
|
||||
}
|
||||
@@ -330,26 +266,56 @@ namespace SystemExtensions.Threading
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private void CreateAndStartWorkerThread(ThreadPriority threadPriority)
|
||||
{
|
||||
var worker = new WorkerThread();
|
||||
worker.Thread = new Thread(() => ThreadMainLoop(ref worker));
|
||||
worker.Thread.Name = "ThreadPool WorkerThread";
|
||||
worker.Thread.Priority = threadPriority;
|
||||
worker.Running = true;
|
||||
worker.CancellationTokenSource = new CancellationTokenSource();
|
||||
worker.Thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
private void CreateAndStartWorkerThread()
|
||||
{
|
||||
var worker = new WorkerThread();
|
||||
worker.Thread = new Thread(() => ThreadMainLoop(ref worker));
|
||||
worker.Thread.Name = "ThreadPool WorkerThread";
|
||||
worker.Running = true;
|
||||
worker.CancellationTokenSource = new CancellationTokenSource();
|
||||
worker.Thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
/// <summary>
|
||||
/// Main loop that a thread from the pool is running.
|
||||
/// </summary>
|
||||
/// <threadId>Id of thread</threadId>
|
||||
private void ThreadMainLoop(ref WorkerThread thisWorkerThread)
|
||||
{
|
||||
thisWorkerThread.running = true;
|
||||
while (thisWorkerThread.running)
|
||||
thisWorkerThread.Running = true;
|
||||
while (thisWorkerThread.Running)
|
||||
{
|
||||
//Check if there are tasks
|
||||
if (thisWorkerThread.CancellationTokenSource.Token.IsCancellationRequested)
|
||||
{
|
||||
thisWorkerThread.Running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if there are tasks
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
//If there are tasks, acquire a lock onto the list
|
||||
//and try to dequeue the highest priority task.
|
||||
//Finally, release the lock and invoke the task.
|
||||
|
||||
thisWorkerThread.working = true;
|
||||
thisWorkerThread.Working = true;
|
||||
QueueEntry task = null;
|
||||
while (!Monitor.TryEnter(tasksLock)) ;
|
||||
while (!Monitor.TryEnter(tasksLock))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
task = tasks.Dequeue();
|
||||
@@ -358,10 +324,10 @@ namespace SystemExtensions.Threading
|
||||
if (task != null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!");
|
||||
WaitCallback waitCallback = task.WaitCallback;
|
||||
var waitCallback = task.WaitCallback;
|
||||
waitCallback.Invoke(task.Object);
|
||||
}
|
||||
thisWorkerThread.working = false;
|
||||
thisWorkerThread.Working = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,7 +336,7 @@ namespace SystemExtensions.Threading
|
||||
/// </summary>
|
||||
private void ObserverLoop()
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
var statistics = new Statistics();
|
||||
while (true)
|
||||
{
|
||||
//Observer operates on a 100ms loop. Due to the low priority of the thread itself, this loop will almost always take
|
||||
@@ -380,11 +346,16 @@ namespace SystemExtensions.Threading
|
||||
//If counter is under -10, it will try to remove a thread from the threadpool, unless the threadpool has reached less than
|
||||
//max size / 4.
|
||||
|
||||
if (observerCancellationTokenSource.Token.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//This part of code updates the statistics of the threadpool.
|
||||
if (statistics.Initialized)
|
||||
{
|
||||
double loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds;
|
||||
if(statistics.LoopFrequency == 0)
|
||||
var loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds;
|
||||
if (statistics.LoopFrequency == 0)
|
||||
{
|
||||
statistics.LoopFrequency = loopDuration;
|
||||
}
|
||||
@@ -403,10 +374,10 @@ namespace SystemExtensions.Threading
|
||||
|
||||
|
||||
//This part of code adjusts the performance counter. Ideally, the value should be 0.
|
||||
if(tasks.Count > 0)
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
statistics.PerformanceCounter++;
|
||||
if(statistics.PerformanceCounter > 5)
|
||||
if (statistics.PerformanceCounter > 5)
|
||||
{
|
||||
statistics.PerformanceCounter = 5;
|
||||
}
|
||||
@@ -414,18 +385,18 @@ namespace SystemExtensions.Threading
|
||||
else
|
||||
{
|
||||
statistics.PerformanceCounter--;
|
||||
if(statistics.PerformanceCounter < -10)
|
||||
if (statistics.PerformanceCounter < -10)
|
||||
{
|
||||
statistics.PerformanceCounter = -10;
|
||||
}
|
||||
}
|
||||
|
||||
//This part of code adjusts thread priorities based on the current performance of the threadpool
|
||||
if(tasks.Count > 0)
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
//If there are tasks pending, find a thread with priority under Normal and upgrade its priority.
|
||||
Thread t = FindThreadWithLowPriority();
|
||||
if(t != null)
|
||||
var t = FindThreadWithLowPriority();
|
||||
if (t != null)
|
||||
{
|
||||
UpgradeThreadPriority(t);
|
||||
}
|
||||
@@ -433,8 +404,8 @@ namespace SystemExtensions.Threading
|
||||
else
|
||||
{
|
||||
//If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority.
|
||||
Thread t = FindThreadWithAcceptablePriority();
|
||||
if(t != null)
|
||||
var t = FindThreadWithAcceptablePriority();
|
||||
if (t != null)
|
||||
{
|
||||
DowngradeThreadPriority(t);
|
||||
}
|
||||
@@ -449,18 +420,10 @@ namespace SystemExtensions.Threading
|
||||
//Add a thread to the threadpool.
|
||||
//Reset counter to 0.
|
||||
statistics.PerformanceCounter = 0;
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
this.CreateAndStartWorkerThread();
|
||||
}
|
||||
}
|
||||
else if(statistics.PerformanceCounter <= -10)
|
||||
else if (statistics.PerformanceCounter <= -10)
|
||||
{
|
||||
if (threadpool.Count > maxThreads / 4)
|
||||
{
|
||||
@@ -468,14 +431,14 @@ namespace SystemExtensions.Threading
|
||||
//If thread is currently working, notify it to close.
|
||||
//Else, abort the thread.
|
||||
//Reset counter to 0.
|
||||
WorkerThread worker = threadpool[threadpool.Count - 1];
|
||||
if (worker.working)
|
||||
var worker = threadpool[threadpool.Count - 1];
|
||||
if (worker.Working)
|
||||
{
|
||||
worker.running = false;
|
||||
worker.Running = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.thread.Abort();
|
||||
worker.CancellationTokenSource.Cancel();
|
||||
}
|
||||
threadpool.RemoveAt(threadpool.Count - 1);
|
||||
statistics.PerformanceCounter = 0;
|
||||
@@ -489,11 +452,11 @@ namespace SystemExtensions.Threading
|
||||
/// <returns>Thread with low priority.</returns>
|
||||
private Thread FindThreadWithLowPriority()
|
||||
{
|
||||
foreach(WorkerThread t in threadpool)
|
||||
foreach (var t in threadpool)
|
||||
{
|
||||
if(t.thread.Priority == ThreadPriority.Lowest || t.thread.Priority == ThreadPriority.BelowNormal)
|
||||
if (t.Thread.Priority == ThreadPriority.Lowest || t.Thread.Priority == ThreadPriority.BelowNormal)
|
||||
{
|
||||
return t.thread;
|
||||
return t.Thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -504,11 +467,11 @@ namespace SystemExtensions.Threading
|
||||
/// <returns>Thread with BelowNormal or Normal priority.</returns>
|
||||
private Thread FindThreadWithAcceptablePriority()
|
||||
{
|
||||
foreach (WorkerThread t in threadpool)
|
||||
foreach (var t in threadpool)
|
||||
{
|
||||
if (t.thread.Priority == ThreadPriority.Normal || t.thread.Priority == ThreadPriority.BelowNormal)
|
||||
if (t.Thread.Priority == ThreadPriority.Normal || t.Thread.Priority == ThreadPriority.BelowNormal)
|
||||
{
|
||||
return t.thread;
|
||||
return t.Thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -574,25 +537,27 @@ namespace SystemExtensions.Threading
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
if (!this.disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (observer != null)
|
||||
if (this.observer != null)
|
||||
{
|
||||
observer.Abort();
|
||||
this.observerCancellationTokenSource.Cancel();
|
||||
this.observer.Join();
|
||||
}
|
||||
foreach (WorkerThread worker in threadpool)
|
||||
foreach (var worker in threadpool)
|
||||
{
|
||||
worker.thread.Abort();
|
||||
worker.CancellationTokenSource.Cancel();
|
||||
worker.Thread.Join();
|
||||
}
|
||||
threadpool.Clear();
|
||||
tasks.Clear();
|
||||
this.threadpool.Clear();
|
||||
this.tasks.Clear();
|
||||
}
|
||||
threadpool = null;
|
||||
tasks = null;
|
||||
observer = null;
|
||||
disposedValue = true;
|
||||
this.threadpool = null;
|
||||
this.tasks = null;
|
||||
this.observer = null;
|
||||
this.disposedValue = true;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
+19
-24
@@ -1,14 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class AVLTreeTests
|
||||
@@ -25,7 +20,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i * 20 - (50 + i));
|
||||
}
|
||||
@@ -43,7 +38,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
@@ -57,7 +52,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void RemoveTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
@@ -73,7 +68,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
@@ -87,24 +82,24 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void CopyToTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
|
||||
int[] array = new int[100];
|
||||
var array = new int[100];
|
||||
avlTree.CopyTo(array, 0);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
int count = 0;
|
||||
foreach(int value in avlTree)
|
||||
var count = 0;
|
||||
foreach(var value in avlTree)
|
||||
{
|
||||
count++;
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
@@ -119,34 +114,34 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
|
||||
int[] array = avlTree.ToArray();
|
||||
var array = avlTree.ToArray();
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Serialize()
|
||||
{
|
||||
AVLTree<int> avlTree2 = new AVLTree<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
var avlTree2 = new AVLTree<int>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
var serializer = new BinaryFormatter();
|
||||
var 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();
|
||||
var avlTreeEnum = avlTree.GetEnumerator();
|
||||
var avlTree2Enum = avlTree2.GetEnumerator();
|
||||
|
||||
for(int i = 0; i < 100; i++)
|
||||
for(var i = 0; i < 100; i++)
|
||||
{
|
||||
if(avlTreeEnum.Current != avlTree2Enum.Current)
|
||||
{
|
||||
+20
-27
@@ -1,16 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SystemExtensions;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Xml.Serialization;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class BinaryHeapTests
|
||||
@@ -38,7 +31,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
binaryHeap.Add(i * 20 - (50 + i));
|
||||
}
|
||||
@@ -59,7 +52,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
int tries = binaryHeap.Count;
|
||||
var tries = binaryHeap.Count;
|
||||
while (binaryHeap.Count > 0)
|
||||
{
|
||||
if (tries == 0)
|
||||
@@ -79,7 +72,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void MinMaxTest()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
@@ -92,7 +85,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
@@ -106,13 +99,13 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ClearTest2()
|
||||
{
|
||||
for (int i = 100; i < 200; i++)
|
||||
for (var i = 100; i < 200; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
binaryHeap.Clear(false);
|
||||
int[] array = binaryHeap.ToArray();
|
||||
if (binaryHeap.Count > 0 || binaryHeap.Capacity != 10)
|
||||
var array = binaryHeap.ToArray();
|
||||
if (binaryHeap.Count > 0 || binaryHeap.Capacity == 10)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
@@ -140,11 +133,11 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for(int i = 0; i < 1000; i++)
|
||||
for(var i = 0; i < 1000; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
int[] array = binaryHeap.ToArray();
|
||||
var array = binaryHeap.ToArray();
|
||||
if(array.Length != binaryHeap.Count)
|
||||
{
|
||||
Assert.Fail();
|
||||
@@ -158,12 +151,12 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
int count = 0;
|
||||
foreach(int value in binaryHeap)
|
||||
var count = 0;
|
||||
foreach(var value in binaryHeap)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
count++;
|
||||
@@ -180,22 +173,22 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void Serialize()
|
||||
{
|
||||
BinaryHeap<int> binaryHeap2 = new BinaryHeap<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
var binaryHeap2 = new BinaryHeap<int>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
var serializer = new BinaryFormatter();
|
||||
var 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();
|
||||
var binaryHeapEnum = binaryHeap.GetEnumerator();
|
||||
var binaryHeapEnum2 = binaryHeap2.GetEnumerator();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
if (binaryHeapEnum.Current != binaryHeapEnum2.Current)
|
||||
{
|
||||
+24
-30
@@ -1,15 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class FibonacciHeapTests
|
||||
@@ -18,7 +12,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void InsertTest()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
@@ -37,21 +31,21 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void MergeTest()
|
||||
{
|
||||
FibonacciHeap<int> fibonacciHeap1 = new FibonacciHeap<int>();
|
||||
FibonacciHeap<int> fibonacciHeap2 = new FibonacciHeap<int>();
|
||||
var fibonacciHeap1 = new FibonacciHeap<int>();
|
||||
var fibonacciHeap2 = new FibonacciHeap<int>();
|
||||
|
||||
for(int i = 0; i < 100; i++)
|
||||
for(var i = 0; i < 100; i++)
|
||||
{
|
||||
fibonacciHeap1.Add(i);
|
||||
}
|
||||
|
||||
for(int i = 100; i < 300; i++)
|
||||
for(var i = 100; i < 300; i++)
|
||||
{
|
||||
fibonacciHeap2.Add(i);
|
||||
}
|
||||
|
||||
fibonacciHeap1.Merge(fibonacciHeap2);
|
||||
for(int i = 1; i < 300; i++)
|
||||
for(var i = 1; i < 300; i++)
|
||||
{
|
||||
if (!fibonacciHeap1.Contains(i))
|
||||
{
|
||||
@@ -76,11 +70,11 @@ namespace SystemExtensions.Collections.Tests
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
if (fibonacciHeap.Remove() != i)
|
||||
{
|
||||
@@ -110,7 +104,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
for(int i = 0; i < 10000; i++)
|
||||
for(var i = 0; i < 10000; i++)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
@@ -123,7 +117,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for(int i = 0; i < 10000; i++)
|
||||
for(var i = 0; i < 10000; i++)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
@@ -138,14 +132,14 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for(int i = 999; i >= 0; i--)
|
||||
for(var i = 999; i >= 0; i--)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
fibonacciHeap.Remove();
|
||||
int[] arr = fibonacciHeap.ToArray();
|
||||
var arr = fibonacciHeap.ToArray();
|
||||
|
||||
for(int i = 1; i < 512; i++)
|
||||
for(var i = 1; i < 512; i++)
|
||||
{
|
||||
if(arr[i - 1] != i)
|
||||
{
|
||||
@@ -157,14 +151,14 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (int i = 999; i >= 0; i--)
|
||||
for (var i = 999; i >= 0; i--)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
var count = 0;
|
||||
|
||||
foreach(int value in fibonacciHeap)
|
||||
foreach(var value in fibonacciHeap)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
count++;
|
||||
@@ -181,23 +175,23 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void Serialize()
|
||||
{
|
||||
FibonacciHeap<int> fibonacciHeap2 = new FibonacciHeap<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
var fibonacciHeap2 = new FibonacciHeap<int>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
fibonacciHeap.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
var serializer = new BinaryFormatter();
|
||||
var 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();
|
||||
var enum1 = fibonacciHeap.GetEnumerator();
|
||||
var enum2 = fibonacciHeap2.GetEnumerator();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
if (enum1.Current != enum2.Current)
|
||||
{
|
||||
+11
-17
@@ -1,15 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SystemExtensions;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class PriorityQueueTests
|
||||
@@ -35,7 +29,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void EnqueueTest()
|
||||
{
|
||||
for(int i = 0; i < 100; i++)
|
||||
for(var i = 0; i < 100; i++)
|
||||
{
|
||||
priorityQueue.Enqueue(i);
|
||||
}
|
||||
@@ -48,11 +42,11 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void DequeueTest()
|
||||
{
|
||||
for(int i = 0; i < 100; i++)
|
||||
for(var i = 0; i < 100; i++)
|
||||
{
|
||||
priorityQueue.Enqueue(i);
|
||||
}
|
||||
for(int i = 0; i < 100; i++)
|
||||
for(var i = 0; i < 100; i++)
|
||||
{
|
||||
if(i != priorityQueue.Dequeue())
|
||||
{
|
||||
@@ -87,23 +81,23 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void Serialize()
|
||||
{
|
||||
PriorityQueue<int> priorityQueue2 = new PriorityQueue<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
var priorityQueue2 = new PriorityQueue<int>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
priorityQueue.Enqueue(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
var serializer = new BinaryFormatter();
|
||||
var 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();
|
||||
var enum1 = priorityQueue.GetEnumerator();
|
||||
var enum2 = priorityQueue2.GetEnumerator();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
if (enum1.Current != enum2.Current)
|
||||
{
|
||||
+23
-27
@@ -1,14 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class SkipListTests
|
||||
@@ -17,19 +12,19 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void SkipListTest()
|
||||
{
|
||||
SkipList<int> skipList = new SkipList<int>();
|
||||
var skipList = new SkipList<int>();
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void SkipListTest2()
|
||||
{
|
||||
SkipList<int> skipList = new SkipList<int>(30);
|
||||
var skipList = new SkipList<int>(30);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void AddTest()
|
||||
{
|
||||
for(int i = 0; i < 200; i++)
|
||||
for(var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
@@ -38,7 +33,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
@@ -52,7 +47,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
@@ -66,13 +61,13 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void CopyToTest()
|
||||
{
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
int[] array = new int[skipList.Count];
|
||||
var array = new int[skipList.Count];
|
||||
skipList.CopyTo(array, 0);
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
if(array[i] != i)
|
||||
{
|
||||
@@ -84,13 +79,13 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
int[] array = skipList.ToArray();
|
||||
var array = skipList.ToArray();
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
if(array[i] != i)
|
||||
{
|
||||
@@ -102,12 +97,12 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
|
||||
foreach(int i in skipList)
|
||||
foreach(var i in skipList)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(i);
|
||||
}
|
||||
@@ -116,7 +111,7 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void RemoveTest()
|
||||
{
|
||||
for (int i = 0; i < 200; i++)
|
||||
for (var i = 0; i < 200; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
@@ -128,25 +123,26 @@ namespace SystemExtensions.Collections.Tests
|
||||
}
|
||||
|
||||
[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++)
|
||||
var skipList2 = new SkipList<int>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
skipList.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
var serializer = new BinaryFormatter();
|
||||
var 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();
|
||||
var enum1 = skipList.GetEnumerator();
|
||||
var enum2 = skipList2.GetEnumerator();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
if (enum1.Current != enum2.Current)
|
||||
{
|
||||
+19
-23
@@ -1,14 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class TreapTests
|
||||
@@ -23,8 +18,8 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void InsertTest()
|
||||
{
|
||||
Random random = new Random();
|
||||
for(int i = 0; i < 1000; i++)
|
||||
var random = new Random();
|
||||
for(var i = 0; i < 1000; i++)
|
||||
{
|
||||
treap.Add(random.Next(0, 5000));
|
||||
}
|
||||
@@ -46,8 +41,8 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 100; i++)
|
||||
var random = new Random();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
treap.Add(random.Next(0, 5000));
|
||||
}
|
||||
@@ -76,12 +71,12 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for(int i = 0; i < 1000; i++)
|
||||
for(var i = 0; i < 1000; i++)
|
||||
{
|
||||
treap.Add(i);
|
||||
}
|
||||
int[] arr = treap.ToArray();
|
||||
for(int i = 0; i < 1000; i++)
|
||||
var arr = treap.ToArray();
|
||||
for(var i = 0; i < 1000; i++)
|
||||
{
|
||||
if(arr[i] != i)
|
||||
{
|
||||
@@ -93,13 +88,13 @@ namespace SystemExtensions.Collections.Tests
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
treap.Add(i);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
foreach(int value in treap)
|
||||
var count = 0;
|
||||
foreach(var value in treap)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
count++;
|
||||
@@ -114,25 +109,26 @@ namespace SystemExtensions.Collections.Tests
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
[Ignore("Binary serialization is obsolete and should not be used anymore")]
|
||||
public void Serialize()
|
||||
{
|
||||
Treap<int> treap2 = new Treap<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
var treap2 = new Treap<int>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
treap.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
var serializer = new BinaryFormatter();
|
||||
var 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();
|
||||
var enum1 = treap.GetEnumerator();
|
||||
var enum2 = treap2.GetEnumerator();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
if (enum1.Current != enum2.Current)
|
||||
{
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace System.Extensions.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class OptionalTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SomeValueShouldEqualOptional()
|
||||
{
|
||||
var value = string.Empty;
|
||||
var optional = value.ToOptional();
|
||||
|
||||
Assert.IsTrue(optional.Equals(value));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OptionalFromNullShouldNotEqual()
|
||||
{
|
||||
object value = null;
|
||||
var optional = value.ToOptional();
|
||||
|
||||
Assert.IsFalse(optional.Equals(value));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OptionalFromValueShouldBeSome()
|
||||
{
|
||||
var optional = Optional.FromValue<object>(new object());
|
||||
|
||||
optional.DoAny(
|
||||
onNone: () => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OptionalFromNullShouldBeNone()
|
||||
{
|
||||
var optional = Optional.FromValue<object>(null);
|
||||
|
||||
optional.DoAny(
|
||||
onSome: _ => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoShouldExecute()
|
||||
{
|
||||
var optional = Optional.FromValue(string.Empty);
|
||||
var nullOptional = Optional.FromValue<string>(null);
|
||||
|
||||
optional.Do(
|
||||
onSome: _ => { },
|
||||
onNone: () => throw new InvalidOperationException());
|
||||
|
||||
nullOptional.Do(
|
||||
onSome: _ => throw new InvalidOperationException(),
|
||||
onNone: () => { });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoAnyShouldExecute()
|
||||
{
|
||||
var optional = Optional.FromValue(string.Empty);
|
||||
var nullOptional = Optional.FromValue<string>(null);
|
||||
|
||||
optional.DoAny(
|
||||
onNone: () => 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);
|
||||
|
||||
var newValue = optional.Switch(
|
||||
onSome: _ => string.Empty,
|
||||
onNone: () => throw new InvalidOperationException())
|
||||
.ExtractValue();
|
||||
|
||||
var newNullValue = nullOptional.Switch<string>(
|
||||
onSome: _ => throw new InvalidOperationException(),
|
||||
onNone: () => null)
|
||||
.ExtractValue();
|
||||
|
||||
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);
|
||||
|
||||
var newValue = optional.SwitchAny(
|
||||
onSome: _ => string.Empty)
|
||||
.ExtractValue();
|
||||
|
||||
var newNullValue = nullOptional.SwitchAny<string>(
|
||||
onNone: () => null)
|
||||
.ExtractValue();
|
||||
|
||||
newValue.Should().Be(string.Empty);
|
||||
newNullValue.Should().Be(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace System.Extensions.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class ResultTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SuccessResultShouldCreateFromSuccess()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var result = Result<string, object>.Success(success);
|
||||
|
||||
result.DoAny(
|
||||
onFailure: () => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void FailureResultShouldCreateFromFailure()
|
||||
{
|
||||
var failure = new object();
|
||||
var result = Result<string, object>.Failure(failure);
|
||||
|
||||
result.DoAny(
|
||||
onSuccess: () => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
successResult.Do(
|
||||
onSuccess: _ => { },
|
||||
onFailure: _ => throw new InvalidOperationException());
|
||||
|
||||
failedResult.Do(
|
||||
onSuccess: _ => throw new InvalidOperationException(),
|
||||
onFailure: _ => { });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoAnyShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
successResult.DoAny(
|
||||
onSuccess: _ => { });
|
||||
|
||||
failedResult.DoAny(
|
||||
onFailure: _ => { });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SwitchShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
var successSwitch = successResult.Switch(
|
||||
onSuccess: _ => string.Empty,
|
||||
onFailure: _ => throw new InvalidOperationException());
|
||||
|
||||
var failedSwitch = failedResult.Switch(
|
||||
onSuccess: _ => throw new InvalidOperationException(),
|
||||
onFailure: _ => string.Empty);
|
||||
|
||||
success.Should().Be(failedSwitch);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SwitchAnyShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
var successSwitch = successResult.SwitchAny(
|
||||
onSuccess: _ => string.Empty);
|
||||
|
||||
var failedSwitch = failedResult.SwitchAny(
|
||||
onFailure: _ => string.Empty);
|
||||
|
||||
success.Should().Be(failedSwitch);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ToOptionalShouldConvert()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
var successOptional = successResult.ToOptional();
|
||||
var failureOptional = failedResult.ToOptional();
|
||||
|
||||
successOptional.Should().NotBeNull();
|
||||
failureOptional.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SystemExtensionsTests.Utils;
|
||||
|
||||
namespace System.Http.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class HttpClientTests
|
||||
{
|
||||
private const string resourceUrl = "resource";
|
||||
|
||||
private static readonly Uri TestAddressUrl = new("https://helloworld.xyz");
|
||||
private readonly MockHttpMessageHandler handler = new();
|
||||
private IHttpClient<object> httpClient;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.httpClient = new HttpClient<object>(this.handler, false)
|
||||
{
|
||||
BaseAddress = TestAddressUrl
|
||||
};
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task HttpClientEmitsCorrectMessages()
|
||||
{
|
||||
var messagesEmitted = 0;
|
||||
this.httpClient.EventEmitted += (sender, message) =>
|
||||
{
|
||||
messagesEmitted++;
|
||||
message.Scope.Should().Be(typeof(object));
|
||||
message.Method.Should().Be("GetAsync");
|
||||
message.Url.Should().Be(TestAddressUrl.ToString());
|
||||
};
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
|
||||
await this.httpClient.GetAsync(TestAddressUrl);
|
||||
|
||||
messagesEmitted.Should().Be(1);
|
||||
}
|
||||
[TestMethod]
|
||||
public void SetBaseAddress()
|
||||
{
|
||||
this.httpClient.BaseAddress = TestAddressUrl;
|
||||
this.httpClient.BaseAddress.Should().Be(TestAddressUrl);
|
||||
}
|
||||
[TestMethod]
|
||||
public void SetDefaultRequestHeaders()
|
||||
{
|
||||
this.httpClient.DefaultRequestHeaders.TryAddWithoutValidation("someheader", "thisvalue");
|
||||
this.httpClient.DefaultRequestHeaders.GetValues("someheader").Should().BeEquivalentTo("thisvalue");
|
||||
}
|
||||
[TestMethod]
|
||||
public void SetMaxResponseContentBufferSize()
|
||||
{
|
||||
this.httpClient.MaxResponseContentBufferSize = 2000;
|
||||
this.httpClient.MaxResponseContentBufferSize.Should().Be(2000);
|
||||
}
|
||||
[TestMethod]
|
||||
public void SetTimeout()
|
||||
{
|
||||
this.httpClient.Timeout = TimeSpan.FromSeconds(1);
|
||||
this.httpClient.Timeout.Should().Be(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task DeleteAsyncStringReturns200()
|
||||
{
|
||||
this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.DeleteAsync(resourceUrl);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task DeleteAsyncUriReturns200()
|
||||
{
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.DeleteAsync(TestAddressUrl);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
[Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")]
|
||||
public async Task DeleteAsyncCanceledThrowsTaskCanceledException()
|
||||
{
|
||||
this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var responseTask = this.httpClient.DeleteAsync(TestAddressUrl, cts.Token);
|
||||
cts.Cancel();
|
||||
|
||||
var awaitAction = new Func<Task<HttpResponseMessage>>(async () =>
|
||||
{
|
||||
return await responseTask;
|
||||
});
|
||||
|
||||
await awaitAction.Should().ThrowAsync<TaskCanceledException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetAsyncStringReturns200()
|
||||
{
|
||||
this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.GetAsync(resourceUrl);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetAsyncUriReturns200()
|
||||
{
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.GetAsync(TestAddressUrl);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
[Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")]
|
||||
public async Task GetAsyncCanceledThrowsTaskCanceledException()
|
||||
{
|
||||
this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var responseTask = this.httpClient.GetAsync(TestAddressUrl, cts.Token);
|
||||
cts.Cancel();
|
||||
|
||||
var awaitAction = new Func<Task<HttpResponseMessage>>(async () =>
|
||||
{
|
||||
return await responseTask;
|
||||
});
|
||||
|
||||
await awaitAction.Should().ThrowAsync<TaskCanceledException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task PostAsyncStringReturns200()
|
||||
{
|
||||
this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.PostAsync(resourceUrl, null);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task PostAsyncUriReturns200()
|
||||
{
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.PostAsync(TestAddressUrl, null);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
[Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")]
|
||||
public async Task PostAsyncCanceledThrowsTaskCanceledException()
|
||||
{
|
||||
this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var responseTask = this.httpClient.PostAsync(TestAddressUrl, null, cts.Token);
|
||||
cts.Cancel();
|
||||
|
||||
var awaitAction = new Func<Task<HttpResponseMessage>>(async () =>
|
||||
{
|
||||
return await responseTask;
|
||||
});
|
||||
|
||||
await awaitAction.Should().ThrowAsync<TaskCanceledException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task SendAsyncUriReturns200()
|
||||
{
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
|
||||
var response = await this.httpClient.SendAsync(new HttpRequestMessage { RequestUri = TestAddressUrl });
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
}
|
||||
[TestMethod]
|
||||
[Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")]
|
||||
public async Task SendAsyncCanceledThrowsTaskCanceledException()
|
||||
{
|
||||
this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var responseTask = this.httpClient.SendAsync(new HttpRequestMessage { RequestUri = TestAddressUrl }, cts.Token);
|
||||
cts.Cancel();
|
||||
|
||||
var awaitAction = new Func<Task<HttpResponseMessage>>(async () =>
|
||||
{
|
||||
return await responseTask;
|
||||
});
|
||||
|
||||
await awaitAction.Should().ThrowAsync<TaskCanceledException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetStreamAsyncStringReturns200()
|
||||
{
|
||||
var ms = new MemoryStream(new byte[] { 13, 10, 11, 12 });
|
||||
var sc = new StreamContent(ms);
|
||||
this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc);
|
||||
|
||||
var response = await this.httpClient.GetStreamAsync(resourceUrl);
|
||||
|
||||
var responseBuffer = new byte[4];
|
||||
await response.ReadAsync(responseBuffer, 0, 4);
|
||||
responseBuffer[0].Should().Be(13);
|
||||
responseBuffer[1].Should().Be(10);
|
||||
responseBuffer[2].Should().Be(11);
|
||||
responseBuffer[3].Should().Be(12);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetStreamAsyncUriReturns200()
|
||||
{
|
||||
var ms = new MemoryStream(new byte[] { 13, 10, 11, 12 });
|
||||
var sc = new StreamContent(ms);
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc);
|
||||
|
||||
var response = await this.httpClient.GetStreamAsync(TestAddressUrl);
|
||||
|
||||
var responseBuffer = new byte[4];
|
||||
await response.ReadAsync(responseBuffer, 0, 4);
|
||||
responseBuffer[0].Should().Be(13);
|
||||
responseBuffer[1].Should().Be(10);
|
||||
responseBuffer[2].Should().Be(11);
|
||||
responseBuffer[3].Should().Be(12);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetStringAsyncStringReturns200()
|
||||
{
|
||||
var sc = new StringContent("hello");
|
||||
this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc);
|
||||
|
||||
var response = await this.httpClient.GetStringAsync(resourceUrl);
|
||||
|
||||
response.Should().Be("hello");
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetStringAsyncUriReturns200()
|
||||
{
|
||||
var sc = new StringContent("hello");
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc);
|
||||
|
||||
var response = await this.httpClient.GetStringAsync(TestAddressUrl);
|
||||
|
||||
response.Should().Be("hello");
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetByteArrayAsyncStringReturns200()
|
||||
{
|
||||
var sc = new ByteArrayContent(new byte[4] { 13, 10, 11, 12 });
|
||||
this.SetupResponse(new Uri(TestAddressUrl, resourceUrl), HttpStatusCode.OK, sc);
|
||||
|
||||
var response = await this.httpClient.GetByteArrayAsync(resourceUrl);
|
||||
|
||||
response[0].Should().Be(13);
|
||||
response[1].Should().Be(10);
|
||||
response[2].Should().Be(11);
|
||||
response[3].Should().Be(12);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task GetByteArrayAsyncUriReturns200()
|
||||
{
|
||||
var sc = new ByteArrayContent(new byte[4] { 13, 10, 11, 12 });
|
||||
this.SetupResponse(TestAddressUrl, HttpStatusCode.OK, sc);
|
||||
|
||||
var response = await this.httpClient.GetByteArrayAsync(TestAddressUrl);
|
||||
|
||||
response[0].Should().Be(13);
|
||||
response[1].Should().Be(10);
|
||||
response[2].Should().Be(11);
|
||||
response[3].Should().Be(12);
|
||||
}
|
||||
[TestMethod]
|
||||
[Ignore("NetStandard2.0 implementation doesn't cancel operation when token is cancelled")]
|
||||
public async Task CancelPendingRequestThrowsTaskCanceledException()
|
||||
{
|
||||
this.SetupLongResponse(TestAddressUrl, HttpStatusCode.OK);
|
||||
|
||||
var responseTask = this.httpClient.GetAsync(TestAddressUrl);
|
||||
this.httpClient.CancelPendingRequests();
|
||||
|
||||
var awaitAction = new Func<Task<HttpResponseMessage>>(async () =>
|
||||
{
|
||||
return await responseTask;
|
||||
});
|
||||
|
||||
await awaitAction.Should().ThrowAsync<TaskCanceledException>();
|
||||
}
|
||||
|
||||
private void SetupResponse(Uri expectedUri, HttpStatusCode statusCode, HttpContent httpContent = null)
|
||||
{
|
||||
this.handler.ResponseResolver = (request) =>
|
||||
{
|
||||
request.RequestUri.Should().Be(expectedUri);
|
||||
return new HttpResponseMessage { StatusCode = statusCode, Content = httpContent };
|
||||
};
|
||||
}
|
||||
private void SetupLongResponse(Uri expectedUri, HttpStatusCode statusCode, HttpContent httpContent = null)
|
||||
{
|
||||
this.handler.ResponseResolverAsync = async (request) =>
|
||||
{
|
||||
request.RequestUri.Should().Be(expectedUri);
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
return new HttpResponseMessage { StatusCode = statusCode, Content = httpContent };
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SystemExtensions.NetStandard.Tests.Logging.Models
|
||||
{
|
||||
public sealed class CachingLogger<T> : ILogger<T>
|
||||
{
|
||||
public List<string> LogCache { get; } = new();
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
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);
|
||||
this.LogCache.Add(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.NetStandard.Tests.Logging.Models;
|
||||
|
||||
namespace System.Logging.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class ScopedLoggerTests
|
||||
{
|
||||
private const string Flow = "Flow";
|
||||
private const string Message = "Some message";
|
||||
private readonly CachingLogger<ScopedLoggerTests> cachingLogger = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CreateLogger_CreatesNewLogger()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.CreateLogger_CreatesNewLogger), Flow);
|
||||
scopedLogger.Should().BeOfType<ScopedLogger<ScopedLoggerTests>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CreateLogger_NullScope_ThrowsArgumentNullException()
|
||||
{
|
||||
var action = new Action(() =>
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(null, Flow);
|
||||
});
|
||||
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CreateLogger_NullFlow_ThrowsArgumentNullException()
|
||||
{
|
||||
var action = new Action(() =>
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.CreateLogger_NullFlow_ThrowsArgumentNullException), null);
|
||||
});
|
||||
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogInformation_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogInformation_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogInformation(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogInformation_EmptyFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), string.Empty);
|
||||
var expectedMessage = $"{nameof(this.LogInformation_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogInformation(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogInformation_WhitespaceFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogInformation_LogsExpected), " ");
|
||||
var expectedMessage = $"{nameof(this.LogInformation_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogInformation(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogDebug_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogDebug_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogDebug(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogDebug_EmptyFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_EmptyFlow_LogsExpected), string.Empty);
|
||||
var expectedMessage = $"{nameof(this.LogDebug_EmptyFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogDebug(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogDebug_WhitespaceFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogDebug_WhitespaceFlow_LogsExpected), " ");
|
||||
var expectedMessage = $"{nameof(this.LogDebug_WhitespaceFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogDebug(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogWarning_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogWarning_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogWarning(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogWarning_EmptyFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_EmptyFlow_LogsExpected), string.Empty);
|
||||
var expectedMessage = $"{nameof(this.LogWarning_EmptyFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogWarning(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogWarning_WhitespaceFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_WhitespaceFlow_LogsExpected), " ");
|
||||
var expectedMessage = $"{nameof(this.LogWarning_WhitespaceFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogWarning(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogError_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogError_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogError(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogError_EmptyFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_EmptyFlow_LogsExpected), string.Empty);
|
||||
var expectedMessage = $"{nameof(this.LogError_EmptyFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogError(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogError_WhitespaceFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_WhitespaceFlow_LogsExpected), " ");
|
||||
var expectedMessage = $"{nameof(this.LogError_WhitespaceFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogError(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogCritical_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogCritical_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogCritical(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogCritical_EmptyFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_EmptyFlow_LogsExpected), string.Empty);
|
||||
var expectedMessage = $"{nameof(this.LogCritical_EmptyFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogCritical(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogCritical_WhitespaceFlow_LogsExpected()
|
||||
{
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_WhitespaceFlow_LogsExpected), " ");
|
||||
var expectedMessage = $"{nameof(this.LogCritical_WhitespaceFlow_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogCritical(Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogWarning_WithException_LogsExpected()
|
||||
{
|
||||
var exception = new Exception();
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogWarning_WithException_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogWarning_WithException_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogWarning(exception, Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogError_WithException_LogsExpected()
|
||||
{
|
||||
var exception = new Exception();
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogError_WithException_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogError_WithException_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogError(exception, Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogCritical_WithException_LogsExpected()
|
||||
{
|
||||
var exception = new Exception();
|
||||
var scopedLogger = this.cachingLogger.CreateScopedLogger(nameof(this.LogCritical_WithException_LogsExpected), Flow);
|
||||
var expectedMessage = $"[{Flow}] {nameof(this.LogCritical_WithException_LogsExpected)}: {Message}";
|
||||
|
||||
scopedLogger.LogCritical(exception, Message);
|
||||
|
||||
this.cachingLogger.LogCache.Should().HaveCount(1);
|
||||
this.cachingLogger.LogCache.First().Should().Be(expectedMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace System.Structures.BitStructures.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Int32BitStructTests
|
||||
{
|
||||
[DataTestMethod]
|
||||
[DataRow(-1)]
|
||||
[DataRow(int.MaxValue)]
|
||||
public void TestSetValueInt(int value)
|
||||
{
|
||||
Int32BitStruct int32 = value;
|
||||
Assert.IsTrue(int32 == value);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(1)]
|
||||
public void TestSetValueUint(int value)
|
||||
{
|
||||
Int32BitStruct int32 = value;
|
||||
Assert.IsTrue(int32 == value);
|
||||
}
|
||||
|
||||
public void TestSetMaxValueUint()
|
||||
{
|
||||
Int32BitStruct int32 = uint.MaxValue;
|
||||
Assert.IsTrue(int32 == uint.MaxValue);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(0)]
|
||||
[DataRow(int.MaxValue)]
|
||||
[DataRow(int.MinValue)]
|
||||
public void TestGetBit(int value)
|
||||
{
|
||||
Int32BitStruct int32 = value;
|
||||
Assert.IsTrue(value >= 0 ? int32.Bit31 == 0 : int32.Bit31 == 1);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(0)]
|
||||
[DataRow(1)]
|
||||
public void TestSetBit(int value)
|
||||
{
|
||||
Int32BitStruct int32 = 0;
|
||||
int32.Bit0 = (uint)value;
|
||||
Assert.IsTrue(int32 == value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUseCaseExample()
|
||||
{
|
||||
// Set value = -1, represented as MSB being 1 and the rest 0.
|
||||
Int32BitStruct int32 = int.MinValue;
|
||||
|
||||
// Test that MSB is 1.
|
||||
Assert.IsTrue(int32.Bit31 == 1);
|
||||
|
||||
// Set MSB to 0 and test that everything else is 0.
|
||||
int32.Bit31 = 0;
|
||||
Assert.IsTrue(int32 == 0);
|
||||
|
||||
// Set the least 31 significant bits (all besides MSB) to 1.
|
||||
int32 = int.MaxValue;
|
||||
|
||||
// Set the MSB to 1 and test that everything is 1.
|
||||
int32.Bit31 = 1;
|
||||
Assert.IsTrue(int32 == uint.MaxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace System.Structures.BitStructures.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Int64BitStructTests
|
||||
{
|
||||
[DataTestMethod]
|
||||
[DataRow(-1L)]
|
||||
[DataRow(long.MaxValue)]
|
||||
public void TestSetValueInt(long value)
|
||||
{
|
||||
Int64BitStruct int64 = value;
|
||||
Assert.IsTrue(int64 == value);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(1UL)]
|
||||
public void TestSetValueUint(long value)
|
||||
{
|
||||
Int64BitStruct int64 = value;
|
||||
Assert.IsTrue(int64 == value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSetMaxValueUint()
|
||||
{
|
||||
Int64BitStruct int64 = ulong.MaxValue;
|
||||
Assert.IsTrue(int64 == ulong.MaxValue);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(0)]
|
||||
[DataRow(long.MaxValue)]
|
||||
[DataRow(long.MinValue)]
|
||||
public void TestGetBit(long value)
|
||||
{
|
||||
Int64BitStruct int64 = value;
|
||||
Assert.IsTrue(value >= 0L ? int64.Bit63 == 0 : int64.Bit63 == 1);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(0)]
|
||||
[DataRow(1)]
|
||||
public void TestSetBit(long value)
|
||||
{
|
||||
Int64BitStruct int64 = 0L;
|
||||
int64.Bit0 = (ulong)value;
|
||||
Assert.IsTrue(int64 == value);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(int.MaxValue, int.MinValue)]
|
||||
public void TestLowHigh(int low, int high)
|
||||
{
|
||||
var int64 = new Int64BitStruct(low, high);
|
||||
Int32BitStruct lowStruct = low;
|
||||
Int32BitStruct highStruct = high;
|
||||
Assert.IsTrue(int64.Low == lowStruct);
|
||||
Assert.IsTrue(int64.High == highStruct);
|
||||
unchecked
|
||||
{
|
||||
Assert.IsTrue(int64 == ((ulong)low + ((ulong)high << 32)));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUseCaseExample()
|
||||
{
|
||||
// Set value = -1, represented as MSB being 1 and the rest 0.
|
||||
Int64BitStruct int64 = long.MinValue;
|
||||
|
||||
// Test that MSB is 1.
|
||||
Assert.IsTrue(int64.Bit63 == 1);
|
||||
|
||||
// Set MSB to 0 and test that everything else is 0.
|
||||
int64.Bit63 = 0;
|
||||
Assert.IsTrue(int64 == 0UL);
|
||||
|
||||
// Set the least 31 significant bits (all besides MSB) to 1.
|
||||
int64 = long.MaxValue;
|
||||
|
||||
// Set the MSB to 1 and test that everything is 1.
|
||||
int64.Bit63 = 1;
|
||||
Assert.IsTrue(int64 == ulong.MaxValue);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUseCaseExample2()
|
||||
{
|
||||
// Set all bits to 1. Check low and high values to be equal to having all 32 bits set.
|
||||
Int64BitStruct int64 = ulong.MaxValue;
|
||||
Assert.IsTrue(int64.Low == uint.MaxValue && int64.High == uint.MaxValue);
|
||||
|
||||
// Set all 63 least significant bits to 1 and MSB to 0.
|
||||
int64 = long.MaxValue;
|
||||
Assert.IsTrue(int64.Bit63 == 0);
|
||||
|
||||
// Check that high has all bits besides MSB set to 1 and that low has all bits set to 1.
|
||||
Assert.IsTrue(int64.High == int.MaxValue && int64.Low == uint.MaxValue);
|
||||
|
||||
// Set the MSB back to 1 and check that all bits are set to 1.
|
||||
int64.Bit63 = 1;
|
||||
Assert.IsTrue(int64 == ulong.MaxValue);
|
||||
Assert.IsTrue(int64.High == uint.MaxValue && int64.Low == uint.MaxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.4" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.4" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetCore\SystemExtensions.NetCore.csproj" />
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+14
-22
@@ -1,15 +1,7 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Threading;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using static SystemExtensions.Threading.PriorityThreadPool;
|
||||
using static System.Threading.PriorityThreadPool;
|
||||
|
||||
namespace SystemExtensions.Threading.Tests
|
||||
namespace System.Threading.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class PriorityThreadPoolTests
|
||||
@@ -22,7 +14,7 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
threadPool.Dispose();
|
||||
threadPool = new PriorityThreadPool();
|
||||
if (threadPool.NumberOfThreads != System.Environment.ProcessorCount)
|
||||
if (threadPool.NumberOfThreads != Environment.ProcessorCount)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
@@ -57,7 +49,7 @@ namespace SystemExtensions.Threading.Tests
|
||||
Thread.Sleep(100);
|
||||
try
|
||||
{
|
||||
int x = threadPool.NumberOfThreads;
|
||||
var x = threadPool.NumberOfThreads;
|
||||
Assert.Fail();
|
||||
}
|
||||
catch(Exception e)
|
||||
@@ -71,17 +63,17 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
threadPool.Dispose();
|
||||
threadPool = new PriorityThreadPool();
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
threadPool.QueueUserWorkItem(o =>
|
||||
{
|
||||
for (int x = 0; x < 100; x++)
|
||||
for (var x = 0; x < 100; x++)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads);
|
||||
@@ -106,11 +98,11 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
threadPool.QueueUserWorkItem(o =>
|
||||
{
|
||||
for (int x = 0; x < 100; x++)
|
||||
for (var x = 0; x < 100; x++)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x);
|
||||
}
|
||||
@@ -134,11 +126,11 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
threadPool.QueueUserWorkItem(o =>
|
||||
{
|
||||
for (int x = 0; x < 100; x++)
|
||||
for (var x = 0; x < 100; x++)
|
||||
{
|
||||
switch (Thread.CurrentThread.Priority)
|
||||
{
|
||||
@@ -161,7 +153,7 @@ namespace SystemExtensions.Threading.Tests
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
for (int i = 0; i < 50; i++)
|
||||
for (var i = 0; i < 50; i++)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads);
|
||||
@@ -176,9 +168,9 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
threadPool.Dispose();
|
||||
threadPool = new PriorityThreadPool();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
TaskPriority taskPriority = TaskPriority.Lowest;
|
||||
var taskPriority = TaskPriority.Lowest;
|
||||
if(i % 10 == 0)
|
||||
{
|
||||
taskPriority = TaskPriority.Highest;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user